Commands for NCM config change templates
There are two commands in a config change template:
-
script
: Defines the input type for each variable defined by the template parameters. -
CLI
: Includes the arguments and logical operations needed to produce a set of CLI commands and execute those commands against each NCM node targeted for a specific config change.
For more information, see:
Script command
The script{}
command declares the input type for every variable defined by the template parameters. The form of the script command is:
script script_name ( data_type @variable data_type @variable data_type @variable )
The data_type
can be int
(integer), string
, or swis.entity
where swis.entity
is a SolarWinds Information Service (SWIS) entity (for example, NCM.Nodes). For descriptions of available entities, see SWIS entities used in config change templates.
Cisco example
script ConfigureVLANmembershipCiscoIOS ( NCM.Nodes @ContextNode, NCM.Interfaces[] @TargetPorts, NCM.VLANs[] @VlansToRemove, NCM.VLANs[] @VlanToAssign )
In this example, the four variables that were introduced in the parameter section of the template with an instance of PARAMETER_LABEL
are each given a specific SolarWinds Information Service entity data type:
@ContextNode
is determined with data from the NCM.Nodes entity in the database.@TargetPorts
is determined with data from the NCM.Interfaces entity.@VlansToRemove
and@VlansToAssign
are determined with data from the NCM.VLANs entity.
Any variable that references an NCM object that NCM knows through device inventory must take a SolarWinds Information Service entity as its data type. In this case, the four variables work with data that NCM captured and stored in the database through the device inventory process. If you attempt to assign a string instead of a SWIS entity in such cases, NCM fails to correctly parse your script.
CLI command
CLI{}
defines a specific CLI command that NCM issues on a target device when the config change template is executed. Its purpose is to create a command line statement that NCM can execute directly on the command line of NCM nodes targeted for the template's config changes.
The config change template creator creates a CLI command by including its arguments wrapped by curly brackets { }
. At run time, NCM parses any variables contained within CLI{}
. Often a CLI command is as simple as the command you would type directly on the command line of an NCM device.
Cisco example
To enter config mode on Cisco IOS devices, type configure terminal
. In your config change template script, add the command as follows:
CLI { configure terminal }
NCM parses the argument of the CLI{}
command by passing through the string itself (configure terminal
) as a command to execute against each targeted NCM node at template run time:
Cisco example with variables
script ConfigureVLANmembershipCiscoIOS ( NCM.Nodes @ContextNode, NCM.Interfaces[] @TargetPorts, NCM.VLANs[] @VlansToRemove, NCM.VLANs[] @VlanToAssign ) { CLI { vlan database vlan @vlaniddescription @vlandesc exit } }
This example shows a CLI statement with variables to specify VLAN properties while using the vlan database
command line editor. For purposes of demonstration, we assume that:
@vlanid
= 1@vlandesc
= Local-Office
At run time, NCM parses the CLI{ }
command as:
vlan database vlan 1 description Local-Office exit
If this were all that is included in the Change VLAN Membership on Ports Cisco IOS template, then the config change result would be to set the description of vlan 1
to Local-Office
on all NCM nodes selected as targets.
This config change template, however, actually changes the VLANs associated with targeted NCM node ports. For that we need to introduce advanced CLI{}
command logic.
Advanced CLI command logic
The scripting framework for change config templates allows you to create CLI{}
command arguments that include foreach loops, if/else conditional operations, and functions for manipulating string patterns.
Foreach loops
A foreach statement iterates through an array of items based on a SWIS entity data type. Foreach statements use the following pattern:
foreach (@ItemVaraible in @EntityArrayVariable)
A primary purpose of a foreach loop is to allow the template user to select multiple NCM objects for config change. The loop instructs NCM to perform the same config change on all items in scope as determined by the SWIS entity in the database and delimited at run time by the template user's selections in the template wizard.
Cisco example
foreach (@portItem in @TargetPorts) { CLI { interface @portItem.InterfaceDescription }
The foreach
statement creates a set that contains two related variables: @portItem
and @TargetPorts
.
The @TargetPorts
variable holds an array of objects with the data type of an SWIS entity called NCM.Interfaces[ ]
. The array will be a set of interfaces on NCM nodes.
The @TargetPorts
variable is associated with the PARAMETER_LABEL
Select port(s)
and the template user selects one or more ports at run time. The template user determines the set of interfaces to fill the array NCM.Interfaces[ ]
, and the template will perform VLAN membership config changes on each interface in that array.
@portItem
is a dynamic variable that the loop uses during its iterating to hold the value of the current interface from the array represented by @TargetPorts
.
The foreach loop format is fixed and NCM expects it to include the dynamic variable.
The user interacts with this template wizard screen:
Click Select Interfaces List to load a tree that displays available interfaces and NCM nodes previously selected in the wizard.
Conditional statements
Conditional logic in a config change template script uses an if/else pattern to define two branches of possible action, enclosing specific conditions within parentheses. Within each branch of the conditional pattern are CLI{}
commands to execute if that branch meets the specific conditions.
Here is the basic structure:
if (condition is true) CLI { execute commands } else CLI { Execute other commands }
The else section is optional. If you omit it, and the if condition is false, NCM excludes the relevant CLI{}
commands from the template output.
Operators
Use any of the following operators to specify a parenthetical condition. Use single quotes around string values.
Operator | Condition |
---|---|
== | Is Equal To |
> | Is Greater Than |
>= | Is Greater Than or Equal To |
< | Is Less Than |
<= | Is Less Than or Equal To |
!= | Is Not Equal To |
Contains | 'string' |
containsExact | 'case sensitive string' |
startsWith | 'string' |
startsWithExact | 'case sensitive string' |
endsWith | 'string' |
endsWithExact | 'case sensitive string' |
Cisco example
Add conditional logic in the foreach loop to prevent errors that may occur if the user accidentally selects an incorrect interface (for example, the loopback address).
foreach @portItem in @TargetPorts) { if (@PortItem.InterfaceDescription != 'Loop0') { CLI { interface @portItem.InterfaceDescription }
If the template encounters the loopback interface, it does nothing and passes on to the next interface. This code prevents damage from template user error.
Manipulating strings
You can use the following five functions to manipulate strings. For example, you can use them to manage ACL config changes for network firewalls when a config change template needs to iterate through a predictably variable set of IP addresses.
Substring
Use the Substring function to specify a starting point within a string and the length from the starting point that you want to capture for manipulation. Declaration:
string Substring(string str, int startIndex, int length)
where:
str
is the full string from which the substring comesstartIndex
marks the position where the substring beginslength
is the number of characters that the substring includes
StrLength
Use the StrLength function to return the length of a string. Declaration:
In StrLength(string str)
where:
str
is the user-input string whose length is used as the integer value
IndexOf
Use the IndexOf function to find the number of characters in a string. Declaration:
int IndexOf(string str, string search)
where:
str
is a string to search onsearch
is a user-input string NCM uses to find the numerical value of the string being searched
SetOctet
Use the SetOctet function to replace an octet within an IP address. Declaration:
string SetOctet(string ipAddr, int octetPosition, string octet)
where:
ipAddr
is the IP addressoctetPostion
marks the position where the target octet beginsoctet
is the new value of the target octet
GetOctet
Use the GetOctet function to retrieve an octet from a user-specified IP address and octet position. Declaration:
string GetOctet(string ipAddress, int octetPosition)
where:
ipAddress
is a user-input IP addressoctetPosition
is the user-input value for the place where the function finds the beginning of the octet to get
Example 1: Manipulating a string
script IPshuffle(string @str, string @search ) { int @length = strlength(@str) int @startIndex = indexof(@str,@search) int @substringLength = @length - @startIndexstring @res = substring(@strA, @startIndex, @substringLength) CLI { @res } }
The user enters ABCDEF
for the @str
variable and CD
for the @search
variable in the template's wizard. Based on those values, the script does the following:
- Uses
ABCDEF
in thestrlength
function to give a value of6
to a variable called@length
. - Uses
CD
as the substring ofABCDEF
to set a value2
for the variable called@startIndex
. - Subtracts 2 (
@startIndex
) from 6 (@length
) to determine the value of@substringLength
as 4. - Takes the original string
ABCDEF
and calculates a result (@res
) using@startIndex
to count in two positions and@substringlength
to count four positions from the start index. - Outputs
CDEF
as the result.
Example 2: Changing an access control list
This example creates a block of access control list (ACL) instructions that predictably vary the value of a specific octet within an IP address. The instructions conform to the pattern 10.10.@id.10
, where the value of @id
is determined by user input.
The user enters 10.10.10.10
as the value of @ipaddress
in the config change template's run-time wizard. The user enters 1
, 22
, and 222
for the @indexes
variable declared in the script command.
.PARAMETER_LABEL @ipaddress IP address .PARAMETER_DESCRIPTION @ipaddress Enter an IP address .PARAMETER_LABEL @indexes Octets .PARAMETER_DESCRIPTION @Indexes Enter a pattern of octet replacements. Separate numbers with a comma. */ script ACLChanges(string @ipaddress, int[] @indexes) { string @ipnew foreach(@id in @indexes) { @ipnew = setoctet(@ipaddress,3,@id) CLI { Allow @ipnew out Allow @ipnew UDP 2055 OUT } } }
The script uses the SetOctet
function to determine the value of an @ipnew
variable. SetOctet
is defined to take the user-input IP address and create a new IP address by iteratively replacing the third octet with user-input values. For each new IP address, the script produces a command to create outgoing UDP transmission access through port 2055:
Allow 10.10.1.10 outAllow 10.10.1.10 UDP 2055 OUT
Allow 10.10.22.10 outAllow 10.10.22.10 UDP 2055 OUT
Allow 10.10.222.10 outAllow 10.10.222.10 UDP 2055 OUT
Example 3: Managing an access control list for multiple routers
In this example, a config change template generates a block of ACL instructions for a router in a store. We create an ACL block of instructions for this device that varies based on a portion of the device's IP address.
If the store has four routers, 10.1.1.1, 10.1.4.1, 10.1.6.1, and 10.1.10.1, the template script generates an ACL block that appears this way on the selected router (10.1.1.1):
Allow 10.1.2.0/24 out
Allow 10.1.2.4 UDP 2055 OUT
Allow 10.1.4.0/24 out
Allow 10.1.4.4 UDP 2055 OUT
Allow 10.1.6.0/24 out
Allow 10.1.6.4 UDP 2055 OUT
Allow 10.1.10.0/24 out
Allow 10.1.10.4 UDP 2055 OUT
Here is the script that produces the output:
script OpenACLs(NCM.Nodes @ContextNode, string[] @IpRouters) { foreach(@ipRouter in @ipRouters) { string @octet = getoctet(@IpRouter,3) string @ipnew = setoctet(@ContextNode, 3,@octet) CLI { Allow @ipnew out Allow @ipnew UDP 2055 OUT } }
This script does the following:
- Uses a foreach loop to go through a user-input series of router IP addresses.
- Uses the
GetOctet
function to focus the third octet of the current router IP address. - Uses the
SetOctet
function to create a new IP address as a value for@ipnew
. - Creates a
CLI { }
command that will execute Allow operations for each of the selected routers.
The result is a set of Allow commands that open access in the ACL so that the router 10.1.1.1 can send OUT traffic via UDP on port 2055 to 10.1.4.1, 10.1.6.1, and 10.1.10.1.
Here are the parameters for this config change template. The template user selects the router on which to make ACL changes and inputs the target router IP address through this template:
.PARAMETER_LABEL @ACLRouter Router for ACL Change .PARAMETER_DESCRIPTION @ACLRouters Select a Router .PARAMETER_LABEL @ipRouters Target Routers .PARAMETER_DESCRIPTION @ipRouters Add Routers to Target with ACL Allowances
Tips
Including special symbols in CLI commands
If you need to include a special symbol, such as a pipe, in a CLI command, you cannot do it directly. For example, the following would break the script:
show clock | append disk0:show_tech
Instead, define a string variable with the symbol as its value, and then place the variable in the command:
script BaseChangeTemplate(NCM.Nodes @ContextNode) { string @PipeSymbol='|' CLI { show clock @PipeSymbol append disk0:show_tech } }
Including variables in CLI commands
To keep config change templates as device-independent as possible, you can include command variables defined in device templates. You can also include node variables (also called macros) to reference attributes of each node. To include these, define a string variable in the CLI command with the command or node variable as its value.
The following example uses the node variable ${StorageAddress} to reference the IP address of the TFTP server. Because the IP address is not hard-coded in the script, the script does not break if the IP address changes.
script BaseChangeTemplate(NCM.Nodes @ContextNode) { string @myTFTPImage='${StorageAddress}' + '/image.bin' CLI { copy tftp://@myTFTPImage flash ... } }
The resulting script is:
copy tftp://${StorageAddress}/image.bin flash