- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
04-11-2020 10:01 PM
Hi, all!
I am trying to construct an xml template for the service. Here is an example of the YANG module I constructed:
... leaf-list device-group { tailf:info "Device group to use"; type leafref { path "/ncs:devices/ncs:device-group/ncs:name"; } } list some-server { key name; leaf name { type string; } } ...
So in XML template I am looping though each device in the device-group, then looping through the some-server list. But while it is inside the some-server loop, I want to reference device name again:
<config-template xmlns="http://tail-f.com/ns/config/1.0" servicepoint="some-point"> <devices xmlns="http://tail-f.com/ns/ncs"> <?foreach {/device-group}?> <device> <name>{deref(.)/../member}</name> <config> <configuration xmlns="http://xml.juniper.net/xnm/1.1/xnm"> <system> <ntp> <?foreach {/some-server}?> <server> <name>{deref(.)/../member}</name> </server> ...
Of course, just placing {deref(.)/../member} will not work. I need to reference the device name, while still in the foreach loop.
I have tried using <?set device-name={deref(.)/../member} ?> (didn't work), tried using {deref(/device-group)/../member}, but it printed devices in the current device-group, instead of a particular device-name.
Does anyone know how to make it work?
Solved! Go to Solution.
- Labels:
-
Other NSO Topics
Accepted Solutions
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
04-13-2020 07:42 AM
As yfherzog suggested, with the advanced template control features, it is quite simple to save the name in a variable that can later be used in your nested loop.
Something like this - devname:
<?foreach {/device-group}?> <device> <name>{deref(.)/../member}</name>
<?set devname = {.}?> <config> <configuration xmlns="http://xml.juniper.net/xnm/1.1/xnm"> <system> <ntp> <?foreach {/some-server}?> <server> <name>{$devname}</name> </server>

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
04-11-2020 11:36 PM
I think it might be possible to find a way to do it using the more advanced template options (if you haven't already, take a look at the development guide under "Processing instructions"), but honestly, I'd advise moving at least some of the iterations from template to Python.
Even if you get it figured out, this template is going to get harder and harder to troubleshoot and to maintain.
It will be cool to get it solved, but it will become this sort of write-only code, which won't be as cool to maintain :)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
04-13-2020 11:20 AM
I would have done it through python main.py file, but the problem is how to use deref here?
So I can loop through device-groups, but then I have a problem accessing device members of that group:
for group in service.device_group: self.log.info('Group name is ',group) for member_name in devices.device_group[group].member: someserver['device_name'] = member_name
Aborted: Python cb_create error. global name 'devices' is not defined
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
04-13-2020 01:25 PM
Use the root input parameter to point to the devices list:
@service.create
def cb_create(self, tctx, root, service, proplist):
devGrp = root.ncs__devices.device_group['nx-dev']
print ("members")
for member in devGrp.member :
print (member)
members
nx-0
nx-1
nx-2
nx-3
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
04-13-2020 02:34 PM
some_service = { 'device_group':{}, } for group in service.device_group: syslog["device_group"][group]={} syslog["device_group"][group]["member"] = {} for member_name in root.devices.device_group[group].member: some_service["device_group"][group]["member"].append(member_name) some_service_tvars=ncs.template.Variables() some_service_tvars.add('DEVICE_GROUP',some_service['device_group']) some_service_template = ncs.template.Template(service) some_service_template.apply('some-service-template', some_service_tvars)
So in the python main.py file I will be able to pull the device-group list, members on that list. But then should I wrap them into a new dictionary, add that dictionary as a template variable and then call it from the xml file?
<config-template xmlns="http://tail-f.com/ns/config/1.0" servicepoint="some-service"> <devices xmlns="http://tail-f.com/ns/ncs"> <?foreach {$DEVICE_GROUP}?> <device> <name>{$member}</name>
Previously I saw examples of creating new global variables in main.py file:
foo = { 'v6_flag':'false', 'v4_flag':'false', } bar_tvars=ncs.template.Variables() bar_tvars.add('V6_FLAG',foo['v6_flag']) bar_tvars.add('V4_FLAG',foo['v4_flag'])
Can you give an example how to add nested dictionary variable via python?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
04-13-2020 04:14 PM
Apparently the solution is to move some_service_tvars under the member loop.
for group in service.device_group: for member_name in root.devices.device_group[group].member: some_service["device_name"]=member_name some_service_tvars=ncs.template.Variables() some_service_tvars.add('DEVICE_NAME',some_service['device_name']) some_service_template = ncs.template.Template(service) some_service_template.apply('some-service-template', some_service_tvars)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
04-14-2020 07:57 AM
Correct, you would need to loop in your code and repetitively call the template with a single set of variables.
Just to elaborate here a bit, the variables passed to the template from your code (be it python, java, erlang..) to the template when the template is applied are passed as _strings_ not in some construct of the code language, such as lists, dictionaries, etc. (this would be quite difficult to implement given the variability of constructs in the different supported languages)

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
04-12-2020 08:00 AM
Try another foreach over the members.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
04-13-2020 07:42 AM
As yfherzog suggested, with the advanced template control features, it is quite simple to save the name in a variable that can later be used in your nested loop.
Something like this - devname:
<?foreach {/device-group}?> <device> <name>{deref(.)/../member}</name>
<?set devname = {.}?> <config> <configuration xmlns="http://xml.juniper.net/xnm/1.1/xnm"> <system> <ntp> <?foreach {/some-server}?> <server> <name>{$devname}</name> </server>
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
04-13-2020 09:52 AM
