How to conditionally execute group of tasks on ansible? - ansible

I want to conditionally execute a set of tasks. Is there any syntax available that would let me execute a group of tasks, where the condition is evaluated once per whole group (like in a if statement in programming languages)?
Take a look at the code snippets below. I know the difference is small, but the first code better expresses my intention without polluting the namespace with additional variables (user_home_result2).
Pseudocode of what I want to do:
- name: Capturing user's home directory
shell: "getent passwd {{ user }} | awk -F: '{ print $6 }'"
register: user_home_result
- set_fact: user_home={{ user_home_result.stdout }}
- when: user_home != ''
- name: Setting up user {{ user }}
user: >
generate_ssh_key=yes
name="{{ user }}"
- name: Capturing user's home directory
shell: "getent passwd {{ user }} | awk -F: '{ print $6 }'"
register: user_home_result
- set_fact: user_home={{ user_home_result.stdout }}
Walkaround:
- name: Capturing user's home directory
shell: "getent passwd {{ user }} | awk -F: '{ print $6 }'"
register: user_home_result
- set_fact: user_home={{ user_home_result.stdout }}
- name: Setting up user {{ user }}
user: >
generate_ssh_key=yes
name="{{ user }}"
when: user_home != ''
- name: Capturing user's home directory
shell: "getent passwd {{ user }} | awk -F: '{ print $6 }'"
register: user_home_result2
when: user_home != ''
- set_fact: user_home={{ user_home_result2.stdout }}
when: user_home != ''

You can put the tasks in a new yml file and use a conditional include:
# subtasks.yml
---
- name: Setting up user {{ user }}
user: >
generate_ssh_key=yes
name="{{ user }}"
- name: Capturing user's home directory
shell: "getent passwd {{ user }} | awk -F: '{ print $6 }'"
register: user_home_result
- set_fact: user_home={{ user_home_result.stdout }}
And in the playbook:
- name: Capturing user's home directory
shell: "getent passwd {{ user }} | awk -F: '{ print $6 }'"
register: user_home_result
- set_fact: user_home={{ user_home_result.stdout }}
- include: subtask.yml
when: user_home != ''

As of version 2.1, ansible has blocks for logical task grouping. Blocks allow you to specify common things for a few tasks only once, including the when conditionals. Ex:
- block:
- name: put a file somewhere
copy: src=asdf dest=asdf
- name: put another file somewhere
template: src=asdf.j2 dest=asdf
when: bool_is_true
The above is equivalent to attaching a when: bool_is_true to both of the tasks inside the block.
More information at https://docs.ansible.com/ansible/latest/user_guide/playbooks_blocks.html

Related

copy multiple output stream to a file in ansible

I am pulling network switches interfaces information e.g. interface name, admin status, description etc. and parsing those values into a single .csv file but it seems like it is overwriting a file rather than appending a file, can you please let me know if I am doing something wrong here ? or there is better way to achieve this, here is my playbook.
---
- name: NXOS interfaces operation status
hosts: NXOS
connection: local
gather_facts: false
tasks:
- name: Discover NXOS interfaces
nxos_command:
commands:
- show run | grep ignore-case interface | exclude feature | exclude source | exclude destination | exclude logging
register: interface_names
- name: Get the interfaces stats
nxos_command:
commands:
# Full interface operational status
# - command: show interface {{ item.split(' ')[1] }}
# Interface name
- command: show interface {{ item.split(' ')[1] }} | head lines 1 | awk '{ print $1 }'
# Interface description
- command: show interface {{ item.split(' ')[1] }} | grep "Description"
# Interface operation status:
- command: show interface {{ item.split(' ')[1] }} | head lines 1 | awk '{ print $3}'
# Interface admin-status
- command: show interface {{ item.split(' ')[1] }} | grep "admin state" | awk '{ print $4 }'
# Interface MTU size
- command: show interface {{ item.split(' ')[1] }} | grep "MTU" | awk '{ print $2 }'
# Loop over the interfaces output from the previous task
loop: "{{ interface_names.stdout_lines[0] }}"
register: interfaces_stats
- name: Saving interfaces facts for NXOS
copy:
content: |
#jinja2: lstrip_blocks: True, trim_blocks: True
{{ inventory_hostname }}
Interface name,Interface description,Interface operational-status,Interface admin-status,Interface MTU size
{{ item.stdout_lines[0] }},{{ item.stdout_lines[1] }},{{ item.stdout_lines[2] }},{{ item.stdout_lines[3] }},{{ item.stdout_lines[4] }}
dest: /opt/ansible/vsansible/info/{{ inventory_hostname }}_info.csv
with_items:
- '{{ interfaces_stats.results }}'
here is the current output shows
Interface name,Interface description,Interface operational-status,Interface admin-status,Interface MTU size
[u'mgmt0'],[u'Description: -sw01-Gig0/39'],[u'up'],[u'up,'],1500
However, it should show me the output for every interface I am looking through in my first task.
please advice.

ansible: how do I display the output from a task that using with_items?

Ansible newbie here
Hopefully there is a simple solution to my problem
I'm trying to run SQL across a number of Oracle databases on one node. I generate a list of databases from ps -ef and use with_items to pass the dbname values.
My question is how do I display the output from each database running the select statement?
tasks:
- name: Exa check | find db instances
become: yes
become_user: oracle
shell: |
ps -ef|grep pmon|grep -v grep|grep -v ASM|awk '{ print $8 }'|cut -d '_' -f3
register: instance_list_output
changed_when: false
run_once: true
- shell: |
export ORAENV_ASK=NO; export ORACLE_SID={{ item }}; export ORACLE_HOME=/u01/app/oracle/database/12.1.0.2/dbhome_1; source /usr/local/bin/oraenv; $ORACLE_HOME/bin/sqlplus -s \"/ as sysdba\"<< EOSQL
select * from v\$instance;
EOSQL
with_items:
- "{{ instance_list_output.stdout_lines }}"
register: sqloutput
run_once: true
The loop below might work.
- debug:
msg: "{{ item.stdout }}"
loop: "{{ sqloutput.results }}"
If it does not take a look at the content of the variable and decide how to use it.
- debug: var=sqloutput

Use awk with ansible to run command

I have a playbook below:
- hosts: localhost
vars:
folderpath:
folder1/des
folder2/sdf
tasks:
- name: Create a symlink
shell: "echo {{folderpath}} | awk -F'/' '{system(\"mkdir \" $1$2 );}'"
register: result
#- debug:
# msg: "{{ result.stdout }}"
with_items:
- " {{folderpath}} "
However when I run the playbook I get 2 folders made. The first one is :
1- folder1des (as expected)
2- folder2 (this should ideally be folder2sdf )
I have tried many combination and still it doesnt want to work. What do I need to have it work properly.
I do not have ansible environment at the moment. But following should work:
- hosts: localhost
tasks:
- name: Create a symlink
shell: "echo {{item}} | awk -F'/' '{system(\"mkdir \" $1$2 );}'"
register: result
#- debug:
# msg: "{{ result.stdout }}"
with_items:
- folder1/des
- folder2/sdf
Reference: Ansible Loops Example
Explanation:
You were adding a single list object to the with_items. so in your with_items it finds only one object (which is of type list) to iterate over. Hence it runs only once. So now what I have done is I have passed a list of items to with_items that way it can iterate over the multiple items present in with_items.
Hope this helps!
Maybe
- hosts: localhost
vars:
folderpath:
folder1/des
folder2/sdf
tasks:
- name: Create a symlink
file:
state : link
path : "{{ item | regex_replace('[0-9]/','_') }}"
src : "{{ item }}"
with_items: " {{ folderpath }} "
Nothing in your given code creates symlinks. Is that really what you meant to do?

Ansible - using {{ item }} with csvfile lookups

I'm trying to work out a way to cut down on lines of code for various modules, repeating stanzas seems pointless. I'd like to use csvfile lookups to help fill in blanks. Take for example the following CSV:
# groups.csv
# name, gid [optional - leave blank], state [present|absent], system [yes|no]
accounts,502,present,no
engineering,504,present,no
So, I have all my group definitions in csv format. The problem is, processing it, no matter what I try I cannot get lookups to work inside the groups module.
So initially, I wanted to do this:
---
- hosts: localhost
become: True
become_user: root
tasks:
- name: get groups
command: /usr/bin/awk -F',' '!/^#/ && !/^$/ { print $1 }' groups.csv
register: groups_out
- debug: var=groups_out.stdout_lines
- name: Process groups
group: >
name="{{ lookup('csvfile', 'item file=groups.csv col=0') }}"
gid="{{ lookup('csvfile', 'item file=groups.csv col=1') }}"
state="{{ lookup('csvfile', 'item file=groups.csv col=2') }}"
system="{{ lookup('csvfile', 'item file=groups.csv col=3') }}"
# with_lines: "/usr/bin/awk -F',' '!/^#/ && !/^$/ { print $1 }' groups.csv"
# with_items: "{{ groups_out.stdout_lines }}"
with_lines: "{{ groups_out.stdout_lines }}"
The result of which is this:
TASK [Process groups] **********************************************************
/bin/sh: accounts: command not found
fatal: [localhost]: FAILED! => {"failed": true, "msg": "lookup_plugin.lines(accounts) returned 127"}
As you can see from the code, I've also tried using with_items and with_lines using the awk command directly, however it appears the groups module doesn't like me doing this.
Ansible 2.1.1.0 on Centos 7.
Python 2.7.5
Jinja 2.8
Any ideas how I might achieve this?
Thanks in advance,
R
Answer below. Thanks to Jon and Kai on the ansible-project googlegroup for their assistance.
---
- hosts: localhost
become: True
become_user: root
tasks:
- name: get groups
command: /usr/bin/awk -F',' '!/^#/ && !/^$/ { print $1 }' /var/tmp/groups.csv
register: groups_out
- name: Process groups one
group: >
name={{ lookup('csvfile', item + ' file=groups.csv col=0 delimiter=,') }}
gid={{ lookup('csvfile', item + ' file=groups.csv col=1 delimiter=,') }}
state={{ lookup('csvfile', item + ' file=groups.csv col=2 delimiter=,') }}
system={{ lookup('csvfile', item + ' file=groups.csv col=3 delimiter=,') }}
with_items: "{{ groups_out.stdout_lines }}"
ignore_errors: True
- name: Process groups two
group: >
name={{ lookup('csvfile', item + ' file=groups.csv col=0 delimiter=,') }}
gid={{ lookup('csvfile', item + ' file=groups.csv col=1 delimiter=,') }}
state={{ lookup('csvfile', item + ' file=groups.csv col=2 delimiter=,') }}
system={{ lookup('csvfile', item + ' file=groups.csv col=3 delimiter=,') }}
with_lines: /usr/bin/awk -F',' '!/^#/ && !/^$/ { print $1 }' /var/tmp/groups.csv

complex loop in ansible with_together

How do I skip empty item in list if I use with_together?
see the code below:
- name: get data_files list
shell: ls -l data_files | awk -F " " {'print $9'}
register: csv_file_list
- debug: var=csv_file_list
- name: get table name list
shell: ls -l data_files/ | awk -F " " {'print $9'} | sed -e "s/.csv//g" | sed -e "s/-/./g"
register: table_list
- debug: var=table_list
- name: copy table from csv to demo db
shell: psql -U postgres -d demo -c "\copy {{ item.1 }} from /home/ubuntu/data_files/{{ item.0 }} DELIMITER ',' CSV HEADER"
with_together:
- csv_file_list.stdout_lines
- table_list.stdout_lines
when: {{ item.1 }} != ''
Test if item.1 is not none.
when: item.1 != None

Resources