REST API Integration
Objective
In this lesson you will learn how to use Python's requests library to interact with REST APIs exposed by network controllers (Catalyst Center, FMC, SD‑WAN Manager). We will authenticate, retrieve inventory, push a simple policy/template, and poll for operational status. This matters because in production networks, automation via REST APIs reduces human error and speeds configuration changes across many devices — for example, pushing a security policy to all branch firewalls or deploying a fabric configuration to campus access devices.
Quick Recap
Reference the topology from Lesson 1 (core router, distribution switches, access switches, and management plane). This lesson does not change the data‑plane topology; it adds three management systems on the management network:
ASCII Topology (management network)
- All management hosts are reachable on the management VLAN 10 via the management switch mgmt0.
+---------------------------+
| Management Switch | mgmt0
| Interface: mgmt0/1 |
| IP/Network: 10.0.0.0/24 |
+-----------+---------------+
|
+------------------+------------------+
| | |
10.0.0.10/CatalystCenter 10.0.0.20/FMC 10.0.0.30/SDWANManager
(hostname: catalyst.lab.nhprep.com) (hostname: fmc.lab.nhprep.com) (hostname: sdwan.lab.nhprep.com)
Device table
| Device | Role | Management IP | Hostname |
|---|---|---|---|
| Catalyst Center | Network controller (REST API) | 10.0.0.10 | catalyst.lab.nhprep.com |
| FMC | Security controller (REST API) | 10.0.0.20 | fmc.lab.nhprep.com |
| SD‑WAN Manager | SD‑WAN orchestration (API) | 10.0.0.30 | sdwan.lab.nhprep.com |
| Management Switch mgmt0 | L2 Management fabric | 10.0.0.1 (gateway) | mgmt0 |
Credentials and organization used in examples:
- Username: admin
- Password: Lab@123
- Organization: NHPREP
Key Concepts
- REST API basics: REST uses HTTP methods (GET, POST, PUT, DELETE). GET retrieves data, POST creates, PUT replaces, DELETE removes. In production, controllers expose versioned endpoints like /api/v1 to avoid breaking changes.
- Authentication models: Controllers commonly support Basic Auth (HTTP header), token-based auth (session cookie or bearer token), or certificate-based auth. Token workflows typically require you to POST credentials and receive a token used in subsequent Authorization headers.
- JSON payloads and schema: Controller APIs accept and return JSON. Understand the schema (field names and data types). Using sample GET responses helps you craft correct POST/PUT bodies.
- Idempotence and transactions: Good APIs document whether a POST is idempotent. In production, prefer PUT or PATCH for idempotent updates to reduce accidental duplicates.
- Polling and asynchronous operations: Some operations are asynchronous; the server returns a task ID and you must poll a status endpoint until completion (e.g., 202 Accepted then check /tasks/{id}/status). This prevents blocking the controller and allows scale.
Tip: Always inspect the controller’s API documentation or use an interactive tool (Swagger/OpenAPI) if available. When not available, GETting common endpoints like /api/v1, /api/v1/status, or /restconf can reveal capabilities.
Step-by-step configuration
Step 1: Prepare the Python environment
What we are doing: Install and validate the Python requests library and create a working directory for scripts. This ensures your environment can make HTTPS REST calls to controllers.
python3 -m venv ~/lab51_env
source ~/lab51_env/bin/activate
pip install --upgrade pip
pip install requests
mkdir -p ~/lab51_rest
cd ~/lab51_rest
What just happened: The first command creates an isolated Python virtual environment, keeping dependencies separate from system Python. Activating it ensures pip installs into the venv. Installing requests provides the HTTP client used in subsequent steps. Creating the directory organizes your lab scripts.
Real-world note: Using virtual environments avoids dependency conflicts across multiple automation projects.
Verify:
python -c "import requests, json; print('requests', requests.__version__)"
Expected output:
requests 2.31.0
Step 2: Authenticate to a controller (token-based)
What we are doing: Obtain an authentication token from Catalyst Center using credentials. Tokens are commonly required for subsequent REST calls so the controller can verify identity and scope.
# save as auth_catalyst.py
import requests
BASE = "https://10.0.0.10"
AUTH_ENDPOINT = "/api/v1/auth/login"
creds = {"username": "admin", "password": "Lab@123", "org": "NHPREP"}
resp = requests.post(BASE + AUTH_ENDPOINT, json=creds, verify=False)
print(resp.status_code)
print(resp.headers.get("Content-Type"))
print(resp.json())
What just happened: The script posts credentials to the controller’s login endpoint. If successful, the controller typically returns HTTP 200 with a JSON body containing a token (or a session cookie in headers). verify=False is used here to bypass certificate validation for the lab; in production you must validate TLS.
Real-world note: In production, use certificate validation; never use verify=False. Store tokens securely and rotate them regularly.
Verify:
# Example output after running python auth_catalyst.py
200
application/json
{'token': 'abcdef1234567890', 'expires_in': 3600}
Interpretation: HTTP 200 indicates success and the JSON contains the bearer token. You will use "abcdef1234567890" in Authorization headers.
Step 3: GET inventory from Catalyst Center
What we are doing: Query the device inventory endpoint to retrieve managed devices. This allows gathering facts to drive automation decisions, such as targeting only devices of a certain model.
# save as get_inventory.py
import requests
BASE = "https://10.0.0.10"
INV_ENDPOINT = "/api/v1/devices"
token = "abcdef1234567890"
headers = {"Authorization": "Bearer " + token, "Accept": "application/json"}
resp = requests.get(BASE + INV_ENDPOINT, headers=headers, verify=False)
print(resp.status_code)
print(resp.json())
What just happened: The GET request retrieves a JSON list of devices managed by Catalyst Center. The controller responds with device objects including IDs, hostnames, management IPs, and operational state. This is a read-only operation and does not change config.
Real-world note: Use pagination parameters (limit, offset) for large inventories to avoid timeouts.
Verify:
# Example output
200
[
{"id": "dev-001", "hostname": "sw-access-01", "mgmt_ip": "192.168.1.11", "state": "online"},
{"id": "dev-002", "hostname": "sw-access-02", "mgmt_ip": "192.168.1.12", "state": "offline"}
]
Step 4: POST a template to the SD‑WAN Manager
What we are doing: Create (POST) a simple device template on the SD‑WAN Manager. This demonstrates writing configuration via REST — key for orchestration.
# save as post_template_sdwan.py
import requests
BASE = "https://10.0.0.30"
TEMPLATE_ENDPOINT = "/api/v1/templates"
token = "abcdef1234567890" # obtained via auth flow for sdwan
headers = {"Authorization": "Bearer " + token, "Content-Type": "application/json"}
payload = {
"name": "NHPREP-Access-Base",
"description": "Base template for branch access devices",
"config": {
"interfaces": [
{"name": "GigabitEthernet0/0", "ip": "dhcp"},
{"name": "GigabitEthernet0/1", "vlan": 10, "description": "Mgmt"}
]
}
}
resp = requests.post(BASE + TEMPLATE_ENDPOINT, headers=headers, json=payload, verify=False)
print(resp.status_code)
print(resp.json())
What just happened: This POST creates a template resource on the SD‑WAN controller. If the API is asynchronous, the response might include a task ID; if synchronous, it returns the created resource. Creating templates allows consistent device configuration across many sites.
Real-world note: Validate template logic in a lab before applying to production devices to avoid widespread misconfiguration.
Verify:
# Example output
201
{"template_id": "tpl-1001", "name": "NHPREP-Access-Base", "status": "created"}
Interpretation: HTTP 201 confirms resource creation and returns the new template ID.
Step 5: Poll FMC for policy deployment status
What we are doing: Many controllers perform policy deployments asynchronously. We'll request a policy deployment and then poll the status endpoint until completion.
# save as deploy_and_poll_fmc.py
import requests, time
BASE = "https://10.0.0.20"
DEPLOY_ENDPOINT = "/api/v1/policies/deploy"
STATUS_ENDPOINT = "/api/v1/tasks/"
token = "abcdef1234567890"
headers = {"Authorization": "Bearer " + token, "Content-Type": "application/json"}
# Trigger deployment
deploy_resp = requests.post(BASE + DEPLOY_ENDPOINT, headers=headers, json={"policy_id": "pol-001"}, verify=False)
print("deploy status", deploy_resp.status_code)
task = deploy_resp.json().get("task_id")
# Poll
while True:
s = requests.get(BASE + STATUS_ENDPOINT + task, headers=headers, verify=False)
data = s.json()
print(data)
if data.get("status") in ("completed", "failed"):
break
time.sleep(5)
What just happened: The POST initiated a policy deployment and returned a task_id. We then poll the tasks endpoint until the status becomes completed or failed. This pattern lets you track long-running operations without blocking the controller.
Real-world note: Implement exponential backoff and timeout logic for robust polling in production.
Verify:
# Example output
deploy status 202
{"task_id": "task-789"}
{"task_id": "task-789", "status": "in_progress", "percent_complete": 20}
{"task_id": "task-789", "status": "in_progress", "percent_complete": 60}
{"task_id": "task-789", "status": "completed", "percent_complete": 100}
Interpretation: HTTP 202 indicates the request was accepted for processing. The polling shows progress; state "completed" indicates success.
Verification Checklist
- Check 1: Authentication succeeds — run the auth script and verify a token is returned (HTTP 200 and JSON token).
- Check 2: Inventory retrieval returns device list — run get_inventory.py and confirm expected devices are listed (HTTP 200).
- Check 3: Template creation returns 201 and a template_id — run post_template_sdwan.py and confirm creation.
- Check 4: Policy deployment completes — run deploy_and_poll_fmc.py and confirm task status becomes completed.
Common Mistakes
| Symptom | Cause | Fix |
|---|---|---|
| 401 Unauthorized on API calls | Using wrong credentials or expired token | Re-authenticate and use returned token; check time skew and token expiry |
| SSL/TLS errors in requests | Using verify=False in lab hides cert issues; in production, certs are invalid or not trusted | Use proper CA-signed certificates or provide cert bundle to requests verify parameter |
| JSON decode errors on response | Server returned HTML error page (e.g., 404 or 500) not JSON | Check HTTP status code and response.text to debug; ensure endpoint path is correct |
| Long-running operations time out | No polling strategy or too-short timeout | Implement polling with retries, exponential backoff, and max timeout |
Key Takeaways
- REST APIs use standard HTTP verbs; GET for reading, POST/PUT for creating/updating. Always consult the controller’s API schema for exact endpoint behavior.
- Authentication is the first step — token workflows are common. Store and refresh tokens securely; never hardcode secrets in production scripts.
- Expect asynchronous operations; design scripts to poll task endpoints and to handle partial failures gracefully.
- In production, validate certificates and follow secure coding practices (no verify=False). Automation scales quickly, and mistakes can scale too — test templates and scripts in a lab before deployment.
Warning: Never run write operations (POST/PUT/DELETE) against production controllers without change control and backups. A single erroneous template can affect many devices.
This completes Lesson 5: REST API Integration. In the next lesson we'll combine REST interactions with gNMI telemetry to create a closed‑loop automation workflow.