Extract IPv6 link-local address from facts

Hello ansible people,

I want to extract an interface’s IPv6 link-local address from facts. I’ve figured out a round-about way of doing this in a template. I do:

{% for v6 in hostvars[inventory_hostname][‘ansible_em1’][‘ipv6’] %}

{% if v6.scope == ‘link’ %}

{{v6.address}};

{% endif %}

{% endfor %}

However, I don’t know how to do this in a playbook where I wish to use the link-local address in a task. Any suggestions?

Regards,

Anand

There will be cleaner ways to do this once jinja2.7 becomes more
readily available, but for now you could probably simulate the above
loop with 'with_items' and a 'when' conditional:

tasks:
   - name: ipv6 link local
     debug: msg="{{ item.address }}"
     when: item.scope == 'link'
     with_items: ansible_em1.ipv6

Yes, this is an ugly hack.

K

Kahlil (Kal) Hodgson GPG: C9A02289
Head of Technology (m) +61 (0) 4 2573 0382
DealMax Pty Ltd (w) +61 (0) 3 9008 5281

Suite 1415
401 Docklands Drive
Docklands VIC 3008 Australia

"All parts should go together without forcing. You must remember that
the parts you are reassembling were disassembled by you. Therefore,
if you can't get them together again, there must be a reason. By all
means, do not use a hammer." -- IBM maintenance manual, 1925

Hi Kahlil,

Thank you for this tip. It works!

So you mentioned that with Jinja 2.7 this is easier. I already have Jinja 2.7.1. What feature of this version can I use to avoid this hack?

Regards,

Anand

Glad that helps.

In Jinja2.7 you have the following filters that can be used to traverse or extract parts of lists:

select
selectattr
reject
rejectattr
map

so I believe that following would work

{{ ansible_em1.ipv6 | selectattr(‘scope’, ‘local’) | first | attr(‘address’) }}

just off the top of my head and untested.

Check out http://jinja.pocoo.org/docs/templates/#list-of-builtin-filters

for more details.

Cheers!

Kal

Kahlil (Kal) Hodgson GPG: C9A02289
Head of Technology (m) +61 (0) 4 2573 0382
DealMax Pty Ltd (w) +61 (0) 3 9008 5281

Suite 1415
401 Docklands Drive
Docklands VIC 3008 Australia

“All parts should go together without forcing. You must remember that
the parts you are reassembling were disassembled by you. Therefore,
if you can’t get them together again, there must be a reason. By all
means, do not use a hammer.” – IBM maintenance manual, 1925

Hi Kahlil,

In Jinja2.7 you have the following filters that can be used to traverse or extract parts of lists:

select
selectattr
reject
rejectattr
map

so I believe that following would work

{{ ansible_em1.ipv6 | selectattr(‘scope’, ‘local’) | first | attr(‘address’) }}

just off the top of my head and untested.

Your example looks logical, and looks like it should work, but I get this error when trying to use it:

TASK: [debug msg=‘{{ansible_em1.ipv6 | selectattr(“scope”, “local”) | first | attr(“address”)}}’] ***

fatal: [ns1.ams.authdns.ripe.net] => Traceback (most recent call last):

File “/Users/anandb/git/gii-ansible/portable/lib/ansible/runner/init.py”, line 394, in _executor

exec_rc = self._executor_internal(host, new_stdin)

File “/Users/anandb/git/gii-ansible/portable/lib/ansible/runner/init.py”, line 485, in _executor_internal

return self._executor_internal_inner(host, self.module_name, self.module_args, inject, port, complex_args=complex_args)

File “/Users/anandb/git/gii-ansible/portable/lib/ansible/runner/init.py”, line 679, in _executor_internal_inner

module_args = template.template(self.basedir, module_args, inject, fail_on_undefined=self.error_on_undefined_vars)

File “/Users/anandb/git/gii-ansible/portable/lib/ansible/utils/template.py”, line 319, in template

varname = template_from_string(basedir, varname, vars, fail_on_undefined)

File “/Users/anandb/git/gii-ansible/portable/lib/ansible/utils/template.py”, line 539, in template_from_string

res = jinja2.utils.concat(rf)

File “”, line 12, in root

File “/Users/anandb/git/gii-ansible/portable/lib/jinja2/filters.py”, line 349, in do_first

return next(iter(seq))

File “/Users/anandb/git/gii-ansible/portable/lib/jinja2/filters.py”, line 931, in _select_or_reject

if modfunc(func(transfunc(item))):

File “/Users/anandb/git/gii-ansible/portable/lib/jinja2/filters.py”, line 925, in

name, item, args, kwargs)

File “/Users/anandb/git/gii-ansible/portable/lib/jinja2/environment.py”, line 438, in call_test

raise TemplateRuntimeError(‘no test named %r’ % name)

TemplateRuntimeError: no test named ‘local’

I tried to use Google to look for examples on how to use selectattr, but found nothing useful. The Jinja2 documentation for this filter is quite sparse. If anyone has any more suggestions, I’d be grateful.

Anand

Hi Anand,

Looking at the documentation again, it seems I misinterpreted: i did
not realise that 'none' is a jinja test not a value. It seems the
second argument to selectattr is a test (see the last line of the
backtrace), which makes more sense now that I think of it.

Not sure how to insert an equality test into this using jinja
constructs. Docs do not show a builtin equality test. Hmm had a
quick dive into the jinja2 code on git hub and found this gem about
the undocumented 'equalto' test


    This appears to be a useless test as it does exactly the same as the
    ``==`` operator, but it can be useful when used together with the
    `selectattr` function:

    .. sourcecode:: jinja

        {{ users|selectattr("email", "equalto", "foo@bar.invalid") }}

So I think the following might work:

{{ ... | selectattr('scope', 'equalto', 'local') | ... }}

Hope this helps,

K

Kahlil (Kal) Hodgson GPG: C9A02289
Head of Technology (m) +61 (0) 4 2573 0382
DealMax Pty Ltd (w) +61 (0) 3 9008 5281

Suite 1415
401 Docklands Drive
Docklands VIC 3008 Australia

"All parts should go together without forcing. You must remember that
the parts you are reassembling were disassembled by you. Therefore,
if you can't get them together again, there must be a reason. By all
means, do not use a hammer." -- IBM maintenance manual, 1925

Further note: just check the timestamp on the commit that introduced
the 'equalto' test (2013-11-22),
so that might not be in the version you are using.

K

Kahlil (Kal) Hodgson GPG: C9A02289
Head of Technology (m) +61 (0) 4 2573 0382
DealMax Pty Ltd (w) +61 (0) 3 9008 5281

Suite 1415
401 Docklands Drive
Docklands VIC 3008 Australia

"All parts should go together without forcing. You must remember that
the parts you are reassembling were disassembled by you. Therefore,
if you can't get them together again, there must be a reason. By all
means, do not use a hammer." -- IBM maintenance manual, 1925

Hi Kahlil,

Further note: just check the timestamp on the commit that introduced
the ‘equalto’ test (2013-11-22),
so that might not be in the version you are using.

Thank you for taking the time to dig into this, and discovering the “equalto” test. I appreciate it a lot! It doesn’t work on my systems yet, because I have Jinja 2.7.1, which was released on 7-Aug-2013. I will keep an eye on Jinja releases, and update my module and playbook when the equalto test becomes available.

Regards,

Anand

Hi again Kahlil,

I branched my ansible setup, and patched jinja2 with the commit from github to add the “equalto” test.

So I think the following might work:

{{ … | selectattr(‘scope’, ‘equalto’, ‘local’) | … }}

So in my playbook I wrote:

debug: msg=‘{{ ansible_em1.ipv6 | selectattr(“scope”, “equalto”, “link”) | first | attr(“address”) }}’

But now I get the error message:

TASK: [debug msg=‘{{ansible_em1.ipv6 | selectattr(“scope”, “equalto”, “link”) | first | attr(“address”)}}’] ***

fatal: [ns1.ams.authdns.ripe.net] => One or more undefined variables: ‘dict object’ has no attribute ‘address’

This is getting weirder!

Hi Anand,

Fun though it may be, I hope we are not getting too off-topic by
discussing new and obscure jinja2 features on the ansible list :slight_smile:

I currently don't have things set up to test this, so I'm just making
guesses based on the documentation and eye-balling the code.

My next thought is to see what we are passing to the last link in the
filter chain with

{{ansible_em1.ipv6 | selectattr("scope", "equalto", "link") | first | pprint }}

K

Kahlil (Kal) Hodgson GPG: C9A02289
Head of Technology (m) +61 (0) 4 2573 0382
DealMax Pty Ltd (w) +61 (0) 3 9008 5281

Suite 1415
401 Docklands Drive
Docklands VIC 3008 Australia

"All parts should go together without forcing. You must remember that
the parts you are reassembling were disassembled by you. Therefore,
if you can't get them together again, there must be a reason. By all
means, do not use a hammer." -- IBM maintenance manual, 1925

Hi Anand,

Fun though it may be, I hope we are not getting too off-topic by
discussing new and obscure jinja2 features on the ansible list :slight_smile:

I hope so too, but no-one has told us to shut up, so maybe they also want to use about this feature.

I currently don’t have things set up to test this, so I’m just making
guesses based on the documentation and eye-balling the code.

My next thought is to see what we are passing to the last link in the
filter chain with

{{ansible_em1.ipv6 | selectattr(“scope”, “equalto”, “link”) | first | pprint }}

This gives me:

TASK: [debug msg=‘{{ansible_em1.ipv6 | selectattr(“scope”, “equalto”, “link”) | first | pprint}}’] ***

ok: [ns1.ams.authdns.ripe.net] => {

“msg”: “{uaddress: ufe80::baca:3aff:feee:daf3, uprefix: u64, uscope: ulink}”

}

So it looks like a dictionary with an attribute called “address”. But then using attr() fails.