How to verify GET request values in ansible - ansible

I'm new to ansible and I'm trying to figure out how I can verify values in a GET request.
Here is my GET request:
#
# GET Results
#
- name:Results
uri:
url: "https://getresults.com"
method: GET
user: "{{ user }}"
password: "{{ pass }}"
status_code:
- 200
- 202
validate_certs: no
return_content: yes
headers:
Content-Type: "application/json"
ignore_errors: true
register: new_task_results
Here is the values returned from my GET request:
"content_length": "296",
"content_type": "application/json",
"cookies": {},
"cookies_string": "",
"date": "Fri, 02 Jun 2021 14:24:21 GMT",
"elapsed": 0,
"failed": false,
"json": {
"dataProducts": [],
"id": "xyzg777-2479-4f23-b835-5675e58eef22",
"name": "UPDATE",
"priority": 1,
"processor": null,
"qualityOfService": {
"frequency": 1,
"intervalSeconds": 800
},
How do I verify that "priority" is 1 and the "id" is correct?

- debug:
msg: "priority is 1 and id is correct"
when: _p == 1 and _i == 'xyzg777-2479-4f23-b835-5675e58eef22'
vars:
_p: "{{ new_task_results.json.priority | int }}"
_i: "{{ new_task_results.json.id }}"

Related

Schedule deletion of unused template

In Ansible Tower, is there a possibility to create a scheduled task that checks if a template has not been executed for one year and if so, deletes it?
The short answers is: yes, of course. The long answer is: someone has to create such task. To do so, one may getting familiar with the Ansible Tower REST API, in detail Job Templates - List Jobs for a Job Template.
In example, a call for Jobs of a Job Template which was never executed
curl --silent --user ${ACCOUNT}:${PASSWORD} https://${TOWER_URL}/api/v2/job_templates/${ID}/jobs/ --write-out "\n%{http_code}\n"| jq .
would result into an output of
{
"count": 0,
"next": null,
"previous": null,
"results": []
}
200
A call for Jobs of a Job Template which is executed daily would result into an output of
{
"count": 70,
"next": "/api/v2/job_templates/<id>/jobs/?page=2",
"previous": null,
"results": [
{
"id": <id>,
<snip>
"created": "2022-06-10T05:57:18.976798Z",
"modified": "2022-06-10T05:57:19.666354Z",
"name": "<name>",
"description": "<description>",
"unified_job_template": <id>,
"launch_type": "manual",
"status": "successful",
"failed": false,
"started": "2022-06-10T05:57:19.870208Z",
"finished": "2022-06-10T05:57:33.752072Z",
"canceled_on": null,
"elapsed": 13.882,
"job_explanation": "",
"execution_node": "<executionNode>",
"controller_node": "",
"job_type": "run",
"inventory": <id>,
"project": <id>,
"playbook": "<path>",
"scm_branch": "",
"forks": 0,
"limit": "<hostgroup>",
"verbosity": 0,
"extra_vars": "{\"if_there_any\": \"false\"}",
"job_tags": "check",
"force_handlers": false,
"skip_tags": "",
"start_at_task": "",
"timeout": 0,
"use_fact_cache": false,
"organization": <id>,
"job_template": <id>,
"passwords_needed_to_start": [
"ssh_password"
],
"allow_simultaneous": false,
"artifacts": {},
"scm_revision": "<rev>",
"instance_group": 1,
"diff_mode": false,
"job_slice_number": 0,
"job_slice_count": 1,
"webhook_service": "",
"webhook_credential": null,
"webhook_guid": ""
}
]
}
200
Since the goal is to execute it via Ansible Engine, as well schedule via Ansible Tower, a sample rest.yml playbook
---
- hosts: localhost
become: false
gather_facts: false
vars:
TOWER_API_URL: "<tower_url>/api/v2"
FILTER: ".version"
ID: "<id>"
tasks:
- name: Example REST API call
shell:
cmd: curl --silent -u '{{ ansible_user }}:{{ ansible_password }}' --location {{ TOWER_API_URL }}/ping | jq {{ FILTER }}
warn: false
register: result
failed_when: result.rc != 0
changed_when: false
check_mode: false
- name: Show result
debug:
msg: "{{ result.stdout }}"
- name: List Jobs for a Job Template
uri:
url: "https://{{ TOWER_API_URL }}/job_templates/{{ ID }}/jobs/"
user: "{{ ansible_user }}"
password: "{{ ansible_password }}"
force_basic_auth: true
method: GET
validate_certs: yes
return_content: yes
status_code: 200
body_format: json
check_mode: false
register: result
- name: Show result
debug:
msg: "{{ result.json.results }}" # list of jobs
which can be called from CLI via
sshpass -p ${PASSWORD} ansible-playbook --user ${ACCOUNT} --ask-pass rest.yml
Please take note that the "count": 70 is greater than the result set result.json.results | length of 25 and there is a next page mentioned "next": "...?page=2". The result.json.results | last therefore does not contain the most recent execution. This is because of Pagination.
Depending on the setup and actual configuration of Ansible Tower one may need to adjust the page_size. In example to get the most recent result
...
url: "https://{{ TOWER_API_URL }}/job_templates/{{ ID }}/jobs/?page_size=100"
...
msg: "{{ result.json.results | last }}"

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

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

Searching a value in a list of dict in 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)

Resources