run task once all tasks on all servers completed - ansible

Consider next scenario:
multiple hosts needs to be configured independently. At some point in time, after ALL configuration tasks on ALL hosts been completed successfully, some final tasks needs to be run on ONLY ONE host. what would be the proper solution for ansible playbook ?

Use run_once for that: http://docs.ansible.com/ansible/latest/user_guide/playbooks_delegation.html#run-once
Example:
---
- hosts: all
tasks:
- command: echo preparing stuff on all hosts
- command: echo run only on single host
run_once: True

Related

ansible delegate_to run for multiple times

I am trying to run certain tasks using delegate_to localhost or connection: local and other tasks on the remote host. however the task is executed on the localhost multiple times when i use "delegate_to: localhost"
my inventory
localhost ansible_host=127.0.0.1 ansible_connection=local ansible_python_interpreter="{{ansible_playbook_python}}"
[master1]
ip-10-90-148-195.ap-southeast-1.compute.internal
[master2]
ip-10-90-149-130.ap-southeast-1.compute.internal
[master3]
ip-10-90-150-239.ap-southeast-1.compute.internal
[master:children]
master1
master2
master3
[worker]
ip-10-90-148-206.ap-southeast-1.compute.internal
ip-10-90-149-178.ap-southeast-1.compute.internal
ip-10-90-150-86.ap-southeast-1.compute.internal
[all:vars]
ansible_user="core"
ansible_ssh_private_key_file="~/.ssh/id_rsa"
my task:
- name: host name
shell: echo `hostname` >> /tmp/123
#delegate_to: localhost
#connection: local
if i comment delegate_to: localhost and connection: local, i will get a file /tmp/123 on each remote host with their own hostname inside it. expected result.
however if i uncomment either one of them,the task will be executed 6 times on the localhost. meaning /tmp/ls on localhost will have localhost's hostname printed 6 times in it.
my goal is simple, i just want to run certain task on all host as per define in playbook hosts: groupa:groupb, and certain task on localhost, but 1 time only. i thought this is straight forward but i have been spending hours but no result.
if your hosts contains groupa:groupb then yes make sense to have 6 entries (it runs the tasks 6 times on localhost)
you need to add the option run_once: true in your task level.
or modify the playbook to run on the localhost only.

How to execute Play 2 only if Play 1 succeeds in Ansible

I have two Plays having one task each.
The first Play checks if the /var/test.dat exists on each target. Only if the first play is successful do I want the second play to run which executes these scripts in parallel.
If the first play fails i.e the test.dat does not exist I wish to terminate the playbook without the second Play getting executed. For this purpose, I have set any_errors_fatal set to true
I need to have an ansible Play strategy set to free as each of the scripts takes 30 minutes to complete.
My understanding of ansible is limited.
I understand that if I have both the tasks under a single PLAY and set the strategy to free both the tasks will run in parallel which is something I do not want.
---
- name: Play 1- check for login and script
hosts: all_hosts
any_errors_fatal: true
strategy: free
tasks:
- name: Check script existence
shell: "ls /var/test.dat"
register: checkscript
- name:
fail:
msg: "script {{ scriptdet }} missing on {{ inventory_hostname }}"
when: checkscript.rc != 0
- name: Play 2- Run scripts
hosts: all_hosts
user: "{{ USER }}"
strategy: free
tasks:
- name: Execute backup script
shell: "{{ scriptdet }}"
args:
chdir: ~/..
I tried the above playbook but I see the second play executes despite the first play's task failed.
Can you please suggest how can I get this to work?
Unless any_errors_fatal is true - Ansible will finish running on all hosts - even if some other host failed.
However, as you found out any_errors_fatal does not work with a free strategy.
It's also impossible to create a global variable.
However, you mentioned that you want to use free strategy to speed up the execution.
However, free strategy only prevents "blocking new tasks for hosts that have already finished.".
If you need to execute the same task without waiting for other hosts to finish, you need parallelism.
Strategy has nothing to do with parallelism.
In Ansible you adjust the number of parallel hosts with forks. However the default is very low, and is only 5.
What you want is to set this number higher - depending on your executing host resources. In my experience with a good amount of cpu and memory, this can be adjusted to hundreds.
You set this either in ansible.cfg or in the command line:
ansible-playbook -f 30 my_playbook.yml
This way you can use the default linear strategy with any_errors_fatal set to true.

How to make ansible loop over hosts sequentially

I have set of tasks that i want to execute at set of hosts sequentially.
Example is below.
hosts: all
tasks:
- name: do some work
include_tasks: tasks_here.yml
loop: "{{ vars[play_hosts] }}"
ansible-playbook main.yml --limit myhosts
I expect that set of tasks would be executed at first host, then at second host etc... But in fact these tasks are being executed simulatineously at all hosts in "limit".
I suspect that it's happening because I use limit but i need it in my case.
So what I should I do?
By default, as specified here:
plays run with a linear strategy, in which all hosts will run each task before any host starts the next task.
You can use the strategy serial: 1 to execute the tasks on each host sequentially.
For example:
- hosts: all
serial: 1
tasks:
...

Single role multiple hosts different tasks

I have a playbook with multiple tasks for a single role, i want to divide the tasks say 80% to first host and remaining 20% to second host , the first and second host will be picked from
ansible-playbook -i 1.2.3.4, 2.3.4.5, update.yml
where 1.2.3.4 is first server ip and 2.3.4.5 is second server ip. How can i achieve this.
To recap:
You have one role with 10 tasks. 6 of which you want to execute on server 1 and the rest on server 2
A way would be to write 2 different playbooks which will include the tasks you want to execute on the specified hosts.
Another might be to use tags on each task and execute ansible with --tags and specify them on playbook level
- hosts: all
tags:
- foo
role:
...
- hosts: all
tags:
- bar
role:
...
ref https://docs.ansible.com/ansible/latest/user_guide/playbooks_tags.html
Playbook tasks execution can be controlled by tags or blocks. My previous answer was related to the task execution on few of the hosts(I miss understood)
For eg.
serial: "80%"
would mean that all the tasks will be performed on 80% of the hosts first then will be performed on the remaining hosts.
For playbook to execute some tasks on few hosts and some on few hosts you can may be use when with ansible_hostname set to some hosts

In Ansible, can playbooks pass tags to other playbooks?

We have a "periodic" tag in our roles that is intended to be run at regular intervals by our Ansible box for file assurance, etc. Would it be possible to have a playbook for periodic runs that calls the other playbooks with the appropriate host groups and tags?
The only way to execute an Ansible playbook "with the appropriate host groups and tags" is to run ansible-playbook executable. This is the only case in which all the data structures starting from the inventory would be created in isolation from the currently running playbook.
You can simply call the executable using command module on the control machine:
- hosts: localhost
tasks:
- command: ansible-playbook {{ playbook }} --tags {{ tags }}
You can also use local_action or delegate_to.
It might be that you want to include plays, or use roles, however given the problem description in the question, it's impossible to tell.
Here is what we ended up with: It turns out that tags and variables passed on the command-line are inherited all the way down the line. This allowed us to pass this on the command line:
ansible-playbook -t periodic periodic.yml
Which calls a playbook like this:
---
- name: This playbook must be called with the "periodic" tag.
hosts: 127.0.0.1
any_errors_fatal: True
tasks:
- fail:
when: periodic not True
- name: Begin periodic runs for type 1 servers
include: type1-server.yml
vars:
servers:
- host_group1
- host_group2
- ...
- name: Begin periodic runs for type 2 servers
...
Our 'real' playbooks have - hosts: "{{ servers }}" so that they can be inherited from the parent. The tasks in our roles are tagged with "periodic" for things that need to be run on a schedule. We then use SystemD to schedule the runs. You can use cron, but SystemD is better IMHO. Examples can be provided upon request.

Resources