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:-
<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:-
{% 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()"
{% 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?
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.
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:
{% 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
@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.
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
.... 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
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"
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.
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:-
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
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
you should change it anyway - UUIDs are unique. If you have found it, you can return.
there is a return uuids
statement missing at the end of my cut-n-paste - chat on the PR about it
Resolution on this has been that @AdSchellevis added the UUID to items via a `@uuid` parameter, thus enabling the ability to write as such:
{{item['@uuid']}}
Reference to the discussion on Github:-
https://github.com/opnsense/core/issues/2664#issuecomment-415675706
Thanks @AdSchellevis !!