Skip to content

Quickstart

Four commands. The first two set up the control plane, the third builds the network, the fourth populates the CMS.

Do not run this casually

make local-lab-up builds two images, pulls the whole NeOps stack and deploys 15 device containers. The SR Linux nodes alone want a few GB of RAM, and the first run takes a couple of minutes. Make sure you have been through Prerequisites.

1. Mint the CMS keypair

make lab-jwt

Writes cms/jwt/{private,public}.pem with openssl if they are not already there. The CMS mounts them read-only and refuses to start without them. Idempotent — an existing keypair is left alone.

You rarely run this directly: local-env-init depends on it.

2. Bring up the control plane

make local-env-init

This is the one-time-per-environment step. In order, it:

  1. touch cms_api_key.env — the engine’s env_file must exist before compose reads it.
  2. docker compose pull then docker compose up -d — the base stack (docker-compose.yml): CMS, workflow engine, monitor app, web client, Postgres, Elasticsearch, Redis. A wait_health service makes up -d block until CMS, engine and web client report healthy.
  3. Mints a CMS API key via manage.py generate_api_key and writes it into cms_api_key.env.
  4. Runs ./apply_cms_config — grants the neops user a full-permission role (lab-admin, default_permission=7) and configures the Global scope’s columns, drill-down and dashboard.
  5. docker compose up -d --force-recreate workflow_engineenv_file changes do not trigger a recreate on their own, so the engine is restarted to pick up the new token.

Why the CMS config is applied before the engine restart

The CMS caches each user’s accessible scopes in memory for 10 minutes. If the engine queries the CMS as neops before the grant lands, that stale (empty) cache hides the Global scope from the web client for up to ten minutes — the classic “scope not available when first used” report. Granting first means the first neops query caches the grant.

3. Build the network

make local-lab-up

The long one. It depends on build-docker, then:

  1. ./gen_clab_topology — renders generated/neops-lab.clab.json, the per-device FRR/SR Linux configs, and three of the four discovery parameter files from topology.json.
  2. docker compose up -d with the worker overlay — adds the worker and the one-shot lab_bootstrap containers and creates the lab-net bridge (172.30.0.0/24) that containerlab attaches the devices to.
  3. docker compose wait lab_bootstrap — blocks until the one-shot container that POSTs every workflows/*.yaml to the engine has exited, and propagates its exit code.
  4. containerlab deploy — the 15 devices with real point-to-point links. Deployed early on purpose: SR Linux boots slowly, so it overlaps with the waits below.
  5. ./wait_ready fb.base.neops.io/global_discover_network:0.1.0 — the worker registers its function blocks with the engine asynchronously after its container starts; this polls the engine’s per-function-block worker registry until an online worker exists.
  6. docker compose exec -T worker python3 lab/wait_devices — polls TCP 22 on every device’s management IP, from inside the lab network.

Each of those waits exists because of a real, reproduced failure. See Troubleshooting for the symptom each one prevents, and The /app/lab mount for why step 6 has a lab/ prefix that host commands do not.

When it finishes you get a banner:

Lab is up (containerlab: 10 FRR + 5 Nokia SR Linux, real links).
  Web client:   http://localhost:8080/
  Engine UI:    http://localhost:3031
  Engine API:   http://localhost:3030/
  CMS admin:    http://localhost:8001/admin/ (neops / neops)
  CMS GraphQL:  http://localhost:8001/graphql

4. Populate the CMS

make local-lab-discover

Runs the discovery workflow and waits for a terminal state. Covered in detail on the next page.

Where to look

URL What you get
http://localhost:8080/ Web client — entity browser; the devices land here after step 4
http://localhost:3031 Monitor app — workflow definitions and live execution monitoring
http://localhost:3030 Workflow engine REST API
http://localhost:8001/admin/ CMS Django admin — log in as neops / neops
http://localhost:8001/graphql CMS GraphQL API

Shutting down

make local-lab-down     # destroy the devices, stop the stack, KEEP the volumes
make local-env-prune    # docker compose down -v — the true reset, drops ES + Postgres

Full reset from scratch:

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

Next

Your first discovery