ansible - 确保文件内容在服务器之间相同 [英] ansible - ensure content of file is the same across servers

查看:42
本文介绍了ansible - 确保文件内容在服务器之间相同的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆