Introduction
If you have been working with Network Plug and Play (PnP) for a while, you might find some of these tools useful. I am going to assume you have seen my earlier blogs, so have a good understanding of the PnP process, the API and how they work. The scripts are purely educational, and you should adapt them for your own environment.
Installation
The tools are published at the following repository https://github.com/aradford123/PnPTools.git
Instructions for installing on a MAC/Linux machine follow:
I have written each as a standalone application. I recommend you use a virtual environment to install the requirements. Note: these scripts use the uniq library, which requires python3.
cd PnPTools
virtualenv -p python3 env
source env/bin/activate
|
Remember, if you exit your shell or logout, you will need to run the command "source env/bin/activate" each time to activate the virtual environment.
#1 PnPWatch
This utility shows you the steps and progress of the PnP process for a device.
To install and run do the following:
cd PnPWatch/
pip install -r requirements.txt
|
To run the script you need to add your controller and the credentials for it. You can do this in two ways:
- edit the apic_config.py file
- use the APIC, APIC_USER and APIC_PASSWORD environment variables. For example the shell command "export APIC='sandboxapic.cisco.com'" would set the controller to the DevNet cloud controller. Be very careful with quotes.
You also provide a serial number for the device you are watching. You need to have a rule for the device, or it needs to be in the unclaimed devices list.
$ ./src/watch_provision.py FDO1732Q00B
Watching unclaimed for serial:FDO1732Q00B
19:49:35: Duration (0) Unclaimed
19:49:43: Duration (9) Waiting for Resource
19:50:02: Duration (28) Start Provisioning
19:51:08: Duration (94) Deploying Device Certificate
19:52:09: Duration (155) Deploying Config
19:54:09: Duration (275) Provisioned
19:54:09: Completed (275): PROVISIONED
|
each step of the process is shown, along with the number of seconds it took to execute. For example, it took 155 seconds for the "Deploying Config" step.
#2 PnPSync
This utility keeps your library of configuration, template and images files synced up to APIC-EM. As you are not able to edit directly on the controller, you can edit the disk based version of these files then sync them up to the controller. The SHA1 hash is checked first to ensure an upload is required. Any missing files are uploaded (POST), and any existing files are updated (PUT)
You will need to perform the same steps as the first example above.
There is an extra variable which is the directory containing the folders for the configuration, template and image files. Those folders are called "configs", "templates" and "images".
$ ./src/pnp_file_sync.py
NameSpace:config:valid
Updated File:4451.txt (c0991ef7-2274-40a8-8b21-7a690fc73193)
NameSpace:template:valid
Uploaded File:new-template.txt (967e44ab-bd66-40bb-9645-71d69b7db0a6)
NameSpace:image:valid
Skipping File:c2960x-universalk9-mz.152-4.E.bin (2f4380b4-64f5-401c-9464-ad5925f783a9) SHA1hash:67ff12708d66c188e998e78641d4f2f18e29c539
Skipping File:cat3k_caa-universalk9.SPA.03.06.05.E.152-2.E5.bin (f2b2c594-73de-45cc-9c70-ed0315e5b0ff) SHA1hash:c87f5ea36cd66d4558af1729c9d41f5058da4123
|
This shows the file "configs/4451.txt" was updated.
File "templates/new-template.txt" was uploaded.
File "images /c2960x-universalk9-mz.152-4.E.bin" was left unchanged as the SHA1 hash was identical.
#3 PnPConfigTemplator
This is an "industrialized" version of the initial example I wrote about in earlier blogs. There are two main differences:
1) It does not append a 4 digit number onto the end of projects and filenames
2) It uses nested jinja2 templates to generate configuration files for switch stacks. There is a base template, that gets extended through macros and loops.
You will need to do the same steps as #1 to install the requirements and update the variables for the APIC-EM, username and password.
$ ./10_create_and_upload.py ./work_files/hosts.csv
Using device file: ./work_files/hosts.csv
Using template directory: work_files/templates
##########################
Variables: {'HOSTNAME': 'fourswitch', 'imageFile': 'cat3k_caa-universalk9.SPA.03.06.05.E.152-2.E5.bin', 'VoiceVlan': '300', 'ManagementIP': '10.10.10.220', 'stackCount': '4', 'DISTRO': 'distribution2-2-2', 'site': 'Sydney', 'serialNumber': '12345678901', 'USERVLAN': '100', 'platformId': '3850-stack', 'management': '90', 'template': 'four_switch.jnja'}
created file: work_files/configs/fourswitch-config
creating project:Sydney
Configuration File_id: b01989ab-19e7-47ee-88ec-812a90fc479c
Creating Rule [
{
"eulaAccepted": true,
"serialNumber": "12345678901",
"licenseLevel": "ipbase",
"platformId": "3850-stack",
"memberCount": "4",
"imageId": "f2b2c594-73de-45cc-9c70-ed0315e5b0ff",
"pkiEnabled": true,
"configId": "b01989ab-19e7-47ee-88ec-812a90fc479c",
"hostName": "fourswitch"
}
]
Rule Status: {"message":"Success creating new site device(rule)","ruleId":"1aff050c-ba3f-456f-976d-e9a3531f544c"}
<SNIPPED>
|
The script has quite a lot of debugging in it to show you what is happening.
I can see:
- variables used for the template: Variables: {'HOSTNAME'…
- configuration file being created: created file: work_files/configs/fourswitch-config
- - project being created: creating project:Sydney
- - Configuration file ID:Configuration File_id: b01989ab-19e7-47ee-88ec-812a90fc479c
- - The rule being uploaded: Creating Rule […..
- - Rule status: Rule Status: {"
These rules assume that an image file "cat3k_caa-universalk9.SPA.03.06.05.E.152-2.E5.bin"is present on the controller. You can either edit the file "work_files/hosts.csv" to remove it, upload a dummy file for testing, or a real file for production.
How do the templates work
These examples are using jinja2 templates. A sample configuration file is below. All of the base IOS commands are in the file "work_files/templates/base.jnja". There are "macros" defined for the different port types in the file "work_files/templates/macros.jnja".
The base file has a "block" in it called "interfaces" {% block interfaces %}. The template fills out that block (you could have other blocks as well, if required).
Jinja2 supports for loops {% for stack_num in range(1,3) %} . In this case the variable "stack_num" will be set to 1 and 2.
"stack_num" is used to define the interface range, and then the macro "user_port" has the configurations for a user port.
{% from "macros.jnja" import user_port, ap_port, uplink_trunk with context%}
{% extends "base.jnja" %} {% block interfaces %} {% for stack_num in range(1,3) %} interface range g{{ stack_num }}/0/1 - 40 {{ user_port() }} int range g{{ stack_num }}/0/45 - 48 {{ ap_port() }} int ten{{ stack_num }}/1/4 {{ uplink_trunk() }} {% endfor %} {% endblock %}
|
There are many ways this could be optimized and extended. This example is just to illustrate the basic concepts.
Cleanup.
Running
./12_clean_up_all.py work_files/hosts.csv
|
will remove all of the files/projects/rules. This is for testing purposes
What Next?
I will keep adding to these utilities as I get time. They are not officially (or unofficially J) supported, just examples of tools to make life easier.
In the meantime, if you would like to learn more about this, you could come hang out with us in The Cisco Devnet DNA Community. We’ll have a continuous stream of blogs like this and you can ask questions and we’ll get you answers.
In addition, we have a Github repository where you can get examples related to PnP.
Thanks for reading,
@adamradford123