I've been writing a bunch of ansible playbooks, and in one case I had to transform a list of dicts to extract two attributes from each dict and create a new list of dicts. i.e., given a list like this:
entities: - id: 123 label: Label 1 type: foo status: enabled - id: 234 label: Label 2 type: foo status: enabled - id: 345 label: Label 3 type: bar status: enabled
I need to transform it into this:
entities: - id: 123 type: foo - id: 234 type: foo - id: 345 type: bar
I found the examples in the ansible docs to be very limited. In most cases there are no examples that show the use of additional parameters to filters. I defintely couldn't find anything that would let me extract two attributes from a list of dicts. There are examples to extract a single element using map(attribute='xxx')
, but nothing to extract more than one attribute, so I had to come up with something of my own.
I ended up with two possible solutions depending on how much flexibility you have in your playbook.
1. Using loop
The easier option is to use loop
and construct the new list one element at a time. You can do this if you have the option to use a set_fact
block separate from where you need to use the variable.
- set_fact: entities_transformed: '{{ entities_transformed|d([]) + [{"id": item.id, "type": item.type}] }}' loop: '{{ entities }}'
This set_fact
block creates a new fact called entities_transformed
by repeatedly appending each transformed element to a new list.
2. As a one liner
If you need to write it all as a one liner without a set_fact
, then this second approach works for you.
entities_transformed: '{{ entities | map("dict2items") | map("selectattr", "key", "in", ["id", "type"]) | map("items2dict") }}'
This works in multiple steps and I'll explain each with what the output looks like at that stage.
map("dict2items")
This transforms the entities list into the following:
- - key: id value: 123 - key: label value: Label 1 - key: type value: foo - key: status value: enabled - - key: id value: 234 - key: label value: Label 2 - key: type value: foo - key: status value: enabled - - key: id value: 345 - key: label value: Label 3 - key: type value: bar - key: status value: enabled
map("selectattr", "key", "in", ["id", "type"])
This strips down to the required keys:
- - key: id value: 123 - key: type value: foo - - key: id value: 234 - key: type value: foo - - key: id value: 345 - key: type value: bar
map("items2dict")
This reverses the first step giving us the following:
- id: 123 type: foo - id: 234 type: foo - id: 345 type: bar
Both options work equally well, but I prefer the second because it avoids creating additional facts and requiring loops in places where I cannot use one.
0 comments :
Post a Comment