Cisco DNA Center Network Automation with Template Programmer API – Part 1

Using APIs to apply templates to network devices

Cisco DNA center provides Day0 to Day-N support for network device automation.

This blog looks at one aspect of automation, the template programmer.  Specifically, it covers the API’s used to apply templates to network devices.

Template programmer uses the velocity templating language for templates.  The templates are created via the template editor and are applied via the User Interface or programmatically via the API.

This initial blog is going to cover the basics of finding templates, getting a specific version and applying a template to a device.  To better illustrate how the API calls can be used in a practical manner, I am going to use a small python script published on github.

I am going to use a common (practical example) template of changing the vlan assigned to an interface on a switch.  The template will take two variables:

An interface name (e.g. gig1/0/20)

A vlan number (e.g. 20)

Interaction with PnP Day0

For those familiar with this blog series, I have covered day0 configuration with Network PnP and also some basic velocity examples.

Day-0 templates are applied only when the device first contacts the controller and is onboarded to the network.  Depending on your operational model, the day0 configuration might be quite small (just enough to establish secure connectivity) and day-N templates are used to apply ongoing configuration changes.

Configuration Templates on Cisco DNA Center

Step 1 – Listing Templates

The first step is to find the templates available on the Cisco DNA Center.

If you downloaded the example script, you can just run it with no arguments to see a list of templates.

(in order to run this script you will need to either edit the dnac_config.py file, or set the appropriate environment variables to customize your DNA Center and loging credentials – as outlined in the README).  The template of interest is called “Adam/int-vlan” .

The API call is shown below.  When the script is run without any argumnets, it prints the names of all templates.  The first part of the name is the template project.  In this case “Adam”.  A project is just a folder to group templates.

$ ./template.py
Available Templates:
https://dnac:443/dna/intent/api/v1/template-programmer/template
Adam/acl
Adam/binding
Adam/int-vlan
Adam/interface-des
DB/prefix
Onboarding Configuration/9300
Onboarding Configuration/advanced
Onboarding Configuration/basic
Onboarding Configuration/encs-9k
Production/base
Production/comp1
Production/interfaces

Step 2– Getting the latest version

To get more details on a particular template, the script can be run with the –template <template-name> option.   The latest version of the template (Version: 10) is selected.

The TemplateId is then used to return the body of this version of the template.

The body is quite simple, applying an access vlan to the given switch port.  This is shown in green.

The script also requires two parameters ({“vlan”:””,”interface”:””})

$ ./template.py --template Adam/int-vlan
Looking for: Adam/int-vlan
https://dnac:443/dna/intent/api/v1/template-programmer/template
TemplateId: 610a718c-0a71-484b-a632-a79b64192cb7 Version: 11

https://dnac:443/dna/intent/api/v1/template-programmer/template/610a718c-0a71-484b-a632-a79b64192cb7
Showing Template Body:
interface $interface
switchport access vlan $vlan

Required Parameters for template body: {"vlan":"","interface":""}

Bindings []

Step 3– Applying the template

The script can be executed with a device (ip address) and params provided.  Note the params are in single quote to avoid shell issues.

$ /template.py --template Adam/int-vlan --device 10.10.50.2 --params '{"vlan":"20","interface":"gig1/0/20"}'
Looking for: Adam/int-vlan
https://dnac:443/dna/intent/api/v1/template-programmer/template
TemplateId: 610a718c-0a71-484b-a632-a79b64192cb7 Version: 11

https://dnac:443/dna/intent/api/v1/template-programmer/template/610a718c-0a71-484b-a632-a79b64192cb7
Showing Template Body:
interface $interface
switchport access vlan $vlan

Required Parameters for template body: {"interface":"","vlan":""}

Bindings []

Up to this point, the output is the same as before.  The payload for applying the template is below.  Some notes:

The targetInfo can be a list, which means multiple devices can be provisioned at the same time.

Each target has its own set of parameters.

The target device can be specified in multiple ways. In this example “MANAGED_DEVICE_IP” is the type, and the IP of the device is  10,.10.50.2.   UUID is also supported.

The templateId is also required.

{'targetInfo': [{'params': {u'interface': u'gig1/0/20', u'vlan': u'20'},
'type': 'MANAGED_DEVICE_IP',
'id': '10.10.50.2'}],
'forcePushTemplate': False,
'templateId': u'610a718c-0a71-484b-a632-a79b64192cb7'}

The POST call to https://dnac:443/dna/intent/api/v1/template-programmer/template/deploy returns a task, which contains a deploymentId which needs to be polled for completion.

Executing template on:10.10.50.2, with Params:{"vlan":"20","interface":"gig1/0/20"}
payload {'targetInfo': [{'params': {u'interface': u'gig1/0/20', u'vlan': u'20'}, 'type': 'MANAGED_DEVICE_IP', 'id': '10.10.50.2'}], 'forcePushTemplate': False, 'templateId': u'610a718c-0a71-484b-a632-a79b64192cb7'}
https://dnac:443/dna/intent/api/v1/template-programmer/template/deploy
Response {u'duration': u'0 seconds', u'deploymentId': u'Deployment of Template: 610a718c-0a71-484b-a632-a79b64192cb7.ApplicableTargets: [10.10.50.2]Template Deployemnt Id: 41ac69b9-8f2b-43a5-bb4b-622936f0f244', u'endTime': u'', u'startTime': u''}

The deploymentId status needs to be polled until the deployment is  competed.

waiting for deploymentId 41ac69b9-8f2b-43a5-bb4b-622936f0f244
https://dnac:443/api/v1/template-programmer/template/deploy/status/41ac69b9-8f2b-43a5-bb4b-622936f0f244
{u'status': u'INIT', u'templateName': u'int-vlan', u'projectName': u'Adam', u'devices': [{u'status': u'IN_PROGRESS', u'name': u'', u'detailedStatusMessage': None, u'deviceId': u'e05075e8-eb5b-42f5-9f60-d56380702655', u'startTime': u'04:33:56 15/01/2019', u'duration': u'0 minutes 0 seconds', u'endTime': u'', u'ipAddress': u'e05075e8-eb5b-42f5-9f60-d56380702655'}], u'deploymentId': u'41ac69b9-8f2b-43a5-bb4b-622936f0f244', u'startTime': u'', u'duration': u'0 seconds', u'endTime': u'', u'templateVersion': u'11'}
Task=41ac69b9-8f2b-43a5-bb4b-622936f0f244 has not completed yet. Sleeping 2 seconds...
https://dnac:443/api/v1/template-programmer/template/deploy/status/41ac69b9-8f2b-43a5-bb4b-622936f0f244
{u'status': u'SUCCESS', u'templateName': u'int-vlan', u'projectName': u'Adam', u'devices': [{u'status': u'SUCCESS', u'name': u'', u'detailedStatusMessage': u'Provisioning success for template int-vlan', u'deviceId': u'e05075e8-eb5b-42f5-9f60-d56380702655', u'startTime': u'04:33:56 15/01/2019', u'duration': u'0 minutes 2 seconds', u'endTime': u'', u'ipAddress': u'e05075e8-eb5b-42f5-9f60-d56380702655'}], u'deploymentId': u'41ac69b9-8f2b-43a5-bb4b-622936f0f244', u'startTime': u'', u'duration': u'0 seconds', u'endTime': u'04:33:57 15/01/2019', u'templateVersion': u'11'}

Once completed, the status is displayed. The status (SUCCESS/FAIL), time taken, template name, version and deviceId are all shown.

Response:
{
"status": "SUCCESS",
"templateName": "int-vlan",
"projectName": "Adam",
"devices": [
{
"status": "SUCCESS",
"name": "",
"detailedStatusMessage": "Provisioning success for template int-vlan",
"deviceId": "e05075e8-eb5b-42f5-9f60-d56380702655",
"startTime": "04:33:56 15/01/2019",
"duration": "0 minutes 2 seconds",
"endTime": "",
"ipAddress": "e05075e8-eb5b-42f5-9f60-d56380702655"
}
],
"deploymentId": "41ac69b9-8f2b-43a5-bb4b-622936f0f244",
"startTime": "",
"duration": "0 seconds",
"endTime": "04:33:57 15/01/2019",
"templateVersion": "11"
}

The interface Gig1/0/20 on the switch has successfully been provisioned into vlan 20.

Tips and Traps

One of the most obvious issues when testing is an error message related to “deployed with same params”, an example appears below.

Executing template on:10.10.50.2, with Params:{"vlan":"20","interface":"gig1/0/20"}
payload {'targetInfo': [{'params': {u'interface': u'gig1/0/20', u'vlan': u'20'}, 'type': 'MANAGED_DEVICE_IP', 'id': '10.10.50.2'}], 'forcePushTemplate': False, 'templateId': u'610a718c-0a71-484b-a632-a79b64192cb7'}
https://dnac:443/dna/intent/api/v1/template-programmer/template/deploy
Response {u'duration': u'0 seconds', u'deploymentId': u'Deployment of Template: 610a718c-0a71-484b-a632-a79b64192cb7.ApplicableTargets: [10.10.50.2],Template int-vlan:11 is already deployed with same params,. Not deploying it.None of the targets are applicable for the template. Hence not deploying', u'endTime': u'', u'startTime': u''}
Error: 11 is already deployed with same params,. Not deploying it.None of the targets are applicable for the template. Hence not deploying

By default Cisco DNA Center will not deploy the same template, with the same parameters twice (if the first attempt was successful). There are times where you may want to change this behaviour. The –force option can be used to set the ‘forcePushTemplate’: False, option to True.
One other thing you may find confusing is the following message.

Executing template on:10.10.50.20, with Params:{"vlan":"20","interface":"gig1/0/20"}
payload {'targetInfo': [{'params': {u'interface': u'gig1/0/20', u'vlan': u'20'}, 'type': 'MANAGED_DEVICE_IP', 'id': '10.10.50.20'}], 'forcePushTemplate': False, 'templateId': u'610a718c-0a71-484b-a632-a79b64192cb7'}
https://dnac:443/api/v1/template-programmer/template/deploy
Response {u'duration': u'0 seconds', u'deploymentId': u'Deployment of Template: 610a718c-0a71-484b-a632-a79b64192cb7.nonApplicableTargets: {10.10.50.20=Device is not applicable for the template due to mismatch of deviceType or softwareType or softwareVersion}.ApplicableTargets: NoneNone of the targets are applicable for the template. Hence not deploying', u'endTime': u'', u'startTime': u''}
Error: Deployment of Template: 610a718c-0a71-484b-a632-a79b64192cb7.nonApplicableTargets: {10.10.50.20=Device is not applicable for the template due to mismatch of deviceType or softwareType or softwareVersion}.ApplicableTargets: NoneNone of the targets are applicable for the template. Hence not deploying

At first glance, you might think the device type of the template does not match that of the device. This could be true however, somewhat confusingly, it could also be the device IP address cannot be found on the controller. Be careful with devices that have multiple IP addresses, make sure you use the same IP as the controller used to discover and manage the device. In this case 10.10.50.20 is not a valid device in the controller inventory. 10.10.50.2 was used in the earlier examples.

The final thing to be careful of is some parameters might be “typed”.  For example, I could have type “int” for vlan in this example (rather than a string).   Make sure the payload reflects that.

What Next?

This simple example showed how to use a template to assign a vlan to an interface on a switch.  In future blogs I will cover more sophisticated concepts such as “bindings”, tags and CI/CD integration.

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

Thanks for reading

@adamradford123