json_query for a value of json output in Ansible - 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.

Related

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

Fetch the values of the variables in 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.

How to filter Ansible 'find' output

I would like to view the list of symbolic links from some remote servers in the terminal, but a lot of information is being printed when I run the playbook.
This is ansible 2.7.12 running on an Ubuntu server. I am using 'find' module and file_type: link to get the softlink details.
Find is returning a lot of details with the return value key "files" but I just need the soft links and corresponding server name in the terminal.
---
# tasks file for application
- name: Get the current applications running
find:
paths: /path/to/app
file_type: link
register: find_result
- name: Print find output
debug:
var: find_result.results
Actual Result:
ok: [client3.example.com] => {
"find_result.files": [
{
"atime": 1559027986.555,
"ctime": 1559027984.828,
"dev": 64768,
"gid": 0,
"gr_name": "root",
"inode": 4284972,
"isblk": false,
"ischr": false,
"isdir": false,
"isfifo": false,
"isgid": false,
"islnk": true,
"isreg": false,
"issock": false,
"isuid": false,
"mode": "0777",
"mtime": 1559027984.828,
"nlink": 1,
"path": "/path/to/app/softlink.1",
"pw_name": "root",
"rgrp": true,
...
...
Would like to get some filtered output in the terminal like:
ok: [client3.example.com] => {
"find_result.files": [
{
"path": "/path/to/app/softlink.1",
},
There are a couple of ways of addressing this question. You could use the map filter to extract just the path attribute from your results:
- name: Print find output
debug:
var: results.files|map(attribute='path')|list
Given the sample data in your question, this would result in:
TASK [Print find output] *****************************************************************************************************************************************************
ok: [localhost] => {
"results.files|map(attribute='path')|list": [
"/path/to/app/softlink.1"
]
}
You can also accomplish something similar using the json_query filter, which applies JMESPath queries to your data:
- name: Print find output
debug:
var: results.files|json_query('[*].path')

How to get a substring of a path name with Ansible?

I want to install tomcat via ansible on a windows server, I check if there is alreay a java installation and get the path to java.exe. Which is:
"path": "D:\\Products\\abcd\\java\\jdk1.8.0_51\\bin\\java.exe"
I need to set JAVA_HOME in a config var for tomcat, how can I get the needed part -> D:\\Products\\abcd\\java\\jdk1.8.0_51 from the path? I can not get JAVA_HOME from the remote server since there are various installations.
TASK [tomcat : debug]
ok: [v-sax-769-e-a.develop.ebiz.grp] => {
"file_info_java.files[0]": {
"attributes": "Archive",
"checksum": "8c2c2f3d687fe99d9a724514f09f53bcb989a1e0",
"creationtime": 1511365795.4331064,
"extension": ".exe",
"filename": "java.exe",
"isarchive": true,
"isdir": false,
"ishidden": false,
"islnk": false,
"isreadonly": false,
"isshared": false,
"lastaccesstime": 1511365795.4331064,
"lastwritetime": 1438168336,
"owner": "BUILTIN\\Administrators",
"path": "D:\\Products\\CPeRef\\java\\jdk1.8.0_51\\bin\\java.exe",
"size": 206400
}
}
To extract a path given in Windows format, use win_dirname filter:
vars:
path: "D:\\Products\\abcd\\java\\jdk1.8.0_51\\bin\\java.exe"
tasks:
- debug:
msg: "{{ path | win_dirname }}"
Result:
ok: [localhost] => {
"msg": "D:\\Products\\abcd\\java\\jdk1.8.0_51\\bin"
}
But, as you seemingly want to get rid of bin-part, you need to decide on a method. Either way, you can do it with a regex filter:
remove the last element from the path:
{{ path | win_dirname | regex_replace('\\\\(?:(?!\\\\).)*$', '') }}
remove the last \\bin from the path:
{{ path | win_dirname | regex_replace('\\\\bin$', '') }}
remove the fixed part without using win_dirname at all:
{{ path | regex_replace('\\\\bin\\\\java.exe$', '') }}

Fetch doesn't transfer when i use variable

fetch module does not transfer file when i use variable and getting message as "msg": "the remote file does not exist, not transferring, ignored". But file exits in the source directory. Please suggest if anything wrong in this.
ansible 2.1.0.0
---
- hosts: host_A
become_user: yes
gather_facts: no
tasks:
- name: list files
shell: ls -1 /root/stuff/install.1_comiskey-v01
register: dumpfiles
-debug: var=dumpfiles
- name: fetch files
fetch: src={{item}} dest=/tmp/fetched/ flat=yes
with_items: ('{{dumpfiles.stdout_lines}}')
register: test
- debug: var=test
Output:
TASK [fetch files]
*************************************************************
ok: [10.1.31.82] => (item=('[u'/root/stuff/install.1_comiskey-v01',u'/root/stuff/install.1_comiskey-v02']'))
TASK [debug] *******************************************************************
ok: [10.1.31.82] => {
"test": {
"changed": false,
"msg": "All items completed",
"results": [
{
"_ansible_item_result": true,
"_ansible_no_log": false,
"changed": false,
"file": "('[u'/root/stuff/install.1_comiskey-v01', u'/root/stuff/install.1_comiskey-v02']')",
"invocation": {
"module_args": {
"dest": "/tmp/fetched/",
"flat": "yes",
"src": "('[u'/root/stuff/install.1_comiskey-v01', u'/root/stuff/install.1_comiskey-v02']')"
},
"module_name": "fetch"
},
"item": "('[u'/root/stuff/install.1_comiskey-v01', u'/root/stuff/install.1_comiskey-v02']')",
"msg": "the remote file does not exist, not transferring, ignored"
}
]
}
}
Remove parentheses from with_items. You can note that item variable is not correct on your debug output.

Resources