包含文件夹和文件的嵌套模板

Nested templating with folders and files

有一个变量包含一个值为 foo 的名称。只有这个名字 'special' 必须进行模板化。文件夹名称、文件名和内容必须模板化 2 次,一次不添加任何内容。其余文件也必须模板化,但不进行特殊处理。让我描述一下我的问题:

这是我的变量:

bar:
  - name: something
  - name: foo

这是我在 Ansible 中的模板目录:

templates/foo/another_folder/foo.spec
templates/foo/folder_folder/folder2/some_file/foo.service
templates/foo/some_file.txt
templates/something/ignore.txt

foo.spec的内容:

name: foo

在目标机器上拥有目录结构的目标:

foo/another_folder/foo.spec
foo/folder_folder/folder2/some_file/foo.service
foo/some_file.txt

foo-1/another_folder/foo-1.spec
foo-1/folder_folder/folder2/some_file/foo-1.service
foo-1/some_file.txt

foo-2/another_folder/foo-2.spec
foo-2/folder_folder/folder2/some_file/foo-2.service
foo-2/some_file.txt

something/ignore.txt

每个 foo.spec 的内容应模板化为:

# for foo:
name: foo
--
# for foo-1
name: foo-1
--
# for foo-2
name: foo-2

为了解决我的问题,我看了一个类似的问题,就是。但是,我根本不知道从哪里开始。这可以在 Ansible 中配置吗?

这是一个相当尴尬的要求,但制定解决方案很有趣,所以我们开始吧。

以下解决方案理所当然地认为您的模板与部署它们的目标文件具有完全相同的文件名。如果您想向它们添加 j2 扩展,请参阅 examples in the filetree documentation 以在模板化目标时将其删除。

在 ansible 中不可能在同一任务中重叠循环。解决方案是循环 include_tasks 并在包含的文件中添加更多循环。

基本操作是将整个文件树模板化到目标目录,因此这将是我们最终包含的文件。在这两者之间,我们只需要检测我们是否处于 foo 我们想要在一个整数范围内循环 X 次的情况,或者在我们只处理目录一次的默认情况下。

我在测试中使用了您在问题中介绍的完全相同的文件树。唯一的变化是 foo/another_folder/foo.spec 的内容现在是:

name: {{ spec_name }}

让我们从基础剧本开始 deploy.yml

---
- name: my bizare templating pattern
  hosts: localhost
  gather_facts: false

  vars:
    bar:
      - name: something
      - name: foo

    target_base_dir: /tmp/example/

  tasks:
    - name: make sure target base dir exists
      file:
        path: "{{ target_base_dir }}"
        state: directory

    - name: load template pattern chooser file
      include_tasks: "template_pattern_chooser.yml"
      loop: "{{ bar }}"
      loop_control:
        loop_var: template_pattern

这是随附的 template_pattern_chooser.yml

---
- name: Select the corresponding templating pattern
  vars:
    find_me:
      - "pattern_{{ template_pattern.name }}.yml"
      - "pattern_default.yml"
  include_tasks: "{{ lookup('first_found', find_me) }}"

如您所见,这将查找以模板模式名称命名的特定文件或回退到默认文件。

这是具体的 pattern_foo.yml。请注意,这是设置上面模板中使用的 var spec_name 的地方。

---
- name: "loop over our {{ template_pattern.name }} pattern"
  vars:
    target_dir_name: "{{ template_pattern.name }}-{{ pattern_iteration }}"
    spec_name: "{{ target_dir_name }}"
  include_tasks: "template_tree.yml"
  loop: "{{ range(1,4) | list }}"
  loop_control:
    loop_var: pattern_iteration

pattern_default.yml:

---
- name: default templating pattern
  vars:
    target_dir_name: "{{ template_pattern.name }}"
  include_tasks: template_tree.yml

请注意,这两个文件包含相同的 template_tree.yml 文件。唯一的变化是我们在处理 foo 模式时循环它。这是真正的工作发生的地方:

---
- name: Get list of templates only once
  set_fact:
    template_tree: "{{ query('filetree', 'templates/' ~ template_pattern.name ~ '/') }}"

- name: Create needed target dir
  file:
    path: "{{ target_base_dir }}/{{ target_dir_name }}"
    state: "directory"

- name: Create needed directories inside target
  file:
    path: "{{ target_base_dir }}/{{ target_dir_name }}/{{ item.path }}"
    state: "{{ item.state }}"
  loop: "{{ template_tree }}"
  when: item.state == 'directory'

- name: Deploy templates
  template:
    src: "{{ item.src }}"
    dest: "{{ target_base_dir }}/{{ target_dir_name }}/{{ item.path }}"
  loop: "{{ template_tree }}"
  when: item.state == 'file'

运行 这是在我的机器上进行的测试:

$ ansible-playbook deploy.yml 

PLAY [my bizare templating pattern] *****************************************************************************

TASK [make sure target base dir exists] *****************************************************************************
changed: [localhost]

TASK [load template pattern chooser file] *****************************************************************************
included: /home/user/test/template_pattern_chooser.yml for localhost => (item={'name': 'something'})
included: /home/user/test/template_pattern_chooser.yml for localhost => (item={'name': 'foo'})

TASK [Select the corresponding templating pattern] *****************************************************************************
included: /home/user/test/pattern_default.yml for localhost

TASK [default templating pattern] *****************************************************************************
included: /home/user/test/template_tree.yml for localhost

TASK [Get list of templates only once] *****************************************************************************
ok: [localhost]

TASK [Create needed target dir] *****************************************************************************
changed: [localhost]

TASK [Create needed directories inside target] *****************************************************************************
skipping: [localhost] => (item={'root': '/home/user/test/templates/something/', 'path': 'ignore.txt', 'state': 'file', 'src': '/home/user/test/templates/something/ignore.txt', 'uid': 1000, 'gid': 100, 'owner': 'user', 'group': 'users', 'mode': '0644', 'size': 6, 'mtime': 1640280116.3296282, 'ctime': 1640280116.3296282}) 

TASK [Deploy templates] *****************************************************************************
changed: [localhost] => (item={'root': '/home/user/test/templates/something/', 'path': 'ignore.txt', 'state': 'file', 'src': '/home/user/test/templates/something/ignore.txt', 'uid': 1000, 'gid': 100, 'owner': 'user', 'group': 'users', 'mode': '0644', 'size': 6, 'mtime': 1640280116.3296282, 'ctime': 1640280116.3296282})

TASK [Select the corresponding templating pattern] *****************************************************************************
included: /home/user/test/pattern_foo.yml for localhost

TASK [loop over our foo pattern] *****************************************************************************
included: /home/user/test/template_tree.yml for localhost => (item=1)
included: /home/user/test/template_tree.yml for localhost => (item=2)
included: /home/user/test/template_tree.yml for localhost => (item=3)

TASK [Get list of templates only once] *****************************************************************************
ok: [localhost]

TASK [Create needed target dir] *****************************************************************************
changed: [localhost]

TASK [Create needed directories inside target] *****************************************************************************
changed: [localhost] => (item={'root': '/home/user/test/templates/foo/', 'path': 'folder_folder', 'state': 'directory', 'uid': 1000, 'gid': 100, 'owner': 'user', 'group': 'users', 'mode': '0755', 'size': 3, 'mtime': 1640280024.0969715, 'ctime': 1640280024.0969715})
changed: [localhost] => (item={'root': '/home/user/test/templates/foo/', 'path': 'another_folder', 'state': 'directory', 'uid': 1000, 'gid': 100, 'owner': 'user', 'group': 'users', 'mode': '0755', 'size': 3, 'mtime': 1640279254.875486, 'ctime': 1640279254.875486})
skipping: [localhost] => (item={'root': '/home/user/test/templates/foo/', 'path': 'some_file.txt', 'state': 'file', 'src': '/home/user/test/templates/foo/some_file.txt', 'uid': 1000, 'gid': 100, 'owner': 'user', 'group': 'users', 'mode': '0644', 'size': 4, 'mtime': 1640280116.3376281, 'ctime': 1640280116.3376281}) 
changed: [localhost] => (item={'root': '/home/user/test/templates/foo/', 'path': 'folder_folder/some_file', 'state': 'directory', 'uid': 1000, 'gid': 100, 'owner': 'user', 'group': 'users', 'mode': '0755', 'size': 3, 'mtime': 1640280051.5691671, 'ctime': 1640280051.5691671})
skipping: [localhost] => (item={'root': '/home/user/test/templates/foo/', 'path': 'folder_folder/some_file/foo.service', 'state': 'file', 'src': '/home/user/test/templates/foo/folder_folder/some_file/foo.service', 'uid': 1000, 'gid': 100, 'owner': 'user', 'group': 'users', 'mode': '0644', 'size': 4, 'mtime': 1640280051.561167, 'ctime': 1640280051.561167}) 
skipping: [localhost] => (item={'root': '/home/user/test/templates/foo/', 'path': 'another_folder/foo.spec', 'state': 'file', 'src': '/home/user/test/templates/foo/another_folder/foo.spec', 'uid': 1000, 'gid': 100, 'owner': 'user', 'group': 'users', 'mode': '0644', 'size': 21, 'mtime': 1640279254.871486, 'ctime': 1640279254.871486}) 

TASK [Deploy templates] *****************************************************************************
skipping: [localhost] => (item={'root': '/home/user/test/templates/foo/', 'path': 'folder_folder', 'state': 'directory', 'uid': 1000, 'gid': 100, 'owner': 'user', 'group': 'users', 'mode': '0755', 'size': 3, 'mtime': 1640280024.0969715, 'ctime': 1640280024.0969715}) 
skipping: [localhost] => (item={'root': '/home/user/test/templates/foo/', 'path': 'another_folder', 'state': 'directory', 'uid': 1000, 'gid': 100, 'owner': 'user', 'group': 'users', 'mode': '0755', 'size': 3, 'mtime': 1640279254.875486, 'ctime': 1640279254.875486}) 
changed: [localhost] => (item={'root': '/home/user/test/templates/foo/', 'path': 'some_file.txt', 'state': 'file', 'src': '/home/user/test/templates/foo/some_file.txt', 'uid': 1000, 'gid': 100, 'owner': 'user', 'group': 'users', 'mode': '0644', 'size': 4, 'mtime': 1640280116.3376281, 'ctime': 1640280116.3376281})
skipping: [localhost] => (item={'root': '/home/user/test/templates/foo/', 'path': 'folder_folder/some_file', 'state': 'directory', 'uid': 1000, 'gid': 100, 'owner': 'user', 'group': 'users', 'mode': '0755', 'size': 3, 'mtime': 1640280051.5691671, 'ctime': 1640280051.5691671}) 
changed: [localhost] => (item={'root': '/home/user/test/templates/foo/', 'path': 'folder_folder/some_file/foo.service', 'state': 'file', 'src': '/home/user/test/templates/foo/folder_folder/some_file/foo.service', 'uid': 1000, 'gid': 100, 'owner': 'user', 'group': 'users', 'mode': '0644', 'size': 4, 'mtime': 1640280051.561167, 'ctime': 1640280051.561167})
changed: [localhost] => (item={'root': '/home/user/test/templates/foo/', 'path': 'another_folder/foo.spec', 'state': 'file', 'src': '/home/user/test/templates/foo/another_folder/foo.spec', 'uid': 1000, 'gid': 100, 'owner': 'user', 'group': 'users', 'mode': '0644', 'size': 21, 'mtime': 1640279254.871486, 'ctime': 1640279254.871486})

TASK [Get list of templates only once] *****************************************************************************
ok: [localhost]

TASK [Create needed target dir] *****************************************************************************
changed: [localhost]

TASK [Create needed directories inside target] *****************************************************************************
changed: [localhost] => (item={'root': '/home/user/test/templates/foo/', 'path': 'folder_folder', 'state': 'directory', 'uid': 1000, 'gid': 100, 'owner': 'user', 'group': 'users', 'mode': '0755', 'size': 3, 'mtime': 1640280024.0969715, 'ctime': 1640280024.0969715})
changed: [localhost] => (item={'root': '/home/user/test/templates/foo/', 'path': 'another_folder', 'state': 'directory', 'uid': 1000, 'gid': 100, 'owner': 'user', 'group': 'users', 'mode': '0755', 'size': 3, 'mtime': 1640279254.875486, 'ctime': 1640279254.875486})
skipping: [localhost] => (item={'root': '/home/user/test/templates/foo/', 'path': 'some_file.txt', 'state': 'file', 'src': '/home/user/test/templates/foo/some_file.txt', 'uid': 1000, 'gid': 100, 'owner': 'user', 'group': 'users', 'mode': '0644', 'size': 4, 'mtime': 1640280116.3376281, 'ctime': 1640280116.3376281}) 
changed: [localhost] => (item={'root': '/home/user/test/templates/foo/', 'path': 'folder_folder/some_file', 'state': 'directory', 'uid': 1000, 'gid': 100, 'owner': 'user', 'group': 'users', 'mode': '0755', 'size': 3, 'mtime': 1640280051.5691671, 'ctime': 1640280051.5691671})
skipping: [localhost] => (item={'root': '/home/user/test/templates/foo/', 'path': 'folder_folder/some_file/foo.service', 'state': 'file', 'src': '/home/user/test/templates/foo/folder_folder/some_file/foo.service', 'uid': 1000, 'gid': 100, 'owner': 'user', 'group': 'users', 'mode': '0644', 'size': 4, 'mtime': 1640280051.561167, 'ctime': 1640280051.561167}) 
skipping: [localhost] => (item={'root': '/home/user/test/templates/foo/', 'path': 'another_folder/foo.spec', 'state': 'file', 'src': '/home/user/test/templates/foo/another_folder/foo.spec', 'uid': 1000, 'gid': 100, 'owner': 'user', 'group': 'users', 'mode': '0644', 'size': 21, 'mtime': 1640279254.871486, 'ctime': 1640279254.871486}) 

TASK [Deploy templates] *****************************************************************************
skipping: [localhost] => (item={'root': '/home/user/test/templates/foo/', 'path': 'folder_folder', 'state': 'directory', 'uid': 1000, 'gid': 100, 'owner': 'user', 'group': 'users', 'mode': '0755', 'size': 3, 'mtime': 1640280024.0969715, 'ctime': 1640280024.0969715}) 
skipping: [localhost] => (item={'root': '/home/user/test/templates/foo/', 'path': 'another_folder', 'state': 'directory', 'uid': 1000, 'gid': 100, 'owner': 'user', 'group': 'users', 'mode': '0755', 'size': 3, 'mtime': 1640279254.875486, 'ctime': 1640279254.875486}) 
changed: [localhost] => (item={'root': '/home/user/test/templates/foo/', 'path': 'some_file.txt', 'state': 'file', 'src': '/home/user/test/templates/foo/some_file.txt', 'uid': 1000, 'gid': 100, 'owner': 'user', 'group': 'users', 'mode': '0644', 'size': 4, 'mtime': 1640280116.3376281, 'ctime': 1640280116.3376281})
skipping: [localhost] => (item={'root': '/home/user/test/templates/foo/', 'path': 'folder_folder/some_file', 'state': 'directory', 'uid': 1000, 'gid': 100, 'owner': 'user', 'group': 'users', 'mode': '0755', 'size': 3, 'mtime': 1640280051.5691671, 'ctime': 1640280051.5691671}) 
changed: [localhost] => (item={'root': '/home/user/test/templates/foo/', 'path': 'folder_folder/some_file/foo.service', 'state': 'file', 'src': '/home/user/test/templates/foo/folder_folder/some_file/foo.service', 'uid': 1000, 'gid': 100, 'owner': 'user', 'group': 'users', 'mode': '0644', 'size': 4, 'mtime': 1640280051.561167, 'ctime': 1640280051.561167})
changed: [localhost] => (item={'root': '/home/user/test/templates/foo/', 'path': 'another_folder/foo.spec', 'state': 'file', 'src': '/home/user/test/templates/foo/another_folder/foo.spec', 'uid': 1000, 'gid': 100, 'owner': 'user', 'group': 'users', 'mode': '0644', 'size': 21, 'mtime': 1640279254.871486, 'ctime': 1640279254.871486})

TASK [Get list of templates only once] *****************************************************************************
ok: [localhost]

TASK [Create needed target dir] *****************************************************************************
changed: [localhost]

TASK [Create needed directories inside target] *****************************************************************************
changed: [localhost] => (item={'root': '/home/user/test/templates/foo/', 'path': 'folder_folder', 'state': 'directory', 'uid': 1000, 'gid': 100, 'owner': 'user', 'group': 'users', 'mode': '0755', 'size': 3, 'mtime': 1640280024.0969715, 'ctime': 1640280024.0969715})
changed: [localhost] => (item={'root': '/home/user/test/templates/foo/', 'path': 'another_folder', 'state': 'directory', 'uid': 1000, 'gid': 100, 'owner': 'user', 'group': 'users', 'mode': '0755', 'size': 3, 'mtime': 1640279254.875486, 'ctime': 1640279254.875486})
skipping: [localhost] => (item={'root': '/home/user/test/templates/foo/', 'path': 'some_file.txt', 'state': 'file', 'src': '/home/user/test/templates/foo/some_file.txt', 'uid': 1000, 'gid': 100, 'owner': 'user', 'group': 'users', 'mode': '0644', 'size': 4, 'mtime': 1640280116.3376281, 'ctime': 1640280116.3376281}) 
changed: [localhost] => (item={'root': '/home/user/test/templates/foo/', 'path': 'folder_folder/some_file', 'state': 'directory', 'uid': 1000, 'gid': 100, 'owner': 'user', 'group': 'users', 'mode': '0755', 'size': 3, 'mtime': 1640280051.5691671, 'ctime': 1640280051.5691671})
skipping: [localhost] => (item={'root': '/home/user/test/templates/foo/', 'path': 'folder_folder/some_file/foo.service', 'state': 'file', 'src': '/home/user/test/templates/foo/folder_folder/some_file/foo.service', 'uid': 1000, 'gid': 100, 'owner': 'user', 'group': 'users', 'mode': '0644', 'size': 4, 'mtime': 1640280051.561167, 'ctime': 1640280051.561167}) 
skipping: [localhost] => (item={'root': '/home/user/test/templates/foo/', 'path': 'another_folder/foo.spec', 'state': 'file', 'src': '/home/user/test/templates/foo/another_folder/foo.spec', 'uid': 1000, 'gid': 100, 'owner': 'user', 'group': 'users', 'mode': '0644', 'size': 21, 'mtime': 1640279254.871486, 'ctime': 1640279254.871486}) 

TASK [Deploy templates] *****************************************************************************
skipping: [localhost] => (item={'root': '/home/user/test/templates/foo/', 'path': 'folder_folder', 'state': 'directory', 'uid': 1000, 'gid': 100, 'owner': 'user', 'group': 'users', 'mode': '0755', 'size': 3, 'mtime': 1640280024.0969715, 'ctime': 1640280024.0969715}) 
skipping: [localhost] => (item={'root': '/home/user/test/templates/foo/', 'path': 'another_folder', 'state': 'directory', 'uid': 1000, 'gid': 100, 'owner': 'user', 'group': 'users', 'mode': '0755', 'size': 3, 'mtime': 1640279254.875486, 'ctime': 1640279254.875486}) 
changed: [localhost] => (item={'root': '/home/user/test/templates/foo/', 'path': 'some_file.txt', 'state': 'file', 'src': '/home/user/test/templates/foo/some_file.txt', 'uid': 1000, 'gid': 100, 'owner': 'user', 'group': 'users', 'mode': '0644', 'size': 4, 'mtime': 1640280116.3376281, 'ctime': 1640280116.3376281})
skipping: [localhost] => (item={'root': '/home/user/test/templates/foo/', 'path': 'folder_folder/some_file', 'state': 'directory', 'uid': 1000, 'gid': 100, 'owner': 'user', 'group': 'users', 'mode': '0755', 'size': 3, 'mtime': 1640280051.5691671, 'ctime': 1640280051.5691671}) 
changed: [localhost] => (item={'root': '/home/user/test/templates/foo/', 'path': 'folder_folder/some_file/foo.service', 'state': 'file', 'src': '/home/user/test/templates/foo/folder_folder/some_file/foo.service', 'uid': 1000, 'gid': 100, 'owner': 'user', 'group': 'users', 'mode': '0644', 'size': 4, 'mtime': 1640280051.561167, 'ctime': 1640280051.561167})
changed: [localhost] => (item={'root': '/home/user/test/templates/foo/', 'path': 'another_folder/foo.spec', 'state': 'file', 'src': '/home/user/test/templates/foo/another_folder/foo.spec', 'uid': 1000, 'gid': 100, 'owner': 'user', 'group': 'users', 'mode': '0644', 'size': 21, 'mtime': 1640279254.871486, 'ctime': 1640279254.871486})

PLAY RECAP *****************************************************************************
localhost                  : ok=24   changed=12   unreachable=0    failed=0    skipped=1    rescued=0    ignored=0

这是目标目录中的结果:

$ tree /tmp/example/
/tmp/example/
├── foo-1
│   ├── another_folder
│   │   └── foo.spec
│   ├── folder_folder
│   │   └── some_file
│   │       └── foo.service
│   └── some_file.txt
├── foo-2
│   ├── another_folder
│   │   └── foo.spec
│   ├── folder_folder
│   │   └── some_file
│   │       └── foo.service
│   └── some_file.txt
├── foo-3
│   ├── another_folder
│   │   └── foo.spec
│   ├── folder_folder
│   │   └── some_file
│   │       └── foo.service
│   └── some_file.txt
└── something
    └── ignore.txt

13 directories, 10 files

例如 foo.spec 个文件的内容:

$ cat /tmp/example/foo-2/another_folder/foo.spec 
name: foo-2