Issue
This is a string/json/ansible parsing issue.
Big Picture: I'm creating a VPC, adding some security groups and creating some VMs.
The following example works fine with the output shown below. However, I need to labels the newly-created security group IDs so I can use them to create VMs.
- name: Create an VPC and some security groups and show the security group ID
hosts: localhost
vars:
security_groups: []
aws_region: "us-east-1"
tasks:
- name: "Create VPC test in AWS"
amazon.aws.ec2_vpc_net:
name: "test_vpc"
cidr_block: "10.5.2.0/24"
state: present
region: "us-east-1"
register: create_vpc_output
- name: "Set VPC ID as fact"
ansible.builtin.set_fact:
vpc_id: "{{ create_vpc_output.vpc.id }}"
- name: "Configuring security groups for VPC {{ vpc_id }}"
amazon.aws.ec2_security_group:
name: "{{ item.value.name }}"
description: "{{ item.value.description }}"
tags:
Name: "{{ item.value.name }}"
state: present
vpc_id: "{{ vpc_id }}"
region: "{{ aws_region }}"
loop: "{{ query('dict', vpc_security_groups) }}"
register: "create_sg_output"
vars:
vpc_security_groups:
private_test1:
name: "test1"
description: "Allow all connections"
private_test2:
name: "test2"
description: "Allow all connections"
- name: Extract group_id and group_name
set_fact:
sg_groups: "{{ create_sg_output.results | map(attribute='group_id') | zip(create_sg_output.results | map(attribute='group_name')) }}"
- name: Display extracted groups
debug:
var: sg_groups
Results:
TASK [Display extracted groups] ****************************************************************************************
ok: [localhost] => {
"sg_groups": [
[
"sg-08xxxxxxxxxxxxxxxx",
"test1"
],
[
"sg-05xxxxxxxxxxxxxxxx",
"test2"
]
]
}
How can I adjust this so the output is like this:
"sg_groups": [
{
"group_id" : "sg-08xxxxxxxxxxxxxx",
"group_name" : "test1"
},
{
"group_id": "sg-05xxxxxxxxxxxxxx",
"group_name" : "test2"
}
]
}
Note the added 'group_id' and 'group_name' which is the labels for the data in the json returned from the ec2_security_group call.
Solution
There are more options:
- Use the filter json_query
sg_groups: "{{ create_sg_output.results|
json_query('[].{group_id: group_id,
group_name: group_name}') }}"
gives what you want
sg_groups:
[
{
"group_id": "sg-08",
"group_name": "test1"
},
{
"group_id": "sg-05",
"group_name": "test2"
}
]
This option allows you to rename the attributes. For details see JMESPath Specification.
- The next option is the filter ansible.utils.keep_keys. The below expression gives the same result
sg_groups: "{{ create_sg_output.results|
ansible.utils.keep_keys(target=['group_id', 'group_name']) }}"
Example of a complete playbook for testing
- hosts: localhost
vars:
create_sg_output:
results:
- group_id: sg-08
group_name: test1
- group_id: sg-05
group_name: test2
sg_groups: "{{ create_sg_output.results|map(attribute='group_id')|
zip(create_sg_output.results|map(attribute='group_name')) }}"
sg_group2: "{{ create_sg_output.results|
json_query('[].{group_id: group_id,
group_name: group_name}') }}"
sg_group3: "{{ create_sg_output.results|
ansible.utils.keep_keys(target=['group_id', 'group_name']) }}"
tasks:
- debug:
var: sg_groups
- debug:
var: sg_group2|to_nice_json
- debug:
var: sg_group3|to_nice_json
- The simplest option is the filter items2dict if the values of group_id are unique
sg_groups_dict: "{{ create_sg_output.results|
items2dict(key_name='group_id',
value_name='group_name') }}"
gives the dictionary
sg_groups_dict:
sg-05: test2
sg-08: test1
You can iterate the dictionary
- debug:
msg: "{{ item.key }} {{ item.value }}"
with_dict: "{{ sg_groups_dict }}"
gives (abridged)
ok: [localhost] => (item={'key': 'sg-08', 'value': 'test1'}) =>
msg: sg-08 test1
ok: [localhost] => (item={'key': 'sg-05', 'value': 'test2'}) =>
msg: sg-05 test2
If you want to convert the dictionary to list use the filter dict2items
sg_groups: "{{ sg_groups_dict|
dict2items(key_name='group_id',
value_name='group_name') }}"
gives the expected result
sg_groups:
[
{
"group_id": "sg-08",
"group_name": "test1"
},
{
"group_id": "sg-05",
"group_name": "test2"
}
]
Example of a complete playbook for testing
- hosts: localhost
vars:
create_sg_output:
results:
- group_id: sg-08
group_name: test1
- group_id: sg-05
group_name: test2
sg_groups_dict: "{{ create_sg_output.results|
items2dict(key_name='group_id',
value_name='group_name') }}"
sg_groups: "{{ sg_groups_dict|
dict2items(key_name='group_id',
value_name='group_name') }}"
tasks:
- debug:
var: sg_groups_dict
- debug:
var: sg_groups|to_nice_json
- debug:
msg: "{{ item.key }} {{ item.value }}"
with_dict: "{{ sg_groups_dict }}"
Answered By - Vladimir Botka Answer Checked By - Senaida (WPSolving Volunteer)