OPNsense Forum

English Forums => Development and Code Review => Topic started by: ndejong on August 22, 2018, 02:52:03 am

Title: [SOLVED] Accessing the UUID of a config item in (Jinja2) templates
Post by: ndejong on August 22, 2018, 02:52:03 am
I'm having a challenge in figuring out out to obtain the UUID of an item when rendering templates - by way of example I have this configuration structure:-
Code: [Select]
<VerbNetworks>
  <autossh version="0.1.0">
    <tunnels>
      <tunnel uuid="490829b9-f1b0-42ad-8dad-182de0c06afb">
        <user>myuser</name>
        <host>panic.verbnetworks.com</type>
      </tunnel>
    </tunnels>
  </autossh>
</VerbNetworks>

I note the template helper functions `getUUID()` and `getUUIDtag()` in `template_helpers.py` that take a UUID as an input parameter and return data associated with that UUID - this is not what I want despite the `getUUID()` function having a correct sounding name.

What (I think) I want to write is something like the following:-
Code: [Select]
{% for tunnel_uuid, tunnel_item in 'VerbNetworks.autossh.tunnels.tunnel'.iteritems() %}
[autossh_{{ tunnel_uuid }}]
{% endfor %}
It is not clear to me how to write or express the tag-name that gets passed to `.iteritems()` and thus the above code fails.

In a maybe-perfect world it might be nice if you could obtain a list of UUIDs for a tag-name using a helper function that I imagine might be called "getUUIDs()"
Code: [Select]
{% for tunnel_uuid in helpers.getUUIDs('VerbNetworks.autossh.tunnels.tunnel') %}
{% set tunnel = helpers.getUUID(tunnel_uuid) %}
Host {{ tunnel_uuid }}
  User {{ tunnel.user }}
  HostName {{ tunnel.host }}
{% endfor %}

Before I set about trying to write and introduce such a new helper function is there another way of achieving what I'm setting out to do here?
Title: Re: Accessing the UUID of a config item in (Jinja2) templates
Post by: fabian on August 22, 2018, 06:26:36 pm
Sure it works - with a really dirty workaround:

https://github.com/opnsense/plugins/blob/94a55d5e61668ed13cc4cc245911294d9dadcfc2/www/nginx/src/opnsense/service/templates/OPNsense/Nginx/http.conf#L138-L144

If you write a helper method, it would be probably a better solution.

Title: Re: Accessing the UUID of a config item in (Jinja2) templates
Post by: AdSchellevis on August 22, 2018, 06:42:06 pm
Hi Nicholas,

I think you just want to iterate the items in the tunnel section, normally you should be able to do something similar to this:

Code: [Select]
{%  if helpers.exists('VerbNetworks.autossh.tunnels.tunnel') %}
{%    for tunnel in helpers.toList('VerbNetworks.autossh.tunnels.tunnel') %}
{{tunnel.user}} {{tunnel.host}}
{%    endfor %}
{%  endif %}


The core repository contains quite some examples of constructions like these, for example
https://github.com/opnsense/core/blob/master/src/opnsense/service/templates/OPNsense/Filter/filter_tables.conf

If you need the uuid of the item itself, I'll have to check if/how you can reach that. We normally write the unique identification for the record in a model field as well if we need it.

Best regards,

Ad
Title: Re: Accessing the UUID of a config item in (Jinja2) templates
Post by: fabian on August 22, 2018, 07:17:18 pm
@ad the code I've linked does the reverse. If you iterate over a list of elements without a previous reference, you have no designed to use way to get the uuid of the current node. In my case I use the uuid to reference them.
Title: Re: Accessing the UUID of a config item in (Jinja2) templates
Post by: ndejong on August 22, 2018, 07:22:50 pm
ahh - I just took this up as an issue in between this being posted - you guys are awesome.

https://github.com/opnsense/core/issues/2664

N
Title: Re: Accessing the UUID of a config item in (Jinja2) templates
Post by: ndejong on August 22, 2018, 07:26:04 pm
.... actually, there is a subtle but important difference, that is being able to access the UUID - the `toList()` approach does not allow you to access the item UUID
Title: Re: Accessing the UUID of a config item in (Jinja2) templates
Post by: ndejong on August 22, 2018, 07:39:43 pm
If I understand things correctly, the Nginx workaround approach looks dangerous for the same reason as I describe in the Issue, that is, you can very easily have a name collision among plugins.

As in the Nginx example, it would be pretty easy for another plugin to use a tag-name "server"
Title: Re: Accessing the UUID of a config item in (Jinja2) templates
Post by: fabian on August 22, 2018, 07:58:10 pm
It is not dangerous - it compares the object with each other which means that it compares the internal references of the interpreter. This means that it easily breaks if I would get a copy of the original object (understand it as something similar like comparing C pointers).  server is my current element in the loop - not an element name. It is just a pice of code that should never be in a template but there is currently no alternative.
Title: Re: Accessing the UUID of a config item in (Jinja2) templates
Post by: ndejong on August 22, 2018, 08:35:46 pm
Ahh, thanks for helping me see though this - I missed where the that `server` variable was coming from - putting a PR together now for this then:-

Code: [Select]
    def getUUIDs(self, tag):
        """ retrieve a list of uuids from the item list returned by tag
        :param tag: tag in dot notation (section.item)
        :return: []
        """
        uuids = []
        for item in self.toList(tag):
            for uuid in self._template_in_data['__uuid__']:
                if self._template_in_data['__uuid__'][uuid] == item:
                    uuids.append(uuid)
        return uuids
Title: Re: Accessing the UUID of a config item in (Jinja2) templates
Post by: ndejong on August 22, 2018, 09:01:38 pm
Pull request here:-
https://github.com/opnsense/core/pull/2665

In other news I need help de-tangling my commits, this PR includes previous commits - gack - will figure it out tomorrow I guess
Title: Re: Accessing the UUID of a config item in (Jinja2) templates
Post by: fabian on August 22, 2018, 10:17:33 pm
you should change it anyway - UUIDs are unique. If you have found it, you can return.
Title: Re: Accessing the UUID of a config item in (Jinja2) templates
Post by: ndejong on August 23, 2018, 02:57:53 am
there is a
Code: [Select]
return uuids statement missing at the end of my cut-n-paste - chat on the PR about it
Title: Re: Accessing the UUID of a config item in (Jinja2) templates
Post by: ndejong on August 27, 2018, 01:39:40 am
Resolution on this has been that @AdSchellevis added the UUID to items via a `@uuid` parameter, thus enabling the ability to write as such:
Code: [Select]
{{item['@uuid']}}

Reference to the discussion on Github:-
https://github.com/opnsense/core/issues/2664#issuecomment-415675706

Thanks @AdSchellevis !!