3

I have data that looks like this:

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

I need the Ansible equivalent of the following Python loop:

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

I was hoping I could do this:

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

But that fails because properties is a dictionary, not a list. And you can't do this either:

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

Any pointers?

4
  • Have you seen dict? Nov 2, 2018 at 19:11
  • I have, but I'm not clear how I would use it in this situation. I mean, it's basically the same a calling .items() on a dictionary.
    – larsks
    Nov 2, 2018 at 19:24
  • Can you tell us more about how you are going to use this?
    – Zoredache
    Nov 2, 2018 at 20:14
  • @Zoredache I want to check if a property is set on a given flavor, and only update it if it does not already have the requested value. So, for each flavor (for each property (get property value, test it against requested value, and possibly set it )).
    – larsks
    Nov 2, 2018 at 20:40

2 Answers 2

4

Well I can suggest a semi-hacky solution where you use set_fact a couple times to construct a list of dicts that you can probably use?

- 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

Results.

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   

I believe this would easily allow you to loop over the constructed lists setting the each property.

1

If I ignore the "I want to check the value first" part, I could solve this through templating instead, like this:

- 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 }}"

That works, but it's ugly, and will result in everything being changed every playbook run. I could munge the data before passing it to ansible so that the properties keys is a list of lists instead of a list of dicts, as in:

- 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

But that's somewhat less intuitive to read and write...and it's effectively re-implementing the .items() method by hand.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .