循环内的循环

huangapple go评论82阅读模式
英文:

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

我正在努力理解如何使用这些 "子循环"。

我对每个应用程序的任务是:

  1. 根据 name 值创建一些文件夹
  2. 如果存在 settings/log_dir 值,则创建日志文件夹
  3. 如果指定了,复制相关文件

这里的任务语法不是问题,我对它们很熟悉 - 我只需要知道如何访问这个 applications 变量中的信息。特别是第 3 个任务对我来说似乎有问题 - 我需要在循环内部进行循环。

为了调试这个问题,我一直在尝试运行以下任务:

- debug:
    msg: "{{ item }}"
  with_subelements:
    - "{{ applications }}"
    - settings

以下是输出:

  • with_items:我收到错误消息 with_items 期望一个列表或一个集合
  • with_nested:我可以看到顶层信息(例如,msg: {{ item }} 输出一个包含 app1app2 等的数组)
  • 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:

  1. Create some folders based purely on the name value
  2. Create a log folder if a settings/log_dir value exists
  3. 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 error with_items expects a list or a set
  • with_nested: I can see the top level information (e.g. msg: {{ item }} outputs an array of app1, app2 etc)
  • with_subelements: I get the error subelements 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   

huangapple
  • 本文由 发表于 2020年1月6日 18:39:19
  • 转载请务必保留本文链接:https://go.coder-hub.com/59610605.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定