Skip to content

Dashboard API Reference

Base URL: http://192.168.56.13:31880

The OpenAPI description is GET /api/v1/openapi.json, for any logged-in user.

Authentication

Every route requires a Keycloak access token for the dashboard realm client:

Authorization: Bearer <access token>

Reads need the dashboard-viewer or dashboard-admin role, writes need dashboard-admin. Three routes answer without a token: /health, /api/v1/cluster/info and /api/v1/apps/public. The backend refuses to start with any other route that has no role. See security/iam.md for the full matrix. In the tables below, "—" means any logged-in role.


Health

Method Path Auth Description
GET /health — Backend liveness check

Pods & Deployments (Control Room)

Method Path Auth Description
GET /api/v1/pods — List pods. Query: ?namespace=5g
GET /api/v1/pods/{pod}/describe — Describe a pod. Query: ?namespace=5g
POST /api/v1/deployments/{deployment}/restart ✅ Admin Rolling restart a deployment. Query: ?namespace=5g

ConfigMaps

Method Path Auth Description
GET /api/v1/configmaps/{name} — Read a ConfigMap. Query: ?namespace=5g
PUT /api/v1/configmaps/{name} ✅ Admin Update a ConfigMap. Requires DASHBOARD_ALLOW_CONFIGMAP_WRITE=true

Topology Map

Method Path Auth Description
GET /api/v1/topology — Pod nodes + OVS bridges with Multus interface metadata. Query: ?namespace=5g
GET /api/v1/network/nads — List NetworkAttachmentDefinitions. Query: ?namespace=5g
GET /api/v1/ovs/bridges/{bridge}/flows — OVS OpenFlow rules for a bridge (from ovs-ofctl dump-flows)

Subscriber Management

Method Path Auth Description
GET /api/v1/subscribers — List all Open5GS subscriber records
POST /api/v1/subscribers ✅ Admin Create a subscriber. Body: subscriber object
PUT /api/v1/subscribers/{imsi} ✅ Admin Update a subscriber
DELETE /api/v1/subscribers/{imsi} ✅ Admin Delete a subscriber
POST /api/v1/subscribers/init ✅ Admin Trigger Ansible subscriber import (reset to defaults)

UE Monitoring

Method Path Auth Description
GET /api/v1/ue/summary — Prometheus-backed gauges: gNBs, RAN UEs, PDU sessions, registration counts
GET /api/v1/ue/events — Log-parsed UE events. Query: ?minutes=10
GET /api/v1/ue/active — Active UE list reconstructed from AMF/SMF logs
GET /api/v1/ue/pods — UERANSIM UE pod list
POST /api/v1/ue/test/ping ✅ Admin Run ping from a UE pod. Body: {pod, namespace, target_ip}
POST /api/v1/ue/test/iperf ✅ Admin Run iperf3 from a UE pod. Body: {pod, namespace, target_ip, duration}

Metrics

Method Path Auth Description
GET /api/v1/metrics/nodes — Node-level CPU, memory, disk from Prometheus/Node Exporter
GET /api/v1/metrics/nf — Per-NF CPU, memory, restart counts

RAN

Admin only (reads included). Attach and detach are pieces: POST /api/v1/pieces/ran_attach/run and POST /api/v1/pieces/ran_detach/run (see Pieces and operations).

Method Path Auth Description
GET /api/v1/ran/status ✅ Admin The physical RAN's state: the worker's RAN interface and its link, br-ran and its ports, the RAN network attachment, the AMF's RAN interface, the UPF's route back, the gNB (address, NG Setup, NGAP port), UE and PDU counts, and chain, the five links the RAN page shows (serving, broken with the first broken link and its fix, or detached)
GET /api/v1/ran/modes/status ✅ Admin The same for the physical RAN, plus the UERANSIM workloads, for the RAN page
POST /api/v1/ran/modes/ueransim/enable, .../disable ✅ Admin UERANSIM on or off. Not offered by the page: the phase that installs it is not maintained
GET, POST, PATCH, DELETE /api/v1/ran/ueransim/... ✅ Admin UERANSIM gNBs and UEs (status, defaults, forms, create, change, activate, delete)

Network Health

Method Path Auth Description
GET /api/v1/network/health — N-interface connectivity results (N2/N3/N4/N6): the last run when it is younger than 25 s, otherwise a new run
POST /api/v1/network/health/run — Run the checks now

Status

Method Path Auth Description
GET /api/v1/status/summary — Overall state for the header: state (ok, warn, error) and problems (area, text, severity). Sources: nodes not Ready; 5G pods Failed, Pending, Running but not ready, or stuck (CrashLoopBackOff, image pull errors); the last network check run if younger than 10 min, with its age (never starts one); the AMF CNI alert. A source that cannot be read is a warn problem; an unreachable Kubernetes API is the single error problem

Pieces and operations

Admin only. A piece is a named part of a phase playbook (ansible/pieces.yml), run by the runner on the ansible VM; see contributing.md.

Method Path Auth Description
GET /api/v1/pieces ✅ Admin The registry: per piece title, tier (change or disrupt), changes, stops, takes_s
POST /api/v1/pieces/{name}/run ✅ Admin Start a piece. Returns {id, state}; a piece already running returns the running one's id. 404 for an unknown piece
GET /api/v1/operations ✅ Admin The 50 newest runs' records, ?state= to filter (running, done, failed, interrupted). Each has reads_back (its piece has a read-back); a stored failed read-back is returned as failed
GET /api/v1/operations/retention ✅ Admin The record's limits and what it holds: max_age_days, max_mb, runs, bytes, oldest
PUT /api/v1/operations/retention ✅ Admin Set the limits. Body {max_age_days, max_mb}, days 1 to 3650, MB 1 to 10240: 400 for a number outside them, 422 for a value that is not a whole number. Returns the same shape as GET. Audit-logged
GET /api/v1/operations/{id} ✅ Admin One run: steps, the tail of its log, and its read-back (check), made once within 600 s of the end; a failed read-back makes the state failed. 404 for an unknown id

Isolation

Method Path Auth Description
GET /api/v1/isolation/planes — Plane filter counters per rule over ?window= (default 24h, max 7d): mode, planes, every pair with verdict and packets, drops outside the planes
GET /api/v1/isolation/planes/samples — Latest packets the filter logged on the worker, per rule (?limit=, default 5), last 24 h
GET /api/v1/isolation/policies — Per isolated namespace: role, allowed sources per app, egress limits, policy names; unlisted namespaces; common sources
GET /api/v1/isolation/targets — Sources and destinations (Services with ports) for the flow check
POST /api/v1/isolation/check — Evaluate a flow on the live NetworkPolicies without sending it. Body: {"source": "mec", "destination": {"namespace": "5g", "service": "mongodb", "port": 27017}} or {"destination": {"internet": true}}

Northbound (positioning / CAMARA)

Method Path Auth Description
GET /api/v1/northbound/services — Inventory of the camara/positioning/mec deployments (image, ready replicas, pods)
GET /api/v1/northbound/adapters — Live adapter registry from the engine (GET /adapters via the API-server service proxy): per adapter kind, registered_via, last_seen_s_ago, and derived state (live/unreachable/stale)
GET /api/v1/northbound/contract — Adapter contract guidance: Measurement schema, Python skeleton, env.contract.yaml template, doc links
GET /api/v1/northbound/contract/{service} — Live per-service contract fetched from the service's own /contract (kind, external_origin var, required/recommended/optional env). Degrades to {available: false} when the service exposes none
GET /api/v1/northbound/config/{service} — Guided-setup read: the contract plus current state (non-sensitive values; sensitive reported set/unset only, never the value)
PUT /api/v1/northbound/config/{service} ✅ Admin Guided-setup apply. Body: {values: {VAR: value}}. Routes each var by the contract sensitive flag (Secret vs ConfigMap, both via envFrom), then rolls the deployment
DELETE /api/v1/northbound/adapters/{name} ✅ Admin Force-remove a stale registry entry (engine DELETE /adapters/{name}). Adapters self-register, so there is no manual register endpoint
POST /api/v1/northbound/deploy ✅ Admin Deploy a custom adapter image. Requires DASHBOARD_ALLOW_WORKLOAD_CREATE=true. Body: {name, image, port, env[], image_pull_secret?, kind?}. The backend injects the self-registration env so the adapter announces itself to the engine
DELETE /api/v1/northbound/workloads/{name} ✅ Admin Delete a deploy-from-image adapter (Deployment, Service, Secret) and unregister it
GET /api/v1/northbound/assets ✅ Admin Asset Identity Map from the gateway (GET /assets); Bearer forwarded
PUT /api/v1/northbound/assets ✅ Admin Replace the Asset Map (PUT /assets); Bearer forwarded. The engine broadcasts each device from its adapter's capability, so onboarded assets go live without a track-list sync
GET /api/v1/northbound/assets/discoverable ✅ Admin Gateway discoverable candidates (not yet onboarded)
GET /api/v1/northbound/assets/{asset_id}/details ✅ Admin Gateway per-asset details

Edge apps (phase 12)

Operator-deployed application pods in the mec namespace; the local registry lives in the registry namespace. See architecture/edge-apps.md.

Method Path Auth Description
GET /api/v1/apps — Inventory of deployed apps (name, image, replicas, ready, exposed, public URL kelt-<name>.<base>, mec_attached, mec_ip, pods for log streaming)
GET /api/v1/apps/public — Unauthenticated (no token even in auth mode): names + public URLs of exposed apps, for the front-door welcome page
GET /api/v1/apps/updates — Per app: whether the registry digest for its tag is newer than the running pod's
POST /api/v1/apps ✅ Admin Deploy an app. Requires DASHBOARD_ALLOW_WORKLOAD_CREATE=true. Body: {name, image, port?, replicas?, env[], image_pull_secret?, expose?, attach_mec?, mec_ip?, udp_ports[]}. Creates a Deployment (+ Service on port 80 when exposed) pinned to the worker; attach_mec adds an N6m interface (n6m-net, or n6m-static when mec_ip is set) so UEs reach it over the user plane
PUT /api/v1/apps/{name}/image ✅ Admin Retarget a deployed app to a chosen registry tag (date-ordered picker), preserving its other settings. Body: {image}. Requires DASHBOARD_ALLOW_WORKLOAD_CREATE=true
DELETE /api/v1/apps/{name} ✅ Admin Delete an app (Deployment, Service, config ConfigMap/Secret)
GET /api/v1/apps/registry-credentials ✅ Admin Local-registry host + basic-auth credentials, so an admin can docker login and push
GET /api/v1/apps/registry/images ✅ Admin Repos and tags in the local registry, each tag with its build timestamp (newest first)
GET /api/v1/apps/starter-kit ✅ Admin Zip (README + .env.example + deploy.sh) prefilled with the registry host, for an app developer
POST /api/v1/apps/provision ✅ Admin Deploy the platform from the UI (phases 12 + 11), streaming progress as NDJSON
GET /api/v1/apps/gnb/console — gNB management console state (configured, origin host:port, public URL)
PUT /api/v1/apps/gnb/console ✅ Admin Expose the gNB web UI at kelt-gnb.<base>. Body: {host, port?}. Registers a selectorless Service+Endpoints gnb reached via the dynamic apps route. Requires DASHBOARD_ALLOW_WORKLOAD_CREATE=true
DELETE /api/v1/apps/gnb/console ✅ Admin Remove the gNB console Service+Endpoints

Storage

Node disk usage and the reclaim actions. Sizes are measured by walking the filesystem, so they are cached; the filesystem totals are always live. See modules.md.

Method Path Auth Description
GET /api/v1/storage — Worker disk breakdown: filesystem totals, containerd image layers vs blobs, persistent volumes (total and per claim, with namespace), the in-cluster registry as a subset of those, and journald. ?refresh=true re-walks instead of using the cache
GET /api/v1/storage/preview — Estimated saving per reclaim action: unused image count and bytes, and how far journald sits over its cap. Estimates, not promises: shared image layers are counted once per image, so the real saving is usually a little lower
POST /api/v1/storage/prune-images ✅ Admin Remove image layers no container references. Returns bytes freed and free space after
POST /api/v1/storage/vacuum-journal ✅ Admin Trim systemd journals to the 500M cap phase 01 configures
POST /api/v1/storage/registry-gc ✅ Admin Garbage-collect unreferenced blobs in the in-cluster registry. ?dry_run=true (default) reports what would go, with the total size of those blobs, without touching the store

IAM

Convenience endpoint behind the Identity & Access settings page. See iam.md.

Method Path Auth Description
GET /api/v1/iam/master-admin-password ✅ Admin Reveal the Keycloak master admin password (read from .testbed.secrets). Read-only: this credential is automation-owned and auto-generated, surfaced only so an operator can sign in to the master console without opening the host file. Audit-logged
GET /api/v1/iam/client-secret/{client_id} ✅ Admin Reveal the client secret of a seeded M2M client (camara-gateway, camara-api-demo, dashboard-readonly), read from .testbed.secrets on the host. Admin-only despite being a GET; every reveal is audit-logged. Returns found: false when the key is not in the file (the realm then holds its changeme default)
POST /api/v1/iam/client-secret/{client_id}/rotate ✅ Admin Rotate that client's secret: generates a random value, writes .testbed.secrets first (the source of truth), then converges Keycloak; for camara-gateway also patches the gateway pod env and rolls it. Audit-logged; returns the new secret. On a half-failure the file already holds the new value and kelt run-phase 08-iam (or rotating again) converges Keycloak to it. See iam.md "Secret rotation"

WebSocket Endpoints

WebSocket connections are made to the same host on port 31880.

Log streaming

WS /api/v1/ws/logs/{namespace}/{pod}?container=<name>

Streams live container logs. Equivalent to kubectl logs -f. The server closes the connection when the pod disappears or the client disconnects.

Messages (server → client): JSON {line: "...", timestamp: "..."} per log line.

Traffic intensity

WS /api/v1/ws/traffic/intensity

Streams real-time OVS bridge counter deltas every second.

Messages (server → client):

{
  "bridges": {
    "br-n2": {"rx_packets": 42, "tx_packets": 38, "rx_bytes": 5400, "tx_bytes": 4800},
    "br-n3": {"rx_packets": 120, ...},
    ...
  },
  "timestamp": "2026-03-11T10:00:01Z"
}


Planned / Stubbed

Method Path Description
POST /api/v1/experiments/run Run a test scenario
POST /api/v1/snapshot/create Create a testbed state snapshot