How can i release code on 50% machine in Ansibe - amazon-ec2

we have running 100 Machines in aws with tag Name=ad_server
so how can i run release code only 50% machines.
Example:
- hosts: tag_Name_ad_server
sudo: yes
remote_user: ubuntu
tasks:
- name: whatever
so how can i do this..

Option 1: serial + pause
This will use standard feature of batches for rolling updates and require some user interaction.
We add pause with prompt as a first task to wait for ENTER to be pressed at the start of every batch.
So press ENTER on the first 50%-batch and then abort execution when asked to start the second half.
- hosts: tag_Name_ad_server
user: ubuntu
serial: "50%"
tasks:
- pause: prompt="Press ENTER to run this batch"
- shell: echo task1
- shell: echo task2
With every playbook run serial will always choose the same servers from inventory. In this case first 50% from the list.
Option 2: form a new dynamic group
Loop through hosts in tag_Name_ad_server group and form a new 50_percent group.
Then execute your actual tasks within this new group.
No user interaction required.
- hosts: tag_Name_ad_server
gather_facts: no
tasks:
- group_by: key=50_percent
when: 100 | random > 50
- hosts: 50_percent
user: ubuntu
tasks:
- shell: echo task1
- shell: echo task2
With ever playbook run random will choose 50% random servers from the list.
Option 3: dirty trick with max_fail_percentage
If you have only one task to run, you can use max_fail_percentage: -1 to stop execution after first task of first batch.
This will make a 50%-batches, execute first task on every host of this batch and check failed servers count, as it always will be above -1 playbook will stop execution.
- hosts: tag_Name_ad_server
user: ubuntu
serial: "50%"
max_fail_percentage: -1
tasks:
- shell: echo task1
- shell: echo task2 # this task will never be executed with max_fail_percentage == -1

Related

How to end a whole play while using serial (Ansible 2.9)

Using Ansible 2.9, how do you end a playbook while also using serial?
When I run the following code that is a rolling upgrade, it executes the prompt for each target system. When using serial, run_once only seems to work for the current target. I only want it to execute once.
- hosts: all
become: yes
serial: 1
handlers:
- include: handlers/main.yml
pre_tasks:
- name: Populate service facts
service_facts:
- name: Prompt
pause:
prompt: "NOTE: You are running a dangerous playbook. Do you want to continue? (yes/no)"
register: confirm_input
run_once: True
- name: end play if user didn't enter yes
meta: end_play
when: confirm_input.user_input | default ("yes") =="no"
run_once: True
tasks:
(other stuff)
run_once will be executed at each serial execution in the play. That means, if you choose serial = 1, it will be asked to confirm as many times as the quantity of targets on the play.
Check Ansible docs: https://docs.ansible.com/ansible/latest/user_guide/playbooks_strategies.html#running-on-a-single-machine-with-run-once
When used together with serial, tasks marked as run_once will be run
on one host in each serial batch. If the task must run only once
regardless of serial mode, use when: inventory_hostname ==
ansible_play_hosts_all[0] construct.
to avoid default ansible behaviour and do what you want, follow the doc and use when: inventory_hostname == ansible_play_hosts_all[0] on the prompt task.

running a task on different hosts with intervals in ansible

this is my task/main.yml:
- name: Create and start services
docker_compose: ...
and I have 3 hosts. I'd like this task will be run on each host with 3 minute intervals.
for example: running on host1 at minute 0, running on host2 at minute 3 and running on host3 at minute 6.
How can I do that?
There's "pause" available in ansible playbook. Have you tried it?
Here is the official doc : https://docs.ansible.com/ansible/latest/modules/pause_module.html
As per this doc,
To pause/wait/sleep per host, use the wait_for module.
you can use "wait_for" module : https://docs.ansible.com/ansible/latest/modules/wait_for_module.html#wait-for-module
Code snippet which you can use for "pause" :
tasks:
- name: Test
pause:
minutes: 2
- name: Echo
debug:
msg: Test Pause
Code snippet for "wait_for"
tasks:
- name: sleep for 120 seconds and continue with play
wait_for:
timeout: 120
- name: Echo
debug:
msg: Test Pause

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:
...

ansible rolling restart playboook

Folks,
I'd like to have a service be restarted individually on each host, and wait for user input before continuing onto the next host in the inventory.
Currently, if you have the following:
- name: Restart something
command: service foo restart
tags:
- foo
- name: wait
pause: prompt="Make sure org.foo.FooOverload exception is not present"
tags:
- foo
It will only prompt once, and not really have the effect desired.
What is the proper ansible syntax to wait for user input before running the restart task on each host?
Use a combination of serial attribute and step option of a playbook.
playbook.yml
- name: Do it
hosts: myhosts
serial: 1
tasks:
- shell: hostname
Call the playbook with --step option
ansible-playbook playbook.yml --step
You will be prompted for every host.
Perform task: shell hostname (y/n/c): y
Perform task: shell hostname (y/n/c): ****************************************
changed: [y.y.y.y]
Perform task: shell hostname (y/n/c): y
Perform task: shell hostname (y/n/c): ****************************************
changed: [z.z.z.z]
For more information: Start and Step
I went ahead with this:
- name: Restart Datastax Agent
tags:
- agent
hosts: cassandra
sudo: yes
serial: 1
gather_facts: yes
tasks:
- name: Pause
pause: prompt="Hit RETURN to restart datastax agent on {{ inventory_hostname }}"
- name: Restarting Datastax Agent on {{ inventory_hostname }}
service: name=datastax-agent state=restarted

Resources