Avatar

In part 1 of this blog series we covered advanced concepts including if statements, regexp and bound variables.  This post takes bound variables one step further and provides some more sophisticated examples linking them into loops.

Bound Variables – advanced

The last blog showed how data about a device (device Product Id) could be accessed from within a template.   Another common use case  is to pass in information about interfaces on the device to the template.  This is achieved through a bound variable.  In this case there will be a list of interfaces, each with attributes.    The template below expects a list of interfaces ${interfaces}.   The foreach statement will look at each one and assign it to the variable $interface.

The if statement looks for interfaces with an attribute called “interfaceType” and “mediaType”.  Essentially looking for copper interfaces on the switch.  In the simple example, the template just updates the description to include the interfaceType and mediaType. It could easily be changed to add any configuration to the interface.

#foreach ($interface in ${interfaces})
#if ($interface.interfaceType == "Physical"  && 
    $interface.mediaType == "10/100/1000BaseTX")

interface $interface.portName
description $interface.interfaceType $interface.mediaType
#end
#end

To define the binding, click on the variable definition icon in the template (as in the earlier blog). Again, it is bind to source. The source is “inventory” and this time the entity is “interface”. No attributes are selected, which means all of them are provided to the template.

How do you know what attributes are available? Click in the attribute section and it will provide a dropdown. Alternatively, a REST API call for /dna/intent/api/v1/interface, below is an example.

{
      "adminStatus": "UP",
      "className": "SwitchPort",
      "description": "",
      "deviceId": "a9265e64-4384-4498-9037-64033fba31c1",
      "duplex": "AutoNegotiate",
      "id": "3faf73ef-bdc3-4d5c-bb9e-d6219d9b9f65",
      "ifIndex": "18",
      "instanceTenantId": "5d817bf369136f00c74cb23b",
      "instanceUuid": "3faf73ef-bdc3-4d5c-bb9e-d6219d9b9f65",
      "interfaceType": "Physical",
      "ipv4Address": null,
      "ipv4Mask": null,
      "isisSupport": "false",
      "lastUpdated": "2020-04-21 07:48:55.517",
      "macAddress": "6c:41:6a:0d:e7:8b",
      "mappedPhysicalInterfaceId": null,
      "mappedPhysicalInterfaceName": null,
      "mediaType": "10/100/1000BaseTX",
      "nativeVlanId": "1",
      "ospfSupport": "false",
      "pid": "WS-C3650-48PQ-E",
      "portMode": "access",
      "portName": "GigabitEthernet2/0/11",
      "portType": "Ethernet Port",
      "serialNo": "FDO17020000",
      "series": "Cisco Catalyst 3650 Series Switches",
      "speed": "1000000",
      "status": "down",
      "vlanId": "1",
      "voiceVlan": null
    }

To deploy this template, goto inventory, select a device then choose provision. It is assumed the site profile has been created and the template added to the profile. When you see “Advanced Config” select your device (in this case adam-WS-C3650-48PQ-E).

Then click on interfaces (underneath binding). A list of interfaces for the device will appear and you can select one or more. The red box shows two were selected.

 

After provisioning the interface will have the following description.  Obviously not a real example, but an educational one.

show run int g2/0/10
Building configuration...

Current configuration : 122 bytes
!
interface GigabitEthernet2/0/10
 description Physical 10/100/1000BaseTX

 

Appending a Description

A more realistic situation is appending the “lan” keyword to the description of an interface.  This is presently required for Application Visibility in Cisco DNA Center.

The template loops through all interfaces.  If the interface is physical and and access port, look to see if the lan field is already configured via the regular expression (“.* lan”) .  Append “lan” to the description if it is not present.

#foreach ($interface in ${interfaces})

#if ($interface.interfaceType == "Physical" && $interface.portMode == "access") 

#if  ($interface.description.matches(".* lan")) 
int $interface.portName
desc $interface.description
#else
int $interface.portName
desc $interface.description lan 
#end
#end
#end 

This will change the configuration of g2/0/11 as follows:

show run int g2/0/11
Building configuration...

Current configuration : 150 bytes
!
interface GigabitEthernet2/0/11
 description Physical 10/100/1000BaseTX lan 
 switchport

For Software defined Access (SDA), this template can be made more explicit. The vlan of an access port is between 1000 and 2000. vlan needs to be converted to an integer so mathematical operators can be used, as <> do not apply to strings.

#set($Integer = 0)
#foreach ($interface in ${interfaces})

## convert vlan to integer
#if ($interface.vlanId)
#set ($vlan = $Integer.parseInt($interface.vlanId))
#end

#if ($interface.interfaceType == "Physical" && 
 $vlan < 2000 && $vlan > 1000) 

#if  ($interface.description.matches(".* lan))
int $interface.portName
desc $interface.description
#else
int $interface.portName
desc $interface.description lan 
#end
#end
#end

Some Tips

When using bound variables, remember this is the DNAC view of the device.  If you have made some recent change to the configuration, make sure you resync the device (and that has completed) before applying the template.  By default, resync occurs every 6 hours, or within 10mins of a configuration change.

When you apply the same template, with the same values to a device, DNAC will not push it again.  To force a template to be pushed again use the “Push these templates even if its deployed before” option.

What Next?

This blog shows advanced topics for velocity templates.  The next blog in the series will look at interactive  and exec commands embedded in templates.

In the meantime, if you would like to learn more about Cisco DNA Center you could visit  Cisco Devnet.

Thanks for reading

@adamradford123

Related resources: