How to get nested value from list - ansible

I'm having trouble to get ID from json code that mutch a specific value in such array
I explain:
I have this code json:
{
"results": [
{
"TAB": "bleu",
"exp": [
{
"A": "NOT_PROTECTED",
"B": [
"500",
"600"
],
"C": false
}
],
"ID": "000041"
},
{
"TAB": "rouge",
"exp": [
{
"A": "PROTECTED",
"B": [
"700",
"800"
],
"C": true
}
],
"ID": "000042"
}
]
}

I'm assuming the question is how you access the values in Ansible, since it has the ansible tag.
You can use the map filter in Ansible to access the values like so: (where your json is in the some_json variable.)
- debug:
msg: "{{ some_json.results | map(attribute='ID') | list }}"
results:
ok: [localhost] => {
"msg": [
"000041",
"000042"
]
}
If you want to do it with json_query/jmespath (As the question is also tagged with json_query and jmespath) then it would be like this:
- debug:
msg: "{{ some_json.results | json_query('[*].ID') | list }}"
ok: [localhost] => {
"msg": [
"000041",
"000042"
]
}
That being said, I do prefer the map method myself since it does not require any extra dependencies where as json_query requires jmespath to be installed.

Related

How to loop dictionary with nested dictionaries

from the json below I need to gather the interface name and the unit name value in a loop.
This is partial output of my json:
{
"configuration": {
"#": {
"junos:changed-localtime": "2021-04-30 12:47:05 PDT",
"junos:changed-seconds": "1619812025",
"xmlns": "http://xml.juniper.net/xnm/1.1/xnm"
},
"interfaces": {
"interface": [
{
"name": "irb",
"unit": [
{
"family": {
"inet": {
"address": [
{
"name": "100.111.10.4/24"
}
],
"mtu": 9100
}
},
"name": 4010
},
{
"family": {
"inet": {
"address": [
{
"name": "100.127.9.2/31"
}
]
}
},
"name": 4093
}
]
},
{
"name": "lo0",
"unit": [
{
"family": {
"inet": {
"address": [
{
"name": "100.127.0.32/32"
}
],
}
},
"name": 0
}
]
}
]
}
}
}
The playbook I'm using is below:
- name: Print response
debug:
msg: "{{item.name}}.{{item|json_query('unit[*].name')}}"
loop: "{{ test.parsed_output.configuration.interfaces.interface}}"
ignore_errors: yes
The problem that I'm having is this:
"msg": "lo0.[0]"
"msg": "irb.[4010, 4093]"
What I want to get is:
"msg": "lo0.0"
"msg": "irb.4010"
"msg": "irb.4093"
Same outside name with each unit.name, but I don't know how to do this.
Thanks.
Iterate with_subelements, e.g.
- debug:
msg: "{{ item.0.name }} {{ item.1.name }}"
with_subelements:
- "{{ test.parsed_output.configuration.interfaces.interface }}"
- unit
gives
msg: irb 4010
msg: irb 4093
msg: lo0 0

ansible: Invalid data passed to 'loop'

I have this following playbook, which gather facts in google cloud and filter instance names we want.
tasks:
- name: get tags
delegate_to: localhost
gcp_compute_instance_info:
auth_kind: serviceaccount
service_account_file: "xxx"
zone: "xxx"
filters:
- "name:{{ names }}*"
project: "{{ project }}"
register: ilist
- name: Display output
debug: var=ilist['items']
- set_fact:
instances: "{{ instances|default([]) + [ item.name ] }}"
loop: "{{ ilist['items']}}"
when: item.name is regex(".*"+tag+"-[a-z0-9]{4}$")
- debug:
var: instances
I'm getting following error in the loop task
Invalid data passed to 'loop', it requires a list, got this instead:
<built-in method items of dict object at 0x7fe0f370aa70>. Hint: If you
passed a list/dict of just one element, try adding wantlist=True to
your lookup invocation or use q/query instead of lookup.
what I'm doing wrong here? thanks
and this is the output of ilist
{
"changed":false,
"failed":false,
"resources":[
{
"canIpForward":false,
"cpuPlatform":"Intel Haswell",
"creationTimestamp":"2020-09-14T04:05:58.316-07:00",
"deletionProtection":false,
"disks":[
{
"autoDelete":true,
"boot":true,
"deviceName":"persistent-disk-0",
"diskSizeGb":"10",
"guestOsFeatures":[
{
"type":"VIRTIO_SCSI_MULTIQUEUE"
}
],
"index":0,
"interface":"SCSI",
"kind":"compute#attachedDisk",
"licenses":[
"xxxx"
],
"mode":"READ_WRITE",
"source":"xxxx",
"type":"PERSISTENT"
}
],
"fingerprint":"3yOdLl6Hp8g=",
"id":"3503717950118097018",
"kind":"compute#instance",
"labelFingerprint":"IP52FxBvsW0=",
"labels":{
"block":"internal",
"component":"dev",
"function":"internal"
},
"lastStartTimestamp":"2020-09-14T04:06:26.016-07:00",
"machineType":"xxxx",
"metadata":{
"fingerprint":"sTp1wPeotCo=",
"items":[
{
"key":"instance-template",
"value":"xxxx
},
{
"key":"created-by",
"value":"xxxx"
}
],
"kind":"compute#metadata"
},
"name":"test-vm",
"networkInterfaces":[
{
"fingerprint":"ae26IqBpxVo=",
"kind":"compute#networkInterface",
"name":"nic0",
"network":"xxxx",
"networkIP":"xxxx"
}
],
"scheduling":{
"automaticRestart":true,
"onHostMaintenance":"MIGRATE",
"preemptible":false
},
"selfLink":"xxxxx",
"serviceAccounts":[
{
"email":"xxxx",
"scopes":[
"https://www.googleapis.com/auth/devstorage.read_only",
"https://www.googleapis.com/auth/logging.write",
"https://www.googleapis.com/auth/monitoring.write",
"https://www.googleapis.com/auth/pubsub",
"https://www.googleapis.com/auth/service.management.readonly",
"https://www.googleapis.com/auth/servicecontrol",
"https://www.googleapis.com/auth/trace.append"
]
}
],
"startRestricted":false,
"status":"RUNNING",
"tags":{
"fingerprint":"Oyf1u-BGqNA=",
"items":[
"no-ip-b"
]
},
"zone":"xxxx"
},
{
"canIpForward":false,
"cpuPlatform":"Intel Haswell",
"creationTimestamp":"2020-10-15T06:59:52.505-07:00",
"deletionProtection":false,
"disks":[
{
"autoDelete":true,
"boot":true,
"deviceName":"persistent-disk-0",
"diskSizeGb":"10",
"guestOsFeatures":[
{
"type":"VIRTIO_SCSI_MULTIQUEUE"
}
],
"index":0,
"interface":"SCSI",
"kind":"compute#attachedDisk",
"licenses":[
"xxxx"
],
"mode":"READ_WRITE",
"source":"xxxxx",
"type":"PERSISTENT"
}
],
"fingerprint":"-E0UpLFggow=",
"id":"5900118287465179960",
"kind":"compute#instance",
"labelFingerprint":"IP52FxBvsW0=",
"labels":{
"block":"internal",
"component":"dev",
"function":"internal"
},
"lastStartTimestamp":"2020-10-15T07:00:37.895-07:00",
"machineType":"xxxxx",
"metadata":{
"fingerprint":"05Oj3Bq6zb4=",
"items":[
{
"key":"instance-template",
"value":"xxxx"
},
{
"key":"created-by",
"value":"xxxx"
}
],
"kind":"compute#metadata"
},
"name":"test-vm",
"networkInterfaces":[
{
"fingerprint":"H24HFGkCFNg=",
"kind":"compute#networkInterface",
"name":"nic0",
"network":"xxxx",
"networkIP":"xxxx"
}
],
"scheduling":{
"automaticRestart":true,
"onHostMaintenance":"MIGRATE",
"preemptible":false
},
"selfLink":"xxxx",
"serviceAccounts":[
{
"email":"xxxx",
"scopes":[
"https://www.googleapis.com/auth/devstorage.read_only",
"https://www.googleapis.com/auth/logging.write",
"https://www.googleapis.com/auth/monitoring.write",
"https://www.googleapis.com/auth/pubsub",
"https://www.googleapis.com/auth/service.management.readonly",
"https://www.googleapis.com/auth/servicecontrol",
"https://www.googleapis.com/auth/trace.append"
]
}
],
"startRestricted":false,
"status":"RUNNING",
"tags":{
"fingerprint":"Oyf1u-BGqNA=",
"items":[
"no-ip-b"
]
},
"zone":"xxxx"
}
]
}
You can try with the query function
loop: {{ query('dict', ilist.items) }}

What the syntax would be to pull the "members" value out of this JSON where the name value is "PROD_poolgroup"

What the syntax would be to pull the "members" value out of this JSON where the name value is "PROD_poolgroup".
I think it should be [?config.name == "PROD_poolgroup"].config.members
I've tried other variations without success also.
"all_members": [
{
"config": {
"_last_modified": "1594434546441212",
"cloud_ref": "https://192.168.86.20/api/cloud/cloud-5a7a41cb-156e-43f4-ad28-031b27dac813",
"implicit_priority_labels": false,
"members": [{
"pool_ref": "https://192.168.86.20/api/pool/pool-cb436bba-000a-4d72-8ff5-7d6cdf1ac2fa",
"ratio": 1
}],
"min_servers": 0,
"name": "PROD_poolgroup",
"tenant_ref": "https://192.168.86.20/api/tenant/admin",
"url": "https://192.168.86.20/api/poolgroup/poolgroup-e08933c0-d142-4787-9990-45f94dfc6b89",
"uuid": "poolgroup-e08933c0-d142-4787-9990-45f94dfc6b89"
},
"uuid": "poolgroup-e08933c0-d142-4787-9990-45f94dfc6b89"},
{
"config": {
"_last_modified": "1594404797173635",
"cloud_ref": "https://192.168.86.20/api/cloud/cloud-5a7a41cb-156e-43f4-ad28-031b27dac813",
"implicit_priority_labels": false,
"members": [{
"pool_ref": "https://192.168.86.20/api/pool/pool-f98ed65c-00b2-4638-83df-8b89df79deec",
"ratio": 1
}],
"min_servers": 0,
"name": "QA_poolgroup",
"tenant_ref": "https://192.168.86.20/api/tenant/admin",
"url": "https://192.168.86.20/api/poolgroup/poolgroup-0b19b515-9ae6-41ef-9111-00e61470e615",
"uuid": "poolgroup-0b19b515-9ae6-41ef-9111-00e61470e615"},
"uuid": "poolgroup-0b19b515-9ae6-41ef-9111-00e61470e615"
}
]
Use either single quote or backquote for using literal expression to compare value of name. Below are two working examples:
Using single quote:
- debug:
msg: "{{ all_members | json_query(query) | list }}"
vars:
query: "[?config.name == 'PROD_poolgroup'].config.members"
Using literal expression:
- debug:
msg: "{{ all_members | json_query(query) | list }}"
vars:
query: '[?config.name == `"PROD_poolgroup"`].config.members'

Ansible : Return a attribute from list, with filter applied on another attribute

I am getting the below dictionary from calling python library called from Ansible.
{
"replication_detail": [
{
"name": "xxx.203.server:11111",
"self": true,
"state": 1,
"stateStr": "PRIMARY",
"syncSourceHost": "",
"syncingTo": ""
},
{
"name": "xxx.204.server:11111",
"state": 2,
"stateStr": "SECONDARY",
"syncSourceHost": "xxx.203,server:11111",
"syncingTo": "xxx.203,server:11111"
},
{
"name": "xxx.205,server:11111"
"state": 8,
"stateStr": "(not reachable/healthy)",
"syncSourceHost": "",
"syncingTo": ""
}
]
}
I wanted to have a filter which look into another element which is "StateStr" should be in ["PRIMARY","SECONDARY"] and return the "name"
I tried match or equalto but they all take only one value. Is there other any function which can look into multiple search values.
I am trying to get the data using map in single line rather than with_loop.
the code like
"select name from replication_detail where sateStr in (PRIMARY, SECONDARY)"
replication_detail| stateStr in (PRIMARY, SECONDARY)) | map(attribute="name"|list
You can use the selectattr filter to filter a list of dictionaries by an attribute. For example, if the data in your question is contained in a variable named data, then the following task:
- debug:
msg: "name: {{ item }}"
loop: "{{ data.replication_detail|selectattr('stateStr', 'match', 'SECONDARY|PRIMARY')|map(attribute='name')|list }}"
Would output:
TASK [debug] **********************************************************************************************************************************************************************************
ok: [localhost] => (item=xxx.203.server:11111) => {
"msg": "name: xxx.203.server:11111"
}
ok: [localhost] => (item=xxx.204.server:11111) => {
"msg": "name: xxx.204.server:11111"
}
Would output:

Remove brackets from ansible json_query

I'm trying to parse json in ansible and I got the value I need but the output is an array. How can I get just the value?
Example json:
{
"Version": "2015-08-13",
"Accounts": [{
"AccountName": "account1",
"Regions": [{
"RegionName": "region1",
"RegionId": "region1",
"RegionDetails": [{
"id": "id1",
"version": "v1"
}, {
"id": "id2",
"version": "v2"
}]
}]
}, {
"AccountName": "account2",
"Regions": [{
"RegionName": "region1",
"RegionId": "region1",
"RegionDetails": [{
"id": "id1",
"version": "v1"
}, {
"id": "id2",
"version": "v2"
}]
}]
}]
}
Ansible playbook example:
- name: Set Global Vars
hosts: localhost
tasks:
- name: print json file
debug:
msg: "{{ (lookup('file','./example.json') | from_json) | json_query(query) }}"
vars:
query: "Accounts[?AccountName=='account1'][Regions[?RegionName=='region1'].RegionId]"
register: region_id
Ansible output:
TASK [print json file] *********************************************************
ok: [localhost] => {
"msg": [
[
[
"region1"
]
]
]
}
As you can see the value 'region1' is still nested. How can I get just the value out?
Thanks!
Your original data has nested lists: Accounts is a list, each account contains Regions list.
With your JMESPath query you filter lists by some criteria, but result is still a list, because your data may have more then one account with name AccountName=='account1'.
If you are interested only in first found account and first found region of that account, you can modify query as follows:
Accounts[?AccountName=='account1'] | [0].Regions[?RegionName=='region1'] | [0].RegionId

Resources