- Start
- What's New
- Getting Started
- User Guide
- About
- Basic Operations
- Network Element Drivers and Adding Devices
- Managing Network Services
- NSO CLI
- The NSO Device Manager
- SSH Key Management
- Alarm Manager
- Plug-and-play Scripting
- Compliance reporting
- NSO Packages
- Life-cycle Operations - Manipulating Existing Services and Devices
- Web User Interface
- Network Simulator
- Administration Guide
- Northbound APIs
- Development Guide
- Preface
- Development Environment and Resources
- The Configuration Database and YANG
- Basic Automation with Python
- Developing a Simple Service
- Applications in NSO
- Implementing Services
- Templates
- Services Deep Dive
- The NSO Java VM
- The NSO Python VM
- Embedded Erlang applications
- The YANG Data Modeling Language
- Using CDB
- Java API Overview
- Python API Overview
- NSO Packages
- Package Development
- Service Development Using Java
- NED Development
- NED Upgrades and Migration
- Service Handling of Ambiguous Device Models
- Scaling and Performance Optimization
- NSO Concurrency Model
- Developing Alarm Applications
- SNMP Notification Receiver
- The web server
- Kicker
- Scheduler
- Progress Trace
- Nano Services for Staged Provisioning
- Encryption Keys
- External Logging
- NSO Developer Studio
- Web UI
- Layered Service Architecture
- Manual Pages
- NSO Documentation Home
- NSO SDK API Reference
- NSO Change Log Explorer
- NSO NED Change Log Explorer
- NSO NED Capabilities Explorer
- NSO on DevNet
- Get Support
OUTDATED
OUTDATED
This documentation corresponds to an older version of the product, is no longer updated, and may contain outdated information.
Please access the latest versions from https://cisco-tailf.gitbook.io/nso-docs and update your bookmarks. OK
This chapter defines a scripting mechanism to be used together with the CLI (scripting is not available for any other northbound interfaces). The chapter is intended for users that are familiar with UNIX shell scripting and/or programming. With the scripting mechanism it is possible for an end-user to add new functionality to NSO in a plug-and-play like manner. No special tools are needed. There are three categories of scripts:
command scripts
-
used to add new commands to the CLI.
policy scripts
-
invoked at validation time and may control the outcome of a transaction. Policy scripts have the mandate to cause a transaction to abort.
post-commit scripts
-
invoked when a transaction has been committed. Post-commit scripts can for example be used for logging, sending external events etc.
The terms "script" and "scripting" used throughout this description refer to how functionality can be added without a requirement for integration using the NSO programming APIs. NSO will only run the scripts as UNIX executables. Thus they may be written as shell scripts, or using some other scripting language that is supported by the OS, e.g., Python, or even be compiled code. The scripts are run with the same user id as NSO. The examples in this section are written using shell scripts as a least common denominator, but they could have been written in whatever is suitable, e.g., Python or C.
Scripts are stored in a directory tree with a predefined structure where there is a sub-directory for each script category:
scripts/ command/ policy/ post-commit/
For all script categories it suffices to just add a valid script in the correct sub-directory in order to enable the script. See the details for each script category for how a valid script of that category is defined. Scripts with a name beginning with a dot character ('.') are ignored.
The directory path to the location of the scripts is
configured with the
/ncs-config/scripts/dir
configuration parameter. It is possible to have several scripts
directories.
The sample ncs.conf
file that comes with
the NSO release specifies two script directories:
./scripts
and
${NCS_DIR}/scripts
.
All scripts are required to provide a formal description of their interface. When the scripts are loaded, NSO will invoke the scripts with (one of)
--command
--policy
--post-commit
as argument depending of the script category.
The script must respond by writing its formal interface
description on stdout
and exit normally. Such a
description consists of one or more sections. Which sections
that are required depends on the category of the script.
The sections do however have a common syntax. Each section begins with the keyword "begin" followed by the type of section. After that one or more lines of settings follows. Each such setting begins with a name, followed by a colon character (':') and after that the value is stated. The section ends with the keyword "end". Empty lines and spaces may be used to improve the readability.
For examples see each corresponding section below.
Scripts are automatically loaded at startup and may also be
manually reloaded with the CLI command script
reload. The command takes an optional
verbosity
parameter which may have one
of the following values:
diff
-
Shows info about those scripts that have been changed since the latest (re)load. This is the default.
all
-
Shows info about all scripts regardless of whether they have been changed or not.
errors
-
Shows info about those scripts that are erroneous, regardless of whether they have been changed or not. Typical errors are invalid file permissions and syntax errors in the interface description.
Yet another parameter may be useful when debugging reload of scripts:
debug
-
Shows additional debug info about the scripts.
An example session reloading scripts:
admin@ncs# script reload all
$NCS_DIR/examples.ncs/getting-started/using-ncs/7-scripting/scripts:
ok
command:
add_user.sh: unchanged
echo.sh: unchanged
policy:
check_dir.sh: unchanged
post-commit:
show_diff.sh: unchanged
/opt/ncs/scripts: ok
command:
device_brief.sh: unchanged
device_brief_c.sh: unchanged
device_list.sh: unchanged
device_list_c.sh: unchanged
device_save.sh: unchanged
Command scripts are used to add new commands to the CLI. The
scripts are executed in the context of a transaction.
When the script is run in oper
mode, this is a
read-only transaction, when it is run in config
mode, it is a read-write transaction.
In that context the script may make use of the
environment variables NCS_MAAPI_USID
and
NCS_MAAPI_THANDLE
in order to attach
to the active transaction. This makes it simple to make use of
the ncs-maapi command (see the
ncs-maapi(1) in Manual Pages
manual page) for various purposes.
Each command script must be able to handle the argument
--command
and, when invoked, write a
command
section to stdout
.
If the CLI command is intended to take parameters, one
param
section per CLI parameter must also be
emitted.
The command is not paginated by default in the CLI and will only do so if it is piped to more.
joe@io> example_command_script | more
The following settings can be used to define a command:
modes
-
Defines in which CLI mode(s) that the command should be available. The value can be
oper
,config
or both (separated with space). styles
-
Defines in which CLI styles that the command should be available. The value can be one or more of
c
,i
andj
(separated with space).c
means Cisco style,i
, means Cisco IOS andj
for J-style. cmdpath
-
Is the full CLI command path. For example the command path
my script echo
implies that the command will be calledmy script echo
in the CLI. help
-
Command help text.
An example of a command section is:
begin command modes: oper styles: c i j cmdpath: my script echo help: Display a line of text end
In this section various aspects of a parameter is specified. This may both affect the parameter syntax for the end-user in the CLI as well as what the command script will get as arguments. The following settings can be used to customize each CLI parameter:
name
-
Optional name of the parameter. If provided, the CLI will prompt for this name before the value. By default the name is not forwarded to the script. See
flag
andprefix
. type
-
The type of the parameter. By default each parameter has a value, but by setting the type to
void
the CLI will not prompt for a value. In order to be useful thevoid
type must be combined withname
and eitherflag
orprefix
. presence
-
Controls whether the parameter must be present in the CLI input or not. Can be set to
optional
ormandatory
. words
-
Controls the number of words that the parameter value may consist of. By default the value must consist of just one word (possibly quoted if it contains spaces). If set to
any
, the parameter may consist of any number of words. This setting is only valid for the last parameter. flag
-
Extra word added before the parameter value. For example if set to
-f
and the user enterslogfile
, the script will get-f logfile
as arguments. prefix
-
Extra string prepended to the parameter value (as a single word). For example if set to
--file=
and the user enterslogfile
, the script will get--file=logfile
as argument. help
-
Parameter help text.
If the command takes a parameter to redirect the output to a file, a param section might look like this:
begin param name: file presence: optional flag: -f help: Redirect output to file end
A command denying changes the configured trace-dir for a
set of devices it can use the check_dir.sh
script.
#!/bin/bash set -e while [ $# -gt 0 ]; do case "$1" in --command) # Configuration of the command # # modes - CLI mode (oper config) # styles - CLI style (c i j) # cmdpath - Full CLI command path # help - Command help text # # Configuration of each parameter # # name - (optional) name of the parameter # more - (optional) true or false # presence - optional or mandatory # type - void - A parameter without a value # words - any - Multi word param. Only valid for the last param # flag - Extra word added before the parameter value # prefix - Extra string prepended to the parameter value # help - Command help text cat << EOF begin command modes: config styles: c i j cmdpath: user-wizard help: Add a new user end EOF exit ;; *) break ;; esac shift done ## Ask for user name while true; do echo -n "Enter user name: " read user if [ ! -n "${user}" ]; then echo "You failed to supply a user name." elif ncs-maapi --exists "/aaa:aaa/authentication/users/user{${user}}"; then echo "The user already exists." else break fi done ## Ask for password while true; do echo -n "Enter password: " read -s pass1 echo if [ "${pass1:0:1}" == "$" ]; then echo -n "The password must not start with $. Please choose a " echo "different password." else echo -n "Confirm password: " read -s pass2 echo if [ "${pass1}" != "${pass2}" ]; then echo "Passwords do not match." else break fi fi done groups=`ncs-maapi --keys "/nacm/groups/group"` while true; do echo "Choose a group for the user." echo -n "Available groups are: " for i in ${groups}; do echo -n "${i} "; done echo echo -n "Enter group for user: " read group if [ ! -n "${group}" ]; then echo "You must enter a valid group." else for i in ${groups}; do if [ "${i}" == "${group}" ]; then # valid group found break 2; fi done echo "You entered an invalid group." fi echo done echo "Creating user" ncs-maapi --create "/aaa:aaa/authentication/users/user{${user}}" ncs-maapi --set "/aaa:aaa/authentication/users/user{${user}}/password" \ "${pass1}" echo "Setting home directory to: /homes/${user}" ncs-maapi --set "/aaa:aaa/authentication/users/user{${user}}/homedir" \ "/homes/${user}" echo "Setting ssh key directory to: /homes/${user}/ssh_keydir" ncs-maapi --set "/aaa:aaa/authentication/users/user{${user}}/ssh_keydir" \ "/homes/${user}/ssh_keydir" ncs-maapi --set "/aaa:aaa/authentication/users/user{${user}}/uid" "1000" ncs-maapi --set "/aaa:aaa/authentication/users/user{${user}}/gid" "100" echo "Adding user to the ${group} group." gusers=`ncs-maapi --get "/nacm/groups/group{${group}}/user-name"` for i in ${gusers}; do if [ "${i}" == "${user}" ]; then echo "User already in group" exit 0 fi done ncs-maapi --set "/nacm/groups/group{${group}}/user-name" "${gusers} ${user}"
Calling $NCS_DIR/examples.ncs/getting-started/using-ncs/7-scripting/scripts/command/echo.sh
with the argument --command
argument produces a
command section and a couple of param sections:
$ ./echo.sh --command
begin command
modes: oper
styles: c i j
cmdpath: my script echo
help: Display a line of text
end
begin param
name: nolf
type: void
presence: optional
flag: -n
help: Do not output the trailing newline
end
begin param
name: file
presence: optional
flag: -f
help: Redirect output to file
end
begin param
presence: mandatory
words: any
help: String to be displayed
end
In the complete example
$NCS_DIR/examples.ncs/getting-started/using-ncs/7-scripting
there is a README
file and a simple
command script
scripts/command/echo.sh
.
Policy scripts are invoked at validation time, before a change is committed. A policy script can reject the data, accept it, or accept it with a warning. If a warning is produced, it will be displayed for interactive users (e.g. through the CLI or Web UI). The user may choose to abort or continue to commit the transaction.
Policy scripts are typically assigned to individual leafs or containers. In some cases it may be feasible to use a single policy script, e.g. on the top level node of the configuration. In such a case, this script is responsible for the validation of all values and their relationships throughout the configuration.
All policy scripts are invoked on every configuration change. The policy scripts can be configured to depend on certain subtrees of the configuration, which can save time but it is very important that all dependencies are stated and also updated when the validation logic of the policy script is updated. Otherwise an update may be accepted even though a dependency should have denied it.
There can be multiple dependency declarations for a policy script. Each declaration consists of a dependency element specifying a configuration subtree that the validation code is dependent upon. If any element in any of the subtrees is modified, the policy script is invoked. A subtree is specified as an absolute path.
If there are no declared dependencies, the root of the configuration tree (/) is used, which means that the validation code is executed when any configuration element is modified. If dependencies are declared on a leaf element, an implicit dependency on the leaf itself is added.
Each policy script must handle the argument
--policy
and, when invoked, write a
policy
section to stdout
. The script
must also perform the actual validation when invoked with the
argument --keypath
.
The following settings can be used to configure a policy script:
keypath
-
Mandatory. Keypath is a path to a node in the configuration data tree. The policy script will be associated with this node. The path must be absolute. A keypath can for example be
/devices/device/c0
. The script will be invoked if the configuration node, referred to by by the keypath, is changed or if any node in the subtree under the node (if the node is a container or list) is changed. dependency
-
Declaration of a dependency. The dependency must be an absolute keypath. Multiple dependency settings can be declared. Default is
/
. priority
-
An optional integer parameter specifying the order policy scripts will be evaluated, in order of increasing priority, where lower value is higher priority. The default priority is
0
. call
-
This optional setting can only be used if the associated node, declared as
keypath
, is a list. If set toonce
, the policy script is only called once even though there exists many list entries in the data store. This is useful if we have a huge amount of instances or if values assigned to each instance have to be validated in comparison with its siblings. Default iseach
.
A policy that will be run for every change on or under /devices/device.
begin policy keypath: /devices/device dependency: /devices/global-settings priority: 4 call: each end
When NSO has come to the conclusion that
the policy script should be invoked to perform its validation
logic, the script is invoked with the option
--keypath
. If the registered node is a leaf,
its value will be given with the --value
option.
For example --keypath /devices/device/c0
or if
the node is a leaf --keypath
/devices/device/c0/address --value 127.0.0.1
.
Once the script has performed its validation logic it must exit with a proper status. The following exit statuses are valid:
0
-
Validation ok. Vote for commit.
1
-
When the outcome of the validation is dubious it is possible for the script to issue a warning message. The message is extracted from the script output on stdout. An interactive user has the possibility to choose to abort or continue to commit the transaction. Non-interactive users automatically vote for commit.
2
-
When the validation fails it is possible for the script to issue an error message. The message is extracted from the script output on stdout. The transaction will be aborted.
A policy denying changes the configured trace-dir for a
set of devices it can use the check_dir.sh
script.
#!/bin/sh usage_and_exit() { cat << EOF Usage: $0 -h $0 --policy $0 --keypath <keypath> [--value <value>] -h display this help and exit --policy display policy configuration and exit --keypath <keypath> path to node --value <value> value of leaf Return codes: 0 - ok 1 - warning message is printed on stdout 2 - error message is printed on stdout EOF exit 1 } while [ $# -gt 0 ]; do case "$1" in -h) usage_and_exit ;; --policy) cat << EOF begin policy keypath: /devices/global-settings/trace-dir dependency: /devices/global-settings priority: 2 call: each end EOF exit 0 ;; --keypath) if [ $# -lt 2 ]; then echo "<ERROR> --keypath <keypath> - path omitted" usage_and_exit else keypath=$2 shift fi ;; --value) if [ $# -lt 2 ]; then echo "<ERROR> --value <value> - leaf value omitted" usage_and_exit else value=$2 shift fi ;; *) usage_and_exit ;; esac shift done if [ -z "${keypath}" ]; then echo "<ERROR> --keypath <keypath> is mandatory" usage_and_exit fi if [ -z "${value}" ]; then echo "<ERROR> --value <value> is mandatory" usage_and_exit fi orig="./logs" dir=${value} # dir=`ncs-maapi --get /devices/global-settings/trace-dir` if [ "${dir}" != "${orig}" ] ; then echo "/devices/global-settings/trace-dir: must retain it original value (${orig})" exit 2 fi
Trying to change that parameter would result in an aborted transaction
admin@ncs(config)#devices global-settings trace-dir ./testing
admin@ncs(config)#commit
Aborted: /devices/global-settings/trace-dir: must retain it original value (./logs)
In the complete example
$NCS_DIR/examples.ncs/getting-started/using-ncs/7-scripting/
there is a README
file and a simple
policy script
scripts/policy/check_dir.sh
.
Post-commit scripts are run when a transaction has been committed, but before any locks have been released. The transaction hangs until the script has returned. The script cannot change the outcome of the transaction. Post-commit scripts can for example be used for logging, sending external events etc. The scripts run as the same user id as NSO.
The script is invoked with --post-commit
at script (re)load. In future releases it is possible that the
post-commit
section will be used for control of
post-commit scripts behavior.
At post-commit, the script is invoked without parameters. In
that context the script may make use of the environment
variables NCS_MAAPI_USID
and
NCS_MAAPI_THANDLE
in order to attach
to the active (read-only) transaction.
This makes it simple to make use of the ncs-maapi command. Especially the command ncs-maapi --keypath-diff / may turn out to be useful, as it provides a listing of all updates within the transaction on a format that is easy to parse.
All post-commit scripts must be able to handle the argument
--post-commit
and, when invoked, write
an empty post-commit
section to stdout
:
begin post-commit end
Assume the administrator of a system would want to have a mail
each time a change is performed on the system, a script such
as mail_admin.sh
:
#!/bin/bash set -e if [ $# -gt 0 ]; then case "$1" in --post-commit) cat << EOF begin post-commit end EOF exit 0 ;; *) echo echo "Usage: $0 [--post-commit]" echo echo " --post-commit Mandatory for post-commit scripts" exit 1 ;; esac else file="mail_admin.log" NCS_DIFF=$(ncs-maapi --keypath-diff /) mail -s "NCS Mailer" admin@example.com <<EOF AutoGenerated mail from NCS $NCS_DIFF EOF fi
If the admin then loads this script
admin@ncs#script reload debug
$NCS_DIR/examples.ncs/getting-started/using-ncs/1-simulated-cisco-ios/scripts: ok post-commit: mail_admin.sh: new --- Output from $NCS_DIR/examples.ncs/getting-started/using-ncs/1-simulated-cisco-ios/scripts/post-commit/mail_admin.sh --post-commit --- 1: begin post-commit 2: end 3: --- admin@ncs#config
Entering configuration mode terminal admin@ncs(config)#devices global-settings trace-dir ./again
admin@ncs(config)#commit
Commit complete.
This configuration change will produce an email to admin@example.com
with subject NCS Mailer
and body
AutoGenerated mail from NCS value set : /devices/global-settings/trace-dir
In the complete example
$NCS_DIR/examples.ncs/getting-started/using-ncs/7-scripting/
there is a README
file and a simple
post-commit script
scripts/post-commit/show_diff.sh
.