Software Image Management Guide
Introduction
Catalyst Center provides APIs to manage the operating system images of the devices that are registered to it, where the developer can upload, distribute and activate an image on a device.
Goal
The goals of this guide are:
- Get the device information.
- Get a list of images filtered by family.
- Distribute the golden image to the selected device.
- Activate the golden image.
Endpoints and methods used
- GET
/dna/intent/api/v1/network-device
- GET
/dna/intent/api/v1/image/importation
- POST
/dna/intent/api/v1/image/distribution
- POST
/dna/intent/api/v1/image/activation/device
- GET
/dna/intent/api/v1/task/{task_id}
Prerequisites
For this module, we recommend that the user already has experience authenticating with Catalyst Center, obtaining device information, and handling asynchronous tasks.
Environment
This guide was developed using:
Software Image Management API
The software image management API includes 5 endpoints for image uploading, distribution and activation.
Get Device Information
We are going to update the image on the CSR1Kv-03.devnet.local
device.
First, we must authenticate and retrieve a token from the API.
Notes: Do not use
verify=False
orurllib3.disable_warnings()
if you are not sure of its purpose. Read Authentication and Authorization.
import requests
from requests.auth import HTTPBasicAuth
import urllib3
urllib3.disable_warnings()
BASE_URL = 'https://<IP Address>'
AUTH_URL = '/dna/system/api/v1/auth/token'
USERNAME = '<USERNAME>'
PASSWORD = '<PASSWORD>'
response = requests.post(BASE_URL + AUTH_URL, auth=HTTPBasicAuth(USERNAME, PASSWORD), verify=False)
token = response.json()['Token']
With the token, we can proceed to query the devices API to get the device ID of CSR1Kv-03.devnet.local
:
# Get device
headers = {'X-Auth-Token': token, 'Content-Type': 'application/json'}
query_params = {
'hostname': 'CSR1Kv-03.devnet.local'
}
DEVICES_URL = '/dna/intent/api/v1/network-device'
response = requests.get(BASE_URL + DEVICES_URL,
params=query_params,
headers=headers, verify=False)
device_id = response.json()['response'][0]['id']
Image Importation
The developer can use this endpoint to import an image, using HTTP or FTP, to Catalyst Center.
# Print software images
SOFTWARE_IMAGE_IMPORT_URL = '/dna/intent/api/v1/image/importation/source/url'
import_info = {
"sourceURL": "http://10.104.49.64/cat3k_caa_universalk9.16.12.03a.SPA.bin"
}
response = requests.post(BASE_URL + SOFTWARE_IMAGE_IMPORT_URL,
json=import_info,
headers=headers, verify=False)
image_id = response.json()['response']
Image Details
With this endpoint, it is possible to get the information available on Catalyst Center. In this case, we are filtering the results based on the family of the image.
# Print software images
SOFTWARE_IMAGE_URL='/dna/intent/api/v1/image/importation'
query_params ={
'family': 'cat3k'
}
response = requests.get(BASE_URL + SOFTWARE_IMAGE_URL,
params=query_params,
headers=headers, verify=False)
image_id = response.json()['response'][0]['imageUuid']
Image Distribution
After obtaining the image, distribute it to network devices. First, set the image as golden using the web interface.
For image distribution, you need the device ID and image ID. Since this is an asynchronous API, query the task API to obtain the result.
SOFTWARE_IMAGE_DISTRIBUTION_URL = '/dna/intent/api/v1/image/distribution'
TASK_BY_ID_URL = '/dna/intent/api/v1/task/{task_id}'
distribution_info = [
{
'deviceUuid': device_id,
'imageUuid': image_id
}
]
response = requests.post(BASE_URL + SOFTWARE_IMAGE_DISTRIBUTION_URL,
json=distribution_info,
headers=headers, verify=False)
task_id = response.json()['response']['taskId']
time.sleep(10)
response = requests.get(BASE_URL + TASK_BY_ID_URL.format(task_id=task_id),
headers=headers, verify=False)
print(response.json()['response']['data'])
Image Activation
Finally, after distributing the image, use the API to instruct the device to activate the image. This is also asynchronous, so query the task API for the result.
SOFTWARE_IMAGE_ACTIVATION_URL = '/dna/intent/api/v1/image/activation/device'
activate_info = [
{
'deviceUuid': device_id,
'imageUuidList': [
image_id
]
}
]
response = requests.post(BASE_URL + SOFTWARE_IMAGE_ACTIVATION_URL,
json=activation_info,
headers=headers, verify=False)
task_id = response.json()['response']['taskId']
time.sleep(10)
response = requests.get(BASE_URL + TASK_BY_ID_URL.format(task_id=task_id),
headers=headers, verify=False)
print(response.json()['response']['data'])
Code
The repository for this guide is here. The final code with functions appears as below.
# Modules import
import requests
from requests.auth import HTTPBasicAuth
import time
# Disable SSL warnings. Not needed in production environments with valid certificates
import urllib3
urllib3.disable_warnings()
# Authentication
BASE_URL = 'https://<IP Address>'
AUTH_URL = '/dna/system/api/v1/auth/token'
USERNAME = '<USERNAME>'
PASSWORD = '<PASSWORD>'
# URLs
DEVICES_URL = '/dna/intent/api/v1/network-device'
SOFTWARE_IMAGE_URL='/dna/intent/api/v1/image/importation'
SOFTWARE_IMAGE_IMPORT_URL = '/dna/intent/api/v1/image/importation/source/url'
SOFTWARE_IMAGE_DISTRIBUTION_URL = '/dna/intent/api/v1/image/distribution'
SOFTWARE_IMAGE_ACTIVATION_URL = '/dna/intent/api/v1/image/activation/device'
TASK_BY_ID_URL = '/dna/intent/api/v1/task/{task_id}'
# Get Authentication token
def get_dnac_jwt_token():
response = requests.post(BASE_URL + AUTH_URL,
auth=HTTPBasicAuth(USERNAME, PASSWORD),
verify=False)
token = response.json()['Token']
return token
# Import software image
def import_image(headers, import_info):
response = requests.post(BASE_URL + SOFTWARE_IMAGE_IMPORT_URL,
json=import_info,
headers=headers, verify=False)
return response.json()['response']
# Get Software Images
def get_software_images(headers, query_params):
response = requests.get(BASE_URL + SOFTWARE_IMAGE_URL,
params=query_params,
headers=headers, verify=False)
return response.json()['response']
# Get devices
def get_devices(headers, query_params):
response = requests.get(BASE_URL + DEVICES_URL,
params=query_params,
headers=headers, verify=False)
return response.json()['response']
# Distribute image
def distribute_image(headers, distribution_info):
response = requests.post(BASE_URL + SOFTWARE_IMAGE_DISTRIBUTION_URL,
json=distribution_info,
headers=headers, verify=False)
return response.json()['response']
# Activate image
def activate_image(headers, activation_info):
response = requests.post(BASE_URL + SOFTWARE_IMAGE_ACTIVATION_URL,
json=activation_info,
headers=headers, verify=False)
return response.json()['response']
# Get Task result
def get_task(headers, task_id):
response = requests.get(BASE_URL + TASK_BY_ID_URL.format(task_id=task_id),
headers=headers, verify=False)
return response.json()['response']
def main():
# obtain the Catalyst Center Auth Token
token = get_dnac_jwt_token()
headers = {'X-Auth-Token': token, 'Content-Type': 'application/json'}
# Import image
import_info = {
"sourceURL": "http://10.104.49.64/cat3k_caa_universalk9.16.12.03a.SPA.bin"
}
response = import_image(headers, import_info)
time.sleep(30)
# Get software images
query_params ={
'family': 'cat3k'
}
response = get_software_images(headers, query_params)
image_id = response[0]['imageUuid']
# Get device
query_params = {
'hostname': 'CAT3K-03.devnet.local'
}
response = get_devices(headers, query_params)
device_id = response[0]['id']
distribution_info = [
{
'deviceUuid': device_id,
'imageUuid': image_id
}
]
response = distribute_image(headers, distribution_info)
task_id = response['taskId']
time.sleep(10)
response = get_task(headers, task_id)
print(response['data'])
activate_info = [
{
'deviceUuid': device_id,
'imageUuidList': [
image_id
]
}
]
response = activate_image(headers, activate_info)
task_id = response['taskId']
time.sleep(10)
response = get_task(headers, task_id)
print(response['data'])
if __name__ == "__main__":
main()