02-13-2018 05:33 PM - edited 03-01-2019 04:05 AM
Anyone have an example on how to reference nested yang objects in python ? For example, if my yang model is:
container a
container b
leaf c
container d
list e
What would be the the python service or root path ?
service.???
root.???
Solved! Go to Solution.
02-15-2018 05:36 PM
In you service callback:
def cb_create(self, tctx, root, service, proplist):
You have a paremeter named service, that is what we're referring to above with e.g. service.templates.template_content.routermap_name.
So let's say you create an instance of your service named foo.
That means that the "service" parameter in cb_create "points" to /device-template{foo}
So if you do self.log.info(service.name) you can expect to see "foo" in the logs.
Now, the root object "points" to /.
To get to your service instance, you have to do root.device_template["foo"] (this is basically root.device_template[service.name]).
So self.log.info(root.device_template["foo"].name) will also print "foo" to the logs.
02-14-2018 01:19 AM
Assuming your service model looks something like this:
module myservice {
prefix mysvc;
container myservices {
list myservice {
ncs:servicepoint myservice;
...
key name;
leaf name { type string; }
container a {
container b {
leaf c { type string; }
}
}
container d {
list e {
...
}
}
}
}
}
Your python copde would access the leaf c in the particular service instance like this:
class ServiceCallbacks(ncs.application.Service):
@ncs.application.Service.create
def cb_create(self, tctx, root, service, proplist):
the_c = service.a.b.c
# When navigating from the root, we need to specify which service instance
# we're talking about. Assuming we want to access the current service instance
# it has key service.name
c_from_the_root = root.myservices.myservice[service.name].a.b.c
When you cross over from one namespace to another, or if your YANG model uses names that are keywords in Python, you will need to specify the namespace prefix as well. Let's pretend that b is in one of these cases, then you can always add the namespace name and two underscore characters in front of each name, like this:
the_c = service.a.mysvc__b.c
Hope this helps.
02-14-2018 11:17 AM
One addition questions. If the container/leaf/list has a hyphen in the yang, it needs to be replaced with an underscore (_) correct ?
02-14-2018 05:32 PM
Yup... but that's just because python sees "-" as "minus"....
(if you use underscore in yang it requires no change in Python)
cheers
gregg
02-14-2018 06:38 PM
I am having troubles getting past the first list in the yang model. Could you provide the path to get to leaf "routemap-name" ?
I have tried below with no luck:
root.services.device_template.templates.template_contents.routemap_name
root.device_template.templates.template_contents.routemap_name
services.device_template.templates.template_contents.routemap_name
root.services.device_template__device_template.device_template__templates.device_template__template_contents.device_template__routemap_name
root.device_template__device_template.device_template__templates.device_template__template_contents.device_template__routemap_name
services.device_template__device_template.device_template__templates.device_template__template_contents.device_template__routemap_name
YANG:
list device-template
leaf name
uses ncs:service-data;
ncs:servicepoint device-template-servicepoint;
leaf-list device
...
container templates
container template-contents
leaf routemap-name
02-14-2018 07:49 PM
If you have a device-template list instance called "foo", you access it in python:
root.device_template["foo"].templates.template_content.routermap_name
02-14-2018 10:00 PM
Thanks. I guess I should have mentioned what exactly I was trying to do as it looks like this method wont work, as it requires you to know the list key value. All that I am trying to do is capture the values entered into the yang model, assign them to a variable and the ship them off to the xml template. Is there a better method/function I should be using ?
02-14-2018 10:03 PM
aha, so in your service callback, you have two options, I'd prefer the first:
service.templates.template_content.routermap_name
-or-
root.device_template[service.name].templates.template_content.routermap_name
02-15-2018 07:31 AM
Thanks. Do you know what the difference between these two calls are ?
02-15-2018 07:47 AM
The first one is 30% shorter to write.
Seriously, you'd start from service if the data you're looking for is inside the service instance being created/edited. If you need to navigate to something else, e.g. into another service instance, then start at the root.
02-15-2018 12:30 PM
I'm all for shorter code
But what is said is exactly what I was wondering.
Jan Lindblad wrote:
.......If you need to navigate to something else, e.g. into another service instance, then start at the root.
Also I tried both ways, but the plain 'services.' way without 'root.' before it doesnt seem to work. I also dont see 'services.' in ipython whereas I do see 'root.'
[Doesnt work] service.templates.template_content.routermap_name
[Works] root.device_template[service.name].templates.template_content.routermap_name
==> ncs-python-vm-test.log <==
2018-02-15 15:27:35 - test - DEBUG - TransactionCallback.cb_init()
2018-02-15 15:27:35 - test - INFO - Service create(service=/ncs:services/test:test{1})
2018-02-15 15:27:35 - test - ERROR - global name 'services' is not defined
2018-02-15 15:27:35 - test - ERROR - Traceback (most recent call last):
File "/home/cisco/nso-4.4.4.1/src/ncs/pyapi/ncs/application.py", line 340, in wrapper
pl = fn(self, tctx, root, service, proplist)
File "/home/cisco/nso-4.4.4.1/ncs-run/state/packages-in-use/1/test/python/test/main.py", line 17, in cb_create
tportchannel1_number = services.test__test[service.name]. \
NameError: global name 'services' is not defined
02-15-2018 02:28 PM
You have a typo there though, "services" => "service"
02-15-2018 03:15 PM
with "service."
admin@ncs(config-template-contents)# commit dry-run
Aborted: Python cb_create error. 'ListElement' object has no attribute 'test__test'
==> ncs-python-vm-test.log <==
2018-02-15 18:13:29 - test - ERROR - Traceback (most recent call last):
File "/home/cisco/nso-4.4.4.1/src/ncs/pyapi/ncs/application.py", line 340, in wrapper
pl = fn(self, tctx, root, service, proplist)
File "/home/cisco/nso-4.4.4.1/ncs-run/state/packages-in-use/1/test/python/test/main.py", line 17, in cb_create
tportchannel1_number = service.test__test[service.name]. \
File "/home/cisco/nso-4.4.4.1/src/ncs/pyapi/ncs/maagic.py", line 438, in __getattr__
super(Node, self).__getattribute__(name)
AttributeError: 'ListElement' object has no attribute 'test__test'
ipython
In [1]: print(root)
(root)
In [2]: print(root.services)
services
In [3]: print(service)
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-3-eb3457d971bb> in <module>()
----> 1 print(service)
NameError: name 'service' is not defined
02-15-2018 05:36 PM
In you service callback:
def cb_create(self, tctx, root, service, proplist):
You have a paremeter named service, that is what we're referring to above with e.g. service.templates.template_content.routermap_name.
So let's say you create an instance of your service named foo.
That means that the "service" parameter in cb_create "points" to /device-template{foo}
So if you do self.log.info(service.name) you can expect to see "foo" in the logs.
Now, the root object "points" to /.
To get to your service instance, you have to do root.device_template["foo"] (this is basically root.device_template[service.name]).
So self.log.info(root.device_template["foo"].name) will also print "foo" to the logs.
02-15-2018 06:46 AM
Robert,
If there is a list in your Service instance yang, presumably it is there to handle the case of multiple entries of that list type per service instance, you'll need to loop through all those entries to get the service data to provide to the template in variables.
If all you are doing in python is reading the service instance data and providing to template via variables, it is better (more efficient) to pass the service instance data directly to the template without invoking the python create code at all.
-Larry
Discover and save your favorite ideas. Come back to expert answers, step-by-step guides, recent topics, and more.
New here? Get started with these tips. How to use Community New member guide