Software Defined Access Guide
Introduction
Software Defined Access (SDA) API allows the developer to manage SDA network using Catalyst Center. It is a powerful set of APIs that the user can use to create and manage border, edge and control plane devices, assign ports for user devices and access points and deploy a SDA fabric.
Goal
The goals of this guide are:
- Create a SDA fabric
- Assign a site to the SDA Fabric
- Create an authentication profile
- Create a virtual network
- Add an IP pool to the virtual network
- Define a device as a control plane device
- Define a device as an edge device
- Define a device as a border device
- Assign a port as a user device port
- Assign a port as an access point port
Endpoints and methods used
- POST
/dna/system/api/v1/auth/token
- POST
/dna/intent/api/v1/business/sda/fabric
- POST
/dna/intent/api/v1/business/sda/fabric-site
- POST
/dna/intent/api/v1/business/sda/authentication-profile
- POST
/dna/intent/api/v1/business/sda/virtual-network
- POST
/dna/intent/api/v1/business/sda/virtualnetwork/ippool
- POST
/dna/intent/api/v1/business/sda/control-plane-device
- POST
/dna/intent/api/v1/business/sda/border-device
- POST
/dna/intent/api/v1/business/sda/edge-device
- POST
/dna/intent/api/v1/business/sda/hostonboarding/user-device
- POST
/dna/intent/api/v1/business/sda/hostonboarding/access-point
Prerequisites
For this guide, it is recommended that the developer is familiar with authenticating to Catalyst Center API, managing sites, devices and global IP pools.
Environment
This guide was developed using:
Authentication
First, we need to authenticate and retrieve a token from the API.
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']
headers = {'X-Auth-Token': token, 'Content-Type': 'application/json'}
Software Defined Access API
The Software Defined Access API is a very complete API with 32 endpoints that allows the developer to manage the SDA Fabric using Cisco DNA Center.
SDA Fabric Creation
Once the developer has access to the token, it is possible to proceed with the Fabric creation:
SDA_FABRIC_URL = '/dna/intent/api/v1/business/sda/fabric'
sda_fabric_info = {
"fabricName": "DNAC_Guide_Fabric"
}
response = requests.post(BASE_URL + SDA_FABRIC_URL, headers=headers,
json=sda_fabric_info, verify=False)
SDA Fabric - Site assignment
With the SDA Fabric created, the next step is to assign a site to the SDA fabric. You can reference the Sites guide to check how to create and retrieve a site.
SITE_FABRIC_URL = '/dna/intent/api/v1/business/sda/fabric-site'
site_fabric_info = {
"fabricName": "DNAC_Guide_Fabric",
"siteNameHierarchy": "Global/DNA_Center_Guide/DNA_Center_Guide_Building"
}
response = requests.post(BASE_URL + SITE_FABRIC_URL, headers=headers,
json=site_fabric_info, verify=False)
SDA Fabric - Authentication Profile
With the Fabric created and the site selected, it is needed to assign an authentication profile for the devices in the fabric. For the purpose of this guide we will use a No Authentication
profile.
SDA_AUTHENTICATION_PROFILE_URL = '/dna/intent/api/v1/business/sda/authentication-profile'
authentication_profile = [
{
"siteNameHierarchy": "Global/DNA_Center_Guide/DNA_Center_Guide_Building",
"authenticateTemplateName": "No Authentication"
}
]
response = requests.post(BASE_URL + SDA_AUTHENTICATION_PROFILE_URL, headers=headers,
json=authentication_profile, verify=False)
SDA Fabric - Virtual Network
As part of the fabric creation, it is needed to create a Virtual Network, where later IP Addresses pools will be assigned. The virtual networks needs to be tied to the site.
VIRTUAL_NETWORK_URL = '/dna/intent/api/v1/business/sda/virtual-network'
virtual_network_info = {
"virtualNetworkName": "INFRA_VN",
"siteNameHierarchy": "Global/DNA_Center_Guide/DNA_Center_Guide_Building"
}
response = requests.post(BASE_URL + VIRTUAL_NETWORK_URL, headers=headers,
json=virtual_network, verify=False)
SDA Fabric - IP Pools
Once the virtual network is created, IP Pools needs to be assigned to the virtual networks. You can check the Global IP pools for reference on how to create IP Pools. For this guide, we will create an IP pool for data and another one for voice trafic.
VIRTUAL_NETWORK_IPPOOL_URL = '/dna/intent/api/v1/business/sda/virtualnetwork/ippool'
ip_pool_info = [
{
"virtualNetworkName": "INFRA_VN",
"ipPoolName": "data_ip_pool1",
"trafficType": "DATA",
"authenticationPolicyName": "No Authentication",
"scalableGroupName": "",
"isL2FloodingEnabled": True,
"isThisCriticalPool": True,
"poolType": "AP"
}
]
response = requests.post(BASE_URL + VIRTUAL_NETWORK_IPPOOL_URL, headers=headers,
json=ip_pool, verify=False)
ip_pool_info = [
{
"virtualNetworkName": "INFRA_VN",
"ipPoolName": "voice_ip_pool1",
"trafficType": "VOICE",
"authenticationPolicyName": "No Authentication",
"scalableGroupName": "",
"isL2FloodingEnabled": True,
"isThisCriticalPool": True,
"poolType": "Extended"
}
]
response = requests.post(BASE_URL + VIRTUAL_NETWORK_IPPOOL_URL, headers=headers,
json=ip_pool, verify=False)
SDA Fabric - Control Plane, Border and Edge devices
With the virtual network defined and the IP pools assigned, we can proceed defined the different types of devices on the fabric. Check the Devices Guide for reference on how to get the devices information.
First we define the control plane device:
FABRIC_CONTROL_PLANE_URL = '/dna/intent/api/v1/business/sda/control-plane-device'
device_info = [
{
"deviceManagementIpAddress": "10.195.192.96",
"siteNameHierarchy": "Global/DNA_Center_Guide/DNA_Center_Guide_Building"
}
]
response = requests.post(BASE_URL + FABRIC_CONTROL_PLANE_URL, headers=headers,
json=device_info, verify=False)
Next we create a border device
FABRIC_BORDER_URL = '/dna/intent/api/v1/business/sda/border-device'
device_info = [
{
"deviceManagementIpAddress": "10.195.192.95",
"siteNameHierarchy": "Global/DNA_Center_Guide/DNA_Center_Guide_Building",
"externalDomainRoutingProtocolName": "BGP",
"externalConnectivityIpPoolName": "sda_1",
"internalAutonomouSystemNumber": "65002",
"borderSessionType": "EXTERNAL",
"connectedToInternet": False,
"externalConnectivitySettings": [
{
"interfaceName": "FortyGigabitEthernet1/1/1",
"externalAutonomouSystemNumber": "65003",
"l3Handoff": [
{
"virtualNetwork": {
"virtualNetworkName": "INFRA_VN"
}
}
]
}
]
}
]
response = requests.post(BASE_URL + FABRIC_BORDER_URL, headers=headers,
json=device_info, verify=False)
Finally, we assign the edge role to a device:
FABRIC_EDGE_URL = '/dna/intent/api/v1/business/sda/edge-device'
device_info = [
{
"deviceManagementIpAddress": "10.195.192.95",
"siteNameHierarchy": "Global/DNA_Center_Guide/DNA_Center_Guide_Building"
}
]
response = requests.post(BASE_URL + FABRIC_EDGE_URL, headers=headers,
json=device_info, verify=False)
SDA Fabric - Port assignment
With the Fabric created, the virtual network and IP pools defined, and the devices' roles assigned we can proceed to assign ports for user device or access points on the edge device.
The user device port assignment is shown below:
SDA_PORT_ASSIGNMENT_URL = '/dna/intent/api/v1/business/sda/hostonboarding/user-device'
port_assignment_info = [
{
"siteNameHierarchy": "Global/DNA_Center_Guide/DNA_Center_Guide_Building",
"deviceManagementIpAddress": "10.195.192.95",
"interfaceName": "GigabitEthernet1/0/1",
"dataIpAddressPoolName": "data_ip_pool1",
"voiceIpAddressPoolName": "voice_ip_pool1",
"scalableGroupName": "testGroupName",
"authenticateTemplateName": "No Authentication"
}
]
response = requests.post(BASE_URL + SDA_PORT_ASSIGNMENT_URL, headers=headers,
json=port_assignment, verify=False)
The Access Point port assigment is shown below:
SDA_AP_ASSIGNMENT_URL = '/dna/intent/api/v1/business/sda/hostonboarding/access-point'
port_assignment_info = [
{
"siteNameHierarchy": "Global/DNA_Center_Guide/DNA_Center_Guide_Building",
"deviceManagementIpAddress": "10.195.192.95",
"interfaceName": "GigabitEthernet1/0/1",
"addressPoolName": "data_ip_pool1",
"authenticateTemplateName": "No Authentication"
}
]
response = requests.post(BASE_URL + SDA_PORT_ASSIGNMENT_URL, headers=headers,
json=port_assignment, verify=False)
Code
The repository for this guide is here. The final code with functions is shown below.
# Modules import
import requests
from requests.auth import HTTPBasicAuth
import time
import sys
# 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
SDA_FABRIC_URL = '/dna/intent/api/v1/business/sda/fabric'
SITE_URL = '/dna/intent/api/v1/site'
SITE_FABRIC_URL = '/dna/intent/api/v1/business/sda/fabric-site'
FABRIC_CONTROL_PLANE_URL = '/dna/intent/api/v1/business/sda/control-plane-device'
FABRIC_BORDER_URL = '/dna/intent/api/v1/business/sda/border-device'
FABRIC_EDGE_URL = '/dna/intent/api/v1/business/sda/edge-device'
SDA_AUTHENTICATION_PROFILE_URL = '/dna/intent/api/v1/business/sda/authentication-profile'
VIRTUAL_NETWORK_URL = '/dna/intent/api/v1/business/sda/virtual-network'
VIRTUAL_NETWORK_IPPOOL_URL = '/dna/intent/api/v1/business/sda/virtualnetwork/ippool'
SDA_PORT_ASSIGNMENT_URL = '/dna/intent/api/v1/business/sda/hostonboarding/user-device'
SDA_AP_ASSIGNMENT_URL = '/dna/intent/api/v1/business/sda/hostonboarding/access-point'
def get_dnac_jwt_token():
response = requests.post(BASE_URL + AUTH_URL,
auth=HTTPBasicAuth(USERNAME, PASSWORD),
verify=False)
token = response.json()['Token']
return token
# Get list of devices
def get_sda_fabric(headers, query_string_params):
response = requests.get(BASE_URL + SDA_FABRIC_URL,
headers = headers, params = query_string_params,
verify=False)
return response.json()
# Create sda fabric
def create_sda_fabric(headers, sda_fabric_info):
response = requests.post(BASE_URL + SDA_FABRIC_URL, headers=headers,
json=sda_fabric_info, verify=False)
return response.json()
# Get list of sites
def get_sites(headers, site_params):
response = requests.get(BASE_URL + SITE_URL, headers=headers,
params=site_params, verify=False)
return response.json()['response']
# Add site to SDA fabric
def add_site_to_sda_fabric(headers, site_fabric_info):
response = requests.post(BASE_URL + SITE_FABRIC_URL, headers=headers,
json=site_fabric_info, verify=False)
return response.json()
# Add Control Plane device
def add_control_plane_device(headers, device_info):
response = requests.post(BASE_URL + FABRIC_CONTROL_PLANE_URL, headers=headers,
json=device_info, verify=False)
return response.json()
# Add Border device
def add_border_device(headers, device_info):
response = requests.post(BASE_URL + FABRIC_BORDER_URL, headers=headers,
json=device_info, verify=False)
return response.json()
# Add Edge device
def add_edge_device(headers, device_info):
response = requests.post(BASE_URL + FABRIC_EDGE_URL, headers=headers,
json=device_info, verify=False)
return response.json()
# Add default authentication profile in SDA Fabric
def add_authentication_profile(headers, authentication_profile):
response = requests.post(BASE_URL + SDA_AUTHENTICATION_PROFILE_URL, headers=headers,
json=authentication_profile, verify=False)
return response.json()
# Add default authentication profile in SDA Fabric
def add_virtual_network(headers, virtual_network):
response = requests.post(BASE_URL + VIRTUAL_NETWORK_URL, headers=headers,
json=virtual_network, verify=False)
return response.json()
# Add Virtual Network IP Pool
def add_virtual_network_ip_pool(headers, ip_pool):
response = requests.post(BASE_URL + VIRTUAL_NETWORK_IPPOOL_URL, headers=headers,
json=ip_pool, verify=False)
return response.json()
# Add user device port assignment
def add_user_device_port_assignment(headers, port_assignment):
response = requests.post(BASE_URL + SDA_PORT_ASSIGNMENT_URL, headers=headers,
json=port_assignment, verify=False)
return response.json()
# Add port assignment
def add_ap_port_assignment(headers, port_assignment):
response = requests.post(BASE_URL + SDA_PORT_ASSIGNMENT_URL, headers=headers,
json=port_assignment, verify=False)
return response.json()
def main():
# obtain the Catalyst Center Auth Token
token = get_dnac_jwt_token()
headers = {'X-Auth-Token': token, 'Content-Type': 'application/json'}
# Create SDA Fabric
sda_fabric_info = {
"fabricName": "DNAC_Guide_Fabric"
}
response = create_sda_fabric(headers, sda_fabric_info)
site_fabric_info = {
"fabricName": "DNAC_Guide_Fabric",
"siteNameHierarchy": "Global/DNA_Center_Guide/DNA_Center_Guide_Building"
}
response = add_site_to_sda_fabric(headers, site_fabric_info)
authentication_profile = [
{
"siteNameHierarchy": "Global/DNA_Center_Guide/DNA_Center_Guide_Building",
"authenticateTemplateName": "No Authentication"
}
]
response = add_authentication_profile(headers, authentication_profile)
virtual_network_info = {
"virtualNetworkName": "INFRA_VN",
"siteNameHierarchy": "Global/DNA_Center_Guide/DNA_Center_Guide_Building"
}
response = add_virtual_network(headers, virtual_network_info)
ip_pool_info = [
{
"virtualNetworkName": "INFRA_VN",
"ipPoolName": "data_ip_pool1",
"trafficType": "DATA",
"authenticationPolicyName": "No Authentication",
"scalableGroupName": "",
"isL2FloodingEnabled": True,
"isThisCriticalPool": True,
"poolType": "AP"
}
]
response = add_virtual_network_ip_pool(headers, ip_pool_info)
ip_pool_info = [
{
"virtualNetworkName": "INFRA_VN",
"ipPoolName": "voice_ip_pool1",
"trafficType": "VOICE",
"authenticationPolicyName": "No Authentication",
"scalableGroupName": "",
"isL2FloodingEnabled": True,
"isThisCriticalPool": True,
"poolType": "Extended"
}
]
response = add_virtual_network_ip_pool(headers, ip_pool_info)
device_info = [
{
"deviceManagementIpAddress": "10.195.192.96",
"siteNameHierarchy": "Global/DNA_Center_Guide/DNA_Center_Guide_Building"
}
]
response = add_control_plane_device(headers, device_info)
print(response)
device_info = [
{
"deviceManagementIpAddress": "10.195.192.95",
"siteNameHierarchy": "Global/DNA_Center_Guide/DNA_Center_Guide_Building",
"externalDomainRoutingProtocolName": "BGP",
"externalConnectivityIpPoolName": "sda_1",
"internalAutonomouSystemNumber": "65002",
"borderSessionType": "EXTERNAL",
"connectedToInternet": False,
"externalConnectivitySettings": [
{
"interfaceName": "FortyGigabitEthernet1/1/1",
"externalAutonomouSystemNumber": "65003",
"l3Handoff": [
{
"virtualNetwork": {
"virtualNetworkName": "INFRA_VN"
}
}
]
}
]
}
]
response = add_border_device(headers, device_info)
device_info = [
{
"deviceManagementIpAddress": "10.195.192.95",
"siteNameHierarchy": "Global/DNA_Center_Guide/DNA_Center_Guide_Building"
}
]
response = add_edge_device(headers, device_info)
port_assignment_info = [
{
"siteNameHierarchy": "Global/DNA_Center_Guide/DNA_Center_Guide_Building",
"deviceManagementIpAddress": "10.195.192.95",
"interfaceName": "GigabitEthernet1/0/1",
"dataIpAddressPoolName": "data_ip_pool1",
"voiceIpAddressPoolName": "voice_ip_pool1",
"scalableGroupName": "testGroupName",
"authenticateTemplateName": "No Authentication"
}
]
response = add_user_device_port_assignment(headers, port_assignment_info)
port_assignment_info = [
{
"siteNameHierarchy": "Global/DNA_Center_Guide/DNA_Center_Guide_Building",
"deviceManagementIpAddress": "10.195.192.95",
"interfaceName": "GigabitEthernet1/0/1",
"addressPoolName": "data_ip_pool1",
"authenticateTemplateName": "No Authentication"
}
]
response = add_ap_port_assignment(headers, port_assignment_info)
if __name__ == "__main__":
main()