My Task is
- name: task name
shell: openstack floating ip create provider --format json
register: result
The output will be in below json format
{
"router_id": null,
"status": "DOWN",
"description": "",
"created_at": "2017-05-24T10:49:15Z",
"updated_at": "2017-05-24T10:49:15Z",
"floating_network_id": "923-cc77237b08e7",
"headers": "",
"fixed_ip_address": null,
"floating_ip_address": "192.*.*.*",
"revision_number": 1,
"project_id": "2709ad381fcf41c5bce673c916fded10",
"port_id": null,
"id": "c5d187elg-d269-4eae-b6ae-7d258f04983"
}
What i want to do is,get only the floating_ip_address and store it into a variable so that i can use it in another task.
Im using the below code for doing this,
- set_fact:
address: "{{ (result.stdout | from_json | selectattr('floating_ip_address') | list | first).floating_ip_address }}"
But Im getting an error
"ERROR! 'unicode object' has no attribute 'floating_ip_address'"
What is correct format to get only the ip address?
If floating_ip_address is not a list, but a simple key as in your input, for example:
- set_fact:
address: "{{ (result.stdout | from_json)['floating_ip_address'] }}"
Related
Very new to JSON.
I'm trying to extract 2 variables from this json file.
It has many files and id's but I only want the file & id if it contains es7.x86_64
When done my desired variables would be:
id=13140
file=NessusAgent-8.3.0-es7.x86_64.rpm
{
"banners": [],
"containsRequiredAuth": true,
"created_at": "2017-10-13T00:53:32.137Z",
"description": "Download Nessus Agents for use with Tenable.io and Nessus Manager",
"documentation_link": null,
"downloads": [
{
"created_at": "2021-06-29T19:06:41.776Z",
"description": "Red Hat ES 7 (64-bit) / CentOS 7 / Oracle Linux 7 (including Unbreakable Enterprise Kernel)",
"file": "NessusAgent-8.3.0-es7.x86_64.rpm",
"id": 13140,
"meta_data": {
"md5": "f67a2bdd2a7180f66b75f319439d56d5",
"product": "Nessus Agents - 8.3.0",
"product_notes": null,
"product_release_date": "06/29/2021",
"product_type": "default",
"release_date": "06/03/2021",
"sha256": "8a6452086ce0a7193e0f24b1f2adbff3aa6bd0f4ac519384e8453bb68bae0460",
"version": "8.3.0"
},
"name": "NessusAgent-8.3.0-es7.x86_64.rpm",
"page_id": 61,
"publish": true,
"required_auth": false,
"size": 16375828,
"sort_order": null,
"type": "download",
"updated_at": "2021-06-29T19:08:47.628Z"
},
My utterly failed attempt to assign file & id variables that have es7.x86_64.
- name: Convert agent_tempfile to json and register result
shell: python -m json.tool "{{ agent_tempfile }}"
register: result
- name: Extract file & id for es7.x86_64 rpm's
set_fact:
agent_id: "{{ result | json_query('downloads[*es7.x86_64*].id') | first }}"
agent_file: "{{ result | json_query('downloads[*es7.x86_64*].file') | first }}"
I have a feeling I'm going to be doing a lot more of these types of queries soon. Can some one also direct me to a good guide that details parsing specific values from JSON output? The stuff I've found so far just lists arrays but I really want to know how to pull specific data out.
First, there are some great tools out there for playing with JMESPath syntax (the syntax used by the json_query filter). The examples in the JMESPath tutorial are all "live": you can paste your own data into the text fields, and then experiment with filters and check the result.
The jpterm command is a terminal tool for experimenting with JMESPath queries. This is my personal favorite.
To look for items that contain a specific substring (like es7.x86_64), you can use the contains operator, like this:
json_query("downloads[?contains(name, 'es7.x86_64')]")
To make this work for your code, we first need to deal with the fact
that the result of your first task is going to be a string, rather
than a dictionary. We'll need to pass the standard output through the
from_json filter.
We can also avoid having two almost identical json_query expression
by moving the bulk of the expression into a task-local variable.
This gives us something like:
- hosts: localhost
gather_facts: false
tasks:
- command: cat data.json
register: result
- set_fact:
agent_id: "{{ selected[0].id }}"
agent_file: "{{ selected[0].file }}"
vars:
selected: >-
{{
result.stdout |
from_json |
json_query("downloads[?contains(name, 'es7.x86_64')]")
}}
- debug:
msg:
- "ID: {{ agent_id }}"
- "FILE: {{ agent_file }}"
When that task runs, the value of selected will be something like:
[
{
"file": "NessusAgent-8.3.0-es7.x86_64.rpm",
"id": 13140,
"name": "NessusAgent-8.3.0-es7.x86_64.rpm",
"page_id": 61,
"publish": true,
"required_auth": false,
"size": 16375828,
"sort_order": null,
"type": "download",
"updated_at": "2021-06-29T19:08:47.628Z"
}
]
This assumes you're only expecting a single result, so we can just ask
for selected[0] to get at that dictionary, and then it's a simple
matter of getting at the .id and .file attributes.
Running the above playbook produces:
TASK [debug] *********************************************************************************
ok: [localhost] => {
"msg": [
"ID: 13140",
"FILE: NessusAgent-8.3.0-es7.x86_64.rpm"
]
}
Im using ansible 2.9.2 and i have this playbook :
register: output
- debug: msg={{ output.instance }}
which gives this output:
TASK [debug] ***************************************************************************************************************************************************************
ok: [localhost] => {
"msg": {
"annotation": "",
"current_snapshot": null,
"customvalues": {},
"guest_consolidation_needed": false,
"guest_question": null,
"guest_tools_version": "0",
"hw_cluster": null,
"hw_datastores": [
"V1",
],
"hw_esxi_host": "10.10.101.10",
"hw_eth0": {
"addresstype": "assigned",
"ipaddresses": null,
"label": "",
"macaddress": "00:00:00:00:00:51",
"portgroup_key": null,
"portgroup_portkey": null,
"summary": "Vlan1"
How can i get the output to give me onlythe "ipaddresses": null?
I tried this :
debug: msg={{ output.instance | json_query('hw_eth0{}.ipaddresses') }}
but got an error
FAILED! => {"msg": "JMESPathError in json_query filter plugin:\\ninvalid token: Parse error at column 7, token \\"{\\" (LBRACE), for expression:\\n\\"hw_eth0{}.ipaddresses
Your jmespath expression is wrong. You can check the doc for more details
The following should work
- debug:
msg: "{{ output.instance | json_query('hw_eth0.ipaddresses') }}"
Meanwhile, you really don't need json_query in this situation where you just have to read the value in the hash:
- debug:
var: output.instance.hw_eth0.ipaddresses
Note that in the output, ansible will automatically transform the json null value to an empty string.
From the name, I guess this parameter is supposed to return a list when not empty. If you ever need to check on that in your playbook, the best practice is to verify the parameter length, e.g:
- name: Do something only when there are configured IPs
debug:
msg: There is at least one IP configured
when: output.instance.hw_eth0.ipaddresses | length > 0
I am using the URI module and I get a JSON response back. This is my playbook so far.
.. some playbook ..
register: output
- debug: msg="{{ output }}"
- name: get job id
set_fact:
job_id: "{{ output.json.results }}"
- debug: msg="{{ job_id }}"
Here’s the output of job_id from the debug above:
ok: [localhost] => {
"msg": [
{
"approval_state": "pending_approval",
"created_on": "2018-12-18T22:48:40Z",
"description": "Provision from [tpl] to [test]",
"href": "https://foo.ca/api/provision_requests/1000000000143",
"id": "1000000000143",
"message": "VM Provisioning - Request Created",
"options": {
"addr_mode": [
"dhcp",
"DHCP"
],
"auto_approve": false,
"cluster_filter": [
null,
null
],
"cores_per_socket": [
2,
"2"
],
I want to extract the “id” in the 5th line of the JSON output above. Any ideas?
I tried output.json.results.id but that errors out with no object id found
If you look at the JSON that has been produced, you actually have a list of dictionaries, albeit in this particular case, you have a list containing a single dictionary. So given the exact example:
- debug:
msg: "{{ job_id[0].id }}"
will extract the id field.
If you want to extract the id fields from every dictionary in the list (assuming multiple dictionaries are possible), you could instead do:
- debug:
msg: "{{ job_id | map(attribute='id') | list }}"
which will produce a simple list containing the contents of the id field in each dictionary.
My Task is
- name: task name
shell: some command --format json
register: result
The output will be in below json format
[
{
"mac_address": "x.x.x.x.x.x",
"fixed_ips": "{\"subnet_id\": \"s-s-s-s\",\"ip_address\": \"172.*.*.*\"}",
"id": "1",
"name": ""
},
{
"mac_address": "x.x.x.x",
"fixed_ips": "{\"subnet_id\": \"s-s-s-s\", \"ip_address\": \"192.*.*.*\"}",
"id": "2",
"name": ""
}
]
What i want to do is,get only the ip address that starts with 192 and store it into a variable so that i can use it in another task.
If it is a list of dicts, use selectattr:
"{{ (result.stdout | from_json | selectattr('ip_address','match','^192') | list | fist).ip_address }}"
I assume that you need only one element, so I use first to get single element from the list.
Updated expression due to modifications of input data:
- set_fact:
ip_address: "{{ ( result.stdout |
from_json |
map(attribute='fixed_ips') |
map('from_json') |
selectattr('ip_address','match','^192') |
list |
first
).ip_address }}"
fixed_ips is a string, so you need to apply from_json with map to convert every item to be able to apply selectattr filter.
I have an issue to parse a json using ansible
I have a task that connected to rancher and get a json file
task:
- uri:
url: http://rancher.local:8080/v1/hosts
method: GET
user: ##################
password: ################
body_format: json
register: hosts_json
- name: test
set_fact:
rancher_env_hosts: "{{ item.hostname }}"
#when: item.hostname == "*-i-*"
with_items: "{{hosts_json.json.data}}"
- name: output
debug:
msg: "hosts: {{rancher_env_hosts}}"
and I get the following json (after edit it to be more readable):
{
"json": {
"data": [
{
"hostname": "rancher-i-host-02",
"id": "adsfsa"
},
{
"hostname": "rancher-i-host-01",
"id": "gfdgfdg"
},
{
"hostname": "rancher-q-host-01",
"id": "dfgdg"
},
{
"hostname": "rancher-q-host-02",
"id": "dfgdg"
}
]
}
}
When I start the playbook I get only the last host name in the variable and not all the list of hostname. can I register all the list to the same variable?
In addition, I also added a line with the a comment "#" in order to get only the host names that match the string "-i-" bit it's not working. any idea?
This is what filters (and this) for:
- set_fact:
hosts_all: "{{ hosts_json.json.data | map(attribute='hostname') | list }}"
hosts_i: "{{ hosts_json.json.data | map(attribute='hostname') | map('regex_search','.*-i-.*') | select('string') | list }}"
host_all will contain all hostnames, host_i will contain only .*-i-.* matching hostnames.
Try this
- uri:
url: http://rancher.local:8080/v1/hosts
method: GET
user: ##################
password: ################
body_format: json
register: hosts_json
- name: init fact
set_fact:
rancher_env_hosts: "[]"
- name: test
set_fact:
rancher_env_hosts: "{{rancher_env_hosts}} + [ {{item.hostname}} ]"
when: item.hostname | search(".*-i-.*")
with_items: "{{hosts_json.json.data}}"
- name: output
debug:
msg: "hosts: {{rancher_env_hosts}}"
About search you can read here http://docs.ansible.com/ansible/playbooks_tests.html
UPD:
About adding values to array here: Is it possible to set a fact of an array in Ansible?