Browsing JSON variable in Ansible - ansible

For some reasons, I'm not allowed to use jsqon_query with Ansible, I'm trying to reach stdout element in a results list in a variable resulting from a shell call.
The JSON variable is saved this way :
"request": {
"changed": true,
"msg": "All items completed",
"results": [
{
"_ansible_ignore_errors": null,
"_ansible_item_result": true,
"_ansible_no_log": false,
"_ansible_parsed": true,
"changed": true,
"cmd": "echo \"****:********\" | grep -o -P '^*****:[^\\n]*$' | awk '{split($0,a,\":\"); print a[2]}'",
"delta": "0:00:00.003660",
"end": "2018-10-31 17:26:17.697864",
"failed": false,
"invocation": {
"module_args": {
"_raw_params": "echo \"**************\" | grep -o -P '^************:[^\\n]*$' | awk '{split($0,a,\":\"); print a[2]}'",
"_uses_shell": true,
"chdir": null,
"creates": null,
"executable": null,
"removes": null,
"stdin": null,
"warn": true
}
},
"item": "**********:************",
"rc": 0,
"start": "2018-10-31 17:26:17.694204",
"stderr": "",
"stderr_lines": [],
"stdout": "**********",
"stdout_lines": [
"*********"
]
}
]
}
}
I'm trying to browse my stdout element this way :
- name: Tarball copy
copy: src= "{{ '%s/%s' | format( TARBALL_DIR , request.results[0].stdout ) }}" dest= "/tmp/tarball/"
I tryied also :
- name: Tarball copy
copy: src= "{{ '%s/%s' | format( TARBALL_DIR , request.results[.stdout] ) }}" dest= "/tmp/tarball/"
- name: Tarball copy
copy: src= "{{ '%s/%s' | format( TARBALL_DIR , item.stdout ) }}" dest= "/tmp/tarball/"
with_items: "{{ request.results }}"
I've no idea why I'm always getting the same error :
- template error while templating string: unexpected '.'. String: {{ request.results[.stdout] }} (when trying with [.stdout)
- The task includes an option with an undefined variable (when putting [0] index)

I've finally solved my problem using :
- name: Tarball copy
copy:
src: "{{ '%s/%s' | format( TARBALL_DIR , request.results[0].stdout ) }}"
dest: "/tmp/tarball/"
It seems that src and dest couldn't accept space after the equal char.

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

Ansible unarchive module fails with Unexpected error when accessing exploded file: [Errno 2] No such file or directory:

My zip file contains a folder UAT-04022021_01 which has several files.
ls output on my local ansible server zip achieve file and its contents below:
-rwxrwxr-x 1 user1 user1 171910544 Feb 4 07:02 /web
/playbooks/automation/deployments/tmpfiles/04/UAT-04022021_01.zip
$ unzip -l "/web/playbooks/automation/deployments/tmpfiles/04/UAT-04022021_01.zip"
Archive: /web/playbooks/automation/deployments/tmpfiles/04/UAT-04022021_01.zip
Length Date Time Name
--------- ---------- ----- ----
0 02-04-2021 17:31 UAT-04022021_01/
144241065 02-04-2021 15:58 UAT-04022021_01/canv.ear
8342584 02-04-2021 16:00 UAT-04022021_01/canpizza.ear
10522141 02-04-2021 16:01 UAT-04022021_01/cantity.ear
8778258 02-04-2021 15:59 UAT-04022021_01/canipc.ear
--------- -------
171884048 5 files
[user1#linuxlocalhost deployments]$
Below is my code to extract the zip to all remote destination hosts
---
- name: "Play 1"
host: "{{ dest_host }}"
user: "{{ USER }}"
- name: Give better permissions to the zip file
tags: validate
file:
path: "{{ playbook_dir }}/tmpfiles/{{ Latest_Build_Number }}/{{ depfile | basename }}"
mode: 0775
delegate_to: localhost
run_once: true
- name: "Untar artifacts in CURRENT Folder"
tags: validate
unarchive:
src: "{{ playbook_dir }}/tmpfiles/{{ Latest_Build_Number }}/{{ depfile | basename }}"
dest: "/web/bea_apps/applications/{{ domain_home }}/{{ item }}/CURRENT/"
with_items: "{{ CLUSTER.split(',') }}"
Output:
#############################################\n\n')
The full traceback is:
File "/tmp/ansible_MCNgND/ansible_module_unarchive.py", line 873, in main
res_args['changed'] = module.set_fs_attributes_if_different(file_args, res_args['changed'], expand=False)
File "/tmp/ansible_MCNgND/ansible_modlib.zip/ansible/module_utils/basic.py", line 1473, in set_fs_attributes_if_different
file_args['path'], file_args['mode'], changed, diff, expand
File "/tmp/ansible_MCNgND/ansible_modlib.zip/ansible/module_utils/basic.py", line 1204, in set_mode_if_different
path_stat = os.lstat(b_path)
failed: [myserver2] (item=VL_BATCH) => {
"changed": false,
"dest": "/web/bea_apps/applications/mydom1/VL_BATCH/CURRENT/",
"gid": 64332,
"group": "wladmin",
"handler": "ZipArchive",
"invocation": {
"module_args": {
"attributes": null,
"backup": null,
"content": null,
"creates": null,
"delimiter": null,
"dest": "/web/bea_apps/applications/mydom1/VL_BATCH/CURRENT/",
"directory_mode": null,
"exclude": [],
"extra_opts": [],
"follow": false,
"force": null,
"group": null,
"keep_newer": false,
"list_files": false,
"mode": null,
"original_basename": "UAT-04022021_01.zip",
"owner": null,
"regexp": null,
"remote_src": false,
"selevel": null,
"serole": null,
"setype": null,
"seuser": null,
"src": "/home/wladmin/.ansible/tmp/ansible-tmp-1612477399.28-110140157282432/source",
"unsafe_writes": null,
"validate_certs": true
}
},
"item": "VL_BATCH",
"mode": "0755",
"msg": "Unexpected error when accessing exploded file: [Errno 2] No such file or directory: '/web/bea_apps/applications/mydom1/VL_BATCH/CURRENT/UAT-04022021_01/'",
"owner": "wladmin",
"size": 2,
"src": "/home/wladmin/.ansible/tmp/ansible-tmp-1612477399.28-110140157282432/source",
"state": "directory",
"uid": 600000008
}
/web/bea_apps/applications/mydom1/VL_BATCH/CURRENT/ is empty and has permission for the user to write to.
I checked on the destination and it does contain this folder /web/bea_apps/applications/mydom1/VL_BATCH/CURRENT/ but not /web/bea_apps/applications/mydom1/VL_BATCH/CURRENT/UAT-04022021_01/
It was supposed to create this folder UAT-04022021_01 if it unzips under the CURRENT folder.
After researching a bit more I tried this suggested fix of environment but it does not help either.
- name: "Untar artifacts in CURRENT Folder"
tags: validate
unarchive:
src: "{{ playbook_dir }}/tmpfiles/{{ Latest_Build_Number }}/{{ depfile | basename }}"
dest: "/web/bea_apps/applications/{{ domain_home }}/{{ item }}/CURRENT/"
with_items: "{{ CLUSTER.split(',') }}"
environment:
LANG: C
LC_ALL: C
LC_MESSAGES: C
My source is Linux while destination is Solaris.
Can you please suggest what could be wrong?

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.

Unable to get product version. How to set CLASSPATH using ansible

I can get the weblogic version by doing this on the command prompt in unix.
$ . /app/wlserv*/server/bin/setWLSEnv.sh
$ java weblogic.version
I wish to grab the weblogic version using ansible on remote hosts so I wrote this playbook:
---
- hosts: dest_nodes
tasks:
- name: Get weblogic version
shell: "/app/wlserv*/server/bin/setWLSEnv.sh;java weblogic.version"
register: wlsversion
- debug:
msg: "{{ wlsversion }}"
However, I get this error:
fatal: [10.0.0.91]: FAILED! => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"cmd": "/app/wlserv*/server/bin/setWLSEnv.sh;java weblogic.version",
"delta": "0:00:00.271434",
"end": "2020-05-15 16:31:44.209506",
"invocation": {
"module_args": {
"_raw_params": "/app/wlserv*/server/bin/setWLSEnv.sh;java weblogic.version",
"_uses_shell": true,
"argv": null,
"chdir": null,
"creates": null,
"executable": null,
"removes": null,
"stdin": null,
"stdin_add_newline": true,
"strip_empty_ends": true,
"warn": true
}
},
"msg": "non-zero return code",
"rc": 1,
"start": "2020-05-15 16:31:43.938072",
"stderr": "Error: Could not find or load main class weblogic.version",
"stderr_lines": [
"Error: Could not find or load main class weblogic.version"
],
"stdout": "CLASSPATH=/usr/java/jdk1.8.0_192-amd64/lib/tools.jar:/app/wlserver/modules/features/wlst.wls.classpath.jar:\n\nPATH=/app/wlserver/server/bin:/app/wlserver/../oracle_common/modules/thirdparty/org.apache.ant/1.9.8.0.0/apache-ant-1.9.8/bin:/usr/java/jdk1.8.0_192-amd64/jre/bin:/usr/java/jdk1.8.0_192-amd64/bin:/usr/lib64/qt-3.3/bin:/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/bin:/bin:/usr/bin:/app/wlserver/../oracle_common/modules/org.apache.maven_3.2.5/bin\n\nYour environment has been set.",
"stdout_lines": [
"CLASSPATH=/usr/java/jdk1.8.0_192-amd64/lib/tools.jar:/app/wlserver/modules/features/wlst.wls.classpath.jar:",
"",
"PATH=/app/wlserver/server/bin:/app/wlserver/../oracle_common/modules/thirdparty/org.apache.ant/1.9.8.0.0/apache-ant-1.9.8/bin:/usr/java/jdk1.8.0_192-amd64/jre/bin:/usr/java/jdk1.8.0_192-amd64/bin:/usr/lib64/qt-3.3/bin:/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/bin:/bin:/usr/bin:/app/wlserver/../oracle_common/modules/org.apache.maven_3.2.5/bin",
"",
"Your environment has been set."
]
}
From the output, I see that the classpath did get set but java weblogic.version command failed on the remote host.
Can you please suggest how can i get the Weblogic version registered to wlsversion variable ?
Wow, I found the solution after some efforts. Posting the solution here. I'm sure many face this issue.
---
- hosts: dest_nodes
tasks:
- name: Get weblogic CLASSPATH
shell: "/app/wlserv*/server/bin/setWLSEnv.sh"
register: wlsenv
- name: Get weblogic Version
shell: "java weblogic.version"
environment:
CLASSPATH: "{{ wlsenv.stdout }}"
register: wlsversion
- debug:
msg: "{{ wlsversion }}"

Access to stdout_lines when using Ansible

Given I have "registered" files in directory using shell task in a var sonarqube_plugins_installed, when I "debug" this using
- name: Debug
debug:
var: sonarqube_plugins_installed.results
I see for example
TASK [sonarqube : Debug] ************************************************************************
ok: [sonarqube] => {
"sonarqube_plugins_installed.results": [
{
"ansible_loop_var": "item",
"changed": true,
"cmd": "ls /opt/sonarqube/sonarqube-6.7/extensions/plugins/sonar-build-breaker-plugin-*.jar",
"delta": "0:00:00.003748",
"end": "2019-09-18 04:04:54.355667",
"failed": false,
"invocation": {
"module_args": {
"_raw_params": "ls /opt/sonarqube/sonarqube-6.7/extensions/plugins/sonar-build-breaker-plugin-*.jar",
"_uses_shell": true,
"argv": null,
"chdir": null,
"creates": null,
"executable": null,
"removes": null,
"stdin": null,
"stdin_add_newline": true,
"strip_empty_ends": true,
"warn": true
}
},
"item": "build_breaker",
"rc": 0,
"start": "2019-09-18 04:04:54.351919",
"stderr": "",
"stderr_lines": [],
"stdout": "/opt/sonarqube/sonarqube-6.7/extensions/plugins/sonar-build-breaker-plugin-2.2.jar",
"stdout_lines": [
"/opt/sonarqube/sonarqube-6.7/extensions/plugins/sonar-build-breaker-plugin-2.2.jar"
]
}
]
}
How can I access for example stdout in another task? In another task I want to process each item in results using with_items and output stdout.
How can this be done?
The following should be a good start:
- name: show stdout for each result
debug:
var: item.stdout
loop: "{{ sonarqube_plugins_installed.results }}"
As you guessed, this is going trough each elements in your results list.
An other approach if your want to print all lines at once would be to process the data structure through json_query with the relevant jmespath expression to only extract the needed information
- name: show sdtout list for all results
debug:
msg: "{{ sonarqube_plugins_installed | json_query('results[].stdout[]') }}"
You could also combine the two and loop over the simple list of stdouts only
- name: show stdout for each result
debug:
var: item
loop: "{{ sonarqube_plugins_installed | json_query('results[].stdout[]') }}"
You could also use the map filter to extract the desired attribute:
- name: show stdout list of all results
debug:
msg: "{{ sonarqube_plugins_installed.results | map(attribute='stdout') | list }}"
And there other solutions you can use that I'm sure you will find in the specific ansible filters and general jinja2 filters documentations

Resources