VOOZH about

URL: https://www.tecmint.com/create-ansible-plays-and-playbooks/

⇱ How to Create Ansible Plays and Playbooks - Part 5


Skip to content

In this Part 5 of Ansible Series, we will explain how to create Ansible Plays and Playbooks using Ansible modules.

Ansible ships with standalone scripts called modules that are used in playbooks for the execution of specialized tasks on remote nodes.

Modules come in handy for automating tasks such as package management, archiving and copying files to mention just a few. They allow you to make tweaks on configuration files and manage devices such as routers, switches, load balancers, firewalls and a host of other devices.

The objective of this subtopic is to give you an overview of various tasks that can be accomplished by Ansible modules:

Package Management in Linux

Package management is one of the most essential and frequent tasks carried by systems administrators. Ansible ships with modules that help you execute package management tasks both in RedHat and Debian based systems.

They are relatively easy to guess. There is the apt module for APT package management for Debian based, the old yum module for YUM package management and dnf module associated with newer RHEL distributions.

Below are a few examples of how the modules can be used in a playbook:

Example 1: Installing the Apache Webserver on RHEL 8

---
- name: install Apache webserver
 hosts: webservers

 tasks:
 - name: install httpd
 dnf: 
 name: httpd 
 State: latest

Example 2: Installing the Apache Webserver on Debian 10

---
- name: install Apache webserver
 hosts: databases

 tasks:
 - name: install Apache webserver
 apt: 
 name: apache2 
 State: latest

Service Module

The service module allows system administrators to start, stop, update, upgrade and reload services on the system.

Example 1: Starting Apache Webserver

---
- name: Start service httpd, if not started
 service:
 name: httpd
 state: started

Example 2: Stopping Apache Webserver

---
- name: Stop service httpd
 service:
 name: httpd
 state: stopped

Example 3: Restarting a Network Interface enp2s0

---
- name: Restart network service for interface eth0
 service:
 name: network
 state: restarted
 args: enp2s0

Copy Module

As the name suggests, copy module copies files from one location on the remote machine to a different location on the same machine.

Example 1: Copying Files from Local to Remote Linux

---
- name: Copy file with owner and permissions
 copy:
 src: /etc/files/tecmint.conf
 dest: /srv/tecmint.conf
 owner: tecmint
 group: tecmint
 mode: '0644'

The playbook copies the config file tecmint.conf from /etc/files/ directory to /srv/ directory as tecmint user with 0644 permissions.

Permissions can also be represented using symbolic representation as shown in the last line.

Example 2: Copying Files from Local to Remote Linux

---
- name: Copy file with owner and permissions
 copy:
 src: /etc/files/tecmint.conf
 dest: /srv/tecmint.conf
 owner: tecmint
 group: tecmint
 mode: u=rw, g=r, o=r

The permissions in the previous example can be represented as shown in the last line, The user is assigned read and write permissions, the group is assigned write permissions, and the rest of the world is assigned read permissions.

File Module

The file module is used to carry many file operations including creating files & directories, assigning file permissions, and setting symlinks.

Example 1: Perform Linux File Permissions

---
- name: Change file ownership, group, and permissions
 file:
 path: /etc/tecmint.conf
 owner: tecmint
 group: tecmint
 mode: '0644'

The above play creates a file called tecmint.conf in the /etc directory setting permissions to 0644.

Example 2: Delete Linux File

---
- name: Remove file (delete file)
 file:
 path: /etc/tecmint.conf
 state: absent

This removes or deletes the file tecmint.conf.

Example 3: Create a Directory

---
- name: create a directory if it doesn’t exist
 file:
 path: /etc/mydirectory
 State: directory
 mode: '0777'

This will create a directory in the /etc directory setting permissions to 0777.

Example 4: Recursiverly Delete a Directory

---
- name: Recursively deleting a directory
 file:
 path: /etc/tecmint.conf
 state: absent

The above play recursively deletes a directory.

Lineinfile Module

The lineinfile module is helpful when you want to change a single line in a file. It can replace an existing line.

Example 1: Manipulate Files in Linux

---
 - name: Ensure SELinux is set to enforcing mode
 lineinfile:
 path: /etc/selinux/config
 regexp: '^SELINUX='
 line: SELINUX=disabled

The play above sets SELINUX value to disabled.

SELINUX=disabled

Example 2: Alter Files in Linux

---
- name: Add a line to a file if the file does not exist, without passing regexp
 lineinfile:
 path: /etc/hosts
 line: 10.200.50.51 tecmint.com
 create: yes

This adds the entry 10.200.50.51 tecmint.com to the /etc/hosts file.

Archive Module

An Archive module is used for the creation of a compressed archive of a single or multiple files. It assumes the compression source exists is present on the target destination. After archival, the source file can later be deleted or removed using the statement remove=True.

Example 1: Create a Archive File

- name: Compress directory /path/to/tecmint_dir/ into /path/to/tecmint.tgz
 archive:
 path: /path/to/tecmint_dir
 dest: /path/to/tecmint.tgz

This compresses the /path/to/tecmint_dir directory to /path/to/tecmint.tgz

Example 2: Create a Archive File and Remove

- name: Compress regular file /path/to/tecmint into /path/to/foo.gz and remove it
 archive:
 path: /path/to/tecmint
 dest: /path/to/tecmint.tgz
 remove: yes

In the above play, the source file /path/to/tecmint is deleted after the archival is complete.

Example 3: Create a Archive File

- name: Create a bz2 archive of /path/to/tecmint
 archive:
 path: /path/to/tecmint
 format: bz2

This creates a compressed file in bz2 format from the /path/to/tecmint file.

Git Module

The module manages git checkouts of software repositories.

Example 1: Check Git Repositoires

- git:
 repo: 'https://foosball.example.org/path/to/repo.git'
 dest: /srv/checkout
 version: release-0.22

Command Module

One of the most commonly used modules, the command module takes the command name and later followed by a list of arguments. The command is a passed the same way that you’d type in a Linux shell.

Example 1: Run a Command

- name: Executing a command using the command module
 command: cat helloworld.txt

Example 2: Check Uptime of Remote Linux

---
 - name: Check the remote host uptime
 hosts: servers
 tasks:
 - name: Execute the Uptime command over Command module
 register: uptimeoutput
 command: "uptime"

- debug:
 var: uptimeoutput.stdout_lines

The command module retrieves the uptime of remote servers.

Variables to Retrieve the Results of Running Commands

Usually, Ansible playbooks are used to execute tasks on managed hosts without displaying the output on the command line. There are instances, however, that you may be required to capture the output or results. In this section, we walk you through how you can capture the output of a playbook in a variable and later display it.

An ansible register is used for capturing a task’s output and save it a variable. The variable will thereafter contain the stdout of the task.

For instance, let us assume that you want to check disk usage of managed nodes in respective root directories using the df -Th / command. You are going to use the ‘command’ module to define the command and ‘register’ to save the std output in a variable.

To display the command, you will use the ‘debug’ module alongside the stdout return value.

---

 - hosts: all
 become: yes

 tasks:
 - name: Execute /boot usage on Hosts
 command: 'df -Th /'
 register: df

 - debug: var=df.stdout

Now, let’s run the playbook. In this case, we have named our playbook check_disk_space.yml.

# ansible-playbook check_disk_space.yml
👁 check disk usage of Ansible managed nodes
check disk usage of Ansible managed nodes

As you have seen, the output is all jumbled up and makes it difficult to follow along.

To align the output and make it easier to read, replace the stdout return value with stdout_lines.

---

 - hosts: all
 become: yes

 tasks:
 - name: Execute /boot usage on Hosts
 command: 'df -Th /'
 register: df

 - debug: var=df.stdout_lines

Use Conditionals to Control Play Execution

Just like in programming languages, conditional statements are used when more than one outcome is possible. Let’s have a look at some of the commonly used conditional statements in Ansible playbooks.

When statement

Sometimes, you may want to perform tasks on specific nodes and not others. The 'when' conditional statement is quite easy to use and implement in a playbook. When using the 'when' clause simply declare the condition adjacent to the clause as shown:

when: condition

When the condition is satisfied, then the task is performed on the remote system.

Let’s check out a few examples:

Example 1: Using When Operator

---
- hosts: all

 tasks:
 - name: Install Nginx on Debian
 apt: name=nginx state=present
 when: ansible_os_family == “Debian”

The play above installs Nginx webserver on hosts running the Debian family of distros.

You can also use the OR and AND operator alongside the when the conditional statement.

Example 2: Using AND Operator with When

---
- hosts: all

 tasks:
 - name: Install Nginx on Debian
 apt: name=nginx state=present
 when: ansible_os_family == “Debian” and
 ansible_distribution_version == “18.04”

When using the AND operator, both statements must be satisfied for the task to be executed.

The play above installs Nginx on Nodes running a Debian family of OS which is version 18.04. Obviously, this will be Ubuntu 18.04.

Example 3: Using OR Operator with When

With OR operator, the task is executed if either of the conditions is fulfilled.

---
- hosts: all

 tasks:
 - name: Install Nginx on Debian
 apt: name=nginx state=present
 when: ansible_os_family == “Debian” or
	 Ansible_os_family == “SUSE”

The play above installs Nginx webservers on either Debian or SUSE family of OS or both of them.

NOTE: Always ensure to use the double equality sign == when testing a condition.

Conditionals in loops

Conditionals can also be used in a loop. Say for instance you have a list of multiple packages that need to be installed on remote nodes.

In the playbook below, we have an array called packages containing a list of packages that need to be installed. These tasks will be carried out one after the other if the required clause is set to True.

---
 - name: Install Software packages
 hosts: all
 vars:
	packages:
 • name: nginx
required: True
 • name: mysql
required: True
 • name: apache
required: False



 tasks:
 • name: Install “{{ item.name }}”on Debian
apt: 
 name: “{{ item.name }}”
 state: present 
When: item.required == True
loop: “{{ packages }}” 

Configure Error Handling

Sometimes, tasks fail when running playbooks. Let’s assume you are running 5 tasks on 3 servers as shown in the playbook below. If an error occurs on task 3 (Starting MySQL) on server 2, Ansible will stop executing the remaining tasks on server 2 and attempt to complete the remaining tasks on the rest of the servers.

---
 - name: Install Software packages
 hosts: server1, server2, server3
 tasks:
- name: Install dependencies
<< some code >>

- name: Install MySQL database
<< some code >>

- name: Start MySQL
<< some code >>

- name: Install Nginx
<< some code >>

- name: Start Nginx
<< some code >>

If you want consistency in the execution of the playbook, for example, stop the execution of a playbook, should one of the servers fail, add the option.

---
 - name: Install Software packages
 hosts: server1, server2, server3
 any_errors_fatal: true
 tasks:

This way, if one task fails on one server, Ansible will stop the execution of the entire playbook on all the servers and exit.

If you would like the playbook to ignore the errors and proceed to execute the remaining set of tasks, then use the ignore_errors: True option.

---
 - name: Install Software packages
 hosts: server1, server2, server3
 tasks:
- name: Install dependencies
<< some code >>
  ignore_errors: True

Create Playbooks to Configure Systems to a Specified State

In this section, we look at some additional options that are available when running a playbook.

Let’s begin with the Check mode or Dry run option. The dry run or check mode option is used when running a playbook to check if any errors will be encountered and if there are any changes that will be made on the managed hosts. It, however, does not make any changes to the remote nodes.

For example, to dry run a playbook called httpd.yml that installs and starts the Apache webserver run:

# ansible-playbook httpd.yml --check
👁 dry run a Ansible playbook
dry run a Ansible playbook

The other option we need to look at is the --start-at-task option. This is used when specifying the name of the task that the playbook should begin or start at.

Let’s take an example: The playbook below spells out 2 tasks: The first play installs Apache web server and the second installs htop utility.

---
 - name: Install httpd

 hosts: all
 tasks:
 yum:	 
name: httpd
 state: Installed

- name: Install htop

 yum: 
 name: htop
 state: started

If you want to skip installing Apache webserver and instead install htop utility run:

# ansible-playbook playbook.yml --start-at-task “Install htop”
👁 Install Packages using Ansible Playbook
Install Packages using Ansible Playbook

Lastly, you can tag your tasks or plays by adding the tags option to your playbook as shown. This comes in handy when you have quite a large playbook and you want to run specific tasks from the entire playbook.

---
 - name: Install httpd
 tags: Install and start
 hosts: all
 tasks:
 yum:	 
name: httpd
 state: Installed

 tags: Install

 • service: 
name: httpd
state: started
# ansible-playbook playbook.yml -tags "Install"

To omit the tags use the --skip-tags options as shown.

# ansible-playbook playbook.yml --skip-tags "Install"
Conclusion

In this topic, we took you through the commonly used modules in Ansible, how to retrieve stdout from the execution of a playbook for analysis, using conditionals in the playbook and how to manage errors that may occur when running tasks. Lastly, we recapped the configuration of playbooks and how you can use additional options to decide which tasks to run if you do not intend to run the entire playbook.

If this article helped, share it with someone on your team.
TecMint Weekly Newsletter
Get the Learn Linux 7 Days Crash Course free when you join 34,000+ Linux professionals reading every Thursday.
Check your email for a magic link to get started.
Something went wrong. Please try again.
TecMint has been free for 14 years. Help keep it that way.
Google AI Overviews and tools like ChatGPT have cut into search traffic for independent tech sites like TecMint. Running this site costs over $2,000 every month for hosting, infrastructure, and paying authors to keep the content accurate and tested.

If this article helped you solve a problem, consider buying a coffee. It helps keep TecMint free, supports the authors, and keeps the project going.
☕ Buy Me a Coffee
James Kiarie
This is James, a certified Linux administrator and a tech enthusiast who loves keeping in touch with emerging trends in the tech world. When I'm not running commands on the terminal, I'm taking listening to some cool music. taking a casual stroll or watching a nice movie.

Each tutorial at TecMint is created by a team of experienced Linux system administrators so that it meets our high-quality standards.

2 Comments

Leave a Reply
  1. Hello, This code doesn’t seem to work as-is. I thought you might like to know.

    Example 2: Check Uptime of Remote Linux

    ---
     - name: Check the remote host uptime
     hosts: servers
     tasks:
     - name: Execute the Uptime command over Command module
     register: uptimeoutput
     command: "uptime"
    
    - debug:
     var: uptimeoutput.stdout_lines
    
    Reply
    • Hey Craig,

      The indentation of the debug module should be the same as that of the “- name” parameter. They should appear in the same vertical alignment. Please check on that.

      Reply

Got Something to Say? Join the Discussion... Cancel reply

Free Course
Get a free Linux course before you go.
Subscribe to TecMint Weekly and get the Learn Linux 7 Days Crash Course free. Read by 34,000+ Linux professionals every Thursday.
Check your email for a magic link to get started.