Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Advanced use of jinja2 for Ansible Templates

Advanced use of jinja2 for Ansible Templates

Take a practical dive into advanced use of the Jinja2 templating language as implemented in the Ansible core template module.

Keith Resar

March 23, 2017
Tweet

More Decks by Keith Resar

Other Decks in Technology

Transcript

  1. ADVANCED JINJA2 FOR TEMPLATES REVIEW JINJA2 ORIGIN STORY COMPARING TO

    DIY, JINJA 101, AND A DIVE INTO SOME LESS COMMONLY USED PATTERNS Keith Resar @KeithResar
  2. @KeithResar Keith Resar: Bio Wear many hats @KeithResar [email protected] Coder

    Open Source Contributor and Advocate Infrastructure Architect
  3. <b>From:</b> Pro-Speller &lt;[email protected]&gt; <br><b>Date:</b> %{{exec("%s" % ((datetime.today() - timedelta(minutes =

    47)).strftime("%A, %B %e, %Y at %l:%M %p")))}}% <br><b>To:</b> Andrea Jacobs &lt;[email protected]&gt; <br><b>Subject:</b> Your Scan Results - %{{url_f}}% <br> THE ILL ADVISED DIY TEMPLATE
  4. THE ILL ADVISED DIY TEMPLATE %{{INNER_TPL}}% <tr style="%{{style( ('miss_tr',) )}}%">

    <td colspan="2" style="%{{style( ('miss_td',) )}}%"> <div style="%{{style( ('word_div',) )}}%"> <span style="%{{style( ('word_span',) )}}%">%{{INNER.WORD}}%</span> &nbsp;: &nbsp; <span>%{{INNER.SUGGESTIONS}}%</span> </div> <div style="%{{style( ('suggestions_div',) )}}%"> <span>%{{INNER.CONTEXT}}%</span> </div> </td> </td> %{{ENDINNER_TPL}}%
  5. APPLICATION LOGIC IS FOR THE CONTROLLER, BUT DON'T MAKE THE

    TEMPLATE DESIGNER'S LIFE DIFFICULT BY RESTRICTING FUNCTIONALITY TOO MUCH. https://github.com/pallets/jinja#philosophy
  6. {% extends "layout.html" %} {% block body %} <ul> {%

    for user in users %} <li><a href="{{ user.url }}">{{ user.username }}</a></li> {% endfor %} </ul> {% endblock %} PURE, BEAUTIFUL JINJA
  7. PURE, BEAUTIFUL JINJA Sandboxed Execution Mode Every aspect of the

    template execution is monitored and explicitly whitelisted or blacklisted, whatever is preferred. This makes it possible to execute untrusted templates. Template Inheritance Makes it possible to use the same or a similar layout for all templates. Easy to Debug With a debug system that integrates template compile and runtime errors into the standard Python traceback system. Configurable Syntax For instance you can reconfigure Jinja2 to better fit output formats such as LaTeX or JavaScript. (skipped the features more relevant to high-volume usage such as in Django)
  8. TEMPLATE FILE NAMING CONVENTIONS Accepts any text file type text,

    xml, html, etc Convention is to name files with .j2 extension http.conf.j2, sshd_config.j2 Convention to place in the templates/ directory templates/http.conf.j2, templates/sshd_config.j2
  9. EXPRESSIONS AS PYTHON Accessing Ansible variables like {{ ansible_hostname }}

    {{ ansible_date_time.epoch }} We can do math like {{ 1+3 }} Standard data types, like my list: {{ ('a','b','c') }} We can call standard methods associated with our types: {{ "lorem ipsum".upper() }} {{ ['a','b','c'].pop() }}
  10. EXPRESSIONS JINJA STYLE Inline Conditionals: {{ '[%s]' % page.title if

    page.title }} Built-in Filters: {{ my_var | default('my_var undefined') }} Maths: abs, int, float, round, sum Str: capitalize, length, center, escape, lower, regex Lists: join, last, sort, shuffle, json_query
  11. STATEMENTS Loops: <ul> {% for href, caption in my_list }}

    <li><a href="{{ href }}">{{ caption }}</a></li> {% endfor %} </ul> Conditionals: {% if kenny.sick %} Kenny is sick. {% elif kenny.dead %} You killed Kenny! You bastard!!! {% else %} Kenny looks okay --- so far {% endif %}
  12. COMMENTS {# Note: Nothing in the comment will be included

    in the template output {% for user in users %} ... {% endfor %} #}
  13. WHEN THINGS GO WRONG fatal: [localhost]: FAILED! => {"changed": false,

    "failed": true, "msg": "AnsibleUndefinedVariable: 'my_var' is undefined"} fatal: [localhost]: FAILED! => {"changed": false, "failed": true, "msg": "AnsibleError: template error while templating string: expected token 'end of print statement', got '...' String: <...>"}
  14. OVERRIDING BEHAVIOR Include as first line in the template file:

    #jinja2:variable_start_string:'[%' , variable_end_string:'%]', trim_blocks: False
  15. INTERESTING LOOPS Alternation: {% for row in rows %} <li

    class="{{ loop.cycle('odd', 'even') }}">{{ row }}</li> {% endfor %} Empty Lists: <ul> {% for user in users %} <li>{{ user.username|e }}</li> {% else %} <li><em>no users found</em></li> {% endfor %} </ul>
  16. SORTING AND GROUPING FILTERS Sort by Attribute: {% for item

    in iterable|sort(attribute='date') %} ... {% endfor %} Group by Attribute: {% for group in persons|groupby('gender') %} <li>{{ group.grouper }}<ul> {% for person in group.list %} <li>{{ person.first_name }}</li> {% endfor %}</ul></li> {% endfor %}