Score:0

Ansible copy overlays

br flag

Given the tree on the controller

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

Copy the files to the remote host:

  • file_1.txt From template
  • file_2.txt From override
  • file_4.txt From override, even if it is not in template
  • file_A.txt From template
  • file_B.txt From override
Score:0
br flag

Given the tree for testing

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

Declare the paths and the list of overlays

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

There are more options how to copy the files

  1. unionfs

Install the package

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

Mount unionfs

    - 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

The mount point was created

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

The files from override replaced the files from template

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

Create the remote directory and synchronize the 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 }}"

The files were synchronized to the remote host

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

Example of a complete playbook for testing

- 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. Link the overlays

You can link the overlays on your own if you can't use unionfs. Declare the variables

  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)])) }}"

Create the directories and link the overlays

    - 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

Create the remote directory and synchronize the 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

Example of a complete playbook for testing

- 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
I sit in a Tesla and translated this thread with Ai:

mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.