Plug-and-Play Scripting
Use NSO's plug-and-play scripting mechanism to add new functionality to NSO.
A scripting mechanism can be used together with the CLI (scripting is not available for any other northbound interfaces). This section is intended for users who are familiar with UNIX shell scripting and/or programming. With the scripting mechanism, an end-user can 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 by using another scripting language that is supported by the OS, e.g., Python, or even as compiled code. The scripts are run with the same user ID as NSO.
The examples in this section are written using shell scripts as the least common denominator, but they can be written in another suitable language, e.g., Python or C.
Script Storage
Scripts are stored in a directory tree with a predefined structure where there is a sub-directory for each script category:
For all script categories, it suffices to just add a valid script in the correct sub-directory 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 script directories. The sample ncs.conf
file that comes with the NSO release specifies two script directories: ./scripts
and ${NCS_DIR}/scripts
.
Script Interface
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) the following as an argument depending on the script category.
--command
--policy
--post-commit
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 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 follow. 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 readability.
For examples see each corresponding section below.
Script Loading
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 the reload of scripts:
debug
: Shows additional debug info about the scripts.
An example session reloading scripts:
Command Scripts
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
.
command
Section
command
SectionThe 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 beoper
,config
or both (separated with space).styles
: Defines in which CLI styles the command should be available. The value can be one or more ofc
,i
andj
(separated with space).c
means Cisco style,i
means Cisco IOS, andj
J-style.cmdpath
: Is the full CLI command path. For example, thecommand
pathmy 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:
param
Section
param
SectionNow let's look at various aspects of a parameter. 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. Seeflag
andprefix
.type
: The type of the parameter. By default each parameter has a value, but by setting the type tovoid
the CLI will not prompt for a value. 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 tooptional
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 toany
, the parameter may consist of any number of words. This setting is only valid for the last parameter.flag
: Extra argument 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:
Full command
Example
command
ExampleA command denying changes the configured trace-dir
for a set of devices, it can use the check_dir.sh
script.
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:
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
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
.
policy
Section
policy
SectionThe following settings can be used to configure a policy script:
keypath
: Mandatory. The keypath is the 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 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 key path. 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 a lower value is higher priority. The default priority is0
.call
: This optional setting can only be used if the associated node, declared askeypath
, 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
.
Validation
When NSO has concluded 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 can 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.
Full policy
Example
policy
ExampleA policy denying changes the configured trace-dir
for a set of devices, it can use the check_dir.sh
script.
Trying to change that parameter would result in an aborted transaction
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
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 the 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.
post-commit
Section
post-commit
SectionAll post-commit scripts must be able to handle the argument --post-commit
and, when invoked, write an empty post-commit
section to stdout
:
Full post-commit
Example
post-commit
ExampleAssume 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
:
If the admin
then loads this script:
This configuration change will produce an email to admin@example.com
with subject NCS Mailer
and body.
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
.
Last updated