cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
5406
Views
26
Helpful
13
Comments
aradford
Cisco Employee
Cisco Employee

While APIC-EM is used for "policy based" network configuration, not all network device attributes are exposed through policy at this point.  This will be an evolution as the policy model gets filled out.  More on policy models and what this means for simplification in a later blog.

policy_evolution.png

A common question is "How can the non-policy based elements be automated?"  For example, configure a VLAN on a switchport.  The good news is Prime Infrastructure (PI) exposes a REST API for Configuration Templates, which does exactly this (and lots more).  There are 186 templates predefined in PI3.1

This blog provides an outline of template-based configuration using Cisco Prime Infrastructure API.  In particular, assigning a VLAN to an interface using the “Configure Interface” template.  The next blog in the series will cover some more advanced topics.

Getting Started


Make sure you have an API user defined in Prime Infrastructure (PI)

Admin->Users Roles & AAA


PI-API-user.png

An example – VLAN assignment

Here is an example of a simple web application written using Prime Infrastructure configuration template. The UI is not particularly elegant, but this only took 30 minutes to write. When the user selects a vlan on a switch port, a PI template is used to make the configuration change.

sample vlan app.png

First a bit about templates

Templates are predefined command sequences in PI.  There are a 186 built-in templates and you can define new ones.  A template can be applied to a device via an API call. A template has a name and an id.

The ID of the “Configure Interface” template is 541541.  ID might be different on your instance of PI.  Below is a JSON schema for the parameters that you can use in the "Configure Interface" template.  Do not worry about how this was generated; we will cover that in the next blog.

{

"cliTemplateCommand": {

"targetDevices": {

      "targetDevice": {

        "targetDeviceID": "<DEVICEID>",

        "variableValues": {

          "variableValue": [

            {

              "name": "Description",

              "value": ""

            },

            {

              "name": "InterfaceName",

              "value": "required"

            },

            {

              "name": "NativeVLan",

              "value": ""   

            },

            {

              "name": "StaticAccessVLan",

              "value": ""

            },

            {

              "name": "TrunkAllowedVLan",

              "value": ""

            },

            {

              "name": "VoiceVlan",

              "value": ""

            },

            {

              "name": "spd",

              "value": ""

            },

            {

              "name": "A1",

              "value": ""

            },

            {

              "name": "duplexField",

              "value": ""

            },

            {

              "name": "PortFast",

              "value": ""

            }

          ]

        }

      }

},

"templateName": "Configure Interface"

}

}

How to find the targetDeviceID

You will notice the template has an attribute called "targetDeviceID".  The template will be applied to this device.  Every device in PI has a unique identifier, which is available through an API call.  The simplest way is to do a lookup by IP address.

https://{{pi-server}}/webacs/api/v1/data/Devices?ipAddress=10.10.8.100

Will return a record (in JSON or XML) as follows.  610622 is the DeviceID

{

"queryResponse": {

"@last": "0",

"@first": "0",

"@count": "1",

"@type": "Devices",

"@responseType": "listEntityIds",

"@requestUrl": "https://adam-pi/webacs/api/v1/data/Devices?ipAddress=10.10.8.100",

"@rootUrl": "https://adam-pi/webacs/api/v1/data",

"entityId": [

      {

        "@type": "Devices",

        "@url": "https://adam-pi/webacs/api/v1/data/Devices/610622",

        "$": "610622"

      }

]

}

}

Apply the template to the device

The previous step obtained the "targetDeviceID" to identify the device, which the template will be applied to.  Other variables can now be filled in, for example, the "InterfaceName", the "Description" and the "StaticAccessVLAN".  The variable "A1" defines the mode of the switchport, which will be "Access".

All variables need to be present, even if they are not being used.  For example, in this case “VoiceVlan” is not used, so it is just set to "".

{
"cliTemplateCommand" : {
"targetDevices" : {
"targetDevice" : {
"targetDeviceID" : "610622",
"variableValues" : {
"variableValue": [
{
"name": "InterfaceName",
"value": "gigabitethernet1/0/2"
},
{
"name": "Description",
"value": "Fred1"
},
{
"name": "StaticAccessVLan",
"value": "8"
},
{
"name": "A1",
"value": "Access"
},
{
"name": "NativeVLan", "value": ""},
{
"name": "duplexField","value": ""},
{
"name": "TrunkAllowedVLan","value": "" },
{
"name": "spd","value": "" },
{
"name": "VoiceVlan" ,"value": ""},
{
"name": "PortFast","value": "" }
]
}
}
},
"templateName" : "Configure Interface"
}
}

A very simple REST API call is required to apply this template to the device.  Here is a python snippet to do this.  Notice this is a PUT method, not a POST.

PUT https://{{pi-server}}/webacs/api/v1/op/cliTemplateConfiguration/deployTemplateThroughJob.json

PAYLOAD below:  Remember to use the Content-Type : application/json header

{

"cliTemplateCommand" : {

"targetDevices" : {

      "targetDevice" : {

        "targetDeviceID" : "610622",

        "variableValues" : {

          "variableValue": [

            {

              "name": "InterfaceName",

              "value": "gigabitethernet1/0/2"

            },

            {

              "name": "Description",

              "value": "Fred1"

            },

            {

              "name": "StaticAccessVLan",

              "value": "8"

            },

            {

              "name": "A1",

              "value": "Access"

            },

            { "name": "NativeVLan", "value": ""},

            { "name": "duplexField","value": ""},

            { "name": "TrunkAllowedVLan","value": "" },

            { "name": "spd","value": "" },

            { "name": "VoiceVlan" ,"value": ""},

            { "name": "PortFast","value": "" }

          ]

        }

      }

},

"templateName" : "Configure Interface"

}

Monitoring the status of the job

The PUT API call above will create a deployment job.  Deployment jobs are asynchronous, meaning a response will be provided straight away, but that does not indicate success/failure.  The response will contain a "jobName", which you can poll to obtain the job status.

{

"mgmtResponse": {

"@responseType": "operation",

"@requestUrl": "https://adam-pi/webacs/api/v1/op/cliTemplateConfiguration/deployTemplateThroughJob",

"@rootUrl": "https://adam-pi/webacs/api/v1/op",

"cliTemplateCommandJobResult": {

      "jobName": "JobCliTemplateDeployIOSDevices07_35_57_626_PM_06_28_2016",

      "message": "An deploy job has been successfully created. "

}

}

}

The following REST call finds the status of the job.

GET

https://{{pi-server}}/webacs/api/v1/data/JobSummary.json?jobName=JobCliTemplateDeployIOSDevices07_35_57_626_PM_06_28_2016

In this case it is completed.  The last field in "@displayName" indicates completed.  The "jobNumber" is 560885

{

"queryResponse": {

"@last": "0",

"@first": "0",

"@count": "1",

"@type": "JobSummary",

"@responseType": "listEntityIds",

"@requestUrl": "https://adam-pi/webacs/api/v1/data/JobSummary?jobName=JobCliTemplateDeployIOSDevices07_35_57_626_PM_06_28_2016",

"@rootUrl": "https://adam-pi/webacs/api/v1/data",

"entityId": [

      {

        "@type": "JobSummary",

        "@displayName": "CliTemplateDeployIOSDevices,JobCliTemplateDeployIOSDevices07_35_57_626_PM_06_28_2016,COMPLETED",

        "@url": "https://adam-pi/webacs/api/v1/data/JobSummary/560885",

        "$": "560885"

      }

]

}

}

The jobNumber can be used to get more details of execution:

GET https://{{pi-server}}/webacs/api/v1/data/JobSummary/560885.json

With the following result:

{

"queryResponse": {

"@type": "JobSummary",

"@responseType": "getEntity",

"@requestUrl": "https://adam-pi/webacs/api/v1/data/JobSummary/560885",

"@rootUrl": "https://adam-pi/webacs/api/v1/data",

"entity": [

      {

        "@dtoType": "jobSummaryDTO",

        "@type": "JobSummary",

        "@url": "https://adam-pi/webacs/api/v1/data/JobSummary/560885",

        "jobSummaryDTO": {

          "@displayName": "CliTemplateDeployIOSDevices,JobCliTemplateDeployIOSDevices07_35_57_626_PM_06_28_2016,COMPLETED",

          "@id": "560885",

          "completionTime": "2016-06-28T19:36:28.727+10:00",

          "description": "Cli Template Deploy for IOS devices",

          "duration": 0,

          "jobName": "JobCliTemplateDeployIOSDevices07_35_57_626_PM_06_28_2016",

          "jobStatus": "COMPLETED",

          "jobType": "CliTemplateDeployIOSDevices",

          "lastStartTime": "2016-06-28T19:36:27.700+10:00",

          "resultStatus": "SUCCESS",

          "runId": 6477369,

          "runStatus": "COMPLETED",

          "username": "api"

        }

      }

]

}

}

If you want the full details of the execution of the job, you can use the following API call.

GET

https://{{pi-server}}/webacs/api/v1/op/jobService/runhistory.json?jobName=JobCliTemplateDeployIOSDevices07_35_57_626_PM_06_28_2016

The output is below and is very detailed.

{

"mgmtResponse": {

"@responseType": "operation",

"@requestUrl": "https://adam-pi/webacs/api/v1/op/jobService/runhistory?jobName=JobCliTemplateDeployIOSDevices07_35_57_626_PM_06_28_2016",

"@rootUrl": "https://adam-pi/webacs/api/v1/op",

"job": {

      "description": "Cli Template Deploy for IOS devices",

      "jobId": 560885,

      "jobName": "JobCliTemplateDeployIOSDevices07_35_57_626_PM_06_28_2016",

      "jobStatus": "COMPLETED",

      "jobType": "CliTemplateDeployIOSDevices",

      "runInstances": {

        "runInstance": {

          "completionTime": "2016-06-28T19:36:28.727+10:00",

          "lastStartTime": "2016-06-28T19:36:27.700+10:00",

          "resultStatus": "SUCCESS",

          "results": {

            "result": [

              {

                "property": "JobCliTemplateDeployIOSDevices07_35_57_626_PM_06_28_2016",

                "value": "1/1 template configurations successfully applied."

              },

              {

                "property": 610622,

                "value": "configlet:\n        interface gigabitethernet1/0/2\n description Fred1\n                            switchport mode access\n                            switchport ACCess vlan 8  \n                            \n              \n        \n        \n        \n        \n        \n        exit\n\n\n\n\n\n\n\n\n\n\n response:\n<cliChunks><cliChunk><cli>terminal width 0\nconfig t\ninterface gigabitethernet1/0/2\ndescription Fred1\nswitchport mode access\nswitchport ACCess vlan 8\nexit\n</cli><response><![CDATA[terminal width 0\n3650-dns#config t\nEnter configuration commands, one per line.  End with CNTL/Z.\n3650-dns(config)#interface gigabitethernet1/0/2\n3650-dns(config-if)#description Fred1\n3650-dns(config-if)#switchport mode access\n3650-dns(config-if)#switchport ACCess vlan 8\n3650-dns(config-if)#exit\n3650-dns(config)#]]></response></cliChunk></cliChunks>"

              }

            ]

          },

          "runId": 6477369,

          "runStatus": "COMPLETED"

        }

      }

}

}

}

Back to Prime Infrastructure

The job is also displayed in the PI job Dashboard.  Note the user is “api”, and that it was successful.  The interface on the switch has now been assigned to vlan 8.

job dashboard.png

Wrapping up

That should give you a good understanding of how to use the PI template REST APIs.  This is enough to write the "Vlan change" application mentioned at the top of the article.

The second part of this blog will go into more details, including a python tool for generating template schemas and example of a "generic" template execution script that can run any template.

For more examples on Prime Infrastructure API, you could visit Cisco Devnet.

Thanks for reading

@adamradford123

13 Comments
jboga
Level 5
Level 5

Adam,

From the image I understand, coming from a sysadmin background, that Prime Infrastructure is more like a Puppet, Salt, Ansible or Cheff kind of tool, meaning that, at least at the beginning, they were more concerned with just configuration management from a centralized point.

APIC-EM is more an automation tool. Not really focused on configuring a device, but applying policies to a network, and at the moment, is not even possible with APIC-EM to actually go ahead and just change a parameter in an interface.

aradford
Cisco Employee
Cisco Employee

Thanks Jose,

You are totally correct.  APIC-EM is a policy based abstraction of the network. 

The idea of an "abstraction" is to hide details of the physical network... such as VLAN/interfaces etc.

For example in APIC-EM QoS is specified as an expression of intent:

"As a store manager, my store "point of sale" traffic is business relevant"

That gets translated into a policy API call that looks like:

{

"policyName" : "POS-relevant",

"policyScope" : "All-STORE-DEVICES-WIRED-WIRELESS",
"resource" : {"applications" : [ {"appName": "PointOfSale", "id" :""} ]},
"actionProperty": { "relevanceLevel": "Business-Relevant" },

}

Notice there is no reference to devices.  They are abstracted via the policyScope... which is a tag applied to devices.

It is this policy that APIC-EM applies to network devices (rendered as CLI).

Any, that will be another blog topic!

Thanks for the comment, does this make sense?

jboga
Level 5
Level 5

Yes, it does. It's not about a specific device but a network behavior.

Dave Lewis
Level 1
Level 1

Hi Adam,

I'm interested in the screenshot you posted for changing the vlan on the 3850, is it an app or 'service' you've written for APIC-EM?

Thanks,

Dave

mikec85arm
Level 1
Level 1

Hi Adam,

     Could you please add some detail around how you did the simple web ui?  I am looking at doing something similar but not understanding how you did that.   Was that within PI or APIC-EM?

Thanks

Mike

aradford
Cisco Employee
Cisco Employee

Hi Dave,  sorry i missed your question.  It was just a little Python Flask app i wrote that calls APIC-EM and PI API.

aradford
Cisco Employee
Cisco Employee

Hi Mike,

I will put together a little blog post on using Flask in python to develop these apps.  It is very simple to do.

Adam

jboga
Level 5
Level 5

Adam,

Maybe even upload the code to github.

aradford
Cisco Employee
Cisco Employee

yes, i was going to as a part of the post... :-)

mikec85arm
Level 1
Level 1

Hi Adam,

     That would be awesome.

Thank you

Mike

mikec85arm
Level 1
Level 1

Hi Adam,

Was just checking in to see if you had time to post your flask python code?

Thanks

Mike

leesa9char
Level 1
Level 1

Hi Adam, I've been using Prime's APIs for a while but just started trying out the deployTemplateThroughJob one but it doesn't appear to actually write the new config to the device's start-up config. I was googling for that when I stumbled on this blog post but I can't see anything for it in your API call either.

Are you able to shed any light on how to also issue a 'wr' or 'copy run start' via API?

I've checked my test router and the configuration definitely went through but only in running config, not startup config.

Thank you!

- Leesa

Edit: I ended up finding it myself and thought I'd include it here for others.

Add the below to the configuration template that you created within Prime:

#MODE_ENABLE

write memory

#MODE_END_ENABLE

aradford
Cisco Employee
Cisco Employee

yes, thanks for updating everyone else

Getting Started

Find answers to your questions by entering keywords or phrases in the Search bar above. New here? Use these resources to familiarize yourself with the community: