Variables and Facts in Ansible

Ansible is one of the most widely-used automation tools in the IT industry, helping DevOps professionals manage systems and automate tasks with ease. One of the fundamental concepts that you must grasp when using Ansible is the use of variables and facts. Both of these components play a crucial role in making your playbooks dynamic, flexible, and reusable. In this article, we will dive deep into what variables and facts are, how they are used in Ansible, and best practices for working with them.

What Are Variables in Ansible?

Variables in Ansible are used to store values that can be used throughout playbooks and roles. These values can be anything from strings, numbers, lists, or dictionaries. Variables allow you to make your playbooks reusable and adaptable to different environments by abstracting values that might change between executions, like hostnames, IP addresses, or package versions.

Types of Variables in Ansible

Ansible supports several types of variables, which can be sourced from different places:

  • Playbook Variables: Variables defined directly within the playbook, often under a vars section.

- hosts: webservers
  vars:
    apache_port: 80
  tasks:
    - name: Install Apache
      yum:
        name: httpd
        state: present
  • Inventory Variables: Variables that are defined in the Ansible inventory file for a particular host or group of hosts.
[webservers]
web1 ansible_host=192.168.1.10 apache_port=8080
web2 ansible_host=192.168.1.11 apache_port=9090
  • Command-line Variables: Variables can also be defined on the command line using the -e or --extra-vars option when running Ansible commands.

 

ansible-playbook site.yml -e "apache_port=8080"
  • Role Variables: Variables that are defined in the defaults/main.yml or vars/main.yml files within Ansible roles.

  • Facts: System properties collected by Ansible that can be used as variables.

  • External Variables: Variables defined outside of the playbook in external files, such as JSON or YAML files.

 

Using Variables in Ansible Playbooks

Here’s an example that shows how to use variables in a playbook to make it more flexible:

 

- name: Install and configure Apache
  hosts: all
  vars:
    apache_package: httpd
    apache_port: 80
  tasks:
    - name: Install Apache
      yum:
        name: "{{ apache_package }}"
        state: present

    - name: Open Apache port in firewall
      firewalld:
        service: http
        permanent: yes
        state: enabled
        immediate: yes
        port: "{{ apache_port }}/tcp"

In this example:

  • The apache_package and apache_port variables make it easy to customize the playbook’s behavior across different environments or servers.
  • The variable values are referenced within the tasks using the {{ variable_name }} syntax.

 

What Are Facts in Ansible?

In Ansible, facts are system properties automatically gathered by Ansible when it connects to a target host. These facts provide information about the target system such as its operating system, network interfaces, IP addresses, and hardware specifications. Facts are stored in a dictionary-like structure and can be accessed as variables in playbooks.

How Ansible Gathers Facts

By default, Ansible collects a wide variety of facts about the host system using the setup module. This module gathers facts about the system’s environment, including:

  • System architecture (e.g., x86_64)
  • OS type and version (e.g., Ubuntu 20.04)
  • Memory and CPU information
  • IP addresses and network interfaces
  • File system details
  • Mounted devices
  • Environment variables

For example, you can access the IP address of a target host using the fact ansible_default_ipv4.address:

 

- name: Get default IP address
  hosts: all
  tasks:
    - name: Print the default IP address
      debug:
        msg: "The default IP is {{ ansible_default_ipv4.address }}"

How to Disable Fact Gathering

If you don’t need all the facts or want to speed up your playbook execution, you can disable fact gathering by using the gather_facts directive:

 

- hosts: all
  gather_facts: no
  tasks:
    - name: Custom task without fact gathering
      debug:
        msg: "Facts gathering is disabled for this playbook"

Using Facts in Ansible Playbooks

Facts are extremely useful for making playbooks dynamic. They allow you to target specific system attributes, like OS type or architecture, without hardcoding values into your playbook.

For example, the following playbook installs different packages based on the operating system:

- name: Install packages based on OS
  hosts: all
  tasks:
    - name: Install Apache on Debian-based systems
      apt:
        name: apache2
        state: present
      when: ansible_facts['os_family'] == "Debian"

    - name: Install Apache on RedHat-based systems
      yum:
        name: httpd
        state: present
      when: ansible_facts['os_family'] == "RedHat"

Listing All Available Facts

You can use the setup module to explicitly gather and list all available facts:

 

- name: Gather facts and display them
  hosts: all
  tasks:
    - name: Display all facts
      setup:
    - name: Show gathered facts
      debug:
        var: ansible_facts

This will output all the collected facts about the system, which can be extremely useful for debugging or understanding the available data.

Best Practices for Using Variables and Facts in Ansible

1. Use Variables for Dynamic Playbooks

Instead of hardcoding values in your playbooks, use variables to make them more flexible and reusable. This ensures that your playbooks can be used across different environments with minimal changes.

2. Leverage Facts to Make Decisions

Facts provide valuable information about the target system and should be used to make decisions within your playbooks. Use facts to determine the target operating system, architecture, or IP addresses, and adjust tasks accordingly.

3. Minimize Hardcoding

Avoid hardcoding values like paths, package names, or configurations directly in your playbooks. Instead, define variables or use facts wherever possible to enhance the playbook’s reusability and flexibility.

4. Structure Your Variables Effectively

For large projects, consider organizing your variables into separate files or directories. Ansible allows you to include external variable files and use role-based variable structures. This helps keep your playbooks organized and reduces clutter.

5. Use defaults and vars Directories for Roles

If you’re using Ansible roles, it’s a good practice to define default values for variables in the defaults/main.yml file and environment-specific or overriding variables in the vars/main.yml file.

6. Be Mindful of Variable Precedence

Ansible has a specific variable precedence order. When a variable is defined in multiple places, Ansible will use the one with the highest precedence. Understanding this order can help avoid conflicts.

Ashutosh Dixit

I am currently working as a Senior Technical Support Engineer with VMware Premier Services for Telco. Before this, I worked as a Technical Lead with Microsoft Enterprise Platform Support for Production and Premier Support. I am an expert in High-Availability, Deployments, and VMware Core technology along with Tanzu and Horizon.

Leave a Reply