Ansible get unique value in loop for register - ansible

Hi friend below is my sample output from a regsiter name dataInfo
ok: [123.23.44.123] => {
"msg": [
{
"changed": true,
"item": [
{
"artifactName": "helloWorld.jar",
"status": "false"
},
"myGroup1"
],
"rc": 0,
"stderr_lines": [],
"stdout": "ok",
"stdout_lines": [
"ok"
]
},
{
"changed": true,
"item": [
{
"artifactName": "helloWorld.jar",
"status": "false"
},
"myGroup2"
],
"rc": 0,
"stderr_lines": [],
"stdout": "ok",
"stdout_lines": [
"ok"
]
}
Below is my code
- name: My ArtifactName Name
debug:
msg: "artifactName = {{ item.item[0].artifactName }}"
loop: "{{ dataInfo.results }}"
when: item.changed | bool == true and item.stdout == "ok"
How can i only display as below
artifactName = helloWorld.jar
rather than
artifactName = helloWorld.jar
artifactName = helloWorld.jar
I have shared my code as shown above. Please advice

As you are looping with dataInfo.results, the debug message will repeat for each "item". If you only want unique artifactName, then you can save it to a variable using json_query and choose to display only unique ones.
Something like this:
# Save list of artifactName found in dataInfo.results even with duplicates
- name: save artifact names
set_fact:
artifact_names: "{{ artifact_names | default([]) + [ item | json_query('item[].artifactName') ] }}"
loop: "{{ dataInfo.results }}"
# Show each item of artifact_names using unique filter to eliminate duplicates
- name: show unique artifact names
debug:
var: item
loop: "{{ artifact_names | flatten | unique }}"
Update:
Below set_fact:
artifact_names: "{{ artifact_names | default([]) + [ item.item[0].artifactName ] }}"
... will work if you get only 1 hash in item like this:
"item": [
{
"artifactName": "helloWorld.jar",
"status": "false"
},
],
But if it may have multiple hashes like below, it won't work:
"item": [
{
"artifactName": "helloWorld.jar",
"status": "false"
},
{
"artifactName": "someother.jar",
"status": "false"
},
...
],
If this is a possibility, then json_query should be used. It can be used exactly like the jq command.

Related

ansible json_query with character "-"

I have this json file and I need extract some data but problem is with this character -
{
"changed": true,
"failed": false,
"meta": {
"request_url": "pm/config/adom/AMIS/obj/dynamic/interface",
"response_code": 0,
"response_data": [
{
"color": 0,
"defmap-zonemember": [],
"description": "BYOD VLAN sub-interface.\nUsed in policy for firewalls maintaining BYOD traffic on LIBOs",
"dynamic_mapping": null,
"name": "BYOD",
"single-intf": "enable"
},
{
"color": 0,
"defmap-zonemember": [],
"dynamic_mapping": [
{
"_scope": [
{
"name": "ftg02",
"vdom": "dev"
}
],
"intrazone-deny": "enable",
"local-intf": [
"port8"
]
}
],
"name": "DMZ",
"single-intf": "disable"
},
{
"color": 0,
"defmap-zonemember": [],
"description": "Guest VLAN sub-interface. Used in policy for firewalls maintaining Guestnet traffic on LIBOs",
"dynamic_mapping": null,
"name": "Guest",
"single-intf": "enable"
}
]
}
}
I would like to get result of this "name": "DMZ" - DMZ with some condition
if local-intf == port8
I have got this error
FAILED! => {"msg": "template error while templating string: expected token ',', got 'local'. String: {{ item | json_query('dynamic_mapping[0]['local-intf'][0]') }}"}
here is my playbook which does not work \
- name: interface
debug:
msg: "{{ item.name }}"
loop: "{{ interface_info.meta.response_data }}"
when:
- item.dynamic_mapping != 'null'
- item | json_query('dynamic_mapping[0]._scope[0].name') == 'ftg02'
- item | json_query('dynamic_mapping[0]._scope[0].vdom') == 'dev'
- item | json_query('dynamic_mapping[0]['local-intf'][0]) == 'port8' #this line does not work
is some way to dont use loop ? Loop is to slow .
thank you for help
Try this
- debug:
msg: "{{ interface_info.meta.response_data|
selectattr('dynamic_mapping')|
selectattr('dynamic_mapping.0.local-intf.0', '==', 'port8')|
selectattr('dynamic_mapping.0._scope.0.name', '==', 'ftg02')|
selectattr('dynamic_mapping.0._scope.0.vdom', '==', 'dev')|
map(attribute='name')|first }}"
should give the first item
msg: DMZ

How to merge values with the same key in a json in ansible

I would like to merge a value from 1 json to another based on a particular Key value.
Please find below code, which gives me only an empty array while merging. The main problem is that gp_value var is having an empty array.
I would like to merge gpfinalgpid from gpidmgmtfinal.json to gp-test.json matching the gpfinalnet and networkId value.
I have tried adding First fo the gp_value, but that throws an error saying No first item, sequence was empty
tasks:
- name: Combine GP
vars:
gplist: "{{ lookup('file', 'gpidmgmtfinal.json') | from_json }}"
gpconf: "{{ lookup('file', 'gp-test.json') | from_json }}"
gp: >-
{{
gplist
| json_query('results[*].ansible_facts[]')
}}
gp_value: >-
{{
gp
| selectattr('gpfinalnet', '==', item.networkId)
| map(attribute='gpfinalgpid')
| list
| default(None)
}}
set_fact:
value: "{{ gp_value }}"
result: >-
{{
result | default([])
+
[item | combine({'gpid': gp_value})]
}}
loop: "{{ gpconf }}"
gplist JSON:
{
"changed": false,
"msg": "All items completed",
"results": [
{
"ansible_facts": {
"gpfinalgpid": "101",
"gpfinalnet": "L_456789 "
},
"ansible_loop_var": "item",
"changed": false,
"failed": false,
"item": [
{
"gpmgmtcurrent": {
"L_456789": [
"102"
]
}
},
{
"L_456789": [
"101"
]
}
]
},
{
"ansible_facts": {
"gpfinalgpid": "103",
"gpfinalnet": "N_11447788 "
},
"ansible_loop_var": "item",
"changed": false,
"failed": false,
"item": [
{
"gpmgmtcurrent": {
"N_11447788": [
"101"
]
}
},
{
"N_11447788": [
"103"
]
}
]
}
],
"skipped": false
}
gpconf JSON:
[
{
"name": "MGMT",
"applianceIp": "2.2.2.2",
"groupPolicyId": "100",
"networkId": "L_456789",
"subnet": "2.2.2.1/28"
},
{
"name": "MGMT",
"applianceIp": "1.1.1.2",
"groupPolicyId": "101",
"networkId": "N_11447788",
"subnet": "1.1.1.1/28"
} ]
Current Output: The new line with key gpid but with a value and not an empty array.
{
"applianceIp": "1.1.1.2",
"gpid": [],
"groupPolicyId": "101",
"name": "MGMT",
"networkId": "N_11447788",
"subnet": "1.1.1.1/28"
}
Expected Output:
{
"applianceIp": "1.1.1.2",
"gpid": 103,
"groupPolicyId": "101",
"name": "MGMT",
"networkId": "N_11447788",
"subnet": "1.1.1.1/28"
}
This was a basic mistake from my side. I had an extra space in the gplist json for the gpfinalnet. after removing the extra space everything works fine.
With extra space
"gpfinalnet": "N_11447788 "
Without extra space:
"gpfinalnet": "N_11447788"

Ansible, how to query deeply nested json keys

I'm using Ansible to make an API call that returns a huge data set, and I need to be able to get a nested value to print to the screen. I tried using json_query but not sure what I'm doing wrong.
My task:
- name: Get certificate by CN name.
uri:
method: GET
url: "https://mayapi/api/1/certificates?filter=cn;{{ inventory_hostname }}"
headers:
Authorization: Bearer {{ login.json.token }}
Content-Type: application/json
validate_certs: no
register: certs
- name: Print certs for application
debug:
msg: "{{ certs.json | json_query(items) }}"
This is a small snippet of the output. I want to be able to print ID, and email.
{
"msg": {
"changed": false,
"connection": "close",
"content_length": "65833",
"content_type": "application/json",
"cookies": {},
"cookies_string": "",
"date": "Mon, 10 May 2021 21:33:29 GMT",
"elapsed": 0,
"failed": false,
"json": {
"items": [
{
"active": true,
"application": [
{
"director": {
"active": true,
"email": "user#domain.com",
"fullname": "John Doe",
"id": 1611,
"manager": "John Doe",
"managerEmail": "johndoe#email.com",
"username": "jdoe"
},
...
...
...
}
I get the following error indicating "certs.items" doesn't exist:
FAILED! => {"msg": "Error in jmespath.search in json_query filter plugin:\n'items' is undefined"}
I was expecting all of the items to get printed to the screen and then if I wanted something below items I would do items.active, items.application, etc... But this is not correct since I keep erroring out.
I also tried looping through cert.json and cert.json.items:
- name: Print certs for application
debug:
msg: "{{ item.application.name }}"
loop: "{{ certs.json}}"
But get this error message:
{"msg": "Invalid data passed to 'loop', it requires a list, got this instead: {u'items': [{u'status': u'Active-Pending Install'...shows all the data of the nested json
Then I tried this:
- name: Print certs for application
debug:
msg: "{{ item.application.name }}"
loop: "{{ certs.json.items}}"
But got this error message:
{"msg": "Invalid data passed to 'loop', it requires a list, got this instead: <built-in method items of dict object at 0x7f0c9ec43050>. 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."}
Made some progress with this:
- name: Print certs for application
debug:
msg: "KEY:::: {{ item.key }}, VALUE:::: {{ item.value.0 }}"
loop: "{{ lookup('dict', certs.json) }}"
when: "'items' in item.key"
ignore_errors: yes
But this only prints items in index 0 of the list:
"msg": "KEY:::: items, VALUE:::: {u'status': u'Active-Pending Install', u'serialHex': u'1111', u'validityStart': u'2021-05-10T21:01:36+00:00', u'cn': u'node2.test.corp.net', u'validityEnd': u'2023-05-10T21:11:36+00:00', u'application': [{u'uuid': u'2222', u'name': u'abc'}], u'certType': u'CertType.INTERNAL', u'id': 2582, u'issuer': u'server1'}"
I'm trying to print the 'cn', 'id', and 'serialHex' values from each list element for the key 'items'.
This is the data set that I'm trying to query with Ansible:
{
"total": 2,
"items": [
{
"application": [
{
"uuid": "111",
"name": "CDE"
}
],
"validityEnd": "2023-05-10T21:11:36+00:00",
"certType": "CertType.INTERNAL",
"issuer": "server1",
"id": 2582,
"validityStart": "2021-05-10T21:01:36+00:00",
"status": "Active-Pending Install",
"serialHex": "aaa",
"cn": "node2.corp.net"
},
{
"application": [
{
"uuid": "222",
"name": "CDE"
}
],
"validityEnd": "2023-05-10T21:05:26+00:00",
"certType": "CertType.INTERNAL",
"issuer": "server1",
"id": 2581,
"validityStart": "2021-05-10T20:55:26+00:00",
"status": "Active-Pending Install",
"serialHex": "bbbb",
"cn": "node1.corp.net"
}
]
}
You are regrettably stepping on a quirk of "objects in ansible are python dicts" in that .items() and .keys() and quite a few other attributes-which-are-methods cannot be referenced using the . notation since jinja2 believes you intend to call that method. Rather, one must use the __getitem__ syntax of ["items"] in order to make it abundantly clear that you mean the dict key, and not the method of the same name
tasks:
- name: use json_query as you were originally asking
debug:
msg: >-
{{ certs.json | json_query('items[*].{c: cn,i: id,s: serialHex}') }}
- name: or a jinja2 for loop as you separately attempted
debug:
msg: >-
[
{%- for i in certs.json["items"] -%}
{{ "" if loop.first else "," }}
{{ [i.cn, i.id, i.serialHex ]}}
{%- endfor -%}
]
produces the output from their respective steps:
TASK [debug] ******************************************************************************************************************************
ok: [localhost] => {
"msg": [
{
"c": "node2.corp.net",
"i": 2582,
"s": "aaa"
},
{
"c": "node1.corp.net",
"i": 2581,
"s": "bbbb"
}
]
}
TASK [debug] ******************************************************************************************************************************
ok: [localhost] => {
"msg": [
[
"node2.corp.net",
2582,
"aaa"
],
[
"node1.corp.net",
2581,
"bbbb"
]
]
}

filter a key value from the ansible output

I'm trying to filter a key value from a ansible output. Unable to parse it . Request your assistance on how to pass it. Please find the code below.
Playbook:
- uri:
url: "https://*********/nics/nic1"
method: GET
force_basic_auth: true
headers:
cookie: "{{ login.cookies_string }}"
validate_certs: false
register: test
Output :
ok: [192.168.84.203] => {
"allow": "GET, PUT",
"invocation": {
"module_args": {
"status_code": [
200
],
}
},
"json": {
"body": {
"interfaces": {
"#order": [
"ff7574025754b3df1647001"
],
"ff7574025754b3df1647001": {
"addresses": {
"1": "192.168.1.4/22",
"#order": [
"1"
]
},
"mtu": 1500,
"name": "default",
"source_based_routes": [],
"vlantag": 0
}
},
}
}
}
}
From the above output, I need "ff7574025754b3df1647001" to be printed which will have addresses. Just mentioning below in Bold and Italic on what need to be printed to avoid conflicts.
"#order": [
"ff7574025754b3df1647001"
],
"***ff7574025754b3df1647001***": {
"addresses": {
Please assist ..!
I have tried the below approach..
needle_in_haystack: "192.168.1.4/22"
tasks:
- name: find key for given needle
vars:
key_list: >-
{{
test.json.body.interfaces
| dict2items
| selectattr('value.addresses', 'defined')
| map(attribute='value.addresses')
| map('dict2items')
| flatten
| selectattr('value', 'eq', needle_in_haystack)
| map(attribute='key')
| list
}}
debug:
msg: "This is the list of found keys: {{ key_list }}"

Need to map json to list

I have register variable with below json as value and need to extract name and dn from this JSON to list. tried different options using set_fact without any luck.
{
"nodes": {
"status": -1,
"imdata": [
{
"fabricNode": {
"attributes": {
"status": "",
"dn": "topology/pod-1/node-1",
"name": "NOQCJALAB1"
}
}
},
{
"fabricNode": {
"attributes": {
"status": "",
"dn": "topology/pod-1/node-1",
"name": "NOQCJALAB2"
}
}
}
],
"totalCount": 2,
"changed": false,
"failed": false
},
"changed": false,
"_ansible_verbose_always": true,
"_ansible_no_log": false
}
You need to remove the extraneous calls to map('from_json') because the object is already a dict
- set_fact:
node_names: >-
{{ (nodes.stdout | from_json).data
| map(attribute='fabnode')
| map(attribute='attributes')
| map(attribute='dn')
| list
}}
You would only want those map('from_json') call if your data structure contained embedded JSON, like so:
- set_fact:
inner_value: >-
{{ (example_text | from_json).a_key
| map("from_json")
| map(attribute="inner_key")
| list
}}
vars:
example_text: |
{"a_key": ["{\"inner_key\": \"inner value\"}"]}
It's possible to use json_query. For example the tasks below
- set_fact:
my_list: "{{ nodes.imdata|
json_query('[].{dn: fabricNode.attributes.dn,
name: fabricNode.attributes.name}')
}}"
- debug:
var: my_list
give
"my_list": [
{
"dn": "topology/pod-1/node-1",
"name": "NOQCJALAB1"
},
{
"dn": "topology/pod-1/node-1",
"name": "NOQCJALAB2"
}
]

Resources