10 Things you should start using in your Ansible Playbook

I have been working a lot on Ansible these days as we are working on migrating all our org. level Windows deployments from present tool to Ansible. We wrote many custom roles to support windows deployments and came through many interesting Ansible features. Out of many features I decided to share 10 interesting things that you should start using in your Ansible Playbook. I hope you will like these features and start using it in your day to day playbooks. So, Let’s start with the features.

1. with_items:

Sometimes we want to do many things with single tasks like installing many packages with the same tasks just by changing the arguments. This can be achieved using the with_items clause.

# Installing packages individually ( Slower Process )- name: Installing Git
apt:
name: git
update_cache: yes
- name: Installing nginx
apt:
name: nginx
update_cache: yes
- name: Installing memcached
apt:
name: memcached
update_cache: yes
# Installing Packages with one Task ( Faster Process )- name: Installing Packages
apt:
name: "{{ item }}"
update_cache: yes
with_items:
- git
- nginx
- memcached

2. Facts Gathering

In Ansible, Facts are nothing but information that we derive from speaking with the remote system. Ansible uses setup module to discover this information automatically. Sometime this information is required in playbook as this is dynamic information fetched from remote systems.

192.168.56.7 | SUCCESS => {
"ansible_facts": {
"ansible_all_ipv4_addresses": [
"172.17.0.1",
"10.0.2.15",
"192.168.56.7"
],
( many more facts)...
---- hosts: web
gather_facts: False
- hosts: web
gather_facts: True
gather_subset: network
- hosts: web
gather_facts: True
gather_subset: network,virtual
[general]
sample_value=1
sample_fact=normal
ansible all -i local -m setup -a "filter=ansible_local"
192.168.56.7 | SUCCESS => {
"ansible_facts": {
"ansible_local": {
"prefrences": {
"general": {
"sample_fact": "normal",
"sample_value": "1"
}
}
}
},
"changed": false,
"failed": false
}

3. any_errors_fatal

Sometime it is desired to abort the entire play on failure of any task on any host. This can be helpful in a scenario where you are deploying any service on group of hosts and if any failure occurred on any server should fail the entire play because we don’t want the deployments to be partial on any server.

---
- hosts: web
any_errors_fatal: true

4. max_fail_percentage

Ansible is designed in such a way that it will continue to execute the playbook until and unless there are any hosts in the group that are not yet failed. Sometimes it becomes issue while doing deployments because its not maintaining consistency. Consider scenario’s where you have 100+ servers attached to load balancer and you are targeting for zero downtime with rolling updates. As Ansible supports rolling updates and you can define the batch size( Batch size is nothing but the number of servers you want to target for deployment in rolling updates, you can also provide %), you have to monitor these deployments for failure and take decision when to call it off. max_fail_percentage allows you to abort the play if certain threshold of failures have been reached.

---
- hosts: web
max_fail_percentage: 30
serial: 30

5. run_once

There are condition where we have to write our playbook in such a way that will run some tasks or perform some action only on single host from group. If you are thinking of Handlers do the same thing. Think twice because even though multiple tasks notify to perform some action, handlers will only gets executed after all tasks completed in play but on all hosts and not on single.

---
- hosts: web
tasks:
- name: Initiating Database
script: initalize_wp_database.sh
run_once: true

6. Ansible Vault

There are scenarios where we have to keep sensitives information in playbook, like database username and password. Keeping such sensitive information open is not a good idea as we are going to keep our playbook in version control system. To Keep such information, Ansible provided Vault to store such information in encrypted format.

ansible-vault create encryptme.yml
ansible-vault encrypt filename.yml
ansible-vault --new-vault-id dev --new-vault-password-file=development encrypt dev_config.yml
ansible-vault --new-vault-id prod --new-vault-password-file=production encrypt prod_config.yml
ansible-vault --vault-id prod@prompt decrypt prod_config.yml

7. No_logs

In previous section, we covered how we can encrypt the data using Ansible Vault and share it publicly. But this encrypted data is exposed when we run the playbook in -v(verbose) mode. Anyone who has access to controller machine or Ansible Tower jobs, they can easily identify the encrypted data by running the playbook in verbose mode.

Playbook ran with verbose mode to show how encrypted data can be seen.
---
- hosts: web
tasks:
- include_vars: group_vars/encrypted_data.yml
no_log: true
- name: Printing encrypted variable
debug:
var: vault_db_password
no_log: true

8. tags

Sometimes while writing the playbook we never think about dividing the playbook logically and we end up with a long playbook. But what if we can divide the long playbook into logical units. We can achieve this with tags, which divides the playbook into logical sections.

---
- hosts: web

tasks:
- name: Installing git package
apt:
package: git
tags:
- package
- name: Running db setup command
command: setupdb.sh
tags:
- dbsetup
ansible-playbook -i local site.yml --tags package
ansible-playbook -i local site.yml --skip-tags package
ansible-playbook -i local site.yml --skip-tags always

9. command module idempotent (optional)

As we know that all modules are idempotent, which means if we are running a module multiple times should have the same affect as running it just once. To implement idempotency, you have to check module whether its desired state has been achieved or not. If its already achieved then just exit or else perform the action specified. Mostly all Ansible modules are idempotent but there are few modules which are not. Command and Shell modules of Ansible are not idempotent. But there are ways to make them idempotent. Let’s see how we can make them idempotent.

tasks:- name: Running command if file not present
command: setup_db.sh
args:
creates: /opt/database

10. Debugging Playbook on Run

Debugging an ansible playbook is one of the coolest feature that ansible has introduced(in 2.1 version). While we develop any playbook sometimes we see failures and to debug we usually run the playbook again, identify the error that Ansible throws and modify the playbook and then rerun the playbook. What if your playbook takes 30 minutes to run and your play is failing for last few tasks and after debugging you will again run your playbook for almost 30 minutes. I guess that’s ideal way to debug, You can used the ansible debug strategy.

---
- hosts: web
strategy: debug
tasks: ...
---
- hosts: web
strategy: debug
vars:
package: "nginx"
tasks:
- name: Install Git Package
apt:
name: "{{ new_package }}"
Video showing demo of how you can use debug for above playbook

Conclusion:

So these are the few things that you should start using in your day to day ansible playbook. Hope you liked it.

DevOps Consultant, ALM Consultant, CloudOps Consultant