05-03-2023 06:45 AM
Is it possible for an nso (python) service to call an other nso (python) service?
For instance:
service X -> service Y
I was looking at cb_post_modification, but it looks like it doesn't achieve the desired result.
Example python code of service X:
class ServiceCallbacks(Service):
@service.create
def cb_create(self, tctx, root, service, proplist):
self.log.info('Service create(service=', service._path, ')')
template = ncs.template.Template(service)
template_vars = ncs.template.Variables()
@service.post_modification
def cb_post_modification(self, tctx, op, kp, root, proplist):
self.log.info('Service postmod(service=', kp, ')')
service = ncs.maagic.cd(root, kp)
leafref = root.services.X[service.X]
with ncs.maapi.single_write_trans('admin', 'python') as t:
root = ncs.maagic.get_root(t)
root.services.Y.create(leafref)
t.apply()
Also because service Y uses a leafref, i am not sure how it should be referenced
Solved! Go to Solution.
05-03-2023 07:50 AM - edited 05-03-2023 07:52 AM
Hi, I am not sure I follow exactly what you are trying to achieve but I will try to answer anyway.
One service creating another service is something we usually call a stacked service.
See the following example:
leaf device {
type leafref {
path "/ncs:devices/ncs:device/ncs:name";
}
}
leaf dummy {
type inet:ipv4-address;
}
@service.create
def cb_create(self, tctx, root, service, proplist):
self.log.info('Service create(service=', service._path, ')')
servicey = root.servicey.create(service.name + '-created-y')
servicey.dummy = '127.0.0.1'
servicey.device = 'c0'
admin@ncs% commit dry-run
cli {
local-node {
data +servicey test-service-created-y {
+ device c0;
+ dummy 127.0.0.1;
+}
+servicex test-service {
+}
}
}
Here ServiceX will create ServiceY inside the create callback. The leafref to the device is referenced by name "c0". If there is no such device the commit will fail with "Aborted: illegal reference 'servicey test-service-created-y device'
05-04-2023 05:05 AM
In this case the GUI is trying to be helpful by validating the changes before doing commit. You will see the same thing in the CLI if you do "validate".
admin@ncs% commit dry-run
cli {
local-node {
data -servicey newservice {
-}
-servicex newservice {
-}
}
}
admin@ncs% validate
Failed: illegal reference 'servicey newservice name'
[error][2023-05-04 13:38:05]
And this isn't incorrect since ServiceY requires a ServiceX to exist, but behaves differently in the CLI because it doesn't prevent the commit the way the GUI does. In order to remove this dependency you can use a non-strict leafref.
leaf name {
type string;
tailf:non-strict-leafref {
path "/ncs:services/X:X/X:name";
}
}
Since ServiceY has a dependency on ServiceX these types of issues can occur.
I am curious why you want to have a leafref to ServiceX from ServiceY and if there is an alternative solution to your problem. These kinds of circular dependencies can be difficult to work with.
05-03-2023 07:50 AM - edited 05-03-2023 07:52 AM
Hi, I am not sure I follow exactly what you are trying to achieve but I will try to answer anyway.
One service creating another service is something we usually call a stacked service.
See the following example:
leaf device {
type leafref {
path "/ncs:devices/ncs:device/ncs:name";
}
}
leaf dummy {
type inet:ipv4-address;
}
@service.create
def cb_create(self, tctx, root, service, proplist):
self.log.info('Service create(service=', service._path, ')')
servicey = root.servicey.create(service.name + '-created-y')
servicey.dummy = '127.0.0.1'
servicey.device = 'c0'
admin@ncs% commit dry-run
cli {
local-node {
data +servicey test-service-created-y {
+ device c0;
+ dummy 127.0.0.1;
+}
+servicex test-service {
+}
}
}
Here ServiceX will create ServiceY inside the create callback. The leafref to the device is referenced by name "c0". If there is no such device the commit will fail with "Aborted: illegal reference 'servicey test-service-created-y device'
05-03-2023 11:31 AM
Creation seems to work perfect.
Only the deletion of the stacked service doesn't seems to work.
05-03-2023 11:14 PM
What does your code look like now?
This is what you should see when deleting servicex.
admin@ncs% delete servicex test-service
[ok][2023-05-04 08:13:27]
[edit]
admin@ncs% commit dry-run
cli {
local-node {
data -servicey test-service-created-y {
- device c0;
- dummy 127.0.0.1;
-}
-servicex test-service {
-}
}
}
[ok][2023-05-04 08:13:28]
05-04-2023 02:05 AM
Just tested, if i delete it from the ncs_cli, it can be deleted.
But if i delete it from the GUI (NSO 5.6.1), then it gives a reference error. (a bug maybe?)
05-04-2023 02:31 AM
It should work for both, I did not see any issues using the GUI.
I saw that you used post_modification in your first post and just want to mention that configuration set in post_mod (and pre_mod) is not automatically removed when the service is deleted. Those callbacks are handled differently.
05-04-2023 04:11 AM
Config now looks like this, already removed the post_modification
Yang service X
key "name";
leaf name{
type string;
}
Python Service X
class ServiceCallbacks(Service):
@service.create
def cb_create(self, tctx, root, service, proplist):
self.log.info('Service create(service=', service._path, ')')
template = ncs.template.Template(service)
template_vars = ncs.template.Variables()
root.services.Y.create(service.X)
Yang service Y
key name ;
leaf name {
type leafref {
path "/ncs:services/X:X/X:name";
}
}
05-04-2023 05:05 AM
In this case the GUI is trying to be helpful by validating the changes before doing commit. You will see the same thing in the CLI if you do "validate".
admin@ncs% commit dry-run
cli {
local-node {
data -servicey newservice {
-}
-servicex newservice {
-}
}
}
admin@ncs% validate
Failed: illegal reference 'servicey newservice name'
[error][2023-05-04 13:38:05]
And this isn't incorrect since ServiceY requires a ServiceX to exist, but behaves differently in the CLI because it doesn't prevent the commit the way the GUI does. In order to remove this dependency you can use a non-strict leafref.
leaf name {
type string;
tailf:non-strict-leafref {
path "/ncs:services/X:X/X:name";
}
}
Since ServiceY has a dependency on ServiceX these types of issues can occur.
I am curious why you want to have a leafref to ServiceX from ServiceY and if there is an alternative solution to your problem. These kinds of circular dependencies can be difficult to work with.
05-08-2023 01:12 AM
With the non-strict-leafref it works perfectly.
For us its important service X is an service which only exists in the cdb and relates to different services.
Except in some cases there is a little bit of configuration needed, and we don't want to create 1 very complex service.
05-04-2023 05:46 AM
Yes you can.
But you should not be creating a separate transaction. Just create the service directly in the create callback if you want to do it in python, or alternatively and I think typically better, I would add the service that needs to be created into the template of the X service.
A leafref is just a leaf so it should just be referenced like any leaf. Setting the type as leafref just constrains its value.
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