Network Controllers
Policies, Templates, and Controller-Driven Change
What you'll learn
- How a desired-state change is expressed as intent, not a CLI command list
- How submitting a policy change reuses the exact task/polling pattern already learned
- Why controller-driven change still needs the same lab-only mutation discipline
- How this differs from directly rendering and pushing configuration (Phase 2.9/3.0)
Listen to a guided explanation of this lesson.
Spoken narration isn't supported in this browser.
Intent, not commands
Configuration & Template Automation rendered exact CLI lines from a Jinja2 template. Ansible's ios_config sent specific configuration-mode lines. A controller task is different again: the request describes what should be true, and the controller — not the caller — decides what southbound commands actually achieve it.
desired_vlans = [{"id": 10, "name": "USERS"}]
response = requests.post(
"http://127.0.0.1:8766/tasks",
json={"device_id": "SW2", "type": "vlan_config", "desired_vlans": desired_vlans},
headers={"Authorization": "Bearer demo-token"},
timeout=2,
)
print(response.status_code, response.json())desired_vlans describes the outcome — VLAN 10 named USERS should exist. Nothing here says 'run vlan 10, then name USERS' the way Ansible's ios_config lines: did. That translation is the controller's job, on its southbound side, entirely opaque to this request.
202 {'task_id': 'task-SW2-1', 'device_id': 'SW2', 'status': 'queued'}Real, verified output — the exact same submit-then-poll pattern from Lesson 4, now carrying a real desired-state payload instead of a bare device_id/type pair.
The same workflow, not a new one
- You (or your template) specify the exact commands
- Sent to one device at a time
- Synchronous — you know the outcome from the response
- You specify the desired outcome
- One task can represent policy across many devices
- Asynchronous — poll to find out (Lesson 4's pattern, reused)
Still lab-only, still read-first
The same discipline, one more time
Every mutating example in this module runs only against the local mock controller. A real controller change follows the exact same caution "Making Configuration Changes Safely," Reliable Automation's dry-run default, Ansible's check mode, and Phase 3.1's mutation lesson all already established: read/query first, review before changing, and never treat a real controller's mutation endpoints as safe to experiment against outside a controlled lab.
Key takeaways
- A controller task describes desired outcome (intent), not exact CLI commands — the controller decides the southbound details.
- Submitting a policy/config change reuses Lesson 4's exact submit-then-poll workflow — no new mechanism, just a richer request body.
- One task can represent an intent that applies across however many devices a policy targets, unlike a single device-targeted Netmiko/Ansible/REST call.
- The same lab-only, read-first, review-before-mutating discipline from every prior module applies without exception — a controller's abstraction doesn't reduce the real risk of a real change.
Done with this lesson?
Next lesson
Desired State vs. Observed State: Controller-Driven Validation