Skip to content

Your first discovery

One command turns 15 running containers into 15 Device entities with their Interface rows.

Run it

make local-lab-discover

The target does three things:

  1. ./wait_ready fb.base.neops.io/global_discover_network:0.1.0 — confirm an online worker is registered for the discovery function block.
  2. docker compose exec -T worker python3 lab/wait_devices — confirm every device in topology.json accepts SSH.
  3. ./run_workflow --timeout 900 wf.lab.neops.io/simple_lab_discovery:1.2.0 @workflow-execution-parameters/discover-params.json

run_workflow POSTs to /workflow-execution, prints the execution UUID, then polls until the execution reaches a terminal state:

execution 4f2c…-…-…
  [  2s] running
  [ 41s] completed_ack

Its exit code is meaningful: 0 for completed_ack, 1 for failed_safe_ack / failed_unsafe_ack, 2 if the workflow could not be started or polling timed out.

Why the 15-minute timeout

run_workflow’s own default is 300s. Discovering 15 devices — SSH plus fact and interface collection across 10 FRR and 5 slower Nokia SR Linux nodes — legitimately exceeds it, so the make target passes --timeout 900. Autodetection adds an SSH probe per host, and the same ceiling covers that too.

Watch it happen

Open the monitor app at http://localhost:3031 while it runs — the execution appears with its step state and any failure reason. Then open the web client at http://localhost:8080/ and browse to the device list: 15 rows, vendor=FRRouting for the 10 routers and vendor=Nokia for the 5 switches, each with its interfaces recorded.

The discovery function block records the device and its interfaces in one pass: it connects via the matching connection plugin, reads facts plus interfaces, and writes both Device and Interface rows to the CMS. Interface descriptions encode the neighbour (leaf-01:e1/1 -> spine-01:e1/1), and connected ports come up UP, because the links are real veths — not simulated state.

Re-running discovery duplicates interfaces

Devices are keyed by IP, so a second run skips existing devices. Interfaces are always recorded, so a second run against the same CMS adds a second set of interface rows. Run discovery against a fresh CMS (make local-env-prunemake local-env-init) when the interface counts matter.

Targeting discovery differently

make local-lab-discover takes a DISCOVER_PARAMS override, so the same workflow can be pointed at four different shapes of input:

15 /32 subnets with a known platform, and credentials scoped to that platform — so no host is ever tried with the other vendor’s login.

make local-lab-discover
workflow-execution-parameters/discover-params.json
{
  "subnets": [
    { "cidr": "172.30.0.11/32", "platform": "frr" },
    { "cidr": "172.30.0.12/32", "platform": "frr" },
    { "cidr": "172.30.0.13/32", "platform": "frr" },
    { "cidr": "172.30.0.14/32", "platform": "frr" },
    { "cidr": "172.30.0.15/32", "platform": "frr" },
    { "cidr": "172.30.0.16/32", "platform": "frr" },
    { "cidr": "172.30.0.17/32", "platform": "frr" },
    { "cidr": "172.30.0.18/32", "platform": "frr" },
    { "cidr": "172.30.0.19/32", "platform": "frr" },
    { "cidr": "172.30.0.20/32", "platform": "frr" },
    { "cidr": "172.30.0.31/32", "platform": "srl" },
    { "cidr": "172.30.0.32/32", "platform": "srl" },
    { "cidr": "172.30.0.33/32", "platform": "srl" },
    { "cidr": "172.30.0.34/32", "platform": "srl" },
    { "cidr": "172.30.0.35/32", "platform": "srl" }
  ],
  "credentials": [
    { "username": "frr", "password": "frr", "platform": "frr" },
    { "username": "admin", "password": "NokiaSrl1!", "platform": "srl" }
  ]
}

The same /32s with platform left out, so discovery has to detect it — what a real greenfield scan looks like.

make local-lab-discover \
  DISCOVER_PARAMS=workflow-execution-parameters/discover-params-autodetect.json
workflow-execution-parameters/discover-params-autodetect.json
{
  "subnets": [
    { "cidr": "172.30.0.11/32" },
    { "cidr": "172.30.0.12/32" },
    { "cidr": "172.30.0.13/32" },
    { "cidr": "172.30.0.14/32" },
    { "cidr": "172.30.0.15/32" },
    { "cidr": "172.30.0.16/32" },
    { "cidr": "172.30.0.17/32" },
    { "cidr": "172.30.0.18/32" },
    { "cidr": "172.30.0.19/32" },
    { "cidr": "172.30.0.20/32" },
    { "cidr": "172.30.0.31/32" },
    { "cidr": "172.30.0.32/32" },
    { "cidr": "172.30.0.33/32" },
    { "cidr": "172.30.0.34/32" },
    { "cidr": "172.30.0.35/32" }
  ],
  "credentials": [
    { "username": "frr", "password": "frr" },
    { "username": "admin", "password": "NokiaSrl1!" }
  ]
}

One target for the whole management /24, with subnet-scoped credentials. Discovery expands the prefix and probes every address.

make local-lab-discover \
  DISCOVER_PARAMS=workflow-execution-parameters/discover-params-subnet.json
workflow-execution-parameters/discover-params-subnet.json
{
  "subnets": [
    {
      "cidr": "172.30.0.0/24",
      "credentials": [
        {
          "username": "frr",
          "password": "frr"
        },
        {
          "username": "admin",
          "password": "NokiaSrl1!"
        }
      ]
    }
  ]
}

The /24 plus /32 overrides for the SR Linux nodes — exercises longest-prefix-match credential selection.

make local-lab-discover \
  DISCOVER_PARAMS=workflow-execution-parameters/discover-params-mixed.json
workflow-execution-parameters/discover-params-mixed.json
{
  "subnets": [
    {
      "cidr": "172.30.0.0/24",
      "credentials": [
        {
          "username": "frr",
          "password": "frr"
        }
      ]
    },
    { "cidr": "172.30.0.31/32", "platform": "srl", "credentials": [{ "username": "admin", "password": "NokiaSrl1!" }] },
    { "cidr": "172.30.0.32/32", "platform": "srl", "credentials": [{ "username": "admin", "password": "NokiaSrl1!" }] },
    { "cidr": "172.30.0.33/32", "credentials": [{ "username": "admin", "password": "NokiaSrl1!" }] },
    { "cidr": "172.30.0.34/32", "credentials": [{ "username": "admin", "password": "NokiaSrl1!" }] },
    { "cidr": "172.30.0.35/32", "credentials": [{ "username": "admin", "password": "NokiaSrl1!" }] }
  ]
}

The precedence rules behind these — longest prefix wins, credentials scoped from most to least specific — are explained in Discovery.

wait_devices always waits for the known devices

Even when you point discovery at the /24, the readiness poll uses topology.json, not the parameter file. A subnet target also contains unused addresses, and waiting on those would always time out.

Running a workflow by hand

run_workflow is a general-purpose host script, not discovery-specific:

# Parameters from a file (curl-style "@file")
./run_workflow wf.lab.neops.io/simple_lab_discovery:1.2.0 \
  @workflow-execution-parameters/discover-params.json

# Inline JSON
./run_workflow wf.lab.neops.io/simple_lab_discovery:1.2.0 '{"subnets": []}'

# From stdin
echo '{"subnets": []}' | ./run_workflow wf.lab.neops.io/simple_lab_discovery:1.2.0 -

--ids 12,34 fills executeOnParameters.ids for entity-scoped workflows; --engine-url, --timeout and --interval are also available (./run_workflow --help).

Next

  • Discovery — the workflow, the function block and the parameter contract.
  • Troubleshooting — if the run failed, start with the error string.