Avatar

Earlier blog posts in this Cisco DNA Center series gave an overview of PnP, how to use the API and an introduction to the configuration template editor.  This blog post explores creating templates in velocity.  Velocity is a template programming language, used in Cisco Prime Infrastructure and APIC-EM.

Template Engine

The template engine can be used for either Day-0 (PnP) or Day-N (provisioning) changes.  There are a couple of subtle implications of this.

  1. All templates are rendered on DNAC. This means the velocity language does not have access to the current configuration of the device.
  2. PnP templates are pulled from DNAC as a single configuration file and copied to running configuration. Note that composite templates are not currently supported.
  3. Day-N configuration pushes the rendered configuration to the device. This mode supports interactive commands as well as exec commands. EEM scripts can be used to address this limitation for PnP.

Basic Variables

At the heart of any template is the concept of a “variable”.  Variables allow parts of a configuration to be customized for a specific device, while ensuring other parts are standardized across all devices.   A single configuration template is required, but it can be applied to many devices.  In velocity, variables begin with “$”.   A trivial example follows.

hostname  $hname 

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 ).

Advanced Variables

In the example above, there may be a requirement to always end the hostname with “-router”.  The “{}” can be used to specify which part of a string is a variable and which is a string.  In the example below, the suffix will always be “-router” and $hname would be set to “adam” to achieve a similar result to the first example.

hostname  ${hname}-router

When the variable $hname is set to “adam” the template renders as

hostname adam-router

Escaping Variables

Occasionally “$” is required to be used in the configuration for something other than a variable. This is often seen in encrypted passwords for example.  It is possible to mark  these as “not a variable” in the UI.

It is also possible to create a dummy variable for “$” and use that instead.

#set ($d = "$")
enable secret 5 werw${d}2dsf3423${d}dd${d}

In the example above, a variable “d” is defined as “$”.  The “${d}” syntax is used where ever a “$” is required.  The template above renders as

enable secret 5 werw$2dsf3423$dd$

Macros

Macros are a great way of encapsulating a block of CLI. For example, define a configuration block for an uplink. For example, define a configuration block for an uplink.  Once the macro “uplink_interface” has been defined, it can be referenced as #uplink_interface

#macro(uplink_interface)
switchport trunk native vlan 999
switchport mode trunk
channel-group 1 mode active
#end

interface Ten1/0/1
#uplink_interface

This will render as:

interface Ten1/0/1
switchport trunk native vlan 999
switchport mode trunk
channel-group 1 mode active

Loops

Loops are a powerful control construct that can be used in templates.  One common application is when combined with macros.  The macro “uplink_interface” was defined above, and it needs to be applied to every uplink in a switch stack.  A variable called stack_count is provided to the template which contains the number of switches in the stack.

#set ($stack_member_count = $stack_count)

#foreach($switch in [1..${stack_member_count}])
interface Ten${switch}/0/1
#uplink_interface
#end

When the variable “stack_count” is set to “2”, the template renders as shown:

interface Ten1/0/1
switchport trunk native vlan 999
switchport mode trunk
channel-group 1 mode active

interface Ten2/0/1
switchport trunk native vlan 999
switchport mode trunk
channel-group 1 mode active

It is important to define the data type of $stack_count as an integer.  An integer will be treated as a number so the range [1..4] is shorthand for [1,2,3,4] for example.  The earlier blog showed how to change the type of a variable.  Here is a reminder

Manipulating IP Addresses

The final example shows how to manipulate IP addresses.  A common example is supplying an IP address and needing to create the default gateway in a configuration file.    The variable $ip has been defined as a string with IP address syntax.  The split command breaks the string up on octet boundaries and returns an array.  This is assigned to the variable $octets.

#set ($octets = $ip.split('\.'))

gateway $octets[0].$octets[1].$octets[2].1

If $ip is set to “10.11.12.240”, the template will render as

gateway 10.11.12.1

Optionally the data type of “$ip” can be set to ipAddress. This will do input validation in the UI of the template.  If left as Data Type string, then any text could be entered.

What Next?

This blog shows more detail on the template language – velocity.  The next blog in the series will cover some advanced use cases

In the meantime, if you would like to learn more about this, you could visit  Cisco DevNet. DevNet has further explanations about this. In addition, we have a Github repository where you can get examples related to PnP.

Thanks for reading!

@adamradford123


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



Authors

Adam Radford

Distinguished System Engineer

APJ