Avatar

I wrote an earlier blog post on using Velocity templates in Plug-and-Play.  I promised to provide more advanced examples and this blog is a start.  Velocity is a template programming language and has been used in Cisco Prime Infrastructure and APIC-EM.  This series is focused on Day-N templates.  The information from the first blog post is assumed, if you missed it, a short recap on variables.

Variables

At the heart of any template is the concept of a “variable”.  Variables allow parts of configuration to be customized for a specific device, while ensuring other parts are standardized across all devices.   A single configuration template can be applied to many devices.  In Velocity, variables begin with “$”.   If you need to have a variable embedded in a string, you can use ${var} to denote the variable.

To configure a hostname for a network device, the cli command “hostname adam-router” is used.  “adam-router” is the name of the device.  When applying this template to a set of devices, the only thing that changes is the variable (${hname}).  By setting the variable hname = “adam”, “adam-router” would be rendered.

hostname ${hname}-router

Bound Variables

It is possible to access information about the device (from DNAC perspective) using a binding.  Attributes about the device, such as it’s model number can by linked to a variable.  For example in the following template I want to set ${device} to the device product ID (PID) from the inventory.

hostname ${hname}-${device}

When the template is defined in template programmer, click on the variable section.

Selecting the Variables for Template

Then click the variable (device) and bind to source (bottom right).  Select Source = “Inventory”, Entity = “Device” and Attribute = “platformId”.   This indicates this variable should come from the inventory, specifically data about the device.  The attribute is optional, but in this case just the “platformId” (model number) is required.  For a stack this will be a comma separated list.

Binding the Variable

This will render as hostname adam-WS-C3650-48PQ-E when applied to a 3650 switch.

Conditionals

Most programming languages provide if-else constructs. In Velocity, this is simple, #if #end statements denote a simple condition.  There are a number of use cases for if statements.

Optional Variables

Sometimes a variable may be optional, and the configuration line should only be rendered if the variable is set.  In the example below, if the $data_vlan variable is empty, the vlan configuration would be skipped

#if($data_vlan != "")
vlan $data_vlan
name userdata
#end

Related Variables

Based on one variable, you may want to set some others.  This reduces the number of variables needed in the template.  #set is used to assign a variable.  In the example below, if the value of $hostname is “switch01” then the variable $loopback  is set to “10.10.100.1”.

#if ($hostname == "switch01")
#set ($loopback = "10.10.100.1")
#elseif ($hostname == "switch02")
#set ($loopback = "10.10.100.2")
#end

int lo0
ip address $loopback 255.255.255.255

Enable/Disable Trigger

Another example is to trigger a feature to be either enabled or disabled.  For example, a variable could be used to toggle enabling/disabling netflow.  To simplify the example, assume the definition of the netflow collector is also in the template.  The interface name could also be a variable.  In this example “apply” is set to “true” to enable netflow on the interface, and anything else will disable netflow.

int g1/0/10
;#if ($apply == "true")
ip flow monitor myflow input
#else 
no ip flow monitor myflow input
#end 

Regular Expressions

The if statements above showed an exact match of a string. How would a pattern match be done?  Fortunately, regular expression (regexp) are supported.  A detailed discussion of regexp is outside the scope of this post, as there are lots of other places to find tutorials on regexp.

For example,  a single template could do something specific for 9300 switches and still be applied to non-9300 switches.  The model number of the switch (from the inventory) is available via a bound variable.  As seen in the section above.   9300 series switches have a model number structured as 9300-NNXXX or 9300L-NNXXX-YY.  For example, C9300-24UB, C9300-48UXM, C9300L-24P-4G.

The regular expression is “C9300L?-[2|4][4|8].*”. The first part is just a string match “C9300”.  The “L?” means “L” is optional, sometimes it is present, sometimes not.  “-” is just a match.  “[2|4]” means either 2 or 4, and the same with “[4|8]”.  Finally, “.*” matches any remaining letters.  The variable is $model and $model.matches() will return true is the regular expression matches.

#if ($model.matches("C9300L?-[2|4][4|8].*") )
#set ($var = "9300")
#end

The other way regular expressions can be used is to replace parts of a string.   In this example, I want to extract the number of ports on the switch from the model number.

I am using “replaceAll” vs “match”.  ReplaceAll takes a regular expression, as well as an argument to specify what to replace it with.  In this case “$1” is going to replace the contents of the regular expression.  The regular expression is identical to above, with one difference “([2|4][4|8])“.  The () saves the pattern inside, and it can be later referenced as “$1”.  This pattern is the number of ports.  It will match 24 or 48.   $ports would be set to either 24 or 48.

#set($ports = $model.replaceAll("C9300L?-([2|4][4|8]).*","$1"))
$ports

If $model = ” C9300L-24P-4G”, then $ports will be set to 24.

What’s Next?

This blog shows advanced topics for Velocity templates. The next blog in the series will extend these to cover bound variables in more detail, providing some more examples.

In the meantime, if you would like to learn more about Cisco DNA Center, please visit the  Cisco DNA Center page on Cisco DevNet.

Thanks for reading

@adamradford123