Refactor systemctl service handling with @ support

- Unified variable naming: system_service_id → systemctl_id
- Added automatic removal of trailing '@' for role directory resolution
- Improved first_found search: prefer target role, fallback to sys-systemctl defaults
- Split template resolution logic to avoid undefined variable errors
- Added assertion in sys-timer to forbid '@' in systemctl_id
- Corrected default systemctl.service.j2 template description
- Cleaned up path handling and script directory generation

Context: conversation about fixing template resolution and @ handling
https://chatgpt.com/share/68a39994-1bb0-800f-a219-109e643c3efb
This commit is contained in:
Kevin Veen-Birkenbach 2025-08-18 23:22:46 +02:00
parent b9461026a6
commit 185f37af52
No known key found for this signature in database
GPG Key ID: 44D8F11FD62F878E
9 changed files with 76 additions and 44 deletions

View File

@ -1,18 +1,18 @@
# filter_plugins/get_service_script_path.py
# Custom Ansible filter to generate service script paths.
def get_service_script_path(system_service_id, script_type):
def get_service_script_path(systemctl_id, script_type):
"""
Build the path to a service script based on system_service_id and type.
Build the path to a service script based on systemctl_id and type.
:param system_service_id: The identifier of the system service.
:param systemctl_id: The identifier of the system service.
:param script_type: The script type/extension (e.g., sh, py, yml).
:return: The full path string.
"""
if not system_service_id or not script_type:
raise ValueError("Both system_service_id and script_type are required")
if not systemctl_id or not script_type:
raise ValueError("Both systemctl_id and script_type are required")
return f"/opt/scripts/{system_service_id}/script.{script_type}"
return f"/opt/scripts/{systemctl_id}/script.{script_type}"
class FilterModule(object):

View File

@ -1 +1 @@
systemctl_id: sys-ctl-alm-compose
systemctl_id: sys-ctl-alm-compose@

View File

@ -1 +1 @@
systemctl_id: sys-ctl-alm-email
systemctl_id: sys-ctl-alm-email@

View File

@ -1,2 +1 @@
systemctl_id: sys-ctl-alm-telegram
systemctl_id: sys-ctl-alm-telegram@

View File

@ -1,18 +1,20 @@
# roles/sys-systemctl/tasks/03_base.yml
- name: "find best matching source for service script"
set_fact:
service_src: >-
{{
lookup('first_found', {
{{ lookup('first_found',
{
'files': [
'templates/script.sh.j2',
'templates/script.py.j2',
'files/script.sh',
'files/script.py'
]
}, errors='strict')
}}
when:
- systemctl_copy_files | bool
],
'paths': [ systemctl_role_dir ]
},
errors='strict'
) }}
when: systemctl_copy_files | bool
- name: "Load file logic for '{{ systemctl_id }}'"
include_tasks: 04_files.yml

View File

@ -1,19 +1,38 @@
- name: "setup systemctl {{ item }} '{{ systemctl_id }}'"
# 1) Find the template (prefer target role, then fall back to this role)
- name: Resolve systemctl template source
set_fact:
systemctl_template_src: >-
{{ lookup(
'first_found',
{
'files': [
'templates/systemctl@.service.j2',
'templates/systemctl.service.j2'
],
'paths': [
systemctl_role_dir,
role_path
]
},
errors='strict'
) }}
# Optional: sanity check with a clear error if truly nothing found
- name: Ensure a systemctl template was found
assert:
that: systemctl_template_src | length > 0
fail_msg: >-
Could not resolve any systemctl template. Looked in:
{{ systemctl_role_dir }}/templates/ and {{ role_path }}/templates/.
# 2) Now we may safely derive whether its the “@” variant
- name: Flag whether @-template is used
set_fact:
systemctl_uses_at: "{{ (systemctl_template_src | basename) is search('@\\.service\\.j2$') }}"
# 3) Use it
- name: "setup systemctl '{{ systemctl_id }}'"
template:
src: "{{ lookup(
'first_found',
{
'files': ['templates/systemctl' ~ item ~ '.service.j2'],
'paths': [systemctl_role_dir, role_path]
},
errors='strict'
) }}"
dest: "{{ [ PATH_SYSTEM_SERVICE_DIR, systemctl_id ~ item ~ SYS_SERVICE_SUFFIX ] | path_join }}"
notify: "{{ 'reload system daemon' if item == '@' else 'refresh systemctl service' }}"
register: services_template
failed_when:
- services_template is failed
- "'Could not find or access' not in services_template.msg"
loop:
- ""
- "@"
src: "{{ systemctl_template_src }}"
dest: "{{ [ PATH_SYSTEM_SERVICE_DIR, systemctl_id | get_service_name(SOFTWARE_NAME) ] | path_join }}"
notify: "{{ 'reload system daemon' if systemctl_uses_at else 'refresh systemctl service' }}"

View File

@ -1,4 +1,11 @@
- set_fact:
- name: Fail if systemctl_id contains "@"
assert:
that:
- "'@' not in systemctl_id"
fail_msg: "Invalid systemctl_id '{{ systemctl_id }}' → must not contain '@'."
- name: "Make '{{ systemctl_id }}' available for sys-timer"
set_fact:
systemctl_timer_service: "{{ systemctl_id }}"
- name: "include role for sys-timer for {{ systemctl_timer_service }}"

View File

@ -1,5 +1,5 @@
[Unit]
Description=Service for {{ SOFTWARE_NAME }} role 'systemctl_id' (DEFAULT TEMPLATE)
Description=Service for {{ SOFTWARE_NAME }} role '{{ systemctl_id }}' (DEFAULT TEMPLATE)
OnFailure={{ SYS_SERVICE_ON_FAILURE_COMPOSE }}
[Service]

View File

@ -1,6 +1,11 @@
UNIT_SUFFIX_REMOVER_PACKAGE: "unsure"
systemctl_script_dir: "{{ [ PATH_SYSTEMCTL_SCRIPTS, systemctl_id ] | path_join }}"
systemctl_role_dir: "{{ playbook_dir }}/roles/{{ systemctl_id }}"
systemctl_copy_files: true # When set to false file copying will be skipped
systemctl_timer_enabled: false # When set to true timmer will be loaded
systemctl_state: "{{ omit }}"
## Paths
systemctl_role_name: "{{ systemctl_id | regex_replace('@','') }}"
systemctl_role_dir: "{{ [ playbook_dir, 'roles', systemctl_role_name ] | path_join }}"
systemctl_script_dir: "{{ [ PATH_SYSTEMCTL_SCRIPTS, systemctl_id ] | path_join }}"
## Settings
systemctl_copy_files: true # When set to false file copying will be skipped
systemctl_timer_enabled: false # When set to true timmer will be loaded
systemctl_state: "{{ omit }}"