Hi, Could someone please help how to sort the below using ansible
"msg": [
{
"Desc": "jkl - txt to search-\n",
"SCTASK": "SCTASK000001"
},
{
"Desc": "xyz - txt to search-\n",
"SCTASK": "SCTASK000002"
},
{
"Desc": "def - txt to search-\n",
"SCTASK": "SCTASK000003"
},
{
"Desc": "def - txt to search-\n",
"SCTASK": "SCTASK000004"
},
{
"Desc": "abc- txt to search-\n",
"SCTASK": "SCTASK000005"
}
]
I need to get both sctask and description where 'abc' word present in 'Desc'. I tried to use where condition in my code block but it's not filtering.
- set_fact:
SCT: "{{ jsoncontent.json | json_query(query)}}"
vars:
query: "result[*].{Desc: description, SCTASK: number}"
- name: debug
debug: msg="{{ item }}"
loop: "{{SCT}}"
when: SCT is search("abc")
Thanks!
Q: "Get both sctask and description where 'abc' word present in 'Desc'."
A: json_query is not needed. Simply use the filter selectattr
- set_fact:
SCT: "{{ jsoncontent.json.result|selectattr('Desc', 'search', 'abc') }}"
gives
SCT:
- Desc: |-
abc- txt to search-
SCTASK: SCTASK000005
Notes
If you want to select the items in the loop simply iterate the list
- debug:
msg: "{{ item }}"
loop: "{{ jsoncontent.json.result }}"
when: item.Desc is search("abc")
gives
TASK [debug] *******************************************************************************
skipping: [localhost] => (item={'Desc': 'jkl - txt to search-\n', 'SCTASK': 'SCTASK000001'})
skipping: [localhost] => (item={'Desc': 'xyz - txt to search-\n', 'SCTASK': 'SCTASK000002'})
skipping: [localhost] => (item={'Desc': 'def - txt to search-\n', 'SCTASK': 'SCTASK000003'})
skipping: [localhost] => (item={'Desc': 'def - txt to search-\n', 'SCTASK': 'SCTASK000004'})
ok: [localhost] => (item={'Desc': 'abc- txt to search-\n', 'SCTASK': 'SCTASK000005'}) =>
msg:
Desc: |-
abc- txt to search-
SCTASK: SCTASK000005
You can also create the list SCT in a loop. The task below gives the same result.
- set_fact:
SCT: "{{ SCT|d([]) + [item] }}"
loop: "{{ jsoncontent.json.result }}"
when: item.Desc is search("abc")
Related
I'm stuck with the following issue.
My JSON data looks like this:
[
{
"clusters":[
{
"id":"1",
"name":"cluster1"
},
{
"id":"2",
"name":"cluster2"
}
],
"tag":"a"
},
{
"clusters":[
{
"id":"3",
"name":"cluster2"
}
],
"tag":"b"
}
]
What I am trying to do is extracting the tag values which are connected to a certain cluster (say, cluster1). So, I need to check if cluster1 is in the list of clusters[*].name somehow.
Here is my playbook:
- name: "Test"
hosts: localhost
gather_facts: False
vars:
- test:
- clusters:
- name: "cluster1"
id: "1"
- name: "cluster2"
id: "2"
tag: "a"
- clusters:
- name: "cluster2"
id: "3"
tag: "b"
- set_fact:
tags_test: "{{ test | community.general.json_query('[?clusters[].name==`cluster1`].tag') }}"
- debug:
msg: "{{ tags_test }}"
What I am expecting to get is the tag value: "a".
This is the result:
TASK [debug] ******************************************************
ok: [localhost] => {
"msg": []
}
I also tried combining json_query with selectattr, but, no luck.
With JMESPath you have to nest your conditions because you are looking for an object named cluster1 inside the the JSON array clusters which is nested in another array:
[?clusters[?name==`cluster1`]].tag|[0]
So as a task,
- set_fact:
tags_test: >-
{{ test | community.general.json_query(
'[?clusters[?name==`cluster1`]].tag|[0]'
) }}
Create the dictionary of the tags and clusters first
tag_clusters: "{{ test|json_query(tag_clusters_query)|items2dict }}"
tag_clusters_query: '[].{key: tag, value: clusters[].name}'
gives
tag_clusters:
a:
- cluster1
- cluster2
b:
- cluster2
Then, selectattr and map the key(s)
tags_test: "{{ tag_clusters|dict2items|
selectattr('value', 'contains', 'cluster1')|
map(attribute='key') }}"
gives
tags_test:
- a
This ansible playbook works
---
- hosts: localhost
gather_facts: False
vars:
jq: "[?contains(name, 'Pizza')]"
json: |
[{
"name": "Ted's Sub Shop - 720895714701",
"templateid": "24632"
},
{
"name": "Ted's Pizza - 720895714702",
"templateid": "24663"
}]
tasks:
- name: DEBUG
debug:
msg: "{{ json | from_json | json_query(jq) }}"
It returns the following
ok: [localhost] => {
"msg": [
{
"name": "Ted's Pizza - 720895714702",
"templateid": "24663"
}
]
}
I need to take it a few steps further and when the value of name contains Pizza I need it to return just the 12 digit number on the end. So the return output would look like this
ok: [localhost] => {
"msg": "720895714702"
}
Thoughts?
you could try
- name: testplaybook jinja2
hosts: localhost
gather_facts: no
vars:
json: |
[{
"name": "Ted's Sub Shop - 720895714701",
"templateid": "24632"
},
{
"name": "Ted's Pizza - 720895714702",
"templateid": "24663"
}]
tasks:
- name: DEBUG
debug:
msg: "{{ json | from_json | selectattr('name', 'contains' , 'Pizza')
| map(attribute='name')
| map('regex_replace', '^.*?(\\d*)$', '\\1')}}"
result:
ok: [localhost] => {
"msg": [
"720895714702"
]
}
It might be more efficient to add an attribute. For example the declaration below
json_id: "{{ json|zip(id_hash)|map('combine')|list }}"
id_hash: "{{ id_list|
map('community.general.dict_kv', 'id')|list }}"
id_list: "{{ json|
map(attribute='name')|
map('split', '-')|
map('last')|
map('int')|list }}"
expands to
json_id:
- id: 720895714701
name: Ted's Sub Shop - 720895714701
templateid: '24632'
- id: 720895714702
name: Ted's Pizza - 720895714702
templateid: '24663'
Then, the usage is trivial. For example
- debug:
msg: "{{ json_id|
selectattr('name', 'contains' , 'Pizza')|
map(attribute='id')|list }}"
gives
msg:
- 720895714702
The same result gives also json_query below
- debug:
msg: "{{ json_id|
json_query('[?contains(name, `Pizza`)].id') }}"
I am trying to run :
- name: Describe config aggregator
shell: >
aws configservice describe-configuration-aggregators --configuration-aggregator-name test-config
register: config_ouput
below is the data generated.
{
"ConfigurationAggregators": [
{
"ConfigurationAggregatorName": "test-config",
"ConfigurationAggregatorArn": "arn:aws:config:us-east-1:4567:config-aggregator/config-aggregator-uw2o9pzf",
"AccountAggregationSources": [
{
"AccountIds": [
"895677"
],
"AllAwsRegions": true
}
],
"CreationTime": 1624454176.124,
"LastUpdatedTime": 1626426755.504
}
]
}
Now I want to append the accountIds above with any new account say 1234567 which should give me result such as
{
"ConfigurationAggregators": [
{
"ConfigurationAggregatorName": "test-config",
"ConfigurationAggregatorArn": "arn:aws:config:us-east-1:8778:config-aggregator/test-config-pzf",
"AccountAggregationSources": [
{
"AccountIds": [
"895677,1234567"
],
"AllAwsRegions": true
}
],
"CreationTime": 1624454176.124,
"LastUpdatedTime": 1626426755.504
}
]
}
I am trying to do is:
- name: Export results to JSON
set_fact:
config_ouput_json: "{{ config_ouput + [{"AccountIds": "1234567","AllAwsRegions": true}]}}"
but this doesn't work, please let me know the right syntax.
Basically you require bit of JSON manipulation to achieve your task.
Steps :
Store output of first command in some json file. In your case you can keep that as registered variable of ansible.
Get existing account_ids in some variable.
Create a list of new accounts as variables in ansible.
Iterate over new account_ids and add to existing account_ids.
Update the aws config command.
Sample Code :
- name: initial validation
hosts: localhost
connection: local
vars:
newAccountIds:
- "123456"
- "566544"
- "555445"
tasks:
- name: register json file
include_vars:
file: 'abc.json'
name: bundle
- name: set value
set_fact:
values: "{{ bundle['ConfigurationAggregators'][0]['AccountAggregationSources'][0]['AccountIds'] }}"
- set_fact:
values: "{{ (values | default([])) + [item] }}"
with_items: "{{ newAccountIds }}"
- debug:
msg: "{{ values }}"
- debug:
msg: '"aws configservice put-configuration-aggregator --configuration-aggregator-name test-config --account-aggregation-sources "[{"AccountIds": {{ values | to_json }},"AwsRegions": ["us-east-1"]}]\""'
Sample Output :
PLAY [initial validation] ********************************************************************************************
TASK [Gathering Facts] ***********************************************************************************************
ok: [localhost]
TASK [register json file] ********************************************************************************************
ok: [localhost]
TASK [set value] *****************************************************************************************************
ok: [localhost]
TASK [set_fact] ******************************************************************************************************
ok: [localhost] => (item=123456)
ok: [localhost] => (item=566544)
ok: [localhost] => (item=555445)
TASK [debug] *********************************************************************************************************
ok: [localhost] => {
"msg": [
"895677",
"123456",
"566544",
"555445"
]
}
TASK [debug] *********************************************************************************************************
ok: [localhost] => {
"msg": "\"aws configservice put-configuration-aggregator --configuration-aggregator-name test-config --account-aggregation-sources \"[{\"AccountIds\": [\"895677\", \"123456\", \"566544\", \"555445\"],\"AwsRegions\": [\"us-east-1\"]}]\\\"\""}
PLAY RECAP ***********************************************************************************************************
localhost : ok=6 changed=0 unreachable=0 failed=0
I have this ansible playbook which will create and attach volumes to EC2 instances using ec2_vol module and I want to partition the same using parted module. Below is my ec2_vol module,
EC2_VOL Module:
ec2_vol:
aws_access_key: XXXXXXXX
aws_secret_key: XXXXXXXX
security_token: XXXXXXXX
instance: "{{ item.instance_id }}"
region: "{{ var_dict['REGION'] }}"
device_name: "{{ VOL_NAME }}"
volume_type: gp2
volume_size: '1000'
delete_on_termination: false
with_items: "{{ ec2_instances_list.instances}}"
register: ec2_volumes
- debug:
msg: "{{ ec2_volumes.results }}"
Result of ec2_volumes:
And the result that is printing from ec2_volumes.results. I want to loop through the device_name and partition the devices which is created
TASK [debug] *******************************************************************
ok: [localhost] => {
"msg": [
{
"_ansible_ignore_errors": null,
"_ansible_item_label": {
"ami_launch_index": 0,
"architecture": "x86_64",
"block_device_mappings": [
{
"device_name": "/dev/sda1",
"ebs": {
"attach_time": "2021-04-30T15:47:07+00:00",
"delete_on_termination": true,
"status": "attached",
"volume_id": "vol-XXXXXXXXXXXXXX"
}
},
{
"device_name": "/dev/sdb",
"ebs": {
"attach_time": "2021-04-30T15:47:07+00:00",
"delete_on_termination": false,
"status": "attached",
"volume_id": "vol-XXXXXXXXXXXXXXXX"
}
}
],
And here is my parted module code:
- name: Partition Additional volumes
parted:
device: "{{ item.block_device_mappings[0].device_name }}"
number: 1
part_type: 'primary'
state: present
when: ("{{ ec2_volumes.device_name }}" != "/dev/sda1")
with_items: "{{ ec2_volumes.results}}"
But still getting error that 'block_device_mappings' has no attribute.
fatal: [localhost]: FAILED! => {"msg": "'list object' has no attribute 'block_device_mappings'"}
What could be the cause? Can someone help me to resolve this issue?
Edit 1:
Facing another issue after updating the playbook in the parted module
- name: Partition Additional volumes
parted:
device: "{{ item._ansible_item_label.block_device_mappings[0].device_name }}"
number: 1
part_type: 'primary'
state: present
when: ("{{ ec2_volumes.device_name }}" != "/dev/sda1")
with_items: "{{ ec2_volumes.results}}"
fatal: [localhost]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'dict object' has no attribute 'device_name'
The error is clear:
FAILED! => {"msg": "'list object' has no attribute 'block_device_mappings'"}
When you take a look at the list you'll see that block_device_mappings is an attribute of _ansible_item_label
"msg": [
{
"_ansible_ignore_errors": null,
"_ansible_item_label": {
"ami_launch_index": 0,
"architecture": "x86_64",
"block_device_mappings": [
...
Fix the reference
device: "{{ item._ansible_item_label.block_device_mappings[0].device_name }}"
I'm trying to get the datastore name for a specific hard disk but I haven't been successful in being able to figuring out choose an entry in the list.
This output is from the ansible module "vmware_guest_disk_facts"
I save this output to a variable called "vm_info".
"guest_disk_facts": {
"0": {
"backing_filename": "stuffstuff",
"capacity_in_kb": 106954752,
"backing_eagerlyscrub": false,
"backing_datastore": "WHAT I REALLY WANT",
"backing_writethrough": false,
"label": "Hard disk 1",
"backing_type": "FlatVer2",
"key": 2000,
"capacity_in_bytes": 109521666048,
"backing_thinprovisioned": false,
"controller_key": 1000,
"summary": "106,954,752 KB",
"unit_number": 0,
"backing_uuid": "info"
},
"1": {
"backing_filename": "stuffstuff",
"capacity_in_kb": 15728640,
"backing_eagerlyscrub": false,
"backing_datastore": "DON'T CARE OF ABOUT THIS ONE",
"backing_writethrough": false,
"label": "Hard disk 2",
"backing_type": "FlatVer2",
"key": 2001,
"capacity_in_bytes": 16106127360,
"backing_thinprovisioned": false,
"controller_key": 1000,
"summary": "15,728,640 KB",
"unit_number": 1,
"backing_uuid": "info"
}
- debug:
msg: "{{ item.guest_disk_facts | json_query(query) }}"
with_items: "{{ vm_info.results }}"
vars:
query: "guest_disk_facts.0.backing_datastore" #done w/ & w/o quotes around 0
I've also tried the following queries and I feel like I've exhausted all options at this point.
query: "guest_disk_facts.[0].backing_datastore"#done w/ & w/o quotes around 0
query: "guest_disk_facts[0].backing_datastore" #done w/ & w/o quotes around 0
query: "guest_disk_facts.*.backing_datastore" #will give me backing_datastore entries for both dictionaries in this case
I would like to just get backing_datastore for one entry in this list of dictionaries
msg: "WHAT I REALLY WANT"
but so far I'm returned with either this error:
Expecting: ['quoted_identifier', 'unquoted_identifier', 'lbracket', 'lbrace'], got: number: Parse error at column 17, token \"0\" (NUMBER), for expression
OR
msg: ""
OR
msg:[
"0",
]
The task below gives "WHAT YOU REALLY WANT"
- debug:
msg: "{{ guest_disk_facts['0'|quote].backing_datastore }}"
The point is quoting the quoted key. The keys '0' and '1' are not valid variables and must be quoted.
The loop below
- debug:
msg: "{{ guest_disk_facts[item|quote].backing_datastore }}"
loop: "{{ guest_disk_facts.keys() }}"
gives
ok: [localhost] => (item=1) =>
msg: DON'T CARE OF ABOUT THIS ONE
ok: [localhost] => (item=0) =>
msg: WHAT I REALLY WANT
Another way to do this -
- name: Get all disks from existing VM
vmware_guest_disk_info:
validate_certs: False
hostname: '{{ vcenter_hostname }}'
username: '{{ vcenter_username }}'
password: '{{ vcenter_password }}'
datacenter: Asia-Datacenter1
name: VM_8046
register: existing_disk
- name: Get Backing datastore for desired disk id
set_fact:
disk_zero_datastore: "{{ item.value.backing_datastore }}"
with_dict: "{{ existing_disk.guest_disk_info }}"
when: item.key == '0'
- debug:
msg: "{{ disk_zero_datastore }}"
when: disk_zero_datastore is defined