Architecture
Overview
Section titled “Overview”┌─────────────────────────────────────────────────────────────┐│ netsert CLI ││ Commands: run | generate | get | validate │└─────────────────┬───────────────────────────────────────────┘ │ ▼┌─────────────────────────────────────────────────────────────┐│ Runner ││ • Loads assertion files ││ • Manages concurrency (workers × parallel) ││ • Aggregates results │└─────────────────┬───────────────────────────────────────────┘ │ ▼┌─────────────────────────────────────────────────────────────┐│ gNMI Client ││ • One connection per target ││ • gRPC over TLS (or insecure for labs) │└─────────────────┬───────────────────────────────────────────┘ │ ▼┌─────────────────────────────────────────────────────────────┐│ Network Devices ││ Arista, Nokia, Juniper, Cisco (any gNMI-enabled) │└─────────────────────────────────────────────────────────────┘Code structure
Section titled “Code structure”netsert/├── cmd/netsert/│ └── main.go # CLI entry point, cobra commands├── pkg/│ ├── assertion/│ │ ├── types.go # Assertion struct, validation│ │ ├── loader.go # YAML parsing│ │ └── path.go # Short path expansion│ ├── runner/│ │ └── runner.go # Execution engine, concurrency│ ├── gnmiclient/│ │ └── client.go # gNMI connection, Get operations│ ├── generate/│ │ ├── generate.go # Generator registry│ │ ├── bgp.go # BGP generator│ │ ├── interfaces.go # Interface generator│ │ ├── ospf.go # OSPF generator│ │ ├── lldp.go # LLDP generator│ │ └── system.go # System info generator│ ├── inventory/│ │ └── inventory.go # Inventory parsing│ └── config/│ └── config.go # Config file loading└── examples/ └── lab/ # Containerlab topologyExecution flow
Section titled “Execution flow”- Load
assertions.yaml→ parse targets and assertions - Load
netsert.yaml→ get credentials, concurrency settings - Expand inventory groups (
@spines→ list of hosts) - Expand short paths (
bgp[default]/...→ full OpenConfig) - For each target (10 concurrent): connect via gNMI, run assertions (5 parallel), validate
- Aggregate results, exit 0 (pass) or 1 (fail)
Design decisions
Section titled “Design decisions”Why Go?
Section titled “Why Go?”- Single binary, no runtime dependencies
- Excellent concurrency (goroutines, channels)
- Fast startup (important for CI)
- Strong gRPC/protobuf support
Why YAML?
Section titled “Why YAML?”- Human-readable, familiar to network engineers
- Easy to generate programmatically
- Diffable in git
Why short paths?
Section titled “Why short paths?”- OpenConfig paths are verbose (100+ chars)
- Short paths preserve context (
bgp[customer-a]/...) - Leading
/bypasses expansion when needed
Why gNMI?
Section titled “Why gNMI?”- Structured data (no regex parsing)
- Fast (gRPC vs SSH)
- Vendor-neutral paths
- Real-time state
Technologies
Section titled “Technologies”| Component | Technology |
|---|---|
| Language | Go 1.22+ |
| Protocol | gNMI (gRPC-based) |
| Data models | OpenConfig YANG |
| CLI | Cobra |
| Config format | YAML v3 |
| Lab testing | Containerlab + Arista cEOS |
Quick stats
Section titled “Quick stats”| Metric | Value |
|---|---|
| Lines of code | ~2000 Go |
| Binary size | ~15MB |
| Platforms | Linux, macOS, Windows |
| License | MIT |