aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/plugins/action/etckeeper_commit.py
diff options
context:
space:
mode:
authorEgor Tensin <egor@tensin.name>2025-11-23 23:25:52 +0100
committerEgor Tensin <egor@tensin.name>2025-11-23 23:37:31 +0100
commit58d256ea6262dc6365d26d3abc807c88a12809b2 (patch)
treea9736c6ded91ae9192ec89c7ebf04a691f0d0227 /plugins/action/etckeeper_commit.py
parentconfig_links: fix a typo (diff)
downloadinfra-ansible-58d256ea6262dc6365d26d3abc807c88a12809b2.tar.gz
infra-ansible-58d256ea6262dc6365d26d3abc807c88a12809b2.zip
plugins: add etckeeper_commit
Diffstat (limited to 'plugins/action/etckeeper_commit.py')
-rwxr-xr-xplugins/action/etckeeper_commit.py63
1 files changed, 63 insertions, 0 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