diff options
| author | Egor Tensin <egor@tensin.name> | 2025-11-23 23:25:52 +0100 |
|---|---|---|
| committer | Egor Tensin <egor@tensin.name> | 2025-11-23 23:37:31 +0100 |
| commit | 58d256ea6262dc6365d26d3abc807c88a12809b2 (patch) | |
| tree | a9736c6ded91ae9192ec89c7ebf04a691f0d0227 | |
| parent | config_links: fix a typo (diff) | |
| download | infra-ansible-58d256ea6262dc6365d26d3abc807c88a12809b2.tar.gz infra-ansible-58d256ea6262dc6365d26d3abc807c88a12809b2.zip | |
plugins: add etckeeper_commit
| -rwxr-xr-x | plugins/action/etckeeper_commit.py | 63 | ||||
| -rw-r--r-- | roles/etckeeper/handlers/commit.yml | 30 | ||||
| -rw-r--r-- | roles/etckeeper/handlers/main.yml | 13 | ||||
| -rw-r--r-- | roles/etckeeper_commit/defaults/main.yml | 2 | ||||
| -rw-r--r-- | roles/etckeeper_commit/tasks/main.yml | 45 |
5 files changed, 74 insertions, 79 deletions
diff --git a/plugins/action/etckeeper_commit.py b/plugins/action/etckeeper_commit.py new file mode 100755 index 0000000..065b9eb --- /dev/null +++ b/plugins/action/etckeeper_commit.py @@ -0,0 +1,63 @@ +#!/usr/bin/python + +import re + +from ansible.errors import AnsibleActionFail +from ansible.plugins.action import ActionBase + + +class ActionModule(ActionBase): + def run(self, tmp=None, task_vars=None): + result = super().run(tmp, task_vars) + + msg = self._task.args['msg'] + allowlist = self._task.args.get('allowlist', []) + allowlist = [re.compile(pattern) for pattern in allowlist] + skip_no_changes = self._task.args.get('skip_no_changes', False) + + dirty_files = self._get_dirty_file_list('/etc', task_vars) + if not dirty_files: + if skip_no_changes: + return result + raise AnsibleActionFail('Nothing to commit') + + if allowlist: + unexpected = [ + path for path in dirty_files + if not any([pattern.fullmatch(path) for pattern in allowlist]) + ] + if unexpected: + raise AnsibleActionFail(f"Unexpected modifications in repository:\n{'\n'.join(unexpected)}") + + return self._commit(msg, task_vars) + + def _get_dirty_file_list(self, repo_dir, task_vars): + status = self._get_status(repo_dir, task_vars) + status = status.splitlines() + status = [line[3:] for line in status] + return status + + def _get_status(self, repo_dir, task_vars): + cmd_result = self._execute_module( + module_name='ansible.builtin.command', + module_args=dict( + argv=['git', 'status', '--porcelain'], + chdir=repo_dir, + ), + task_vars=task_vars, + ) + if cmd_result.get('failed'): + raise AnsibleActionFail(f"Couldn't get git status for {repo_dir}", result=cmd_result) + return cmd_result['stdout'] + + def _commit(self, msg, task_vars): + cmd_result = self._execute_module( + module_name='ansible.builtin.command', + module_args=dict( + argv=['etckeeper', 'commit', msg], + ), + task_vars=task_vars, + ) + if cmd_result.get('failed'): + raise AnsibleActionFail('etckeeper commit failed', result=cmd_result) + return cmd_result diff --git a/roles/etckeeper/handlers/commit.yml b/roles/etckeeper/handlers/commit.yml deleted file mode 100644 index de64614..0000000 --- a/roles/etckeeper/handlers/commit.yml +++ /dev/null @@ -1,30 +0,0 @@ -# This was copied to role etckeeper_commit. -# -# TODO: figure out how to dedupe this (handlers cannot use include_role). - -- name: Get list of modified files - become: true - ansible.builtin.shell: | - set -o pipefail && \ - git status --porcelain=v1 \ - | cut -c 4- \ - | grep -G -v {{ ('^' + (paths | map("regex_replace", "^/", "") | list | join("\|^"))) | quote }} - args: - chdir: /etc - vars: - ansible_shell_executable: /bin/bash - register: git_status - changed_when: false - failed_when: git_status.rc not in [0, 1] - -- name: Fail if unexpected files were modified - ansible.builtin.fail: - msg: | - Unexpected files were modified: - {{ git_status.stdout }} - when: git_status.rc == 0 - -- name: etckeeper commit - become: true - ansible.builtin.command: | - etckeeper commit {{ commit_msg | quote }} diff --git a/roles/etckeeper/handlers/main.yml b/roles/etckeeper/handlers/main.yml index 76c225e..c67dc02 100644 --- a/roles/etckeeper/handlers/main.yml +++ b/roles/etckeeper/handlers/main.yml @@ -1,13 +1,10 @@ - name: Commit etckeeper.conf - ansible.builtin.include_tasks: commit.yml - vars: - paths: [etckeeper/etckeeper.conf] - commit_msg: configure etckeeper + tensin.infra.etckeeper_commit: + msg: configure etckeeper + allowlist: [etckeeper/etckeeper.conf] listen: etckeeper_commit_conf - name: Commit .gitignore - ansible.builtin.include_tasks: commit.yml - vars: - paths: ['.*'] - commit_msg: configure ignored files + tensin.infra.etckeeper_commit: + msg: configure ignored files listen: etckeeper_commit_gitignore diff --git a/roles/etckeeper_commit/defaults/main.yml b/roles/etckeeper_commit/defaults/main.yml index 4a75c85..205b501 100644 --- a/roles/etckeeper_commit/defaults/main.yml +++ b/roles/etckeeper_commit/defaults/main.yml @@ -1,2 +1,2 @@ -#etckeeper_commit_paths: [] +#etckeeper_commit_allowlist: [] #etckeeper_commit_msg: '' diff --git a/roles/etckeeper_commit/tasks/main.yml b/roles/etckeeper_commit/tasks/main.yml index 94370d0..061942e 100644 --- a/roles/etckeeper_commit/tasks/main.yml +++ b/roles/etckeeper_commit/tasks/main.yml @@ -1,41 +1,6 @@ -# This was copied from role etckeeper's handlers. -# -# TODO: figure out how to dedupe this (handlers cannot use include_role). - -- name: Get list of modified files +- name: Run etckeeper commit become: true - ansible.builtin.shell: | - set -o pipefail && \ - git status --porcelain=v1 | cut -c 4- - args: - chdir: /etc - vars: - ansible_shell_executable: /bin/bash - register: git_status - changed_when: false - -- name: Try to commit if there're modified files - when: git_status.stdout_lines | length > 0 - block: - - name: Filter out expected modifications - ansible.builtin.shell: | - set -o pipefail && \ - echo {{ git_status.stdout | quote }} \ - | grep -G -v {{ ('^' + (etckeeper_commit_paths | map("regex_replace", "^/", "") | list | join("\|^"))) | quote }} - vars: - ansible_shell_executable: /bin/bash - register: unexpected_files - changed_when: false - failed_when: unexpected_files.rc not in [0, 1] - - - name: Fail if unexpected files were modified - ansible.builtin.fail: - msg: | - Unexpected files were modified: - {{ unexpected_files.stdout }} - when: unexpected_files.stdout_lines | length > 0 - - - name: etckeeper commit - become: true - ansible.builtin.command: | - etckeeper commit {{ etckeeper_commit_msg | quote }} + tensin.infra.etckeeper_commit: + msg: '{{ etckeeper_commit_msg }}' + allowlist: '{{ etckeeper_commit_allowlist }}' + skip_no_changes: true |
