Route Mechanicsnetwork engineering

// field notes · automation

From config to intent: why automation matters

Replaying CLI through a script isn't automation. Model the service, validate the inputs, generate the config, then prove the network matches.

The first automation most network teams build is a script that logs into a box and pastes commands. It’s useful, and it’s a start, but it isn’t the destination. It automates the typing, not the engineering.

A workshop manual doesn’t tell you which spanner to turn and in what order. It gives you the torque figure and the clearance. That’s the spec, and it’s what you check your work against. Intent-based automation works the same way.

Four layers

1. Model the service

Describe what you want in data, not in vendor syntax:

# services/customer-acme.yaml
customer: acme
vlan: 2140
sites:
  - device: leaf3
    interface: et-0/0/12
  - device: leaf7
    interface: et-0/0/12
bgp:
  asn: 64512
  prefixes: [198.51.100.0/24]

2. Validate the inputs

Before anything touches a device, check the request makes sense. Pydantic does most of the heavy lifting:

from ipaddress import IPv4Network
from pydantic import BaseModel, Field, field_validator


class Site(BaseModel):
    device: str
    interface: str = Field(pattern=r"^(et|xe|ge)-\d+/\d+/\d+$")


class Service(BaseModel):
    customer: str
    vlan: int = Field(ge=2, le=4094)
    sites: list[Site] = Field(min_length=1)
    prefixes: list[IPv4Network]

    @field_validator("prefixes")
    @classmethod
    def no_bogons(cls, v: list[IPv4Network]) -> list[IPv4Network]:
        for net in v:
            if net.is_private or net.prefixlen > 24:
                raise ValueError(f"{net} is not an acceptable customer prefix")
        return v

Half of all outages caused by change are caught here, cheaply, by a computer, before a change window.

3. Render the config

Templates turn the model into vendor syntax. Keep the logic in Python and the templates dumb. If a Jinja template has more if than text, the model is wrong.

4. Verify the state

This is the step that’s usually missing. After the change, read the network back (operational state, not config) and compare it with the intent:

  • Is the VLAN present on both leaves?
  • Is the BGP session Established?
  • Is the customer prefix received and active?

If you can’t verify it, you haven’t automated it. You’ve only made it faster to get wrong.

Why it matters

  • Repeatable: the same input always produces the same network.
  • Reviewable: a pull request on a YAML file is something a human can actually read.
  • Observable: drift between intent and state becomes an alert, not a surprise.

Automate the spec, not the spanner.