What does "? | "? in Ansible jinja2 templating?

What does " | " in Ansible jinja2 templating?

It is a while that the Open-Community invented such a distinguished software manager for Linux/Unix systems. Even though Ansible has strong support for Windows as well(Finally Microsoft convinced to implement OpenSSH on windows by default). But what I am gonna talk about today is beyond a simple yml scripting for deployment and etc. I have recently started to write some playbooks on my own because I found it really handy to use for my personal Storages, Web and Application servers. Before I used to write functions on a Fabfile in order to solve each task. So here it makes sense to raise a Question, why I should have such a fabulous idea to re-invent the wheel when something is working very good???. The first answer would be "Just For Fun"(aka JFF) and the second answer is that Jinja2 gives me the power to program my deployment in a very dynamic and versatile approach...

No alt text provided for this image

So I assume that you have already known what are Jinja2 and Ansible and what they do but I write this Article to share with you some hidden features of Ansible and its wonderful colleague Jinja2. We knew that we can create some *.j2 files in the templates folder and call this template accordingly for a specific task and make our life easier. btw I have a simple example here:

{% for vhost in hosts -%}
server {
    listen      80;

    server_name  {{ vhost }} www.{{ vhost }};

    location / {
        root   /var/www/{{ vhost }}/public_html;
        index  index.html index.htm;
        error_log /var/www/{{ vhost }}/error.log;

    }
}

{% endfor %}

 So as you can see, it reads a list variable of "hosts" and iterates through it and finally creates the corresponding directive of Nginx config file. So if we call this template with the template module of Ansible tasks, ansible asks jinja2 templating to parse this file for it and complete the file accordingly.

But as we know Jinja2 has more capabilities than this. If you want to annotate Jinja as Ninja, feel free because you are absolutely right. so let's create some tasks of debug that we can read the identical msg after jinja2 compilation

  hosts: test

  tasks:
    - name: Jinja2 for statement
      debug:
        msg: >
             example of for statement

             {% for ip in ansible_all_ipv4_addresses -%}
                IP Address entry {{ loop.index }} = {{ ip }}
             {% endfor %}

So in the above example ```{{ loop.index }} ``` gives you the ability to access the actual index of your loops. As you know it might be very handy at the time you occasionally want to access something applying the index of it. It was something that I have noticed recently and I guess it might be good for you to know that such a feature exists. But I am going to talk about filters in Jinj2 which are really useful when we want to select some Specifics. As an example let's say we need only all even numbers and we don't like odds. In the following example, there are some points that we can speak for many hours about them. For example what would be the corresponding result if we set step of the loop 2 instead of 1, or on the other hand what would be the corresponding result if we set the range 0 to 10 instead. But thanks to the team of Python, Ansible and Jinja2 we do not need to. we can use filters.

  hosts: test

  tasks:
    - name: for iteration in range 
      debug:
        msg: >
            

             {% for number in range(1, 11, 1) -%}
                {% if number is odd -%}
                   {% continue %}
                {% endif -%}
                {{ number }}
             {% endfor %}

Using filters depends on the use case could be the Best Practice. Also, maintain and housekeeping of playbooks get easier. lets jump to the topic quickly,

if you go to this page you will have literally the access to whole documentation about filter regarding jinja2 with Ansible playbooks. I will some also cover some of them here.

If you like to use a filter you need to specify it using "|". The pip in jinja2 litriture means filter by. The two most simplest are min and max. Just take a look at the following example:

  hosts: test

  tasks:
    - name: Ansible Jinja2 filters
      debug:
        msg: >
             ---*** Min and Max filter ***---

             {{ [1, 2, 3, 4, 5] | min }}
 
             {{ [1, 2, 3, 4, 5] | max }}

If you execute ansible-playbook and passing this playbook as playbook it will give you one "1" corresponding by min filter and five "5" corresponding to max filter. In the reality you can combine this filters either with notify and handlers or with when directives to achieve your proper condition in order to have a clean deployment. There are still some simple but handy filters available that you can use them depend on your use cases, like unique, difference and random.

  hosts: test

  tasks:
    - name: Ansible Jinja2 filters
      debug:
        msg: >
             ---*** Ansible Jinja2 filters ***---


             {{ [1, 1, 2, 2, 3, 3, 4, 4, 5, 5] | unique }}

             {{ [1, 2, 3, 4, 5] | difference([2, 3, 4]) }}

             {{ [1, 2, 3] | random }}

The most sophisticated one that I really liked when I used for first time is urlspilit which needs to be provided with one valid argument. According to the Documentation they are:

{{ "https://user:[email protected]:9000/dir/index.html?query=term#fragment" | urlsplit('hostname') }}
# => 'www.acme.com'

{{ "https://user:[email protected]:9000/dir/index.html?query=term#fragment" | urlsplit('netloc') }}
# => 'user:[email protected]:9000'

{{ "https://user:[email protected]:9000/dir/index.html?query=term#fragment" | urlsplit('username') }}
# => 'user'

{{ "https://user:[email protected]:9000/dir/index.html?query=term#fragment" | urlsplit('password') }}
# => 'password'

{{ "https://user:[email protected]:9000/dir/index.html?query=term#fragment" | urlsplit('path') }}
# => '/dir/index.html'

{{ "https://user:[email protected]:9000/dir/index.html?query=term#fragment" | urlsplit('port') }}
# => '9000'

{{ "https://user:[email protected]:9000/dir/index.html?query=term#fragment" | urlsplit('scheme') }}
# => 'http'

{{ "https://user:[email protected]:9000/dir/index.html?query=term#fragment" | urlsplit('query') }}
# => 'query=term'

{{ "https://user:[email protected]:9000/dir/index.html?query=term#fragment" | urlsplit('fragment') }}
# => 'fragment'

{{ "https://user:[email protected]:9000/dir/index.html?query=term#fragment" | urlsplit }}
# =>
#   {
#       "fragment": "fragment",
#       "hostname": "www.acme.com",
#       "netloc": "user:[email protected]:9000",
#       "password": "password",
#       "path": "/dir/index.html",
#       "port": 9000,
#       "query": "query=term",
#       "scheme": "http",
#       "username": "user"
#   }

Or you may need to use regex to extract some IP address you need. It worth to note it down, that here in Jinja2 regex is based on python standard regular expression module(aka re)

{{ 'Some DNS servers are 8.8.8.8 and 8.8.4.4' | regex_findall('\\b(?:[0-9]{1,3}\\.){3}[0-9]{1,3}\\b') }}

Or you need to replace some text:

{{ 'foobar' | regex_replace('^f.*o(.*)$', '\\1') }}

Use map for some complex variable. in this case comma seprated mountpoints

{{ ansible_mounts | map(attribute='mount') | join(',') }}

Use quote to make a variable to string and many many other examples.

You can also combine filters

# give me largest permutations (order matters)

"{{ [1,2,3,4,5] | permutations | list }}"

# give me permutations of sets of three

 "{{ [1,2,3,4,5] | permutations(3) | list }}"

# give me combinations for sets of two"{{ [1,2,3,4,5] | combinations(2) | list }}"

And many many other capabilities that you can invent by combine filters.

I hope you enjoyed my Article and feel free to send me your feedback and raise your question regarding Ansible.

要查看或添加评论,请登录

Ashkan Kamyab的更多文章

  • Let's ClearLinux*

    Let's ClearLinux*

    It has been a couple of Months, that I have participated in OpenStack Summit. During the summit have met an Old Friend,…

  • Open Stack Summit, Summary

    Open Stack Summit, Summary

    Hackathon What the journey! It was one of most exciting summits, I have ever had attended. It started within a…

    4 条评论
  • AWS Startupday, Berlin Oct 2018

    AWS Startupday, Berlin Oct 2018

    Every day I receive a collection of E-Mails about meetups, forums, and semi/webinars around the World in divers of…

  • Docker everywhere! Contemplation or Confrontation?

    Docker everywhere! Contemplation or Confrontation?

    It is circa 5 years that docker is released according to Wikipedia in this page; and we use it day to day for different…

  • Minikube + Vagrant + Libvirt

    Minikube + Vagrant + Libvirt

    As a person who is always keen about K8s it was always a question of how to test my study-cases within a literally…

  • Dockerfile in best Practices

    Dockerfile in best Practices

    It's quite a long time ago that I used Docker for the first Time, approximately 5 years but for 3 years I am working…

  • Why tmux as primary Terminal

    Why tmux as primary Terminal

    I love working with the command line. Seriously, I think there’s hardly any more productive and more versatile tool for…

社区洞察

其他会员也浏览了