Use skip_reason as a condition in a task - ansible

Is it possible to use the skip_reason as condition to another task?
Here is the task:
- name: PSP Validation
script: roles/OS_minor_upgrade/files/PSP_validation.sh
ignore_errors: true.
register: PSP_VAL
when: >
not 'VMware' in HWMODEL.stdout
Which output:
TASK [OS_minor_upgrade : PSP Postwork] ******************************************************************************************************************************************************
task path: /home/ansible/linuxpatching_OS_Upgrade/roles/OS_minor_upgrade/tasks/upgrade.yml:264
skipping: [server123] => {
"changed": false,
"skip_reason": "Conditional result was False"
}
Now I want to use the above as condition to execute another task, I tried with the task below but it seem like it is not working.
- name: OSupgrade done
shell: echo {{ inventory_hostname }} "OS Upgrade Done" > OUTGOING-OSUPGRADE-PATCHCOMPLETION/inventory_{{ inventory_hostname }}_{{ '%y%m%d%H%M%S' | strftime }}_Offlineoutput
delegate_to: localhost
when: >
fs_check.rc == 0 and val_etrust.rc == 0 and 'PSP Installation is successfully completed' in PSP_VAL.stdout or 'Conditional result was False' in PSP_VAL.skip_reason
How can this be achieved?

Technically, you can use 'skip_reason' as any other variable, but I STRONGLY suggest you not to.
The reason is that person, reading your code (you, 1 week later) would be in a total loss over such decision.
If you have important information about your host, you can use set_fact module to update your host information. Further tasks can use this to make decisions.
- name: Update vmware info
set_fact:
vmware_flag: ('VMware' in HWMODEL.stdout)
- name: PSP Validation
script: roles/OS_minor_upgrade/files/PSP_validation.sh
failed_when: false
register: PSP_VAL
when: not vmware_flag
- name: OSupgrade done
delegate_to: localhost
copy:
dest: OUTGOING-OSUPGRADE-PATCHCOMPLETION/inventory_{{ inventory_hostname }}_{{ '%y%m%d%H%M%S' | strftime }}_Offlineoutput
content: '{{ inventory_hostname }} "OS Upgrade Done"'
when: (some other conditions) or vmware_flag

There are specific ansible tests to verify the registered result of a task
In your specific case:
when: <...all other conditions...> or PSP_VAL is skipped

Related

Loop over list and evaluate element property in Ansible

I have a list with shell lines that I want to execute on inventory hosts so I can determine if the database is working. For the test purposes I have 1 server with PostgreSQL and 1 with MySQL.
This is my playbook so far:
- name: Check db statuses
shell: "{{ item }}"
loop:
- ps -fp $(pgrep -u postgres) | grep /usr/lib/postgresql
- ps -fp $(pgrep -u mysql) | grep mysqld
register: http
ignore_errors: yes
changed_when: item.failed == false
this is failing with:
{
"http": {
"failed": true,
"msg": "The conditional check 'item.failed == false' failed. The error was: error while evaluating conditional (item.failed == false): 'ansible.parsing.yaml.objects.AnsibleUnicode object' has no attribute 'failed'"
}
}
I want to assign only the item.failed==false result in the register variable (http) but ignore the failed ones.
You can't select what will be registered in a loop. Instead, you'll have to evaluate the registered results in the next task(s), e.g.
- hosts: localhost
tasks:
- command: "{{ item }}"
loop:
- /bin/true
- /bin/false
register: http
ignore_errors: true
- debug:
msg: "{{ item.item }} failed: {{ item.failed }}"
loop: "{{ http.results }}"
loop_control:
label: "{{ item.cmd }}"
gives
ok: [localhost] => (item=['/bin/true']) =>
msg: '/bin/true failed: False'
ok: [localhost] => (item=['/bin/false']) =>
msg: '/bin/false failed: True'

How to display values of two different task register variables in ansible

Below is my playbook,
---
- hosts: all
tasks:
- name: asyn task 1 use time command to see diff use when hostname to get faster output
command: sleep 15
async: 2
poll: 0
register: result1
- name: asyn task
command: sleep 2
register: result2
- name: showing result1
debug:
var: result1
var1: result2
- name: debugging output
debug: msg=this is the {‌{ result1 }} and {‌{ result2 }}
# with_items:
# - {‌{ result1 }}
# - {‌{ result2 }}
getting below error,
changed: [vishwa]
TASK [showing result1] **************************************************************************************************
fatal: [rudra]: FAILED! => {"changed": false, "msg": "'var1' is not a valid option in debug"}
fatal: [arya]: FAILED! => {"changed": false, "msg": "'var1' is not a valid option in debug"}
fatal: [vishwa]: FAILED! => {"changed": false, "msg": "'var1' is not a valid option in debug"}
to retry, use: --limit #/home/admin/ansibledemo/asynch.retry
First point, debug module doesn't have an option var1 and so the error from showing result1 task. You probably have figured that out and written debugging output task with msg option.
This brings to the second point, registering status of an asynchronous task. Since you are using poll: 0, the task would be executing in asynchronous mode so the result may not be immediately available to the registered variable. Use async_status to check the result as described here. Also, in your scenario you should use async value more than sleep period.
An example,
- name: Wait for asynchronous job to end
async_status:
jid: '{{ result1.ansible_job_id }}'
register: job_result
until: job_result.finished
retries: 5
Maybe below playbook file could help you to fulfill your requirement. If not then I have some other alternatives too.
---
- hosts: all
gather_facts: false
name: "[ Debug Senario Test ]"
become: true
become_method: sudo
tasks:
- name: "[[ Command Task 1 ]]"
command: "echo Command Task 1"
register: register1
- name: "[[ Command Task 2 ]]"
command: "echo Command Task 2"
register: register2
- name: "[[ Display Registers ]]"
command: "echo {{ item.stdout }}"
with_items:
- "{{ register1 }}"
- "{{register2}}"
register: register3
- debug:
msg: "{{ register3 }}"
debug does not have a parameter var1, or var. You can't just create a parameter for a module. The error message is clear.
If you would like to store the result1 or result2 then use set_fact module.
You are executing a task in async running in the background. Async task follows a fire and forget execution. That task will be triggered and in running state while the other is being triggered. Use 2 https://docs.ansible.com/ansible/latest/modules/async_status_module.html
for fetching the result of the async task.
Ref:https://docs.ansible.com/ansible/2.7/user_guide/playbooks_async.html

Invoke multiple roles in Ansible with where condition

Is there a possibility to invoke roles depends on the when condition OR may be use Ansible handlers?
I have a below playbook which gets the current status of deployment on remote host and if and only required then perform the next steps. Below is the validation.yml from validations role (1st one to invoke) which does the validations -
---
- name: Getting the status of current deployment
stat:
path: "{{ tomcat_symlink_path }}"
register: p
- set_fact:
current_release: "{{ p.stat.lnk_target.split('/')[4] | regex_replace('^Release(.*)$', '\\1') }}"
- debug:
msg: "The currently deployed release is : {{ p.stat.lnk_target.split('/')[4] | regex_replace('^Release(.*)$', '\\1') }}"
- name: Copying Application Configuration files and get the checksum
template:
src: "{{ item }}"
dest: "{{config_location}}/{{ item | basename | regex_replace('.j2$', '') }}"
mode: 0755
with_fileglob:
- /temp/env/*.j2
register: config_var
- block:
- name: "Exit the deployment if no changes required...."
debug:
msg: "Target Release and currently deployed release is same OR no configuration changed required.. so Exiting the Deployment!!!!"
- meta: end_play
when: myvm_release_version == current_release and config_var.changed == false
Now depends on the above 2 variables. I need to invoke roles. For example -
if config_var.changed == true and myvm_release_version == current_release then invoke only roles stoptomcat and starttomcat and exit the deployment because it is just the config change so only restart tomcat is required.
if only config_var.changed == false and myvm_release_version != current_release then continue with the playbook which will execute everything and all the roles
This may be a weird requirement but may be someone expert can throw some light on it.
It's a common requirement
You can include role with when condition as simple as following..
Solution: 1
you can not refer two of more than two task with when condition, only one task is allowed,
simple hack can be include a external playbook In that conditional task.
Solution: 2
Your Ansible code till "register: config_var"
- name: include conditional role
include_role: "{{item}}"
when: config_var.changed == true and myvm_release_version == current_release
with_items:
- "stoptomcat"
- 'starttomcat"
- name: block of code
block:
// conditional ansible tasks
when: config_var.changed == false and myvm_release_version != current_release
I was able to find a solution as below using meta
- block:
- name: "Doing Configuration Changes...."
include_role:
name: '{{ roleinputvar }}'
loop:
- stoptomcat
- starttomcat
loop_control:
loop_var: roleinputvar
- meta: end_play
when: config_var.changed == true and myvm_release_version == current_release
Just posting so it might help others.

Understanding Ansible conditionals

I have a playbook (CIS compliance standard) with multiple tasks and I want to produce a "success" or "failed" depending on the ansible return code.
---
- name: 2.2.# Ensure ### Server is not enabled
block:
- name: Check if ### exists
stat: path=/usr/lib/systemd/system/###.service
register: exists
- name: Disable if exists
service:
name: ###
state: stopped
enabled: no
when: exists.stat.exists
register: result
- name: To File
block:
- name: Success
lineinfile:
dest: ./results/{{ customer }}-{{ scan_type }}-{{ inventory_hostname }}.txt
line: "{{ inventory_hostname }} 2.2.9 success"
insertafter: EOF
delegate_to: localhost
check_mode: False
when: ((result is skipped) or (result.enabled == false))
- name: Failed
lineinfile:
dest: ./results/{{ customer }}-{{ scan_type }}-{{ inventory_hostname }}.txt
line: "{{ inventory_hostname }} 2.2.9 failed"
insertafter: EOF
delegate_to: localhost
check_mode: False
when: ((result is not skipped) or (result.enabled == true))
From my observation, 'result' can have two different outputs depending on if the "Disable if exists" block is triggered.
If it is triggered, it'll give an output based on the "service" module.
If it is skipped, it'll give the generic Ansible output.
I'm fine with that, but what I can't seem to work out is the conditional statement.
when: ((result is not skipped) or (result.enabled == true))
This will always try to resolve both options, so if the module triggers, it will fail because "skipped" is not an attribute of the service module. If it skips, it'll pass, but obviously fail if it ever gets triggered. It's like it wants all conditions to exist before evaluating despite the "or" statement.
What am I doing wrong?
Do you mean result is skipped rather than result is not skipped? In any case, you can solve this using the default filter, which provides a default value if the input expression is undefined. For example:
when: result.enabled|default(false) == true
Of course, since that's a boolean, you can further simplify it to:
when: result.enabled|default(false)

How to make Ansible run one certain task only on one host?

The playbook looks like:
- hosts: all
tasks:
- name: "run on all hosts,1"
shell: something1
- name: "run on all hosts,2"
shell: something2
- name: "run on one host, any host would do"
shell: this_command_should_run_on_one_host
- name: "run on all hosts,3"
shell: something3
I know with command line option --limit, I can limit to one host, is it possible to do it in playbook?
For any host (with defaults it will match the first on the list):
- name: "run on first found host"
shell: this_command_should_run_on_one_host
run_once: true
For a specific host:
- name: "run on that_one_host host"
shell: this_command_should_run_on_one_host
when: ansible_hostname == 'that_one_host'
Or inventory_hostname (hostname as defined in the Ansible inventory) instead of ansible_hostname (hostname as defined on the target machine), depending on which name you want to use.
Techraf's first answer is the exact one for the OP's question.
I just wanted to show a better way to run a task on a specific host:
- name: "run on that_one_host host"
shell: this_command_should_run_on_one_host
run_once: true
delegate_to: that_one_host
If the group the playbook is run on contains many hosts, using when: ansible_hostname == 'that_one_host' or when: ansible_hostname == play_hosts[0] will evaluate the when-clause on all the hosts (which could be long if the when-clause had other more complicated conditions) and result in a long list of skipped hosts in the playbook's output.
Combining run_once and delegate_to, the playbook's output will be cleaner, only showing the task being executed on the chosen host.
- hosts: all
gather_facts: no
tasks:
- name: Run on one specific host | when-clause
debug:
msg: "Hello world"
when: inventory_hostname == play_hosts[0]
- name: Run on one specific host | run_once + delegate_to
debug:
msg: "Hello world"
run_once: true
delegate_to: play_hosts[0]
TASK [Run on one specific host | when-clause] **********************************************************************************
skipping: [host2]
skipping: [host3]
ok: [host1] => {
"msg": "Hello world"
}
skipping: [host4]
TASK [Run on one specific host | run_once + delegate_to] ***********************************************************************
ok: [host2 -> play_hosts[0]] => {
"msg": "Hello world"
}
Whichever solution you choose, never combine these, if you want a task to be run once on a precise host:
run_once: true and
when: inventory_hostname == 'that_one_host'
If you do, it will be impossible to know in advance if the task will be executed or not (I have learnt it the hard way). The reason is that run_once: true will select a random host in the play's group and only later apply the when-clause:
if run_once selected to run the task on 'that_one_host', the task will be executed
if run_once selected 'another_host', the task will be skipped.
True way
- include_tasks: custom-tasks.yml
when: inventory_hostname == item
with_items: "{{ ansible_play_hosts }}"

Resources