08-21-2024 06:58 AM
Hello,
I created a python-and-template skeleton for Vlan service.
Very simple yang:
- vlan ID
- description
- list of switches with an IP address.
The XML configure a "interface vlan <ID> with IP and description.
The idea is to use python to "calculate" the description. In this example, the "calculation" is a string 'Configured by NSO'.
But when I commit, I get the error 'A variable value has not been assigned to: DESCRIPTION'.
Servicepoints seem OK; if I replace $DESCRIPTION by a sring n XML, everything works fine…
So it seems it's an issue in communication between Python and XML.
Any idea ?
admin@ncs(config)# services cfs-vlan VLAN200 cfs-vlan-id 200 cfs_description "*** vlan 200 ***" cfs-switch nx1 cfs-ip-add 200.1.1.1/24
admin@ncs(config-cfs-switch-nx1)# commit dry-run
Aborted: A variable value has not been assigned to: DESCRIPTION
admin@ncs(config-cfs-switch-nx1)#
YANG:
module cfs-vlan {
namespace "http://example.com/cfs-vlan";
prefix cfs-vlan;
augment /ncs:services {
list cfs-vlan {
key cfs-name;
leaf cfs-name {
type string;
}
uses ncs:service-data;
ncs:servicepoint "cfs-vlan-servicepoint";
leaf cfs-vlan-id {
type uint32;
}
leaf cfs_description {
type string;
}
list cfs-switch {
key cfs-switch-name;
unique "cfs-ip-add";
leaf cfs-switch-name {
type leafref {
path "/ncs:devices/ncs:device/ncs:name";
}
}
leaf cfs-ip-add {
type string;
}
}
}
}
}
XML:
<config-template xmlns="http://tail-f.com/ns/config/1.0" servicepoint="cfs-vlan-servicepoint">
<services xmlns="http://tail-f.com/ns/ncs">
<?foreach {/cfs-switch}?>
<rfs-router-intf xmlns="http://example.com/rfs-router-intf">
<rfs-name>{cfs-switch-name)}</rfs-name>
<rfs-device-name>{cfs-switch-name}</rfs-device-name>
<rfs-vlan>
.../...
<rfs-description>{$DESCRIPTION}</rfs-description>
</rfs-vlan>
</rfs-router-intf>
<?end?>
</services>
</config-template>
PYTHON:
class ServiceCallbacks(Service):
@service.create
def cb_create(self, tctx, root, service, proplist):
self.log.info('Service create(service=', service._path, ')')
vars = ncs.template.Variables()
vars.add('DESCRIPTION', 'Configured by NSO')
template = ncs.template.Template(service)
template.apply('cfs-vlan-template', vars)
class Main(ncs.application.Application):
def setup(self):
self.log.info('Main RUNNING')
self.register_service('cfs-vlan-servicepoint', ServiceCallbacks)
MAKEFILE:
[root@nso-dev-nc-nso6 src]#make
pylint --disable=R,C --reports=n ../python/cfs_vlan/*.py || (test $? -ge 4)
************* Module cfs_vlan.main
/root/nso-instance-NOEL/packages/cfs-vlan/python/cfs_vlan/main.py:17:8: W0622: Redefining built-in 'vars' (redefined-builtin)
/root/nso-instance-NOEL/packages/cfs-vlan/python/cfs_vlan/main.py:15:49: W0212: Access to a protected member _path of a client class (protected-access)
------------------------------------------------------------------
Your code has been rated at 8.67/10 (previous run: 8.67/10, +0.00)
Solved! Go to Solution.
08-22-2024 02:11 AM
You have the servicepont in the template and you have it in the python code. The servicepoint in the template is overriding the one in the python so the python code is not being executed.
This happens when you start with a template service and then convert to a python+template and just copy over the template file - I've done it a few times.. better is to keep the skeleton generted template first and last lines and just include the content.
All you need to do is remove the servicepoint attribute in the first line of the template.
08-21-2024 10:00 AM
Can you post the tree output of your package (cd /path/to/your/packages && tree cfs-vlan) and the content of the file /path/to/your/packages/cfs-vlan/package-meta-data.xml?
08-22-2024 12:28 AM
[root@nso-dev-nc-nso6 cfs-vlan]# pwd
/root/nso-instance-NOEL/packages/cfs-vlan
[root@nso-dev-nc-nso6 cfs-vlan]# more package-meta-data.xml
<ncs-package xmlns="http://tail-f.com/ns/ncs-packages">
<name>cfs-vlan</name>
<package-version>1.0</package-version>
<description>Generated Python package</description>
<ncs-min-version>6.3</ncs-min-version>
<component>
<name>main</name>
<application>
<python-class-name>cfs_vlan.main.Main</python-class-name>
</application>
</component>
</ncs-package>
[root@nso-dev-nc-nso6 cfs-vlan]#
08-22-2024 12:33 AM
[root@nso-dev-nc-nso6 cfs-vlan]# tree
.
├── load-dir
│ └── cfs-vlan.fxs
├── package-meta-data.xml
├── python
│ └── cfs_vlan
│ ├── __init__.py
│ └── main.py
├── README
├── src
│ ├── Makefile
│ └── yang
│ └── cfs-vlan.yang
├── templates
│ └── cfs-vlan-template.xml
└── test
├── internal
│ ├── lux
│ │ ├── Makefile
│ │ └── service
│ │ ├── dummy-device.xml
│ │ ├── dummy-service.xml
│ │ ├── Makefile
│ │ ├── pyvm.xml
│ │ └── run.lux
│ └── Makefile
└── Makefile
10 directories, 16 files
08-22-2024 01:04 AM - edited 08-22-2024 01:06 AM
Looking good from my point of view (however, I didn't use NSO much in the last couple of months).
Can you try, delete the loop in the template and instead do the loop in the Python code?
TEMPLATE
<config-template xmlns="http://tail-f.com/ns/config/1.0" servicepoint="cfs-vlan-servicepoint">
<services xmlns="http://tail-f.com/ns/ncs">
<rfs-router-intf xmlns="http://example.com/rfs-router-intf">
<rfs-name>{$SWITCH}</rfs-name>
<rfs-device-name>{$SWITCH}</rfs-device-name>
<rfs-vlan>
.../...
<rfs-description>{$DESCRIPTION}</rfs-description>
</rfs-vlan>
</rfs-router-intf>
</services>
</config-template>
PYTHON
class ServiceCallbacks(Service):
.create
def cb_create(self, tctx, root, service, proplist):
self.log.info('Service create(service=', service._path, ')')
vars = ncs.template.Variables()
template = ncs.template.Template(service)
for sw in service.cfs-switch:
vars.add('SWITCH', sw)
vars.add('DESCRIPTION', 'Configured by NSO')
template.apply('cfs-vlan-template', vars)
class Main(ncs.application.Application):
def setup(self):
self.log.info('Main RUNNING')
self.register_service('cfs-vlan-servicepoint', ServiceCallbacks)
08-22-2024 01:38 AM
<config-template xmlns="http://tail-f.com/ns/config/1.0" servicepoint="cfs-vlan-servicepoint">
<services xmlns="http://tail-f.com/ns/ncs">
<rfs-router-intf xmlns="http://example.com/rfs-router-intf">
<rfs-name>{$SWITCH}</rfs-name>
<rfs-device-name>{$SWITCH}</rfs-device-name>
<rfs-vlan>
<rfs-vlan-id>{$VLANID}</rfs-vlan-id>
<rfs-ip-add>{$IPADD}</rfs-ip-add>
<rfs-description>{$DESCRIPTION}</rfs-description>
</rfs-vlan>
</rfs-router-intf>
</services>
</config-template>
class ServiceCallbacks(Service):
# The create() callback is invoked inside NCS FASTMAP and
# must always exist.
@service.create
def cb_create(self, tctx, root, service, proplist):
self.log.info('Service create(service=', service._path, ')')
vars = ncs.template.Variables()
template = ncs.template.Template(service)
for sw in service.cfs-switch:
vars.add('SWITCH', sw)
vars.add('DESCRIPTION', 'Configured by NSO')
vars.add('VLANID', '12')
vars.add('IPADD', '10.1.1.1/24')
template.apply('cfs-vlan-template', vars)
admin@ncs(config-cfs-switch-nx1)# commit dry-run
Aborted: A variable value has not been assigned to: DESCRIPTION, IPADD, SWITCH, VLANID
08-22-2024 02:04 AM
Also delete the servicepoint from the template:
<config-template xmlns="http://tail-f.com/ns/config/1.0">
<services xmlns="http://tail-f.com/ns/ncs">
<rfs-router-intf xmlns="http://example.com/rfs-router-intf">
<rfs-name>{$SWITCH}</rfs-name>
<rfs-device-name>{$SWITCH}</rfs-device-name>
<rfs-vlan>
<rfs-vlan-id>{$VLANID}</rfs-vlan-id>
<rfs-ip-add>{$IPADD}</rfs-ip-add>
<rfs-description>{$DESCRIPTION}</rfs-description>
</rfs-vlan>
</rfs-router-intf>
</services>
</config-template>
08-22-2024 02:11 AM
You have the servicepont in the template and you have it in the python code. The servicepoint in the template is overriding the one in the python so the python code is not being executed.
This happens when you start with a template service and then convert to a python+template and just copy over the template file - I've done it a few times.. better is to keep the skeleton generted template first and last lines and just include the content.
All you need to do is remove the servicepoint attribute in the first line of the template.
08-22-2024 02:46 AM
And yes it works !!!
Thanks !!
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