Help us improve your experience.

Let us know what you think.

Do you have time for a two-minute survey?


Building Templates

A rule performs checking based upon patterns. Thus, to form a rule, you should define both pattern(s) and rule(s).

Cisco IOS Example

The following is an example Cisco IOS template made up of two patterns “hasip” and “shutdown” followed by a rule “Shutdown_or_noip” which checks the interface block based on the presence or absence of these two patterns. The interface blocks (represented by keyword “interface”) are looped through with a “foreach” statement. If either pattern “hasip” is not matched or pattern “shutdown” is matched, a severity level of “warning” is raised. Otherwise, a severity level of “information” is raised via the print statement (equivalent of “raise info”).


In the pattern hasip, note that the word following “ip address” is being saved into a variable with name “myip”, so that the IP address can be printed out subsequently in the Shutdown_or_noip rule.

Blank lines and white spaces in templates are ignored (except when used in regular expressions). So using blank lines to separate blocks of text in the template are not necessary

Juniper JUNOS Example

The following is a simple Juniper example to check a global variable, the OS version, and raise different severity levels depending upon the OS version. In this case, referencing a pattern is not necessary, since $(version) is a global variable.

Because Junos contains a well-defined hierarchical structure defined by braces, it is possible to design configuration compliance assessments at specific levels of the hierarchy. For example, the following rule check_rsvp checks for the existence of traceoptions under the protocols rsvp clause of each device:


For Junos pattern definitions, key structural characters like ‘{‘ and ‘;’ should not be substituted by a regular-expression, since they have special meanings to the program.

For example, if there is a section for chassis as follows, the user can use the syntax chassis.fpc.pic to loop through the pic’s as in “foreach chassis.fpc.pic do”:

If the next item in the hierarchy is an unknown name, such as for the interfaces {} block, under which are the interface names such as ge-0/0/1, ge-0/0/2, etc. the keyword “child” can be used as follows, and its contents can be printed using $(instance).

For more Paragon Planner keywords, see Paragon Planner Keywords For Use Within a Rule.

Match Ordered, Unordered, or Exact

In addition to performing compliance assessments on specific blocks of code, there is a rule to check for lines within the entire configlet, using the keyword “match”, or its equivalent keyword “conform.”

Suppose the config file contains five lines:

Then within the template file, we can define patterns, and rules to check for an exact match of the pattern, an ordered match, or an unordered match:

Match and Severity

The match function will categorize the matched results based on different matched conditions. The severity of these categories be changed from the Settings option and saved per project. The following categories are available:

  • Matched: matched

  • Missing line: missing line from the defined template

  • Missing block: the first line is missing from the defined template

  • Extra line: there is an extra line from the defined template

  • Unordered line: the line is not in the same order as the defined template.

Match Block with Variables

In some configurations, the block to match may be slightly different based on different routers or vendors. This match block with variable feature allows users to define statements to account for these cases.

In the following example, we will try to match the policy statement. On each router, the term is different based on the router’s country code and location which can be extracted from the router’s hostname.

Table 1: Template Syntax

@define <Pattern Name>

Define a pattern of a block of text. It could contain one word, one line or multiple lines.

- Wild card, *, can be used to match any text. Alternatively, regular expression can be used if appropriate #conform use regular-expression statement is included in the header.

- Note: The wild card should not be used to hide key syntax operators on the first line such as braces ‘{‘ and semi-colons ‘;’

- $(<Variable Name>) can be used to capture and turn any text into a variable, which can then be printed out in the subsequent rule.

Example: @define pattern1 ip vrf $(vrf) rd $(rd) route-target export * route-target import *

@define rule <Rule Name>

Define a compliance assessment rule used for the syntax checking.

- Multiple rules can be defined within one template.

- Rules can be assigned to different categories by adding category=<Category Name> in the end. - Various flow control, loop, logic boolean, logic operator, print functions can used in the rule.

- Additional flow controller keyword:

Exit : Once flow reaches exit statement, program will immediately stop checking for the current rule and move on to the next rule if any.

Example :

@define rule BFD-Check category=Protocol

@define external <Rule Name> output=[<path>|append]

Define a rule to execute an external program:

- A external program can be written in any language which uses stdout as result output, e.g., a perl script could be used. Make sure this program is executable from the command line.

- The result can be either output to a file or it can be appended to wandl’s compliance assessment report if the result is in the same CSV format or can be output to another separate file.

Example :

@define external rule1 output=/tmp/ls.csv /usr/bin/ls -l @define external rule2 output=append /export/home/wandl/

@define description <Rule Name>

Provide a description/explanation for the compliance assessment rule.

Example : @define description This rule checks whether the interface is shutdown or not

Table 2: Flow Control Syntax

foreach <block> doend

Define a loop function to go through each pattern block matched in configuration, or to loop through each array element of an array. Flow controller keywords to use within the loop function include the following:

- Next : Once flow reaches next statement, program will immediately stop the current loop and move on to the next loop.

- Break : program will immediately leave the current foreach loop. Note that nested loops can be used in configuration files with well-defined hierarchical structures, such as Junos.

Example for array, using reserved keyword $(element):

foreach $(your_array) do
print $(element)

You can get an array element by using the subscript operation. It’s syntax as follows:


If $(array) is an array and $(index) is a number variable, then $(array.index), $(array.0), $(array.1), are valid syntax.

$(array.length) will return the size of the array.

The keyword in can be used to check if a variable exists in an array if $(string1) in $(array1) then...

Example for pattern block:

@define hasbandwidth
bandwidth $(bandwidth);
@define rule junosrule1 category=Interface
foreach interfaces.child.unit do
if hasbandwidth then print “$(interfaces.child)
has bw $(bandwidth)”

Nested loops are allowed for pattern blocks only if the nested loop loops through a descendent of the parent loop. For example, the above could be written as follows:

foreach interfaces.child do
for each unit do
if hasbandwidth then print “$(interfaces.child)
has bw $(bandwidth)”

if (<boolean logic condition>) thenelseif (<boolean logic condition>) thenelseend

Define a boolean logic condition to separate flow into different scenarios based on true or false boolean result.

- Both elseif and else statements are optional.

- Multiple elseif statements are allowed, if necessary.

- Additional Boolean logic operator keywords include the following:



if (pattern1 && !pattern2) then print “pattern1 matched and pattern2 unmatched” elseif (pattern1 && pattern2) then print "both pattern1 and pattern2 matched " elseif (pattern3 ~= “Loopback*”) then print "loopback found in pattern3" else print "none of above" end

Table 3: Built-In Functions For Use Within a Rule

$(<Variable Name>)

To define a variable.

Example: $(x)


To define a string.

Example: “This is a string”


To define a value to a variable

Example: set $(x) 1


Arithmetic addition between number value or number variable or concatenate between string and string variable.

Example 1 : set $(count) $(count) + 1

Example 2 : set $(string1) $(hostname) + "," + $(


To read in an external plain-text file containing multiple lines into a single degree string array variable. One line per array member which can be used together with “In: function.

Example : read $(array1) "/tmp/interface-list.txt"


Note: /tmp/interface-list.txt contains following lines Router1,interface1 Router2,interface2 RouterN,interfaceN


To add an element to an array. add $(your_array) $(your_element)

Example :foreach interfaces.child do if $(instance) ~= "xe*" then add $(full_interface_list) $(instance) end end

To copy one array to another array. add $(array1) "a" add $(array1) "b" add $(array2) $(array1) print “test case 1: $(array2)” # prints “[a, b]” add $(array2) "c" print "test case 1: $(array2)" # prints "[a, b, c]"


To remove an element from an array. remove $(your_array) $(your_element)

Example :foreach protocols.isis.interface do if $( ~= "xe*" then if isis_disable then remove $(full_interface_list) $( end end end


To check if a string variable exists in a string array and yield true or false boolean value.

Example :fif $(string1) in $(array1) then raise info "$(string) is in the file" end


To write strings into a file. This can be used to create custom reports or output file. The first input parameter is the file to write in. The second input parameter is the string to write in the file. If the file already exists, it will be overwritten.

Example :@define rule test_write set $(file) "/home/wandl/CAT/test/write_file.txt" foreach interfaces.child do print "$(hostname),$(instance),$(description)" writeln $(file) "$(hostname),$(instance),$(description)" end

This will generate a file called write_file.txt in the directory /home/wandl/CAT/test/ with content similar to this sample:

J1,ge-0/0/0,management interface for J1
J1,ge-0/0/1,to 3550S2 FastEthernet0/23
J1,lo0,loop - provision by WANDL


To print a message entry to the compliance assessment result report with severity assigned (pass, info, minor, major and critical)

To print a message entry to the compliance assessment result report with severity assigned (pass, info, minor, major and critical)

Example :

major “This is a major event" As a shortcut, a number can be used. The mapping between severities and numbers are as follows:

- critical: 5 - major: 4 - minor: 3 - warning: 2 - info: 1 - pass: 0

Example :raise 4 “This is a major event"


Print is equivalent to raising an info message:

Example :print “This is a info event"


The “child” property can be used within a foreach loop to access the child item.

Example :In the following configlet segment, ge-* and xe-* can be accessed using “foreach class-of-service.interfaces.child do”

class-of-service {interfaces { ge-* { } xe-* { }


To get a list of single words from config block use the keyword "line"

prefix-list list1 {;;; } e.g. foreach policy-options.prefix-list do if $( == "list1" then foreach line do print "$(instance)" end end end


For arrays, a reserved variable to refer to the value of the current array object:

Example: foreach $(your_array) do print $(element) done

conform <Pattern Name> match <Pattern Name>

Looks for a match for the provided pattern and automatically raises a message entry into the resulting report. The Detailed Results tab will show related line numbers and line content under Template Line and Template Line #.

Matches if all lines and subblocks exists in config file. These lines do not have to be in the same order for a match.

Example :conform myconfiglet

conform ordered <Pattern_name> match ordered <Pattern_name>

All template lines and block should be in configuration file. In addition, all the lines must be ordered correctly. Note that config files may have additional lines or subblocks.

Example :conform ordered myconfiglet

conform exact <Pattern_name> match exact <Pattern_name>

To match, the config file must contain the exact same section as the template. In addition to having the lines ordered in the same way, no additional lines are allowed in that section for a match.

Example :conform exact myconfiglet