From fff7d261a25eb69c9e1143f56311abaa53cb6bc4 Mon Sep 17 00:00:00 2001 From: Kevin Veen-Birkenbach Date: Sun, 30 Nov 2025 18:51:40 +0100 Subject: [PATCH] Refactor run-once logic across multiple roles and integrate unified utils/run_once.yml This commit standardizes all run-once implementations across the following roles: - desk-git - dev-fakeroot - dev-git - dev-python-yaml - sys-lock - sys-svc-certs (wildcard flavor) - update-apt - update-pacman - update-compose - user-root (moved logic to 01_core.yml + unified run-once handling) - web-app-matomo - web-svc-libretranslate All roles now: - Use a block guarded by 'run_once_' facts - Trigger run-once state through utils/run_once.yml - Optionally disable handler flushing via 'flush_handlers: false' - Achieve consistent per-host one-time execution semantics Conversation reference: https://chatgpt.com/share/692c7fbb-ff68-800f-8cb4-4b132cffc8e4 --- roles/desk-git/tasks/main.yml | 16 ++++----- roles/dev-fakeroot/tasks/main.yml | 18 +++++----- roles/dev-git/tasks/main.yml | 16 ++++----- roles/dev-python-yaml/tasks/main.yml | 20 +++++------ roles/sys-lock/tasks/main.yml | 16 ++++----- .../sys-svc-certs/tasks/flavors/wildcard.yml | 24 ++++++------- roles/update-apt/tasks/main.yml | 18 +++++----- roles/update-compose/tasks/01_core.yml | 8 +++-- roles/update-pacman/tasks/main.yml | 16 ++++----- roles/user-root/tasks/01_core.yml | 30 ++++++++++++++++ roles/user-root/tasks/main.yml | 34 ++----------------- roles/web-app-matomo/tasks/01_core.yml | 2 ++ roles/web-app-matomo/tasks/main.yml | 7 +--- roles/web-svc-libretranslate/tasks/main.yml | 15 ++++---- 14 files changed, 119 insertions(+), 121 deletions(-) create mode 100644 roles/user-root/tasks/01_core.yml diff --git a/roles/desk-git/tasks/main.yml b/roles/desk-git/tasks/main.yml index dab1c4d6..f3a9482c 100644 --- a/roles/desk-git/tasks/main.yml +++ b/roles/desk-git/tasks/main.yml @@ -10,12 +10,12 @@ vars: package_name: gitconfig -- name: setup git - command: gitconfig --merge-option rebase --name "{{users.client.full_name}}" --email "{{users.client.email}}" --website "{{users.client.website}}" --signing gpg --gpg-key "{{users.client.gpg}}" - when: run_once_desk_git is not defined - become: false +- when: run_once_desk_git is not defined + block: + - name: setup git + command: gitconfig --merge-option rebase --name "{{users.client.full_name}}" --email "{{users.client.email}}" --website "{{users.client.website}}" --signing gpg --gpg-key "{{users.client.gpg}}" + become: false -- name: run the gitconfig tasks once - set_fact: - run_once_desk_git: true - when: run_once_desk_git is not defined \ No newline at end of file + - include_tasks: utils/run_once.yml + vars: + flush_handlers: false \ No newline at end of file diff --git a/roles/dev-fakeroot/tasks/main.yml b/roles/dev-fakeroot/tasks/main.yml index 362aa819..f2cb20ab 100644 --- a/roles/dev-fakeroot/tasks/main.yml +++ b/roles/dev-fakeroot/tasks/main.yml @@ -1,11 +1,11 @@ --- -- name: Install fakeroot - community.general.pacman: - name: fakeroot - state: present - when: run_once_dev_fakeroot is not defined +- when: run_once_dev_fakeroot is not defined + block: + - name: Install fakeroot + community.general.pacman: + name: fakeroot + state: present -- name: run the fakeroot tasks once - set_fact: - run_once_dev_fakeroot: true - when: run_once_dev_fakeroot is not defined \ No newline at end of file + - include_tasks: utils/run_once.yml + vars: + flush_handlers: false \ No newline at end of file diff --git a/roles/dev-git/tasks/main.yml b/roles/dev-git/tasks/main.yml index c0dcc67b..ace978e5 100644 --- a/roles/dev-git/tasks/main.yml +++ b/roles/dev-git/tasks/main.yml @@ -1,10 +1,10 @@ -- name: install git - community.general.pacman: - name: git - state: present - when: run_once_dev_git is not defined +- block: + - name: install git + community.general.pacman: + name: git + state: present -- name: run the git tasks once - set_fact: - run_once_dev_git: true + - include_tasks: utils/run_once.yml + vars: + flush_handlers: false when: run_once_dev_git is not defined \ No newline at end of file diff --git a/roles/dev-python-yaml/tasks/main.yml b/roles/dev-python-yaml/tasks/main.yml index 9f699fbd..ca88940a 100644 --- a/roles/dev-python-yaml/tasks/main.yml +++ b/roles/dev-python-yaml/tasks/main.yml @@ -1,11 +1,11 @@ --- -- name: python-yaml install - community.general.pacman: - name: python-yaml - state: present - when: run_once_dev_python_yaml is not defined - -- name: run the python_yaml tasks once - set_fact: - run_once_dev_python_yaml: true - when: run_once_dev_python_yaml is not defined +- when: run_once_dev_python_yaml is not defined + block: + - name: python-yaml install + community.general.pacman: + name: python-yaml + state: present + + - include_tasks: utils/run_once.yml + vars: + flush_handlers: false diff --git a/roles/sys-lock/tasks/main.yml b/roles/sys-lock/tasks/main.yml index cb2084d3..b7ebb7c2 100644 --- a/roles/sys-lock/tasks/main.yml +++ b/roles/sys-lock/tasks/main.yml @@ -1,11 +1,11 @@ --- -- name: create {{ PATH_SYSTEM_LOCK_SCRIPT }} - copy: - src: sys-lock.py - dest: "{{ PATH_SYSTEM_LOCK_SCRIPT }}" - when: run_once_sys_lock is not defined +- block: + - name: create {{ PATH_SYSTEM_LOCK_SCRIPT }} + copy: + src: sys-lock.py + dest: "{{ PATH_SYSTEM_LOCK_SCRIPT }}" -- name: execute the script copying once - set_fact: - run_once_sys_lock: true + - include_tasks: utils/run_once.yml + vars: + flush_handlers: false when: run_once_sys_lock is not defined diff --git a/roles/sys-svc-certs/tasks/flavors/wildcard.yml b/roles/sys-svc-certs/tasks/flavors/wildcard.yml index bfd80446..9af9be46 100644 --- a/roles/sys-svc-certs/tasks/flavors/wildcard.yml +++ b/roles/sys-svc-certs/tasks/flavors/wildcard.yml @@ -1,10 +1,14 @@ -- name: "Load wildcard certificate for domain" - include_tasks: "dedicated.yml" - vars: - wildcard_domain: true - when: - - domain.split('.') | length == (PRIMARY_DOMAIN.split('.') | length + 1) and domain.endswith(PRIMARY_DOMAIN) - - run_once_receive_certificate is not defined +- block: + - name: "Load wildcard certificate for domain" + include_tasks: "dedicated.yml" + vars: + wildcard_domain: true + when: + - domain.split('.') | length == (PRIMARY_DOMAIN.split('.') | length + 1) and domain.endswith(PRIMARY_DOMAIN) + - name: run the receive_certificate tasks once + set_fact: + run_once_receive_certificate: true + when: run_once_receive_certificate is not defined - name: "Load dedicated certificate for domain" include_tasks: "dedicated.yml" @@ -12,8 +16,4 @@ wildcard_domain: false when: - not (domain.split('.') | length == (PRIMARY_DOMAIN.split('.') | length + 1) and domain.endswith(PRIMARY_DOMAIN)) - -- name: run the receive_certificate tasks once - set_fact: - run_once_receive_certificate: true - when: run_once_receive_certificate is not defined \ No newline at end of file + \ No newline at end of file diff --git a/roles/update-apt/tasks/main.yml b/roles/update-apt/tasks/main.yml index 5d063ccc..4c6cd378 100644 --- a/roles/update-apt/tasks/main.yml +++ b/roles/update-apt/tasks/main.yml @@ -1,11 +1,11 @@ -- name: apt update all packages to their latest version - apt: - update_cache: yes - upgrade: dist - force_apt_get: yes - when: run_once_update_apt +- block: + - name: apt update all packages to their latest version + apt: + update_cache: yes + upgrade: dist + force_apt_get: yes -- name: run the {{ role_name }} logic just once - set_fact: - run_once_update_apt: true + - include_tasks: utils/run_once.yml + vars: + flush_handlers: false when: run_once_update_apt is not defined \ No newline at end of file diff --git a/roles/update-compose/tasks/01_core.yml b/roles/update-compose/tasks/01_core.yml index e389cea3..7f799c25 100644 --- a/roles/update-compose/tasks/01_core.yml +++ b/roles/update-compose/tasks/01_core.yml @@ -7,11 +7,15 @@ - name: "Update with pacman" include_role: name: update-pacman - when: ansible_distribution == 'Archlinux' + when: + - ansible_distribution == 'Archlinux' + - run_once_update_pacman is not defined - name: "Update with apt" include_role: name: update-apt - when: ansible_distribution == "Debian" + when: + - ansible_distribution == "Debian" + - run_once_update_apt is not defined - include_tasks: utils/run_once.yml \ No newline at end of file diff --git a/roles/update-pacman/tasks/main.yml b/roles/update-pacman/tasks/main.yml index 6f1b2b5f..eb8e7ac6 100644 --- a/roles/update-pacman/tasks/main.yml +++ b/roles/update-pacman/tasks/main.yml @@ -1,10 +1,10 @@ -- name: update pacman - community.general.pacman: - update_cache: yes - upgrade: yes - when: run_once_update_pacman is not defined +- block: + - name: update pacman + community.general.pacman: + update_cache: yes + upgrade: yes -- name: run update pacman once - set_fact: - run_once_update_pacman: true + - include_tasks: utils/run_once.yml + vars: + flush_handlers: false when: run_once_update_pacman is not defined \ No newline at end of file diff --git a/roles/user-root/tasks/01_core.yml b/roles/user-root/tasks/01_core.yml new file mode 100644 index 00000000..1e6f40d4 --- /dev/null +++ b/roles/user-root/tasks/01_core.yml @@ -0,0 +1,30 @@ +- name: Check if the SSH key for root already exists + ansible.builtin.stat: + path: "/root/.ssh/id_rsa.pub" + register: ssh_key + +- block: + - name: Generate a SSH key for root if it does not exist + community.crypto.openssh_keypair: + path: "/root/.ssh/id_rsa" + type: rsa + size: 4096 + + - name: Display the public SSH key + command: cat /root/.ssh/id_rsa.pub + register: public_key + + - name: Output the public SSH key + debug: + msg: "{{ public_key.stdout }}" + when: not ssh_key.stat.exists + +- name: "embed user routines for {{ role_path | basename }}" + include_role: + name: user + vars: + user_name: "root" + +- include_tasks: utils/run_once.yml + vars: + flush_handlers: false diff --git a/roles/user-root/tasks/main.yml b/roles/user-root/tasks/main.yml index d955f395..79e095fc 100644 --- a/roles/user-root/tasks/main.yml +++ b/roles/user-root/tasks/main.yml @@ -1,33 +1,3 @@ -- name: Check if the SSH key for root already exists - ansible.builtin.stat: - path: "/root/.ssh/id_rsa.pub" - register: ssh_key - -- name: Generate a SSH key for root if it does not exist - community.crypto.openssh_keypair: - path: "/root/.ssh/id_rsa" - type: rsa - size: 4096 - when: not ssh_key.stat.exists and run_once_user_root is not defined - -- name: Display the public SSH key - command: cat /root/.ssh/id_rsa.pub - register: public_key - when: not ssh_key.stat.exists and run_once_user_root is not defined - -- name: Output the public SSH key - debug: - msg: "{{ public_key.stdout }}" - when: not ssh_key.stat.exists and run_once_user_root is not defined - -- name: "embed user routines for {{ role_path | basename }}" - include_role: - name: user - vars: - user_name: "root" - when: run_once_user_root is not defined - -- name: run the user_root tasks once - set_fact: - run_once_user_root: true +- name: "Execute Role (once)" + include_tasks: 01_core.yml when: run_once_user_root is not defined \ No newline at end of file diff --git a/roles/web-app-matomo/tasks/01_core.yml b/roles/web-app-matomo/tasks/01_core.yml index b5c561e9..c9c73362 100644 --- a/roles/web-app-matomo/tasks/01_core.yml +++ b/roles/web-app-matomo/tasks/01_core.yml @@ -40,3 +40,5 @@ token_auth: "{{ matomo_auth_token }}" return_content: yes status_code: 200 + +- include_tasks: utils/run_once.yml \ No newline at end of file diff --git a/roles/web-app-matomo/tasks/main.yml b/roles/web-app-matomo/tasks/main.yml index c35aaabe..f969da9b 100644 --- a/roles/web-app-matomo/tasks/main.yml +++ b/roles/web-app-matomo/tasks/main.yml @@ -1,9 +1,4 @@ --- -- name: "construct {{ role_name }}" +- name: "Execute Role (once)" include_tasks: 01_core.yml when: run_once_web_app_matomo is not defined - -- name: run the docker matomo tasks once - set_fact: - run_once_web_app_matomo: true - when: run_once_web_app_matomo is not defined \ No newline at end of file diff --git a/roles/web-svc-libretranslate/tasks/main.yml b/roles/web-svc-libretranslate/tasks/main.yml index 3459fa24..4cb4814e 100644 --- a/roles/web-svc-libretranslate/tasks/main.yml +++ b/roles/web-svc-libretranslate/tasks/main.yml @@ -1,9 +1,6 @@ -- name: "load docker, db and proxy for {{ application_id }}" - include_role: - name: sys-stk-full-stateful - when: run_once_web_app_libretranslate is not defined - -- name: run the libretranslate tasks once - set_fact: - run_once_web_app_libretranslate: true - when: run_once_web_app_libretranslate is not defined +- block: + - name: "load docker, db and proxy for {{ application_id }}" + include_role: + name: sys-stk-full-stateful + - include_tasks: utils/run_once.yml + when: run_once_web_svc_libretranslate is not defined