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:

By using the with_items, ansible creates a temporary variable called {{item}} which consist the value for the current iteration. Let’s have some example to understand this. We will install few packages with below playbook.

# 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

The above playbook will run 3 tasks each for installing individual package. Rather than specifying three different tasks, we can use with_items and specify the list of packages that we need to install.

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

Here, while executing the task “Installing packages” Ansible will read the list from with_items and install packages one by one. You can also use with_items with roles as well. So if you have any custom role defined and you want to execute that role multiple times, rather than defining it multiple times you can use with_items and just pass your elements.

2. Facts Gathering

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

It becomes a time consuming process in Ansible as it has to gather information from all the hosts listed in your inventory file. We can avoid this situation and speed up our play execution by specifying gathering_facts to false in playbook.

---- hosts: web
gather_facts: False

We can also filter the facts gathering to save some time.This case is mainly useful when you want only hardware or network information that you want to use in your playbook. So rather than asking for all facts, we can minimize this by only asking network or hardware facts to save some time. To do this, you have to keep gather_facts to True and also pass one more attribute named gather_subset to fetch specific remote information. Ansible supports network, hardware, virtual, facter, ohai as subset. To specify subset in your playbook you have to follow the below example.

- hosts: web
gather_facts: True
gather_subset: network

To specify multiple subsets , you can combine then using comma (ex. network, virtual)

- hosts: web
gather_facts: True
gather_subset: network,virtual

Sometimes there might be requirement for creating local custom facts on remote machines. This can be achieved by creating .fact file under /etc/ansible/facts.d/ location on remote machine. The .fact file can have JSON, INI or executable file returning JSON. For example, I have created a file called local.fact under /etc/ansible/facts.d/local.fact and defined with following value.

[general]
sample_value=1
sample_fact=normal

By default, you will get these facts whenever you gather fact on the remote server you defined this. If you want to filter the facts, you can use the below command.

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

---
- hosts: web
any_errors_fatal: true

The any_error_fatal option will mark all the hosts as failed if fails and immediately abort the playbook execution.

4. max_fail_percentage

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

If 30 of the servers to fail out of 100. Ansible will abort the rest of the play.

5. run_once

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

To achieve this, Ansible provided run_once module, which will run only on single host from group of hosts. By default, Ansible will select the first host from the group to execute. This can also be used with delegate_to to run the task on specific server. When executed with serial, task marked as run_once gets executed on one host from each batch.

6. Ansible Vault

Ansible Vault can be used to encrypt binary files, group_vars, host_vars, include_vars and var_files. Ansible vault can be used with command line tool named ansible-vault.You can create encrypted file using following command.

ansible-vault create encryptme.yml

If you are running this command for first time, it will ask you for setting vault password. Later you have to provide the same while running ansible-playbook command using--ask-vault-pass.

To encrypt any file, you can use the following command

ansible-vault encrypt filename.yml

This will encrypt all your content and can only be decrypted using vault password.

Since Ansible 2.4 you can have multiple vault passwords. The reason for allowing multiple passwords is because you cannot encrypt dev and prod passwords using single vault password. The passwords for environments dev will be different, than prod environment. Now, if anyone who has dev vault password would not be able to decrypt prod password which makes it more secure. The Vault credentials are encrypted through vault-id. Please follow below examples for creating multiple vault passwords.

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

The vault-id is used for decrypting the passwords. The vault-id dev is used to encrypt dev_config.yml whereas vault-id prod is used to encrypt prod_config.yml. To decrypt, we use the following command.

ansible-vault --vault-id prod@prompt decrypt prod_config.yml

This command will ask vault password for vault-id prod.

7. No_logs

Playbook ran with verbose mode to show how encrypted data can be seen.

In above screenshot, you can see that the encrypted data is exposed in ansible_facts. To secure or censor such information, Ansible has provide a keyword named no_log which you can set to true to keep any task’s information censored.

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

This way you can keep verbose output but hide sensitive information from others. This can also be applied to play but it becomes difficult for debug and not recommended.

Note that when debugging Ansible with ANSIBLE_DEBUG, the no_logs cannot stop ansible from showing the information.

8. tags

Ansible Tags are supported by tasks and play. You can use tags keyword and provide any tag to task or play. Tags are inherited down to the dependency chain which means that if you applied the tags to a role or play, all tasks associated under that will also get the same tag.

---
- hosts: web

tasks:
- name: Installing git package
apt:
package: git
tags:
- package
- name: Running db setup command
command: setupdb.sh
tags:
- dbsetup

To run your playbook with specific tag, you have to provide command line attribute --tags and name of your tag.

ansible-playbook -i local site.yml --tags package

Above command will run tasks which are tagged as package and skip all other tasks. Sometimes you have to play complete playbook and skip some part. This can be achieved with--skip-tag attribute.

ansible-playbook -i local site.yml --skip-tags package

The above command will run all tasks and skip tasks tagged with package.If you want to list all tags, that can be done with--list-tag attribute.

Ansible also provided some special tags as always, tagged, untagged and all.

ansible-playbook -i local site.yml --skip-tags always

By default , ansible runs with--tags all which will execute all tasks.

9. command module idempotent (optional)

Command module runs same command again and again. To make it idempotent we can use the attribute create or remove. When used with create attribute, Ansible will only run the command task if the file specified by the pattern does not exists. Alternatively you could use remove, which will only execute the task if the file specified exists.

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

As Ansible supports idempotent, make sure you use all such modules in your playbook to make your play idempotent so that re-running should be safe.

10. Debugging Playbook on Run

Ansible provides a debug strategy which will help to enable the debugger when a task fails. It will provide access to all features of the debugger in the context of failed task. This way if you encounter a failed task, you can set the values of the variables, update the module arguments and re-run the failed task with new arguments and variables.

To use the debug strategy in your playbook, you have to define the strategy as debug.

---
- hosts: web
strategy: debug
tasks: ...

With Debugger, it provides multiple commands to debug your failed tasks.

P task/host/result/vars ->Prints the value to executed a module

task.args[key] = value — upgrade the module arguments

vars[args]=value — set argument value

r(edo) — run the task again

c(continue) — Just continue

q(uit) — quit from debugger

Let’s run the following playbook to demonstrate this feature.

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

Note: the debugger doesn’t work with debug module, so if you have any undefined variables it will not work.

Conclusion:

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store