Does current Ansible support templates macro?

323 views
Skip to first unread message

Xinhuan Zheng

unread,
Jan 14, 2020, 4:27:45 PM1/14/20
to Ansible Project
Hello,

I'm working on a role for system SSSD daemon. I found this piece of code online:

I have defined my own sssd_config variable in my role's defaults directory, so I'd like to use that piece of code. That code is neat. However, I don't understand what it is doing in line:
{% from "templates/encoder/macros/ini_encode_macro.j2" import ini_encode with context -%}

Also does current Ansible support templates macro like above?

If it doesn't, then sssd_config variable is a large dictionary map, with INI-style different sections. What really needs to happen is based on that variable, change it to use = symbol as delimiter for each INI section. For example:

sssd_config:
  sssd:
    debug_level: 1
    config_file_version: 2
...

Then the produced sssd.conf file would look like below:

[sssd]
debug_level=1
config_file_version=2

Thank you,

Xinhuan Zheng


Vladimir Botka

unread,
Jan 14, 2020, 5:42:22 PM1/14/20
to Xinhuan Zheng, ansible...@googlegroups.com
On Tue, 14 Jan 2020 13:27:45 -0800 (PST)
Xinhuan Zheng <xinhua...@gmail.com> wrote:

> ... However, I don't understand what it is doing in line:
> {% from "templates/encoder/macros/ini_encode_macro.j2" import ini_encode
> with context -%}

This link to the Jinja doc will help you
https://jinja.palletsprojects.com/en/2.10.x/templates/#import

-vlado

Xinhuan Zheng

unread,
Jan 15, 2020, 12:45:42 PM1/15/20
to Ansible Project
I still cannot figure out how to loop through my variable:

sssd_config:
  sssd:
    debug_level: 1
  nss:
    reconnection_retries: 3
 pam:
  debug_level: 5

Here is my template code:

{% for item in sssd_config %}
[{{ item }}]
{% set list = sssd_config[item] %}
{% for i in list %}
{{ i }} =
{% endfor %}
{% endfor %}

I cannot figure out what to put after {{ i }}. Please HELP!

Thank you,

- Xinhuan Zheng

Vladimir Botka

unread,
Jan 15, 2020, 1:36:02 PM1/15/20
to Xinhuan Zheng, ansible...@googlegroups.com
On Wed, 15 Jan 2020 09:45:41 -0800 (PST)
Xinhuan Zheng <xinhua...@gmail.com> wrote:

> *I still cannot figure out how to loop through my variable:*
>
> *sssd_config:*
> * sssd:*
> * debug_level: 1*
> * nss:*
> * reconnection_retries: 3*
> * pam:*
> * debug_level: 5*
>
> Here is my template code:
>
> {% for item in sssd_config %}
> [{{ item }}]

Variable 'sssd_config' is dictionary. It's not possible to iterate
dictionary. Try for example

{% for item in sssd_config.items() %}
{{ item }}
{% endfor %}

see the 'items' in the created file and fit the template to your needs.

HTH,

-vlado

Xinhuan Zheng

unread,
Jan 15, 2020, 1:40:53 PM1/15/20
to Ansible Project
Tried what you said. Here is what {{ item }} look like:

[(u'sssd', {u'debug_level': 5, u'reconnection_retries': 3, u'config_file_version': 2, u'sbus_timeout': 30})]

[(u'services', [u'nss', u'pam', u'ssh'])]

...

What should I do next?

Thanks again,

- Xinhuan

Vladimir Botka

unread,
Jan 15, 2020, 1:47:42 PM1/15/20
to Xinhuan Zheng, ansible...@googlegroups.com
On Wed, 15 Jan 2020 10:40:53 -0800 (PST)
Xinhuan Zheng <xinhua...@gmail.com> wrote:

> Tried what you said. Here is what {{ item }} look like:
>
> [(u'sssd', {u'debug_level': 5, u'reconnection_retries': 3,
> u'config_file_version': 2, u'sbus_timeout': 30})]
> [(u'services', [u'nss', u'pam', u'ssh'])]
>
> What should I do next?

Fit the template to your needs. For example the template

{% for item in sssd_config.items() %}
[{{ item.0 }}]
{{ item.1.keys().0 }}={{ item.1.values().0 }}
{% endfor %}

gives

[nss]
reconnection_retries=3
[pam]
debug_level=5
[sssd]
debug_level=1

HTH,

-vlado

Vladimir Botka

unread,
Jan 15, 2020, 1:56:58 PM1/15/20
to Xinhuan Zheng, ansible...@googlegroups.com
On Wed, 15 Jan 2020 19:47:23 +0100
Vladimir Botka <vbo...@gmail.com> wrote:

> Fit the template to your needs. For example the template
>
> {% for item in sssd_config.items() %}
> [{{ item.0 }}]
> {{ item.1.keys().0 }}={{ item.1.values().0 }}
> {% endfor %}
>
> gives
>
> [nss]
> reconnection_retries=3
> [pam]
> debug_level=5
> [sssd]
> debug_level=1

There might be more items in the configuration sections. The template
below gives the same result and would include other parameters if present

{% for item in sssd_config.items() %}
[{{ item.0 }}]
{% for iitem in item.1.items() %}
{{ iitem.0 }}={{ iitem.1 }}

Xinhuan Zheng

unread,
Jan 15, 2020, 2:57:49 PM1/15/20
to Ansible Project
I tested the solution, it doesn't work. item.1 becomes:
{u'id_provider': u'local', u'auth_provider': u'local', u'enumerate': True}

So I get error there is no keys on {{ item.1.keys().0 }}

- Xinhuan

Xinhuan Zheng

unread,
Jan 15, 2020, 3:00:41 PM1/15/20
to Ansible Project
Got this error:

"AnsibleUndefinedVariable: 'list object' has no attribute 'items' for item.1.items()

- Xinhuan

Vladimir Botka

unread,
Jan 15, 2020, 3:45:44 PM1/15/20
to Xinhuan Zheng, ansible...@googlegroups.com
On Wed, 15 Jan 2020 11:57:49 -0800 (PST)
Xinhuan Zheng <xinhua...@gmail.com> wrote:

> I tested the solution, it doesn't work. item.1 becomes:
> {u'id_provider': u'local', u'auth_provider': u'local', u'enumerate': True}
> So I get error there is no keys on {{ item.1.keys().0 }}

Both versions works for me. Double-check the code. The playbook

- hosts: localhost
vars:
sssd_config:
sssd:
debug_level: 1
nss:
reconnection_retries: 3
pam:
debug_level: 5
tasks:
- template:
src: template.j2
dest: config.ini

with the template

% for item in sssd_config.items() %}
[{{ item.0 }}]
{{ item.1.keys().0 }}={{ item.1.values().0 }}
{% endfor %}
# ------------------------------------------
{% for item in sssd_config.items() %}
[{{ item.0 }}]
{% for iitem in item.1.items() %}
{{ iitem.0 }}={{ iitem.1 }}
{% endfor %}
{% endfor %}

gives

[nss]
reconnection_retries=3
[pam]
debug_level=5
[sssd]
debug_level=1
# ------------------------------------------
[nss]
reconnection_retries=3
[pam]
debug_level=5
[sssd]
debug_level=1

--

Xinhuan Zheng

unread,
Jan 16, 2020, 8:49:07 AM1/16/20
to Ansible Project
Hello,

Your testing looks fine in the test data model. However, the sssd_config real data model is like below:

    sssd_config:
      sssd:
        debug_level: 1
        additional_key: additional_value
        another_addtional_key: another_additional_value
      nss:
        reconnection_retries: 3
        additional_key: additional_value
        another_addtional_key: another_additional_value
      pam:
        debug_level: 5
        additional_key: additional_value
        another_addtional_key: another_additional_value

The addtional_key and another_additional_key isn't same per section (pam,nss,sssd), and number of additional_key per section isn't identical either. So nss section may have 5 key/value pairs, pam may have 6 key/value pairs, and sssd may have only 3 key/value pairs. Each additional_key is pretty much unique to that section.

Because this is so difficult to manipulate in template (I spend most yesterday to figure it out), I think it is probably better just put INI-style content into template file, then fill in the values from variables that varies for that key/value pair. It makes the work more simpler.

Thank you for providing the test case. I'll remember this lesson.

- Xinhuan

Vladimir Botka

unread,
Jan 16, 2020, 10:50:25 AM1/16/20
to Xinhuan Zheng, ansible...@googlegroups.com
On Thu, 16 Jan 2020 05:49:07 -0800 (PST)
Xinhuan Zheng <xinhua...@gmail.com> wrote:

> sssd_config:
> sssd:
> debug_level: 1
> additional_key: additional_value
> another_addtional_key: another_additional_value
> nss:
> reconnection_retries: 3
> additional_key: additional_value
> another_addtional_key: another_additional_value
> pam:
> debug_level: 5
> additional_key: additional_value
> another_addtional_key: another_additional_value
>
> Because this is so difficult to manipulate in template (I spend most
> yesterday to figure it out), I think it is probably better just put
> INI-style content into template file

It also possible to use module 'ini_file'
https://docs.ansible.com/ansible/latest/modules/ini_file_module.html

With the configuration data transformed to this list

sssd_config:
- params:
- additional_key: additional_value
- reconnection_retries: 3
- another_addtional_key: another_additional_value
section: nss
- params:
- debug_level: 5
- another_addtional_key: another_additional_value
- additional_key: additional_value
section: pam
- params:
- debug_level: 1
- another_addtional_key: another_additional_value
- additional_key: additional_value
section: sssd

the task below

- ini_file:
path: /scratch/tmp/config.ini
section: "{{ item.0.section }}"
option: "{{ item.1.keys()|list|first }}"
value: "{{ item.1.values()|list|first }}"
with_subelements:
- "{{ sssd_config }}"
- params

gives

$ cat /scratch/tmp/config.ini
[nss]
additional_key = additional_value
reconnection_retries = 3
another_addtional_key = another_additional_value
[pam]
debug_level = 5
another_addtional_key = another_additional_value
additional_key = additional_value
[sssd]
debug_level = 1
another_addtional_key = another_additional_value
additional_key = additional_value

--

Xinhuan Zheng

unread,
Jan 16, 2020, 12:08:29 PM1/16/20
to Ansible Project
Hello Mr. Botka,

This is exactly what I am looking for. It looks so neat with ini_file module instead of template. I'll play with it in my tasks.

Thank you very much! :)

- Xinhuan
Reply all
Reply to author
Forward
0 new messages