Ansible 101: Working With Facts and Templates

Written by cloudkungfu | Published 2024/01/30
Tech Story Tags: devops | ansible | docker | automation | ansible-variables | learn-ansible | ansible-templates-guide | hackernoon-top-story

TLDRAnsible 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.via the TL;DR App

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.

  1. 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!


Written by cloudkungfu | Sharing DevOps thoughts, ideas & experiments.
Published by HackerNoon on 2024/01/30