Ansible 复制覆盖

Ansible 复制覆盖

鉴于控制器上的树

shell> tree /tmp/test/
/tmp/test/
├── override
│   ├── dir1
│   │   └── file_B.txt
│   ├── file_2.txt
│   └── file_4.txt
└── template
    ├── dir1
    │   ├── file_A.txt
    │   └── file_B.txt
    ├── file_1.txt
    └── file_2.txt

4 directories, 7 files

将文件复制到远程主机:

  • file_1.txt 来自模板
  • file_2.txt 来自覆盖
  • file_4.txt 来自覆盖,即使它不在模板中
  • file_A.txt 来自模板
  • file_B.txt 来自覆盖

答案1

给定测试树

shell> tree /tmp/test
/tmp/test
├── override
│   ├── dir1
│   │   └── file_B.txt
│   ├── file_2.txt
│   └── file_4.txt
└── template
    ├── dir1
    │   ├── file_A.txt
    │   └── file_B.txt
    ├── file_1.txt
    └── file_2.txt

4 directories, 7 files
shell> find /tmp/test -type f | sort | xargs cat
override dir1 file_B.txt
override file_2.txt
override file_4.txt
template dir1 file_A.txt
template dir1 file_B.txt
template file_1.txt
template file_2.txt

声明路径和叠加层列表

  remote_path: /tmp/test
  local_path: /mnt/test
  overlays:
    - /tmp/test/override
    - /tmp/test/template

还有更多复制文件的选项

  1. 联合文件系统

安装包

    - name: Install unionfs
      package:
        name: unionfs-fuse
        state: present
      run_once: true
      delegate_to: localhost
      when: install|d(false)|bool

联合文件系统

    - name: Mount unionfs
      block:
        - file:
            state: directory
            path: "{{ local_path }}"
        - debug:
            msg: "dirs={{ overlays|product(['=ro'])|map('join')|join(':') }}"
        - mount:
            state: mounted
            path: "{{ local_path }}"
            fstype: unionfs
            opts: "allow_other,dirs={{ overlays|product(['=ro'])|map('join')|join(':') }}"
            src: dummy
      run_once: true
      delegate_to: localhost

挂载点已创建

shell> tree /mnt/test
/mnt/test
├── dir1
│   ├── file_A.txt
│   └── file_B.txt
├── file_1.txt
├── file_2.txt
└── file_4.txt

1 directory, 5 files

来自的文件覆盖替换了以下文件模板

shell> find /mnt/test -type f | sort | xargs cat
template dir1 file_A.txt
override dir1 file_B.txt
template file_1.txt
override file_2.txt
override file_4.txt

创建远程目录并同步文件

    - name: Create {{ remote_path }}
      file:
        state: directory
        path: "{{ remote_path }}"

    - name: Sync {{ local_path }} to {{ remote_path }}
      synchronize:
        src: "{{ local_path }}/"
        dest: "{{ remote_path }}"

文件已同步至远程主机

shell> ssh admin@test_13 find /tmp/test -type f | sort
/tmp/test/dir1/file_A.txt
/tmp/test/dir1/file_B.txt
/tmp/test/file_1.txt
/tmp/test/file_2.txt
/tmp/test/file_4.txt
shell> ssh admin@test_13 'find /tmp/test -type f | sort | xargs cat'
template dir1 file_A.txt
override dir1 file_B.txt
template file_1.txt
override file_2.txt
override file_4.txt

完整测试剧本的示例

- hosts: all
  become: true

  vars:

    remote_path: /tmp/test
    local_path: /mnt/test
    overlays:
      - /tmp/test/override
      - /tmp/test/template

  tasks:

    - name: Install unionfs
      package:
        name: unionfs-fuse
        state: present
      run_once: true
      delegate_to: localhost
      when: install|d(false)|bool

    - name: Mount unionfs
      block:
        - file:
            state: directory
            path: "{{ local_path }}"
        - debug:
            msg: "dirs={{ overlays|product(['=ro'])|map('join')|join(':') }}"
        - mount:
            state: mounted
            path: "{{ local_path }}"
            fstype: unionfs
            opts: "allow_other,dirs={{ overlays|product(['=ro'])|map('join')|join(':') }}"
            src: dummy
      run_once: true
      delegate_to: localhost

    - name: Create {{ remote_path }}
      file:
        state: directory
        path: "{{ remote_path }}"

    - name: Sync {{ local_path }} to {{ remote_path }}
      synchronize:
        src: "{{ local_path }}/"
        dest: "{{ remote_path }}"

    - name: Umount {{ local_path }}
      mount:
        state: unmounted
        path: "{{ local_path }}"
      run_once: true
      delegate_to: localhost
      when: umount|d(false)|bool

  1. 链接叠加层

如果你不能使用,你可以自己链接叠加层联合文件系统. 声明变量

  dirs: "{{ dirs_out.results|json_query('[].stdout_lines')|flatten|unique }}"
  files: "{{ files_out.results|json_query('[].stdout_lines') }}"
  files_dict: "{{ dict(overlays|zip([files.0, files.1|difference(files.0)])) }}"

创建目录并链接覆盖

    - name: Link overlays
      block:

        - name: Find directories
          command: "sh -c 'cd {{ item }}; find * -type d'"
          loop: "{{ overlays }}"
          register: dirs_out
          changed_when: false
        - debug:
            var: dirs|to_yaml
        - name: Create directories
          file:
            state: directory
            path: "{{ item }}"
          loop: "{{ [local_path]|product(dirs)|map('path_join') }}"

        - name: Find files
          command: "sh -c 'cd {{ item }}; find * -type f'"
          loop: "{{ overlays }}"
          register: files_out
          changed_when: false
        - debug:
            var: files|to_yaml
        - debug:
            var: files_dict|to_yaml
        - name: Link files
          file:
            state: link
            src: "{{ (item.0.key, item.1)|path_join }}"
            dest: "{{ (local_path, item.1)|path_join }}"
          with_subelements:
            - "{{ files_dict|dict2items }}"
            - value

      run_once: true
      delegate_to: localhost
shell> tree /mnt/test
/mnt/test
├── dir1
│   ├── file_A.txt -> /tmp/test/template/dir1/file_A.txt
│   └── file_B.txt -> /tmp/test/override/dir1/file_B.txt
├── file_1.txt -> /tmp/test/template/file_1.txt
├── file_2.txt -> /tmp/test/override/file_2.txt
└── file_4.txt -> /tmp/test/override/file_4.txt

1 directory, 5 files

创建远程目录并同步文件

    - name: Create {{ remote_path }}
      file:
        state: directory
        path: "{{ remote_path }}"

    - name: Sync {{ local_path }} to {{ remote_path }}
      synchronize:
        src: "{{ local_path }}/"
        dest: "{{ remote_path }}"
        copy_links: true

完整测试剧本的示例

- hosts: all
  become: true

  vars:

    remote_path: /tmp/test
    local_path: /mnt/test
    overlays:
      - /tmp/test/override
      - /tmp/test/template

    dirs: "{{ dirs_out.results|json_query('[].stdout_lines')|flatten|unique }}"
    files: "{{ files_out.results|json_query('[].stdout_lines') }}"
    files_dict: "{{ dict(overlays|zip([files.0, files.1|difference(files.0)])) }}"

  tasks:

    - name: Link overlays
      block:

        - name: Find directories
          command: "sh -c 'cd {{ item }}; find * -type d'"
          loop: "{{ overlays }}"
          register: dirs_out
          changed_when: false
        - debug:
            var: dirs|to_yaml
        - name: Create directories
          file:
            state: directory
            path: "{{ item }}"
          loop: "{{ [local_path]|product(dirs)|map('path_join') }}"

        - name: Find files
          command: "sh -c 'cd {{ item }}; find * -type f'"
          loop: "{{ overlays }}"
          register: files_out
          changed_when: false
        - debug:
            var: files|to_yaml
        - debug:
            var: files_dict|to_yaml
        - name: Link files
          file:
            state: link
            src: "{{ (item.0.key, item.1)|path_join }}"
            dest: "{{ (local_path, item.1)|path_join }}"
          with_subelements:
            - "{{ files_dict|dict2items }}"
            - value

      run_once: true
      delegate_to: localhost

    - name: Create {{ remote_path }}
      file:
        state: directory
        path: "{{ remote_path }}"

    - name: Sync {{ local_path }} to {{ remote_path }}
      synchronize:
        src: "{{ local_path }}/"
        dest: "{{ remote_path }}"
        copy_links: true

    - name: Unlink {{ local_path }}
      file:
        state: absent
        path: "{{ (local_path, item.1)|path_join }}"
      with_subelements:
        - "{{ files_dict|dict2items }}"
        - value
      run_once: true
      delegate_to: localhost
      when: umount|d(false)|bool

相关内容