【问题标题】:How to loop over a list of dict elements deep 3 in Ansible如何在 Ansible 中循环遍历 3 深的 dict 元素列表
【发布时间】:2021-08-14 21:07:29
【问题描述】:

我的 var 文件中有以下变量:

repo_type:
  hosted:
    data:
      - name: hosted_repo1
        online: true
        storage:
          blobstarage: default
          write_policy: allow_once
      - name: hosted_repo2
        online: true
        storage:
          blobstarage: default
          write_policy: allow_once
  proxy:
    data:
      - name: proxy_repo1
        online: true
        storage:
          blobstarage: default
          write_policy: allow_once
      - name: proxy_repo2
        online: true
        storage:
          blobstarage: default
          write_policy: allow_once
  group:
    data:
      - name: group_repo1
        online: true
        storage:
          blobstarage: default
          write_policy: allow_once
      - name: group_repo2
        online: true
        storage:
          blobstarage: default
          write_policy: allow_once

我想配置一个任务来循环(托管、代理和组)和数据字典的主体。

这是任务:

- name: Create pypi hosted Repos
  uri:
    url: "{{ nexus_api_scheme }}://{{ nexus_api_hostname }}:{{ nexus_api_port }}\
      {{ nexus_api_context_path }}{{ nexus_rest_api_endpoint }}/repositories/pypi/{{ item.key}}"
    user: "{{ nexus_api_user }}"
    password: "{{ nexus_default_admin_password }}"
    headers:
      accept: "application/json"
      Content-Type: "application/json"
    body_format: json
    method: POST
    force_basic_auth: yes
    validate_certs: "{{ nexus_api_validate_certs }}"
    body: "{{  item  }}"
    status_code: 201
  no_log: no
  with_dict: "{{ repo_type}}"

我尝试过with_itemswith_dictwith_nested,但没有任何帮助。

任务包含一个带有未定义变量的选项。错误是:'dict object' 没有属性'data'

任何帮助将不胜感激!

【问题讨论】:

    标签: ansible nexus


    【解决方案1】:

    如果您的目标是将data 键的内容作为平面列表循环,您可以这样做:

    - debug:
        msg: "repo {{ item.name }} write_policy {{ item.storage.write_policy }}"
      loop_control:
        label: "{{ item.name }}"
      loop: "{{ repo_type | json_query('*.data[]') }}"
    

    使用JMESPath 表达式从每个 顶级字典,然后展平生成的嵌套列表。在 换句话说,它将您的原始结构转换为:

    - name: hosted_repo1
      online: true
      storage:
        blobstarage: default
        write_policy: allow_once
    - name: hosted_repo2
      online: true
      storage:
        blobstarage: default
        write_policy: allow_once
    - name: proxy_repo1
      online: true
      storage:
        blobstarage: default
        write_policy: allow_once
    - name: proxy_repo2
      online: true
      storage:
        blobstarage: default
        write_policy: allow_once
    - name: group_repo1
      online: true
      storage:
        blobstarage: default
        write_policy: allow_once
    - name: group_repo2
      online: true
      storage:
        blobstarage: default
        write_policy: allow_once
    

    当使用您的示例数据运行时,这会产生输出:

    TASK [debug] *********************************************************************************************************
    ok: [localhost] => (item=hosted_repo1) => {
        "msg": "repo hosted_repo1 write_policy allow_once"
    }
    ok: [localhost] => (item=hosted_repo2) => {
        "msg": "repo hosted_repo2 write_policy allow_once"
    }
    ok: [localhost] => (item=proxy_repo1) => {
        "msg": "repo proxy_repo1 write_policy allow_once"
    }
    ok: [localhost] => (item=proxy_repo2) => {
        "msg": "repo proxy_repo2 write_policy allow_once"
    }
    ok: [localhost] => (item=group_repo1) => {
        "msg": "repo group_repo1 write_policy allow_once"
    }
    ok: [localhost] => (item=group_repo2) => {
        "msg": "repo group_repo2 write_policy allow_once"
    }
    

    如果您想做其他事情,请更新您的问题,以便 它清楚地显示了您对每次迭代的期望值 循环。

    【讨论】:

    • @larsks:您好,感谢您的回复。但我想遍历数据中的每个键作为正文:“{{ item }}”。那可能吗?还如何将(托管、代理和组)作为变量传递给。 url: "{{ nexus_api_scheme }}://{{ nexus_api_hostname }}:{{ nexus_api_port }}\ {{ nexus_api_context_path }}{{ nexus_rest_api_endpoint }}/repositories/pypi/{{ item.key}}"
    【解决方案2】:

    正如@larsk 所报告的那样,您实际上没有设法清楚地解释您是如何尝试循环数据的,以及您的 api 调用实际期望什么。

    但是这次你走运了,因为我已经在 Nexus 上搞砸了很多(我认为I actually recognize those variable names and overall task layout

    Nexus 存储库POST /v1/repositories/pypi/[hosted|proxy|group] API 端点期待对data 中的每个存储库进行一次调用。要实现您的要求,您需要遍历 repo_type 中的键以选择适当的端点,然后再次遍历 data 中的每个元素以发送要创建的 repo 定义。

    这实际上可以在您的循环中组合 dict2itemssubelements 过滤器,如下面的剧本(未直接测试)。

    转换的基本内容如下:

    1. 使用dict2items 将您的字典转换为键/值列表,例如(缩短的例子)
      - key: hosted
        value:
          data:
            - <repo definition 1>
            - <repo definition 2>
      [...]
      
    2. 使用subelements 过滤器将每个顶部元素与value.data 中的每个元素组合起来,例如:
      - # <- This is the entry for first repo i.e. `item` in your loop
        - key: hosted # <- this is the start of the corresponding top element i.e. `item.0` in your loop
          value:
            data:
              - <repo definition 1>
              - <repo definition 2>
        - <repo definition 1> # <- this is the sub-element i.e. `item.1` in your loop 
      - # <- this is the entry for second repo
        - key: hosted
          value:
            data:
              - <repo definition 1>
              - <repo definition 2>
        - <repo definition 2>
      [...]
      

    根据您的一个 cmets 并根据我的经验,我在示例中添加了一个使用 to_json 过滤器的 repo 定义的显式 json 序列化。

    综合起来就是:

    - name: Create pypi hosted Repos
      uri:
        url: "{{ nexus_api_scheme }}://{{ nexus_api_hostname }}:{{ nexus_api_port }}\
          {{ nexus_api_context_path }}{{ nexus_rest_api_endpoint }}/repositories/pypi/{{ item.0.key }}"
        user: "{{ nexus_api_user }}"
        password: "{{ nexus_default_admin_password }}"
        headers:
          accept: "application/json"
          Content-Type: "application/json"
        body_format: json
        method: POST
        force_basic_auth: yes
        validate_certs: "{{ nexus_api_validate_certs }}"
        body: "{{ item.1 | to_json }}"
        status_code: 201
      no_log: no
      loop: "{{ repo_type | dict2items | subelements('value.data') }}"
    

    【讨论】:

    • 道歉不够清楚。 @ Zeitounator - 感谢您的回复。我刚刚尝试并给了我这个错误MSG: could not find 'data' key in iterated item {'key': 'hosted', 'value': {'data': [{'name': 'hosted_repo1', 'online': True, 'storage': {'blobstarage': 'default', 'write_policy': 'allow_once'}}, {'name': 'hosted_repo2', 'online': True, 'storage': {'blobstarage': 'default', 'write_policy': 'allow_once'}}]}}
    • 我的第一篇文章有​​一个错字,自示例的最后一行以来已更正。 subelements 的参数应该是 value.data
    • 谢谢。现在得到 - 无法从 START_OBJECT 令牌中反序列化 java.lang.String 的实例\"\n}。(item=[{'key': 'hosted', 'value': {'data': [{'name': 'hosted_repo1', 'online': True, 'storage': {'blobstarage': 'default', 'write_policy': 'allow_once'}}, {'name': 'hosted_repo2', 'online': True, 'storage': {'blobstarage': 'default', 'write_policy': 'allow_once'}}]}}, {'name': 'hosted_repo1', 'online': True, 'storage': {'blobstarage': 'default', 'write_policy': 'allow_once'}}]) =&gt; { "ansible_loop_var": "item", 抱歉,无法添加所有错误消息。
    • 非常感谢您的帮助! to_json 没有帮助。我会在最后进一步调试。
    • 你是对的,这是一个示例数据,但为了测试我使用了正确的参数,如 https:///swagger-ui 文档。 .
    猜你喜欢
    • 1970-01-01
    • 2018-09-05
    • 1970-01-01
    • 2018-07-11
    • 1970-01-01
    • 2019-12-21
    • 1970-01-01
    • 1970-01-01
    • 2010-11-16
    相关资源
    最近更新 更多