Tuesday, February 7, 2023

Ansible Jinja2 Templates - ansible template module

Here I'm starting this post with famous ARISTOTLE quote.

"We are what we repeatedly do. Excellence, then is not an act, but a Habit"


Welcome back Ansible Automations and who are habituated as Ansible automation specialists this post for them to give boosted walk through, In this post, I would like to share my experiments with Jinja2 templates usage on the Ansible playbook. Of-course Jinja is from Japan it is world famous for templatization capabilities by integrating with multiple languages such as Python, Ruby, Salt talk etc.

In this post we will be cover the following topics:
  1. What is Jinja2 template do?
  2. Template with filters
  3. Template with Lists and sets
  4. Template module in Ansible
  5. Template with Flow Control
  6. Template using Looping
  7. Template inheritance**

What is Jinja template do?
Jinja2 is another Python library created for Flask web framework, that comes part of Ansible installation. It is special ability as interpolate or put stuff into YAML Variables(other strings). Those variables can be part of HTML document putting stuff at run-time.

A template is any string of text that contains placeholders {{ }} for the template language, to be able to replace those placeholders by some values. The syntax used for the placeholders and the whole syntax of the template as a whole is known as a template language and the underlying code that evaluates the template and puts the new values in is called a template engine Ansible comes with powerful Jinja2 template language.
 
Let's explore more about Ansible Jinja templates experiments with examples.


Prerequisites

Firstly you must have Ansible installed and the ssh-key authorized for all the managed nodes those are configured inside your targeted environment in the Ansible inventory host list.

How to use string filters in a playbook?

This is common requirement where we can use the different string filters such as: upper, lower, title, replace, default value in the following example.


---
- name: test string values
  hosts: localhost
  vars:
    my_name: 'Pavan Deverakonda the great'
  tasks:
    - name: String filter examples
      debug:
        msg: 
        - "The name is {{ my_name }}"
        - "The name is {{ my_name |upper }}"
        - "The name is {{ my_name |lower }}"
        - "The name is {{ my_name |title }}"
        - "The name is {{ my_name |replace('Pavan','Raghav') }}"
        - "The name is {{ title |default('Mr.') }}{{ my_name }}"
  
After the execution of the string filters the output :

Applying string filters on text in a Ansible playbook


How to play with Jinja2 lists and sets in Ansible?

It is very simple to understand about the Lists and Sets in Jinja2 they can be operated similar to Python Lists and Sets here in the Ansible we need to use them in the YAML as follows:

---
- name: test aggregate values
  hosts: localhost
  vars:
    mylist: [10,20,30]
    x: [8,3,9,5,1]
    y: [44, 5,5]
    words: ["Learning","by","doing"]
  tasks:
    - name: aggregate filter examples
      debug:
        msg: 
        - "The max {{ mylist|max }}"
        - "The min {{ mylist|min }}"
        - "The last {{ mylist|last}}"

    - name: set filters 
      debug:
        msg:
        - "The unique: {{ [2,5,2,9,7,5]|unique }}"
        - "The union: {{ x|union(y) }}"
        - "The another union: {{ [10,3.4]|union([4,2])}}"
        - "The intersect: {{ x|intersect(y) }}"
        - "The intersect: {{ [10,20,30,10]| intersect ([40,30])}}"
        - "The joining words: {{ words|join(' ') }}"
The execution on the lists and sets goes here as output:
Jinja2 Lists and Sets in Ansible playbooks

How to write an Ansible playbook using templates?

It's so simple to use the Jinja2 templates in the Ansible playbooks. To know all the available default ansible variables at the runtime, you can inspect with the following command:
ansible -m setup localhost
It will give you the facts about the localhost. To filtering out to get all the facts which starts with 'ansible_'
ansible -m setup db |grep ansible_


Ansible setup module
ansible_user details using ansible command setup module


Now, Let's move on to our main goal to playing with the templates in playbook and experiment to know how the template engine helps our examples.
 

Writing Simple Ansible playbook using templates module

Ansible uses Jinja2 templates where it can be lookup inside 'templates' folder, where your playbook runs. All the values of variables will replaced at the time of running the playbook. Runtime value replaces at the time of remote execution.
cat templates/sample-conf.j2
env = {{ env }}
remote_ip = {{ ansible_host }}
remote_user = {{ ansible_user_id}}
remote_hostname = {{ (ansible_fqdn|default(ansible_host)) }}
To test the template values in the playbook write it as :
# File: mytemplate-test.yaml
---
- name: test template values
  hosts: web
  vars:
    env: dev
  tasks:
    - name: template module runs on remote
      template:
        src: sample-conf.j2
        dest: /etc/sample.conf
      become: true
Advanced settings for templates adding the user, group, file permissions with mode attributes.
 ansible-playbook mytemplate-test.yaml -b
 

setup the permissions on the templated files.



Ansible Jinja template experiment
Ansible Jinja template experiment

Now connect to the Node1 or Node2 where this hosts are in the play, and check that file content of /etc/sample.conf

Execution of Ansible template sample
Jinja2 template execution with ansible playbook

How to specify "if else" statements in Ansible Jinja2 (.j2) templates? 

Assuming that you are assigning somewhere in the playbook or at the time of launching the Ansible in the extra_vars, in AWX here we go with the "test_var" value with some bool value and you want to test the following is the Jinja syntax to test
- debug:
	msg: "{% if test_var == true %} Good to go!{% else %} Not operational!{% endif %}"
You can also include the ansible facts in the message content.
controlplane $ cat condition1.yml 
- name: Condition test
  hosts: localhost
  gather_facts: no
  vars:
    test_var: yes
  tasks:
    - name: checking if-condition
      debug:
        msg: "{% if test_var == true %} Good to go!{% else %} Not operational!{% endif %}"
	
Simple if-else Jinja template syntax in Ansible playbook

Looping with Jinja templates

Here is a fun looping playbook which will be using a list variable 'myex' that stored all my experiances in the IT industry.
---
- name: Testing Jinja templates with loops
  hosts: localhost
  vars:
    myex: ['Teleparadigm','IBM Global Services','BirlaSoft','Virtusa','Rubicon Red', 'Oracle Corporation','Garmin']
  tasks:
    - name: extracting my experiance
      template:
        src: myex.j2
        dest: /tmp/experiance.txt
  
Jinja template you can store in a file called myex.j2
This is my experience list:

{% for e in myex %}
 
{{loop.index}}. {{ e }}

{% endfor %}
 
When we run the playbook we could see a nice output as:
Loops in Jinja templates in Ansible playbook

Nested loops in Jinja template 

Many Thanks! to Mr. Tim Fairweather RedHat Solution Architect, who shared crazy and funny post "Mastering loops with Jinja templates in Ansible" with this inspiration I've created following nested loop section, where I would like to experiment with the template usage and that too the role created with the ansible-galaxy command as shown:
ansible-galaxy init jinja-templates
  tree jinja-templates/
  jinja-templates/
|-- README.md
|-- defaults
|   `-- main.yml
|-- files
|-- handlers
|   `-- main.yml
|-- meta
|   `-- main.yml
|-- tasks
|   `-- main.yml
|-- templates
|-- tests
|   |-- inventory
|   `-- test.yml
`-- vars
    `-- main.yml
Here is template using playbook my flow of developing code as follows:
  1. Create variables which will contain a map/dictionary
  2. Define a task that uses template module and generates output
  3. Create template that will referring to the variables defined in the step 1
  4. Add a configuration to work with the do statement in template
  5. Create main playbook to test the nested loop in Jinja Template
Create variables 
Let's create the variables which have dictonaries in a yaml format `vi jinja-templates/vars/main.yml`
---
    inspiring_people:
    - name: Nielgogte
      fav_colour: Blue
    - name: Siva
      fav_colour: Blue
    - name: RanjanShee
      fav_colour: Orange
    - name: Sanjeet
      fav_colour: Orange
    - name: Pankaj
      fav_colour: Yellow
    - name: Prateek
      fav_colour: Blue

  colours:
    - name: Blue
      thinks:
        - Sky is The Limit
        - See as sea into the Depth
    - name: Yellow
      thinks:
        - Expressive
        - Task Oriented
        - Brainstroming
    - name: Orange
      thinks:
        - Proactive
        - Extreme
        - Cares a lot
  
Create task using template module 
Now what we want to perform with this role contained task, we will define under the tasks folder where we can define multiple task `vi jinja-templates/tasks/main.yml`
  - name: Create the Jinja2 based template
	template:
	  src: inspiring.j2 
	  dest: /tmp/impactingMe.out
  
Create template with nested for-loop
See here is the logic that goes fantastic for the nested loops in a Jinja Template `jinja-templates/templates/inspiring.j2`

  • Some variable names modified to test how they are working
  • Inside the template I've used Jinja filter ' | upper'.
 
---
{% for colour in colours %}
Colour number {{ loop.index }} is {{ colour.name }}.
  {% set colour_count = 0 %}
{% for person in inspiring_people if person.fav_colour == colour.name %}
{{ person.name | upper }}
{% set colour_count = colour_count + 1 %}
     {% do colour.update({'inspiring_people_count':colour_count}) %}
{% endfor %}
Currently {{ colour.inspiring_people_count }} inspiring_people choose color {{ colour.name }} as their favourite.
And the following are their thoughts for {{ colour.name }} :
  {% for item in colour.thinks %}
  -> {{ item }}
  {% endfor %}
{% endfor %}
  
All set to test our new learning that is nested loop within Jinja2 templates in Ansible
---
- name: Demonstrating variables in Jinja2 Loops
  hosts: localhost
  connection: local
  gather_facts: no
  roles:
        - jinja-templates

  tasks:
    - name: display file
      shell: cat /tmp/impactingMe.out
      register: output

    - debug:
        msg: "{{ output.stdout.split('\n') }}"	
  
Here we go... that nice output of-course I've worked on it to get it working almost half day :)

Ansible nested loops in Jinja Templates

Template inherence


Ansible Jinja template inheritance allows you to create the building blocks that you can combine use them. Here is an example of an Ansible playbook that uses Jinja2 templates with inheritance to create an index.html page. As The head template implementation can be 'included' and the body template is extendes in the final index template to generate the complete index.html page.
---
- name: Create index.html page
  hosts: localhost
  gather_facts: false
  vars:
    title: My Ansible experiment Website
    description: A sample website created with Ansible and Jinja2 templates
    keywords: sample, website, Ansible, Jinja2
  tasks:
    - name: Create head template
      template:
        src: templates/head.j2
        dest: head.html

    - name: Create body template
      template:
        src: templates/body.j2
        dest: body.html

    - name: Create index.html
      template:
        src: templates/index.j2
        dest: index.html  
  

The head template, created with templates/head.j2, sample might look like this:
  
  
    {{ title }}
    
    
  
The body template, created with templates/body.j2, sample might look like this:

  
  

Welcome to {{ title }}

{{ description }}

Finally, here's an example of the index.j2 template, which extends the body.j2 and includes head.html that was generated with `head.j2` templates:
  
{% include "head.html" %}
{% extends "body.j2" %}
  

H A P P Y !!    Template using A U TO M A T I O N S !!

Good Document References:

Hope you enjoyed this post, Keep sharing your comments on this post.

No comments:

Categories

Kubernetes (24) Docker (20) git (13) Jenkins (12) AWS (7) Jenkins CI (5) Vagrant (5) K8s (4) VirtualBox (4) CentOS7 (3) docker registry (3) docker-ee (3) ucp (3) Jenkins Automation (2) Jenkins Master Slave (2) Jenkins Project (2) containers (2) docker EE (2) docker private registry (2) dockers (2) dtr (2) kubeadm (2) kubectl (2) kubelet (2) openssl (2) Alert Manager CLI (1) AlertManager (1) Apache Maven (1) Best DevOps interview questions (1) CentOS (1) Container as a Service (1) DevOps Interview Questions (1) Docker 19 CE on Ubuntu 19.04 (1) Docker Tutorial (1) Docker UCP (1) Docker installation on Ubunutu (1) Docker interview questions (1) Docker on PowerShell (1) Docker on Windows (1) Docker version (1) Docker-ee installation on CentOS (1) DockerHub (1) Features of DTR (1) Fedora (1) Freestyle Project (1) Git Install on CentOS (1) Git Install on Oracle Linux (1) Git Install on RHEL (1) Git Source based installation (1) Git line ending setup (1) Git migration (1) Grafana on Windows (1) Install DTR (1) Install Docker on Windows Server (1) Install Maven on CentOS (1) Issues (1) Jenkins CI server on AWS instance (1) Jenkins First Job (1) Jenkins Installation on CentOS7 (1) Jenkins Master (1) Jenkins automatic build (1) Jenkins installation on Ubuntu 18.04 (1) Jenkins integration with GitHub server (1) Jenkins on AWS Ubuntu (1) Kubernetes Cluster provisioning (1) Kubernetes interview questions (1) Kuberntes Installation (1) Maven (1) Maven installation on Unix (1) Operations interview Questions (1) Oracle Linux (1) Personal access tokens on GitHub (1) Problem in Docker (1) Prometheus (1) Prometheus CLI (1) RHEL (1) SCM (1) SCM Poll (1) SRE interview questions (1) Troubleshooting (1) Uninstall Git (1) Uninstall Git on CentOS7 (1) Universal Control Plane (1) Vagrantfile (1) amtool (1) aws IAM Role (1) aws policy (1) caas (1) chef installation (1) create deployment (1) create organization on UCP (1) create team on UCP (1) docker CE (1) docker UCP console (1) docker command line (1) docker commands (1) docker community edition (1) docker container (1) docker editions (1) docker enterprise edition (1) docker enterprise edition deep dive (1) docker for windows (1) docker hub (1) docker installation (1) docker node (1) docker releases (1) docker secure registry (1) docker service (1) docker swarm init (1) docker swarm join (1) docker trusted registry (1) elasticBeanStalk (1) global configurations (1) helm installation issue (1) mvn (1) namespaces (1) promtool (1) service creation (1) slack (1)