Run play book with multiple conditions - ansible

I have written a playbook which run handlers if the task was successful.Now I want to use some type conditions that if the above task fail then run different handler. Just like simple IF else statement works.
Current PLAYBOOK
tasks:
- name: checking file format
command: named-checkzone example.com /var/named/example.com
notify: service
handlers:
- name: "service reload"
command: rndc reload example.com
listen: "service"
Now I want to omit file name in configuration file if the main tasks fails

Q: "1) Run handler if the task was successful. 2) If the task fails then run another handler."
A: The simple way is to notify a handler when a task is changed. When a task fails the status is failed not changed and no handler is notified.
In this particular case, you don't care whether the command succeeded or failed. The handler shall always be notified. This can be achieved by an explicit combination of ignore_errors, failed_when, and changed_when.
Notify both handlers service success and service fail. The conditions in the handlers will decide which handler will run. For example the playbook
shell> cat playbook.yml
- hosts: localhost
tasks:
- command: "{{ cmd }}"
register: named_checkzone_result
ignore_errors: true
failed_when: false
changed_when: true
notify:
- service success
- service fail
handlers:
- name: service success
debug:
msg: Service success
when: named_checkzone_result.rc == 0
- name: service fail
debug:
msg: Service fail
when: named_checkzone_result.rc == 1
gives (abridged) if the command succeeds
shell> ansible-playbook playbook.yml -e "cmd=true"
TASK [command] ****
changed: [localhost]
RUNNING HANDLER [service success] ****
ok: [localhost] =>
msg: Service success
RUNNING HANDLER [service fail] ****
skipping: [localhost]
gives (abridged) if the command fails
shell> ansible-playbook playbook.yml -e "cmd=false"
TASK [command] ****
changed: [localhost]
RUNNING HANDLER [service success] ****
skipping: [localhost]
RUNNING HANDLER [service fail] ****
ok: [localhost] =>
msg: Service fail

Related

ansible handlers include_task not work with tags

I have a problem when trying to invoke an include tasks with tags from handlers but when executing it, it does not take the tags and executes all the tasks of the playbook
services.yaml
- name: stop service
become: true
systemd:
name: httpd
state: stopped
tags: stop
- name: start service
become: true
systemd:
name: httpd
state: started
tags: start
main.yaml
- hosts: webservers
tasks:
- name: ask stop / start
pause:
prompt: "please type start or stop"
echo: yes
register: ask
changed_when: true
notify: service
tags: restarting
handlers:
- name: service
include_tasks: services.yaml
tags: "{{ ask.user_input }}"
execute
ansible-playbook main.yam -t restarting
When I run it launches all the tasks omitting the tag
There is no point to use tags on handlers. A handler is either notified or not. Use conditions if you want to run handlers conditionally, e.g.
shell> cat services.yaml
- debug:
msg: stop service
when: ask.user_input == 'stop'
- debug:
msg: start service
when: ask.user_input == 'start'
Then the playbook
shell> cat pb.yml
- hosts: localhost
tasks:
- name: ask stop / start
pause:
prompt: "please type start or stop"
echo: true
register: ask
changed_when: true
notify: service
tags: [restarting, never]
handlers:
- name: service
include_tasks: services.yaml
gives
shell> ansible-playbook pb.yml -t restarting
PLAY [localhost] ***********************************************************
TASK [ask stop / start] ****************************************************
[ask stop / start]
please type start or stop:
changed: [localhost]
RUNNING HANDLER [service] **************************************************
included: /export/examples/example-269/services.yaml for localhost
RUNNING HANDLER [debug] ****************************************************
skipping: [localhost]
RUNNING HANDLER [debug] ****************************************************
ok: [localhost] =>
msg: start service
PLAY RECAP *****************************************************************
localhost: ok=3 changed=1 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
Add never tag to ask for the input only when restarting is selected.

echo message based on ansible stdout value

Team,
Not sure why my message with echo is not getting printed. I want to print a text if command that ran before for stopping process was successful.
In my case am checking for apache2 process status. Basically, if stdout is empty it passed and if stderr exists it failed. I also referred this link but no luck..
https://stackoverflow.com/questions/26142343/ansible-conditional-based-on-stdout-of-result
- name: stop apache2 process
command: systemctl stop apache2
ignore_errors: no
changed_when: false
register: service_apache2_status
become: true
- debug:
var: service_apache2_status.stdout
- name: Check if apache2 stopped
command: echo "Successfully Stopped Apache2"
# when: service_apache2_status.stdout == " "
when: service_apache2_status.stdout | length == 0
Actual output:
TASK [diskcache_prerequisites : stop apache2 process] **********************************************************************************
ok: [localhost]
TASK [diskcache_prerequisites : debug] *************************************************************************************************
ok: [localhost] => {
"service_apache2_status.stdout": ""
}
TASK [diskcache_prerequisites : Check if apache2 stopped] ******************************************************************************
changed: [localhost]
expected output:
TASK [diskcache_prerequisites : Check if apache2 stopped] ******************************************************************************
changed: [localhost]
Successfully Stopped Apache2
You don't need the "check if apache2 stopped" at all if you use the systemd module instead of trying to use command: to call systemctl by hand
As for your question: if you want to see output, that's what - debug: msg="Successfully stopped Apache2" is for; the command: module is not a general purpose debugging tool, it's for running commands

Ansible How to specify groups on the command line to run the corresponding tasks

ansible inventory
# hosts
[groupA]
192.168.1.1
[groupB]
192.168.1.1
192.168.1.3
ansible tasks:
# site.yml
---
- name: test
hosts: all
tasks:
- name: taskA
command: echo testA
when: "'groupA' in group_names "
- name: taskB
command: echo testB
when: "'groupB' in group_names "
I want to perform the task of taskA through groupA, how to do it?I use the following command to execute
ansible-playbook site.yml -l groupA -i hosts
However, getting the following result is not what I want because it also executes taskB, but I only want to use groupA to execute taskA.
I don't want to use ansible tag because I have a lot roles, there will be a lot of work to add each tag to each role.
PLAY [test] *******************************************************************************************************************************************
TASK [Gathering Facts] ********************************************************************************************************************************
ok: [192.168.1.1]
TASK [taskA] ******************************************************************************************************************************************
changed: [192.168.1.1]
TASK [taskB] ******************************************************************************************************************************************
changed: [192.168.1.1]
PLAY RECAP ********************************************************************************************************************************************
192.168.1.1 : ok=3 changed=2 unreachable=0 failed=0
Q "I just want the machine inside group_B to execute Task of B...For example, the machine inside group_B only executes Task of B."
A: Test the membership of the hosts in the groups. See the code below.
- hosts: all
tasks:
- name: Task of group_A
command: bash groupA.sh
when: inventory_hostname in groups['group_A']
- name: Task of group_B
command: bash groupB.sh
when: inventory_hostname in groups['group_B']
Q: "I just want to run Task of group_B. What should my order be? ansible-playbook site.yml -l group_B -i ansible_inventory If group_A and group_B have a common ip, Task of group_A will be executed, but I only want to execute Task of group_B."
"I don't want to use ansible tag because I have a lot. roles, there will be a lot of work to add each tag to each role."
A: Use include_role and apply tags (added in 2.7). Such applied tags are inherited by all tasks in the included role. See the code below.
- name: Task of group_B
include_role:
name: role123
apply:
tags: group_B
when: inventory_hostname in groups['group_B']
tags: group_B
Run the play
ansible-playbook -t group_B -i ansible_inventory site.yml

including handlers from different file

The handlers I have are not being run by the playbook or tasks
I have the following directory structur:
<project>
- playbook.yml
- <roles>
-<handler>
- main.yml
-<meta>
-<tasks>
-main.yml
The problem is the handler is never called.
tasks/main.yml:
- name: run task1
command: run_task
notify: "test me now"
handler/main.yml:
- name: tested
register: val1
listen: "test me now"
The playbook just calls the task/main.yml and has host:all
Do I ned an include/import? I tried in playbook but it didn't help
The play below works
tasks:
- include_tasks: tasks/main.yml
- meta: flush_handlers
- debug: var=val1.stdout
handlers:
- import_tasks: handlers/main.yml
handlers must be imported to be present when the task notifies it.
tasks may be included, or imported.
A module is missing in handler/main.yml. This would cause:
ERROR! no action detected in task. This often indicates a misspelled module name, or incorrect module path.
Use some module in handler/main.yml. For example:
- name: tested
command: "echo 'running handler'"
register: val1
listen: "test me now"
Running such play gives
val1.stdout: running handler
Simplified example
Running the playbook below
shell> cat playbook.yml
- hosts: localhost
tasks:
- include_tasks: tasks/main.yml
handlers:
- import_tasks: handlers/main.yml
shell> cat tasks/main.yml
- command: date
register: result
notify: test me now
shell> cat handlers/main.yml
- name: test me now
debug:
msg: "{{ result.stdout }} Running handler."
gives
shell> ansible-playbook playbook.yml
PLAY [localhost] *****************************************************************************
TASK [Gathering Facts] ***********************************************************************
ok: [localhost]
TASK [include_tasks] *************************************************************************
included: /export/scratch/tmp8/test-801/tasks/main.yml for localhost
TASK [command] *******************************************************************************
changed: [localhost]
RUNNING HANDLER [test me now] ****************************************************************
ok: [localhost] =>
msg: Mon 25 Apr 2022 04:59:02 PM CEST Running handler.
PLAY RECAP ***********************************************************************************
localhost : ok=4 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
You should have the structure described in https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html thus the directory should be called handlers (and not handler)

ansible playbook run a task only once

I need to run a task ,set a flag and the second time the play runs run the task only if the flag is not set
Play at a later stage
- name: Dump all databases
mysql_db:
state: dump
name: all
target: /root/mysql_all.sql
when: ansible_local.mysql.replication.setup is not defined
- name: create directory for ansible custom facts
file: state=directory recurse=yes path=/etc/ansible/facts.d
- name: install custom fact stating mysql is setup
template:
src: mysql.fact.j2
dest: /etc/ansible/facts.d/mysql.fact
The problem is that the fist time this play runs its throwing an error.
FAILED! => {"failed": true, "msg": "The conditional check 'ansible_local.mysql.replication.setup is not defined' failed. The error was: error while evaluating conditional (ansible_local.mysql.replication.setup is not defined): 'ansible_local' is undefined
What is the best way to run a task only in the first run and skip for subsequent runs.
you should make a task prior that registers if /root/mysql_all.sql exists then add it to your when clause.
Example:
- name: check if dump exists
stat:
path: /root/mysql_all.sql
register: mysqldump
- name: Dump all databases
mysql_db:
state: dump
name: all
target: /root/mysql_all.sql
when:
- ansible_local.mysql.replication.setup is not defined
- mysqldump.stat.exists == true
- name: create directory for ansible custom facts
file: state=directory recurse=yes path=/etc/ansible/facts.d
- name: install custom fact stating mysql is setup
template:
src: mysql.fact.j2
dest: /etc/ansible/facts.d/mysql.fact
One option is to utilize the fact cache. When enabled, you can set cacheable facts in your play and check for them.
Fact caching always takes place. There are various fact cache plug-ins available of which the memory plug-in is the default, and json file and redis cache are the most popular. You can only set one plug-in. Refer to
https://docs.ansible.com/ansible/latest/plugins/cache.html
When you want to explore with the json file you can set the environment variables as follows:
export ANSIBLE_CACHE_PLUGIN=jsonfile
export ANSIBLE_CACHE_PLUGIN_CONNECTION="~/ansiblefactcache"
In your play book you can check for facts and set them as cacheable, Refer to
https://docs.ansible.com/ansible/latest/collections/ansible/builtin/set_fact_module.html
A small example playbook.yaml:
- name: Example Fact Cache Playbook
hosts: all
gather_facts: false # the default is true; it gathers various host facts
tasks:
- name: Runs when examplefact equals something
debug:
msg: "Runs when examplefact equals something"
when: ansible_facts['examplefact'] is defined and ansible_facts['examplefact'] == "something"
- name: Does not run when examplefact equals something
debug:
msg: "does not run when examplefact equals something"
when: ansible_facts['examplefact'] is not defined or ansible_facts['examplefact'] != "something"
- name: Set the examplefact to something
set_fact:
examplefact: "something"
cacheable: true
Note the usage of the cacheable instruction. When true the fact goes into the cache.
After having run this small playbook you will notice the creation of a localhost file in your home's subfolder ansiblefactcache which contains your cached facts.
Also note the usage of the gather_facts instruction. The default being true will scan your machine for various details such as environment variables, network details, etc. All are cached. You can play with it and see the localhost file being populated with it.
You can also try to edit the localhost file yourself or even delete it and run the play again.
I used the following inventory file inventory.yaml:
all:
hosts:
localhost:
ansible_connection: local
And I run ansible as follows:
ansible-playbook playbook.yaml -i inventory.yaml -vvv
First run yields the following:
PLAY [Example Fact Cache Playbook] ********************************************************************************************************************************************************************************
TASK [Runs when examplefact equals something] *********************************************************************************************************************************************************************
skipping: [localhost]
TASK [Does not run when examplefact equals something] *************************************************************************************************************************************************************
ok: [localhost] => {
"msg": "does not run when examplefact equals something"
}
TASK [Set the examplefact to something] ***************************************************************************************************************************************************************************
ok: [localhost]
Second run yields the following:
PLAY [Example Fact Cache Playbook] ********************************************************************************************************************************************************************************
TASK [Runs when examplefact equals something] *********************************************************************************************************************************************************************
ok: [localhost] => {
"msg": "Runs when examplefact equals something"
}
TASK [Does not run when examplefact equals something] *************************************************************************************************************************************************************
skipping: [localhost]
TASK [Set the examplefact to something] ***************************************************************************************************************************************************************************
ok: [localhost]

Resources