Searching a value in a list of dict in Ansible - ansible

First of all, I know it's kind of a duplicate question : I found similar topics here :
Searching for key in a list of dicts in Ansible, Ansible lookup values from complex structure?
I don't know if I have to ask my question directly within those topics or not, if so, I sincerely apologize.
Anyways, in Ansible, I need to extract a specific ID within an API query from a web application.
I have this code :
- name: API query
uri:
method: GET
url: "{{ apiquery }}"
headers:
Content-Type: application/json
App-Token: "{{ appToken }}"
Session-Token: "{{ currentSessionToken.json.session_token }}"
register: wantedState
- name: DEBUG | wantedState output
debug:
msg: "{{ wantedState }}"
The message is this :
ok: [localhost] => {
"msg": {
"accept_range": "State 1000",
"access_control_expose_headers": "content-type, content-range, accept-range",
"cache_control": "no-store, no-cache, must-revalidate",
"changed": false,
"connection": "close",
"content_length": "138",
"content_range": "0-1/2",
"content_type": "application/json; charset=UTF-8",
"cookies": {},
"cookies_string": "",
"date": "Thu, 24 Jan 2019 11:51:42 GMT",
"expires": "Mon, 26 Jul 1997 05:00:00 GMT",
"failed": false,
"json": {
"content-range": "0-1/2",
"count": 2,
"data": [
{
"1": "state1",
"2": 12
},
{
"1": "state11",
"2": 10
}
],
"order": "ASC",
"sort": 1,
"totalcount": 2
},
"msg": "OK (138 bytes)",
"pragma": "no-cache",
"redirected": false,
"server": "Apache/2.4.18 (Ubuntu)",
"status": 200,
"url": "..."
}
}
What I need is to get the proper ID associated with the stateName variable.
I followed the advice given in the two other topics and my syntax is this one:
- name: DEBUG | Displaying ID
debug:
msg: "{{ (wantedState.json.data | selectattr('1', 'equalto', stateName) | list | first).2 }}"
I got the following error message :
"msg": "The task includes an option with an undefined variable. The error was: dict object has no element 1"
I don't know why my query is not functioning properly to be honnest ...
Thanks in advance,
Simon

Jinja2 converts integer-like strings to numbers under the hood.
So '1' and '2' are used to refer the first and the second elements of a list.
I don't know any way to disable this behaviour in Jinja2.
You have correct syntax in general. If your data items have keys a and b and not 1 and 2, you'd be OK.
For your case you can use JMESPath to filter items:
- name: DEBUG | Displaying ID
debug:
msg: "{{ (wantedState.json.data | json_query('[?\"1\"==`'+stateName+'`]') | first)['2'] }}"
Note that:
double quotes around 1 are escaped, because we are inside YAML quoted string msg: "..."
there are JMESPath literal quotes (back quote) around stateName value
resulting value is accessed via ['2'] (string) and not .2 (int)

Related

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"
]
]
}

how to filter e filter string from list in ansible

this is the list which i have filtered from a nested json using the below json_query
Please see the content of tmpdata
{
"content_length": "4883",
"status": 200,
"cookies": {},
"changed": false,
"strict_transport_security": "max-age=15768000",
"x_api_total_time": "0.234s",
"_ansible_item_result": true,
"_ansible_no_log": false,
"json": {
"job_tags": "",
"type": "job",
"scm_revision": "",
"status": "successful",
"credential": null,
"force_handlers": false,
"job_slice_number": 0,
"ask_credential_on_launch": false,
"started": "2021-02-24T06:48:29.884643Z",
"ask_job_type_on_launch": false,
"start_at_task": "",
"event_processing_finished": true,
"elapsed": 27.82,
"finished": "2021-02-24T06:48:57.704791Z",
"ask_variables_on_launch": true,
"ask_limit_on_launch": false,
"job_slice_count": 1,
"ask_skip_tags_on_launch": false,
"extra_vars": "{\"domain\": \"abc-cn-1\", \"mgmt_password\": \"admin123\", \"mgmt_server\": \"192.168.20.30\", \"fingerprint\": \"9125544D272B5AD28F3E9AB7BC8AA3F276E45064\", \"fwcmd\": \"fw sam -v -J src 192.68.10.10\", \"targets\": [\"abc-cn-c1\"]}",
"use_fact_cache": false,
"name": "test-Checkpoint",
"created": "2021-02-24T06:48:29.003796Z",
"url": "/api/v2/jobs/1198/",
"vault_credential": null,
"verbosity": 4,
"job_args": "[\"ansible-playbook\", \"-u\", \"root\", \"-vvvv\", \"-i\", \"/tmp/awx_1198_e4iie_fm/tmpz4bfietf\", \"-e\", \"#/tmp/awx_1198_e4iie_fm/env/extravars\", \"chkpoint.yml\"]",
"modified": "2021-02-24T06:48:29.720325Z",
"unified_job_template": 7,
"project": 6,
"limit": "",
"timeout": 0,
"host_status_counts": {
"ok": 1
},
"result_traceback": "",
"launch_type": "manual"
},
"server": "nginx/1.12.2",
"connection": "close",
"_ansible_parsed": true,
"allow": "GET, DELETE, HEAD, OPTIONS",
"redirected": false,
"cookies_string": "",
"_ansible_ignore_errors": null
}
i am using the below json_query to filter the output from the tempdata
- name: "search for traget fw"
set_fact:
job_status2: "{{ tmpdata | json_query('[json.status, json.extra_vars]') }}"
please see the output from the above facts, you can see dict inside the list and i want to filter only expected output mentioned below
current output:
ok: [localhost] => {
"msg": [
"successful",
"{\"domain\": \"abc-cn-1\", \"mgmt_password\": \"admxxxxxin123\", \"mgmt_server\": \"192.168.10.20\", \"fingerprint\": \"9125544D272B5AD28F3E9AB7BC8AA3F276E45064\", \"fwcmd\": \"fw sam -v -J src 192.68.10.10\", \"targets\": [\"abc-cn-c1\"]}"
]
}
expected output:
["successful", targets": ["abc-cn-c1"]]
please help me id if this is possible
There are (at least) two answers to your question if you want to continue to use json_query, and one that sidesteps that mess entirely. We'll start with the latter because it's less typing for me :-)
- set_fact:
job_status2: '{{ [ tmpdata.json.status, (tmpdata.json.extra_vars|from_json).targets] }}'
the second is a slight variation on that, in that someone needs to resolve that embedded JSON to a dict and (AFAIK) JMESPath has no such ability
- set_fact:
job_status2: "{{ newdata | json_query('[json.status, json.extra_vars.targets]') }}"
vars:
newdata: >-
{{ tmpdata
| combine({"json":{"extra_vars", tmpdata.json.extra_vars|from_json}}, recursive=True)
}}
I mention that one mostly for the case where you are doing other things with json_query and thus it would be advantageous to know how to coerce the structure to be friendlier for JMESPath
and finally, you can cheat and use the JMESPath literal notation to embed the already JSON-ified string right into the query
- set_fact:
job_status2: "{{ newdata | json_query('[json.status, `' + newdata.json.extra_vars + '`.targets]') }}"

How I can put variable in ansible j2 template correctly

I have problem with ansible j2 template when i run this task
I use this task for create grafana datasource
- name: Get certifacete
slurp:
src: /var/lib/cloudera-scm-server/certmanager/CMCA/ca-db/newcerts/00.pem
register: cert
- name: test
uri:
url: https://127.0.0.1:3000/api/datasources
method: POST
validate_certs: no
force_basic_auth: yes
user: "{{ grafana_admin_user }}"
password: "{{ grafana_admin_password }}"
body: "{{ lookup('template', 'test_template.j2') }}"
body_format: json
headers:
Content-Type: "application/json"
template
{
"name": "Cloudera Manager",
"type": "foursquare-clouderamanager-datasource",
"url":"https://{{ hostvars[groups['tag_Group_cm'][0]]['ec2_private_ip_address'] }}:7183",
"access":"proxy",
"isDefault":false,
"basicauth":true,
"basicAuthUser":"{{ managerUser }}",
"basicAuthPassword":"{{ managerPassword }}",
"jsonData": {
"cmAPIVersion":"{{ cmapi }}",
"tlsAuthWithCACert": true},
"secureJsonData":{
"tlsCACert": "{{ cert['content'] | b64decode | string }}"
},
"database": "foursquare-clouderamanager-datasource"}
I got this error when I use this template with variable
fatal: [10.0.1.31]: FAILED! => {"cache_control": "no-cache", "changed": false, "connection": "close", "content": "[{\"classification\":\"DeserializationError\",\"message\":\"invalid character '\\\\\\\\' looking for beginning of object key string\"},{\"fieldNames\":[\"Name\"],\"classification\":\"RequiredError\",\"message\":\"Required\"},{\"fieldNames\":[\"Type\"],\"classification\":\"RequiredError\",\"message\":\"Required\"},{\"fieldNames\":[\"Access\"],\"classification\":\"RequiredError\",\"message\":\"Required\"}]", "content_length": "359", "content_type": "application/json; charset=utf-8", "date": "Thu, 14 Nov 2019 10:48:45 GMT", "elapsed": 0, "expires": "-1", "json": [{"classification": "DeserializationError", "message": "invalid character '\\\n' looking for beginning of object key string"}, {"classification": "RequiredError", "fieldNames": ["Name"], "message": "Required"}, {"classification": "RequiredError", "fieldNames": ["Type"], "message": "Required"}, {"classification": "RequiredError", "fieldNames": ["Access"], "message": "Required"}], "msg": "Status code was 400 and not [200]: HTTP Error 400: Bad Request", "pragma": "no-cache", "redirected": false, "status": 400, "strict_transport_security": "max-age=86400; preload", "url": "https://127.0.0.1:3000/api/datasources", "x_frame_options": "deny", "x_xss_protection": "1; mode=block"}
When i use template without variable works fine
example debug output without variable:
"body": {
"access": "proxy",
"basicAuthPassword": "passs",
"basicAuthUser": "user",
"basicauth": true,
"database": "foursquare-clouderamanager-datasource",
"isDefault": false,
"jsonData": {
"cmAPIVersion": "v4-5",
"tlsAuthWithCACert": true
},
"name": "Cloudera Manager",
"secureJsonData": {
"tlsCACert": "-----BEGIN CERTIFICATE-----\nMIIEmDCCAwCgAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJVUzEL\nMAkGA1UECAwCQ0ExQTA/BgNVBAMMOFNDTSBMb2NhbCBDQSBvbiBkZXBsb3ltZW50\nIGFicnluZHphLWRldi1kZXZsaWdodC1tYW5hZ2VyMB4XDTE5MTExNDA4NDYxOFoX\nDTQ5MTEwMTIzNTk1OVowXTELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMUEwPwYD\nVQQDDDhTQ00gTG9jYWwgQ0Egb24gZGVwbG95bWVudCBhYnJ5bmR6YS1kZXYtZGV2\nbGlnaHQtbWFuYWdlcjCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBAK5z\nQOfwxFUMbtMGsVNsheJRNx+8en7iyv4emUu2h7VBIwInzqd9qG3gpTjTHPmp/q/T\nnCi9peKT3EbhvCdbzUmyDX8oAHEIZ0ww+oVyz6omDcV9hkWWsm/JEOyZdP2/OLyb\nv4gdm03vfiZXN6/Xz8C8XZtpgM+pq9+aFK8bQuKE2M333xKqoWnPDlBeFXYKeDjZ\ndtR6OKmChXVViQdkXvhTaG48coBmIrDOCUwm1SMYmohltNSzpdfSgX3GSwVse3fM\nbnWlV/ITDjCkklBcJENn86M7Cb8z55gvwqAHD8Xoqmjt/rzS7hQDcUsG0Zy2cOkl\nuq6ClYpn3Gpm4nXU3bYEvpmiYMKo62wgUz2OC0IAWz4WGvoh0maCKtFnErvGkxkR\nS30Ayz5bPPud3m24gnW92uNcJRStVMrlmg/MdpBr+AiuWrImMX2d1kXBd2zh4L78\n1nk5ZCMyaO6kvnTez6cGc8YqJdFIy76Phw2qeEBhjPkA7+w/BVHSIs2eP79wIwID\nAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRmmdoZo1DrE6uSw1GT\n01061RzynTAfBgNVHSMEGDAWgBRmmdoZo1DrE6uSw1GT01061RzynTAOBgNVHQ8B\nAf8EBAMCAgQwDQYJKoZIhvcNAQELBQADggGBAHykOktg6mWPwAXh5RyCKLv+2bVQ\nrtAy4JkTiAsroURm+sdYqQ7KD61vfFI7V1twytOmohfbtJ/4qhcGrh1w1s7yv/a0\nbm7fcG7qViX3QoMaVrgs1wkUQC2JNcT9vPFjHcKA/YtvHVcoYYTPVvr+jS6sbh9e\nvTMu14klVyaqRlPsF30I+xjzCLgZoO7eXCuNV9Lu4zTNWIap6jPKOu8QEXWweUza\nhmn4GyKmrT+1mLhXMqh4U7B2GZdVo9/iY/xcHlVp7UhfOqx1K0OetPn/x+entBR5\nH1uBXU1Yx7tSZ/RN192Af6czMw+THXBh0LgzzJgBIIKdjyy5acLBfh7bnV6PV6G+\nnWWyr4WVrrH4wH3pKisCnIoPpsjEXPSJRnu4PTVELM71l8hZlES9dazRPiMOaxOj\nTfaz1vGa1mDPMbobiN5NH0ueX4LAUDMkpWFuAP+AJ9UqAax+Cq0KX+dUMXqyWY82\nV7jPmgHqYTNRw/zvfdOP1qeqhkIeTp8vPbp3lw==\n-----END CERTIFICATE-----\n"
},
"type": "foursquare-clouderamanager-datasource",
"url": "https://127.0.0.1:7183"
}
Example debug output with variable:
"body": "{\n\"name\": \"Cloudera Manager\",\n\"type\": \"foursquare-clouderamanager-datasource\",\n\"url\":\"https://127.0.0.1:7183\",\n\"access\":\"proxy\",\n\"isDefault\":false,\n\"basicauth\":true,\n\"basicAuthUser\":\"user\",\n\"basicAuthPassword\":\"pass\",\n\"jsonData\": {\n\"cmAPIVersion\":\"v4-5\",\n\"tlsAuthWithCACert\": true},\n\"secureJsonData\":{\n \"tlsCACert\": \"-----BEGIN CERTIFICATE-----\nMIIEmDCCAwCgAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJVUzEL\nMAkGA1UECAwCQ0ExQTA/BgNVBAMMOFNDTSBMb2NhbCBDQSBvbiBkZXBsb3ltZW50\nIGFicnluZHphLWRldi1kZXZsaWdodC1tYW5hZ2VyMB4XDTE5MTExNDA4NDYxOFoX\nDTQ5MTEwMTIzNTk1OVowXTELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkNBMUEwPwYD\nVQQDDDhTQ00gTG9jYWwgQ0Egb24gZGVwbG95bWVudCBhYnJ5bmR6YS1kZXYtZGV2\nbGlnaHQtbWFuYWdlcjCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBAK5z\nQOfwxFUMbtMGsVNsheJRNx+8en7iyv4emUu2h7VBIwInzqd9qG3gpTjTHPmp/q/T\nnCi9peKT3EbhvCdbzUmyDX8oAHEIZ0ww+oVyz6omDcV9hkWWsm/JEOyZdP2/OLyb\nv4gdm03vfiZXN6/Xz8C8XZtpgM+pq9+aFK8bQuKE2M333xKqoWnPDlBeFXYKeDjZ\ndtR6OKmChXVViQdkXvhTaG48coBmIrDOCUwm1SMYmohltNSzpdfSgX3GSwVse3fM\nbnWlV/ITDjCkklBcJENn86M7Cb8z55gvwqAHD8Xoqmjt/rzS7hQDcUsG0Zy2cOkl\nuq6ClYpn3Gpm4nXU3bYEvpmiYMKo62wgUz2OC0IAWz4WGvoh0maCKtFnErvGkxkR\nS30Ayz5bPPud3m24gnW92uNcJRStVMrlmg/MdpBr+AiuWrImMX2d1kXBd2zh4L78\n1nk5ZCMyaO6kvnTez6cGc8YqJdFIy76Phw2qeEBhjPkA7+w/BVHSIs2eP79wIwID\nAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRmmdoZo1DrE6uSw1GT\n01061RzynTAfBgNVHSMEGDAWgBRmmdoZo1DrE6uSw1GT01061RzynTAOBgNVHQ8B\nAf8EBAMCAgQwDQYJKoZIhvcNAQELBQADggGBAHykOktg6mWPwAXh5RyCKLv+2bVQ\nrtAy4JkTiAsroURm+sdYqQ7KD61vfFI7V1twytOmohfbtJ/4qhcGrh1w1s7yv/a0\nbm7fcG7qViX3QoMaVrgs1wkUQC2JNcT9vPFjHcKA/YtvHVcoYYTPVvr+jS6sbh9e\nvTMu14klVyaqRlPsF30I+xjzCLgZoO7eXCuNV9Lu4zTNWIap6jPKOu8QEXWweUza\nhmn4GyKmrT+1mLhXMqh4U7B2GZdVo9/iY/xcHlVp7UhfOqx1K0OetPn/x+entBR5\nH1uBXU1Yx7tSZ/RN192Af6czMw+THXBh0LgzzJgBIIKdjyy5acLBfh7bnV6PV6G+\nnWWyr4WVrrH4wH3pKisCnIoPpsjEXPSJRnu4PTVELM71l8hZlES9dazRPiMOaxOj\nTfaz1vGa1mDPMbobiN5NH0ueX4LAUDMkpWFuAP+AJ9UqAax+Cq0KX+dUMXqyWY82\nV7jPmgHqYTNRw/zvfdOP1qeqhkIeTp8vPbp3lw==\n-----END CERTIFICATE-----\n\"\n},\n\"database\": \"foursquare-clouderamanager-datasource\"}"
I think maybe I have problem in this string "tlsCACert": "{{ cert['content'] | b64decode | string }}" but i don`t have any idea how to solve this problem
The problem is that you are using string templating to compose a structured document (in this case JSON); jinja2 does not know it is JSON, only that it is text. You would receive a similar error if you were to try and template {"hello": "{{ world | string }}" using a variable of world="abc\ndef" because the \n in the string is literally inserted in the mustaches, but JSON does not allow newlines in string literals.
You have two paths forward: either ensure the rendering is JSON safe with | to_json instead of | string, or compose the body as an actual dict so that uri: will serialize it correctly
I suspected that is what was happening, but I confirmed it the same way you can: echo that {"body": "{\n\"name\": \"Cloudera Mana... string through jq -r .body (or python -c "import sys, json;print(json.load(sys.stdin)['body'])" if you don't have jq handy) and you will see that tlsCACert has newlines in it

How to retrieve a value from stdout of ansible registered variable?

One of my ansible play is using a shell module to create a vault token.The command returns some value that I want to use in next play.
I registered the command output in vault_output parameter.Here I am getting stdout from that variable.
"vault_output.stdout": {
"auth": {
"accessor": "XXXXXXXXXXXXXXXXXXX",
"client_token": "abcdefghijkl",
"entity_id": "XXXXXXXXXXXXXXXXXXX",
"lease_duration": 600,
"metadata": {
"username": "vault"
},
"policies": [
"default",
],
"renewable": true,
"token_policies": [
"default",
]
},
"data": {},
"lease_duration": 0,
"lease_id": "",
"renewable": false,
"request_id": "3470a160-3ed5-ceaa-f57b-4f3d74f6a269",
"warnings": null,
"wrap_info": null
}
}
I am looking to get value of client_token which should be abcdefghijkl. Can anyone help me out to get that value which can be used in next play.
I have tried using vault_output.stdout[num], vault_output.stdout_lines, vault_output.stdout.auth , vault_output.stdout.['auth'] but no luck.
Expecting Result:
"client_token": "abcdefghijkl"
Finally found an answer to this.
- set_fact:
result: "{{ (vault_output.stdout | from_json).auth.client_token }}"
- debug:
var: result
result: 9fa7fdd6-c8da-ac8c-b5d8-df18b17eb3f0
The output from debug: var=vault_output.stdout is actually a bit misleading here. The variable does not contain a dict object Ansible can index. You will need to first parse it with the from_json filter:
- set_fact:
result: "{{ vault_output.stdout | from_json }}"
- debug:
var: result.auth.client_token

How can loop items as input parameters to a ansible role

I am trying to convert an existing ansible playbook (for extracting the webpage content of multiple webpage URL's in parallel fashion) to re-usable roles. I need the role to accept variables in a loop and produce the output for all the items in a single task which my current playbook is able to do. But the current role is only able to produce the output of the last item in the loop
I have tried registering the webpage content inside and outside the roles but of no use. And also looping the response results with_items same as of the role is producing results for non-200 values
FYI I got the expected output by including the loop inside the role but it's defeating the purpose of maintaining a role for GET call because I will not need a loop every time for the GET call. So I am expecting to loop the role in the testplaybook.yml.
Test-Role: main.yml
uri:
url: "{{ URL_Variable }}"
method: GET
status_code: 200
return_content: yes
register: response
ignore_errors: true
testplaybook.yml:
- hosts: localhost
gather_facts: true
tasks:
- name: Include roles
include_role:
name: Test-Role
vars:
URL_Variable: "http://{{ item }}:{{ hostvars[groups['group1'][0]]['port'] }}/{{ hostvars[groups['group1'][0]]['app'] }}/"
with_items: "{{ groups['group1'] }}"
- name: "Display content"
debug:
var: response.results
Expected Output:
response.results:
ok: [127.0.0.1] => (item=[0, 'item1']) => {
"ansible_loop_var": "item",
"item": [
0,
"item1"
],
"response": {
"accept_ranges": "bytes",
"changed": false,
"connection": "close",
"content": "content1",
"content_length": "719",
"content_type": "text/html",
"cookies": {},
"failed": false,
"msg": "OK (719 bytes)",
"redirected": false,
"server": "42",
"status": 200,
"url": "http://item1:port/app/"
}
}
ok: [127.0.0.1] => (item=[1, 'item2']) => {
"ansible_loop_var": "item",
"item": [
1,
"item2"
],
"response": {
"accept_ranges": "bytes",
"changed": false,
"connection": "close",
"content": "content2",
"content_length": "719",
"content_type": "text/html",
"cookies": {},
"failed": false,
"msg": "OK (719 bytes)",
"redirected": false,
"server": "42",
"status": 200,
"url": "http://item2:port/app/"
}
}
try this Test-Role: main.yml file:
- uri:
url: "{{ URL_Variable }}"
method: GET
status_code: 200
return_content: yes
register: response
ignore_errors: true
- name: Add response to responses array
set_fact:
responses_results: "{{ responses_results | default([]) + [{'URL': URL_Variable, 'response': response.content}] }}"
this works with include_tasks, i assume it would work with include_role as well, the variable responses_results should persist across roles assuming its in the same play. if not works, try to switch your code to a single role instead, with an include_tasks.
hope it helps

Resources