alembic-engine 0.5.0

Planning, apply, and state engine for Alembic.
Documentation

alembic

the connective tissue of your network automation layer, co-evolved with ai

alembic is a data-model-first converger + loader for dcim/ipam systems. it defines a canonical, vendor-neutral ir (intermediate representation) and an engine that validates, plans, and applies changes to a backend. it supports multiple backend adapters, including NetBox, Nautobot, Infrahub, generic REST APIs, and PeeringDB (read-only).

when not to use alembic

alembic is built to converge a vendor-neutral data model onto one or more dcim/ipam backends, and to migrate between them. it is probably the wrong tool when:

  • you have a single backend and a simple one-off load. a pynetbox script or csv import is less machinery for the same result.
  • your infrastructure is ephemeral or event-driven. alembic reconciles batches against a known desired state; it is not an event processor or a real-time sync daemon.
  • you need built-in approval, rbac, or audit workflows. alembic is a cli that emits deterministic plans; wrap it in your own ci/review process, or use a platform that bundles those.

how it compares

most tools manage the boxes in your infrastructure graph: the state inside a single system. alembic works on the edges, the correspondence between systems. it transforms data from a source of truth into a vendor-neutral model, validates it, and converges that model onto one or more backends. each alternative below owns a box; alembic connects them:

  • terraform + netbox provider: covers the apply segment for a single backend, with hand-written hcl resources. alembic builds the desired state by transforming your source of truth into the ir, then applies it to multiple backends from that one model.
  • nautobot ssot / netbox diode: cover ingestion into one system. alembic does the same source-to-infra load, but through a backend-neutral model with an explicit plan/diff, and can target several backends from it.
  • infrahub native sync: infrahub is itself a source of truth with its own transform/sync into infrahub. alembic keeps the canonical model outside any single backend, so infrahub is one destination among several.
  • ansible (netbox.netbox collection): connects source data to a backend imperatively, task by task. alembic covers the same path with a typed ir, schema validation, and a deterministic create/update/delete plan.
  • pynetbox / custom scripts: the same source-to-infra glue, hand-rolled. alembic provides the transformation, validation, stable uids across renames, and reproducible plans so you do not rebuild that each time.

concepts

  • ir objects: typed objects with stable uid (uuid), a type, a human key, and attrs.
  • relationships: references are always by uid, never backend ids.
  • plan: a deterministic list of operations (create/update/delete) generated by diffing desired ir against observed backend state.
  • state store: maps uid to backend ids (integers or uuids) per type to keep renames stable; defaults to .alembic/state.json and can use postgres.

quickstart

  1. create an inventory file (yaml) describing your desired state. see examples/inventory.yaml.

  2. validate:

cargo run -p alembic-cli -- validate -f examples/inventory.yaml
  1. plan (writes a json plan file):
# netbox
NETBOX_URL=https://netbox.example.com NETBOX_TOKEN=... \
  cargo run -p alembic-cli -- plan --backend netbox -f examples/inventory.yaml -o plan.json

# nautobot
NAUTOBOT_URL=https://nautobot.example.com NAUTOBOT_TOKEN=... \
  cargo run -p alembic-cli -- plan --backend nautobot -f examples/inventory.yaml -o plan.json

# infrahub
INFRAHUB_URL=https://infrahub.example.com INFRAHUB_TOKEN=... \
  cargo run -p alembic-cli -- plan --backend infrahub -f examples/inventory.yaml -o plan.json
  1. apply:
NETBOX_URL=https://netbox.example.com NETBOX_TOKEN=... \
  cargo run -p alembic-cli -- apply --backend netbox -p plan.json --allow-delete
  1. optional: generate a django app from an inventory:
cargo run -p alembic-cli -- cast django -f examples/inventory.yaml -o ./out \
  --project alembic_project --app alembic_app

adapter coverage

netbox and nautobot adapters are schema-driven and resolve types dynamically via their content type/object type APIs. the infrahub adapter uses graphql and can optionally provision missing types/fields by generating an infrahub schema file and applying it during apply.

  • any type with a REST endpoint can be observed and applied
  • attrs are passed through using backend field names
  • ref/list_ref fields are resolved via state mappings during apply
  • custom fields and tags are mapped by adapters when supported by the backend
  • netbox custom object types can be provisioned on apply when the netbox custom objects plugin is installed

relationships are validated strictly by schema and uid references.

workspace layout

  • crates/alembic-core: ir types, serde, validation primitives
  • crates/alembic-engine: loader, graph validation, planning, state store
  • crates/alembic-adapter-registry: adapter config + registry for the cli
  • crates/alembic-adapter-netbox: netbox adapter
  • crates/alembic-adapter-nautobot: nautobot adapter
  • crates/alembic-adapter-infrahub: infrahub graphql adapter
  • crates/alembic-adapter-generic: generic rest adapter
  • crates/alembic-adapter-peeringdb: peeringdb adapter
  • crates/alembic-cli: cli binary

notes

  • input files never contain backend ids.
  • plans are deterministic and stable-sorted.
  • deletes are gated behind --allow-delete.

beyond the open core

the dcim/ipam and generic-rest adapters here are the open core. the same ir drives config and deployment across live and lab fabrics, plus monitoring, dns, and access, through a separate, commercial ops layer.

documentation

  • docs/index.md
  • docs/ir.md
  • docs/inventory.md
  • docs/map.md
  • docs/engine.md
  • docs/plan.md
  • docs/state.md
  • docs/cli.md
  • docs/cast.md
  • docs/netbox.md
  • docs/nautobot.md
  • docs/infrahub.md
  • docs/external-adapters.md
  • docs/development.md
  • docs/case-studies/