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.
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.
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
We’d love to hear what you think. Ask a question or leave a comment below.
And stay connected with Cisco DevNet on social!
Twitter @CiscoDevNet | Facebook | LinkedIn
Visit the new Developer Video Channel
Hi,
I have Cisco Prime Infrastructure 3.4.
We have lot of devices and so lot of long config files.
We have a requirement to do compliance and so need to generate compliance templates(policies with lot of rules).This is a lot of typing.
Can we automate this process.
How easy is it to write a script that takes a lot of info in the config-template file and convert into a compliance-template xml file.
I can then I suppose import the compliance template into PI GUI and run a compliance audit on various devices.
I could even take this compliance-template xml file and just do file comparision with other configs to deduce violations.
What are your thoughts on this? Can you point to some resources or contacts?
Thanks.
This is to save typing in a lot of rules adn policies
Hi Chakri, Cisco Prime Infra has config compliance. https://www.cisco.com/c/en/us/td/docs/net_mgmt/prime/infrastructure/3-1-5/user/guide/pi_ug/compliance.pdf
Hi Adam, thanks so much for share this example!
Regards
Juan
Glad you liked the examples Juan, enjoy the other blogs in the series
Hi,
Is it possible to check a condition against the device running config. ? for eg:
Currently i am getting an error when i try to execute the below using template.
TEST_Switchconfig)#ntp trusted-key 13
%NTP trusted-key is invalid : key already configured
This actually makes the template fail.
My intent here is to first check the running config of the device and see if this command is existing. If not push the command.
for Eg:
$var = “false”
#if ($config.contains(“ntp trusted-key 13”) )
!$config here is the variable which contains device config
#set ($var = “true”)
#end
#if ($var==”false”)
ntp trusted-key 13
#end
Hi Adam,
thanks a lot for your blog in general and these examples.
I am looking for more advanced features as so far it does not support much, but this extends it a bit.
Are there any resources on these advanced integrations of Velocity and DNAC?
Thanks a lot!