conditionally run tasks when given multiple input to a variable - ansible

I have written a ansible script which runs fine when there is only 1 input to a variable:
---
- hosts: ListA
vars:
app-dir: /tmp
service_name: exampleAAA
roles:
- prechecks
Below is the task i am using and working when only one service defined for service_name:
---
- name: check service status
command: "{{app_dir}}/app-name {{item}} status"
with_items: '{{service_name}}'
ignore_errors: yes
register: service_status
- name: starting service if it's in failed state
set_fact: serviceTostart={{item}}
with_items: '{{service_name}}'
when: service_status | failed
- shell: "{{app_dir}}/app-name {{serviceTostart}} start"
when: service_status | failed
As per my usecase i need this to work for below:
vars:
service_name:
- exampleAAA
- exampleBBB
- exampleCCC
When i run the playbook after defining multiple service_name. it shows failed status of service in step check service status but it says ok in rest of the steps. When i check the status of services there is no change. How can i make it work for multiple service_names ???
So here i what the script should do(I am stuck with points 2 & 3, can someone please let me know what need to be done to make it work):
The script will check the status of all the services mentioned (it is doing this correctly)
If one of the service status shows as stop. It will go the tasks which will run the command to bring back that particular service.
If after one start the service still does not come up then script should fail ( I am yet to write code for this part).

Honestly the answer to your question is in the documentation: Using register with a loop.
- name: check service status
command: "{{app_dir}}/app-name {{item}} status"
with_items: "{{service_name}}"
ignore_errors: yes
register: service_status
- shell: "{{app_dir}}/app-name {{item.item}} start"
when: item | failed
with_items: "{{service_status.results}}"

Related

Write task output to file while using "until"

I have an ansible task that fails about 20% of the time. It almost always succeeds if retried a couple of times. I'd like to use until to loop until the task succeeds and store the output of each attempt to a separate log file on the local machine. Is there a good way to achieve this?
For example, my task currently looks like this:
- name: Provision
register: prov_ret
until: prov_ret is succeeded
retries: 2
command: provision_cmd
I can see how to store the log output from the last retry when it succeeds, but I'd like to store it from each retry. To store from the last attempt to run the command I use:
- name: Write Log
local_action: copy content={{ prov_ret | to_nice_json }} dest="/tmp/ansible_logs/provision.log"
It's not possible as of 2.9. The until loop doesn't preserve results as loop does. Once a task terminates all variables inside this task will be gone except the register one.
To see what's going on in the loop write a log inside the command at the remote host. For example, the command provision_cmd writes a log to /scratch/provision_cmd.log. Run it in the block and display the log in the rescue section.
- block:
- name: Provision
command: provision_cmd
register: prov_ret
until: prov_ret is succeeded
retries: 2
rescue:
- name: Display registered variable
debug:
var: prov_ret
- name: Read the log
slurp:
src: /scratch/provision_cmd.log
register: provision_cmd_log
- name: Display log
debug:
msg: "{{ msg.split('\n') }}"
vars:
msg: "{{ provision_cmd_log.content|b64decode }}"

Execute role in play based on a failure [duplicate]

I'm trying to spin up an AWS deployment environment in Ansible, and I want to make it so that if something fails along the way, Ansible tears down everything on AWS that has been spun up so far. I can't figure out how to get Ansible to throw an error within the role
For example:
<main.yml>
- hosts: localhost
connection: local
roles:
- make_ec2_role
- make_rds_role
- make_s3_role
2. Then I want it to run some code based on that error here.
<make_rds_role>
- name: "Make it"
- rds:
params: etc <-- 1. Let's say it fails in the middle here
I've tried:
- name: this command prints FAILED when it fails
command: /usr/bin/example-command -x -y -z
register: command_result
failed_when: "'FAILED' in command_result.stderr"
As well as other things on within the documentation, but what I really want is just a way to use something like the "block" and "rescue" commands , but as far as I can tell that only works within the same book and on plays, not roles. Does anyone have a good way to do this?
Wrap tasks inside your roles into block/rescue thing.
Make sure that rescue block has at least one task – this way Ansible will not mark the host as failed.
Like this:
- block:
- name: task 1
... # something bad may happen here
- name: task N
rescue:
- assert: # we need a dummy task here to prevent our host from being failed
that: ansible_failed_task is defined
Recent versions of Ansible register ansible_failed_task and ansible_failed_result when hit rescue block.
So you can do some post_tasks in your main.yml playbook like this:
post_tasks:
- debug:
msg: "Failed task: {{ ansible_failed_task }}, failed result: {{ ansible_failed_result }}"
when: ansible_failed_task is defined
But be warned that this trick will NOT prevent other roles from executing.
So in your example if make_rds_role fails ansible will apply make_s3_role and run your post_tasks afterwards.
If you need to prevent it, add some checking for ansible_failed_task fact in the beginning of each role or something.

Checking the status of Ansible processes

The machine I am targeting should, in theory, have a process running for each individual client called 'marketaccess {client_name}' and I want to ensure that this process is running. Ansible is proving very challenging for checking if processes are running. Below is the playbook I am trying to use to see if there is a process running on a given machine. I plan to then run a conditional on the 'stdout' and say that if it does not contain the customer's name then run a restart process script against that given customer. The issue is that when I run this playbook it tells me that the dictionary object has no attribute 'stdout' yet when I remove the '.stdout' it runs fine and I can clearly see the stdout value for service_status.
- name: Check if process for each client exists
shell: ps aux | grep {{ item.key|lower }}
ignore_errors: yes
changed_when: false
register: service_status
with_dict: "{{ customers }}"
- name: Report status of service
debug:
msg: "{{ service_status.stdout }}"
Your problem is that service_status is a result of a looped task, so it has service_status.results list which contains results for every iteration.
To see stdout for every iteration, you can use:
- name: Report status of service
debug:
msg: "{{ item.stdout }}"
with_items: "{{ service_status.results }}"
But you may want to read this note about idempotent shell tasks and rewrite your code with clean single task.

Ansible target specific host (not delegate_to)

There are 3 hosts in my play.
[machines]
MachineA
MachineB
MachineC
MongoDB runs on these servers. And one of these servers can be a MasterDB of Mongo.
So, each of these machines can be a 'Master'. This is determined by setting the fact if the machine is master, in this example only MachineA is targeted:
- name: check if master
shell: 'shell command to check if master'
set_fact: MasterHost="machineA"
when: 'shell command to check if master'.stdout == "true"
This is also done for MachineB and MachineC.
Mission to achieve: To run commands only on on the Master machine, which has the fact "MasterHost".
I tried the delegate_to module, but delegate_to also uses the two other machines:
- name: some task
copy: src=/tmp/test.txt dest=/tmp/test.txt
delegate_to: "{{ MasterHost }}"
I want to target the master it in my playbook and run only commands on the master, not in the shell via the --limit option.
Assuming the command run to check whether the host is the master or not is not costly, you can go without setting a specific fact:
- name: check if master
shell: 'shell command to check if master'
register: master_check
- name: some task
copy: src=/tmp/test.txt dest=/tmp/test.txt
when: master_check.stdout == "true"
Run the play on all hosts and only the one that is the master will run some task.
Eventually, this was my answer. Sorry for the first post, still learning how to make a good post. Hihi
- name: Check which host is master
shell: mongo --quiet --eval 'db.isMaster().ismaster'
register: mongoMaster
- name: Set fact for mongoMasterr
set_fact: MongoMasterHost="{{ item }}"
with_items: "{{ groups['HOSTS'] }}"
when: mongoMaster.stdout == "true"
- name: Copy local backup.tgz to master /var/lib/mongodb/backup
copy: src=/tmp/backup.tgz dest=/var/lib/backup/backup.tgz
when: mongoMaster.stdout == "true"
Thanks for helping and pointing me toward the right direction.

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