5.13 Catalyst Center Integration
- Version: 2.1
- Last Updated: December 30, 2025
- Author: Abhavtech Network Architecture Team
- Status: Production Ready
- Classification: Internal Use Only
5.13.1 Integration Overview
Catalyst Center (formerly DNA Center) and SD-WAN Manager integration enables unified visibility and coordinated management across the SD-Access and SD-WAN domains. This section covers the integration architecture, configuration, and operational workflows.
Integration Architecture
┌─────────────────────────────────────────────────────────────────────────────────────────────┐
│ CATALYST CENTER AND SD-WAN MANAGER INTEGRATION │
└─────────────────────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────────────┐
│ UNIFIED OPERATIONS VIEW │
│ │
│ ┌───────────────────────────────────────────────────────────────────────────────┐ │
│ │ THIRD-PARTY INTEGRATION │ │
│ │ ServiceNow │ Splunk │ Grafana │ PagerDuty │ Custom Apps │ │
│ └───────────────────────────────────────────────────────────────────────────────┘ │
│ │ │
│ REST APIs │
│ │ │
│ ┌─────────────────────────────────────┼─────────────────────────────────────────┐ │
│ │ │ │ │
│ │ ┌─────────────────────┐ ┌─────▼─────────────┐ │ │
│ │ │ │ │ │ │ │
│ │ │ CATALYST CENTER │◄────► SD-WAN MANAGER │ │ │
│ │ │ (SD-Access Mgmt) │ │ (vManage) │ │ │
│ │ │ │ │ │ │ │
│ │ │ • Fabric Provisioning │ • WAN Edge Mgmt │ │ │
│ │ │ • Assurance │ │ • Policy Config │ │ │
│ │ │ • Policy Admin │ │ • Analytics │ │ │
│ │ │ • PnP │ │ • ZTP │ │ │
│ │ │ │ │ │ │ │
│ │ └──────────┬──────────┘ └──────────┬─────────┘ │ │
│ │ │ │ │ │
│ └──────────────┼───────────────────────────┼──────────────────────────────────────┘ │
│ │ │ │
│ ┌──────────────┴───────────────────────────┴──────────────────────────────────────┐ │
│ │ SHARED SERVICES │ │
│ │ │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ ISE │ │ Infoblox │ │ Syslog │ │ SNMP │ │ │
│ │ │ (Auth/SGT) │ │ (IPAM) │ │ (Logging) │ │(Monitoring) │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │ │
│ │ │ │
│ └──────────────────────────────────────────────────────────────────────────────────┘ │
│ │
└────────────────────────────────────────────────────────────────────────────────────────┘
Integration Capabilities
| Capability |
Description |
Benefit |
| Cross-domain visibility |
View SD-WAN health from Catalyst Center |
Single pane of glass |
| Unified authentication |
Shared ISE for both domains |
Consistent identity |
| Correlated analytics |
End-to-end path analysis |
Faster troubleshooting |
| Coordinated provisioning |
Automated handoff setup |
Reduced errors |
| Event correlation |
Unified alarms and events |
Streamlined operations |
5.13.2 Prerequisites
System Requirements
| Component |
Version |
Purpose |
| Catalyst Center |
2.3.7.x |
SD-Access management |
| SD-WAN Manager |
20.15.x |
SD-WAN management |
| ISE |
3.3/3.4 |
Shared authentication |
| Python |
3.9+ |
Automation scripts |
| Network |
HTTPS connectivity |
API communication |
Network Connectivity
Network Connectivity Requirements
=================================
Catalyst Center to SD-WAN Manager:
- Protocol: HTTPS (TCP 443)
- Source: Catalyst Center cluster VIP (10.10.50.100)
- Destination: SD-WAN Manager cluster VIP (10.255.0.10)
- Direction: Bidirectional
API Rate Limits:
- Catalyst Center: 60 requests/minute per user
- SD-WAN Manager: 100 requests/minute per session
Firewall Rules Required:
┌─────────────────────────────────────────────────────────────────┐
│ Source │ Destination │ Port │ Proto │
├─────────────────────────────────────────────────────────────────┤
│ 10.10.50.100 (DNAC) │ 10.255.0.10 (vManage)│ 443 │ TCP │
│ 10.255.0.10 (vManage)│ 10.10.50.100 (DNAC) │ 443 │ TCP │
│ 10.10.50.100 (DNAC) │ 10.10.50.21 (ISE) │ 443 │ TCP │
│ 10.255.0.10 (vManage)│ 10.10.50.21 (ISE) │ 443 │ TCP │
└─────────────────────────────────────────────────────────────────┘
5.13.3 API Authentication Setup
Catalyst Center API Credentials
#!/usr/bin/env python3
"""
Catalyst Center API Authentication Setup
"""
import requests
import json
import urllib3
from base64 import b64encode
urllib3.disable_warnings()
class CatalystCenterAuth:
def __init__(self, host, username, password):
self.host = host
self.base_url = f"https://{host}"
self.username = username
self.password = password
self.token = None
def get_auth_token(self):
"""Get authentication token from Catalyst Center"""
url = f"{self.base_url}/dna/system/api/v1/auth/token"
# Basic auth for token request
credentials = b64encode(f"{self.username}:{self.password}".encode()).decode()
headers = {
'Authorization': f'Basic {credentials}',
'Content-Type': 'application/json'
}
response = requests.post(url, headers=headers, verify=False)
if response.status_code == 200:
self.token = response.json()['Token']
print(f"✓ Token obtained successfully")
print(f" Token expires in: 1 hour")
return self.token
else:
print(f"✗ Failed to get token: {response.status_code}")
return None
def get_headers(self):
"""Get headers for API calls"""
if not self.token:
self.get_auth_token()
return {
'X-Auth-Token': self.token,
'Content-Type': 'application/json'
}
def test_connection(self):
"""Test API connectivity"""
url = f"{self.base_url}/dna/intent/api/v1/network-device/count"
headers = self.get_headers()
response = requests.get(url, headers=headers, verify=False)
if response.status_code == 200:
count = response.json()['response']
print(f"✓ API connection successful")
print(f" Total devices: {count}")
return True
else:
print(f"✗ API connection failed: {response.status_code}")
return False
# Usage
if __name__ == "__main__":
dnac = CatalystCenterAuth(
host='catalyst-center.abhavtech.com',
username='admin',
password='<password>'
)
dnac.get_auth_token()
dnac.test_connection()
SD-WAN Manager API Credentials
#!/usr/bin/env python3
"""
SD-WAN Manager (vManage) API Authentication Setup
"""
import requests
import json
import urllib3
urllib3.disable_warnings()
class SDWANManagerAuth:
def __init__(self, host, username, password):
self.host = host
self.base_url = f"https://{host}:443"
self.username = username
self.password = password
self.session = requests.Session()
self.token = None
def login(self):
"""Authenticate to SD-WAN Manager"""
# Step 1: j_security_check
login_url = f"{self.base_url}/j_security_check"
payload = {
'j_username': self.username,
'j_password': self.password
}
response = self.session.post(login_url, data=payload, verify=False)
# Check for successful login
if '<html>' in response.text:
print("✗ Login failed - invalid credentials")
return False
# Step 2: Get XSRF token
token_url = f"{self.base_url}/dataservice/client/token"
token_response = self.session.get(token_url, verify=False)
if token_response.status_code == 200:
self.token = token_response.text
self.session.headers['X-XSRF-TOKEN'] = self.token
print(f"✓ Authentication successful")
return True
else:
print(f"✗ Failed to get XSRF token")
return False
def test_connection(self):
"""Test API connectivity"""
url = f"{self.base_url}/dataservice/system/device/vedges"
response = self.session.get(url, verify=False)
if response.status_code == 200:
devices = response.json().get('data', [])
print(f"✓ API connection successful")
print(f" WAN Edge devices: {len(devices)}")
return True
else:
print(f"✗ API connection failed: {response.status_code}")
return False
def logout(self):
"""Logout from SD-WAN Manager"""
logout_url = f"{self.base_url}/logout"
self.session.get(logout_url, verify=False)
print("✓ Logged out successfully")
# Usage
if __name__ == "__main__":
vmanage = SDWANManagerAuth(
host='sdwan-manager.abhavtech.com',
username='admin',
password='<password>'
)
if vmanage.login():
vmanage.test_connection()
vmanage.logout()
5.13.4 Cross-Domain Inventory Synchronization
Unified Device Inventory
#!/usr/bin/env python3
"""
Cross-Domain Device Inventory Synchronization
Correlates devices between Catalyst Center and SD-WAN Manager
"""
import requests
import json
import urllib3
from datetime import datetime
urllib3.disable_warnings()
class UnifiedInventory:
def __init__(self, dnac_host, vmanage_host, username, password):
self.dnac_host = dnac_host
self.vmanage_host = vmanage_host
self.username = username
self.password = password
# Initialize sessions
self.dnac_token = self._get_dnac_token()
self.vmanage_session = self._create_vmanage_session()
def _get_dnac_token(self):
"""Get Catalyst Center token"""
url = f"https://{self.dnac_host}/dna/system/api/v1/auth/token"
response = requests.post(url, auth=(self.username, self.password), verify=False)
return response.json()['Token']
def _create_vmanage_session(self):
"""Create vManage session"""
session = requests.Session()
login_url = f"https://{self.vmanage_host}/j_security_check"
session.post(login_url, data={'j_username': self.username, 'j_password': self.password}, verify=False)
token_url = f"https://{self.vmanage_host}/dataservice/client/token"
token_response = session.get(token_url, verify=False)
if token_response.status_code == 200:
session.headers['X-XSRF-TOKEN'] = token_response.text
return session
def get_dnac_devices(self):
"""Get devices from Catalyst Center"""
headers = {'X-Auth-Token': self.dnac_token, 'Content-Type': 'application/json'}
url = f"https://{self.dnac_host}/dna/intent/api/v1/network-device"
response = requests.get(url, headers=headers, verify=False)
devices = response.json().get('response', [])
# Filter and format
formatted = []
for device in devices:
formatted.append({
'hostname': device.get('hostname'),
'ip': device.get('managementIpAddress'),
'type': device.get('type'),
'role': device.get('role'),
'family': device.get('family'),
'serial': device.get('serialNumber'),
'status': device.get('reachabilityStatus'),
'source': 'catalyst-center'
})
return formatted
def get_vmanage_devices(self):
"""Get devices from SD-WAN Manager"""
url = f"https://{self.vmanage_host}/dataservice/device"
response = self.vmanage_session.get(url, verify=False)
devices = response.json().get('data', [])
# Filter and format
formatted = []
for device in devices:
formatted.append({
'hostname': device.get('host-name'),
'ip': device.get('system-ip'),
'type': device.get('device-type'),
'role': device.get('personality'),
'family': 'SD-WAN',
'serial': device.get('board-serial'),
'status': device.get('reachability'),
'source': 'sdwan-manager'
})
return formatted
def correlate_handoff_devices(self):
"""Find devices involved in SD-Access/SD-WAN handoff"""
dnac_devices = self.get_dnac_devices()
vmanage_devices = self.get_vmanage_devices()
# Find border nodes and WAN edges
borders = [d for d in dnac_devices if d['role'] == 'BORDER ROUTER']
wan_edges = [d for d in vmanage_devices if d['role'] == 'vedge']
correlations = []
# Match by site (based on hostname convention)
for border in borders:
site_code = border['hostname'].split('-')[1] if '-' in border['hostname'] else ''
matching_edges = [w for w in wan_edges if site_code in w['hostname']]
correlations.append({
'site': site_code,
'border_node': border['hostname'],
'border_ip': border['ip'],
'border_status': border['status'],
'wan_edges': [{'hostname': w['hostname'], 'ip': w['ip'], 'status': w['status']} for w in matching_edges]
})
return correlations
def generate_inventory_report(self):
"""Generate unified inventory report"""
dnac_devices = self.get_dnac_devices()
vmanage_devices = self.get_vmanage_devices()
correlations = self.correlate_handoff_devices()
report = {
'generated': datetime.now().isoformat(),
'summary': {
'catalyst_center_devices': len(dnac_devices),
'sdwan_manager_devices': len(vmanage_devices),
'handoff_correlations': len(correlations)
},
'catalyst_center': {
'total': len(dnac_devices),
'by_role': {},
'by_status': {}
},
'sdwan_manager': {
'total': len(vmanage_devices),
'by_role': {},
'by_status': {}
},
'handoff_sites': correlations
}
# Count by role and status
for device in dnac_devices:
role = device['role'] or 'Unknown'
status = device['status'] or 'Unknown'
report['catalyst_center']['by_role'][role] = report['catalyst_center']['by_role'].get(role, 0) + 1
report['catalyst_center']['by_status'][status] = report['catalyst_center']['by_status'].get(status, 0) + 1
for device in vmanage_devices:
role = device['role'] or 'Unknown'
status = device['status'] or 'Unknown'
report['sdwan_manager']['by_role'][role] = report['sdwan_manager']['by_role'].get(role, 0) + 1
report['sdwan_manager']['by_status'][status] = report['sdwan_manager']['by_status'].get(status, 0) + 1
return report
def print_report(self):
"""Print formatted inventory report"""
report = self.generate_inventory_report()
print("\n" + "="*70)
print("UNIFIED NETWORK INVENTORY REPORT")
print(f"Generated: {report['generated']}")
print("="*70)
print("\n--- SUMMARY ---")
print(f" Catalyst Center Devices: {report['summary']['catalyst_center_devices']}")
print(f" SD-WAN Manager Devices: {report['summary']['sdwan_manager_devices']}")
print(f" Handoff Sites: {report['summary']['handoff_correlations']}")
print("\n--- CATALYST CENTER DEVICES ---")
print(" By Role:")
for role, count in report['catalyst_center']['by_role'].items():
print(f" {role}: {count}")
print(" By Status:")
for status, count in report['catalyst_center']['by_status'].items():
print(f" {status}: {count}")
print("\n--- SD-WAN MANAGER DEVICES ---")
print(" By Role:")
for role, count in report['sdwan_manager']['by_role'].items():
print(f" {role}: {count}")
print(" By Status:")
for status, count in report['sdwan_manager']['by_status'].items():
print(f" {status}: {count}")
print("\n--- HANDOFF CORRELATIONS ---")
for site in report['handoff_sites']:
print(f"\n Site: {site['site']}")
print(f" Border Node: {site['border_node']} ({site['border_ip']}) - {site['border_status']}")
for edge in site['wan_edges']:
print(f" WAN Edge: {edge['hostname']} ({edge['ip']}) - {edge['status']}")
print("\n" + "="*70)
if __name__ == "__main__":
inventory = UnifiedInventory(
dnac_host='catalyst-center.abhavtech.com',
vmanage_host='sdwan-manager.abhavtech.com',
username='admin',
password='<password>'
)
inventory.print_report()
5.13.5 Unified Dashboard Integration
Cross-Domain Health Dashboard
#!/usr/bin/env python3
"""
Cross-Domain Health Dashboard
Aggregates health metrics from both platforms
"""
import requests
import json
import urllib3
from datetime import datetime
import time
urllib3.disable_warnings()
class CrossDomainDashboard:
def __init__(self, dnac_host, vmanage_host, username, password):
self.dnac_host = dnac_host
self.vmanage_host = vmanage_host
self.username = username
self.password = password
self.dnac_token = self._get_dnac_token()
self.vmanage_session = self._create_vmanage_session()
def _get_dnac_token(self):
url = f"https://{self.dnac_host}/dna/system/api/v1/auth/token"
response = requests.post(url, auth=(self.username, self.password), verify=False)
return response.json()['Token']
def _create_vmanage_session(self):
session = requests.Session()
login_url = f"https://{self.vmanage_host}/j_security_check"
session.post(login_url, data={'j_username': self.username, 'j_password': self.password}, verify=False)
token_url = f"https://{self.vmanage_host}/dataservice/client/token"
token_response = session.get(token_url, verify=False)
if token_response.status_code == 200:
session.headers['X-XSRF-TOKEN'] = token_response.text
return session
def get_sdaccess_health(self):
"""Get SD-Access fabric health from Catalyst Center"""
headers = {'X-Auth-Token': self.dnac_token}
# Get overall health
health_url = f"https://{self.dnac_host}/dna/intent/api/v1/network-health"
response = requests.get(health_url, headers=headers, verify=False)
if response.status_code == 200:
health_data = response.json().get('response', [])
if health_data:
return {
'overall_health': health_data[0].get('healthScore', 0),
'healthy_devices': health_data[0].get('goodCount', 0),
'warning_devices': health_data[0].get('unmonitoredCount', 0),
'critical_devices': health_data[0].get('fairCount', 0) + health_data[0].get('badCount', 0),
'total_devices': health_data[0].get('totalCount', 0)
}
return {'overall_health': 0, 'healthy_devices': 0, 'warning_devices': 0, 'critical_devices': 0, 'total_devices': 0}
def get_sdwan_health(self):
"""Get SD-WAN health from vManage"""
# Get device health
url = f"https://{self.vmanage_host}/dataservice/device"
response = self.vmanage_session.get(url, verify=False)
devices = response.json().get('data', [])
healthy = 0
warning = 0
critical = 0
for device in devices:
reachability = device.get('reachability', 'unreachable')
status = device.get('status', 'unknown')
if reachability == 'reachable' and status == 'normal':
healthy += 1
elif reachability == 'reachable':
warning += 1
else:
critical += 1
total = len(devices)
overall_health = (healthy / total * 100) if total > 0 else 0
return {
'overall_health': round(overall_health, 1),
'healthy_devices': healthy,
'warning_devices': warning,
'critical_devices': critical,
'total_devices': total
}
def get_tunnel_health(self):
"""Get SD-WAN tunnel health"""
url = f"https://{self.vmanage_host}/dataservice/device/tunnel/statistics"
# Get tunnel stats for all devices
devices_url = f"https://{self.vmanage_host}/dataservice/device"
devices_response = self.vmanage_session.get(devices_url, verify=False)
devices = devices_response.json().get('data', [])
total_tunnels = 0
up_tunnels = 0
for device in devices:
if device.get('device-type') == 'vedge':
system_ip = device.get('system-ip')
tunnel_url = f"https://{self.vmanage_host}/dataservice/device/tunnel/statistics?deviceId={system_ip}"
tunnel_response = self.vmanage_session.get(tunnel_url, verify=False)
tunnels = tunnel_response.json().get('data', [])
for tunnel in tunnels:
total_tunnels += 1
if tunnel.get('tunnel-state') == 'up':
up_tunnels += 1
return {
'total_tunnels': total_tunnels,
'up_tunnels': up_tunnels,
'down_tunnels': total_tunnels - up_tunnels,
'health_percentage': round((up_tunnels / total_tunnels * 100) if total_tunnels > 0 else 0, 1)
}
def get_combined_alerts(self):
"""Get alerts from both platforms"""
alerts = []
# Catalyst Center alarms
headers = {'X-Auth-Token': self.dnac_token}
alarm_url = f"https://{self.dnac_host}/dna/intent/api/v1/issues"
params = {'priority': 'P1,P2', 'issueStatus': 'active'}
response = requests.get(alarm_url, headers=headers, params=params, verify=False)
if response.status_code == 200:
issues = response.json().get('response', [])
for issue in issues[:10]: # Top 10
alerts.append({
'source': 'Catalyst Center',
'severity': issue.get('priority', 'P3'),
'name': issue.get('name', 'Unknown'),
'device': issue.get('deviceName', 'Unknown'),
'timestamp': issue.get('lastOccurenceTime', '')
})
# SD-WAN Manager alarms
alarm_url = f"https://{self.vmanage_host}/dataservice/alarms"
params = {'query': json.dumps({'query': {'condition': 'AND', 'rules': [{'field': 'active', 'type': 'boolean', 'value': ['true']}]}})}
response = self.vmanage_session.get(alarm_url, params=params, verify=False)
if response.status_code == 200:
alarms = response.json().get('data', [])
for alarm in alarms[:10]: # Top 10
severity_map = {'Critical': 'P1', 'Major': 'P2', 'Minor': 'P3', 'Warning': 'P4'}
alerts.append({
'source': 'SD-WAN Manager',
'severity': severity_map.get(alarm.get('severity', 'Warning'), 'P4'),
'name': alarm.get('message', 'Unknown'),
'device': alarm.get('system-ip', 'Unknown'),
'timestamp': alarm.get('entry_time', '')
})
# Sort by severity
severity_order = {'P1': 0, 'P2': 1, 'P3': 2, 'P4': 3}
alerts.sort(key=lambda x: severity_order.get(x['severity'], 4))
return alerts
def display_dashboard(self):
"""Display unified dashboard"""
sdaccess = self.get_sdaccess_health()
sdwan = self.get_sdwan_health()
tunnels = self.get_tunnel_health()
alerts = self.get_combined_alerts()
print("\n" + "="*70)
print(" ABHAVTECH UNIFIED NETWORK HEALTH DASHBOARD")
print(f" {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print("="*70)
# Health summary
print("\n┌─────────────────────────────────────────────────────────────────────┐")
print("│ HEALTH SUMMARY │")
print("├─────────────────────────────────────────────────────────────────────┤")
print(f"│ SD-Access Health: {sdaccess['overall_health']:>5.1f}% │ SD-WAN Health: {sdwan['overall_health']:>5.1f}% │")
print(f"│ Tunnel Health: {tunnels['health_percentage']:>5.1f}% │ │")
print("└─────────────────────────────────────────────────────────────────────┘")
# Device counts
print("\n┌────────────────────────────┬────────────────────────────────────────┐")
print("│ SD-ACCESS │ SD-WAN │")
print("├────────────────────────────┼────────────────────────────────────────┤")
print(f"│ Total Devices: {sdaccess['total_devices']:>5} │ Total Devices: {sdwan['total_devices']:>5} │")
print(f"│ Healthy: {sdaccess['healthy_devices']:>5} │ Healthy: {sdwan['healthy_devices']:>5} │")
print(f"│ Warning: {sdaccess['warning_devices']:>5} │ Warning: {sdwan['warning_devices']:>5} │")
print(f"│ Critical: {sdaccess['critical_devices']:>5} │ Critical: {sdwan['critical_devices']:>5} │")
print("└────────────────────────────┴────────────────────────────────────────┘")
# Tunnel status
print("\n┌─────────────────────────────────────────────────────────────────────┐")
print("│ TUNNEL STATUS │")
print("├─────────────────────────────────────────────────────────────────────┤")
print(f"│ Total Tunnels: {tunnels['total_tunnels']:>5} Up: {tunnels['up_tunnels']:>5} Down: {tunnels['down_tunnels']:>5} │")
print("└─────────────────────────────────────────────────────────────────────┘")
# Active alerts
print("\n┌─────────────────────────────────────────────────────────────────────┐")
print("│ ACTIVE ALERTS (Top 10) │")
print("├────────┬─────────────────┬──────────────────────────────────────────┤")
print("│ Sev │ Source │ Description │")
print("├────────┼─────────────────┼──────────────────────────────────────────┤")
for alert in alerts[:10]:
sev = alert['severity']
source = alert['source'][:15]
desc = alert['name'][:40]
print(f"│ {sev:<6} │ {source:<15} │ {desc:<40} │")
if not alerts:
print("│ │ No active alerts │ │")
print("└────────┴─────────────────┴──────────────────────────────────────────┘")
print("\n" + "="*70)
if __name__ == "__main__":
dashboard = CrossDomainDashboard(
dnac_host='catalyst-center.abhavtech.com',
vmanage_host='sdwan-manager.abhavtech.com',
username='admin',
password='<password>'
)
dashboard.display_dashboard()
5.13.6 Automated Provisioning Workflows
Coordinated Site Provisioning
#!/usr/bin/env python3
"""
Coordinated Site Provisioning Workflow
Provisions both SD-Access and SD-WAN components for a new site
"""
import requests
import json
import urllib3
import time
from datetime import datetime
urllib3.disable_warnings()
class CoordinatedProvisioning:
def __init__(self, dnac_host, vmanage_host, username, password):
self.dnac_host = dnac_host
self.vmanage_host = vmanage_host
self.username = username
self.password = password
self.dnac_token = self._get_dnac_token()
self.vmanage_session = self._create_vmanage_session()
def _get_dnac_token(self):
url = f"https://{self.dnac_host}/dna/system/api/v1/auth/token"
response = requests.post(url, auth=(self.username, self.password), verify=False)
return response.json()['Token']
def _create_vmanage_session(self):
session = requests.Session()
login_url = f"https://{self.vmanage_host}/j_security_check"
session.post(login_url, data={'j_username': self.username, 'j_password': self.password}, verify=False)
token_url = f"https://{self.vmanage_host}/dataservice/client/token"
token_response = session.get(token_url, verify=False)
if token_response.status_code == 200:
session.headers['X-XSRF-TOKEN'] = token_response.text
return session
def provision_new_site(self, site_config):
"""
Provision a new site with both SD-Access and SD-WAN
site_config = {
'site_name': 'Hyderabad',
'site_code': 'HYD',
'site_id': 403,
'region': 'India',
'wan_edge_serial': 'FDO2345X1AE',
'wan_edge_model': 'C8300-1N1S-6T',
'system_ip': '10.255.4.4',
'transport_type': 'internet_lte',
'vpns': [10, 20, 30]
}
"""
print(f"\n{'='*60}")
print(f"COORDINATED SITE PROVISIONING: {site_config['site_name']}")
print(f"Started: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print(f"{'='*60}")
results = {
'site_name': site_config['site_name'],
'steps': [],
'success': True
}
# Step 1: Create site in Catalyst Center
print("\n[Step 1] Creating site in Catalyst Center...")
dnac_site_result = self._create_dnac_site(site_config)
results['steps'].append({'step': 'Create DNAC Site', 'result': dnac_site_result})
if not dnac_site_result['success']:
results['success'] = False
print(f" ✗ Failed: {dnac_site_result['message']}")
else:
print(f" ✓ Site created: {dnac_site_result['site_id']}")
# Step 2: Add WAN Edge to vManage inventory
print("\n[Step 2] Adding WAN Edge to SD-WAN Manager...")
wan_edge_result = self._add_wan_edge(site_config)
results['steps'].append({'step': 'Add WAN Edge', 'result': wan_edge_result})
if not wan_edge_result['success']:
results['success'] = False
print(f" ✗ Failed: {wan_edge_result['message']}")
else:
print(f" ✓ WAN Edge added: {site_config['wan_edge_serial']}")
# Step 3: Generate template variables
print("\n[Step 3] Generating template variables...")
variables = self._generate_variables(site_config)
print(f" ✓ Variables generated for {len(site_config['vpns'])} VPNs")
# Step 4: Attach device template
print("\n[Step 4] Attaching device template...")
template_result = self._attach_template(site_config, variables)
results['steps'].append({'step': 'Attach Template', 'result': template_result})
if not template_result['success']:
results['success'] = False
print(f" ✗ Failed: {template_result['message']}")
else:
print(f" ✓ Template attached successfully")
# Step 5: Configure handoff (if hub site)
if site_config.get('is_hub', False):
print("\n[Step 5] Configuring SD-Access handoff...")
handoff_result = self._configure_handoff(site_config)
results['steps'].append({'step': 'Configure Handoff', 'result': handoff_result})
if not handoff_result['success']:
results['success'] = False
print(f" ✗ Failed: {handoff_result['message']}")
else:
print(f" ✓ Handoff configured")
# Summary
print(f"\n{'='*60}")
if results['success']:
print(f"✓ SITE PROVISIONING COMPLETED SUCCESSFULLY")
else:
print(f"✗ SITE PROVISIONING COMPLETED WITH ERRORS")
print(f"{'='*60}")
return results
def _create_dnac_site(self, site_config):
"""Create site in Catalyst Center hierarchy"""
headers = {'X-Auth-Token': self.dnac_token, 'Content-Type': 'application/json'}
url = f"https://{self.dnac_host}/dna/intent/api/v1/site"
payload = {
"type": "building",
"site": {
"building": {
"name": site_config['site_name'],
"parentName": f"Global/{site_config['region']}",
"address": f"{site_config['site_name']}, {site_config['region']}"
}
}
}
try:
response = requests.post(url, headers=headers, json=payload, verify=False)
if response.status_code in [200, 202]:
return {'success': True, 'site_id': site_config['site_code'], 'message': 'Site created'}
else:
return {'success': False, 'message': f"HTTP {response.status_code}"}
except Exception as e:
return {'success': False, 'message': str(e)}
def _add_wan_edge(self, site_config):
"""Add WAN Edge to vManage inventory"""
url = f"https://{self.vmanage_host}/dataservice/system/device"
payload = {
"deviceIP": site_config['system_ip'],
"personality": "vedge",
"serialNumber": site_config['wan_edge_serial'],
"configOperationMode": "vmanage",
"deviceModel": site_config['wan_edge_model'],
"deviceState": "tokengenerated",
"validity": "valid",
"site-id": str(site_config['site_id']),
"host-name": f"ABVT-{site_config['site_code']}-WE01"
}
try:
response = self.vmanage_session.post(url, json=payload, verify=False)
if response.status_code == 200:
return {'success': True, 'message': 'WAN Edge added'}
else:
return {'success': False, 'message': f"HTTP {response.status_code}"}
except Exception as e:
return {'success': False, 'message': str(e)}
def _generate_variables(self, site_config):
"""Generate template variables for the site"""
variables = {
'device_hostname': f"ABVT-{site_config['site_code']}-WE01",
'device_system_ip': site_config['system_ip'],
'device_site_id': str(site_config['site_id']),
'transport_type': site_config['transport_type']
}
# VPN-specific variables
vpn_base_ip = int(site_config['system_ip'].split('.')[-1])
for vpn in site_config['vpns']:
variables[f'vpn{vpn}_gateway'] = f"10.{vpn}.{vpn_base_ip}.1"
return variables
def _attach_template(self, site_config, variables):
"""Attach device template to WAN Edge"""
# Get template ID
template_name = "Branch-C8300-Template"
templates_url = f"https://{self.vmanage_host}/dataservice/template/device"
templates_response = self.vmanage_session.get(templates_url, verify=False)
templates = templates_response.json().get('data', [])
template_id = None
for template in templates:
if template.get('templateName') == template_name:
template_id = template.get('templateId')
break
if not template_id:
return {'success': False, 'message': f"Template '{template_name}' not found"}
# Attach template
attach_url = f"https://{self.vmanage_host}/dataservice/template/device/config/attachfeature"
payload = {
"deviceTemplateList": [{
"templateId": template_id,
"device": [{
"csv-status": "complete",
"csv-deviceId": site_config['wan_edge_serial'],
"csv-deviceIP": site_config['system_ip'],
"csv-host-name": variables['device_hostname'],
**{f"/{k}/": v for k, v in variables.items()}
}],
"isEdited": False,
"isMasterEdited": False
}]
}
try:
response = self.vmanage_session.post(attach_url, json=payload, verify=False)
if response.status_code == 200:
return {'success': True, 'message': 'Template attached'}
else:
return {'success': False, 'message': f"HTTP {response.status_code}"}
except Exception as e:
return {'success': False, 'message': str(e)}
def _configure_handoff(self, site_config):
"""Configure SD-Access handoff for hub sites"""
# This would configure BGP peering and handoff interfaces
# Implementation depends on specific automation requirements
return {'success': True, 'message': 'Handoff configured (manual verification required)'}
if __name__ == "__main__":
# Example: Provision new site
site_config = {
'site_name': 'Hyderabad',
'site_code': 'HYD',
'site_id': 403,
'region': 'India',
'wan_edge_serial': 'FDO2345X1AE',
'wan_edge_model': 'C8300-1N1S-6T',
'system_ip': '10.255.4.4',
'transport_type': 'internet_lte',
'vpns': [10, 20, 30],
'is_hub': False
}
provisioner = CoordinatedProvisioning(
dnac_host='catalyst-center.abhavtech.com',
vmanage_host='sdwan-manager.abhavtech.com',
username='admin',
password='<password>'
)
provisioner.provision_new_site(site_config)
5.13.7 Event Correlation and Alerting
Unified Alert Configuration
# unified-alerts-config.yaml
# Configuration for cross-domain alert correlation
alert_correlation:
enabled: true
correlation_window: 300 # seconds
# Alert sources
sources:
- name: catalyst-center
type: dnac
host: catalyst-center.abhavtech.com
poll_interval: 60
- name: sdwan-manager
type: vmanage
host: sdwan-manager.abhavtech.com
poll_interval: 60
# Correlation rules
rules:
- name: border-wan-edge-failure
description: Correlate border and WAN edge failures at same site
conditions:
- source: catalyst-center
device_role: BORDER ROUTER
alert_type: reachability
- source: sdwan-manager
device_role: vedge
alert_type: control-connection
correlation_key: site_code
output_severity: critical
notification:
- type: pagerduty
service_key: ${PAGERDUTY_KEY}
- type: slack
channel: "#network-critical"
- name: tunnel-bfd-correlation
description: Correlate tunnel and BFD failures
conditions:
- source: sdwan-manager
alert_type: tunnel-down
- source: sdwan-manager
alert_type: bfd-session-down
correlation_key: system_ip
output_severity: major
# Notification channels
notifications:
pagerduty:
enabled: true
api_url: https://events.pagerduty.com/v2/enqueue
slack:
enabled: true
webhook_url: ${SLACK_WEBHOOK}
email:
enabled: true
smtp_server: smtp.abhavtech.com
recipients:
- noc@abhavtech.com
- network-ops@abhavtech.com
5.13.8 Best Practices
Integration Best Practices
| Area |
Best Practice |
Rationale |
| Authentication |
Use service accounts |
Avoid user credential lockouts |
| API calls |
Implement retry logic |
Handle transient failures |
| Rate limiting |
Respect API limits |
Prevent throttling |
| Token management |
Refresh tokens proactively |
Avoid auth failures |
| Error handling |
Log all API errors |
Facilitate troubleshooting |
| Monitoring |
Monitor integration health |
Detect issues early |
Security Considerations
- API Credentials: Store in secrets manager (HashiCorp Vault, AWS Secrets Manager)
- Network Isolation: Use dedicated management VLAN for API traffic
- TLS Verification: Enable in production (disable only for testing)
- Audit Logging: Log all API calls for compliance
- RBAC: Use least-privilege API accounts
References
- Cisco Catalyst Center API Documentation
- Cisco SD-WAN Manager API Reference
- Abhavtech Integration Standards
- Cisco DevNet Learning Labs
Document Version: 2.1
Last Updated: December 30, 2025
Classification: Internal Use Only
Abhavtech.com - SD-WAN Documentation