在 Ansible 中获取本地目录(包含模板)的非递归列表

问题描述 投票:0回答:3

我有一堆目录,其中包含类似的模板文件。
像这样的东西:

/ansible/
└── roles
    └── webserver
        ├── tasks
        │   └── main.yml
        └── templates
            └── sites
                ├── bar
                │   ├── index.html
                │   ├── script.js
                │   ├── style.css
                │   └── webapp.conf
                ├── baz
                │   ├── index.html
                │   ├── script.js
                │   ├── style.css
                │   └── webapp.conf
                └── foo
                    ├── index.html
                    ├── script.js
                    ├── style.css
                    └── webapp.conf

在任务中,我想列出目录(

bar
baz
foo
,以及我在那里创建的任何新目录)并将模板操作应用于它们的文件。

我试过使用

with_fileglob
但它不能列出目录(只有文件,它会忽略目录)。

- name: Template index.html
   template:
     src: "sites/{{item}}/index.html"
     dest: "/var/www/{{item}}/index.html"
   with_fileglob: "templates/sites/*"

还有一个回归以至于它甚至无法在目录中找到带有glob的文件。

- name: Template index.html
   template:
     src: "sites/{{item}}"
     dest: "/var/www/{{item}}/index.html"
   with_fileglob: "templates/sites/*/index.html"

我试过了

find
,但我无法让它在本地模板目录上工作(它似乎在主机上找到了东西。)

我试过了

filetree

- name: Template index.html
   template:
     src: "sites/{{item.path}}"
     dest: "/var/www/{{item.path}}/index.html"
   with_filetree: "templates/sites/"
   when: item.state == 'directory'

但是它:

  • 是递归的(即使我使用
    when
    将其限制为目录,它返回子目录)
  • 打印关于所有它跳过的东西的恼人消息

有没有办法在我的本地模板目录中获取我所有站点的列表?

ansible glob subdirectory
3个回答
2
投票

如果你想使用

filetree
并使其不那么冗长并满足你的需要,你可以将它用作查找,而不是作为
with_*
循环。

这样你就可以在

selectattr
rejectattr
过滤器的帮助下进行预过滤:

例如:

- debug:
    msg: "{{ item.path }}"
  loop: >-
    {{
      lookup('community.general.filetree', 'templates/sites')
        | selectattr('state', '==', 'directory')
        | rejectattr('path', 'contains', '/')
    }}
  loop_control:
    label: "{{ item.path }}"

在这个任务中:

  • selectattr('state', '==', 'directory')
    将确保您只列出目录
  • rejectattr('path', 'contains', '/')
    将拒绝包含
    /
    的路径,因此有效地排除了子目录
  • loop_control
    及其参数
    label: "{{ item.path }}"
    将使复杂词典上的循环不那么冗长

或者您可以使用 JMESPath,因为您确实部分使用了它,但过滤可以是查询的一部分:

- debug:
    msg: "{{ item }}"
  loop: >-
    {{
      lookup('community.general.filetree', 'templates/sites')
        | json_query('[?state == `directory` && !contains(path, `/`)].path')
    }}

鉴于文件结构:

.
└── templates
    └── sites
        ├── bar
        │   ├── baz
        │   └── index.html
        └── foo
            └── index.html

baz
是一个子目录,上面的两个任务都会产生:

ok: [localhost] => (item=bar) => 
  msg: bar
ok: [localhost] => (item=foo) => 
  msg: foo

2
投票

简而言之,使用您之前引用的

find
模块

roles/webserver/vars/main.yml

---
available_sites: "{{ find_sites_subdirs.files | d([]) 
  | map(attribute='path') | map('basename') }}"

注意:

d
default
的别名,只是为了避免在运行下面的
find
之前使用 var 时出现错误(在这种情况下它将是一个空列表)

然后在

roles/webserver/tasks/main.yml

---
- name: Find sites subdirs
  ansible.builtin.find:
    paths:
      - "{{ role_path }}/templates/sites"
    file_type: directory
    recurse: false
  register: find_sites_subdirs
  delegate_to: localhost
  run_once: true

- name: Template index.html
  ansible.builtin.template:
    src: "sites/{{ item }}/index.html"
    dest: "/var/www/{{ item }}/index.html"
  loop: "{{ available_sites }}"

1
投票

我找到了一种使用

filetree
和一些管道的方法,可以将其过滤到基本目录。

- name: Template index.html
  template:
    src: "sites/{{item}}"
    dest: "/var/www/{{item}}/index.html"
  with: >-
    {{
      lookup('filetree', 'templates/sites')
      | selectattr('state', 'eq', 'directory')
      | rejectattr('path', 'contains', '/')
      | map(attribute='path')
      | list
    }}
  • lookup('filetree', 'templates/sites')
    做目录的递归扫描
  • selectattr('state', 'eq', 'directory')
    过滤掉文件
  • rejectattr('path', 'contains', '/')
    过滤掉子目录
  • map(attribute='path')
    仅返回
    item.path
    的列表,而不是包含大量无关字段的完整对象。
  • list
    将其转换为可与
    with:
  • 一起使用的列表

要多次使用这个列表,把它放在一个变量中效率会更高。它可以像这样进入

roles/webserver/vars/main.yml

my_sites: >-
  {{
    lookup('filetree', 'templates/sites')
    | selectattr('state', 'eq', 'directory')
    | rejectattr('path', 'contains', '/')
    | map(attribute='path')
    | list
  }}

然后模板就可以使用

with: "{{my_sites}}"

© www.soinside.com 2019 - 2024. All rights reserved.