Назад | Перейти на главную страницу

Ansible: повторение вложенного словаря?

У меня есть данные, которые выглядят так:

nova_flavors:
- disk: 10
  name: m1.tiny
  properties:
    disk_read_bytes_sec: 12500000
    disk_read_iops_sec: 1000
    disk_write_bytes_sec: 3125000
    disk_write_iops_sec: 250
    vif_inbound_average: 2500
    vif_inbound_burst: 3750000
    vif_inbound_peak: 12500
    vif_outbound_average: 2500
    vif_outbound_burst: 3750000
    vif_outbound_peak: 12500
  ram: 1
- disk: 10
  name: m1.small
  properties:
    disk_read_bytes_sec: 25000000
    disk_read_iops_sec: 2000
    disk_write_bytes_sec: 6250000
    disk_write_iops_sec: 500
    vif_inbound_average: 5000
    vif_inbound_burst: 7500000
    vif_inbound_peak: 25000
    vif_outbound_average: 5000
    vif_outbound_burst: 7500000
    vif_outbound_peak: 25000
  ram: 2

Мне нужен Ansible-эквивалент следующего цикла Python:

for flavor in nova_flavors:
  for propname, propval in flavor['properties'].items():
    # do something with (flavor['name'], propname, propval)

Я надеялся, что смогу это сделать:

- debug:
    msg: "{{ item }}"
  with_subelements:
    - "{{ nova_flavors }}"
    - "properties"

Но это не удается, потому что properties это словарь, а не список. И вы тоже не можете этого сделать:

- debug:
    msg: "{{ item }}"
  with_subelements:
    - "{{ nova_flavors }}"
    - "properties.items()"

Есть указатели?

Что ж, я могу предложить полу-хакерское решение, в котором вы пару раз используете set_fact для создания списка dicts, который вы, вероятно, можете использовать?

- hosts: localhost
  vars:
    nova_flavors:
    - disk: 10
      name: m1.tiny
      properties:
        disk_read_bytes_sec: 12500000
        disk_read_iops_sec: 1000
        disk_write_bytes_sec: 3125000
      ram: 1
    - disk: 10
      name: m1.small
      properties:
        vif_outbound_burst: 7500000
        vif_outbound_peak: 25000
      ram: 2
  tasks:
  - set_fact:
      aslist: |
        [
        {% for item in nova_flavors %}
        {% for prop in item.properties.keys() %}
        {{ '{' }} 'name':'{{ item.name }}','propname':'{{ prop }}','propvalue':{{item.properties[prop]}} {{ '}' }},
        {% endfor %}
        {% endfor %}
        ]

  - debug:
      var: aslist

Полученные результаты.

TASK [debug] *******************************************************************
ok: [localhost] => {
    "aslist": [
        {
            "name": "m1.tiny", 
            "propname": "disk_write_bytes_sec", 
            "propvalue": 3125000
        }, 
        {
            "name": "m1.tiny", 
            "propname": "disk_read_iops_sec", 
            "propvalue": 1000
        }, 
        {
            "name": "m1.tiny", 
            "propname": "disk_read_bytes_sec", 
            "propvalue": 12500000
        }, 
        {
            "name": "m1.small", 
            "propname": "vif_outbound_peak", 
            "propvalue": 25000
        }, 
        {
            "name": "m1.small", 
            "propname": "vif_outbound_burst", 
            "propvalue": 7500000
        }
    ]
}

PLAY RECAP *********************************************************************
localhost                  : ok=4    changed=0    unreachable=0    failed=0   

Я считаю, что это легко позволит вам перебирать построенные списки, устанавливая каждое свойство.

Если я проигнорирую часть «Я хочу сначала проверить значение», я мог бы решить эту проблему с помощью шаблонов, например:

- name: set flavor properties:
  command: >-
    openstack flavor set
    {%for prop in item.properties.items()%}--property
    {{prop.0}}={{prop.1}} {%endfor %} {{ item.name }}
  loop: "{{ nova_flavors }}"

Это работает, но это некрасиво, и в результате все будет changed каждый запуск playbook. Я мог бы изменить данные перед передачей их в анзибль, чтобы properties keys - это список списков, а не список dicts, например:

- disk: 10
  name: m1.tiny
  properties:
    - [disk_read_bytes_sec,  12500000]
    - [disk_read_iops_sec,  1000]
    - [disk_write_bytes_sec,  3125000]
    - [disk_write_iops_sec,  250]
    - [vif_inbound_average,  2500]
    - [vif_inbound_burst,  3750000]
    - [vif_inbound_peak,  12500]
    - [vif_outbound_average,  2500]
    - [vif_outbound_burst,  3750000]
    - [vif_outbound_peak,  12500]
  ram: 1
  vcpus: 1
- disk: 10
  name: m1.small
  properties:
    - [disk_read_bytes_sec: 25000000]
    - [disk_read_iops_sec: 2000]
    - [disk_write_bytes_sec: 6250000]
    - [disk_write_iops_sec: 500]
    - [vif_inbound_average: 5000]
    - [vif_inbound_burst: 7500000]
    - [vif_inbound_peak: 25000]
    - [vif_outbound_average: 5000]
    - [vif_outbound_burst: 7500000]
    - [vif_outbound_peak: 25000]
  ram: 2
  vcpus: 1

Но это несколько менее интуитивно понятно для чтения и записи ... и эффективно повторно реализует .items() метод вручную.