ank_pydantic
Phase 59/62 (100%)
The Insight
Network topology modeling typically forces a choice between the speed of untyped graph libraries (NetworkX) and the rigidity of database-backed sources of truth. ank-pydantic eliminates this trade-off by using Pydantic for schema validation and a high-performance Rust core (petgraph) for graph traversals.
Quick Facts
| Status | Phase 59/62 (100%) |
| Language | N/A |
| Started | 2026 |
What This Is
A Python library for modeling and querying network topologies with type-safe Pydantic models and a high-performance Rust core. Expressive Python API backed by blazing-fast graph algorithms, with automatic configuration generation for multi-vendor network deployments.
Key Features
- Two-Stage Transformation Model: Whiteboard (sketch) → Plan (logical) → Protocol Layers (physical)
- Type-Safe Models: Pydantic validation ensures correct topology structure at design time
- Lazy Query API: Composable queries with Rust-backed execution (powered by
petgraph) - Configuration Generation: Automatic multi-vendor config generation (Cisco IOS/IOS-XR/NX-OS, Juniper JunOS, Arista EOS)
- Batteries-Included Blueprints: Pre-built domain models for ISIS, MPLS, EVPN, L3VPN, IXP
- Rust Core (
ank_nte): Graph operations run at native speed with Python FFI bindings
Examples
Service Provider Core: IS-IS + MPLS + iBGP
Input Topology (transitnet.yaml):
topology:
- metadata:
name: TransitNet SP Core
organisation: TransitNet
asn: 65000
- nodes:
- P1:
role: core
data:
pop: West
platform: iosxr
loopback: 10.0.0.1/32
endpoints:
- Gi0/0/0/0 # to P3
- Gi0/0/0/1 # to P5
- Gi0/0/0/2 # to PE1
- P3:
role: core
data:
pop: East
platform: iosxr
loopback: 10.0.0.3/32
endpoints:
- Gi0/0/0/0 # to P1
- Gi0/0/0/2 # to PE3
- PE1:
role: pe
data:
pop: West
platform: iosxr
loopback: 10.0.0.11/32
endpoints:
- Gi0/0/0/0 # to P1
- links:
- [P1, Gi0/0/0/0, P3, Gi0/0/0/0] # West-East core
- [P1, Gi0/0/0/2, PE1, Gi0/0/0/0] # Core-PE
Build Protocol Layers:
from ank_pydantic import Topology
from ank_pydantic.blueprints.designs.isis import build_isis_layer
from ank_pydantic.blueprints.designs.mpls import build_mpls_layer
# ank_pydantic
topology = Topology.from_yaml("transitnet.yaml")
# ank_pydantic
isis_layer = build_isis_layer(
topology,
level=2,
area="49.0001",
parent_layer="physical"
)
# ank_pydantic
mpls_layer = build_mpls_layer(
topology,
igp_layer="isis",
layer_name="mpls"
)
Generated Configuration (P1 - Cisco IOS-XR):
hostname P1
!
interface Loopback0
ipv4 address 10.0.0.1 255.255.255.255
!
interface GigabitEthernet0/0/0/0
description to P3
ipv4 address 10.1.0.1 255.255.255.252
!
interface GigabitEthernet0/0/0/2
description to PE1
ipv4 address 10.1.0.5 255.255.255.252
!
router isis CORE
is-type level-2-only
net 49.0001.0100.0000.0001.00
address-family ipv4 unicast
metric-style wide
!
interface Loopback0
passive
address-family ipv4 unicast
!
interface GigabitEthernet0/0/0/0
point-to-point
address-family ipv4 unicast
metric 10
!
!
interface GigabitEthernet0/0/0/2
point-to-point
address-family ipv4 unicast
metric 10
!
!
!
mpls ldp
router-id 10.0.0.1
interface GigabitEthernet0/0/0/0
!
interface GigabitEthernet0/0/0/2
!
!
L3VPN Configuration
Input: Add customer sites to PE routers:
# ank_pydantic
- nodes:
- CE1:
role: ce
data:
organisation: NetCorp
asn: 65100
loopback: 192.168.1.1/32
endpoints:
- Gi0/0
- CE2:
role: ce
data:
organisation: NetCorp
asn: 65100
loopback: 192.168.2.1/32
endpoints:
- Gi0/0
- links:
- [PE1, Gi0/0/0/1, CE1, Gi0/0] # PE-CE link
- [PE3, Gi0/0/0/1, CE2, Gi0/0] # PE-CE link
Build L3VPN Layer:
from ank_pydantic.blueprints.designs.l3vpn import build_l3vpn_layer
# ank_pydantic
l3vpn_layer = build_l3vpn_layer(
topology,
service_name="NetCorp-L3VPN",
customer="NetCorp",
customer_asn=65100,
provider_asn=65000,
vpn_id=100
)
Generated VRF Configuration (PE1):
vrf NETCORP
address-family ipv4 unicast
import route-target
65000:100
!
export route-target
65000:100
!
!
!
interface GigabitEthernet0/0/0/1
description to CE1 (NetCorp)
vrf NETCORP
ipv4 address 10.100.1.1 255.255.255.252
!
router bgp 65000
vrf NETCORP
rd 65000:100
address-family ipv4 unicast
redistribute connected
!
neighbor 10.100.1.2
remote-as 65100
description CE1
address-family ipv4 unicast
route-policy NETCORP-IN in
route-policy NETCORP-OUT out
!
!
!
!
Containerlab Deployment
Export to Containerlab:
from ank_pydantic.blueprints.environments import get_environment
# ank_pydantic
env = get_environment('containerlab')
# ank_pydantic
artifacts = env.generate(topology)
# ank_pydantic
with open("transitnet.clab.yml", "w") as f:
f.write(artifacts.files['topology.clab.yml'])
Generated Containerlab File (transitnet.clab.yml):
name: transitnet
mgmt:
network: mgmt
ipv4-subnet: 172.20.20.0/24
topology:
nodes:
P1:
kind: cisco_xrv9k
image: vrnetlab/vr-xrv9k:7.3.2
mgmt-ipv4: 172.20.20.11
binds:
- ./configs/P1.cfg:/config/startup-config.cfg
P3:
kind: cisco_xrv9k
image: vrnetlab/vr-xrv9k:7.3.2
mgmt-ipv4: 172.20.20.13
binds:
- ./configs/P3.cfg:/config/startup-config.cfg
PE1:
kind: cisco_xrv9k
image: vrnetlab/vr-xrv9k:7.3.2
mgmt-ipv4: 172.20.20.21
binds:
- ./configs/PE1.cfg:/config/startup-config.cfg
links:
- endpoints: ["P1:Gi0/0/0/0", "P3:Gi0/0/0/0"]
- endpoints: ["P1:Gi0/0/0/2", "PE1:Gi0/0/0/0"]
Deploy and Verify:
# ank_pydantic
sudo containerlab deploy -t transitnet.clab.yml
# ank_pydantic
sudo containerlab inspect -t transitnet.clab.yml
# ank_pydantic
# ank_pydantic
# ank_pydantic
# ank_pydantic
# ank_pydantic
# ank_pydantic
# ank_pydantic
# ank_pydantic
docker exec -it clab-transitnet-P1 show isis neighbors
# ank_pydantic
# ank_pydantic
# ank_pydantic
# ank_pydantic
# ank_pydantic
# ank_pydantic
docker exec -it clab-transitnet-P1 show mpls ldp neighbor
# ank_pydantic
# ank_pydantic
# ank_pydantic
# ank_pydantic
# ank_pydantic
# ank_pydantic
# ank_pydantic
Query API Usage
Composable queries with Rust-backed execution:
# ank_pydantic
core_routers = topology.query.nodes().where(
lambda n: n.data.role == "core" and n.data.pop == "North"
).models()
# ank_pydantic
inter_pop_links = topology.query.links().where(
lambda l: l.data.link_type == "long-haul"
).count()
# ank_pydantic
mpls_devices = topology.layer("mpls").nodes().where(
mpls_enabled=True
).ids()
Integration with NetVis
Export for visualization:
# ank_pydantic
topology.export_for_netvis(
"output.json",
layout="hierarchical",
node_metadata=True
)
NetVis applies advanced layout algorithms to produce publication-quality diagrams.
YAML Topology Format
Define topologies in YAML for rapid prototyping:
topology:
- metadata:
name: TransitNet SP Core
organisation: TransitNet
asn: 65000
- nodes:
- P1:
role: core
data:
pop: West
platform: iosxr
loopback: 10.0.0.1/32
endpoints:
- Gi0/0/0/0 # to P3
- Gi0/0/0/1 # to P5
- PE1:
role: pe
data:
pop: West
platform: iosxr
loopback: 10.0.0.11/32
endpoints:
- Gi0/0/0/0 # to P1
- Gi0/0/0/1 # customer-facing
- links:
- [P1, Gi0/0/0/0, P3, Gi0/0/0/0] # West-East
- [P1, Gi0/0/0/1, P5, Gi0/0/0/0] # West-North
- [P1, Gi0/0/0/2, PE1, Gi0/0/0/0] # Core-PE
Load and process:
topology = Topology.from_yaml("transitnet.yaml")
# ank_pydantic
isis_layer = build_isis_layer(topology, level=2, area="49.0001")
mpls_layer = build_mpls_layer(topology, igp_layer="isis")
# ank_pydantic
env = get_environment('containerlab')
artifacts = env.generate(topology)
Available Blueprints
Pre-built design functions for common network patterns:
| Blueprint | Purpose | Key Features |
|---|---|---|
| IS-IS | IGP routing | Multi-level (L1, L2, L1/L2), area assignment, NET generation |
| MPLS/LDP | Label switching | Follows IGP adjacencies, label range configuration, targeted LDP |
| L3VPN | VPN services | VRF configuration, RD/RT generation, PE-CE sessions |
| EVPN | L2/L3 overlay | VXLAN, MAC/IP routes, multi-tenancy |
| IXP | Peering fabric | Route server, bilateral peering, BGP communities |
| Data Center | Spine-leaf | CLOS topology, ECMP, BGP unnumbered |
Each blueprint provides:
- Layer builder functions for protocol derivation
- Pydantic models for type-safe configuration
- Query helpers for network analysis
- Config templates for multi-vendor export
Current Status
Feature-complete, final polish and documentation before 1.0 release.
Tech Stack
Python (Pydantic), Rust core (petgraph-backed), PyO3 bindings
| ← Back to Network Automation | ← Back to Projects |