Fetch the values of the variables in ansible - ansible

I am trying to list the names whose matches have been found.
- name: search for files containing string
find:
paths: /root/ansible-dir
patterns: "file3.yml"
contains: "{{ item }}"
with_items: "{{ names_list }}"
register: file_match
- name: print file
debug:
msg: "{{ file_match }}"
After the above code is run, the below code gets generated :
"msg": {
"changed": false,
"msg": "All items completed",
"results": [
{
"ansible_loop_var": "item",
"changed": false,
"examined": 14,
"failed": false,
"files": [],
"invocation": {
"module_args": {
"age": null,
"age_stamp": "mtime",
"contains": "node_mem",
"depth": null,
"excludes": null,
"file_type": "file",
"follow": false,
"get_checksum": false,
"hidden": false,
"paths": [
"/root/ansible-dir"
],
"patterns": [
"file3.yml"
],
"recurse": false,
"size": null,
"use_regex": false
}
},
"item": "node_mem",
"matched": 0,
"msg": ""
},
How to fetch the name of the item where the matched attribute is >=1?

Use subelements. The debug below gives you a hint how to iterate the results and fetch files that contain the items
- debug:
msg: "Fetch {{ item.1 }}"
with_subelements:
- "{{ file_match.results }}"
- files
It is not necessary to test the number of files is >=1. If the list of files is empty the iteration will be skipped anyway.

Related

How do I get Ansible's json_query to return a value from this JSON document

After several hours of beating my head against this (not to mention leaving it for a day) I'm pretty much stumped on trying to figure out why I can't JMESPath to return a value in Ansible.
I have a task which runs a shell command and returns the following output:
[
{
"ansible_loop_var": "item",
"changed": false,
"cmd": [
"pvesh",
"create",
"/access/users/user#pve/token/pve-apikey",
"-privsep=0",
"--output=json"
],
"delta": "0:00:00.707130",
"end": "2022-09-22 12:28:43.746253",
"failed": false,
"invocation": {
"module_args": {
"_raw_params": "pvesh create /access/users/\"user#pve\"/token/\"pve-apikey\" -privsep=0 --output=json",
"_uses_shell": false,
"argv": null,
"chdir": null,
"creates": null,
"executable": null,
"removes": null,
"stdin": null,
"stdin_add_newline": true,
"strip_empty_ends": true,
"warn": false
}
},
"item": {
"token": "pve-apikey",
"user": "user#pve"
},
"msg": "",
"rc": 0,
"start": "2022-09-22 12:28:43.039123",
"stderr": "",
"stderr_lines": [],
"stdout": "{\"full-tokenid\":\"user#pve!pve-apikey\",\"info\":{\"privsep\":\"0\"},\"value\":\"dc2aa48f-daf6-4efe-b95e-83774a588988\"}",
"stdout_lines": [
"{\"full-tokenid\":\"user#pve!pve-apikey\",\"info\":{\"privsep\":\"0\"},\"value\":\"dc2aa48f-daf6-4efe-b95e-83774a588988\"}"
]
}
]
I'm now trying to obtain the UUID returned as value in the stdout_line using json_query and this is far as I can get:
- debug:
msg: "{{ token | community.general.json_query(query) }}"
vars:
query: '[].stdout'
This json_query returns the following output:
"msg": [
"{\"full-tokenid\":\"tfuser#pve!tfe-pve-apikey\",\"info\":{\"privsep\":\"0\"},\"value\":\"e47e82d4-6798-47ea-9592-c7cf55cc8b61\"}"
]
I believe that this is a list, so I've tried extending the json_query as [].stdout[].value but that returns null. I've tried various permutations but so far nothing seems to work.
Any advice on how to proceed would be very welcome!
The items of the list stdout_lines are strings. You can test it. For example,
- debug:
var: output.0.stdout_lines.0|type_debug
gives
output.0.stdout_lines.0|type_debug: AnsibleUnsafeText
Convert the items to dictionaries. For example
- debug:
var: output.0.stdout_lines.0|from_yaml
gives
output.0.stdout_lines.0|from_yaml:
full-tokenid: user#pve!pve-apikey
info:
privsep: '0'
value: dc2aa48f-daf6-4efe-b95e-83774a588988
To get the UUID, declare the variable
UUID: "{{ output|map(attribute='stdout_lines')|
map('map', 'from_yaml')|list|
json_query('[].value') }}"
This gives the list of the values
UUID:
- dc2aa48f-daf6-4efe-b95e-83774a588988
Example of a complete playbook for testing
- hosts: localhost
vars:
output: "{{ lookup('file', 'output.json') }}"
UUID: "{{ output|map(attribute='stdout_lines')|
map('map', 'from_yaml')|list|
json_query('[].value') }}"
tasks:
- debug:
var: output.0.stdout_lines.0|type_debug
- debug:
var: output.0.stdout_lines.0|from_yaml
- debug:
var: UUID

Output of Ansibble task

I am using command hcloud to create cloud server in Hetzner. I get an output like this:
changed: [localhost] => (item={'name': 'TEST-VARIABLES', 'server_type': 'cx11', 'os_image': 'ubuntu-20.04', 'server_labels': 'Name=test-server', 'server_location': 'hel1'}) => {
"ansible_loop_var": "item",
"changed": true,
"hcloud_server": {
"backup_window": "None",
"datacenter": "hel1-dc2",
"delete_protection": false,
"id": "19461514",
"image": "ubuntu-20.04",
"ipv4_address": "11.111.111.111",
"ipv6": "1a71:7f9:c011:0b09::/64",
"labels": {
"Name": "test-server"
},
"location": "hel1",
"name": "TEST-VARIABLES",
"placement_group": null,
"rebuild_protection": false,
"rescue_enabled": false,
"server_type": "cx11",
"status": "running"
},
"invocation": {
"module_args": {
"allow_deprecated_image": false,
"api_token": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
"backups": null,
"datacenter": null,
"delete_protection": null,
"endpoint": "https://api.SERVER.cloud/v1",
"firewalls": null,
"force": false,
"force_upgrade": false,
"id": null,
"image": "ubuntu-20.04",
"labels": {
"Name": "test-server"
},
"location": "hel1",
"name": "TEST-VARIABLES",
"placement_group": null,
"rebuild_protection": null,
"rescue_mode": null,
"server_type": "cx11",
"ssh_keys": null,
"state": "present",
"upgrade_disk": false,
"user_data": null,
"volumes": null
}
},
"item": {
"name": "TEST-VARIABLES",
"os_image": "ubuntu-20.04",
"server_labels": "Name=test-server",
"server_location": "hel1",
"server_type": "cx11"
},
"root_password": "DFLDJFLDFDLFKJDLFKJ"
}
I try to get line with "ipv4_address": "11.111.111.111", and "root_password": "DFLDJFLDFDLFKJDLFKJ", but when I use task:
---
- name: Create a basic server
hcloud_server:
api_token: "{{ token }}"
name: "{{ item.name }}"
server_type: "{{ item.server_type }}"
image: "{{ item.os_image }}"
labels: "{{ item.server_labels }}"
location: "{{ item.server_location }}"
state: present
register: server_info
with_items: "{{ server }}"
- name: Here IP
debug:
var: server_info.root_password
I got error:
TASK [/etc/ansible/roles/CREATE-server : Here IP.] *********************************************************************************************************
ok: [localhost] => {
"server_info.root_password": "VARIABLE IS NOT DEFINED!"
}
Could you please help, how I can get IP line and password line, to use them in the next task (for example to send via email). Thank you!
you register the content of loop, so your result is a list (results):
- name: display
debug:
msg: "ip: {{ item.hcloud_server.ipv4_address }} has password: {{ item.root_password }}"
loop: "{{ server_info.results }}"
result: here you have just one server declared, so just one item in the list results
"msg": "ip: 11.111.111.111 has password: DFDFDFDFDFDFDFDF"
if you want to limit the output of record, you could add loop_control parameter to loop with argument label:
loop: "{{ server_info.results }}"
loop_control:
label: "{{ item.hcloud_server.ipv4_address }}"
you could put another comment if you want with label or even empty string:
loop: "{{ server_info.results }}"
loop_control:
label: "result"

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

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)

json_query for a value of json output in Ansible

The following outputs to the shell when I run my Ansible play:
TASK [java : debug] ************************************************************************************************************************************************************
ok: [10.3.16.114] => {
"msg": {
"changed": false,
"examined": 1,
"failed": false,
"files": [
{
"attributes": "Directory, NotContentIndexed",
"creationtime": 1551375173.18858,
"filename": "jre1.8.0_201",
"isarchive": false,
"isdir": true,
"ishidden": false,
"islnk": false,
"isreadonly": false,
"isshared": false,
"lastaccesstime": 1551375199.2058175,
"lastwritetime": 1551375199.2058175,
"owner": "NT AUTHORITY\\SYSTEM",
"path": "C:\\Program Files\\Java\\jre1.8.0_201",
"size": 205713652
}
],
"matched": 1
}
}
I need just the value of path so that I can use it as a varuable to set a dynamic java_home inside of windows.
I have been trying to use json_query inside of my yaml but I'm having knowledge limitations here.
- name: Obtain information about a folder
win_find:
paths: C:\Program Files\Java
recurse: no
file_type: directory
register: java_folder
- set_fact:
java_home_dir: "{{java_folder.file | json_query()}}"
It's a simple path. Addressing of the first element is needed, because "files" is a list.
- set_fact:
java_home_dir: "{{ java_folder.files[0].path }}"
If there is more files in the list json_query will be needed.

Resources