can someone explain why the following happens:
I am trying to re-use the same variable (output) in two different tasks, of which only one task will run depending on a conditional (bool). I don't understand why when the following playbook is run, the debug hi task results in an error.
The echo hello and debug hello run and work as expected and then the echo hi is skipped (which is also expected as bool == True) but I don't understand why the debug hi results in an error. The error I get is:
The conditional check output.stdout == hi failed. The error was: error while evaluating conditional: output 'dict object' has no attribute stdout
Why doesn't the the output variable persist through the debug hi task? It's almost as if it is losing its value when debug hi is skipped.
- hosts: localhost
vars:
bool: True
tasks:
- name: echo hello
shell: echo "hello"
register: output
when: bool == True
- name: debug hello
debug:
msg: "hello"
when: output.stdout == "hello"
- name: echo hi
shell: echo "hi"
register: output
when: bool != True
- name: debug hi
debug:
msg: "hi"
when: output.stdout == "hi"
You are still registering the task result to output, even though the task was skipped. Take these very simple tasks for example:
- command: echo Hello
register: result
when: false
- debug:
var: result
The variable result is still created, and has the following contents:
"result": {
"changed": false,
"skip_reason": "Conditional result was False",
"skipped": true
}
This is still very useful information (i.e. to know that a task was skipped). You will need to account for this logic in your plays.
This task:
- name: echo hi
shell: echo "hi"
register: output
when: bool != True
registers output whether bool is true or not.
See the ansible documentation.
If a task fails or is skipped, the variable still is registered with a failure or skipped status, the only way to avoid registering a variable is using tags.
You can replace your latest when: condition with:
when: output.stdout is defined and output.stdout == "hi"
Related
Consider this playbook:
---
- name: test
hosts: localhost
gather_facts: no
tasks:
- name: foo
shell: echo foo # skipped when running in check mode
register: result
- debug: msg="foo"
when: (result is defined)
and (result.stdout == 'foo')
I thought the is defined would result in short circuit evaluation as in other languages, but it doesn't.
If this is run in check mode, I get:
fatal: [localhost]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'dict object' has no attribute 'stdout'
I know I can ignore the error with ignore_errors: "{{ansible_check_mode}}", but I want to learn how to fix this problem.
How do I rewrite the when clause to prevent referencing undefined variables?
Actually, if you debug the var without a condition, you will see it is defined. It simply does not contain a stdout key since the task was skipped. The correct ways to work arround this (non exhaustive list):
- debug: msg="{{ result.stdout | default('no value') }}
when: result.stdout | default('') == 'foo'
- debug: msg="foo"
when:
- result is not skipped
- result.stdout == 'foo'
Note that since your above shell example is not changing anything on the remote target you can also decide to play it even when running in check mode:
- name: foo
shell: echo foo
check_mode: false
changed_when: false
register: result
- debug: msg="foo"
when: result.stdout == 'foo'
- name:
debug:
with_items: "{{ result.stdout }}"
TASK [pvc_precheck : check_rpm_versionlock warning message] ********************
skipping: [ip]
{
"msg": "Hello world!"
}
Somehow came across this test case. Here, when I run this code in Ansible got output but default message is also printing "Hello world!"
How can I omit this default message, I don't want any custom message as well, just executing it is enough.
Q: "Don't want any custom message as well. Just execution is enough."
A: If 'just execution is enough' use meta: noop e.g. the task below just silently does nothing
- meta: noop
Notes
1. Module debug doesn't require arguments
It's not possible to make debug display nothing. It wouldn't make sense. Why do you want to run debug when you don't want to see anything? No parameter is mandatory. msg defaults to "Hello world!" and var defaults to 0 e.g.
- debug:
gives
msg: Hello world!
2. Condition
Use a condition if you want to skip debug (eliminate message) e.g.
- debug:
msg: "{{ result.stdout }}"
when: debug_enable|default(false)|bool
3. Undefined variable
If the variable might be undefined it's possible to either skip the task e.g.
- debug:
msg: "{{ result.stdout }}"
when: result.stdout is defined
, or display a default value e.g.
- debug:
msg: "{{ result.stdout|default('NOT DEFINED') }}"
How do we check for a registered variable if only one of the two conditions turns out to be true having the same registered variable?
Below is my playbook that executes only one of the two shell modules.
- name: Check file
shell: cat /tmp/front.txt
register: myresult
when: Layer == 'front'
- name: Check file
shell: cat /tmp/back.txt
register: myresult
when: Layer == 'back'
- debug:
msg: data was read from back.txt and print whatever
when: Layer == 'back' and myresult.rc != 0
- debug:
msg: data was read from front.txt and print whatever
when: Layer == 'front' and myresult.rc != 0
Run the above playbook as
ansible-playbook test.yml -e Layer="front"
I do get error that says myresult does not have an attribute rc. What is the best way to print debug one statements based on the condition met?
I tried myresult is changed but that too does not help. Can you please suggest.
Use ignore_errors: true and change the task order. Try as below.
- name: Check file
shell: cat /tmp/front.txt
register: myresult
when: Layer == 'front'
- debug:
msg: data was read from front.txt and print whatever
when: not myresult.rc
ignore_errors: true
- name: Check file
shell: cat /tmp/back.txt
register: myresult
when: Layer == 'back'
- debug:
msg: data was read from back.txt and print whatever
when: not myresult.rc
ignore_errors: true
So far I can see using a when in ansible to determin whether to run a task but do I have to define 2 tasks to run the alternative option..
example - if I want to run the following task then run the debug task, i need to run two tasks or existStatus will not have been defined for the debug statement. Can I not use some sort of if else statement rather than include 2 separate tasks?
- name: Print user does not exist status
shell: echo 'user does not exist'
when: kafka_configs_result.stdout_lines[1] == '1'
register: existStatus
- name: Print user does not exist status
shell: echo 'user already exists so could not be created'
when: kafka_configs_result.stdout_lines[1] == '0'
register: existStatus
- debug: msg="{{ existStatus.stdout_lines }}"
You can do this in one single task without having to go through an unneeded shell execution. A simple way is to use a test and the ternary filter
I added the var section simply for readability. You can make a long one liner if you wish.
- debug:
vars:
exists_test: "{{ kafka_configs_result.stdout_lines[1] == '1' }}"
msg_exists: "user already exists so could not be created"
msg_notexists: "user does not exist"
msg: "{{ exists_test | ternary(msg_notexists, msg_exists) }}"
You can write something like this to utilize if-loop
- set_fact: build="{% if '<something>' in <something> %}<VALUE>{% else %}<VALUE>{% endif %}"
This is my code or checking wheter the website is valid and running:
- hosts: master
become: true
tasks:
- name: "Checking server availibility"
uri:
url: http://www.google.pl
timeout: 5
register: command_result
ignore_errors: yes
- debug: msg= "{{ command_result }}"
So command_result variable always returns this output regardless of the website availability:
ok: [Centos.v1] => {
"changed": false,
"msg": "Hello world!"
}
I would like to know if the first task was succesful or not but i can't do that when the output of registered variable is always the same.
How to setup my variable properly to read the return code?
and also
Is there some other way to check if an error occured in the previous task?
This has nothing to do with registering.
Remove the space character after msg=, otherwise you pass an empty string to the debug module and it prints Hello World! as a result (its default behaviour).
Better yet, use var parameter and YAML syntax:
- debug:
var: command_result