How to iterate through two dimensions list with Ansible? - ansible

I have a variable like that :
"files": {
"results": [
{
"files": [
{
"path": "/etc/file1.xml",
},
{
"path": "/etc/file2.xml",
}
]
},
{
"files": [
{
"path": "/etc/file2.xml",
}
]
},
{
"files": []
}
}
}
How can iterate through all paths ?

You don't need to iterate two dimensions to get all paths.
Use map filter to reduce your original list.
To get plain list of paths from your example:
- debug: msg="{{ files.results | map(attribute='files') | sum(start=[]) | map(attribute='path') | list }}"

Related

jq - generate list of dictionaries instead of list of strings

The following command:
cat foo | jq -r '[.items[] | select(.metadata.random_field["foo/foo"] == "true") | .metadata.name]'
results in
[
"test_data"
]
I would like the following output to be:
[
{"name":"test", "data":"test_data"}
]
foo
{
"apiVersion": "v1",
"items":[
{
"metadata": {
"random_field": {
"foo/foo": "true"
},
"creationTimestamp": "2022-03-09T21:54:08Z",
"name": "test_data"
}
}
]
}
UPDATE: added test data so the point can be illustrated properly.
It's not entirely clear where the value for name in the output comes from in your question, but let's assume for a moment that it is the first part until the underscore of the name from the input. The the following produces your required output:
.items | map(
.metadata
| select(.random_field."foo/foo" == "true")
| { name: .name|split("_")|first, data: .name }
)
Output:
[
{
"name": "test",
"data": "test_data"
}
]

How to get nested value from list

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.

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) }}

Ansible JSON parsing empty string

I am trying to learn JSON parsing using jmesquery in Ansible.
Please consider the following play:
---
- name: GET ALL THE INTERFACES
junos_command:
commands: show configuration interfaces | display json
register: A
- name: DISPLAY VARIABLE A CONTENTS
debug:
var: A.stdout_lines
- name: JOSN QUERY TO STORE PORTS IN NEW VARIABLE ALL_PORTS
set_fact:
ALL_PORTS: "{{ A.stdout_lines | json_query(jmesquery) }}"
vars:
jmesquery: 'configuration.interfaces.interface[*].name'
- name: DISPLAY VARIABLE ALL_PORTS CONTENTS
debug:
var: ALL_PORTS
#
Based on the JSON query, the port ge-0/0/0 will be stored in ALL_PORT, but we do not see that when we run the playbook, debug on ALL_PORT shows it is empty.
PLAY [ROUTER-STIG-PLAYBOOK] ************************************************************************************************
TASK [STIG_ROUTER : GET ALL THE INTERFACES] ********************************************************************************
ok: [192.168.22.9]
TASK [STIG_ROUTER : DISPLAY VARIABLE A CONTENTS] ***************************************************************************
ok: [192.168.22.9] => {
"A.stdout_lines": [
{
"configuration": {
"#": {
"junos:changed-localtime": "2020-05-10 11:14:49 UTC",
"junos:changed-seconds": "1589109289",
"xmlns": "http://xml.juniper.net/xnm/1.1/xnm"
},
"interfaces": {
"interface": [
{
"name": "ge-0/0/0",
"unit": [
{
"family": {
"inet": {
"address": [
{
"name": "192.168.22.9/24"
}
]
}
},
"name": 0
}
]
}
]
},
"security": {
"policies": {
"global": {
"policy": [
{
"match": {
"application": [
"any"
],
"destination-address": [
"any"
],
"source-address": [
"any"
]
},
"name": "TEST",
"then": {
"permit": [
null
]
}
}
]
}
},
"screen": {
"ids-option": [
{
"icmp": {
"ping-death": [
null
]
},
"ip": {
"source-route-option": [
null
],
"tear-drop": [
null
]
},
"name": "untrust-screen",
"tcp": {
"land": [
null
],
"syn-flood": {
"alarm-threshold": 1024,
"attack-threshold": 200,
"destination-threshold": 2048,
"queue-size": 2000,
"source-threshold": 1024,
"timeout": 20
}
}
}
]
},
"zones": {
"security-zone": [
{
"name": "trust",
"tcp-rst": [
null
]
},
{
"name": "untrust",
"screen": "untrust-screen"
},
{
"host-inbound-traffic": {
"protocols": [
{
"name": "all"
}
],
"system-services": [
{
"name": "all"
}
]
},
"interfaces": [
{
"name": "ge-0/0/0.0"
}
],
"name": "A"
}
]
}
},
"system": {
"license": {
"autoupdate": {
"url": [
{
"name": "https://ae1.juniper.net/junos/key_retrieval"
}
]
}
},
"root-authentication": {
"encrypted-password": "$6$thcHCjAV$e3o5ZRNWv7WtysOxuKpBP2X0cA3QDNtWYyCSBAUkImSEsulEGTgfwEQBa12Wll0fegpwvZfTHLvCbDUIW1n211"
},
"services": {
"ftp": [
null
],
"netconf": {
"ssh": [
null
]
},
"ssh": {
"root-login": "allow"
}
},
"syslog": {
"file": [
{
"contents": [
{
"any": [
null
],
"name": "any"
},
{
"info": [
null
],
"name": "authorization"
}
],
"name": "messages"
},
{
"contents": [
{
"any": [
null
],
"name": "interactive-commands"
}
],
"name": "interactive-commands"
}
],
"user": [
{
"contents": [
{
"emergency": [
null
],
"name": "any"
}
],
"name": "*"
}
]
}
},
"version": "20191026.124700_builder.r1063854"
}
}
]
}
TASK [STIG_ROUTER : JOSN QUERY TO STORE PORTS IN NEW VARIABLE ALL_PORTS] ***************************************************
ok: [192.168.22.9]
TASK [STIG_ROUTER : DISPLAY VARIABLE ALL_PORTS CONTENTS] *******************************************************************
ok: [192.168.22.9] => {
"ALL_PORTS": ""
}
#
I used online JSON query tester.
https://jsonpath.com/
When I checked my my query "configuration.interfaces.interface[*].name" against A.stdout_lines, I found the expected response i.e
[
ge-0/0/0
]
Any feedback/guidance is appreciated!!
Have a good weekend!!
Your JMESPath may very well be correct for one object but as its name implies, and as your debug: var=A.stdout_lines shows, stdout_lines is a list
So, you can do one of several things:
recognize that your stdout_lines only contains one object and just feed that into json_query as {{ A.stdout_lines[0] | json_query(jmesquery) }}
use the map filter to apply that same filter to every list item, with something like {{ A.stdout_lines | map("json_query", jmesquery) | list }}
rewrite your JMESPath to apply that filter to the input list, akin to json_query("[*].configuration.AND THE REST HERE")
Those last two will naturally produce a different output shape, since they are lists of lists, and so it will look like [['ge-0/0/0']] when output, but they do have the advantage that if your stdout_lines ever does mysteriously start to contain more objects, they will be json_query-ied as expected

Resources