JSON_QUERY Not Working when JSON key contains Colon - ansible

My JSON File
{
"msg": {
"changed": false,
"failed": false,
"ontap_info": {
"ontap_version": "160",
"volume_info": {
"testvol1:test1": {
"encrypt": "false",
"encryption_state": "none",
"encryption_type": "none",
"key_id": null,
"volume_antivirus_attributes": {
"on_access_policy": "default"
},
},
"testvol2:test2": {
"encrypt": "false",
"encryption_state": "none",
"encryption_type": "none",
"key_id": null,
"volume_antivirus_attributes": {
"on_access_policy": "default"
},
},
},
},
},
}
My Task
- name: Volume Aggr Info
raw: |
VOLUME_NAME="{{ ontap_volume_info | json_query( info ) | json_query( "'item'" ) | json_query( volumename ) }}"
delegate_to: localhost
loop: "{{ ontap_volume_info.ontap_info.volume_info.keys() | list }}"
I have to loop through the key which contains the colon, for example "testvol2:test2".
I tried multiple solutions and nothing is working. When I try to display the VOLUME_NAME variable, it is displaying an empty string.

Q: "Loop through the key which contains the colon, for example, "testvol2:test2"
A: Each of the keys must be unique. YAML places no further restrictions on the nodes.
Given a valid JSON in the variable my_data. The task below does the job
- debug:
msg: "{{ my_data.ontap_info.volume_info[item] }}"
loop: "{{ my_data.ontap_info.volume_info.keys()|list }}"
should give
ok: [localhost] => (item=testvol1:test1) => {
"msg": {
"encrypt": "false",
"encryption_state": "none",
"encryption_type": "none",
"key_id": null,
"volume_antivirus_attributes": {
"on_access_policy": "default"
}
}
}
ok: [localhost] => (item=testvol2:test2) => {
"msg": {
"encrypt": "false",
"encryption_state": "none",
"encryption_type": "none",
"key_id": null,
"volume_antivirus_attributes": {
"on_access_policy": "default"
}
}
}

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"

Parse / Loop ansible registered variable

Trying to figure out how to filter out the list of UserNames in the output of the following playbook.
- name: Get all users
ome_user_info:
hostname: "{{ dellome_hostname }}"
username: "{{ dellome_username }}"
password: "{{ dellome_password }}"
register: users
Now the output provides the following:
ok: [192.168.1.100] => {
"users": {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"deprecations": [
{
"msg": "Distribution Ubuntu 18.04 on host 192.168.1.100 should use /usr/bin/python3, but is using /usr/bin/python for backward compatibility with prior Ansible releases. A future Ansible release will default to using the discovered platform python for this host. See https://docs.ansible.com/ansible/2.8/reference_appendices/interpreter_discovery.html for more information",
"version": "2.12"
}
],
"failed": false,
"user_info": {
"192.168.1.100": {
"#odata.context": "/api/$metadata#Collection(AccountService.Account)",
"#odata.count": 3,
"value": [
{
"#odata.id": "/api/AccountService/Accounts('10066')",
"#odata.type": "#AccountService.Account",
"Description": "admin",
"DirectoryServiceId": 0,
"Enabled": true,
"Id": "10066",
"IsBuiltin": true,
"Locked": false,
"Name": "admin",
"Password": null,
"Permissions#odata.navigationLink": "/api/AccountService/Accounts('10066')/Permissions",
"RoleId": "10",
"UserName": "admin",
"UserTypeId": 1
},
{
"#odata.id": "/api/AccountService/Accounts('10102')",
"#odata.type": "#AccountService.Account",
"Description": null,
"DirectoryServiceId": 0,
"Enabled": true,
"Id": "10102",
"IsBuiltin": false,
"Locked": false,
"Name": "dell",
"Password": null,
"Permissions#odata.navigationLink": "/api/AccountService/Accounts('10102')/Permissions",
"RoleId": "10",
"UserName": "dell",
"UserTypeId": 1
},
{
"#odata.id": "/api/AccountService/Accounts('10233')",
"#odata.type": "#AccountService.Account",
"Description": null,
"DirectoryServiceId": 10232,
"Enabled": true,
"Id": "10233",
"IsBuiltin": false,
"Locked": false,
"Name": "Domain Users",
"Password": null,
"Permissions#odata.navigationLink": "/api/AccountService/Accounts('10233')/Permissions",
"RoleId": "10",
"UserName": "Domain Users",
"UserTypeId": 2
}
]
}
}
}
}
I was able to determine the following from the output of the registered variable users.
- debug:
var: "{{ users | length }}"
This provides me the length of 5. Which makes sense to an extent. If I start poking into the output I can then determine the following:
- debug:
var: "{{ users.user_info | length }}"
This shows me the length of 1 which makes sense. If I add the var using users.user_info I can then see the output below.
TASK [manage_users : debug] *************************************************************************************************************************************************************
ok: [192.168.1.100] => {
"users.user_info": {
"192.168.1.100": {
"#odata.context": "/api/$metadata#Collection(AccountService.Account)",
"#odata.count": 3,
"value": [
{
"#odata.id": "/api/AccountService/Accounts('10066')",
"#odata.type": "#AccountService.Account",
"Description": "admin",
"DirectoryServiceId": 0,
"Enabled": true,
"Id": "10066",
"IsBuiltin": true,
"Locked": false,
"Name": "admin",
"Password": null,
"Permissions#odata.navigationLink": "/api/AccountService/Accounts('10066')/Permissions",
"RoleId": "10",
"UserName": "admin",
"UserTypeId": 1
},
{
"#odata.id": "/api/AccountService/Accounts('10102')",
"#odata.type": "#AccountService.Account",
"Description": null,
"DirectoryServiceId": 0,
"Enabled": true,
"Id": "10102",
"IsBuiltin": false,
"Locked": false,
"Name": "dell",
"Password": null,
"Permissions#odata.navigationLink": "/api/AccountService/Accounts('10102')/Permissions",
"RoleId": "10",
"UserName": "dell",
"UserTypeId": 1
},
{
"#odata.id": "/api/AccountService/Accounts('10233')",
"#odata.type": "#AccountService.Account",
"Description": null,
"DirectoryServiceId": 10232,
"Enabled": true,
"Id": "10233",
"IsBuiltin": false,
"Locked": false,
"Name": "Domain Users",
"Password": null,
"Permissions#odata.navigationLink": "/api/AccountService/Accounts('10233')/Permissions",
"RoleId": "10",
"UserName": "Domain Users”,
"UserTypeId": 2
}
]
}
}
}
Trying to figure out how I can loop through and get an array of the following: value —> UserName. Essentially I am going to take the following value and loop through and delete users that don’t equal the following. Admin, dell, domain users.
Now one might say you would easily just say while not = to items - then that list would work - I first need to figure out how to search and get the values out. I have tried the following:
- debug:
var: users.user_info().value()
- debug:
var: users.user_info.find('UserName')
- debug:
msg: UserName
loop: users.user_info."192.168.1.100".value
#- debug:
# var: users.user_info."{{ dellome_hostname }}".UserName
#- debug:
# var: "(claims1 | from_json).value"
# msg: "{{ users.user_info.UserName | list }}"
# (output_text.stdout | from_json).ismaster
#- debug:
# msg: "{{ item }}"
#loop: "{{ users.user_info | from_json | list }}"
At the end of this once I understand how to get the data out i can then create a loop to execute the following:
---
- name: Delete a User in Dell OME
ome_user:
hostname: "{{ dellome_hostname }}"
username: "{{ dellome_username }}"
password: "{{ dellome_password }}"
state: "{{ requestedState }}"
name: "{{ requstedUserName }}"
This is where i can then add the loop to eliminate users that don't meet the list of names i provide. Any help would be greatly appreciated.
Here are some of the errors i have run into.
TASK [manage_users : debug] *************************************************************************************************************************************************************
fatal: [192.168.1.100]: FAILED! => {"msg": "Unexpected templating type error occurred on ({{users.user_info().value()}}): 'dict' object is not callable"}
TASK [manage_users : debug] *************************************************************************************************************************************************************
fatal: [192.168.1.100]: FAILED! => {"msg": "template error while templating string: expected name or number. String: {{users.user_info.\"192.168.1.100\".value()}}"}
Or as i am looking at this - if i can figure out a way to create a loop that looks for the roleID and when it is not equal to 10 then delete the user.
Use json_query. The tasks below
- set_fact:
users_rm: "{{ users.user_info|
json_query('*.value[].UserName') }}"
- debug:
var: users_rm
give
users_rm:
- admin
- dell
- Domain Users
You are running the query at the host 192.168.1.100 and the dictionary users comprises the users from this single host only. If there are more hosts in the dictionary the asterisk '*' in the query above would select them all. It would be better to select users for the particular host the query is running at. For example, the task below gives the same result
- set_fact:
users_rm: "{{ users.user_info[inventory_hostname].value|
map(attribute='UserName')|
list }}"

Ansible getent module's loop output results parsing

I am trying to check if a number of users are present or not in the managed node using getent module and create a list of users who are not present.
The piece of code is:
- getent:
database: passwd
key: "{{ item }}"
fail_key: no
register: x
loop:
- "user1"
- "user2"
- debug: var=x.results
- set_fact:
fail_list: "{{ x.results | }}"
I am stuck at this point.
Is there any way I can save the users who are not present to the variable fail_list as a list?
In the above example, user1 is not present and user2 is present in the managed node.
The ansible version I am using is 2.9 and the debug output is a list of dicts as below:
"x.results": [
{
"ansible_facts": {
"getent_passwd": {
"user1": null
}
},
"ansible_loop_var": "item",
"changed": false,
"failed": false,
"invocation": {
"module_args": {
"database": "passwd",
"fail_key": false,
"key": "user1",
"service": null,
"split": null
}
},
"item": "user1",
"msg": "One or more supplied key could not be found in the database."
},
{
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python",
"getent_passwd": {
"user2": [
"x",
"0",
"0",
"user2",
"/home/user2",
"/bin/bash"
]
}
},
"ansible_loop_var": "item",
"changed": false,
"failed": false,
"invocation": {
"module_args": {
"database": "passwd",
"fail_key": false,
"key": "user2",
"service": null,
"split": null
}
},
"item": "user2"
},
Run getent once and search the list of users. For example
- hosts: localhost
tasks:
- getent:
database: passwd
- debug:
msg: User {{ item }} exists.
loop:
- root
- user1
- user2
when: item in my_users
vars:
my_users: "{{ getent_passwd.keys()|list }}"
gives
ok: [localhost] => (item=root) => {
"msg": "User root exists."
}
skipping: [localhost] => (item=user1)
skipping: [localhost] => (item=user2)

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