Reputation: 1361
I'm running Ansible 2.7.5 on RHEL 7.4. (I know it's old; I'll upgrade soon- promise). The zip feature came out in Ansible 2.3. Anyway, I can't seem to get a couple of lists to create a dict properly through the zip filter.
I had read in the list from a variables file. The list is network_interfaces['computer_type']
in the loop which follows further down; here it is from debug output:
[{u'interface': u'bond0.160', u'notes': u'note160'},
{u'interface': u'bond0.197', u'notes': u'note197'},
{u'interface': u'bond1', u'notes': u'bonded, numa1, broadcom device'}]
The problem is, I'm trying to get the interface names that you see above, into a dict along with their values (which for now as an example are "notes"). But when I try to perform the dict (_keys|zip(_vals))
as shown in the first example of _reused_val
below, I am getting the corresponding error msg number 1. So for debugging, I reran my task with #2 uncommented, and subsequently with #3 uncommented.
- debug:
msg: >
ITEM: {{ item }}
* :::network_interfaces::: {{ network_interfaces[computer_type] }}
* :::_keys::: {{ _keys }}
* :::_vals::: {{ _vals }}
* :::_reused_val::: {{ _reused_val }}
loop: [ " {{ computer_type }} " ]
vars:
computer_type: big_computer
_keys: "{{ network_interfaces[computer_type]|map(attribute='interface')|list }}"
_vals: "{{ network_interfaces[computer_type] }}" # returns a list
_reused_val: "{{ dict(_keys|zip(_vals)) }}" #1
#_reused_val: "{{ _keys|zip(_vals) | list }}" #2
#_reused_val: "{{ _keys|zip(_vals) }}" #3
output showing reused_val
(I adjusted the spacing a little to make it easier to read):
1- "msg": "Unexpected templating type error occurred on ({{ dict(_keys|zip(_vals)) }}): <lambda>() takes exactly 0 arguments (1 given)"
2- [(u'bond0.160', {u'interface': u'bond0.160', u'notes': u'note160'}),
(u'bond0.197', {u'interface': u'bond0.197', u'notes': u'note197'}),
(u'bond1', {u'interface': u'bond1', u'notes': u'bonded, numa1, broadcom device'})]
3- <itertools.izip object at 0x7f311c048dd0>
#1 is what I'm trying to get to work- the dict(_keys|zip(_vals))
.
I don't know why #3 shows an itertools.izip object. I thought it was supposed to return a list. And for #2, I don't know what those parentheses are for. Is it because there are 3 dictionaries in the list?
Finally, here is the full output of the msg for case #3; I broke the lines a little bit just to make it easier to read:
"ITEM: big_computer * :::network_interfaces:::
[{u'interface': u'bond0.160', u'notes': u'note160'}, {u'interface': u'bond0.197', u'notes': u'note1
97'}, {u'interface': u'bond1', u'notes': u'bonded, numa1, broadcom device'}]
* :::_keys::: [u'bond0.160', u'bond0.197', u'bond1']
* :::_vals::: [{u'interface': u'bond0.160', u'notes': u'note160'}, {u'interface': u'bond0.197', u'notes': u'note197'}, {u'interface': u'bond1', u'notes': u'bonded, numa1, broadcom device'}]
* :::_reused_val::: <itertools.izip object at 0x7fc768049cb0>\n"
This work is a result of the work from my question at Ansible: need to combine information from 2 files for a task later I'm trying to follow the examples but after a days' work, I'm still stuck. Thanks.
Upvotes: 0
Views: 343
Reputation: 311238
I think you should just upgrade your Ansible.
With ansible 2.10.8, the following playbook runs without error and I think it produces the output you want. This is mostly identical to what you have, except I'm using a list in the debug
task to produce more legible output.
- hosts: localhost
gather_facts: false
vars:
network_interfaces:
big_computer:
- interface: bond0.160
notes: note160
- interface: bond0.197
notes: note197
- interface: bond1
notes: 'bonded, numa1, broadcom devices'
tasks:
- debug:
msg:
- "ITEM: {{ item }}"
- "network_interfaces: {{ network_interfaces[computer_type] }}"
- "keys: {{ _keys }}"
- "vals: {{ _vals }}"
- "reused_val: {{ _reused_val }}"
loop: [ " {{ computer_type }} " ]
vars:
computer_type: big_computer
_keys: "{{ network_interfaces[computer_type]|map(attribute='interface')|list }}"
_vals: "{{ network_interfaces[computer_type] }}" # returns a list
_reused_val: "{{ dict(_keys|zip(_vals)) }}" #1
Running this produces:
TASK [debug] *********************************************************************************************************************************************************************************
ok: [localhost] => (item= big_computer ) => {
"msg": [
"ITEM: big_computer ",
"network_interfaces: [{'interface': 'bond0.160', 'notes': 'note160'}, {'interface': 'bond0.197', 'notes': 'note197'}, {'interface': 'bond1', 'notes': 'bonded, numa1, broadcom devices'}]",
"keys: ['bond0.160', 'bond0.197', 'bond1']",
"vals: [{'interface': 'bond0.160', 'notes': 'note160'}, {'interface': 'bond0.197', 'notes': 'note197'}, {'interface': 'bond1', 'notes': 'bonded, numa1, broadcom devices'}]",
"reused_val: {'bond0.160': {'interface': 'bond0.160', 'notes': 'note160'}, 'bond0.197': {'interface': 'bond0.197', 'notes': 'note197'}, 'bond1': {'interface': 'bond1', 'notes': 'bonded, numa1, broadcom devices'}}"
]
}
If I run this with Ansible 2.7.5, I still don't see any of the errors you've reported (that's one reason why it's always a good idea to include a runnable example in your question), but I don't get the same behavior as with 2.10.8, either. I get:
TASK [debug] *********************************************************************************************************************************************************************************
ok: [localhost] => (item= big_computer ) => {
"msg": [
"ITEM: big_computer ",
"network_interfaces: [{'interface': 'bond0.160', 'notes': 'note160'}, {'interface': 'bond0.197', 'notes': 'note197'}, {'interface': 'bond1', 'notes': 'bonded, numa1, broadcom devices'}]",
"keys: ['bond0.160', 'bond0.197', 'bond1']",
"vals: [{'interface': 'bond0.160', 'notes': 'note160'}, {'interface': 'bond0.197', 'notes': 'note197'}, {'interface': 'bond1', 'notes': 'bonded, numa1, broadcom devices'}]",
"reused_val: {'[': '[', \"'\": 's', 'b': \"'\", 'o': 'n', 'n': 'o', 'd': 't', '0': 'd', '.': '0', '1': 'e', '6': 'a', ',': \"'\", ' ': ',', '9': '1', '7': '6', ']': \"'\"}"
]
}
So, it's all good except for the final step. The biggest problem here is that Ansible 2.7.5 doesn't handle anything other than string values very well. When you write this...
_keys: "{{ network_interfaces[computer_type]|map(attribute='interface')|list }}"
The result is a string value, not a list, whereas in more recent
versions of Ansible the _keys
variable will be a list. We can work
around this by explicitly serializing and de-serializing everything
to/from JSON:
- debug:
msg:
- "ITEM: {{ item }}"
- "network_interfaces: {{ network_interfaces[computer_type] }}"
- "keys: {{ _keys }}"
- "vals: {{ _vals }}"
- "reused_val: {{ _reused_val }}"
loop: [ " {{ computer_type }} " ]
vars:
computer_type: big_computer
_keys: "{{ network_interfaces[computer_type]|map(attribute='interface')|list|to_json }}"
_vals: "{{ network_interfaces[computer_type]|to_json }}"
_reused_val: "{{ dict(_keys|from_json|zip(_vals|from_json)) }}"
This produces the same output as the original version did with 2.10.8:
TASK [debug] *********************************************************************************************************************************************************************************
ok: [localhost] => (item= big_computer ) => {
"msg": [
"ITEM: big_computer ",
"network_interfaces: [{'interface': 'bond0.160', 'notes': 'note160'}, {'interface': 'bond0.197', 'notes': 'note197'}, {'interface': 'bond1', 'notes': 'bonded, numa1, broadcom devices'}]",
"keys: [\"bond0.160\", \"bond0.197\", \"bond1\"]",
"vals: [{\"interface\": \"bond0.160\", \"notes\": \"note160\"}, {\"interface\": \"bond0.197\", \"notes\": \"note197\"}, {\"interface\": \"bond1\", \"notes\": \"bonded, numa1, broadcom devices\"}]",
"reused_val: {'bond0.160': {'interface': 'bond0.160', 'notes': 'note160'}, 'bond0.197': {'interface': 'bond0.197', 'notes': 'note197'}, 'bond1': {'interface': 'bond1', 'notes': 'bonded, numa1, broadcom devices'}}"
]
}
...but that's an awful solution, and it would be much cleaner just to upgrade.
Upvotes: 2