Learn by Doing: Service Health Verification & Importing Packages

NSO has a ton of features. This repository is the first of a series which will show a simple use case, along with a feature. The purpose is dual:

  1. See NSO applied to a variety of configuration situations and see how versatile it is..
  2. Learn something new and have an example to follow

This example is a service package deploying:

SVI Configuration

and the features I am showcasing are:

Service Health Verifications
Importing Packages

This example assumes a working knowledge of services and NSO.

Installation

Reserve the NSO Reservable Sandbox

If you need to revisit some of the NSO Basics, you can start here.

Use some type of file transfer program or VS Code has remote SSH (drag and drop the package into the packages directory)

This project requires two repos. The first is this one (svi_verify_example). The second is the selftest package.

Both packages should go here:

/var/opt/ncs/packages/

If you are reproducing this elsewhere, here are the version details:

using NSO 5.3.0.1
cisco-asa-cli-6.8
cisco-iosxr-cli-7.20
on 
Nexus9000 9.2(3)
ASAv 9.12(2)

After both packages are on the configured NSO system install server (10.10.20.49) at the packages folder, make sure the yang is compiled reload packages and configure a sample service instance and sample verification.

Configure service

First, you will need to compile the yang and reload the packages, then create a service instance of the SVI package:

** transfer selftest AND svi_verify_example package over **
cd /var/opt/ncs/packages/svi_verify_example/src
make
cd /var/opt/ncs/packages/selftest/src
make
ncs_cli
packages reload
conf
svi_verify_example first-instance vlan-id 1337 vlan-name SVI-DEMO switches first-sw switch-device dist-sw01
exit
switches second-sw switch-device dist-sw02
exit
firewalls first-fw firewall-device edge-firewall01
exit
commit dry-run outformat native
commit
end

Configure and run selftest

After the service instance is deployed and committed, you can populate and run selftest. This will be explained after the output section.

show running-config svi_verify_example first-instance | display xpath
conf
selftest svi-tests service /svi_verify_example[name='first-instance']
commands ping-test command ping arguments 172.16.107.2 failstring "No route to host" devices dist-sw01
exit
commands sh-ip-int-br command show arguments "ip interface brief" devices dist-sw01
exit
commands test-svi-fail command ping arguments 172.16.110.2 devices dist-sw01 failstring "No route to host"
top
commit
selftest svi-tests execute
end
show svi_verify_example selftest-result

Sample Output for SVI Service

here is some sample output:

[developer@nso ]$ cd /var/opt/ncs/packages/svi_verify_example/src
[developer@nso src]$ make
/opt/ncs/current/bin/ncsc  `ls svi_verify_example-ann.yang  > /dev/null 2>&1 && echo "-a svi_verify_example-ann.yang"` \
             --yangpath ../../selftest/src/yang -c -o ../load-dir/svi_verify_example.fxs yang/svi_verify_example.yang
[developer@nso src]$ cd /var/opt/ncs/packages/selftest/src/
[developer@nso src]$ make
/opt/ncs/current/bin/ncsc  `ls svi_verify_example-ann.yang  > /dev/null 2>&1 && echo "-a svi_verify_example-ann.yang"` \
             --yangpath ../../selftest/src/yang -c -o ../load-dir/svi_verify_example.fxs yang/svi_verify_example.yang
[developer@nso src]$ ncs_cli

developer connected from 192.168.254.11 using ssh on nso developer@ncs# packages reload

>>> System upgrade is starting. >>> Sessions in configure mode must exit to operational mode. >>> No configuration changes can be performed until upgrade has completed. >>> System upgrade has completed successfully. reload-result { package cisco-asa-cli-6.8 result true } reload-result { package cisco-ios-cli-6.44 result true } reload-result { package cisco-iosxr-cli-7.20 result true } reload-result { package cisco-nx-cli-5.15 result true } reload-result { package resource-manager result true } reload-result { package selftest result true } reload-result { package svi_verify_example result true } developer@ncs# System message at 2020-11-17 14:38:28... Subsystem stopped: ncs-dp-39-cisco-nx-cli-5.15:NexusDp developer@ncs# System message at 2020-11-17 14:38:28... Subsystem stopped: ncs-dp-38-cisco-ios-cli-6.44:IOSDp developer@ncs# System message at 2020-11-17 14:38:28... Subsystem stopped: ncs-dp-40-resource-manager:AddressallocationIPvalidation developer@ncs# System message at 2020-11-17 14:38:28... Subsystem stopped: ncs-dp-37-cisco-asa-cli-6.8:ASADp developer@ncs# System message at 2020-11-17 14:38:28... Subsystem started: ncs-dp-41-cisco-asa-cli-6.8:ASADp developer@ncs# System message at 2020-11-17 14:38:28... Subsystem started: ncs-dp-42-cisco-ios-cli-6.44:IOSDp developer@ncs# System message at 2020-11-17 14:38:28... Subsystem started: ncs-dp-43-cisco-nx-cli-5.15:NexusDp developer@ncs# System message at 2020-11-17 14:38:28... Subsystem started: ncs-dp-44-resource-manager:AddressallocationIPvalidation developer@ncs# developer@ncs# developer@ncs# conf Entering configuration mode terminal developer@ncs(config)# svi_verify_example first-instance vlan-id 1337 vlan-name SVI-DEMO switches first-sw switch-device dist-sw01 developer@ncs(config-switches-first-sw)# exit developer@ncs(config-svi_verify_example-first-instance)# switches second-sw switch-device dist-sw02 developer@ncs(config-switches-second-sw)# exit developer@ncs(config-svi_verify_example-first-instance)# firewalls first-fw firewall-device edge-firewall01 developer@ncs(config-firewalls-first-fw)# exit developer@ncs(config-svi_verify_example-first-instance)# commit dry-run outformat native native { device { name dist-sw01 data vlan 1337 name SVI-DEMO ! interface Vlan1337 no shutdown description SVI-DEMO ip address 172.16.107.2/24 no ip redirects ip router ospf 1 area 0.0.0.0 no ipv6 redirects hsrp 10 ipv4 ip 172.16.107.1 exit exit } device { name dist-sw02 data vlan 1337 name SVI-DEMO ! interface Vlan1337 no shutdown description SVI-DEMO ip address 172.16.107.2/24 no ip redirects ip router ospf 1 area 0.0.0.0 no ipv6 redirects hsrp 10 ipv4 ip 172.16.107.1 exit exit } device { name edge-firewall01 data object network INSIDE-SVI-DEMO subnet 172.16.107.0 255.255.255.0 exit object-group network INSIDE-NETWORKS network-object object INSIDE-SVI-DEMO ! } } developer@ncs(config-svi_verify_example-first-instance)# commit Commit complete. developer@ncs(config-svi_verify_example-first-instance)# end

Verifying with the custom Selftest package

developer@ncs# show running-config svi_verify_example first-instance | display xpath
/svi_verify_example[name='first-instance']/switches[id='first-sw']/switch-device dist-sw01
/svi_verify_example[name='first-instance']/switches[id='second-sw']/switch-device dist-sw02
/svi_verify_example[name='first-instance']/firewalls[id='first-fw']/firewall-device edge-firewall01
/svi_verify_example[name='first-instance']/vlan-id 1337
/svi_verify_example[name='first-instance']/vlan-name SVI-DEMO
developer@ncs# conf
Entering configuration mode terminal
developer@ncs(config)# selftest svi-tests ?
Possible completions:
  commands
  execute
  service    Path to the service where the selftest result will be stored
  <cr>
developer@ncs(config)# selftest svi-tests service /svi_verify_example[name='first-instance']
developer@ncs(config-selftest-svi-tests)# commands ?
Possible completions:
  <name:string>
developer@ncs(config-selftest-svi-tests)# commands ping-test ?
Possible completions:
  arguments
  command
  devices
  failstring   regular expression for a fail result
  <cr>
developer@ncs(config-selftest-svi-tests)# commands ping-test command ping arguments 172.16.107.2 failstring "No route to host" devices dist-sw01
developer@ncs(config-commands-ping-test)# exit
developer@ncs(config-selftest-svi-tests)# commands sh-ip-int-br command show arguments "ip interface brief" devices dist-sw01
developer@ncs(config-commands-sh-ip-int-br)# exit
developer@ncs(config-selftest-svi-tests)# commands test-svi-fail command ping arguments 172.16.110.2 devices dist-sw01 failstring "No route to host"
developer@ncs(config-commands-test-svi-fail)# exit
developer@ncs(config-selftest-svi-tests)# top
developer@ncs(config)# commit
Commit complete.
developer@ncs(config)# selftest
Possible completions:
  <name:string>  svi-tests 
developer@ncs(config)# selftest svi-tests execute
result
output from ping
device: dist-sw01

PING 172.16.107.2 (172.16.107.2): 56 data bytes 64 bytes from 172.16.107.2: icmp_seq=0 ttl=255 time=1.752 ms 64 bytes from 172.16.107.2: icmp_seq=1 ttl=255 time=0.594 ms 64 bytes from 172.16.107.2: icmp_seq=2 ttl=255 time=1.217 ms 64 bytes from 172.16.107.2: icmp_seq=3 ttl=255 time=1.34 ms 64 bytes from 172.16.107.2: icmp_seq=4 ttl=255 time=1.173 ms

--- 172.16.107.2 ping statistics --- 5 packets transmitted, 5 packets received, 0.00% packet loss round-trip min/avg/max = 0.594/1.215/1.752 ms

output from show device: dist-sw01

IP Interface Status for VRF "default"(1) Interface IP Address Interface Status Vlan101 172.16.101.2 protocol-up/link-up/admin-up Vlan102 172.16.102.2 protocol-up/link-up/admin-up Vlan103 172.16.103.2 protocol-up/link-up/admin-up Vlan104 172.16.104.2 protocol-up/link-up/admin-up Vlan105 172.16.105.2 protocol-up/link-up/admin-up Vlan1337 172.16.107.2 protocol-up/link-up/admin-up Eth1/3 172.16.252.1 protocol-up/link-up/admin-up Eth1/4 172.16.252.5 protocol-up/link-up/admin-up

output from ping device: dist-sw01

PING 172.16.110.2 (172.16.110.2): 56 data bytes ping: sendto 172.16.110.2 64 chars, No route to host Request 0 timed out ping: sendto 172.16.110.2 64 chars, No route to host Request 1 timed out ping: sendto 172.16.110.2 64 chars, No route to host Request 2 timed out ping: sendto 172.16.110.2 64 chars, No route to host Request 3 timed out ping: sendto 172.16.110.2 64 chars, No route to host Request 4 timed out

--- 172.16.110.2 ping statistics --- 5 packets transmitted, 0 packets received, 100.00% packet loss

developer@ncs(config)# exit developer@ncs# show svi_verify_example selftest-result ? Description: last results for the service selftest action Possible completions: command | <cr> developer@ncs# show svi_verify_example selftest-result NAME NAME RESULT TIME

first-instance ping-test OK 2020-11-17 15:19:52 sh-ip-int-br OK 2020-11-17 15:19:52 sh-ip-test OK 2020-11-17 15:14:23 test-svi-fail FAIL 2020-11-17 15:20:05

developer@ncs#

Service Design Considerations

This Learn by Doing example is not so much about the service design, but the integration of verification. As such, the Yang and Templates are relatively simple, reusing concepts from previous Learn by Doing repos.

I originally created this package with the expectation I would write my own health checks, so there is skeleton Python code in the python directory. It was not used, since I ended up using the selftest package.

The configuration template loops over each device in the switch and firewall device list, with some basic inputs for VLAN ID and VLAN Name to be consistent between the firewalls and switches. The IP Addresses are static for the sake of development time, and keeping the example simple. They should be replaced with more sophisticated inputs if that is desired:

<config-template xmlns="http://tail-f.com/ns/config/1.0">
  <devices xmlns="http://tail-f.com/ns/ncs">
        <?foreach {/switches}?>
               <device>
                 <name>{switch-device}</name>
                 <config>
                   <vlan xmlns="http://tail-f.com/ned/cisco-nx">
                     <vlan-list>
                       <id>{/vlan-id}</id>
                       <name>{/vlan-name}</name>
                     </vlan-list>
                   </vlan>
                   <interface xmlns="http://tail-f.com/ned/cisco-nx">
                     <Vlan>
                       <name>{/vlan-id}</name>
                       <description>{/vlan-name}</description>
                       <ip>
                         <address>
                           <ipaddr>172.16.107.2/24</ipaddr>
                         </address>
                         <redirects>false</redirects>
                         <router>
                           <ospf>
                             <name>1</name>
                             <area>0.0.0.0</area>
                           </ospf>
                         </router>
                       </ip>
                       <ipv6>
                         <redirects>false</redirects>
                       </ipv6>
                       <hsrp>
                         <hsrp-list>
                           <id>10</id>
                           <addr_type>ipv4</addr_type>
                           <ip>
                             <address>172.16.107.1</address>
                           </ip>
                         </hsrp-list>
                       </hsrp>
                     </Vlan>
                   </interface>
                 </config>
               </device>
              <?end?> <!-- end foreach {/endpoint} -->
             </devices>


<devices xmlns="http://tail-f.com/ns/ncs"> <?foreach {/firewalls}?> <device> <name>{firewall-device}</name> <config> <object xmlns="http://cisco.com/ned/asa"> <network> <name>INSIDE-{/vlan-name}</name> <subnet> <address>172.16.107.0</address> <mask>255.255.255.0</mask> </subnet> </network> </object> <object-group xmlns="http://cisco.com/ned/asa"> <network> <id>INSIDE-NETWORKS</id> <network-object> <id>object INSIDE-{/vlan-name}</id> </network-object> </network> </object-group> </config> </device> <?end?> <!-- end foreach {/endpoint} --> </devices> </config-template>

The data model imports selftest, which is the custom verification package we downloaded and compiled. It also includes uses selftest:selftest-result; in the service so that we can store the operational values of the output in our service.

module svi_verify_example {

namespace "http://example.com/svi_verify_example"; prefix svi_verify_example;

import ietf-inet-types { prefix inet; } import tailf-common { prefix tailf; } import tailf-ncs { prefix ncs; } // assumes makefile has been updated import selftest { prefix selftest; }

description "Bla bla...";

revision 2016-01-01 { description "Initial revision."; }

list svi_verify_example { description "This is an RFS skeleton service";

<span class="pl-s1">key</span> <span class="pl-s1">name</span><span class="pl-kos">;</span>
<span class="pl-s1">leaf</span> <span class="pl-s1">name</span> <span class="pl-kos">{</span>
  tailf:<span class="pl-s1">info</span> <span class="pl-s">"Unique service id"</span><span class="pl-kos">;</span>
  tailf:<span class="pl-s1">cli</span><span class="pl-c1">-</span><span class="pl-s1">allow</span><span class="pl-c1">-</span><span class="pl-s1">range</span><span class="pl-kos">;</span>
  <span class="pl-s1">type</span> <span class="pl-s1">string</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span>
<span class="pl-c">// gives us linkage to selftest</span>
uses <span class="pl-s1">selftest</span>:<span class="pl-s1">selftest</span><span class="pl-c1">-</span><span class="pl-s1">result</span><span class="pl-kos">;</span>
uses <span class="pl-s1">ncs</span>:<span class="pl-s1">service</span><span class="pl-c1">-</span><span class="pl-s1">data</span><span class="pl-kos">;</span>
ncs:<span class="pl-s1">servicepoint</span><span class="pl-kos"></span> <span class="pl-s1">svi_verify_example</span><span class="pl-c1">-</span><span class="pl-s1">servicepoint</span><span class="pl-kos">;</span>

list switches { key "id"; leaf id{ tailf:info "Switches identifier"; type string; } leaf switch-device { mandatory true; type leafref { path "/ncs:devices/ncs:device/ncs:name"; } } } list firewalls { key "id"; leaf id{ tailf:info "firewalls identifier"; type string; } leaf firewall-device { mandatory true; type leafref { path "/ncs:devices/ncs:device/ncs:name"; } } }

  <span class="pl-s1">leaf</span> <span class="pl-s1">vlan</span><span class="pl-c1">-</span><span class="pl-s1">id</span> <span class="pl-kos">{</span>
    <span class="pl-s1">type</span> <span class="pl-s1">uint16</span><span class="pl-kos">;</span>
    <span class="pl-s1">mandatory</span> <span class="pl-s1">true</span><span class="pl-kos">;</span>
  <span class="pl-kos">}</span>
  <span class="pl-s1">leaf</span> <span class="pl-s1">vlan</span><span class="pl-c1">-</span><span class="pl-s1">name</span><span class="pl-kos">{</span>
    <span class="pl-s1">type</span> <span class="pl-s1">string</span><span class="pl-kos">;</span>
    <span class="pl-s1">mandatory</span> <span class="pl-s1">true</span><span class="pl-kos">;</span>
  <span class="pl-kos">}</span>

} }

Changes to Makefile

In order for the SVI Service to include the Yang files of the selftest package, I changed the Makefile in the SVI service to include this statement

YANGPATH += ../../selftest/src/yang

This tells NSO to pull in the data models from the other package. Since we then imported it, and used it, we now can use this package's functionality in our package.

Service Verification

There are multiple ways to verify a service health. You can include some Python actions, writing your own tests, or use some type of outside (not NSO) application to check on the health of the network.

In this case, we are reusing the framework package written by Hakan, in order to save development time and also demonstrate reusing another package in our own service.

The selftest package has a number of different features, but for our purposes, it is an easy to use wrapper around some Python code that allows us to define a list of verification operational commands to send, and some basic REGEX to see if there is a failure scenario in the output.

The package uses the NSO live-status functionality to send commands to devices. I picked a few commands to send, showing successful and relevant tests, as well as one test that fails on purpose. The commands I chose were:

ping 172.16.107.2 (which should pass)
show ip interface brief (which should show our SVI)
ping 172.16.110.2 (which should fail)

The package checks to see if certain failstrings are present, for the ping test that was easy. For the show ip interface brief, we want to see that something is present for it succeed (the SVI being there is good), so it will always pass, but it gives us a record of the output to see the SVI is there.

The pass and fail records are visible in our service because we have linked them together with the uses statement:

developer@ncs# show svi_verify_example selftest-result
NAME            NAME           RESULT  TIME

first-instance ping-test OK 2020-11-17 15:19:52 sh-ip-int-br OK 2020-11-17 15:19:52 sh-ip-test OK 2020-11-17 15:14:23 test-svi-fail FAIL 2020-11-17 15:20:05

developer@ncs#

Note that the test-svi-fail test which was designed to fail, did indeed fail since the IP address 172.16.110.2 was not provisioned for this service, but the 172.16.107.2 one was and it passed.

Related Sandbox

Reserve the NSO Reservable Sandbox

Use Case

A Switch Virtual Interfaces (SVI) represents a logical Layer 3 interface on a switch. VLANs divide broadcast domains in a LAN environment. Whenever hosts in one VLAN need to communicate with hosts in another VLAN, the traffic must be routed between them. This is known as inter-VLAN routing.

Installation

This project requires two repositories. The first is this one (svi_verify_example). The second is the selftest package

Both packages should go in this directory /var/opt/ncs/packages/ here are the version details required

using NSO 5.3.0.1cisco-asa-cli-6.8cisco-iosxr-cli-7.20

on devices

Nexus9000 9.2(3)ASAv 9.12(2)

After both packages are on the configured NSO system install server at the packages folder, make sure the yang is compiled reload packages and configure a sample service instance and sample verification.

Configure service

Compile the yang and reload the packages, then create a service instance of the SVI package:

Configure and run selftest

After the service instance is deployed and committed, populate and run selftest

Sample Output for SVI Service

Related Sandbox

Reserve the NSO Reservable Sandbox

View code on GitHub

Code Exchange Community

Get help, share code, and collaborate with other developers in the Code Exchange community.View Community
Disclaimer:
Cisco provides Code Exchange for convenience and informational purposes only, with no support of any kind. This page contains information and links from third-party websites that are governed by their own separate terms. Reference to a project or contributor on this page does not imply any affiliation with or endorsement by Cisco.