英文:
Loops within loops
问题
我已经在我的Ansible group_vars
中设置了一些应用程序信息,如下所示:
applications:
- name: app1
- name: app2
- name: app3
- name: app4
settings:
log_dir: /var/logs/app4
associated_files:
- auth/key.json
- name: app5
settings:
log_dir: /var/logs/app5
repo_path: new_apps/app5
我正在努力理解如何使用这些 "子循环"。
我对每个应用程序的任务是:
- 根据
name
值创建一些文件夹 - 如果存在
settings/log_dir
值,则创建日志文件夹 - 如果指定了,复制相关文件
这里的任务语法不是问题,我对它们很熟悉 - 我只需要知道如何访问这个 applications
变量中的信息。特别是第 3 个任务对我来说似乎有问题 - 我需要在循环内部进行循环。
为了调试这个问题,我一直在尝试运行以下任务:
- debug:
msg: "{{ item }}"
with_subelements:
- "{{ applications }}"
- settings
以下是输出:
with_items
:我收到错误消息with_items 期望一个列表或一个集合
with_nested
:我可以看到顶层信息(例如,msg: {{ item }}
输出一个包含app1
、app2
等的数组)with_subelements
:我收到错误消息subelements 查找期望一个字典,但得到了 'None'
可能/很可能我在首次设置变量时的方式是错误的。如果有更好的方法来做这个,更改它不是问题。
英文:
I've set up some application information in my Ansible group_vars
like this:
applications:
- name: app1
- name: app2
- name: app3
- name: app4
settings:
log_dir: /var/logs/app4
associated_files:
- auth/key.json
- name: app5
settings:
log_dir: /var/logs/app5
repo_path: new_apps/app5
I'm struggling to get my head around how I can use these "sub loops".
My tasks for each application are:
- Create some folders based purely on the
name
value - Create a log folder if a
settings/log_dir
value exists - Copy associated files over, if specified
The syntax for these tasks isn't the problem here, I'm comfortable with those - I just need to know how to access the information from this applications
variable. Number 3 in particular seems troublesome to me - I need to loop within a loop.
To debug this, I've been trying to run the following task:
- debug:
msg: "{{ item }}"
with_subelements:
- "{{ applications }}"
- settings
Here's the output:
with_items
: I get the errorwith_items expects a list or a set
with_nested
: I can see the top level information (e.g.msg: {{ item }}
outputs an array ofapp1
,app2
etc)with_subelements
: I get the errorsubelements lookup expects a dictionary, got 'None'
It's possible/probable that the way I've set the variable up in the first instance is wrong. If there's a better way to do this, it's not a problem to change it.
答案1
得分: 3
您不能使用with_subelements
,因为settings
是一个字典,而不是一个列表。如果您重构您的数据,使settings
成为一个列表,就像这样:
applications:
- name: app1
- name: app2
- name: app3
- name: app4
settings:
- name: log_dir
value: /var/logs/app4
- name: associated_files
value:
- auth/key.json
- name: app5
settings:
- name: log_dir
value: /var/logs/app5
- name: repo_path
value: new_apps/app5
然后,您可以编写类似以下的代码来迭代每个应用程序的每个设置项:
---
- hosts: localhost
gather_facts: false
vars_files:
- applications.yml
tasks:
- debug:
msg: "set {{ item.1.name }} to {{ item.1.value }} for {{ item.0.name }}"
loop: "{{ applications|subelements('settings', skip_missing=true) }}"
loop_control:
label: "{{ item.0.name }}.{{ item.1.name }} = {{ item.1.value }}"
(我在这里使用loop_control
只是为了使输出更好看。)
使用您在applications.yml
中发布的示例数据,这将产生以下输出:
PLAY [localhost] *********************************************************************
TASK [debug] *************************************************************************
ok: [localhost] => (item=app4.log_dir = /var/logs/app4) => {
"msg": "set log_dir to /var/logs/app4 for app4"
}
ok: [localhost] => (item=app4.associated_files = ['auth/key.json']) => {
"msg": "set associated_files to ['auth/key.json'] for app4"
}
ok: [localhost] => (item=app5.log_dir = /var/logs/app5) => {
"msg": "set log_dir to /var/logs/app5 for app5"
}
ok: [localhost] => (item=app5.repo_path = new_apps/app5) => {
"msg": "set repo_path to new_apps/app5 for app5"
}
PLAY RECAP ***************************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
英文:
You can't use with_subelements
because settings
is a dictionary, not a list. If you were to restructure your data so that settings
is a list, like this:
applications:
- name: app1
- name: app2
- name: app3
- name: app4
settings:
- name: log_dir
value: /var/logs/app4
- name: associated_files
value:
- auth/key.json
- name: app5
settings:
- name: log_dir
value: /var/logs/app5
- name: repo_path
value: new_apps/app5
You could then write something like the following to iterate over each setting for each application:
---
- hosts: localhost
gather_facts: false
vars_files:
- applications.yml
tasks:
- debug:
msg: "set {{ item.1.name }} to {{ item.1.value }} for {{ item.0.name }}"
loop: "{{ applications|subelements('settings', skip_missing=true) }}"
loop_control:
label: "{{ item.0.name }}.{{ item.1.name }} = {{ item.1.value }}"
(I'm using loop_control
here just to make the output nicer.)
Using the sample data you posted in applications.yml
, this will produce as output:
PLAY [localhost] *********************************************************************
TASK [debug] *************************************************************************
ok: [localhost] => (item=app4.log_dir = /var/logs/app4) => {
"msg": "set log_dir to /var/logs/app4 for app4"
}
ok: [localhost] => (item=app4.associated_files = ['auth/key.json']) => {
"msg": "set associated_files to ['auth/key.json'] for app4"
}
ok: [localhost] => (item=app5.log_dir = /var/logs/app5) => {
"msg": "set log_dir to /var/logs/app5 for app5"
}
ok: [localhost] => (item=app5.repo_path = new_apps/app5) => {
"msg": "set repo_path to new_apps/app5 for app5"
}
PLAY RECAP ***************************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论