Ansible 101: Working With Facts and Templatesby@cloudkungfu
892 reads
892 reads

Ansible 101: Working With Facts and Templates

by cloud-kung-fuJanuary 30th, 2024
Read on Terminal Reader
Read this story w/o Javascript

Too Long; Didn't Read

Ansible utilizes variables, facts, and templates to create adaptable automation workflows. Variables enable dynamic configuration management, facts provide system-specific information, and templates generate customizable configuration files. This approach ensures playbooks are reusable and flexible across different environments.
featured image - Ansible 101: Working With Facts and Templates
cloud-kung-fu HackerNoon profile picture

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.

How facts, variables, and templates work together

  • 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
   curr_time: "{{ now() }}"
   - name: Distro Check
      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
   - name: Write distro name
      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


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.

  1. Clone the repo.
git clone

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
   dev1: "Debian"
   dev2: "RedHat"
   - name: Install NGINX for Debian-based systems   
      name: nginx
      state: present
     when: ansible_facts['os_family'] == dev1       

   - name: Install Lighttpd for RedHat-based systems 
      name: lighttpd
      state: present
     when: ansible_facts['os_family'] == dev2       

   - name: Display the distribution
      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.

  <title>Welcome to {{ ansible_facts['os_family'] }}</title>
  <h1>Server running on {{ ansible_facts['distribution'] }}</h1>

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
   dev1: "Debian"
   dev2: "RedHat"
   - name: Create Homepage with Jinja2 Template for NGINX
      src: index.html.j2
      dest: /var/www/html/index.html
      mode: '644'
     when: ansible_facts['os_family'] == dev1
     notify: restart nginx

   - name: Restart NGINX
     listen: "restart nginx"
      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.


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!