ansible - 确保文件内容在服务器之间相同 [英] ansible - ensure content of file is the same across servers
问题描述
使用 Ansible 2.9.12
问题:如何配置 Ansible 以确保文件的内容在至少 3 台主机中相同,如果文件存在于至少一台主机上?
假设有 3 个主机.
主机 1 没有 /file.txt
.
主机 2 有 /file.txt
,内容为 hello
.
主机 3 有 /file.txt
,内容为 hello
.
在播放之前,我不知道该文件是否存在.因此该文件可能存在于 host1、host2 或 host3 上.但该文件至少存在于其中一台主机上.
我如何确保每次运行 Ansible 时,主机上的文件都是相等的.所以最终Host 1和Host 2或Host 3拥有相同的文件,内容相同.
我希望动态设置它,而不是指定主机名或组名,例如时间:inventory_hostname == host1
.
我不希望检查主机 2 和 3 的内容是否相等
不过,我希望以幂等方式进行设置.
我觉得下面的剧本就行了
shell>猫pb.yml- 主持人:所有任务:- 名称:获取状态.状态:路径:/file.txt注册:状态- 堵塞:- 名称:创建字典状态.设置事实:状态:{{dict(keys|zip(values))}}";变量:键:{{ ansible_play_hosts }}"值:"{{ ansible_play_hosts|map('extract', hostvars, ['status','stat','exists'])|列表}}"- 名称:失败.不存在文件.失败:msg: 文件不存在何时: status.values()|list 不存在- 名称:设置对存在文件的第一个主机的引用.设置事实:参考:"{{ status|dict2items|选择属性('值')|地图(属性='键')|第一个}}"- 名称:获取文件.拿来:源代码:/file.txt目标:/tmpdelegate_to:{{ 参考}}";run_once: 真- 名称:如果文件不存在则复制复制:src: "/tmp/{{ 参考 }}/file.txt";目标:/file.txt时间:不是状态[inventory_hostname]
但是,这不会检查现有文件是否同步.我认为同步所有主机会更安全
- 名称:同步文件同步:src: "/tmp/{{ 参考 }}/file.txt";目标:/file.txt时间:不是状态[inventory_hostname]
<小时><块引用>
问:致命的.无法在 Ansible 控制器上找到或访问 '/tmp/test-multi-01/file.txt.但是,文件夹/tmp/test-multi-03 存在,其中包含 file.txt.
A:fetch
模块,当任务被委派给另一个主机时.当 TASK [Fetch file.]
被委托给 test-multi-01
时,在这种情况下是本地主机 改变:[test-multi-03 ->127.0.0.1]
文件将从 test-multi-01
获取,但会存储在 /tmp/test-multi-03/file.txt
.结论是,fetch
模块在创建特定于主机的目录(尚未报告).
作为一种解决方法,可以设置 flat: true
并将文件存储在特定目录中.例如,在目录中添加变量sync_files_dir
,设置fetch flat: true
,并使用目录来获取和复制文件
- hosts: all变量:sync_files_dir:/tmp/sync_files任务:- 名称:获取状态.状态:路径:/file.txt注册:状态- 堵塞:- 名称:为要获取和同步的文件创建目录文件:状态:目录路径:{{sync_files_dir }}"delegate_to: 本地主机- 名称:创建字典状态.设置事实:状态:{{dict(keys|zip(values))}}";变量:键:{{ ansible_play_hosts }}"值:"{{ ansible_play_hosts|map('extract', hostvars, ['status','stat','exists'])|列表}}"- 调试:变量:状态- 名称:失败.不存在文件.失败:msg: 文件不存在何时: status.values()|list 不存在- 名称:设置对存在文件的第一个主机的引用.设置事实:参考:"{{ status|dict2items|选择属性('值')|地图(属性='键')|第一个}}"- 名称:获取文件.拿来:源代码:/file.txt目标:{{sync_files_dir }}/"平面:真实delegate_to:{{ 参考}}";run_once: 真- 名称:如果文件不存在则复制复制:源代码:{{sync_files_dir }}/file.txt";目标:/file.txt时间:不是状态[inventory_hostname]
Using Ansible 2.9.12
Question: How do I configure Ansible to ensure the contents of a file is equal amongst at least 3 hosts, when the file is present at at least one host?
Imagine there are 3 hosts.
Host 1 does not has /file.txt
.
Host 2 has /file.txt
with contents hello
.
Host 3 has /file.txt
with contents hello
.
Before the play is run, I am unaware whether the file is present or not. So the file could exist on host1, or host2 or host3. But the file exists on at least one of the hosts.
How would I ensure each time Ansible runs, the files across the hosts are equal. So in the end, Host 1 has the same file with the same contents as Host 2 or Host 3.
I'd like this to be dynamically set, instead of specifying the host names or group names, e.g. when: inventory_hostname == host1
.
I am not expecting a check to see whether the contents of host 2 and 3 are equal
I do however, want this to be setup in an idempotent fashion.
The play below does the job, I think
shell> cat pb.yml
- hosts: all
tasks:
- name: Get status.
stat:
path: /file.txt
register: status
- block:
- name: Create dictionary status.
set_fact:
status: "{{ dict(keys|zip(values)) }}"
vars:
keys: "{{ ansible_play_hosts }}"
values: "{{ ansible_play_hosts|
map('extract', hostvars, ['status','stat','exists'])|
list }}"
- name: Fail. No file exists.
fail:
msg: No file exists
when: status.values()|list is not any
- name: Set reference to first host with file present.
set_fact:
reference: "{{ status|dict2items|
selectattr('value')|
map(attribute='key')|
first }}"
- name: Fetch file.
fetch:
src: /file.txt
dest: /tmp
delegate_to: "{{ reference }}"
run_once: true
- name: Copy file if not exist
copy:
src: "/tmp/{{ reference }}/file.txt"
dest: /file.txt
when: not status[inventory_hostname]
But, this doesn't check the existing files are in sync. It would be safer to sync all hosts, I think
- name: Synchronize file
synchronize:
src: "/tmp/{{ reference }}/file.txt"
dest: /file.txt
when: not status[inventory_hostname]
Q: "FATAL. could not find or access '/tmp/test-multi-01/file.txt on the Ansible controller. However, folder /tmp/test-multi-03 is present with the file.txt in it."
A: There is a problem with the fetch
module when the task is delegated to another host. When the TASK [Fetch file.]
is delegated to test-multi-01
which is localhost in this case changed: [test-multi-03 -> 127.0.0.1]
the file will be fetched from test-multi-01
but will be stored in /tmp/test-multi-03/file.txt
. The conclusion is, the fetch
module ignores delegate_to
when it comes to creating host-specific directories (not reported yet).
As a workaround, it's possible to set flat: true
and store the files in a specific directory. For example, add the variable sync_files_dir
with the directory, set fetch flat: true
, and use the directory to both fetch and copy the file
- hosts: all
vars:
sync_files_dir: /tmp/sync_files
tasks:
- name: Get status.
stat:
path: /file.txt
register: status
- block:
- name: Create dir for files to be fetched and synced
file:
state: directory
path: "{{ sync_files_dir }}"
delegate_to: localhost
- name: Create dictionary status.
set_fact:
status: "{{ dict(keys|zip(values)) }}"
vars:
keys: "{{ ansible_play_hosts }}"
values: "{{ ansible_play_hosts|
map('extract', hostvars, ['status','stat','exists'])|
list }}"
- debug:
var: status
- name: Fail. No file exists.
fail:
msg: No file exists
when: status.values()|list is not any
- name: Set reference to first host with file present.
set_fact:
reference: "{{ status|dict2items|
selectattr('value')|
map(attribute='key')|
first }}"
- name: Fetch file.
fetch:
src: /file.txt
dest: "{{ sync_files_dir }}/"
flat: true
delegate_to: "{{ reference }}"
run_once: true
- name: Copy file if not exist
copy:
src: "{{ sync_files_dir }}/file.txt"
dest: /file.txt
when: not status[inventory_hostname]
这篇关于ansible - 确保文件内容在服务器之间相同的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!