Ansible fetch value from dict - dictionary

I have below output from the debug, I need to set variable and loop thru commands
Debug output:
ok: [leafsw] => {
"msg": [
{
"cl_list": "AWSCL",
"delete": [
{
"list": "11111:10000",
"seq": 1
},
{
"list": "22222:10000",
"seq": 2
}
],
"name": "AWSCL",
"permit": [
"11111:10000",
"22222:10000"
]
},
{
"cl_list": "NORM_CL",
"name": "NORM_CL",
"permit": [
"33333:10000",
"44444:10000"
]
}
]
}
I need to fetch cl_list then next task is to use "with_items" to run other commands.
First: how to fetch dict value cl_list
Second: Add to variable so that I can use it a loop.
I tried:
- name: Get CL Name
debug: var="{{ item }}"
with_items: "{{ getclname.cl_list }}"
doesn't worked, also I tried:
- name: Get CL Name
debug: var="{{ item.cl_list }}"
with_items: "{{ getclname }}"
What I would like:
variable = ['AWSCL','NORM_CL'] so that I can use that in with_items loops
Any ideas?

you were almost there! try this task:
- name: get the cl_list from the variable
debug:
var: item.cl_list
with_items:
- "{{ my_var }}"
result:
TASK [get the cl_list from the variable] ****************************************************************************************************************************************************************************
ok: [localhost] => (item=None) => {
"item.cl_list": "AWSCL"
}
ok: [localhost] => (item=None) => {
"item.cl_list": "NORM_CL"
}
PLAY RECAP
its ready to be processed item by item.
SECOND WAY:
you could do this to get them in a list variable:
- name: get the cl_list from the variable
debug:
var: my_var | map(attribute="cl_list") | list
result:
TASK [get the cl_list from the variable] ****************************************************************************************************************************************************************************
ok: [localhost] => {
"my_var | map(attribute=\"cl_list\") | list": [
"AWSCL",
"NORM_CL"
]
}

Related

Symfony - switch from php-ampqlib RabbitMQ bundle to messenger - which is the way?

I am trying to change switch to symfony messenger, but documentation doesnt show me way.
Lets have old configuration for php-ampqlib:
mail_queue:
connection: message
exchange_options: { name: 'mail_queue', type: direct }
queue_options: { name: 'mail_queue',arguments: { 'x-dead-letter-exchange': [ 'S', 'mail_queue_failed' ],'x-dead-letter-routing-key': [ 'S', '' ],'x-max-priority': [ 'I',10 ] } }
callback: AppBundle\Consumer\MailQueueConsumer
qos_options: { prefetch_size: 0, prefetch_count: 1, global: false }
mail_queue_failed:
connection: message
exchange_options: { name: 'mail_queue_failed', type: direct }
queue_options: { name: 'mail_queue_failed', arguments: { 'x-message-ttl': [ 'I', 20000 ], 'x-dead-letter-exchange': [ 'S', 'mail_queue' ],'x-dead-letter-routing-key': [ 'S', '' ] } }
callback: AppBundle\Consumer\DoingNothingConsumer
How is the same configuration for Symfony messenger? I have spended a lot of hours without success.
Thank you very much.
D

Get starting dictionary

I have a problem with the usage of Jinja templating in Ansible. I have this nested dictionary:
"fruits": {
"summer": {
"june": {
"fruit": {
"cherry": "cherry"
},
"vars": {}
},
"july": {
"fruit": {
"peach": "peach"
},
"vars": {}
},
"august": {
"fruit": {
"watermelon": "watermelon",
"strawberry": "strawberry"
},
"vars": {}
}
}}
and I want to remove the object "peach". I have tried with pop method, and It works, but I want to use the filter rejectattr
I tried:
tasks:
- set_fact:
test: |
{%- for x,y in fruits.items() -%}
{%- for j,k in y.items() -%}
{{ k.fruit | dict2items | rejectattr ('key', 'eq', 'peach') | items2dict }}
{%- endfor -%}
{%- endfor -%}`
It gives me the following:
"test": "{
"cherry": "cherry"}
{}
{"watermelon": "watermelon", "strawberry": "strawberry"}"
But I want to get the starting structure, less "peach" object.
Any suggestion? Thank You
Ansible isn't a great tool for modifying deeply nested data structures (or really for modifying data structures in general). While I'm sure someone is going to drop by with a clever json_query filter or something, this is trivial to solve by writing a custom filter plugin. If we put the following in filter_plugins/badfruit.py:
def filter_badfruit(v, *exclude):
for months in v.values():
for data in months.values():
data["fruit"] = {k: v for k, v in data["fruit"].items() if k not in exclude}
return v
class FilterModule(object):
filter_map = {"badfruit": filter_badfruit}
def filters(self):
return self.filter_map
Then we can write a playbook like this:
- hosts: localhost
gather_facts: false
vars:
"fruits": {
"summer": {
"june": {
"fruit": {
"cherry": "cherry"
},
"vars": {}
},
"july": {
"fruit": {
"peach": "peach"
},
"vars": {}
},
"august": {
"fruit": {
"watermelon": "watermelon",
"strawberry": "strawberry"
},
"vars": {}
}
}}
tasks:
- debug:
var: >-
fruits|badfruit('peach')
And get this output:
PLAY [localhost] ***************************************************************
TASK [debug] *******************************************************************
ok: [localhost] => {
"fruits|badfruit('peach')": {
"summer": {
"august": {
"fruit": {
"strawberry": "strawberry",
"watermelon": "watermelon"
},
"vars": {}
},
"july": {
"fruit": {},
"vars": {}
},
"june": {
"fruit": {
"cherry": "cherry"
},
"vars": {}
}
}
}
}
PLAY RECAP *********************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
The filter is written so that we can provide multiple keys to exclude:
- debug:
var: >-
fruits|badfruit('peach', 'strawberry')
Q: "I want to use the filter rejectattr."
A: The rejectattr line from your code can be used as is. Combine the dictionaries
test_str: |
summer:
{% for i in fruits.summer|dict2items %}
{{ i.key }}:
{{ i.value|combine({'fruit': i.value.fruit|dict2items|rejectattr('key', 'eq', 'peach')|items2dict}) }}
{% endfor %}
test: "{{ test_str|from_yaml }}"
gives the expected result
test:
summer:
august:
fruit:
strawberry: strawberry
watermelon: watermelon
vars: {}
july:
fruit: {}
vars: {}
june:
fruit:
cherry: cherry
vars: {}
Optionally, put the excluded items into a dictionary, e.g.
exclude:
fruit: ['peach']
and walk the tree. The variable test will expand to the expected result as well
test_str: |
{% for season,sa in fruits.items() %}
{{ season }}:
{% for month,ma in sa.items() %}
{{ month }}:
{% for a,b in ma.items() %}
{{ a }}:
{
{% for k,v in b.items() %}
{% if k not in exclude[a] %}
{{ k }}: {{ v }},
{% endif %}
{% endfor %}
}
{% endfor %}
{% endfor %}
{% endfor %}
test: "{{ test_str|from_yaml }}"

Ansible dict: How to group by a key and set fact to be re-used later

I've a CSV which I converted into a dict using read_csv module.
My aim is to group the data by a field within the dictionary.
For example, in below data I want to use firstname & secondname group by departmentGroup, so that I get a dict array to be re-used later
Below is the input dict created from csv
{
{
"ID02": {
"department": "IT",
"departmentGroup": "IT-development",
"firstname": "first02",
"id": "ID02",
"salary": "40000",
"secondname": "surnam2",
"subDepartment": "development"
}
},
{
"ID03": {
"department": "IT",
"departmentGroup": "IT-development",
"firstname": "first03",
"id": "ID03",
"salary": "42000",
"secondname": "surnam3",
"subDepartment": "development"
}
},
{
"ID04": {
"department": "IT",
"departmentGroup": "IT-operations",
"firstname": "first04",
"id": "ID04",
"salary": "46000",
"secondname": "surnam4",
"subDepartment": "operations"
}
},
{
"ID05": {
"department": "IT",
"departmentGroup": "IT-operations",
"firstname": "first05",
"id": "ID05",
"salary": "42000",
"secondname": "surnam5",
"subDepartment": "operations"
}
}
I'm looking for output of values grouped by departmentGroup, so i can loop it for future tasks to build-up templates
{
"IT-development":
[
{"id": "ID02", "firstname": "first02", "secondname": "surnam2"},
{"id": "ID03", "firstname": "first03", "secondname": "surnam3"}
],
"IT-operations":
[
{"id": "ID04", "firstname": "first04", "secondname": "surnam4"},
{"id": "ID05", "firstname": "first05", "secondname": "surnam5"}
]
}
I've tried using map but couldn't reach much.
Any ideas on how to group in such a way in ansible?
I confirmed that I could do it by using the filters only.
The below is simpler than using Jinja2 code.
---
- name: Example Playbook for 65447303
hosts: localhost
gather_facts: false
tasks:
- name: Read a csv file and converts to dict
read_csv:
path: test.csv
key: name
register: csv_result
- debug: msg="{{ csv_result }}"
- name: Set combined data variable
set_fact:
combined_data: >-
{{ combined_data | default({})
| combine({item.value.departmentGroup: []
+ [{
'id': item.value.id,
'firstname': item.value.firstname,
'secondname': item.value.secondname
}]
+ combined_data[item.value.departmentGroup] | default([]) })
}}
with_dict: "{{ csv_result.dict }}"
- debug: msg="{{ combined_data }}"
I could do it by using Jinja2.
It wasn't easy to do it using the Ansible or Jinja2 filters only.
So I implemented the code using Jinja2.
How about this like?
csv file
(venv) $ vi test.csv
name,department,departmentGroup,firstname,id,salary,secondname,subDepartment
ID02,IT,IT-development,first02,ID02,40000,surnam2,development
ID03,IT,IT-development,first03,ID03,42000,surnam3,development
ID04,IT,IT-operations,first04,ID04,46000,surnam4,operations
ID05,IT,IT-operations,first05,ID05,42000,surnam5,operations
Playbook
(venv) $ vi main.yml
---
- name: Example Playbook for 65447303
hosts: localhost
gather_facts: false
tasks:
- name: Read a csv file and converts to dict
read_csv:
path: test.csv
key: name
register: csv_result
- debug: msg="{{ csv_result }}"
- name: Set combined data variable
set_fact:
combined_data: |
{% set data = {} %}
{% set tmp = {} %}
{# initialize data variable #}
{% for key in csv_result.dict.keys() %}
{% set _ = tmp.update(csv_result.dict[key]) %}
{% set _ = data.update({tmp['departmentGroup']: []}) %}
{# Append the data to each department key #}
{% endfor %}
{% for key in csv_result.dict.keys() %}
{% set _ = tmp.update(csv_result.dict[key]) %}
{% set _ = data[tmp['departmentGroup']].append({
'id': tmp['id'],
'firstname': tmp['firstname'],
'secondname': tmp['secondname']
}) %}
{% endfor %}
{{ data }}
- debug: msg="{{ combined_data | type_debug }}"
- debug: msg="{{ combined_data }}"
Execute and Result
(venv) $ ansible-playbook main.yml
(snip)
TASK [debug] ***************************************************************************************************************************************************************************
ok: [localhost] => {
"msg": {
"IT-development": [
{
"firstname": "first02",
"id": "ID02",
"secondname": "surnam2"
},
{
"firstname": "first03",
"id": "ID03",
"secondname": "surnam3"
}
],
"IT-operations": [
{
"firstname": "first04",
"id": "ID04",
"secondname": "surnam4"
},
{
"firstname": "first05",
"id": "ID05",
"secondname": "surnam5"
}
]
}
}
(snip)

Ansible: Appending to the dictionaries skips duplicated key names

I'm trying to populate dictionary from register output result.containers which happens to override the item.Image with same value.
Here is my output.
"result.containers": [
{
"Image": "lna-docker/webproxy:2.4.0",
"Names": [
"/se-webproxyui-dev-01"
],
},
{
"Image": "lna-docker-dev-local/webproxy:1.8.1",
"Names": [
"/se-webproxy-dev-01"
],
},
{
"Image": "docker-release/consul:1.0.1",
"Names": [
"/consul-client"
],
},
{
"Image": "docker.dev/webproxy:0.6.1",
"Names": [
"/webproxy-dev-01"
],
},
]
}
Here is my code.
- name: Populate dictonary for containerup
set_fact:
containeruplist: "{{ containeruplist|default({}) | combine({item.Image.split('/')[-1].split(':')[0]:item.Names[0][1:]} ) }}"
loop: "{{ result.containers }}"
here is my output
ok: [VM3node.lite.com] => {
"containeruplist": {
"consul": "consul-client",
"webproxy": "webproxy-dev-01"
}
}
I'm trying to populate dictionary from register output result.containers which happens to override the item.Image with same value. Any help would be greatly appreciated.
Ideally I should be getting below output. It's overriding the first two item.Image with value "webroxy" . Could someone help me achieve the below.
containeruplist": {
"webproxy":"se-webproxyui-dev-01"
"webproxy":"se-webproxy-dev-01"
"consul": "consul-client",
"webproxy": "webproxy-dev-01"
}

Ansible build a list of dictionaries and append to list within dictionary

Taking this cut down example set of inventory hostvars:
{
"_meta": {
"hostvars": {
"host-a.foo.com": {
"host_domain": "foo.com",
"subnet_address": "192.168.1.0",
"subnet_mask": "255.255.254.0"
},
"host-b.foo.com": {
"host_domain": "foo.com",
"subnet_address": "192.168.2.0",
"subnet_mask": "255.255.254.0"
},
"host-c.bar.com": {
"host_domain": "bar.com",
"subnet_address": "192.168.2.0",
"subnet_mask": "255.255.254.0"
}
}
}
}
I'm trying to produce something representing the following in ansible:
[
{
"192.168.1.0": {
"mask": "255.255.254.0",
"domains": [
"foo.com"
]
},
"192.168.2.0": {
"mask": "255.255.254.0",
"domains": [
"foo.com",
"bar.com"
]
}
}
]
So far I have this, but I'm unsure how to append to the domains list for each dictionary item (instead of overwriting it):
- name: inventory subnets
set_fact:
inventory_subnets: "{{ inventory_subnets | default({}) | combine({
hostvars[item].subnet_address: {
'mask': hostvars[item]['subnet_mask'],
'domains': [
# How to build this list?
]
}
}) }}"
loop: "{{ query('inventory_hostnames', 'all') }}"
Is it possible to perform another combine within a dictionary definition somehow?
The tasks below
- set_fact:
hostvars_list: "{{ hostvars_list|default([]) +
[{'host': item.key}|combine(item.value)] }}"
loop: "{{ hostvars|dict2items }}"
- set_fact:
subnets: "{{ subnets|default([]) +
[{item.0: {'mask': item.1|json_query('[].subnet_mask')|first,
'domains': item.1|json_query('[].host_domain')}}] }}"
loop: "{{ hostvars_list|groupby('subnet_address') }}"
- debug:
var: subnets
give
"subnets": [
{
"192.168.1.0": {
"domains": [
"foo.com"
],
"mask": "255.255.254.0"
}
},
{
"192.168.2.0": {
"domains": [
"foo.com",
"bar.com"
],
"mask": "255.255.254.0"
}
}
]

Resources