In Ansible, variables and facts, along with templates, are foundational tools for creating flexible automation workflows. Variables allow you to manage and change your configurations dynamically. Facts are a special subset of variables that Ansible gathers from the remote systems, providing context-specific information.
Templates enable the generation of variable-driven configuration files, making your playbooks adaptable to varied environments and scenarios.
These tools make playbooks reusable and adaptable, allowing you to avoid hard-coding values and enabling customization for different environments.
Variables & Facts
Variables allow for parameters to be modified without altering the playbook's core logic.
- Types of Variables:
-
Boolean: True or False values.
-
List: An ordered collection of items.
-
Dictionary: Key-value pairs for complex data structures.
-
Registered Variables: Captures the output of tasks to use later in your playbook.
-
Facts: Auto-collected variables that provide details about the remote systems you are managing.
-
NB: Avoid conflicts in variable names by using bracket notation.
- name: Print the distribution of the target
hosts: all
vars:
curr_time: "{{ now() }}"
tasks:
- name: Distro Check
ansible.builtin.debug:
msg: "The target system is {{ ansible_facts['distribution'] }}. Timestamp: {{ curr_time }}"
Templates & Files
Templates in Ansible use the Jinja2 templating language to dynamically create files using variable interpolation, loops, and conditionals.
- name: Write distro name
hosts: all
tasks:
- name: Write distro name
ansible.builtin.template:
src: distro.j2
dest: /root/distro.txt
mode: '644'
# src: location of jinja2 template file
# dest: location it will be copied to
# permissions that will be granted to the file
Practice
We're going to use the OS Family to determine whether to install NGINX of Lighttpd, and then, we'll deploy a custom homepage to the remote host containing NGINX all without hardcoding hostnames.
- Clone the repo.
git clone https://github.com/perplexedyawdie/ansible-learn.git
2. Change directory to facts-and-templates
cd ansible-learn/facts-and-templates
3. Spin up the environment using docker-compose
docker compose up -d --build
4. SSH into the Ansible server
ssh -o StrictHostKeyChecking=no -o NoHostAuthenticationForLocalhost=yes root@localhost -p 2200
# password: test123
Variables & Facts
5. Create a playbook called server_setup.yaml
. Here, we'll setup NGINX & Lighttpd, and then, output the name of the distro for each remote host.
- name: Install NGINX on Debian & Lighttpd on RedHat
hosts: all
vars:
dev1: "Debian"
dev2: "RedHat"
tasks:
- name: Install NGINX for Debian-based systems
ansible.builtin.apt:
name: nginx
state: present
when: ansible_facts['os_family'] == dev1
- name: Install Lighttpd for RedHat-based systems
ansible.builtin.yum:
name: lighttpd
state: present
when: ansible_facts['os_family'] == dev2
- name: Display the distribution
ansible.builtin.debug:
msg: "The server is running {{ ansible_facts['distribution'] }}"
6. Run ansible-lint.
ansible-lint server_setup.yaml
7. Run the playbook.
ansible-playbook --key-file /root/.ssh/id_rsa_ansible -u root -i inventory.yaml server_setup.yaml
8. Confirm that the setup was successful.
ssh -i /root/.ssh/id_rsa_ansible root@server3 nginx -V
ssh -i /root/.ssh/id_rsa_ansible root@server2 lighttpd -v
ssh -i /root/.ssh/id_rsa_ansible root@server1 lighttpd -v
Templates & Files
9. Create a Jinja2 template file called index.html.j2
It will get auto-populated with the OS Family & Distribution.
<html>
<head>
<title>Welcome to {{ ansible_facts['os_family'] }}</title>
</head>
<body>
<h1>Server running on {{ ansible_facts['distribution'] }}</h1>
</body>
</html>
10. Create a playbook called custom_homepage.yaml.
We're deploying the custom homepage created above to NGINX then restarting the server.
- name: Deploy Custom Homepage and restart
hosts: all
vars:
dev1: "Debian"
dev2: "RedHat"
tasks:
- name: Create Homepage with Jinja2 Template for NGINX
ansible.builtin.template:
src: index.html.j2
dest: /var/www/html/index.html
mode: '644'
when: ansible_facts['os_family'] == dev1
notify: restart nginx
handlers:
- name: Restart NGINX
listen: "restart nginx"
ansible.builtin.service:
name: nginx
state: restarted
when: ansible_facts['os_family'] == dev1
11. Run the linter.
ansible-lint custom_homepage.yaml
12. Run the playbook.
ansible-playbook --key-file /root/.ssh/id_rsa_ansible -u root -i inventory.yaml custom_homepage.yaml
13. Confirm deployment by visiting http://localhost:2203
in your browser.
Recap
Awesome effort! 🙌 We've learned how to use variables & facts in a playbook along with how to create dynamic files using templates. Next, we'll look at modularization and error handling. Til then, take care!
The DevOps Writing Contest is sponsored by Aptible. Aptible’s hosting platform automates the work of provisioning, managing, and scaling infrastructure, so developers can focus on what actually matters: their product. Get started for free with Aptible.