Ansible shell module does not recognize "failed" attribute on a failed task - ansible

Following code results 'dict object' has no attribute 'failed' error:
shell module:
- hosts: localhost
tasks:
- shell: "not_available_command"
register: module_result
until: module_result.failed == false
retries: 2
delay: 1
Result:
fatal: [localhost]: FAILED! => {
"failed": true,
"msg": "The conditional check 'module_result.failed == false' failed. The error was: error while evaluating conditional (module_result.failed == false): 'dict object' has no attribute 'failed'"
}
But when I changed the syntax of until as:
until: module_result.stderr == ""
It successfully retries. I executed it with -vvv option for debugging; after 2 retries it failed as expected:
fatal: [localhost]: FAILED! => {
"attempts": 2,
"changed": true,
"cmd": "not_available_command",
"delta": "0:00:00.010290",
"end": "2017-09-25 17:28:14.078318",
"failed": true,
"invocation": {
"module_args": {
"_raw_params": "not_available_command",
"_uses_shell": true,
"chdir": null,
"creates": null,
"executable": null,
"removes": null,
"warn": true
}
},
"rc": 127,
"start": "2017-09-25 17:28:14.068028",
"stderr": "/bin/sh: 1: not_available_command: not found",
"stderr_lines": [
"/bin/sh: 1: not_available_command: not found"
],
"stdout": "",
"stdout_lines": []
}
As seen both failed or stderr attributes are existed however failed is not recognized when tried to define until syntax.
Let's try with a different module:
get_url module:
- hosts: localhost
tasks:
- get_url:
url: "http://unavailable_file_on_the_web.txt"
dest: "{{ playbook_dir }}"
register: module_result
until: module_result.failed == false
retries: 2
delay: 1
This time until: module_result.failed == false syntax works; 'failed' attribute is recognized.
So how to identify this issue on modules? Does it seem to be a bug?

Yes, it seems like a bug or not expected behaviour: failed field is not populated during intermediate attempts. You can inspect it with ANSIBLE_DEBUG=1:
{
"changed": true,
"end": "2017-09-25 13:01:17.269225",
"stdout": "",
"cmd": "not_available_command",
"rc": 127,
"start": "2017-09-25 13:01:17.257604",
"stderr": "/bin/sh: not_available_command: command not found",
"delta": "0:00:00.011621",
"invocation": {
"module_args": {
"warn": true,
"executable": null,
"_uses_shell": true,
"_raw_params": "not_available_command",
"removes": null,
"creates": null,
"chdir": null
}
},
"warnings": []
}
In Ansible 2.4 the failed field is present.
For your information there are task result tests like failed/succeeded.
You can use them in your when/until statements:
until: module_result | succeeded
This works well in 2.2.x and 2.3.x.

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

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

Ansible command inside a playbook with shell module

Can I use something as below in ansible:
---
- hosts: webserver
gather_facts: False
tasks:
- name: Check ping
shell: ansible -i localhost.yml -m shell -a 'ping'
That localhost contains all hosts whereas playbook will run on webserver.
Actual requirement is to run on webserver whereas in one task I need to run a command on all hosts specified in the host file.
Thanks in advance!
Just to add error is :
fatal: [webservice]: FAILED! => {
"changed": true,
"cmd": "ansible -i localhost.yml -m shell -a 'ping'",
"delta": "0:00:00.009121",
"end": "2020-02-12 04:47:06.174390",
"invocation": {
"module_args": {
"_raw_params": "ansible -i localhost.yml -m shell -a 'ping'",
"_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": 127,
"start": "2020-02-12 04:47:06.165269",
"stderr": "ansible: not found",
"stderr_lines": [
"ansible: not found"
],
"stdout": "",
"stdout_lines": [] }
You want to run an ansible playbook or a shell command inside a server ?
If you want to run a shell command then don't mention playbook name. If you want to run a playbook then don't mention -m shell -a shell parameter.

Ansible parse debug output

I have this ansible output got from 3 different hosts, using ansible debug module:
TASK [debug] ***************************************************************************************************************************************************************************************
ok: [10.240.22.44] => {
"msg": {
"changed": true,
"msg": "All items completed",
"results": [
{
"_ansible_ignore_errors": true,
"_ansible_item_result": true,
"_ansible_no_log": false,
"_ansible_parsed": true,
"changed": true,
"cmd": "/opt/confluent/bin/nodefirmware smm1",
"delta": "0:00:00.128325",
"end": "2020-02-05 11:22:19.435049",
"failed": false,
"invocation": {
"module_args": {
"_raw_params": "/opt/confluent/bin/nodefirmware smm1",
"_uses_shell": true,
"chdir": null,
"creates": null,
"executable": null,
"removes": null,
"stdin": null,
"warn": true
}
},
"item": "10.240.18.20",
"rc": 0,
"start": "2020-02-05 11:22:19.306724",
"stderr": "",
"stderr_lines": [],
"stdout": "smm1: SMM: 1.10 (TESM14F)\nsmm1: PSOC: 0.7",
"stdout_lines": [
"smm1: SMM: 1.10 (TESM14F)",
"smm1: PSOC: 0.7"
]
},
{
"_ansible_ignore_errors": true,
"_ansible_item_result": true,
"_ansible_no_log": false,
"_ansible_parsed": true,
"changed": true,
"cmd": "/opt/confluent/bin/nodefirmware smm1",
"delta": "0:00:00.096292",
"end": "2020-02-05 11:22:22.847949",
"failed": false,
"invocation": {
"module_args": {
"_raw_params": "/opt/confluent/bin/nodefirmware smm1",
"_uses_shell": true,
"chdir": null,
"creates": null,
"executable": null,
"removes": null,
"stdin": null,
"warn": true
}
},
"item": "10.240.19.21",
"rc": 0,
"start": "2020-02-05 11:22:22.751657",
"stderr": "",
"stderr_lines": [],
"stdout": "smm1: SMM: 1.10 (TESM14F)\nsmm1: PSOC: 0.7",
"stdout_lines": [
"smm1: SMM: 1.10 (TESM14F)",
"smm1: PSOC: 0.7"
]
}
]
}
}
I'm trying to parse this output and display in the end, for each hosts, strictly the:
"stdout_lines": [
"smm1: SMM: 1.10 (TESM14F)",
"smm1: PSOC: 0.7"
The playbook that shows the above output is this:
- debug:
msg: "{{ smm_output }}"
when: "('primary' in default_hostname or 'Primary' in default_hostname)"
tags: ['ic', 'smm']
I tried with "{{ smm_output.stdout_lines }}" but says there's not such dict object
Any clues?
You are registering the output of a looping task. Quoting the documentation:
When you register a variable in a task with a loop, the registered variable contains a value for each item in the loop. The data structure placed in the variable during the loop will contain a results attribute, that is a list of all responses from the module. For a more in-depth example of how this works, see the Loops section on using register with a loop.
To debug each stdout_lines of your respective results in smm_output you can use the following task:
- name: debug result
debug:
var: item.stdout_lines
loop: "{{ smm_output.results }}"
Ref: https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#registering-variables

How to Store and display the output of shell command run in loop using with_lines

Below is the playbook i have created. I am not getting the way to store and display the output od the shell command and pass the same output to other play having different hosts.
---
- hosts: localhost
tasks:
- name: "check the connectivity with username for all the LLC servers from hosts.new file"
shell: ssh dp794d#{{ item }} "date"
register: result
with_lines: cat "/home/capio/ansible/pmossWipm/day2/logs/ipAddress.txt"
- debug: var=result
Now how can i display the result of register variable "result". I tried using the debug, but it didn't worked.
Below is the output of var=result
TASK [debug] *******************************************************************
ok: [localhost] => {
"result": {
"changed": true,
"msg": "All items completed",
"results": [
{
"_ansible_item_result": true,
"_ansible_no_log": false,
"_ansible_parsed": true,
"changed": true,
"cmd": "ssh dp794d#130.6.50.131 \"date\"",
"delta": "0:00:00.237866",
"end": "2017-05-09 08:59:13.918581",
"invocation": {
"module_args": {
"_raw_params": "ssh dp794d#130.6.50.131 \"date\"",
"_uses_shell": true,
"chdir": null,
"creates": null,
"executable": null,
"removes": null,
"warn": true
},
"module_name": "command"
},
"item": "130.6.50.131",
"rc": 0,
"start": "2017-05-09 08:59:13.680715",
"stderr": " _________________________________________________________________\n\n This system is restricted to ABC authorized users for business\n purposes. Unauthorized access is a violation of the law. This\n service may be monitored for administrative and security reasons.\n By proceeding, you consent to this monitoring.\n _________________________________________________________________\n\n ,
"stdout": "Tue May 9 08:59:13 EDT 2017",
"stdout_lines": [
"Tue May 9 08:59:13 EDT 2017"
],
"warnings": []
},
{
"_ansible_item_result": true,
"_ansible_no_log": false,
"_ansible_parsed": true,
"changed": true,
"cmd": "ssh dp794d#130.6.50.132 \"date\"",
"delta": "0:00:00.245660",
"end": "2017-05-09 08:59:14.430728",
"invocation": {
"module_args": {
"_raw_params": "ssh dp794d#130.6.50.132 \"date\"",
"_uses_shell": true,
"chdir": null,
"creates": null,
"executable": null,
"removes": null,
"warn": true
},
"module_name": "command"
},
"item": "130.6.50.132",
"rc": 0,
"start": "2017-05-09 08:59:14.185068",
"stderr": " _________________________________________________________________\n\n This system is restricted to ABC authorized users for business\n purposes. Unauthorized access is a violation of the law. This\n service may be monitored for administrative and security reasons.\n By proceeding, you consent to this monitoring.\n _________________________________________________________________\n\n [,
"stdout": "Tue May 9 08:59:14 EDT 2017",
"stdout_lines": [
"Tue May 9 08:59:14 EDT 2017"
],
"warnings": []
}
]
}
}
You can store result to file as follows:
- copy:
content: '{{ result.results | map(attribute="stdout") | list | join("\n") }}'
dest: /tmp/out.txt

Resources