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_1和directory_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
假设我有以下树:
foo/
├─ bar/
│ ├─ secret/
│ │ ├─ directory_1/
│ │ │ ├─ file1
│ │ │ ├─ file2
│ │ ├─ directory_2/
│ │ │ ├─ file3
│ │ │ ├─ file4
我不知道这些文件是什么,里面有多少directory_1和directory_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