mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2025-08-26 21:45:20 +02:00
refactor: improve service handling and introduce MODE_ASSERT
- Improved get_service_name filter plugin (clearer suffix handling, consistent var names). - Added MODE_ASSERT flag to optionally execute validation/assertion tasks. - Fixed systemd unit handling: consistent use of %I instead of %i, correct escaping of instance names. - Unified on_failure behavior and alarm composer scripts. - Cleaned up redundant logging, handlers, and debug config. - Strengthened sys-service template resolution with assert (only active when MODE_ASSERT). - Simplified timer and suffix handling with get_service_name filter. - Hardened sensitive tasks with no_log. - Added conditional asserts across roles (Keycloak, DNS, Mailu, Discourse, etc.). These changes improve consistency, safety, and validation across the automation stack. Conversation: https://chatgpt.com/share/68a4ae28-483c-800f-b2f7-f64c7124c274
This commit is contained in:
parent
6e538eabc8
commit
a10dd402b8
@ -15,8 +15,8 @@ Suffix handling:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def get_service_name(systemctl_id, software_name, suffix=""):
|
def get_service_name(systemctl_id, software_name, suffix=""):
|
||||||
sid = str(systemctl_id).strip().lower()
|
sid = str(systemctl_id).strip().lower()
|
||||||
sw = str(software_name).strip().lower()
|
software_name = str(software_name).strip().lower()
|
||||||
|
|
||||||
# Determine suffix
|
# Determine suffix
|
||||||
if suffix is False:
|
if suffix is False:
|
||||||
@ -24,14 +24,13 @@ def get_service_name(systemctl_id, software_name, suffix=""):
|
|||||||
elif suffix == "" or suffix is None:
|
elif suffix == "" or suffix is None:
|
||||||
sfx = ".service"
|
sfx = ".service"
|
||||||
else:
|
else:
|
||||||
sfx = "." + str(suffix).strip().lower()
|
sfx = str(suffix).strip().lower()
|
||||||
|
|
||||||
if sid.endswith("@"):
|
if sid.endswith("@"):
|
||||||
base = sid[:-1] # drop the trailing '@'
|
base = sid[:-1] # drop the trailing '@'
|
||||||
return f"{base}.{sw}@{sfx}"
|
return f"{base}.{software_name}@{sfx}"
|
||||||
else:
|
else:
|
||||||
return f"{sid}.{sw}{sfx}"
|
return f"{sid}.{software_name}{sfx}"
|
||||||
|
|
||||||
|
|
||||||
class FilterModule(object):
|
class FilterModule(object):
|
||||||
def filters(self):
|
def filters(self):
|
||||||
|
@ -6,4 +6,5 @@ MODE_UPDATE: true # Executes updates
|
|||||||
MODE_BACKUP: true # Activates the backup before the update procedure
|
MODE_BACKUP: true # Activates the backup before the update procedure
|
||||||
MODE_CLEANUP: true # Cleanup unused files and configurations
|
MODE_CLEANUP: true # Cleanup unused files and configurations
|
||||||
MODE_DEBUG: false # This enables debugging in ansible and in the apps, You SHOULD NOT enable this on production servers
|
MODE_DEBUG: false # This enables debugging in ansible and in the apps, You SHOULD NOT enable this on production servers
|
||||||
MODE_RESET: false # Cleans up all Infinito.Nexus files. It's necessary to run to whole playbook and not particial roles when using this function.
|
MODE_RESET: false # Cleans up all Infinito.Nexus files. It's necessary to run to whole playbook and not particial roles when using this function.
|
||||||
|
MODE_ASSERT: false # Executes validation tasks during the run.
|
@ -14,7 +14,7 @@ SYS_SERVICE_REPAIR_DOCKER_HARD: "{{ 'sys-ctl-rpr-docker-hard' | get_servic
|
|||||||
SYS_SERVICE_UPDATE_DOCKER: "{{ 'update-docker' | get_service_name(SOFTWARE_NAME) }}"
|
SYS_SERVICE_UPDATE_DOCKER: "{{ 'update-docker' | get_service_name(SOFTWARE_NAME) }}"
|
||||||
|
|
||||||
## On Failure
|
## On Failure
|
||||||
SYS_SERVICE_ON_FAILURE_COMPOSE: "{{ 'sys-ctl-alm-compose' | get_service_name(SOFTWARE_NAME,'%i.service') }}"
|
SYS_SERVICE_ON_FAILURE_COMPOSE: "{{ ('sys-ctl-alm-compose@') | get_service_name(SOFTWARE_NAME, False) }}%n.service"
|
||||||
|
|
||||||
## Groups
|
## Groups
|
||||||
SYS_SERVICE_GROUP_BACKUPS: >
|
SYS_SERVICE_GROUP_BACKUPS: >
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
# Service Timers
|
# Service Timers
|
||||||
|
|
||||||
## Meta
|
## Meta
|
||||||
SYS_TIMER_SUFFIX: ".{{ SOFTWARE_NAME | lower }}.timer"
|
|
||||||
SYS_TIMER_ALL_ENABLED: "{{ not MODE_DEBUG }}" # Runtime Variables for Process Control - Activates all timers, independend if the handlers had been triggered
|
SYS_TIMER_ALL_ENABLED: "{{ not MODE_DEBUG }}" # Runtime Variables for Process Control - Activates all timers, independend if the handlers had been triggered
|
||||||
|
|
||||||
## Server Tact Variables
|
## Server Tact Variables
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
name: github.com
|
name: github.com
|
||||||
key: "{{ lookup('pipe', 'ssh-keyscan -t ed25519 github.com | grep -v \"^#\"') }}"
|
key: "{{ lookup('pipe', 'ssh-keyscan -t ed25519 github.com | grep -v \"^#\"') }}"
|
||||||
become: true
|
become: true
|
||||||
|
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
||||||
|
|
||||||
- name: Create installation directory for Kevin's Package Manager
|
- name: Create installation directory for Kevin's Package Manager
|
||||||
file:
|
file:
|
||||||
@ -37,7 +38,7 @@
|
|||||||
- name: create config.yaml
|
- name: create config.yaml
|
||||||
template:
|
template:
|
||||||
src: config.yaml.j2
|
src: config.yaml.j2
|
||||||
dest: "{{pkgmgr_config_path}}"
|
dest: "{{ pkgmgr_config_path }}"
|
||||||
become: true
|
become: true
|
||||||
|
|
||||||
- name: Run the Package Manager install command to create an alias for Kevins package manager
|
- name: Run the Package Manager install command to create an alias for Kevins package manager
|
||||||
|
@ -36,8 +36,6 @@ http
|
|||||||
'"X-Forwarded-For: $http_x_forwarded_for" '
|
'"X-Forwarded-For: $http_x_forwarded_for" '
|
||||||
'"Scheme: $scheme" "Protocol: $server_protocol" "ServerName: $server_name"';
|
'"Scheme: $scheme" "Protocol: $server_protocol" "ServerName: $server_name"';
|
||||||
access_log /dev/stdout debug;
|
access_log /dev/stdout debug;
|
||||||
{% else %}
|
|
||||||
access_log /dev/stdout debug;
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
error_log /dev/stderr info;
|
error_log /dev/stderr info;
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
- target
|
- target
|
||||||
- source
|
- source
|
||||||
to non‑empty values in your configuration file.
|
to non‑empty values in your configuration file.
|
||||||
|
when: MODE_ASSERT | bool
|
||||||
|
|
||||||
- include_role:
|
- include_role:
|
||||||
name: sys-service
|
name: sys-service
|
||||||
|
@ -1,13 +1,4 @@
|
|||||||
---
|
---
|
||||||
- name: Wait until OpenResty container is running
|
|
||||||
command: docker inspect -f '{{.State.Running}}' {{ OPENRESTY_CONTAINER }}
|
|
||||||
register: openresty_status
|
|
||||||
retries: 10
|
|
||||||
delay: 3
|
|
||||||
until: openresty_status.stdout.strip() == "true"
|
|
||||||
changed_when: false
|
|
||||||
listen: restart openresty
|
|
||||||
|
|
||||||
- name: Validate OpenResty configuration
|
- name: Validate OpenResty configuration
|
||||||
command: >
|
command: >
|
||||||
docker exec {{ OPENRESTY_CONTAINER }} openresty -t -q
|
docker exec {{ OPENRESTY_CONTAINER }} openresty -t -q
|
||||||
|
@ -6,20 +6,30 @@
|
|||||||
- sys-ctl-alm-email
|
- sys-ctl-alm-email
|
||||||
vars:
|
vars:
|
||||||
flush_handlers: true
|
flush_handlers: true
|
||||||
systemctl_timer_enabled: false
|
system_service_timer_enabled: false
|
||||||
systemctl_copy_files: true
|
system_service_copy_files: true
|
||||||
|
|
||||||
- name: "Include core service for '{{ system_service_id }}'"
|
- name: "Include core service for '{{ system_service_id }}'"
|
||||||
include_role:
|
include_role:
|
||||||
name: sys-service
|
name: sys-service
|
||||||
vars:
|
vars:
|
||||||
flush_handlers: true
|
flush_handlers: true
|
||||||
systemctl_timer_enabled: false
|
system_service_timer_enabled: false
|
||||||
systemctl_copy_files: true
|
system_service_copy_files: true
|
||||||
systemctl_tpl_exec_start: "{{ system_service_script_exec }} %i"
|
system_service_tpl_exec_start: "{{ system_service_script_exec }} %I"
|
||||||
systemctl_tpl_on_failure: "" # No on failure needed, because it's anyhow the default on failure procedure
|
system_service_tpl_on_failure: "" # No on failure needed, because it's anyhow the default on failure procedure
|
||||||
|
|
||||||
- name: "Send message to test service."
|
- block:
|
||||||
systemd:
|
- name: Escape instance name for systemctl call
|
||||||
name: "sys-ctl-alm-compose@{{ SYSTEMCTL_ALARM_COMPOSER_DUMMY_MESSAGE }}.service"
|
ansible.builtin.command:
|
||||||
state: started
|
argv:
|
||||||
|
- systemd-escape
|
||||||
|
- "{{ SYSTEMCTL_ALARM_COMPOSER_DUMMY_MESSAGE }}"
|
||||||
|
register: escaped_name
|
||||||
|
changed_when: false
|
||||||
|
|
||||||
|
- name: Start sys-ctl-alm-compose instance
|
||||||
|
ansible.builtin.systemd:
|
||||||
|
name: "{{ ('sys-ctl-alm-compose@') | get_service_name(SOFTWARE_NAME, False) ~ escaped_name.stdout ~ '.service' }}"
|
||||||
|
state: started
|
||||||
|
when: MODE_ASSERT | bool
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
err=0
|
err=0
|
||||||
set -u
|
set -u
|
||||||
{% for alarm_service in SYSTEMCTL_ALARM_COMPOSER_SUBSERVICES %}
|
{% for alarm in SYSTEMCTL_ALARM_COMPOSER_SUBSERVICES %}
|
||||||
{% set alarm_service_full_name = alarm_service | get_service_name(SOFTWARE_NAME, '"$1".service') %}
|
# sys-ctl-alm-email.infinito.nexus@<escaped>.service (no extra dot!)
|
||||||
if ! /usr/bin/systemctl start {{ alarm_service_full_name }}; then
|
unit="{{ (alarm ~ '@') | get_service_name(SOFTWARE_NAME, False) }}$(systemd-escape "$1").service"
|
||||||
echo "ERROR: Failed to start {{ alarm_service_full_name }}" >&2
|
if ! /usr/bin/systemctl start -- "$unit"; then
|
||||||
|
echo "ERROR: Failed to start $unit" >&2
|
||||||
err=1
|
err=1
|
||||||
fi
|
fi
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
set -u
|
||||||
|
|
||||||
|
STATUS_OUT="$(systemctl status --full "$1" 2>/dev/null | head -n 30)"
|
||||||
|
if [ -z "$STATUS_OUT" ]; then
|
||||||
|
STATUS_OUT="(no matching systemd unit found for: $1)"
|
||||||
|
fi
|
||||||
|
|
||||||
/usr/bin/sendmail -t <<ERRMAIL
|
/usr/bin/sendmail -t <<ERRMAIL
|
||||||
To: {{ users.administrator.email }}
|
To: {{ users.administrator.email }}
|
||||||
@ -7,9 +13,8 @@ Subject: $1
|
|||||||
Content-Transfer-Encoding: 8bit
|
Content-Transfer-Encoding: 8bit
|
||||||
Content-Type: text/plain; charset=UTF-8
|
Content-Type: text/plain; charset=UTF-8
|
||||||
|
|
||||||
A problem with the service $1 occured:
|
A problem with the service $1 occurred:
|
||||||
|
|
||||||
$(systemctl status --full "$1" | head -n 30)
|
|
||||||
|
|
||||||
|
$STATUS_OUT
|
||||||
|
|
||||||
ERRMAIL
|
ERRMAIL
|
||||||
|
@ -3,6 +3,6 @@ Description=status email for %i to user
|
|||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=oneshot
|
Type=oneshot
|
||||||
ExecStart={{ system_service_script_exec }} %i
|
ExecStart={{ system_service_script_exec }} %I
|
||||||
User=root
|
User=root
|
||||||
Group=systemd-journal
|
Group=systemd-journal
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
Please provide non‑empty values for:
|
Please provide non‑empty values for:
|
||||||
- telegram_bot_token # Your Telegram bot’s API token
|
- telegram_bot_token # Your Telegram bot’s API token
|
||||||
- telegram_chat_id # The Telegram chat ID to send messages to
|
- telegram_chat_id # The Telegram chat ID to send messages to
|
||||||
|
when: MODE_ASSERT | bool
|
||||||
|
|
||||||
- include_role:
|
- include_role:
|
||||||
name: sys-service
|
name: sys-service
|
||||||
|
@ -3,6 +3,6 @@ Description=status Telegram message for %i to user
|
|||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=oneshot
|
Type=oneshot
|
||||||
ExecStart={{ system_service_script_exec }} %i
|
ExecStart={{ system_service_script_exec }} %I
|
||||||
User=root
|
User=root
|
||||||
Group=systemd-journal
|
Group=systemd-journal
|
||||||
|
@ -7,7 +7,9 @@
|
|||||||
that:
|
that:
|
||||||
- SYSTEMD_MANAGER_CONF_DIR | regex_search('^/etc/systemd/system\.conf\.d/?$')
|
- SYSTEMD_MANAGER_CONF_DIR | regex_search('^/etc/systemd/system\.conf\.d/?$')
|
||||||
fail_msg: "SYSTEMD_MANAGER_CONF_DIR must be /etc/systemd/system.conf.d"
|
fail_msg: "SYSTEMD_MANAGER_CONF_DIR must be /etc/systemd/system.conf.d"
|
||||||
when: SYSTEMD_MANAGER_RESET_PURGE | bool
|
when:
|
||||||
|
- SYSTEMD_MANAGER_RESET_PURGE | bool
|
||||||
|
- MODE_ASSERT | bool
|
||||||
|
|
||||||
- name: "Purge manager drop-in directory (remove)"
|
- name: "Purge manager drop-in directory (remove)"
|
||||||
file:
|
file:
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
ansible.builtin.assert:
|
ansible.builtin.assert:
|
||||||
that: [ "CLOUDFLARE_API_TOKEN | length > 0" ]
|
that: [ "CLOUDFLARE_API_TOKEN | length > 0" ]
|
||||||
no_log: "{{ cloudflare_no_log | bool }}"
|
no_log: "{{ cloudflare_no_log | bool }}"
|
||||||
|
when: MODE_ASSERT | bool
|
||||||
|
|
||||||
- name: Apply A/AAAA
|
- name: Apply A/AAAA
|
||||||
community.general.cloudflare_dns:
|
community.general.cloudflare_dns:
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
that: [ "_hz_token | length > 0" ]
|
that: [ "_hz_token | length > 0" ]
|
||||||
fail_msg: "HETZNER_API_TOKEN is required for the Cloud flavor."
|
fail_msg: "HETZNER_API_TOKEN is required for the Cloud flavor."
|
||||||
no_log: "{{ hetzner_no_log | bool }}"
|
no_log: "{{ hetzner_no_log | bool }}"
|
||||||
|
when: MODE_ASSERT | bool
|
||||||
|
|
||||||
- name: Collect hcloud servers if needed (server records without identifier)
|
- name: Collect hcloud servers if needed (server records without identifier)
|
||||||
hetzner.hcloud.server_info:
|
hetzner.hcloud.server_info:
|
||||||
@ -61,6 +62,7 @@
|
|||||||
)
|
)
|
||||||
fail_msg: "Could not resolve hcloud server by IPv4 for one or more records."
|
fail_msg: "Could not resolve hcloud server by IPv4 for one or more records."
|
||||||
no_log: "{{ hetzner_no_log | bool }}"
|
no_log: "{{ hetzner_no_log | bool }}"
|
||||||
|
when: MODE_ASSERT | bool
|
||||||
|
|
||||||
- name: Validate records (cloud)
|
- name: Validate records (cloud)
|
||||||
ansible.builtin.assert:
|
ansible.builtin.assert:
|
||||||
@ -74,6 +76,7 @@
|
|||||||
+ ((_rdns_records | default(rdns_records)) | rejectattr('resource','equalto','server') | list | length)
|
+ ((_rdns_records | default(rdns_records)) | rejectattr('resource','equalto','server') | list | length)
|
||||||
) == ((_rdns_records | default(rdns_records)) | length)
|
) == ((_rdns_records | default(rdns_records)) | length)
|
||||||
no_log: "{{ hetzner_no_log | bool }}"
|
no_log: "{{ hetzner_no_log | bool }}"
|
||||||
|
when: MODE_ASSERT | bool
|
||||||
|
|
||||||
- name: Apply rDNS via hcloud
|
- name: Apply rDNS via hcloud
|
||||||
hetzner.hcloud.hcloud_rdns:
|
hetzner.hcloud.hcloud_rdns:
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
- (HETZNER_ROBOT_PASSWORD | default('') | length) > 0
|
- (HETZNER_ROBOT_PASSWORD | default('') | length) > 0
|
||||||
fail_msg: "Robot credentials required: HETZNER_ROBOT_USER / HETZNER_ROBOT_PASSWORD."
|
fail_msg: "Robot credentials required: HETZNER_ROBOT_USER / HETZNER_ROBOT_PASSWORD."
|
||||||
no_log: "{{ hetzner_no_log | bool }}"
|
no_log: "{{ hetzner_no_log | bool }}"
|
||||||
|
when: MODE_ASSERT | bool
|
||||||
|
|
||||||
- name: Validate records (robot)
|
- name: Validate records (robot)
|
||||||
ansible.builtin.assert:
|
ansible.builtin.assert:
|
||||||
@ -16,6 +17,7 @@
|
|||||||
- (rdns_records | selectattr('dns_ptr','defined') | list | length) == (rdns_records | length)
|
- (rdns_records | selectattr('dns_ptr','defined') | list | length) == (rdns_records | length)
|
||||||
fail_msg: "Each record must have ip_address and dns_ptr for Robot rDNS."
|
fail_msg: "Each record must have ip_address and dns_ptr for Robot rDNS."
|
||||||
no_log: "{{ hetzner_no_log | bool }}"
|
no_log: "{{ hetzner_no_log | bool }}"
|
||||||
|
when: MODE_ASSERT | bool
|
||||||
|
|
||||||
- name: Apply rDNS via Hetzner Robot API
|
- name: Apply rDNS via Hetzner Robot API
|
||||||
vars:
|
vars:
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# 1) Find the template (prefer target role, then fall back to this role)
|
|
||||||
- name: Resolve systemctl template source
|
- name: Resolve systemctl template source
|
||||||
set_fact:
|
set_fact:
|
||||||
system_service_template_src: >-
|
system_service_template_src: >-
|
||||||
@ -17,31 +16,29 @@
|
|||||||
errors='strict'
|
errors='strict'
|
||||||
) }}
|
) }}
|
||||||
|
|
||||||
# Optional: sanity check with a clear error if truly nothing found
|
|
||||||
- name: Ensure a systemctl template was found
|
- name: Ensure a systemctl template was found
|
||||||
assert:
|
assert:
|
||||||
that: system_service_template_src | length > 0
|
that: system_service_template_src | length > 0
|
||||||
fail_msg: >-
|
fail_msg: >-
|
||||||
Could not resolve any systemctl template. Looked in:
|
Could not resolve any systemctl template. Looked in:
|
||||||
{{ system_service_role_dir }}/templates/ and {{ role_path }}/templates/.
|
{{ system_service_role_dir }}/templates/ and {{ role_path }}/templates/.
|
||||||
|
when: MODE_ASSERT | bool
|
||||||
|
|
||||||
# 2) Now we may safely derive whether it’s the “@” variant
|
|
||||||
- name: Flag whether @-template is used
|
- name: Flag whether @-template is used
|
||||||
set_fact:
|
set_fact:
|
||||||
system_service_uses_at: "{{ (system_service_template_src | basename) is search('@\\.service\\.j2$') }}"
|
system_service_uses_at: "{{ system_service_id.endswith('@') }}"
|
||||||
|
|
||||||
# 3) Use it
|
|
||||||
- name: "setup systemctl '{{ system_service_id }}'"
|
- name: "setup systemctl '{{ system_service_id }}'"
|
||||||
template:
|
template:
|
||||||
src: "{{ system_service_template_src }}"
|
src: "{{ system_service_template_src }}"
|
||||||
dest: "{{ [ PATH_SYSTEM_SERVICE_DIR, system_service_id | get_service_name(SOFTWARE_NAME) ] | path_join }}"
|
dest: "{{ [ PATH_SYSTEM_SERVICE_DIR, system_service_id | get_service_name(SOFTWARE_NAME) ] | path_join }}"
|
||||||
notify: "{{ 'reload system daemon' if system_service_uses_at else 'refresh systemctl service' }}"
|
notify: "{{ 'reload system daemon' if system_service_uses_at else 'refresh systemctl service' }}"
|
||||||
|
|
||||||
- name: refresh systemctl service when SYS_SERVICE_ALL_ENABLED
|
- name: refresh systemctl service when SYS_SERVICE_ALL_ENABLE
|
||||||
command: /bin/true
|
block:
|
||||||
notify:
|
- command: /bin/true
|
||||||
- reload system daemon
|
notify: reload system daemon
|
||||||
- refresh systemctl service
|
- command: /bin/true
|
||||||
when:
|
notify: refresh systemctl service
|
||||||
- SYS_SERVICE_ALL_ENABLED | bool
|
when: not system_service_uses_at
|
||||||
- not system_service_uses_at
|
when: SYS_SERVICE_ALL_ENABLED | bool
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
that:
|
that:
|
||||||
- "'@' not in system_service_id"
|
- "'@' not in system_service_id"
|
||||||
fail_msg: "Invalid system_service_id '{{ system_service_id }}' → must not contain '@'."
|
fail_msg: "Invalid system_service_id '{{ system_service_id }}' → must not contain '@'."
|
||||||
|
when: MODE_ASSERT | bool
|
||||||
|
|
||||||
- name: "Make '{{ system_service_id }}' available for sys-timer"
|
- name: "Make '{{ system_service_id }}' available for sys-timer"
|
||||||
set_fact:
|
set_fact:
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
[Unit]
|
[Unit]
|
||||||
Description={{ SOFTWARE_NAME }} - Service for role '{{ system_service_id }}'
|
Description={{ SOFTWARE_NAME }} - Service for role '{{ system_service_id }}'
|
||||||
|
{% if system_service_tpl_on_failure |length > 0 %}
|
||||||
OnFailure={{ system_service_tpl_on_failure }}
|
OnFailure={{ system_service_tpl_on_failure }}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type={{ system_service_tpl_type }}
|
Type={{ system_service_tpl_type }}
|
||||||
|
@ -1 +1 @@
|
|||||||
sys_timer_file: "{{ system_service_timer_service }}{{ SYS_TIMER_SUFFIX }}"
|
sys_timer_file: "{{ system_service_timer_service | get_service_name(SOFTWARE_NAME,'.timer') }}"
|
@ -12,6 +12,7 @@
|
|||||||
generate_ssh_key: yes
|
generate_ssh_key: yes
|
||||||
ssh_key_type: rsa
|
ssh_key_type: rsa
|
||||||
ssh_key_bits: 8192
|
ssh_key_bits: 8192
|
||||||
|
no_log: "{{ MASK_CREDENTIALS_IN_LOGS | bool }}"
|
||||||
|
|
||||||
- name: "set correct rights for {{ PATH_ADMINISTRATOR_HOME }}"
|
- name: "set correct rights for {{ PATH_ADMINISTRATOR_HOME }}"
|
||||||
file:
|
file:
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
- docker_compose is defined
|
- docker_compose is defined
|
||||||
- ports is defined
|
- ports is defined
|
||||||
fail_msg: "Load roles/docker-compose/vars/docker-compose.yml and set `database_type` first."
|
fail_msg: "Load roles/docker-compose/vars/docker-compose.yml and set `database_type` first."
|
||||||
|
when: MODE_ASSERT | bool
|
||||||
|
|
||||||
- name: "Disconnect DB container from Discourse networks"
|
- name: "Disconnect DB container from Discourse networks"
|
||||||
ansible.builtin.command:
|
ansible.builtin.command:
|
||||||
|
@ -46,6 +46,7 @@
|
|||||||
- scope_id_rbac | length > 0
|
- scope_id_rbac | length > 0
|
||||||
- (app_client_id_cmd.stdout | trim) is match('^[0-9a-f-]+$')
|
- (app_client_id_cmd.stdout | trim) is match('^[0-9a-f-]+$')
|
||||||
fail_msg: "Could not determine client or scope ID."
|
fail_msg: "Could not determine client or scope ID."
|
||||||
|
when: MODE_ASSERT | bool
|
||||||
|
|
||||||
- name: Get current optional client scopes
|
- name: Get current optional client scopes
|
||||||
shell: >
|
shell: >
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
assert:
|
assert:
|
||||||
that: [ "(ldap_cmp_id.stdout | trim) not in ['', 'null']" ]
|
that: [ "(ldap_cmp_id.stdout | trim) not in ['', 'null']" ]
|
||||||
fail_msg: "LDAP component '{{ KEYCLOAK_LDAP_CMP_NAME }}' not found in Keycloak."
|
fail_msg: "LDAP component '{{ KEYCLOAK_LDAP_CMP_NAME }}' not found in Keycloak."
|
||||||
|
when: MODE_ASSERT | bool
|
||||||
|
|
||||||
- name: Pull LDAP component from dictionary (by name)
|
- name: Pull LDAP component from dictionary (by name)
|
||||||
set_fact:
|
set_fact:
|
||||||
@ -42,6 +43,7 @@
|
|||||||
- ldap_component_tpl | length > 0
|
- ldap_component_tpl | length > 0
|
||||||
- (ldap_component_tpl.subComponents | default({})) | length > 0
|
- (ldap_component_tpl.subComponents | default({})) | length > 0
|
||||||
fail_msg: "LDAP component '{{ KEYCLOAK_LDAP_CMP_NAME }}' not found in KEYCLOAK_DICTIONARY_REALM."
|
fail_msg: "LDAP component '{{ KEYCLOAK_LDAP_CMP_NAME }}' not found in KEYCLOAK_DICTIONARY_REALM."
|
||||||
|
when: MODE_ASSERT | bool
|
||||||
|
|
||||||
- name: Extract mapper 'ldap-roles' from template (raw)
|
- name: Extract mapper 'ldap-roles' from template (raw)
|
||||||
set_fact:
|
set_fact:
|
||||||
@ -59,6 +61,7 @@
|
|||||||
assert:
|
assert:
|
||||||
that: [ "desired_group_mapper_raw | length > 0" ]
|
that: [ "desired_group_mapper_raw | length > 0" ]
|
||||||
fail_msg: "'ldap-roles' mapper not found in dictionary under LDAP component."
|
fail_msg: "'ldap-roles' mapper not found in dictionary under LDAP component."
|
||||||
|
when: MODE_ASSERT | bool
|
||||||
|
|
||||||
- name: Build clean mapper payload
|
- name: Build clean mapper payload
|
||||||
set_fact:
|
set_fact:
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
- kc_lookup_value is defined
|
- kc_lookup_value is defined
|
||||||
- kc_desired is defined
|
- kc_desired is defined
|
||||||
fail_msg: "kc_object_kind, kc_lookup_value, kc_desired are required."
|
fail_msg: "kc_object_kind, kc_lookup_value, kc_desired are required."
|
||||||
|
when: MODE_ASSERT | bool
|
||||||
|
|
||||||
- name: Derive API endpoint and lookup field
|
- name: Derive API endpoint and lookup field
|
||||||
set_fact:
|
set_fact:
|
||||||
@ -67,6 +68,7 @@
|
|||||||
- (kc_obj_id | trim) != ''
|
- (kc_obj_id | trim) != ''
|
||||||
- (kc_obj_id | trim) != 'null'
|
- (kc_obj_id | trim) != 'null'
|
||||||
fail_msg: "{{ kc_object_kind | capitalize }} '{{ kc_lookup_value }}' not found."
|
fail_msg: "{{ kc_object_kind | capitalize }} '{{ kc_lookup_value }}' not found."
|
||||||
|
when: MODE_ASSERT | bool
|
||||||
|
|
||||||
- name: Read current object
|
- name: Read current object
|
||||||
shell: >
|
shell: >
|
||||||
@ -85,6 +87,7 @@
|
|||||||
when:
|
when:
|
||||||
- kc_object_kind == 'component'
|
- kc_object_kind == 'component'
|
||||||
- (kc_desired.providerId is defined)
|
- (kc_desired.providerId is defined)
|
||||||
|
- MODE_ASSERT | bool
|
||||||
assert:
|
assert:
|
||||||
that:
|
that:
|
||||||
- cur_obj.providerId == kc_desired.providerId
|
- cur_obj.providerId == kc_desired.providerId
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
- MAILU_HOSTNAMES | length <= 1
|
- MAILU_HOSTNAMES | length <= 1
|
||||||
fail_msg: "MAILU_HOSTNAMES must be a list with at most one entry (only one host is supported). You can set the other ones as alias."
|
fail_msg: "MAILU_HOSTNAMES must be a list with at most one entry (only one host is supported). You can set the other ones as alias."
|
||||||
success_msg: "MAILU_HOSTNAMES is valid."
|
success_msg: "MAILU_HOSTNAMES is valid."
|
||||||
|
when: MODE_ASSERT | bool
|
||||||
|
|
||||||
- name: "Mailu Docker and Webserver Setup"
|
- name: "Mailu Docker and Webserver Setup"
|
||||||
block:
|
block:
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
- name: "Validate configuration"
|
- name: "Validate configuration"
|
||||||
include_tasks: "02_validate.yml"
|
include_tasks: "02_validate.yml"
|
||||||
|
when: MODE_ASSERT | bool
|
||||||
|
|
||||||
- name: "load docker, proxy for '{{ application_id }}'"
|
- name: "load docker, proxy for '{{ application_id }}'"
|
||||||
include_role:
|
include_role:
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
fail_msg: "Group '{{ item }}' has no entry in 'applications'"
|
fail_msg: "Group '{{ item }}' has no entry in 'applications'"
|
||||||
success_msg: "Group '{{ item }}' is defined in 'applications'"
|
success_msg: "Group '{{ item }}' is defined in 'applications'"
|
||||||
loop: "{{ group_names }}"
|
loop: "{{ group_names }}"
|
||||||
|
when: MODE_ASSERT | bool
|
||||||
|
|
||||||
- name: Merge current play applications
|
- name: Merge current play applications
|
||||||
set_fact:
|
set_fact:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user