Data encodings (JSON, XML, YAML), Python fundamentals, REST & RESTCONF & NETCONF & gNMI, YANG data models, model-driven telemetry, Ansible & Terraform, Embedded Event Manager, and the new wave of AIOps / Cisco AI Assistant / agentic AI in networking.
6.1 Data encoding formats — JSON, XML, YAML
Every automation toolchain in the ENCOR blueprint moves structured data between a controller, a device, and a script. Three formats dominate: JSON (REST/RESTCONF bodies), XML (NETCONF payloads), and YAML (Ansible playbooks and configuration files). All three represent the same logical structure — key/value pairs, lists, and nesting — with different syntax.
Side-by-side comparison
| Aspect | JSON | XML | YAML |
|---|---|---|---|
| Full name | JavaScript Object Notation | Extensible Markup Language | YAML Ain’t Markup Language |
| Syntax marker | Braces { } + brackets [ ] |
Opening/closing tags <tag>…</tag> |
Indentation (spaces, never tabs) |
| Used by | REST, RESTCONF, gNMI, Catalyst Center Intent API | NETCONF (RFC 6241), SOAP | Ansible playbooks, Kubernetes, OpenAPI |
| Human-readable | Good | Verbose | Best |
| Comments | Not supported (standard JSON) | <!-- … --> |
# comment |
| Parser in Python | json.loads(), json.dumps() |
xml.etree.ElementTree, lxml |
yaml.safe_load() (PyYAML) |
The same interface object in three formats
{
"interface": {
"name": "GigabitEthernet0/1",
"enabled": true,
"ipv4": { "address": "10.1.1.1", "mask": "255.255.255.0" }
}
}
<!– XML (what NETCONF sends) –>
<interface>
<name>GigabitEthernet0/1</name>
<enabled>true</enabled>
<ipv4>
<address>10.1.1.1</address>
<mask>255.255.255.0</mask>
</ipv4>
</interface>
# YAML (what an Ansible var file looks like)
interface:
name: GigabitEthernet0/1
enabled: true
ipv4:
address: 10.1.1.1
mask: 255.255.255.0
<rpc> or <edit-config> that’s XML/NETCONF. If it begins with --- and uses indentation with no braces or tags, it’s YAML. Anything with { "key": is JSON.6.2 Basic Python components and scripts
ENCOR doesn’t ask you to write complex software, but you must recognize Python’s core types, read a short script, and tell what it does. You also need to know the go-to libraries for networking: requests, ncclient (NETCONF), netmiko/paramiko (SSH), and PyYAML/json.
Core data types
| Type | Syntax | Mutable? | Typical use |
|---|---|---|---|
| int / float | vlan = 10 |
Immutable | Counters, IDs |
| str | name = "Gi0/1" |
Immutable | Hostnames, interface names, CLI strings |
| bool | up = True |
Immutable | Enable/disable flags |
| list | vlans = [10, 20, 30] |
Mutable | Ordered collection (VLAN list, device list) |
| tuple | addr = ("10.1.1.1", 22) |
Immutable | Fixed pairs (IP, port) |
| dict | cfg = {"hostname":"R1"} |
Mutable | Key/value — maps directly to JSON |
| set | s = {10, 20, 30} |
Mutable | Unique unordered values |
Anatomy of a short script
url = “https://sandboxdnac.cisco.com/dna/intent/api/v1/network-device”
hdrs = {“X-Auth-Token”: token, “Content-Type”: “application/json”}
r = requests.get(url, headers=hdrs, verify=False) # 2 – HTTP GET
devices = r.json()[“response”] # 3 – parse JSON
for d in devices: # 4 – loop through list
if d[“reachabilityStatus”] == “Reachable”:
print(f“{d[‘hostname’]:<20} {d[‘managementIpAddress’]}”)
Key libraries you should recognize on the exam
- requests — synchronous HTTP client;
requests.get / post / put / delete - json — parse/serialize JSON;
json.loads(s)→ dict,json.dumps(d)→ str - ncclient — NETCONF over SSH (port 830);
manager.connect(host, …) - netmiko / paramiko — SSH/CLI automation (screen-scraping)
- PyYAML —
yaml.safe_load()to read inventory or vars files
6.3 APIs — REST / RESTCONF / NETCONF / gNMI
Protocol comparison
| Protocol | Transport / Port | Encoding | Data model | Primary use |
|---|---|---|---|---|
| REST (Catalyst Center Intent API) | HTTPS / 443 | JSON (usually) | Vendor-specific (controller) | Controller northbound API; business intent |
| RESTCONF (RFC 8040) | HTTPS / 443 | JSON or XML | YANG | Device config/state over HTTPS |
| NETCONF (RFC 6241) | SSH / 830 | XML only | YANG | Transactional device config (candidate / running / startup) |
| gNMI | gRPC over HTTP/2 / 57400 (typical) | Protocol Buffers (Protobuf) | OpenConfig YANG | High-performance config + streaming telemetry |
REST verbs & CRUD mapping
| HTTP verb | CRUD operation | Idempotent? | Example (Catalyst Center) |
|---|---|---|---|
| GET | Read | Yes | GET /dna/intent/api/v1/network-device |
| POST | Create | No | POST /dna/system/api/v1/auth/token |
| PUT | Replace (full update) | Yes | PUT /dna/intent/api/v1/global-credential |
| PATCH | Modify (partial update) | No (generally) | PATCH /dna/intent/api/v1/network |
| DELETE | Remove | Yes | DELETE /dna/intent/api/v1/site/{id} |
HTTP status codes to memorize
- 200 OK — request succeeded, body returned
- 201 Created — POST created a new resource
- 202 Accepted — Catalyst Center asynchronous task accepted (poll the task ID)
- 204 No Content — success, no body
- 400 Bad Request — malformed JSON/body
- 401 Unauthorized — missing or expired token
- 403 Forbidden — authenticated but no permission
- 404 Not Found — URI does not exist
- 429 Too Many Requests — rate-limited
- 500 Internal Server Error — server fault
Catalyst Center Intent API auth flow
user:pass) only to obtain the token. Every subsequent request uses X-Auth-Token header — basic auth is never sent again. Token lifetime defaults to 1 hour.6.4 YANG data models & model-driven telemetry
YANG (Yet Another Next Generation, RFC 7950) is the schema language that defines what data a device can expose or accept. NETCONF, RESTCONF, and gNMI all use YANG models — the protocols are just the transport.
YANG model flavors
| Flavor | Authored by | Scope | Examples |
|---|---|---|---|
| Native | Vendor (e.g. Cisco IOS XE) | Everything the platform can do (including proprietary) | Cisco-IOS-XE-native |
| OpenConfig | Vendor-neutral industry group | Common features across vendors (great for multi-vendor) | openconfig-interfaces |
| IETF standard | IETF RFCs | Baseline features standardized across the industry | ietf-interfaces, ietf-routing |
Within any model, nodes are classified as configuration (writable, used with <edit-config>) or operational/state (read-only, used for telemetry and show-style queries).
Model-Driven Telemetry (MDT)
Instead of SNMP pull, MDT is push: the device streams YANG-modeled data to a collector. Two subscription types:
| Mode | When data is sent | Use case |
|---|---|---|
| Periodic (cadence-based) | Every N centiseconds, regardless of change | Interface counters, CPU/memory utilization trending |
| On-change | Only when a monitored value changes | Link state transitions, BGP neighbor state, LLDP |
The default Cisco encoding for dial-out gRPC telemetry is KVGPB (Key-Value Google Protocol Buffers). Other options include compact GPB and JSON.
6.5 Configuration management — Ansible & Terraform
Ansible — the de-facto network config tool
- Agentless — the control node pushes changes over SSH or network-CLI; no software installed on the device.
- Declarative playbooks written in YAML.
- Inventory file lists target hosts and variables.
- Modules do the work; for Cisco IOS the main ones are
cisco.ios.ios_config,cisco.ios.ios_command,cisco.ios.ios_facts. - Idempotent by task — a second run produces no change if the device already matches the desired state (assuming the module supports it).
[routers]
R1 ansible_host=10.1.1.1
R2 ansible_host=10.1.1.2
[routers:vars]
ansible_connection=network_cli
ansible_network_os=cisco.ios.ios
ansible_user=admin
ansible_password=Cisco123!
# playbook.yml
– name: Configure loopback on routers
hosts: routers
gather_facts: no
tasks:
– name: Create Loopback100
cisco.ios.ios_config:
lines:
– ip address 192.168.100.1 255.255.255.0
parents: interface Loopback100
Terraform vs Ansible — when to use which
| Aspect | Terraform | Ansible |
|---|---|---|
| Primary role | Infrastructure provisioning (create/destroy) | Configuration management (ongoing state) |
| Language | HCL (HashiCorp Configuration Language) — declarative | YAML playbooks — declarative |
| State | Yes — persistent state file tracks resources | Stateless — re-reads device each run |
| Idempotency | Native (compares desired vs current state) | Per-module (most network modules are idempotent) |
| Agent | Agentless | Agentless (SSH/network-CLI) |
| Network example | Spin up a virtual firewall in AWS / Azure; allocate IPs | Push VLAN/ACL/interface config to the firewall after provisioning |
6.6 Embedded Event Manager (EEM)
EEM is an on-device automation engine in Cisco IOS / IOS-XE / IOS-XR / NX-OS. No controller, no Python host — the router reacts to its own events. Two building blocks:
- Event detector — what to watch for (syslog pattern, SNMP trap, timer, CLI match, interface counter, routing change, etc.).
- Action — what to do (run CLI commands, send syslog, send mail, run a TCL/Python policy).
Two forms: applets (simple inline CLI configuration) and scripts (TCL or Python files registered as policies).
Applet skeleton
R1(config-applet)# event syslog pattern “.*Interface GigabitEthernet0/1, changed state to down”
R1(config-applet)# action 1.0 syslog msg “Gi0/1 went down — attempting recovery”
R1(config-applet)# action 2.0 cli command “enable”
R1(config-applet)# action 3.0 cli command “configure terminal”
R1(config-applet)# action 4.0 cli command “interface Gi0/1”
R1(config-applet)# action 5.0 cli command “shutdown”
R1(config-applet)# action 6.0 cli command “no shutdown”
R1(config-applet)# action 7.0 mail server “10.1.1.50” to “[email protected]“ from “[email protected]“ subject “Gi0/1 bounce” body “Auto-recovery triggered”
event per applet, but many action lines ordered by the numeric label (1.0, 2.0, …). Use action … cli command "enable" before any privileged command and event manager session cli username … if TACACS/AAA is enforced.Common event detectors
| Detector | Example event |
|---|---|
| syslog | Regex match against console/log messages |
| snmp | OID crosses a threshold |
| timer cron / watchdog | Fires at a scheduled time or periodically |
| cli | Runs when a specific CLI command is entered |
| none | Manually triggered (test / on-demand) |
| routing | BGP/OSPF route added or removed |
6.7 AI / ML in networking — AIOps, Cisco AI Assistant, agentic AI
Version 1.2 of the ENCOR blueprint formally added AI as an exam topic. You need to recognize three layers of AI in enterprise networking: traditional ML-driven AIOps, generative AI assistants, and the emerging agentic AI / MCP ecosystem.
Layer 1 — AIOps in Cisco Catalyst Center
- AI Network Analytics — ML baselines per-site & per-SSID (not a fixed threshold). Detects anomalies when current metrics deviate from the learned baseline.
- Predictive analytics — forecasts capacity, radio issues, client experience trends before they become incidents.
- Machine Reasoning Engine (MRE) — encodes Cisco TAC troubleshooting logic; automates root-cause analysis during ticket resolution.
- AI Endpoint Analytics — ML-based endpoint classification (device type/OS) even for unknown or unmanaged clients.
Layer 2 — Cisco AI Assistant (generative AI)
- Natural-language copilot embedded in Catalyst Center, Meraki dashboard, and ThousandEyes.
- Ask questions in plain English (“why is Floor-3 slow?”), get summarized issues with proposed next-step remediation.
- Generates config snippets, explains CLI output, summarizes security policies.
- Accelerates L1/L2 troubleshooting by turning unstructured telemetry into prescriptive guidance.
Layer 3 — Agentic AI & Model Context Protocol (MCP)
Agentic AI systems don’t just answer — they take actions across tools on your behalf, with human-in-the-loop approval at key steps. MCP (Model Context Protocol) is the emerging open standard that lets an LLM/agent discover and call external tools (Catalyst Center API, ServiceNow, Grafana, Jira) through a uniform client/server interface.
- Gartner (2026 outlook): by 2029, 70% of enterprises will deploy agentic AI as part of IT infrastructure operations, up from <5% in 2025.
- I&O’s interaction model is shifting from “scripts and CLI” to prompt engineering + policy definition + workflow orchestration.
- Typical enterprise pattern: MCP gateway fronts many MCP servers; agents reach tools through it with auth, rate-limiting, and audit.
AI in networking — summary map
| Layer | What it is | Where it lives | Automation style |
|---|---|---|---|
| AIOps / ML | Baselines, anomaly detection, predictive analytics, MRE | Catalyst Center Assurance, ThousandEyes | Reactive + predictive insights |
| GenAI assistants | Natural-language copilots, summarization, config generation | AI Assistant in Catalyst Center / Meraki / ThousandEyes | Conversational troubleshooting |
| Agentic AI / MCP | Multi-step autonomous workflows across tools | MCP servers + AI gateway (Cisco & partners) | Goal-driven, human-approved actions |
Hands-on labs (6)
R1(config)# aaa new-model
R1(config)# aaa authentication login default local
R1(config)# aaa authorization exec default local
R1(config)# username netauto privilege 15 secret Cisco123!
R1(config)# ! NETCONF over SSH/830
R1(config)# netconf-yang
R1(config)# ! RESTCONF over HTTPS/443
R1(config)# ip http secure-server
R1(config)# restconf
R1# show netconf-yang sessions
R1# show platform software yang-management process
! From a client host:
$ curl -k -u netauto:Cisco123! https://R1/restconf/data/Cisco-IOS-XE-native:native/hostname \
-H “Accept: application/yang-data+json”
from requests.auth import HTTPBasicAuth
requests.packages.urllib3.disable_warnings()
DNAC = “https://sandboxdnac.cisco.com”
USER, PASS = “devnetuser”, “Cisco123!”
# 1. Acquire token (Basic Auth -> X-Auth-Token)
tok = requests.post(f“{DNAC}/dna/system/api/v1/auth/token”,
auth=HTTPBasicAuth(USER, PASS), verify=False).json()[“Token”]
# 2. Call Intent API with the token
hdr = {“X-Auth-Token”: tok, “Content-Type”: “application/json”}
r = requests.get(f“{DNAC}/dna/intent/api/v1/network-device”,
headers=hdr, verify=False)
for d in r.json()[“response”]:
print(f“{d[‘hostname’]:<22} {d[‘managementIpAddress’]:<16} {d[‘reachabilityStatus’]}”)
[access]
SW1 ansible_host=10.0.0.11
SW2 ansible_host=10.0.0.12
[access:vars]
ansible_connection=network_cli
ansible_network_os=cisco.ios.ios
ansible_user=admin
ansible_password=Cisco123!
# vlans.yml
– name: Ensure VLANs 10 and 20 exist
hosts: access
gather_facts: no
tasks:
– name: Create VLANs
cisco.ios.ios_vlans:
config:
– { vlan_id: 10, name: USERS, state: active }
– { vlan_id: 20, name: VOICE, state: active }
state: merged
– name: Configure access port Gi0/1
cisco.ios.ios_config:
parents: interface GigabitEthernet0/1
lines:
– switchport mode access
– switchport access vlan 10
– switchport voice vlan 20
# Run: ansible-playbook -i inventory.ini vlans.yml
cfg = “””
<config>
<native xmlns=”http://cisco.com/ns/yang/Cisco-IOS-XE-native”>
<interface>
<Loopback>
<name>200</name>
<description>Automated loopback via NETCONF</description>
<ip><address><primary>
<address>10.200.200.1</address>
<mask>255.255.255.0</mask>
</primary></address></ip>
</Loopback>
</interface>
</native>
</config>”””
with manager.connect(host=“R1”, port=830,
username=“netauto”, password=“Cisco123!”,
hostkey_verify=False) as m:
r = m.edit_config(target=“running”, config=cfg)
print(r)
R1(config-applet)# event syslog pattern “%SYS-5-CONFIG_I”
R1(config-applet)# action 1.0 cli command “enable”
R1(config-applet)# action 2.0 cli command “write memory”
R1(config-applet)# action 3.0 syslog msg “Running-config saved automatically by EEM”
! Test
R1(config)# interface loopback 9
R1(config-if)# ip address 9.9.9.9 255.255.255.255
R1(config-if)# exit
R1(config)# exit
*Apr 19 12:00:05.123: %HA_EM-6-LOG: AUTO_SAVE: Running-config saved automatically by EEM
R1(config)# telemetry ietf subscription 101
R1(config-mdt-subs)# encoding encode-kvgpb
R1(config-mdt-subs)# filter xpath /interfaces-ios-xe-oper:interfaces/interface/statistics
R1(config-mdt-subs)# stream yang-push
R1(config-mdt-subs)# update-policy periodic 3000 ! 30 seconds (unit = centiseconds)
R1(config-mdt-subs)# receiver ip address 10.10.10.20 57500 protocol grpc-tcp
R1(config-mdt-subs)# exit
R1(config)# ! On-change subscription for interface oper-state
R1(config)# telemetry ietf subscription 102
R1(config-mdt-subs)# encoding encode-kvgpb
R1(config-mdt-subs)# filter xpath /interfaces-ios-xe-oper:interfaces/interface/oper-status
R1(config-mdt-subs)# stream yang-push
R1(config-mdt-subs)# update-policy on-change
R1(config-mdt-subs)# receiver ip address 10.10.10.20 57500 protocol grpc-tcp
R1# show telemetry ietf subscription all
R1# show telemetry ietf subscription 101 receiver
Check Your Understanding
Twenty questions on this section. Each answer is explained as you go.
