Skip to content

Make targets

The Makefile is the operator contract. Everything below exists in it today.

Lab lifecycle

Target What it does
make local-lab-up Depends on build-docker and lab-env. Generates the containerlab topology + device configs from topology.json, refreshes the worker image, brings up the base stack plus the worker and lab_bootstrap (creating lab-net), waits for workflow registration, ./containerlab deploy --reconfigures the 15 devices (re-runnable), waits for the worker’s function blocks, then waits for every device’s SSH. Refuses to run without cms_api_key.env.
make local-lab-discover Waits for the discovery function block and for device SSH, then POSTs a workflow execution and polls to a terminal state (15-minute ceiling). Override DISCOVER_PARAMS to change targeting.
make local-lab-logs docker compose logs -f worker lab_bootstrap.
make local-lab-down ./containerlab destroy --cleanup (removes the devices and generated/clab-neops-lab/), then docker compose down. Volumes survive.
make clab-suid For the CLAB_NATIVE (host binary) path: sets the SUID bit on the containerlab binary so the lab targets can deploy without sudo. Idempotent — it only prompts for a password when the bit is missing — and warns if you are not in clab_admins. Re-run after every containerlab upgrade. See Prerequisites.

The first four export COMPOSE_FILE=docker-compose.yml:docker-compose.worker.yml, so they see the worker overlay; clab-suid touches no containers, and the local-env-* targets do not get the overlay either.

Variables

Variable Default Purpose
DISCOVER_PARAMS workflow-execution-parameters/discover-params.json Which parameter file local-lab-discover sends
DISCOVER_FB fb.base.neops.io/global_discover_network:0.1.0 The function block wait_ready blocks on
CLAB_TOPO generated/neops-lab.clab.json The generated containerlab topology
CONTAINERLAB ./containerlab The containerlab launcher
CLAB_IMAGE (env) ghcr.io/srl-labs/clab:0.78.2 containerlab version the launcher runs
WAIT_READY_TIMEOUT 180 Seconds wait_ready waits for an online worker
WAIT_DEVICES_TIMEOUT 240 Seconds wait_devices waits for device SSH

These are make/environment variables (make local-lab-up WAIT_READY_TIMEOUT=600); the Makefile does not read .env — only docker compose does.

make local-lab-discover \
  DISCOVER_PARAMS=workflow-execution-parameters/discover-params-autodetect.json

Environment lifecycle

Target What it does
make doctor Host preflight (./doctor): docker + RAM, amd64 emulation on Apple Silicon, mount round-trip, subnet overlaps, the clab image, python3. Read-only apart from pulling two images; the fix is printed per failure.
make lab-jwt Mints cms/jwt/{private,public}.pem with openssl genpkey if absent. Idempotent. A prerequisite of both local-env-init and local-env-up.
make lab-env Copies .env.example to .env if there is no .env yet, so a fresh clone has one to edit. Never overwrites an existing file. Every value in the example is commented out, so it changes no behaviour on its own. A prerequisite of local-lab-up.
make local-env-init One-time per environment: pull (--policy always) + start the base stack, resolve the neops user and mint the CMS API key into cms_api_key.env (fails on an empty key), run apply_cms_config, then force-recreate the engine so it picks up the token.
make local-env-up Start the base stack again later. Fails with a clear message if cms_api_key.env is missing.
make local-env-down docker compose down — stops the base stack, keeps the volumes.
make local-env-prune docker compose down -v — the true reset; drops the Elasticsearch and Postgres volumes.
make apply-cms-config Runs ./apply_cms_config on its own. Idempotent, and worth re-running after a CMS restart (see below).

Re-run apply-cms-config after a CMS restart

The CMS image seeds a scope named Global on every startup with always_update_on_restart=True, so a restart resets its columns and filters to the image defaults. dashboard_configuration is not reset — init_scopes never writes it. Re-run make apply-cms-config to reapply the lab’s columns and drill-down.

What apply_cms_config does

It grants the neops user a full-permission role (lab-admin, default_permission=7) and configures the Global scope from the JSON files under scope/Global/ — table columns for devices, interfaces, clients and groups, a location drill-down schema, and a dashboard configuration.

It is bash, not Python, and it uses manage.py shell rather than GraphQL for the seeding steps: roleUpsert / scopesUpsert / roleScopeUpsert all gate on permissions the freshly-bootstrapped neops user does not yet have. Table columns and drill-down are written through GraphQL, deliberately last, because the CMS’s init_scopes runs on every manage.py invocation and would otherwise overwrite a shell write.

If you reorder anything in that script, read its header comment first.

Images

Target What it does
make build-docker Builds neops-lab-frr:latest from devices/frr/ and neops-lab-bootstrap:latest from bootstrap/. Local tags only — nothing is pushed. A prerequisite of local-lab-up.

See Images.

Quality gates

Target What it runs
make lint ruff format --check . then ruff check .
make format ruff format . then ruff check --fix .
make typeCheck pyrefly check
make test pytest tests — the generator unit tests + repo invariants (subnets, the Python-3.9 rule)
make py39-check Imports the host scripts under Python 3.9 (the stock macOS python3)
make shell-syntax bash -n over apply_cms_config, containerlab, doctor
make check lint typeCheck test py39-check shell-syntax — the one to run before pushing

Documentation

Contributed by the vendored mkdocs-documentation tooling in .make_scripts/mkdocs-documentation/:

Target What it does
make doc-serve Live-preview server; regenerates mkdocs.yml when mkdocs_custom.yml or mkdocs_base.yml change
make doc-build Regenerate mkdocs.yml, mkdocs build, then clean the site dir
make doc-build-docker / make doc-run-docker Build and run the docs as an NGINX image
make doc-create-mkdocs Regenerate mkdocs.yml and refresh the docs CI workflow
make doc-update-assets Pull the latest tooling release into .make_scripts/

mkdocs.yml is autogenerated — never edit it

It is produced by setup_documentation.py from this repo’s mkdocs_custom.yml deep-merged over the shared mkdocs_base.yml. Edit mkdocs_custom.yml. Note that dicts merge but lists concatenate, so re-declaring hooks: or plugins: entries that the base already has registers them twice.

Release and infrastructure

Contributed by the vendored release-management and project-infrastructure tooling:

Target What it does
make tag-patch / tag-minor / tag-major (+ -beta) Create a local annotated SemVer tag
make tag-latest-beta, make check-for-releases, make hard-reset-tags, make tag-major-minor-ruleset Tag helpers
make sync-release-assets, make sync-infrastructure-assets Re-vendor the tooling scripts (destructive by design — they rm -rf the vendored dir first)
make github-set-branch-protections, make github-set-default-branch, make github-autodelete-merged-branches Repository settings

Tagging this repo publishes nothing

neops-lab is not a distributable package — no wheel, no npm package, no registry image. make tag-* creates a local annotated tag; the separate git push --tags is what triggers downstream pipelines in repos that have them. This one has none.

Full reset

make local-lab-down local-env-prune
make local-env-init && make local-lab-up && make local-lab-discover