Skip to content

Neops Remote Lab

A FastAPI service exposing exclusive, queue-brokered access to a real Netlab topology — drive it from a pytest11 plugin (Python), the bundled REST API (any stack), or both.

neops-remote-lab fronts a Netlab host with a small HTTP service and a pytest fixture. Every consumer asks for a session, waits in a FIFO queue, gets the lab, and tears it down when the last consumer walks away. Topologies are identified by their SHA-256 content hash, so byte-identical files share the running lab — and FRR, Nokia SR Linux, and Cisco IOL all work out of the box.

uv add neops-remote-lab
poetry add neops-remote-lab
pip install neops-remote-lab

On PyPI · Source · Worker SDK uses it as a stable contract

Pick your path

  •   Worker SDK developers


    A real Netlab device for your function-block tests.

    • Install + REMOTE_LAB_URL — two steps, then the Worker SDK testing guide takes over
    • Multi-vendor topology patterns (FRR, Nokia SR Linux, Cisco IOL)
    • The pytest fixture the Worker SDK imports as a stable API

    Plug into Worker SDK

  •   Operators


    Run the service on a shared host.

    • 30-second foreground launch + /healthz sanity check
    • Pick the deployment shape — laptop, VM, multi-tenant, or CI runner pool
    • systemd unit, stale-lock recovery, stuck-lab cleanup runbook

    Run the service

  •   Contributors


    Change the codebase safely.

    • The 30-minute path to your first PR
    • Eight invariants every change must preserve
    • Internals deep-dives (async, locking, atexit, test stubbing) and an anti-patterns grep target for review

    Contribute

  •   External API users


    Drive the lab from any HTTP-capable stack.

    • Six cURL calls end-to-end — no Python required
    • Full REST contract with per-endpoint examples
    • Wire into GitHub Actions, GitLab CI, or Jenkins

    Drive from cURL

Session-and-lab lifecycle

Every test follows the same four-step lifecycle: create a session (which joins the queue), wait to become active, upload a topology and acquire the lab, then release on teardown. Client B waits behind Client A without ever touching a lock.

sequenceDiagram
    participant ClientA as Client A (pytest)
    participant ClientB as Client B (CI job)
    participant Server as FastAPI server
    participant Manager as LabManager
    participant Netlab

    ClientA->>Server: POST /session
    Server-->>ClientA: 201 session_id (ACTIVE)

    ClientB->>Server: POST /session
    Server-->>ClientB: 201 session_id (WAITING, position=1)

    ClientA->>Server: POST /lab (topology.yml)
    Server->>Manager: try_acquire(topo, reuse=True)
    Manager->>Netlab: netlab up topology.yml
    Netlab-->>Manager: nodes
    Server-->>ClientA: 200 lab acquired

    loop heartbeat every <300s
        ClientA->>Server: POST /session/heartbeat
    end

    ClientB->>Server: GET /session/{id}
    Server-->>ClientB: status=WAITING, position=1

    ClientA->>Server: DELETE /session/{id}
    Server->>Manager: release() ref--
    Note over Server: teardown, promote next

    Server-->>ClientB: (next poll) status=ACTIVE, position=0

FIFO queue → exclusive access → shared teardown when the last user leaves. The promotion rules, stale-session timeouts, and heartbeat cadence live in Session Queue; SHA-256-keyed reuse counting in Lab Lifecycle.

Where it sits in the neops ecosystem

neops-remote-lab is the test substrate for the wider neops platform. The Worker SDK imports remote_lab_fixture directly. If you’re new to neops, How Remote Lab fits with neops maps the surrounding pieces; if you’re not on neops at all, this section is safely skippable.

No HTTP authentication

neops-remote-lab ships without bearer-token, OAuth, or mTLS authentication. The only access boundary on /lab/* is the X-Session-ID of an ACTIVE session. Deploy behind a VPN. See Security model for the full posture.

Reading paths

Pick the route that matches your current question.

New to the project — you want your first passing test

QuickstartPytest FixturesTopology Format. Install, three-line test, see it pass.

Concepts first — you want to understand before you build

ArchitectureSession QueueLab LifecycleTopology Format. Every invariant the system enforces and why.

Standing up the host — you are deploying the service

Netlab host setupHeadscale quick startOperator runbookConfiguration. Install Netlab, enclose the host in a private tailnet, configure and operate the server.

Wiring in a new client — you are integrating a consumer

REST APIPython ClientPytest Fixtures. The API reference is authoritative; the Python client is a thin wrapper; the fixture is the stable consumer surface.

Driving from a non-Python stack — you are integrating into an existing harness

REST quickstartCI quickstartDebugging. Stand up a session and a lab end-to-end with cURL, then wire it into your CI runner of choice.

Looking for runnable examples

Cookbook. Pytest, Python (no-pytest), cURL, topology, and deployment recipes — every link goes to GitHub so the recipe survives docs-site rebuilds.

External references