NSO
Overview
NSO gathers, parses, and stores the configuration state of the network devices it manages in a configuration database (CDB). Users and applications can then "ask" NSO to create, read, update, or delete configuration in a programmatic way either ad hoc or through customizable network services.
NSO uses software packages called Network Element Drivers (NEDs) to facilitate telnet, SSH, or API interactions with the devices that it manages. The NED provides an abstraction layer that reads in the device's running configuration and parses it into a data-model-validated snapshot in the CDB.
The NEDs also allow for the reverse, creating network configuration from CDB data inputs and then sending the configurations to the network devices. There are hundreds of NEDs covering all the Cisco platforms (including IOS-XE, IOS-XR, NX-OS, and ASA) and all major non-Cisco platforms as well
Installation
Two modes:
System Install: install as an always-on service
Local Install: install as standalone on-demand instance, used for development and evaluation
Configuration files:
ncs.conf: NSO application configuration file. Used to customize aspects of the NSO instance (change ports, enable or disable features, and so on.)
packages/: Directory that has symlinks to the NEDs referenced in the --package arguments at setup.
logs/: Directory that contains all the logs from NSO. Use this directory when troubleshooting.
Simulator Installation
ncs-netsim --dir ~/src/netsim create-network cisco-ios-cli-3.8 2 ios
ncs-setup --dest ~/src --netsim-dir ~/src/netsim
cd ~/src
ncs-netsim --dir ~/src/nso-instance/netsim start|stop internet-rtr0
Setup NCS Instance
go to nso-instance folder and start ncs: ncs
ncs --status: check status
Setup device authentication
NSO uses authgroups to set up credentials for device access. Many authgroups can be configured as needed for the different variations of authentication used across your network. An authgroup can use SNMP or certificates in addition to traditional username/passwords. NSO supports powerful methods of RBAC for identifying and using different authentication and authorization levels depending on the user who is logged into NSO.
To setup authgroup
login to NSO CLI: ncs_cli -u admin -C
enter config mode: config
Adding devices to NSO
After having authgroup setup, devices can be added to inventory which need the following information
device's IP or FQDN
Protocol such as SSH, Telnet, HTTP, Rest and so on and port number
authgroup to be used for the device
the NED (device driver) to use to connect to the device
Add edge-sw01 device:
View current context of device: pwd
Connect to device: connect
By default devices are in locked mode (default)
change admin-state of device: state admin-state unlocked, then commit
Connect to all devices: devices connect
view all devices: show devices list
Other ways to add devices:
Manually type commands for each device like above steps
Use an API
Query a production system that has the full device list and save output to a file, then use load merge command from NSO to read it into NSO and commit
Query and Load merge devicesLog into a source nso: ncs_cli -C -u admin
show running-config devices device | de-select config: view configuration, filter out its configuration
Save output to a file such as devices-config.txt
Log into a destination nso: ncs_cli -C -u admin
change to config mode: conf
load merge devices: load merge /home/developer/devices-config.txt
commit to apply the change
view devices: show devices list
Sync Configuration from Devices
show running-config devices device $device-name config: view device configuration saved in configuraiton database (CDB).
devices sync-from: Enable device configuration sync
devices device-group IOS-DEVICES check-sync: check device group sync status
Group devices together
Create device group and add devices to group
Create an ALL group to include all other groups
commit to apply changes
Update device configuration
Check command commit in dry-run mode: commit dry-run outformat native
If everything works, commit again to apply the staged config
Roll back configuration
show configuration rollback changes: View the latest changes, if rollback
Load up these change and view staged configuration:
Some Commands
Note: Tab completion is case-sensitive
show running-config devices device internet-router config interface | display [json|xml]: view device's interface configuration
show running-config devices device internet-router config interface Vlan * ip address: view ip address of all vlan interfaces
show full-configuration devices device $devicename config | nomore: examine device configuration
devices device $devicename config: Change to device config configuration mode
ios:hostname $newhostname: change hostname of device
show configuration: in this context, it will only show current configuration in transaction (new command)
devices device * config ios:enable password $password: change password on all devices
show devices device dist-sw01 platform [serial-number|version]: View platform information of a device
show devices device * platform [serial-number|vesrion]: View platform information of all devices
show devices device dist-sw01 live-status port-channel: view live-status of devices, rather than pulling from CDB. Can replace port-channel with other options:
ip route
devices device dist-sw01 live-status exec show license usage: run show command on device and get returned result
devices device dist-sw01 live-status exec any dir: run any dir command
devices device dist* live-status exec show license usage | save /home/developer/nexus-license-usage.txt: save output for later usage
Templates
Create a template
check the template and commit:
show configuration
commit
Check and apply template
View device list in config mode: do show devices list
devices device dist-sw01 apply-template template-name SET-DNS-SERVER
show configuration: check configuration to be applied
commit or revert to un-staged configuration
Configuration Compliance
There are 2 steps:
Building a device template that contains the desired configuration to test.
Building a compliance report to check the configuration of a group of devices against a template.
Build device template
or show running-configuration | save template.txt
check configuration: show configuration
and commit
Build compliance report
Apply the template: compliance reports report COMPLIANCE-CHECK run
Apply the template and save output in specific format: compliance reports report COMPLIANCE-CHECK run outformat {text|html}
View the result: cat nso-instance/state/compliance-reports/report*.text
Resolve compliance problems
devices device-group ALL apply-template template-name COMPLIANCE-CHECK
NSO Services
A declarative method to abstract and automate a task that is done repeatedly
can be a customer facing and resource facing service
Service Packages
Service packages are a collection of structured files and folders that NSO loads in to the application to extend NSO with new functionality.
ncs-make-package is a tool to auto-generate a skeleton structure of files and folders for creating a service package
Important files are:
loopback-service/src/yang/loopback-service.yang
loopback-service/templates/loopback-service-template.xml
Generate XML to plug into the template commands
Then show configuration and output as xml
copy the part between config tags
Then put in between config tag of template file above loopback-service/templates/loopback-service-template.xml, then replace ip address 10.10.30.0 with {/dummy}
Then save the file and compile Yang Data model
Load the new package:
Create a service instance
If for some reason, the config is changed after sync-from device, it can be redeploy using
ncs-make-package --service-skeleton template --dest nso-instance/packages/simple-service simple-service printf 'module simple-service { namespace "http://com/example/simpleservice"; prefix simple-service; import tailf-ncs { prefix ncs; } list simple-service { key name; uses ncs:service-data; ncs:servicepoint simple-service; leaf name { type string; } leaf device { type leafref { path "/ncs:devices/ncs:device/ncs:name"; } } leaf secret { type string; } } } ' > nso-instance/packages/simple-service/src/yang/simple-service.yang printf ' {./device} {./secret} ' > nso-instance/packages/simple-service/templates/simple-service-template.xml make -C nso-instance/packages/simple-service/src echo "packages reload" | ncs_cli -C -u admin
config simple-service test1 device ios0 secret mypasswd
developer:simple-service > cd $NCS_DIR/examples.ncs/development-guide/cdb-yang developer:cdb-yang > make showcase ./showcase.sh
Setup the demo
Make sure no previous NSO or netsim processes are running
Create an NSO local install with a fresh runtime directory
make[1]: Entering directory '/home/developer/nso-6.2.1/examples.ncs/development-guide/cdb-yang' rm -rf nso-lab-rundir mkdir nso-lab-rundir ncs-setup --dest ./nso-lab-rundir make[1]: Leaving directory '/home/developer/nso-6.2.1/examples.ncs/development-guide/cdb-yang'
Have the environment variable NSO_RUNDIR point to the runtime directory
Showcase: Extending the CDB with Packages
Step 1: Create a package
gmake[1]: Entering directory '/home/developer/nso-6.2.1/examples.ncs/development-guide/cdb-yang/nso-lab-rundir/packages/my-data-entries/src' mkdir -p ../load-dir /home/developer/nso-6.2.1/bin/ncsc ls my-data-entries-ann.yang > /dev/null 2>&1 && echo "-a my-data-entries-ann.yang"
--fail-on-warnings
-c -o ../load-dir/my-data-entries.fxs yang/my-data-entries.yang gmake[1]: Leaving directory '/home/developer/nso-6.2.1/examples.ncs/development-guide/cdb-yang/nso-lab-rundir/packages/my-data-entries/src'
Step 2: Add package to NSO
admin connected from 127.0.0.1 using console on devpod-4884268602524010749-85755c9897-2gq8k admin@ncs# packages reload reload-result { package my-data-entries result true } admin@ncs# show my-data-entries % No entries found. admin@ncs#
Step 3: Set data
User admin last logged in 2024-04-16T02:13:05.100749+00:00, to devpod-4884268602524010749-85755c9897-2gq8k, from 127.0.0.1 using cli-console admin connected from 127.0.0.1 using console on devpod-4884268602524010749-85755c9897-2gq8k admin@ncs# config Entering configuration mode terminal admin@ncs(config)# my-data-entries "entry number 1" admin@ncs(config-my-data-entries-entry number 1)# dummy 0.0.0.0 admin@ncs(config-my-data-entries-entry number 1)# abort admin@ncs#
Step 4: Inspect the YANG module
User admin last logged in 2024-04-16T02:13:07.428493+00:00, to devpod-4884268602524010749-85755c9897-2gq8k, from 127.0.0.1 using cli-console admin connected from 127.0.0.1 using console on devpod-4884268602524010749-85755c9897-2gq8k admin@ncs# file show packages/my-data-entries/src/yang/my-data-entries.yang | nomore module my-data-entries {
namespace "http://example.com/my-data-entries"; prefix my-data-entries;
import ietf-inet-types { prefix inet; } import tailf-common { prefix tailf; } import tailf-ncs { prefix ncs; }
description "Bla bla...";
revision 2016-01-01 { description "Initial revision."; }
list my-data-entries { description "This is an RFS skeleton service";
} } admin@ncs# show ncs-state loaded-data-models data-model my-data-entries | nomore ncs-state loaded-data-models data-model my-data-entries revision 2016-01-01 namespace http://example.com/my-data-entries prefix my-data-entries exported-to-all admin@ncs#
Showcase: Building and Testing a Model
Step 1: Create a model skeleton
Note: Created the service skeleton package in step 1 of the previous showcase
module my-test-model { namespace "http://example.tail-f.com/my-test-model"; prefix "t";
Step 2: Fill out the model
module my-test-model { namespace "http://example.tail-f.com/my-test-model"; prefix "t";
container host { leaf host-name { type string; description "Hostname for this system"; } leaf-list domains { type string; description "My favourite internet domains"; } container server-admin { description "Administrator contact for this system"; leaf name { type string; } } list user-info { description "Information about team members"; key "name"; leaf name { type string; } leaf expertise { type string; } } } }
Step 3: Compile and load the model
make[1]: Entering directory '/home/developer/nso-6.2.1/examples.ncs/development-guide/cdb-yang/nso-lab-rundir/packages/my-data-entries/src' /home/developer/nso-6.2.1/bin/ncsc ls my-test-model-ann.yang > /dev/null 2>&1 && echo "-a my-test-model-ann.yang"
--fail-on-warnings
-c -o ../load-dir/my-test-model.fxs yang/my-test-model.yang make[1]: Leaving directory '/home/developer/nso-6.2.1/examples.ncs/development-guide/cdb-yang/nso-lab-rundir/packages/my-data-entries/src'
User admin last logged in 2024-04-16T02:13:07.813294+00:00, to devpod-4884268602524010749-85755c9897-2gq8k, from 127.0.0.1 using cli-console admin connected from 127.0.0.1 using console on devpod-4884268602524010749-85755c9897-2gq8k admin@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 my-data-entries result true } admin@ncs#
Step 4: Test the model
User admin last logged in 2024-04-16T02:13:10.603362+00:00, to devpod-4884268602524010749-85755c9897-2gq8k, from 127.0.0.1 using cli-console admin connected from 127.0.0.1 using console on devpod-4884268602524010749-85755c9897-2gq8k admin@ncs# config Entering configuration mode terminal admin@ncs(config)# host host-name my-host admin@ncs(config)# host domains [ tail-f.com tail-f.se ] admin@ncs(config)# host server-admin name Ingrid admin@ncs(config)# host user-info Greta admin@ncs(config-user-info-Greta)# expertise sustainability admin@ncs(config-user-info-Greta)# host user-info Gunvald admin@ncs(config-user-info-Gunvald)# expertise security admin@ncs(config-user-info-Gunvald)# top admin@ncs(config)# show configuration host host-name my-host host domains [ tail-f.com tail-f.se ] host server-admin name Ingrid host user-info Greta expertise sustainability ! host user-info Gunvald expertise security ! admin@ncs(config)# commit Commit complete. admin@ncs(config)# show full-configuration host | display xml | save cdb-init.xml admin@ncs(config)#
cat cdb-init.xml my-host tail-f.com tail-f.se Ingrid Greta sustainability Gunvald security
ncs_load -Fp -p /host my-host tail-f.com tail-f.se Ingrid Greta sustainability Gunvald security
ncs_load -Fc -p /host host host-name my-host host domains [ tail-f.com tail-f.se ] host server-admin name Ingrid host user-info Greta expertise sustainability ! host user-info Gunvald expertise security !
User admin last logged in 2024-04-16T02:13:14.502173+00:00, to devpod-4884268602524010749-85755c9897-2gq8k, from 127.0.0.1 using cli-console admin connected from 127.0.0.1 using console on devpod-4884268602524010749-85755c9897-2gq8k admin@ncs# show running-config host host host-name my-host host domains [ tail-f.com tail-f.se ] host server-admin name Ingrid host user-info Greta expertise sustainability ! host user-info Gunvald expertise security ! admin@ncs# config Entering configuration mode terminal admin@ncs(config)# no host admin@ncs(config)# commit Commit complete. admin@ncs(config)# show full-configuration host % No entries found. admin@ncs(config)# load merge cdb-init.xml Loading. 493 bytes parsed in 0.07 sec (6.44 KiB/sec) admin@ncs(config)# commit dry-run cli { local-node { data host { + host-name my-host; + domains [ tail-f.com tail-f.se ]; server-admin { + name Ingrid; } + user-info Greta { + expertise sustainability; + } + user-info Gunvald { + expertise security; + } } } } admin@ncs(config)# commit Commit complete. admin@ncs(config)# show full-configuration host host host-name my-host host domains [ tail-f.com tail-f.se ] host server-admin name Ingrid host user-info Greta expertise sustainability ! host user-info Gunvald expertise security ! admin@ncs(config)#
Done
developer:cdb-yang > make showcase-rc python3 showcase_rc.py
Setup the demo
Make sure no nso or netsim processes are running
Create an NSO local install with a fresh runtime directory
make[1]: Entering directory '/home/developer/nso-6.2.1/examples.ncs/development-guide/cdb-yang' rm -rf nso-lab-rundir mkdir nso-lab-rundir ncs-setup --dest ./nso-lab-rundir make[1]: Leaving directory '/home/developer/nso-6.2.1/examples.ncs/development-guide/cdb-yang'
Have the environment variable NSO_RUNDIR point to the runtime directory
Done
Showcase: Extending the CDB with Packages
Step 1: Create a package
gmake[1]: Entering directory '/home/developer/nso-6.2.1/examples.ncs/development-guide/cdb-yang/nso-lab-rundir/packages/my-data-entries/src' mkdir -p ../load-dir /home/developer/nso-6.2.1/bin/ncsc ls my-data-entries-ann.yang > /dev/null 2>&1 && echo "-a my-data-entries-ann.yang"
--fail-on-warnings
-c -o ../load-dir/my-data-entries.fxs yang/my-data-entries.yang gmake[1]: Leaving directory '/home/developer/nso-6.2.1/examples.ncs/development-guide/cdb-yang/nso-lab-rundir/packages/my-data-entries/src'
Step 2: Add package to NSO
POST http://localhost:8080/restconf/operations/tailf-ncs:packages/reload { "tailf-ncs:output": { "reload-result": [ { "package": "my-data-entries", "result": true } ] } }
GET http://localhost:8080/restconf/data/my-data-entries:my-data-entries Status code: 204
Step 3: Set data
PATCH http://localhost:8080/restconf/data { "data": { "my-data-entries:my-data-entries": [ { "name": "ex1", "dummy": "0.0.0.0" } ] } } Status code: 204
Step 4: Inspect the YANG module
GET http://localhost:8080/restconf/data/tailf-ncs-monitoring:ncs-state/loaded-data-models/data-model=my-data-entries { "tailf-ncs-monitoring:data-model": [ { "name": "my-data-entries", "revision": "2016-01-01", "namespace": "http://example.com/my-data-entries", "prefix": "my-data-entries", "exported-to-all": [null] } ] }
GET http://localhost:8080/restconf/data/ietf-yang-library:modules-state/module=my-data-entries,2016-01-01/schema { "ietf-yang-library:schema": "http://localhost:8080/restconf/tailf/modules/my-data-entries/2016-01-01" }
GET http://localhost:8080/restconf/tailf/modules/my-data-entries/2016-01-01 module my-data-entries {
namespace "http://example.com/my-data-entries"; prefix my-data-entries;
import ietf-inet-types { prefix inet; } import tailf-common { prefix tailf; } import tailf-ncs { prefix ncs; }
description "Bla bla...";
revision 2016-01-01 { description "Initial revision."; }
list my-data-entries { description "This is an RFS skeleton service";
} }
Showcase: Building and Testing a Model
Step 1: Create a model skeleton
Note: Created the service skeleton package in step 1 of the previous showcase
module my-test-model { namespace "http://example.tail-f.com/my-test-model"; prefix "t";
Step 2: Fill out the model
container host { leaf host-name { type string; description "Hostname for this system"; } leaf-list domains { type string; description "My favourite internet domains"; } container server-admin { description "Administrator contact for this system"; leaf name { type string; } } list user-info { description "Information about team members"; key "name"; leaf name { type string; } leaf expertise { type string; } } } }
Step 3: Compile and load the model
make[1]: Entering directory '/home/developer/nso-6.2.1/examples.ncs/development-guide/cdb-yang/nso-lab-rundir/packages/my-data-entries/src' /home/developer/nso-6.2.1/bin/ncsc ls my-test-model-ann.yang > /dev/null 2>&1 && echo "-a my-test-model-ann.yang"
--fail-on-warnings
-c -o ../load-dir/my-test-model.fxs yang/my-test-model.yang make[1]: Leaving directory '/home/developer/nso-6.2.1/examples.ncs/development-guide/cdb-yang/nso-lab-rundir/packages/my-data-entries/src' POST http://localhost:8080/restconf/operations/tailf-ncs:packages/reload
{ "tailf-ncs:output": { "reload-result": [ { "package": "my-data-entries", "result": true } ] } }
Step 4: Test the model
PATCH http://localhost:8080/restconf/data { "data": { "my-test-model:host": { "host-name": "my-host", "domains": [ "tail-f.com", "tail-f.se" ], "server-admin": { "name": "Ingrid" }, "user-info": [ { "name": "Greta", "expertise": "sustainability" }, { "name": "Gunvald", "expertise": "security" } ] } } } Status code: 204
GET http://localhost:8080/restconf/data/my-test-model:host { "my-test-model:host": { "host-name": "my-host", "domains": ["tail-f.com", "tail-f.se"], "server-admin": { "name": "Ingrid" }, "user-info": [ { "name": "Greta", "expertise": "sustainability" }, { "name": "Gunvald", "expertise": "security" } ] } }
DELETE http://localhost:8080/restconf/data/my-test-model:host Status code: 204 GET http://localhost:8080/restconf/data/my-test-model:host Status code: 204 PATCH http://localhost:8080/restconf/data Status code: 204 GET http://localhost:8080/restconf/data/my-test-model:host
my-host tail-f.com tail-f.se Ingrid Greta sustainability Gunvald security
Done
developer:cdb-yang >
cat >| templates/loopback.xml << EOF {/device} {/loopback-intf}
{/ip-address} 255.255.255.255
EOF ``` - Reload packages: packages reload - Try to configure a device using created service template: ``` config loopback test device core-rtr0 loopback-intf 201 ip-address 192.168.10.1 top commit dry-run outformat native ```
Note
With above service template, there might be some issues such as non-existing device, forgetting to set ip address
A well-designed service should produce consistent and reliable device configurations as an incorrect user input can result in the device rejecting the configuration. With different YANG statements, you can prevent that result before you send the configuration to the device.
Preventing incorrect user input
Open ~/src/nso-instance/packages/loopback/src/yang/loopback.yang, the YANG model of the loopback service again. To prevent incorrect user input, it should change from the following three leaves:
to: (Instead of the string type, use leafref and add a path that points to all devices in NSO)
The IP address is modeled as string which allows the user to provide invalid addresses. Use the inet:ipv4-address type instead, and make it mandatory. Doing so ensures that the user cannot forget to configure it. Import the ietf-inet-types module to be able to use the inet:ipv4-address type:
add tailf:info statements to all leaves that provides description of what value is expected. First import the tailf-common module. Then add the tailf:info with description to each leaf. The final data model should correspond to what this command generates:
Then rebuild the package and reload:
Some commands to debug:
commit | debug service
commit | details
Reference
Last updated