cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
1926
Views
2
Helpful
15
Replies

leaf original-value displayed in python service

ryan-hitch
Level 4
Level 4

I am seeing an odd issue where the following python service code is assigning the 'original-value' (999) of a leaf, while if I run the same code from a python shell I see the current value (2004). I am expecting to see the current value (2004) in my service code. Why am I not seeing this?

### Version: NSO 4.5.5

### XML display from ncs_cli

show configuration devices device s02-sw-2 config ios:interface GigabitEthernet 0/1 | display xml

            <vlan refcounter="2"  original-value="999">2004</vlan>

### Code from python service:

vlan = root.devices.device[switch.switch_name].config.ios__interface.GigabitEthernet[switch_interface.switch_interface_id].switchport.access.vlan

self.log.info('ASDF switch:%s service:%s vpn:%s int:%s vlan:%s' % (switch.switch_name, service.name, vpn.name,  switch_interface.switch_interface_id, vlan))

### Logged output from python service (ncs-python-vm-vpn-environment.log)

<INFO> 03-Apr-2018::15:08:18.674 vpn-environment ncs-dp-26855-vpn-environment:main-3-th-6008: - ASDF switch:s02-sw-2 service:CUST1 vpn:TEST1 int:0/1 vlan:999

### Interactive python output

[user@ncs]$ python

Python 2.7.5 (default, Aug  4 2017, 00:39:18)

[GCC 4.8.5 20150623 (Red Hat 4.8.5-16)] on linux2

Type "help", "copyright", "credits" or "license" for more information.

>>> import ncs.maapi as maapi

>>> import ncs.maagic as maagic

>>> m = maapi.Maapi()

>>> m.start_user_session('admin', 'test_context')

>>> t = m.start_write_trans()

>>> root = maagic.get_root(t)

>>> vlan = root.devices.device['s02-sw-2'].config.ios__interface.GigabitEthernet['0/1'].switchport.access.vlan

>>> vlan

2004

>>>

15 Replies 15

Dan.Sullivan
Cisco Employee
Cisco Employee

Hi Ryan,

What you are seeing is by design.Every time you run through your service, you need to set the vlan values to whatever your service logic requires. Once you apply the changes you can read them as you are doing in an interactive Python session.

There is some documentation which can provide additional details.

Thanks,

-Dan

Is there no way to check the actual VLAN value (2004) assigned that is present on that device interface in CDB? I am trying to check that the VLAN value represents an 'unused' VLAN - one that has not already been assigned to a service, to prevent users from inadvertently assigning a service to a port that is already in use (assigned to another instance of the same service). Grabbing the current value assigned to that interface seemed like an easy way to do it. I suppose that I could also search through the interfaces assigned to other instances of the same service as an alternate approach.

Any documentation would be much appreciated. Why is the behavior different for values that already assigned by a service?

Hi Ryan,

If your VLAN was already assigned, you would of course see it in the FASTMAP create. Its only what you set during the FASTMAP which is removed.

-Dan

Hi Ryan,

One more thing, the NSO documentation is in the doc directory under your NSO installation.

-Dan

Thanks, I am aware of the documentation and examples.ncs, but am still confused.

In my current predicament, someone has already assigned a value to this leaf (vlan) using resource-manager and the actual switch is configured with that value. My service code wants to check the value of the leaf and do something based on that value. I thought that I could do this with the following simple variable assignment.

currentvlan = root.devices.device[switch.switch_name].config.ios__interface.GigabitEthernet[switch_interface.switch_interface_id].switchport.access.vlan


Is there a way to check the current value of this leaf?

I really appreciate any help.

An aside:
I am failing to see the logic behind this behavior. If the leaf value had not been assigned with NSO, then NSO would return the current value, however since the leaf value was previously assigned using the NSO resource-manager, the value that is returned to my service code is the 'original-value', rather than the value that is actually configured on the network device at the present time. To my novice NSO developer eyes, this behavior appears inconsistent and could lead to some confusion. I am sure there is a good reason for this.

It is certainly possible for the code to look up the current configuration of the service (by reading from running), but if you're new to NSO and want to do this, you're likely missing some fundamentals of NSO service design philosophy going down this path.

The reason NSO services are typically an order of magnitude less code than traditional service activation code is that they only need to bother about the create case. Delete is much worse, not to mention the real killer: modify existing service. Now you're starting to write code to analyze what the service code did last time around, so effectively writing code for the modify case. In the very rare cases that this is needed, expect to write quite a lot more code to handle odd cases.

So why is it important for your create code to read the old value? Wouldn't it just use the allocator to allocate a reasonable value? If you use the standard resource allocators, they will allocate the same resource for your service every time, if available.

I think there is some confusion on what I am asking. I want to read the current value assigned to the leaf, not the old value. I apologize if I am being obstinate here, but I am just trying to understand.

Scenario:

A service is configured where NOC staff selects a switch interface which will be assigned a VLAN value. The value to be assigned has already been allocated using the id-allocator package. Prior to actually pushing the configuration to the switch, I want to run a check in the service code to make sure that the switch interface is not already configured with a VLAN value used by another NSO service, i.e. NOC staff did not pick an interface that is already used.

My simple way to check this is to try reading the current VLAN value assigned to the switch interface that the NOC staff picked. In our network VLAN 999 is assigned to all unused switch interfaces. Anything else that is configured on an interface should throw an error.

What I am seeing is that my python service code check is returning a value of '999' for all interfaces, even those whose current value is something different. For example, when I read the VLAN value for the following interfaces 0/1 and 0/2, my service code returns the value of 999 for both, even though 2004 is currently assigned to that switch interface on the actual device. I am expecting the return for 0/1 to be 2004, which would then indicate that the interface is in use as it is already assigned to a service.

This is what CDB looks like:

<GigabitEthernet>

  <name>0/1</name>

<vlan refcounter="2"  original-value="999">2004</vlan>

  <name>0/2</name>

<vlan>999</vlan>

At first glance, this appeared to be a quick and easy way to check for used interfaces, though I am finding out that is not the case. If not, what is recommended?

One of the primary purposes with NSO is to make your service code small and simple. The fundamental corner stone in the design to achieve that is to allow the programmer to only write the create() method, and not also the modify() and delete() methods. Requiring the programmer to write them too would obviously mean more code, but since they are generally way more complex than create(), we're speaking about an order of magnitude reduction in effort.


In the world you're coming from, there seems to be two separate use cases you're concerned with. The initial service creation and any subsequent updates. I guess you'd expect the vlan id to be 999 the first time, and the allocated value the next. With this way of thinking, you're already way into that modify() method that we wanted to avoid.


With NSO, there's only one case you need to program: the code for the initial create(). This is obvious for the first time NSO invokes create() for this service instance.


*** What you seem to miss is that if/when NSO calls create() again for an existing service instance, it has undone everything the create() code for this service instance ever did before the call. ***


Of course that undoing has not been communicated to any devices or so, it's just inside the transaction context where the create() code is running. This is what makes it possible to make services work without coding up that modify() method. So when create() runs, the vlan id is back to 999 again, or whatever it was before create() ran the first time.


Then you have the NSO transaction manager that will figure out the actual diff after create() has run. If it yielded the same output again, there will be no diff and nothing is sent to the network. Similarly, if the create() code writes a request to the resource manager service, the same allocation it had last time will be waiting there already, and so the execution of create() can continue with the same reservation as last time.


If you really, really want to read up the value stored in the running database (and presumably out on the device), you can do so by opening up a connection to the running datastore and read from there (or even to the device live status). I don't quite see the point with this, however. What sort of issues are you hoping to catch? To ensure the resource allocator did not allocate 999 for the vlan the last time the service ran?

Thanks Jan, much appreciated and very detailed explanation.

I am just trying to do some input validation to confirm that the Ethernet switch interface a user has selected is not already in use. My definition of "in use" is configured with a VLAN value other than "999". Our "default" Ethernet switch configuration assigns all interfaces a VLAN value of 999, this has nothing to do with NSO resource pools. We are migrating to the use of NSO for all of our service provisioning, but some interfaces may have VLANs assigned through our old provisioning tool, so I cannot just simply check to see if an Ethernet switch interface is already assigned to an existing NSO service instance.

So maybe your service code should check that the previous value of the vlan assignment is 999, and if not, either refuse the transaction, or ask for a new allocation if that happens. I still don't see why you'd want to read running or the device live-status.

I would rather avoid live-status polls. How do I read the running value for this leaf? I assume that the running value in my example will return 2004?

Still trying to figure out how to access the 'running database' in python service code. Any guidance is greatly appreciated.

Can't rid the feeling you're going in the wrong direction, but I guess there's nothing I can say to stop you, so here are a couple of examples in the NSO installation that do this (open a maapi handle to running) in Python and Java:

+ examples.ncs/getting-started/developing-with-ncs/16-py-maapi//high-level-read.py

+ examples.ncs/getting-started/developing-with-ncs/8-maapi/packages/maapi/src/java/src/com/example/maapi/actions/AddAndSyncDevices.java

Thanks. That's why I could not find any references to the 'running database' in the examples. I did not realize that just opening another maapi transaction would change the behavior simply because it is not called as part of the service instantiation. Just tried it out and

currentvlan = root.devices.device[switch.switch_name].config.ios__interface.GigabitEthernet[switch_interface.switch_interface_id].switchport.access.vlan

assigns a value of [999] to currentvlan

while

m = maapi.Mappi()

m.start_user_session('admin','test_context')

t = m.start_read_trans()

root2 = maagic.get_root(t)

root2.devices.device[switch.switch_name].config.ios__interface.GigabitEthernet[switch_interface.switch_interface_id].switchport.access.vlan

assigns a value of [2004] to currentvlan