What type of API is Cisco Modeling Labs built on
Have you ever tried to spin up a virtual lab, only to waste an hour clicking through menus while your teammates wait for the topology to appear? Think about it: cisco Modeling Labs (CML) answers that call, but the real power shows up when you talk to it programmatically. Consider this: that frustration is exactly why network engineers started looking for a way to script their labs instead of wiring them by hand. So, what kind of API does CML actually expose?
What Is Cisco Modeling Labs
Cisco Modeling Labs is the successor to the older VIRL platform. It lets you design, run, and manage network topologies that behave like real gear — routers, switches, firewalls, even containers — all inside a virtual environment. You can drag‑and‑drop nodes in the GUI, but the product was built from the ground up to be automated. Under the hood, CML runs a set of services that talk to each other over HTTP, and it exposes that same communication path to anyone who wants to drive the lab from code, CI pipelines, or orchestration tools.
Think of CML as a network sandbox that also happens to be a web application. The sandbox gives you realistic packet flows; the web application gives you a programmable interface Turns out it matters..
Why It Matters
When you can control a lab with scripts, a few things change dramatically:
- Repeatability – You can spin up the exact same topology for every test run, eliminating the “it worked on my machine” problem.
- Speed – A well‑written Python script can bring up a ten‑router lab in seconds, whereas manual clicks might take minutes.
- Integration – Labs become a step in a larger automation workflow, feeding data to test frameworks, security scanners, or even CI/CD pipelines that validate configuration changes before they hit production.
If you’re still clicking through the GUI every time you need a fresh lab, you’re missing out on the speed and consistency that modern network operations demand.
How It Works
The RESTful foundation
At its core, CML provides a RESTful API that communicates over HTTPS using JSON payloads. Every action you can perform in the GUI — creating a node, linking interfaces, starting a simulation, pulling statistics — maps to an HTTP method (GET, POST, PUT, DELETE) against a specific endpoint.
Take this: to list all existing labs you would send:
GET https://cml-server/api/v0/labs
The server replies with a JSON array that contains lab IDs, names, and their current state. Creating a new lab looks like this:
POST https://cml-server/api/v0/labs
{
"title": "My Test Lab",
"description": "Quick sanity check",
"topology": {
"nodes": [ ... ],
"links": [ ... ]
}
}
Because the API follows REST conventions, it’s stateless, cacheable, and easy to test with tools like curl, Postman, or any HTTP client library.
Authentication and endpoints
CML protects its API with token‑based authentication. You first exchange your username and password for a short‑lived token:
POST https://cml-server/api/v0/authenticate
{
"username": "admin",
"password": "secret"
}
The response includes a token that you then add to the Authorization header of every subsequent request:
Authorization: Bearer
Tokens expire after a configurable period (usually an hour), which forces you to refresh them regularly — a good practice that limits the window of exposure if a token is leaked Most people skip this — try not to..
All endpoints live under the /api/v0/ namespace, and the documentation is available directly from the GUI under Help → API Reference. That reference lists every resource: labs, nodes, interfaces, images, snapshots, and even system‑level stats like CPU usage And that's really what it comes down to. Nothing fancy..
Python SDK and CLI
While you can certainly craft raw HTTP calls, most engineers prefer the official Python SDK (cmlmagics) or the command‑line tool (cmlcli). Both are thin wrappers around the REST endpoints, handling token management, URL building, and JSON serialization for you Took long enough..
A simple script to bring up a lab might look like:
from cmlmagics import Cml
cml = Cml(url="https://cml-server", verify=False)
cml.login(username="admin", password="secret")
lab = cml.create_node(node_type="iosv", name="R1", x=100, y=100)
switch = lab.Consider this: create_node(node_type="iosvl2", name="SW1", x=300, y=100)
lab. Even so, create_lab(title="Demo Lab")
router = lab. create_link([router.interfaces[0], switch.
lab.start()
print("Lab is running:", lab.state)
The SDK abstracts away the details of token refresh and error handling, letting you focus on the topology logic rather than the plumbing of HTTP It's one of those things that adds up..
Real‑time event streaming via websockets
REST is great for request‑response interactions, but sometimes you want to know the moment a node goes down or a link fails. For that, CML opens a websocket connection (/api/v0/events) that pushes JSON‑encoded events as they happen That's the part that actually makes a difference..
Typical events include:
node_state_changed– when a router boots, crashes, or is haltedlink_state_changed– when a cable is virtually pulled or restoredlab_state_changed– when the whole simulation starts, pauses, or stops
Your automation can subscribe to this stream and react instantly — think of triggering a backup configuration the second a router enters a failed state, or tearing down a lab automatically after a test suite finishes.
Common Mistakes
Treating the API like a GUI shortcut
One frequent error is to assume that every button in the web interface has a one‑to‑one API counterpart and then trying to reproduce a multi‑step wizard with dozens of separate calls. In reality, many complex actions (like importing an external topology file) are exposed as
This is the bit that actually matters in practice.
single, optimized endpoints under the hood. Day to day, the GUI might break a process into five steps for the user, but the API often provides a single POST /import that handles validation, parsing, and node creation in one atomic operation. Before you script anything, check the API reference to see if a bulk or composite action already exists That alone is useful..
Ignoring idempotency and state checks
Another pitfall is assuming that calling create_lab twice with the same title will fail gracefully. Always query the current state (GET /labs) before creating or modifying resources, and use unique identifiers (like a lab slug or a deterministic naming convention) to make your scripts idempotent. By default, the API will happily create a duplicate lab unless you explicitly check for an existing one first. This is especially important in CI/CD pipelines where a failed step might leave a partially created lab running, and a retry would otherwise spawn clutter.
Hardcoding credentials and tokens
It can be tempting to paste a token directly into a script, especially during rapid prototyping. Store secrets in environment variables or a vault, and let the SDK’s login() method pull them at runtime. Resist this. The same applies to server URLs and verification flags — use configuration files or command-line arguments to keep your code portable across development, staging, and production environments Most people skip this — try not to..
Overlooking lab cleanup
In a shared automation environment, orphaned labs consume licenses and server resources quickly. Always implement a teardown phase in your scripts, and consider setting a TTL (time‑to‑live) on labs created for temporary tests. If you are using webhooks or event streams, you can even configure the system to auto‑delete labs that have been idle for a specified duration.
Conclusion
The Cisco Modeling Layer API, combined with the Python SDK and real‑time event streaming, gives you a powerful foundation for automating network simulations at scale. By avoiding the common traps — such as reinventing GUI workflows, ignoring idempotency, hardcoding secrets, and neglecting cleanup — you can build solid, maintainable automation that turns CML from a manual lab tool into a programmable engine for testing, training, and continuous validation.