Unable to fail terminate Ansible playbook upon string match condition - string

I wish to fail and terminate my ansible playbook when Number=TKT334
Below is my playbook:
---
- name: "Play 1"
hosts: localhost
any_errors_fatal: True
serial: 1
tags: always
tasks:
- name: Setting string variable.
set_fact:
inlinevar: '2020-06-10 20:22:16\tTKT334\tKIRAN\tDeployed\tPRODUCTION'
- name: Setting string variable.
set_fact:
environment: 'PRODUCTION'
- block:
- name: "Search to avoid duplicate CR Numbers user:{{ ansible_user_id }}"
shell: "echo SUCCESSSSSSS"
failed_when: (inlinevar is search( Number ) and environment == "PRODUCTION")
- debug:
msg: This is FINAL inlinevar `{{ inlinevar }}`
rescue:
- name: Print custom conditional debug message
fail:
msg: >-
{{
command_result_app.stdout is search( Number ) |
ternary(
"This CR is already Deployed. Hence retry with a Unique CR Number.",
"The Dtabase is not reachable. Unable to connect To the Database."
)
}}
However, when I run the playbook I do not fail and continues to print the debug:
I was expecting it to fail but it shows ansible run as successful and does not terminate the playbook executions.
See the output below:
ansible-playbook test.yml -e Number=TKT334
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'
PLAY [Play 1] *************************************************************************************
TASK [Gathering Facts] *************************************************************************************************************************************************
ok: [localhost]
TASK [Setting string variable.] ****************************************************************
ok: [localhost]
TASK [Setting string variable.] ****************************************************************
ok: [localhost]
TASK [Search to avoid duplicate CR Numbers user:{{ ansible_user_id }}] ***
changed: [localhost]
TASK [debug] ***********************************************************************************************************************************************************
ok: [localhost] => {
"msg": "This is FINAL inlinevar `2020-06-10 20:22:16\\tTKT334\\t KIRAN\\tDeployed\\tPRODUCTION`"
}
PLAY RECAP *************************************************************************************************************************************************************
localhost : ok=5 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Can you please suggest?

environment is a special option used to set environment variables for tasks, e.g.
- name: Do something
shell: echo "whatever"
environment:
http_proxy: http://my.server.com:8080
no_proxy: my.domain.com
In your case, environment is always empty after set_fact and environment == "PRODUCTION" is always false.
Rename your variable to something else, don't use environment (see this other question for more discussion), e.g.
[...]
- name: Setting string variable.
set_fact:
deploy_environment: 'PRODUCTION'
- block:
- name: "Search to avoid duplicate CR Numbers user:{{ ansible_user_id }}"
shell: "echo SUCCESSSSSSS"
failed_when: (inlinevar is search( Number ) and deploy_environment == "PRODUCTION")
[...]

Related

Conditionals against variables

I am building a snapshot management playbook and that checks for an existing snap before taking a snap. I am having trouble testing a conditional when the playbook finds an existing snap. Here is a sample code:
---
- name: Test Snapshot
hosts: axwayT
gather_facts: false
vars_files:
- vault/creds.yml
vars:
mail_body_file: "/tmp/ansible_mail"
pre_tasks:
- name: Delete mail body file
file:
state: absent
path: "{{ mail_body_file }}"
delegate_to: localhost
run_once: true
- name: Create mail body file
file:
state: touch
path: "{{ mail_body_file }}"
delegate_to: localhost
run_once: true
tasks:
- name: find guest's folder using name
vmware_guest_find:
hostname: "{{ vcenter_hostname }}"
username: "{{ vcenter_username }}"
password: "{{ vcenter_password }}"
validate_certs: no
name: "{{ vcenter_hostgroup_name }}"
datacenter: "{{ datacenter_name }}"
register: vm_folder
delegate_to: localhost
- name: Check for existing snapshots
vmware_guest:
hostname: "{{ vcenter_hostname }}"
username: "{{ vcenter_username }}"
password: "{{ vcenter_password }}"
validate_certs: no
name: "{{ vcenter_hostgroup_name }}"
datacenter: "{{ datacenter_name }}"
folder: "{{vm_folder.folders[0]}}"
name: "{{ vcenter_hostgroup_name }}"
state: present
register: vm_state
delegate_to: localhost
- name: debug
debug:
var: vm_state.instance.current_snapshot
- name: Test
shell: echo "Found!"
when: vm_state.instance.current_snapshot !=""
I am working with an inventory of two servers for testing, nothing special. Here is the ouput I want to use a conditional against:
TASK [debug] ********************************************************************************************************************************************************************************************************************************
ok: [swipe901.test.com] => {
"vm_state.instance.current_snapshot": ""
}
ok: [swipe902.test.com] => {
"vm_state.instance.current_snapshot": {
"creation_time": "2023-02-07T21:14:06.812901+00:00",
"description": "",
"id": 13,
"name": "VM Snapshot 2%2f7%2f2023, 3:14:05 PM",
"state": "poweredOn"
}
}
I tried two when statements:
when: vm_state.instance.current_snapshot =""
when: vm_state.instance.current_snapshot is defined
My logic is way off and I am seeing my own limitations with programing logic, which I plan to fix soon.
My plan for the logic is to, skip a step, in my playbook if vm_state.instance.current_snapshot is "". How would this be handled?
Q: "I would like the condition to evaluate false if there is anything populated in current_snapshot."
A: For example, the playbook
shell> cat pb.yml
- name: Evaluate false if there is anything populated in current_snapshot
hosts: localhost
tasks:
- debug:
msg: The variable current_snapshot is either empty or does not exist.
when: current_snapshot|d('', true)|length == 0
gives
shell> ansible-playbook pb.yml
PLAY [Evaluate false if there is anything populated in current_snapshot] *************************************************************
TASK [debug] *************************************************************************************************************************
ok: [localhost] =>
msg: The variable current_snapshot is either empty or does not exist.
PLAY RECAP ***************************************************************************************************************************
localhost: ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
shell> ansible-playbook pb.yml -e current_snapshot=''
PLAY [Evaluate false if there is anything populated in current_snapshot] *************************************************************
TASK [debug] *************************************************************************************************************************
ok: [localhost] =>
msg: The variable current_snapshot is either empty or does not exist.
PLAY RECAP ***************************************************************************************************************************
localhost: ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
shell> ansible-playbook pb.yml -e current_snapshot='anything'
PLAY [Evaluate false if there is anything populated in current_snapshot] *************************************************************
TASK [debug] *************************************************************************************************************************
skipping: [localhost]
PLAY RECAP ***************************************************************************************************************************
localhost: ok=0 changed=0 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
You can also use assert. For example,
shell> cat pb.yml
- name: Evaluate false if there is anything populated in current_snapshot
hosts: localhost
tasks:
- assert:
that: current_snapshot|d('', true)|length == 0
success_msg: The variable current_snapshot is either empty or does not exist.
fail_msg: The variable current_snapshot is populated.

Testing a task result which uses a loop?

So the first task is always skipped because RedHat 8 is detected which should trigger the fail module to run but this gets skipped also. Is works fine without the loop though.
- name: installing packages
hosts: ansible2
ignore_errors: true
vars_files: varsfile
tasks:
- name: install software based on OS distro and version
yum:
name: "{{ item.name }}"
state: latest
loop: "{{ packages }}"
when: >
( ansible_distribution == "RedHat" and ansible_distribution_major_version is version('12', '>=') )
or
( ansible_distribution == "CentOS" and ansible_distribution_major_version | int >= 8 )
register: result
- fail:
msg: error {{ ansible_hostname }} does not meet minimum requirements
when: result is skipped
Regarding
So the first task is always skipped because RedHat 8 is detected which should trigger the fail module to run but this gets skipped also.
with a small test setup and a debug task for the variable name to debug
---
- hosts: test.example.com
become: false
gather_facts: true
tasks:
- name: Install software based on OS distro and version
debug:
msg: "{{ ansible_distribution }} {{ ansible_distribution_major_version }}"
register: result
when: ansible_distribution == "RedHat" and ansible_distribution_major_version is version('12', '>=')
with_items: ['pkg1', 'pkg2']
- name: Show result
debug:
var: result
- fail:
msg: "Error: {{ ansible_hostname }} does not meet minimum requirements"
when: result.results[0].skipped
resulting into an output of
TASK [Gathering Facts] ********************************
ok: [test.example.com]
TASK [Show result] ************************************
ok: [test.example.com] =>
result:
changed: false
msg: All items completed
results:
- ansible_loop_var: item
changed: false
item: pkg1
skip_reason: Conditional result was False
skipped: true
...
TASK [fail] *******************************************
fatal: [test.example.com]: FAILED! => changed=false
msg: 'Error: test does not meet minimum requirements'
you can see that the loop will create a list.
- name: Show result
debug:
var: result.results | type_debug
TASK [Show result] ****************
ok: [test.example.com] =>
result.results | type_debug: list
Therefore you need to set the Conditional to when: result.results[0].skipped.
Regarding
Is works fine without the loop though.
it is recommended to simplify your use case with the following approach
- name: Install software based on OS distro and version
yum:
name: "{{ packages }}"
state: latest
according the yum module Notes
When used with a loop: each package will be processed individually, it is much more efficient to pass the list directly to the name option.
and as it is faster and consumes less resources. Furthermore the result set and conditionals are less complex.

How can I compare a remote file with a reference on controller without failing the playbook when different?

I have a very peculiar problem, in my code I have to compare ansible value with customer expected value and customer expected un_matched value, however the final playbook output should be failed =0 instead of failed =1.
The code is:
- name: show file contents of customer-expects.txt
debug:
msg: "{{ lookup('file', '/customer-expects.txt') }}"
- shell: cat /etc/issue
register: issue
changed_when: false
ignore_errors: yes
- assert:
that:
- lookup('file', '/customer-expects.txt') == issue.stdout
success_msg: "matched! {{ lookup('file', '/customer-expects.txt') }} = {{ issue.stdout }}"
- name: show file contents customer-expects_unmatched.txt
debug:
msg: "{{ lookup('file', '/customer-expects_unmatched.txt') }}"
- shell: cat /etc/issue
register: issue
changed_when: false
ignore_errors: yes
- assert:
that:
- lookup('file', '/customer-expects_unmatched.txt') == issue.stdout
fail_msg: "unmatched! {{ lookup('file', '/customer-expects_unmatched.txt') }} = {{ issue.stdout }}"
success_msg: "matched! {{ lookup('file', '/customer-expects.txt') }} = {{ issue.stdout }}"
Output is:
[root#ansible-master /]# ansible-playbook tab8.role.yml -v
Using /etc/ansible/ansible.cfg as config file
PLAY [This output is for Tab-8 of Function Design document] *********
TASK [Gathering Facts] **********************************************
ok: [ansible-client1]
TASK [issue_tab8 : show file contents of customer-expects.txt] ******
ok: [ansible-client1] => {
"msg": ""
}
TASK [issue_tab8 : shell] *******************************************
ok: [ansible-client1] => {"changed": false, "cmd": "cat /etc/issue", "delta": "0:00:00.005200", "end": "2022-01-25 14:17:57.070688", "rc": 0, "start": "2022-01-25 14:17:57.065488", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}
TASK [issue_tab8 : assert] ******************************************
ok: [ansible-client1] => {
"changed": false,
"msg": "matched! = "
}
TASK [issue_tab8 : show file contents customer-expects_unmatched.txt] *
ok: [ansible-client1] => {
"msg": "abc"
}
TASK [issue_tab8 : shell] *******************************************
ok: [ansible-client1] => {"changed": false, "cmd": "cat /etc/issue", "delta": "0:00:00.004603", "end": "2022-01-25 14:17:57.674059", "rc": 0, "start": "2022-01-25 14:17:57.669456", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}
TASK [issue_tab8 : assert] ******************************************
fatal: [ansible-client1]: FAILED! => {
"assertion": "lookup('file', '/customer-expects_unmatched.txt') == issue.stdout",
"changed": false,
"evaluated_to": false,
"msg": "unmatched! abc = "
}
PLAY RECAP **********************************************************
ansible-client1 : ok=6 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
You are taking this the wrong way and make it unnecessarily complicated IMO.
You have to understand that laying out a playbook in ansible consists of describing the state in which you want to find the target machine. In this particular situation, you want to describe the state in which you want to find a particular file on the target. This is basically done with a task using the copy module. Once you have done that, knowing if the file is similar or different is just a matter of command line switches or task options.
For more on the below explanation see Validating tasks
Ansible has a check_mode which will let you run an entire playbook just to verify what it would do. You can also unconditionally apply that mode to a single task so that it always runs as a check (check_mode: true), or always makes changes to the remote target however the playbook was called (check_mode: false). We are interested here in the first form.
Similarly, ansible has a diff possibility that will let you see what are the differences between the state you described and the modification it (should have to) apply on the target to reach that state.
An example whith your above scenario. I made the test targeting my local machine only but you can get the exact same result on any remote target.
First let's create the reference file we want to check against in our ansible directory.
mkdir -p files
echo "I'm the reference file" > files/ansible_reference.txt
For the example, I'll now create one identical and one different file on our target so that we can compare both cases:
echo "I'm the reference file" > /tmp/ansible_similar.txt
echo "I'm a different file" > /tmp/ansible_different.txt
This is the playbook compare.yml
---
- name: compare remote file to a local reference
hosts: localhost
gather_facts: false
vars:
local_reference: ansible_reference.txt
remote_files_2_check:
- /tmp/ansible_similar.txt
- /tmp/ansible_different.txt
tasks:
- name: Dry run a copy with diff to check if remote file is aligned
copy:
src: "{{ local_reference }}"
dest: "{{ item }}"
check_mode: true
diff: true
loop: "{{ remote_files_2_check }}"
Which gives:
$ ansible-playbook compare.yml
PLAY [compare remote file to a local reference] *****************************
TASK [Dry run a copy with diff to check if remote file is aligned] **********
ok: [localhost] => (item=/tmp/ansible_similar.txt)
--- before: /tmp/ansible_different.txt
+++ after: /home/user/ansible_project/files/ansible_reference.txt
## -1 +1 ##
-I'm a different file
+I'm the reference file
changed: [localhost] => (item=/tmp/ansible_different.txt)
PLAY RECAP ******************************************************************
localhost : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Notes:
Although Ansible reports changed for the different file this is only what would happen. Since we are in dry-run for the given task, the above will not change your target. You can run it any number of times, it will report the same result as long as you don't change the reference or the target state.
I you are not happy with the default reporting of the task, you can register the result, explore its content and use it in subsequent tasks to meet your exact requirement.
Note that the above may report a difference on the permission of the target file. You may have to tune this in the copy module to avoid false positive.

ansible-playbook extra vars passing from command line

My playbook looks like:
---
- name: Install and configure AD authentication
hosts: test
become: yes
become_user: root
vars:
hostname: "{{ host_name }}"
vars_prompt:
- name: "bind_password"
prompt: "Password for xxx.local\\user"
private: yes
tasks:
- name: Ansible prompt example.
debug:
msg: "{{ bind_password }}"
- name: Ansible prompt example.
debug:
msg: "{{ host_name }}"
and i am using below command to pass the variable
ansible-playbook hostname_set.yml --extra-vars "host_name= 'xxx.xxx.local'"
but i am not getting exact variable value what i am using for setting up hostname.
Password for xxx.xxx\user:
PLAY [Install and configure AD authentication]
TASK [Gathering Facts]
ok: [x.x.x.x]
TASK [Ansible prompt example.]
ok: [x.x.x.x] => {
"msg": "wel"
}
TASK [Ansible prompt example.]
ok: [x.x.x.x] => {
"msg": ""
}
TASK [Setup the hostname]
changed: [x.x.x.x]
PLAY RECAP
x.x.x.x : ok=4 changed=1 unreachable=0 failed=0
skipped=0 rescued=0 ignored=0
You have an extra space in your command line that ruins how ansible is interpreting the extra vars. Just remove it:
--extra-vars "host_name='xxx.xxx.local'"
Note that you don't even need all those quotes. The following should also work as expected:
--extra-vars host_name=xxx.xxx.local

How to skip all other plays in ansible playbook if some condition is not met?

I have multiple plays in below playbook. I want to ignore all other plays if some condition is not met.
So for below example - If I cannot find any new file in Play1 then I don't want to execute Play2 and Play3 at all (it should skip it). How can I do that?
I have end_play in Play1 but it only skips Play1 and it still executes Play2 and Play3
---
- name: Play 1
hosts: 127.0.0.1
tasks:
- name: find the latest file
find: paths=/var/lib/jenkins/jobs/process/workspace/files
file_type=file
age=-1m
age_stamp=mtime
register: files
- meta: end_play
when: files.files|count == 0
- name: Copy file, if found
copy:
src: "some stuff here"
dest: "some other stuff here"
when: files.files|count > 0
- name: Play 2
hosts: all
serial: 5
tasks:
- name: copy latest file
copy: src=data_init/goldy.init.qa dest=/data01/admin/files/goldy.init.qa owner=golden group=golden
- name: copy latest file
copy: src=data_init/goldy.init.qa dest=/data02/admin/files/goldy.init.qa owner=golden group=golden
- name: Play 3
hosts: 127.0.0.1
tasks:
- name: execute command
shell: ./data_init --init_file ./goldy.init.qa
args:
chdir: /var/lib/jenkins/jobs/process/workspace/data_init/
Update:
So block module solution doesn't work looks like because you cannot use nested play in block like that..
There are two ways to approach your issue:
Although it is understandable that you tried defining a hosts: localhost to run some tasks on the controller, you don't really need this. Using delegate_to: localhost and run_once: true on the steps you want to run on your controller is a far better approach.
If you really want to go this way (using hosts: localhost), for some reason, then you'll need to save the return of your find, with set_fact in order to reuse it in other hosts with the help of the global hostvars
Using delegation
Any task in the play can be delegated to another host. This is quite simple to do and would just use one extra delegate_to options on your task:
- name: Delegate a find to localhost
find:
path: /test
file_type: any
register: localhost_find
delegate_to: localhost
run_once: true
When doing so, I would advice you to also use run_once: true, because, if you delegate the task to another host, there is no need to, let's say run it ten times if you have ten hosts in your host group.
Here is a little example about that
---
- hosts: hosts
become: true
gather_facts: false
tasks:
- name: Delegate directory creation to localhost
file:
path: /test
state: directory
delegate_to: localhost
run_once: true
- name: Create directory on hosts
file:
path: /test
state: directory
- name: Delegate file creation to localhost
file:
path: /test/localhost.txt
state: touch
delegate_to: localhost
run_once: true
- name: Create file on hosts
file:
path: /test/host.txt
state: touch
- name: Delegate a find to localhost
find:
path: /test
file_type: any
register: localhost_find
delegate_to: localhost
run_once: true
- name: Find in the hosts for comparison
find:
path: /test
file_type: any
register: host_find
- name: List /test of localhost
debug:
msg: "{{ localhost_find.files | map(attribute='path') | list }}"
- name: List /test of host
debug:
msg: "{{ host_find.files | map(attribute='path') | list }}"
- name: Remove /test folder on localhost
file:
path: /test
state: absent
delegate_to: localhost
run_once: true
- name: Delegate an empty find to localhost
find:
path: /test
file_type: any
register: empty_find
delegate_to: localhost
run_once: true
- name: Here are our hostnames from the inventory
debug:
msg: "{{ inventory_hostname }}"
- name: I am the evil host killer
meta: end_host
when: empty_find.files | count == 0 and inventory_hostname != 'host1'
- debug:
msg: "I am a sad message, because I will never display :'( But hopefully host1 likes me :')"
- name: I am the evil playbook killer
meta: end_play
when: empty_find.files | count == 0
- debug:
msg: "I am a sad message, because I will never display :'( No one likes me..."
Where you can see, that, I am skipping the very last debug message by ending the play, when I ended two out of the three hosts I have in my hosts group on the step before.
Output of that playbook:
PLAY [hosts] **************************************************************************************************************************
TASK [Delegate directory creation to localhost] ***************************************************************************************
ok: [host1 -> localhost]
TASK [Create directory on hosts] ****************************************************************************************************
ok: [host3]
ok: [host2]
ok: [host1]
TASK [Delegate file creation to localhost] ********************************************************************************************
changed: [host1 -> localhost]
TASK [Create file on hosts] ****************************************************************************************************
changed: [host2]
changed: [host1]
changed: [host3]
TASK [Delegate a find to localhost] ***************************************************************************************************
ok: [host1 -> localhost]
TASK [Find in the host for comparison] ************************************************************************************************
ok: [host1]
ok: [host3]
ok: [host2]
TASK [List /test of localhost] ********************************************************************************************************
ok: [host1] => {
"msg": [
"/test/localhost.txt"
]
}
ok: [host2] => {
"msg": [
"/test/localhost.txt"
]
}
ok: [host3] => {
"msg": [
"/test/localhost.txt"
]
}
TASK [List /test of host] *************************************************************************************************************
ok: [host1] => {
"msg": [
"/test/host.txt"
]
}
ok: [host2] => {
"msg": [
"/test/host.txt"
]
}
ok: [host3] => {
"msg": [
"/test/host.txt"
]
}
TASK [Remove /test folder on localhost] ***********************************************************************************************
changed: [host1 -> localhost]
TASK [Delegate an empty find to localhost] ********************************************************************************************
ok: [host1 -> localhost]
TASK [Here are our hostnames from the inventory] **************************************************************************************
ok: [host1] => {
"msg": "host1"
}
ok: [host2] => {
"msg": "host2"
}
ok: [host3] => {
"msg": "host3"
}
TASK [debug] **************************************************************************************************************************
ok: [host1] => {
"msg": "I am a sad message, because I will never display :'( But hopefully host1 likes me :')"
}
PLAY RECAP ****************************************************************************************************************************
host1 : ok=12 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
host2 : ok=6 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
host3 : ok=6 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
In the output, you can easily spot the delegation, as is will output
changed: [host1 -> localhost]
When a non-delegated task would just go
changed: [host1]
Using hostvars
I would say the approach is a little bit less state of the art, but could become handy if you would like to delegate on edge cases. I have used it before, so it is not like there is no situation where it could not end up has being the right solution.
Here is the example
---
- hosts: localhost
gather_facts: false
tasks:
- name: Find in localhost
find:
path: /not/existing/folder
file_type: any
register: find
- name: This will register the list under find.files as a variable on the host, making it accessible via hostvars
set_fact:
find_result: "{{ find.files }}"
- meta: end_play
when: find.files | count == 0
- debug:
msg: I am the sanity check message, proving the end_play did happen
- hosts: hosts
gather_facts: false
tasks:
- name: Just to show we are not cheating with an empty host group, we display the hosts names
debug:
msg: "{{ inventory_hostname }}"
- name: To show it is really our empty list and not an empty string or a null variable
debug:
msg: "{{ hostvars['localhost']['find_result'] }}"
- meta: end_play
when: "hostvars['localhost']['find_result'] | count == 0"
- debug:
msg: I am a first sanity check message, proving the end_play did happen
- debug:
msg: I am a second sanity check message, proving the end_play did happen
- hosts: localhost
gather_facts: false
tasks:
- name: To show it is really our empty list and not an empty string or a null variable
debug:
msg: "{{ hostvars['localhost']['find_result'] }}"
- meta: end_play
when: "hostvars['localhost']['find_result'] | count == 0"
- debug:
msg: I am a first sanity check message, proving the end_play did happen
- debug:
msg: I am a second sanity check message, proving the end_play did happen
Where you can see that, at the beginning of each new tasks group for a host, I just run the meta to end the play, based on the variable find_result registered out of the find result
Here is the output for this one
PLAY [localhost] **********************************************************************************************************************
TASK [Find in localhost] **************************************************************************************************************
ok: [localhost]
TASK [This will register the list under find.files as a variable on the host, making it accessible via hostvars] *********************
ok: [localhost]
PLAY [hosts] **************************************************************************************************************************
TASK [Just to show we are not cheating with an empty host group, we display the hosts names] ******************************************
ok: [host1] => {
"msg": "host1"
}
ok: [host2] => {
"msg": "host2"
}
ok: [host3] => {
"msg": "host3"
}
TASK [To show it is really our empty list and not an empty string or a null variable] ************************************************
ok: [host1] => {
"msg": []
}
ok: [host2] => {
"msg": []
}
ok: [host3] => {
"msg": []
}
PLAY [localhost] **********************************************************************************************************************
TASK [To show it is really our empty list and not an empty string or a null variable] ************************************************
ok: [localhost] => {
"msg": []
}
PLAY RECAP ****************************************************************************************************************************
host1 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
host2 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
host3 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
localhost : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Try using a block that only triggers your second two tasks after you do your first:
https://docs.ansible.com/ansible/latest/user_guide/playbooks_blocks.html
---
- name: Play 1
hosts: 127.0.0.1
tasks:
- name: find the latest file
find: paths=/var/lib/jenkins/jobs/process/workspace/files
file_type=file
age=-1m
age_stamp=mtime
register: files
- name: Play 2 & 3 if Play 1 has a file
block:
- name: Play 2
hosts: all
serial: 5
tasks:
- name: copy latest file
copy: src=data_init/goldy.init.qa dest=/data01/admin/files/goldy.init.qa owner=golden group=golden
- name: copy latest file
copy: src=data_init/goldy.init.qa dest=/data02/admin/files/goldy.init.qa owner=golden group=golden
- name: Play 3
hosts: 127.0.0.1
tasks:
- name: execute command
shell: ./data_init --init_file ./goldy.init.qa
when: files != ""
...
Using Variables in hosts value
One trick you can use is set the value of target hosts for the other plays in Play1 this way you can set it to a value that doesn't exist in your inventory (DONOTEXECUTE in the case shown below) the other plays will simply be skipped
- name: Play 1
hosts: 127.0.0.1
tasks:
- name: find the latest file
find: paths=/var/lib/jenkins/jobs/process/workspace/files
file_type=file
age=-1m
age_stamp=mtime
register: files
- name: Copy file, if found
copy:
src: "some stuff here"
dest: "some other stuff here"
when: files.files|count > 0
- name: end_plays
set_fact:
play2_hosts: DONOTEXECUTE
play3_hosts: DONOTEXECUTE
when: files.files|count == 0
- name: continue_plays
set_fact:
play2_hosts: all
play3_hosts: 127.0.0.1
when: files.files|count > 0
- name: Play 2
hosts: "{{hostvars['localhost']['play2_hosts']}}"
serial: 5
tasks:
- name: copy latest file
copy: src=data_init/goldy.init.qa dest=/data01/admin/files/goldy.init.qa owner=golden group=golden
- name: copy latest file
copy: src=data_init/goldy.init.qa dest=/data02/admin/files/goldy.init.qa owner=golden group=golden
- name: Play 3
hosts: "{{hostvars['localhost']['play3_hosts']}}"
tasks:
- name: execute command
shell: ./data_init --init_file ./goldy.init.qa
args:
chdir: /var/lib/jenkins/jobs/process/workspace/data_init/

Resources