Topology Guide

Introduction

Catalyst Center has a Topology Intent API that enables the developer to get an overall look of the physical (Layer 2), logical (layer 3) and site topology.

Goal

The goals of this guide are:

  1. Get the site topology.
  2. Get the physical topology.
  3. Get the logical topology.

Topology workflow

Endpoints and methods used

  • POST /dna/system/api/v1/auth/token
  • GET /dna/intent/api/v1/topology/site-topology
  • GET /dna/intent/api/v1/topology/physical-topology
  • GET /dna/intent/api/v1/topology/l2/{vlan_id}

Prerequisites

For this module, we recommend that the user already has experience authenticating with Catalyst Center:

Environment

This guide was developed using:

Authentication

First, we must authenticate and retrieve a token from the API.

Notes: Do not use verify=False or urllib3.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']

Topology API

The topology API allows the user to obtain information about the site topology, the physical topology of a site, the layer 2, and layer 3 topologies of a network.

Site Topology

Site Topology returns information about the sites in Catalyst Center and their hierarchy that is related to the Global site.

SITE_TOPOLOGY_URL = '/dna/intent/api/v1/topology/site-topology'
response = requests.get(BASE_URL + SITE_TOPOLOGY_URL,
                        headers=headers, verify=False)
response = response.json()['response']
for site in response['sites']:
    print(site['name'], '-->' ,site['groupNameHierarchy'])

Physical Topology

The physical topology returns a raw topology of a site, with information about nodes and connecting links between those nodes.

Note: Links that are displayed are one way, so a link between two nodes appears only once.

PHYSICAL_TOPOLOGY_URL = '/dna/intent/api/v1/topology/physical-topology'
response = requests.get(BASE_URL + PHYSICAL_TOPOLOGY_URL,
                        headers=headers, verify=False)
data = response.json()['response']
nodes = {}
for node in data['nodes']:
    nodes[node['id']] = node['label']

for link in data['links']:
    print('Source: {0}({1}) Target: {2}({3}) Status: {4}'.format(
        nodes[link['source']], link.get('startPortName', ''),
        nodes[link['target']], link.get('endPortName', ''),
        link['linkStatus']
    ))

Layer 2 / VLAN Topology

Returns Layer 2 network topology by specified VLAN ID.

L2_TOPOLOGY_URL = '/dna/intent/api/v1/topology/l2/{vlan_id}'
response = requests.get(BASE_URL + L2_TOPOLOGY_URL.format(vlan_id=vlan_id),
                        headers=headers, verify=False)
data = response.json()['response']
nodes = {}
for node in data['nodes']:
    nodes[node['id']] = node['label']

for link in data['links']:
    print('Source: {0}({1}) Target: {2}({3}) Status: {4}'.format(
        nodes[link['source']], link.get('startPortName', ''),
        nodes[link['target']], link.get('endPortName', ''),
        link['linkStatus']
    ))

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

# 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'
SITE_TOPOLOGY_URL = '/dna/intent/api/v1/topology/site-topology'
PHYSICAL_TOPOLOGY_URL = '/dna/intent/api/v1/topology/physical-topology'
L2_TOPOLOGY_URL = '/dna/intent/api/v1/topology/l2/{vlan_id}'

# Get nodes/links
def get_nodes_links(data):
    nodes = {}
    for node in data['nodes']:
        nodes[node['id']] = node['label']

    for link in data['links']:
        print('Source: {0}({1}) Target: {2}({3}) Status: {4}'.format(
            nodes[link['source']], link.get('startPortName', ''),
            nodes[link['target']], link.get('endPortName', ''),
            link['linkStatus']
        ))

# 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

# Get site topology
def get_site_topology(headers):
    response = requests.get(BASE_URL + SITE_TOPOLOGY_URL,
                            headers=headers, verify=False)
    return response.json()['response']

# Get physical topology
def get_physical_topology(headers):
    response = requests.get(BASE_URL + PHYSICAL_TOPOLOGY_URL,
                            headers=headers, verify=False)
    return response.json()['response']

# Get L2 topology
def get_l2_topology(headers, vlan_id):
    response = requests.get(BASE_URL + L2_TOPOLOGY_URL.format(vlan_id=vlan_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'}

    print('Printing site topology...')
    response = get_site_topology(headers)
    for site in response['sites']:
        print(site['name'], '-->' ,site['groupNameHierarchy'])

    print('\nPrinting physical topology...')
    response = get_physical_topology(headers)
    get_nodes_links(response)

    print('\nPrinting L2 topology...')
    response = get_l2_topology(headers, 3001)
    get_nodes_links(response)

if __name__ == "__main__":
    main()