鉴于控制器上的树
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
还有更多复制文件的选项
安装包
- 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
- 链接叠加层
如果你不能使用,你可以自己链接叠加层联合文件系统. 声明变量
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