Printing the output of an async command in a loop - ansible

Below is a snippet from a playbook. How can I print a message after the command is run for each loop item. Something like.
image.pyc is now running for item1
image.pyc is now running for item2
...
and so on
- name: Image Server(s)
command: python3 image.pyc {{item}} "{{systemVersion}}"
register: async_out
async: 7200
poll: 0
with_items: "{{hostinfo_input.hosts}}"

In a nutshell, extremely simple, untested, to be adapted to your use case specifically in terms of error/output control:
- name: Image Server(s)
ansible.builtin.command: python3 image.pyc {{ item }} "{{ systemVersion }}"
register: async_out
async: 7200
poll: 0
with_items: "{{ hostinfo_input.hosts }}"
- name: Wait for commands to finish
ansible.builtin.async_status:
jid: "{{ item.ansible_job_id }}"
register: job_result
until: job_result.finished
retries: 720
delay: 10
loop: "{{ async_out.results }}"
- name: Show async command output
ansible.builtin.debug:
msg: "{{ item.stdout }}"
loop: "{{ async_out.results }}"
- name: Good guests always clean up after themselves
ansible.builtin.async_status:
jid: "{{ item.ansible_job_id }}"
mode: cleanup
loop: "{{ async_out.results }}"
References:
async in playbooks
async_status module
debug module
Registering variables with a loop

Have a look at Ansible documentation for the debug module: https://docs.ansible.com/ansible/latest/collections/ansible/builtin/debug_module.html
E.g.use it like this:
# playbook.yaml
---
- hosts: localhost
connection: local
vars:
ip_addresses:
- 10.0.0.10
- 10.0.0.11
tasks:
- name: Task
include_tasks: task.yaml
loop: "{{ ip_addresses }}"
# task.yaml
---
- name: Command
ansible.builtin.shell: "echo {{ item }}"
register: output
- name: Message
ansible.builtin.debug:
msg: |
- ip_address={{ item }}
- ouput={{ output }}
Unfortunately this does not work with async. See https://github.com/ansible/ansible/issues/22716.

Related

Ansible - loop over multiple items in stdout_lines

I am performing a grep with multiple items.
---
- hosts: my_host
gather_facts: false
vars:
my_list:
- whatever
- something
tasks:
- name: grep for item in search path
shell: "grep -rIL {{ item }} /tmp"
register: the_grep
loop: "{{ my_list }}"
- debug:
msg: "{{ item.stdout_lines }}"
loop: "{{ the_grep.results }}"
Depending on the result, multiple files could match.
msg:
- /tmp/something.conf
- /tmp/folder/file.txt
Q: How would I configure Ansible to loop over the items in stdout_lines?
The use case I'm solving is to delete .ini sections based on the item, but in this case, Ansible doesn't loop over the stdout_lines.
- name: remove stanza from ini file
ini_file:
path: "{{ item.stdout_lines }}"
section: "{{ item.item }}"
mode: '0600'
state: absent
loop: "{{ the_grep.results }}"
when: item.stdout_lines | length > 0
It seems that this doesn't work, but configuring item.stdout_lines[0] gives the partially expected result, since Ansible will use only the first item in that list. But ofc, not the 2nd and so on.
Perhaps there's a prettier answer, but solved it by using with_nested and creating a json_query:
- name: remove stanza from ini file
ini_file:
path: "{{ item.0 }}"
section: "{{ item.1.item }}"
mode: '0600'
state: absent
with_nested:
- "{{ the_grep | json_query('results[].stdout_lines[]') }}"
- "{{ the_grep.results }}"

Ansible loop through nested inventory lists

I'm trying to loop through a nested ansible inventory looks like this:
inventory:
group_one:
- name: 'entry-one-a'
description: 'one-a'
group_two:
- name: 'entry-two-aa'
description: 'two-aa'
group_three:
- name: 'entry-three-aaa'
description: 'three-aaa'
- name: 'entry-three-aab'
description: 'three-aab'
I've tried it with the following loop, but without success:
- name: print vars
ansible.builtin.debug:
msg: '{{ item }}'
loop: '{{ inventory.group_one.group_two|subelements("group_three") }}'
Any good idea how to loop through the inventory?
Iterate the third loop in the included task, e.g.
shell> cat group_three.yml
- debug:
msg: "{{ item.0.name }} {{ item.1.name }} {{ item2.name }}"
loop: "{{ item.1.group_three }}"
loop_control:
loop_var: item2
- include_tasks: group_three.yml
with_subelements:
- "{{ inventory.group_one }}"
- group_two
gives
msg: entry-one-a entry-two-aa entry-three-aaa
msg: entry-one-a entry-two-aa entry-three-aab

Looping in hostvars

I'm wondering if it is possible to perform a loop in the hostvars folder when using Ansible?
Here is what I've tried but haven't had success in making it work - or is it just not possible to do?
---
list_pool: 'list ltm pool {{ items }}'
with_items:
- 'abc123'
- 'def456'
I would use the "list_pool" variable in a playbook afterward:
- name: List pool
bigip_command:
server: "{{ some_server }}"
user: "{{ some_user }}"
password: "{{ some_password }}"
commands:
- "{{ list_pool }}"
validate_certs: no
delegate_to: localhost
Not sure what you mean when you say you want to loop over hostvars folder.
From what I can interpret from your tasks is: "You need to execute big-ip command list ltm <pool-name> for multiple pools in the list list_pool"
If that's what you're after, this should work:
- name: Set list_pool fact
set_fact:
list_pool: "{{ list_pool | default([]) + [item] }}"
with_items:
- 'abc123'
- 'def456'
- name: List pool
bigip_command:
server: "{{ some_server }}"
user: "{{ some_user }}"
password: "{{ some_password }}"
commands:
- "list ltm {{ item }}"
validate_certs: no
delegate_to: localhost
with_items: "{{ list_pool }}"
I got this working with the following solution:
hostvars file would look like this:
---
pre_checks:
checks:
pool:
- name: "pool_123"
- name: "pool_456"
...
And the play would look like this:
--output truncated---
- name: Fetch device host_vars
set_fact:
device_config: "{{ ((lookup('file','{{playbook_dir}}/host_vars/{{inventory_hostname}}.yml')) | from_yaml) }}"
- name: Check pool
bigip_command:
server: "{{ inventory_hostname }}"
user: "{{ remote_username }}"
password: "{{ remote_passwd }}"
commands:
- "list ltm pool {{ item }}"
validate_certs: no
with_items:
- "{{ device_config.pre_checks | json_query('checks.pool[*].name') }}"
delegate_to: localhost
when: "'active' in Active_LTM['stdout'][0]"
register: Pre_Checks
- name: Verify pool
debug: var=item
with_items: "{{ Pre_Checks.results | map(attribute='stdout_lines') | list }}"

how to get the exit status of the each task in ansible

I have 3 task in my ansible yml file as below.
---
- name: Instance provisioning
local_action:
module: ec2
region: "{{ vpc_region }}"
key_name: "{{ ec2_keypair }}"
instance_type: "{{ instance_type }}"
image: "{{ ec2_image}}"
zone: "{{ public_az }}"
volumes:
- device_name: "{{ device }}"
volume_type: "{{ instance_volumetype }}"
volume_size: "{{ volume }}"
delete_on_termination: "{{ state }}"
instance_tags:
Name: "{{ instance_name }}_{{ release_name }}_APACHE"
environment: "{{ env_type }}"
vpc_subnet_id: "{{ public_id }}"
assign_public_ip: "{{ public_ip_assign }}"
group_id: "{{ sg_apache }},{{ sg_internal }}"
wait: "{{ wait_type }}"
register: ec2
- name: adding group to inventory file
lineinfile:
dest: "/etc/ansible/hosts"
regexp: "^\\[{{ release_name }}\\]"
line: "[{{ release_name }}]"
state: present
- name: adding apache ip to hosts
lineinfile:
dest: "/etc/ansible/hosts"
line: "{{ item.private_ip }} name=apache dns={{ item.public_dns_name }}
with_items: ec2.instances
Now i want to check the exit status of each task whether it is success or failure.
If any one of the task fails my other task should not execute.
Please advice how to write an ansible playbook
In your first task, you have register the output to ec2.
now use fail module to stop the play if the task fails.
Ex.
register: ec2
fail:
when: "ec2.rc == 1"
here rc is the return code of the command .. we are assuming 1 for fail and 0 for success.
use fail module after every task.
Let me know if it works for you ..
Register a variable in each task and then check it in the next task. See http://docs.ansible.com/ansible/playbooks_tests.html#task-results
This is already the default behavior in Ansible. If a task fails, the Playbook aborts and reports the failure. You don't need to build in any extra functionality around this.
Maybe playbook blocks and it's error handling is to help you?
Kumar
if You want to check each task output if it is success or failure do this,
---
- name: Instance provisioning
local_action:
module: ec2
region: "{{ vpc_region }}"
key_name: "{{ ec2_keypair }}"
instance_type: "{{ instance_type }}"
image: "{{ ec2_image}}"
zone: "{{ public_az }}"
volumes:
- device_name: "{{ device }}"
volume_type: "{{ instance_volumetype }}"
volume_size: "{{ volume }}"
delete_on_termination: "{{ state }}"
instance_tags:
Name: "{{ instance_name }}_{{ release_name }}_APACHE"
environment: "{{ env_type }}"
vpc_subnet_id: "{{ public_id }}"
assign_public_ip: "{{ public_ip_assign }}"
group_id: "{{ sg_apache }},{{ sg_internal }}"
wait: "{{ wait_type }}"
register: ec2
- name: adding group to inventory file
lineinfile:
dest: "/etc/ansible/hosts"
regexp: "^\\[{{ release_name }}\\]"
line: "[{{ release_name }}]"
state: present
when: ec2 | changed
register: fileoutput
- name: adding apache ip to hosts
lineinfile:
dest: "/etc/ansible/hosts"
line: "{{ item.private_ip }} name=apache dns={{ item.public_dns_name }}
with_items: ec2.instances
when: fileoutput | changed
In your code register a variable in each and every Task if The Task has Changed to True, The Followed Task will execute otherwise it will skip that Task.

Ansible conditional handlers for a task?

FYI, I'm running my Ansible playbook in "pull-mode" not push mode. Therefore, my nodes will publish the results of their task via Hipchat.
With that said, I have a task that installs RPMs. When the installs are successful, the nodes notify via Hipchat that the task was successfully run. Now, in the event that a task fails, i force it to notify hipchat w/ the "--force-handlers" paramter. My question, is there a way to call a particular handler depending on the outcome of the task?
Task
- name: Install Perl modules
command: sudo rpm -Uvh {{ rpm_repository }}/{{ item.key }}-{{ item.value.svn_tag }}.rpm --force
with_dict: deploy_modules_perl
notify: announce_hipchat
Handler
- name: announce_hipchat
local_action: hipchat
from="deployment"
token={{ hipchat_auth_token }}
room={{ hipchat_room }}
msg="[{{ ansible_hostname }}] Successfully installed RPMs!"
validate_certs="no"
In this case, I use multiple handlers. See following example :
file site.yml
- hosts: all
gather_facts: false
force_handlers: true
vars:
- cmds:
echo: hello
eccho: hello
tasks:
- name: echo
command: "{{ item.key }} {{ item.value }}"
register: command_result
with_dict: "{{ cmds }}"
changed_when: true
failed_when: false
notify:
- "hipchat"
handlers:
- name: "hipchat"
command: "/bin/true"
notify:
- "hipchat_succeeded"
- "hipchat_failed"
- name: "hipchat_succeeded"
debug:
var: "{{ item }}"
with_items: "{{ command_result.results | selectattr('rc', 'equalto', 0) | list }}"
- name: "hipchat_failed"
debug:
var: "{{ item }}"
with_items: "{{ command_result.results | rejectattr('rc', 'equalto', 0) | list }}"
Use command
ansible-playbook -c local -i "localhost," site.yml
CAUTION: use test filter 'equalsto' added in jinja2 2.8

Resources