← All articles
AutomationFeb 11, 202316 min read

Ansible Automation — 2

Ansible commands can be implemented in several ways, including:

Running Ansible commands from the command line: This is the most basic and straightforward way to run Ansible commands. You can use the ansible or ansible-playbook commands to run ad-hoc tasks or playbooks, respectively, from the command line. Using playbooks: Playbooks are Ansible's configuration, deployment, and orchestration language. They are written in YAML and describe a series of tasks that should be executed on target hosts. Playbooks can be run from the command line using the ansible-playbook command. Using modules: Ansible modules are pre-written scripts that perform specific tasks on target hosts. Modules can be called from the command line using the ansible command, or from playbooks using the module keyword. Using roles: Roles are a way to organize and reuse playbooks and modules. They allow you to package playbooks and modules into a self-contained unit that can be easily shared and reused. Roles can be run from playbooks using the include_role keyword. Using dynamic inventories: Dynamic inventories are scripts that dynamically generate the list of target hosts based on the current environment. They allow you to manage large and changing infrastructure without having to manually update the inventory file. Dynamic inventories can be used in Ansible by setting the ansible_inventory environment variable.

Adhoc Commands

Ad-hoc commands are one-off tasks that you can run on target hosts using Ansible. They are useful for running simple commands, making changes to a single host, or testing your configuration.

To run an ad-hoc command using Ansible, you can use the ansible command followed by the target host or group of hosts, the desired module, and any arguments or options.

For example, the following command will run the ping module on all hosts in the webservers group:

ansible webservers -m ping

The following command will run the shell module and execute the ls command on the host web1:

ansible web1 -m shell -a 'ls'
or
ansible web1 -a 'ls'

Ad-hoc commands are a flexible and simple way to run tasks in Ansible. However, they are limited in terms of organization, scaling, and repeatability, and for more complex or automated tasks, you may want to use playbooks instead.

Here are the some sample examples given below with syntax:

$ ansible <host> -b -m <module> -a <arbituary options|OS Cmds >
$ ansible demo --list-hosts
$ ansible demo -m copy -a "src=test.txt dest=/tmp/test.txt"
$ ansible demo -m copy -a "src=test.txt dest=test.txt"
$ ansible demo -b -m apt -a "name=git  state=present"
$ ansible demo -b -m apt -a "name=apache2 state=present"
$ ansible demo -b -m service -a "name=apache2 state=started"
$ ansible demo -b -m user -a "name=adam state=present"
$ ansible demo -m command -a "ls"
$ ansible demo -m shell -a "ls | wc -l"

Playbooks

A playbook is a configuration, deployment, and orchestration language for Ansible that is written in YAML. It consists of a series of tasks that are executed on target hosts, and can be used to automate complex and repetitive tasks.

Syntax

--- # this will be a comment
- hosts: <host>
  become: <yes|no>               # no is default
  connection: <ssh|winrm|local>  # ssh is default
  become_user: <username>        # user in the inventory is default
  gather_facts: <yes|no>         # no is default
  vars:
   - <variablename>: value
   - <variablename>: value       # to retrive '{{variablename}}'
  tasks:
   - name: <name for your task1>
     <module>: <artibutary options>
   - name: <name for your task2>
     <module>: <artibutary options>
     notify: <name for your task to handle>
  handlers:
   - name: <name for your task to handle>
     <module>: <artibutary options>

Here's an example of a simple playbook that installs the Apache web server on a group of servers:

---
- name: Install Apache Web Server
  hosts: webservers
  become: yes
  tasks:
    - name: Install Apache Package
      yum:
        name: httpd
        state: present
    - name: Start Apache Service
      service:
        name: httpd
        state: started
        enabled: yes

In this example, the playbook is named "Install Apache Web Server" and will be executed on the webservers group of servers. The become keyword is used to run the tasks as the root user, and the tasks section contains the list of tasks to be executed.

The first task installs the Apache web server package using the yum module, and the second task starts and enables the Apache service using the service module.

To run this playbook, you would use the following command:

ansible-playbook apache.yml

This will execute the playbook and install the Apache web server on the target servers.

Dry-run

The --check option is used when running Ansible playbooks to perform a "dry run" of the playbook. When this option is used, Ansible will perform all the steps of the playbook, but will not make any actual changes to the target hosts. Instead, it will report what changes would have been made if the playbook had been run without --check.

For example, the following command will run the playbook demo.yml in "check mode".

ansible-playbook demo.yml --check

This is useful for testing and verifying your playbooks before making actual changes to your systems. It allows you to see what changes will be made, without actually making them.

Hosts

The hosts option in a playbook specifies the target systems that the playbook should be executed against. This option is used to define the inventory group or specific hosts that the playbook should target.

Here is an example of a playbook that uses the hosts option to target a specific inventory group:

  • name: Example playbook
  • hosts: webservers
  • tasks:
  • name: Install Apache
  • become: yes
  • package:
  • name: httpd
  • state: present

In this example, the playbook is targeted to the webservers inventory group. When this playbook is executed, the tasks defined in the playbook will be executed on all the hosts in the webservers group.

You can also specify individual hosts or a combination of groups and hosts in the hosts option. Here is an example of a playbook that targets a specific host:

  • name: Example playbook
  • hosts: web1.example.com
  • tasks:
  • name: Install Apache
  • become: yes
  • package:
  • name: httpd
  • state: present

In this example, the playbook is targeted to the host web1.example.com. When this playbook is executed, the tasks defined in the playbook will be executed only on the host web1.example.com.

There are several options available for the hosts option, which include:

Hostname or IP address

You can specify a specific hostname or IP address as the value for the hosts option. This allows you to run a playbook against a single system. Inventory group: You can specify an inventory group as the value for the hosts option. This allows you to run a playbook against a group of systems defined in your Ansible inventory. All: You can use the value all as the value for the hosts option. This will run the playbook against all systems defined in your Ansible inventory. Group and Host combinations: You can also use a combination of groups and individual hosts as the value for the hosts option. For example, webservers:web1.example.com will run the playbook against all systems in the webservers group, as well as the host web1.example.com. Dynamic inventory: You can use a dynamic inventory to specify the target systems for a playbook. A dynamic inventory is a program that generates an inventory on the fly, based on the current state of your infrastructure.

The hosts option in Ansible is used to specify the target systems that a playbook should be executed against. It can be a specific hostname or IP address, an inventory group, or a combination of groups and hosts.

become

The become option in Ansible is used to specify whether or not to execute a playbook with elevated privileges. By default, Ansible playbooks are executed with the privileges of the user who runs the playbook. However, sometimes it is necessary to run a playbook with elevated privileges, such as when you need to install packages or configure system settings.

The become option can be set to yes or true to indicate that a playbook should be executed with elevated privileges. In addition, the become_user option can be used to specify the user that the playbook should be executed as. For example, to execute a playbook as the root user, you would set the become option to yes and the become_user option to root.

Here's an example of how to use the hosts and become options in a playbook:

  • name: Configure the target systems
  • hosts: webservers
  • become: yes
  • become_user: root
  • tasks:
  • name: Install a package
  • package:
  • name: apache2
  • state: present

include

This section allows you to include other playbooks or tasks. This helps in reusing existing playbooks or tasks and modularizing the playbook.

Gather_facts

The gather_facts option, when set to true, tells Ansible to gather information about the target systems before executing tasks. This information is stored in the ansible_facts dictionary and can be used in the playbook. The information gathered by gather_facts includes, but is not limited to: Operating System, CPU information, Memory information, Network information.

By default, gather_facts is set to true, so you only need to specify it if you want to turn it off for a particular playbook.

Setup

The setup module is a built-in module in Ansible that is used to gather information about the target system.

This command will gather information about the target systems and store it in the ansible_facts dictionary. The gathered information can then be used in the playbook.

Here's an example of the output of the command:

$ ansible -m setup -i hosts
192.168.1.100 | SUCCESS => {
    "ansible_facts": {
        "ansible_all_ipv4_addresses": [
            "192.168.1.100"
        ],
        "ansible_all_ipv6_addresses": [],
        "ansible_architecture": "x86_64",
        "ansible_bios_date": "04/01/2014",
        "ansible_bios_version": "6.00",
        "ansible_user_id": "0",
        "ansible_userspace_architecture": "x86_64",
        "ansible_userspace_bits": "64",
        "ansible_virtualization_role": "guest",
        "ansible_virtualization_type": "virtualbox"
    },
    "changed": false
}

Tasks

Tasks are the fundamental building blocks of Ansible playbooks. They represent a single, atomic operation or piece of work that you want Ansible to perform on your target hosts.

Tasks are defined in a playbook using the tasks section, and each task is defined using the - name: syntax. For example:

---
- name: Install and configure Apache Web Server
  hosts: webservers
  become: yes
  tasks:
    - name: Install Apache Package
      yum:
        name: httpd
        state: present
    - name: Start Apache Service
      service:
        name: httpd
        state: started
        enabled: yes
    - name: Copy Apache Configuration
      copy:
        src: httpd.conf
        dest: /etc/httpd/conf/httpd.conf

In this example, the playbook has three tasks. The first task uses the yum module to install the Apache package on the target hosts. The second task uses the service module to start the Apache service and ensure that it is enabled to start automatically after a reboot. The third task uses the copy module to copy the Apache configuration file httpd.conf to the target hosts.

Each task specifies a module and its arguments to perform a specific action on the target host. The modules in Ansible are responsible for performing the actual work, such as installing packages, starting services, and copying files.

Handlers

Handlers in Ansible are a type of task that can be triggered by other tasks during the execution of a playbook. They are used to perform specific actions or operations, such as restarting a service, when a task changes the state of a system.

For example, consider the following playbook:

---
- hosts: demo
  become: yes
  tasks:
   - name: Install Git
     apt: name=git state=present
   - name: Install Apache2
     apt: name=apache2 state=present
     notify: Run Apache2
   - name: Print Hello
     command: echo Hello
     notify: Run Apache2
  handlers:
   - name: Run Apache2
     service: name=apache2 state=started

Variables

Variables in Ansible play a crucial role in managing the configuration of your systems and applications. They allow you to store values that can be used throughout your playbooks and make it easier to maintain and update your playbooks without making changes to the actual code.

Types of Variables in Ansible

There are several types of variables in Ansible, each with its own use case and scope. Some of the most commonly used types of variables in Ansible are:

Inventory Variables

These are variables that are defined in your inventory file, which is a file that lists the systems that Ansible will manage. Inventory variables can be defined for individual systems, groups of systems, or for the entire inventory. Playbook Variables: These are variables that are defined directly in your playbook using the vars keyword. Playbook variables can be used throughout the entire playbook and can be defined once and referenced multiple times. Group Variables: These are variables that are defined for a specific group of systems in your inventory. Group variables can be used to configure common settings for a group of systems, such as the location of a shared resource. Registered Variables: These are variables that are created during the execution of a task and can be used later in the playbook. Registered variables are created using the register keyword and can be used to store the results of a task for later use.

Defining and Using Variables in Ansible

Variables in Ansible can be defined in several different ways, including directly in a playbook, in a separate variable file, or in an inventory file. To define a variable in a playbook, use the vars keyword, like this:

  • name: Define a variable in a playbook
  • vars:
  • my_variable: "Hello, world!"

To use a variable in a playbook, simply reference the variable using double curly braces, like this:

  • name: Use a variable in a task
  • debug:
  • msg: "{{ my_variable }}"

Best Practices for Using Variables in Ansible

When using variables in Ansible, there are several best practices to keep in mind:

Use meaningful names for your variables. Avoid using abbreviations or abbreviated names for your variables, as this can make your playbooks harder to read and understand. Avoid using hardcoded values in your playbooks. Instead, use variables to store values that can be changed without modifying the playbook itself. Use variable files to store commonly used values. This makes it easier to maintain and update your playbooks, as well as reuse variables across multiple playbooks. Use group variables to configure common settings for a group of systems. This makes it easier to manage and maintain your playbooks, as well as make changes to the configuration of a group of systems in one place.

Generally, Ansible has both local and global variables.

Local variables are defined within a task and are only available within the scope of that task. These variables are useful for storing temporary values that are needed for a specific task, but are not needed elsewhere in the playbook. Local variables are defined using the set_fact module and are referenced using the vars keyword. For example:

  • name: Define a local variable
  • set_fact:
  • my_local_variable: "Hello, world!"
  • name: Use a local variable
  • debug:
  • msg: "{{ my_local_variable }}"

Global variables, on the other hand, are available throughout the entire playbook. These variables are defined using the vars keyword and can be referenced anywhere in the playbook. Global variables are useful for storing values that are used in multiple tasks or playbooks, such as the location of a shared resource or the version of an application. For example:

  • name: Define a global variable
  • vars:
  • my_global_variable: "Hello, world!"
  • name: Use a global variable
  • debug:
  • msg: "{{ my_global_variable }}"

In general, it's recommended to use global variables whenever possible, as they make it easier to manage and maintain your playbooks. However, local variables can be useful in certain cases, such as when you need to store temporary values for a specific task.

Examples for local variables

---
- hosts: demo
  become: yes
  vars:
   - mypkg: apache2
  tasks:
   - name: Install Git
     service: name={{mypkg}} state=started
     apt: name=git state=present
   - name: Install Apache2
     apt: name={{mypkg}} state=present
   - name: Run Apache2
$ ansible-playbook local_vars.yml

Ad-hoc variables in Ansible are variables that are passed from the command line when running an Ansible playbook. These variables allow you to customize the behavior of your playbook without changing the actual playbook itself.

To pass an ad-hoc variable, use the -e or --extra-vars option when running the playbook. The option is followed by a key-value pair that defines the variable. For example:

---
- hosts: demo
  become: yes
  vars:
   - myname: Mohan
  tasks:
   - name: Print Name
     command: echo {{myname}}
$ ansible-playbook local_vars.yml --extra-vars "myname=Vittal" -v
---
- hosts: demo
  become: yes
  vars_files:
   - myvars.yml
  tasks:
   - name: Print Name
     command: echo {{myname}}
myvars.yml:
myname: Syed

group_vars and host_vars are two ways to manage global variables in Ansible. These directories allow you to store variables that are specific to a group of hosts or a single host.

group_vars is a directory that can be located in the root of your playbook or in an inventory directory. It contains YAML files that define variables for specific groups of hosts. For example, you might have a group_vars directory that contains a file named app_servers.yml, which defines variables for a group of hosts that run your application. The variables in app_servers.yml are available to all tasks that are run on the hosts in the app_servers group.

host_vars is similar to group_vars, but it contains variables that are specific to a single host. The host_vars directory is also located in the root of your playbook or in an inventory directory, and it contains YAML files that define variables for specific hosts. For example, you might have a host_vars directory that contains a file named app_server_1.yml, which defines variables for a host named app_server_1. The variables in app_server_1.yml are available to all tasks that are run on app_server_1.

Both group_vars and host_vars are useful for managing global variables in large playbooks, as they allow you to store variables in a way that is organized and easy to maintain. Variables defined in group_vars and host_vars are available to all tasks in your playbook and can be referenced using the standard variable syntax.

The priority of variables in Ansible is determined by the scope and location of the variable. In general, the priority of variables in Ansible is as follows:

Runtime variables

These are the variables that are passed to the playbook at runtime using the -e or --extra-vars option. These variables have the highest priority and will override any other variables with the same name that are defined in the playbook. Local variables: These are variables that are defined within a task using the set_fact module. These variables have a higher priority than group and host variables, but lower than runtime variables. Host variables: These are variables that are defined in the host_vars directory for a specific host. These variables have a higher priority than group variables, but lower than local and runtime variables. Group variables: These are variables that are defined in the group_vars directory for a specific group of hosts. These variables have the lowest priority and will be overridden by runtime, local, and host variables.

It is important to understand the priority of variables in Ansible, as it will help you determine which variables will be used in a given task. You can also use this information to resolve conflicts between variables with the same name.

MK
Mohankrishna PodileDevOps Engineer & Cloud Architect · Irving, Texas

Comments

Questions, corrections, war stories — all welcome. Sign in with GitHub to join the discussion.