在 Ansible 中备份配置文件更改,如果文件未更改,则自动删除备份



这是我想要的剧本流程:

  1. 备份我打算(可能(的远程 Linux 配置文件 修改。备份应持久保存到磁盘(在远程服务器上( 在运行我的主要更改任务之前(以防剧本崩溃 半路(。

  2. 执行多个可能会更改文件的 Ansible 任务。例如 2 行文件和 3 块文件任务。

  3. 如果文件已被 (2.( 中的任务更改。我想保留我的 备份文件。否则,应删除该文件。

此外,我想对多个配置文件(大约 10 个(做同样的事情,例如/etc/ssh/sshd_config/etc/ntp.conf等。我希望备份代码尽可能简洁。如何以最佳方式执行步骤 (1.( 和 (3.(?

我尝试/调查过:

  • 存在于许多文件修改中的backup参数 模块(lineinfile,blockinfile等(不是最佳的,因为它会 为每个任务调用创建一个备份。
  • 我宁愿避免post_tasks因为我希望我的主要任务在角色中执行,而角色没有任何执行post_tasks(?(的好方法。
  • 我查看了开发文档并考虑了 编写模块、动作插件或回调插件。但我没有 找到了任何现有的 API 钩子,可以将所有内容很好地联系在一起。

下面是一个关于如何仅针对 1 个配置文件执行此操作的幼稚而冗长的示例。对于另外 9 个配置文件,代码会变得更大。

---
- hosts: all
gather_facts: False
become: yes
tasks:
- name: Create temporary backup of /etc/ssh/sshd_config
copy:
src: "/etc/ssh/sshd_config"
remote_src: yes
dest: "/etc/ssh/sshd_config_{{ now().strftime('%Y-%m-%d_%H_%M_%S') }}.bak"
register: "sshd_config_backup"
changed_when: false
- name: Change sshd ciphers
lineinfile:
dest: /etc/ssh/sshd_config
regexp: '^Ciphers '
line: "Ciphers aes192-ctr"
notify: "sshd config changed"
# 3 more lineinfile/blockinfile tasks that (may) change the same file
# name: ...
# name: ...
# name: ...
# Removing backup file if not changed
- name: Get checksum of /etc/ssh/sshd_config
stat:
path: "/etc/ssh/sshd_config"
get_checksum: yes    
register: sshd_config_stat
- name: Remove backup of /etc/ssh/sshd_config if there are no changes
file:
path: "{{ sshd_config_backup.dest }}"
state: absent
changed_when: false
when: sshd_config_stat.stat.checksum == sshd_config_backup.checksum
handlers:
- name: Reload sshd service
listen: sshd config changed
service:
name: sshd
state: reloaded

下面的重头戏可能完成了你描述的工作

- name: conf_light
hosts: all
gather_facts: no
become: yes
vars_files:
- data1.yml
vars:
cl_backup: yes
tasks:
- name: Create time-stamp
when: cl_backup
set_fact:
cl_timestamp: "{{ '%Y-%m-%d_%H_%M_%S'|strftime }}"
- name: Create backup files
when: cl_backup
copy:
remote_src: yes
src: "{{ item.value.path }}"
dest: "{{ item.value.path }}_{{ cl_timestamp }}.bak"
loop: "{{ cl_confs|dict2items }}"
- name: Configure lines in files
lineinfile:
path: "{{ item.0.path }}"
regexp: "{{ item.1.regexp }}"
line: "{{ item.1.line }}"
loop: "{{ cl_confs|subelements('lines') }}"
notify: "{{ item.0.handler|default(omit) }}"
register: cl_results_lines
- name: Configure blocks in files
blockinfile:
path: "{{ item.0.path }}"
marker: "# {mark} ANSIBLE MANAGED BLOCK {{ item.1.marker }}"
block: "{{ item.1.block }}"
loop: "{{ cl_confs|subelements('blocks') }}"
notify: "{{ item.0.handler|default(omit) }}"
register: cl_results_blocks
- name: Remove backup files that did not change
when: cl_backup
file:
state: absent
path: "{{ item }}_{{ cl_timestamp }}.bak"
loop: "{{ cl_confs|
json_query('*.path')|
difference(cl_results_lines.results|default([])|
json_query('[?changed==`true`].invocation.module_args.path'))|
difference(cl_results_blocks.results|default([])|
json_query('[?changed==`true`].invocation.module_args.path'))
}}"
handlers:
- name: ssh reload
service:
name: ssh
state: reloaded

我已经在 Ubuntu 18.04 中使用以下数据对其进行了测试。(将数据适合任何其他Linux应该不是问题(

shell> cat data1.yml 
cl_confs:
sshd_config:
path: /etc/ssh/sshd_config
handler: ssh reload
lines:
- regexp: '^Ciphers '
line: 'Ciphers aes192-ctr'
blocks: []
ssh_config:
path: /etc/ssh/ssh_config
lines: []
blocks:
- marker: 'srv1.example.com'
block: |2
Host srv1.example.com
Protocol 2
ForwardAgent no

对于一个简单的角色来说,这似乎是个好主意。

最新更新