ansible 嵌套循环 fileglob ansible 字典 with_nested

ansible nested loop fileglob ansible dictionary with_nested

假设我有以下树:

foo/
├─ bar/
│  ├─ secret/
│  │  ├─ directory_1/
│  │  │  ├─ file1
│  │  │  ├─ file2
│  │  ├─ directory_2/
│  │  │  ├─ file3
│  │  │  ├─ file4

我不知道这些文件是什么,里面有多少directory_1directory_2 我希望能够在它们内部循环并列出它们。

我有以下 ansible dict :

my_directory_list:
  var1: secret_dir
  file:
    - directory: directory_1
      secret_name: secret_1
    - directory: directory_2
      secret_name: secret_2

和以下任务:

- name: "my task"
  shell: echo ' in my directory : {{item.0.directory}} i have {{item.1}} '
  with_nested:
    - "{{my_root_directory.file}}"
    - "{{ lookup('fileglob', '/foo/bar/secret/{{item.0.directory}}') }}"

和预期的输出:

in my directory directory_1 i have file1
in my directory directory_1 i have file2
in my directory directory_2 i have file3
in my directory directory_2 i have file4

但我无法让它工作,因为 ansible 列表是空的,我试过了:

- "{{ lookup('fileglob', '/foo/bar/secret/{{item.0.directory}}').split(',') }}"

但列表仍然是空的,我做错了什么?是否可以仅使用 ansible 实现这种输出?没有 jinja/python ?

感谢您的帮助,

首先,您的剧本中有几个语法错误会阻止它运行 根本

引用错误

如果您在 YAML 值中使用引号,则必须引用整个内容。所以当你写:

- name: "my task"
  shell: echo ' in my directory : {{item.0.directory}} i have {{item.1}} '

shell: 键的值会导致错误:

ERROR! We were unable to read either as JSON nor YAML, these are the errors we got from each:
JSON: Expecting value: line 1 column 1 (char 0)

Syntax Error while loading YAML.
  mapping values are not allowed in this context

您需要将整个值放在引号中,如下所示:

- name: "my task"
  shell: "echo ' in my directory : {{item.0.directory}} i have {{item.1}} '"

我更喜欢使用 YAML 的块引用运算符之一,如下所示:

- name: "my task"
  shell: >-
    echo ' in my directory : {{item.0.directory}} i have {{item.1}} '

这避免了在需要使用时必须玩引号转义游戏 命令行中的双引号和单引号。

变量替换错误

您永远不会嵌套 Jinja 模板标记 ({{...}})。当你写:

- "{{ lookup('fileglob', '/foo/bar/secret/{{item.0.directory}}') }}"

您最终将文字字符串 /foo/bar/secret/{{item.0.directory}} 传递给 fileglob 查找。您需要这样写:

- "{{ lookup('fileglob', '/foo/bar/secret/' ~ item.0.directory) }}"

其中 ~ 是 Jinja 字符串连接运算符。但这还是 不会工作,因为...

逻辑错误

循环变量 item 在参数中不可用 with_nested(因为当 参数被解释),所以即使你修复了语法,你也会 看到以下失败:

TASK [my task] *******************************************************************************************************************************************************************************
fatal: [localhost]: FAILED! => {"msg": "'item' is undefined"}

我会通过将任务分成两个独立的部分来解决这个问题 任务:一个查找文件,第二个操作数据 (或显示它)。类似于:

- hosts: localhost
  gather_facts: false
  vars:
    my_directory_list:
      var1: secret_dir
      file:
        - directory: directory_1
          secret_name: secret_1
        - directory: directory_2
          secret_name: secret_2

  tasks:
    - name: "find files"
      find:
        path: "foo/bar/secret/{{ item.directory }}"
      register: files
      loop: "{{ my_directory_list.file }}"

    - name: "display results"
      debug:
        msg: "In my directory {{ item.0.item.directory }} I have {{ item.1.path|basename }}"
      loop: "{{ files.results|subelements('files') }}"
      loop_control:
        label: "{{ item.1.path }}"

在上面的剧本中,“查找文件”任务使用 find 模块来 获取中列出的每个目录中的文件列表 my_directory_list.files。我们将这个循环的结果登记在 变量 files。请参阅 有关在 register 中使用的文档 循环 以了解该变量的结构。

在“显示结果”任务中,我们迭代第一个的结果 使用 subelements 过滤器循环。这有效地给了我们一个 (directory, file_path) 元组的扁平列表,因此我们可以生成 您正在寻找的输出。

使用您的示例文件结构,运行 上面的剧本产生以下输出:


PLAY [localhost] *****************************************************************************************************************************************************************************

TASK [find files] ****************************************************************************************************************************************************************************
ok: [localhost] => (item={'directory': 'directory_1', 'secret_name': 'secret_1'})
ok: [localhost] => (item={'directory': 'directory_2', 'secret_name': 'secret_2'})

TASK [display results] ***********************************************************************************************************************************************************************
ok: [localhost] => (item=foo/bar/secret/directory_1/file2) => {
    "msg": "In my directory directory_1 I have file2"
}
ok: [localhost] => (item=foo/bar/secret/directory_1/file1) => {
    "msg": "In my directory directory_1 I have file1"
}
ok: [localhost] => (item=foo/bar/secret/directory_2/file4) => {
    "msg": "In my directory directory_2 I have file4"
}
ok: [localhost] => (item=foo/bar/secret/directory_2/file3) => {
    "msg": "In my directory directory_2 I have file3"
}

PLAY RECAP ***********************************************************************************************************************************************************************************
localhost                  : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0