Skip to main content

FastAPI-based Remote Lab Manager for Netlab topologies to enable remote testing of Neops Function Blocks against virtual networking labs

Project description

Neops Remote Lab

PyPI Python CI Docs Status: developer preview

[!IMPORTANT] Developer Preview Disclaimer

This repository is an early-stage developer preview and is not production-ready. While we are currently finalizing an open-source friendly license, all rights are reserved in the interim. We encourage you to explore the code, experiment with it, and share your feedback via issues or discussions. Use of this software is at your own risk and provided "as-is" without warranty.

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.

On PyPI · Docs · Worker SDK consumes it as a stable contract

Install

For the Python client / pytest fixture (library install) — pick whichever your project uses:

uv add neops-remote-lab        # uv (recommended)
poetry add neops-remote-lab    # Poetry
pip install neops-remote-lab   # pip

For the runnable server CLI (isolated install):

uv tool install neops-remote-lab   # uv (recommended)
pipx install neops-remote-lab      # pipx

Picking between the two? Library install is what most consumers want — it gives you the pytest fixture and RemoteLabClient. CLI install is for operators standing up the server itself.

Quick start

Use it (consumer)

export REMOTE_LAB_URL=http://lab.example.com:8000
from neops_remote_lab.testing.fixture import remote_lab_fixture

demo = remote_lab_fixture("tests/topologies/demo.yml")
def test_lab_has_two_devices(demo):
    assert len(demo) == 2
pytest -v

The fixture handles session creation, queue waiting, topology upload, heartbeat, and teardown. The Worker SDK imports remote_lab_fixture directly as a stable public API.

Run it (operator)

neops-remote-lab            # binds 0.0.0.0:8000 by default
curl -s -o /dev/null -w "%{http_code}\n" http://localhost:8000/healthz
# 204 = alive

netlab must be on PATH — the launcher refuses to start otherwise. For a fresh host, see Netlab host setup; for a systemd-managed deployment, see the Operator runbook.

How a session flows

sequenceDiagram
    participant ClientA as Client A
    participant ClientB as Client B
    participant Server

    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)
    Note over Server: acquire lab (netlab up)
    Server-->>ClientA: 200 lab acquired

    loop heartbeat (until release)
        ClientA->>Server: POST /session/heartbeat
        Server-->>ClientA: 204
    end

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

    ClientA->>Server: DELETE /session/{id}
    Note over Server: tear down lab, promote next in queue
    Server-->>ClientA: 204

    ClientB->>Server: GET /session/{id}
    Server-->>ClientB: status=ACTIVE, position=0

The full state machine, heartbeat cadence, and timeout semantics live on Session queue; SHA-256-keyed reuse semantics on Lab lifecycle.

Why use it

  • One lab per host, enforced. Cross-process filelock + reference counting; two clients can't trample each other's topology. Topology identity is the SHA-256 of file content, so byte-identical files share a running lab.
  • Stable Python contract. remote_lab_fixture is the public surface the Worker SDK imports directly.
  • Driveable from any HTTP stack. pytest is convenient; cURL works; Go works; whatever you already have works.
  • Operator-friendly. Single-instance systemd unit, structured logs, /healthz and /debug/health, automatic recovery from stale Netlab instances on startup.

Environment variables

Variable Purpose Default
REMOTE_LAB_URL Base URL for client + fixtures — (required)
REMOTE_LAB_REQUEST_TIMEOUT Per-HTTP-request timeout (seconds) 30
REMOTE_LAB_SESSION_TIMEOUT Client-side session-queue wait limit (seconds) 600
REMOTE_LAB_ACQUISITION_TIMEOUT Max wait for lab acquisition (seconds) 600

Timeout-coordination guidance + RemoteLabClient constructor overrides: Client config.

Network access

The service ships without HTTP authentication — the only access boundary on /lab/* is the X-Session-ID of an active session. Treat it as internal-trust; deploy behind a network enclosure. The recommended path is self-hosted Headscale + Headplane because that's what the project's reference deployment uses, but any equivalent enclosure works (managed Tailscale, plain WireGuard, an internal VLAN with IP allowlists, mTLS at a reverse proxy). Walkthroughs and alternatives: Headscale: quick setup and its Other approaches section.

Troubleshooting

Symptom Likely cause + fix
Server exits with Another Remote Lab Manager instance is already running. Stale single-instance filelock from a crashed prior run. See Stale-lock recovery.
Address already in use on port 8000 Prior server didn't exit cleanly, or another service holds the port. lsof -i :8000 and kill, or start with --port.
POST /lab returns 423 Locked Caller's session isn't ACTIVE, or a different topology owns the host. GET /session/{id} to check; release / force-destroy if stuck.

Full table: Debugging.

Documentation

The full docs are at docs.neops.io/neops-remote-lab. Common entry points:

  • Use from Python — pytest fixtures, RemoteLabClient, client config.
  • Run the service — install, systemd, security model, REST contract, debugging.
  • Deploy & Operate — Netlab host setup, VPN paths, vendor walkthroughs (FRR / SR Linux / IOL).
  • Concepts — architecture, session queue, lab lifecycle, topology format.
  • Cookbook — runnable end-to-end recipes.

Interactive OpenAPI UI is at http://<host>:8000/docs once the server is running.

Tests

make test                     # 39 tests; uses a stubbed LabManager (no Netlab needed)

Contributing

Branch from develop. make check runs lint, typecheck, audit, and tests. Full contributor guide: Contributing.

License

See the Developer Preview Disclaimer at the top of this file. A formal open-source license will be applied once finalized.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

neops_remote_lab-1.4.0.tar.gz (25.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

neops_remote_lab-1.4.0-py3-none-any.whl (30.4 kB view details)

Uploaded Python 3

File details

Details for the file neops_remote_lab-1.4.0.tar.gz.

File metadata

  • Download URL: neops_remote_lab-1.4.0.tar.gz
  • Upload date:
  • Size: 25.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.8 {"installer":{"name":"uv","version":"0.11.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for neops_remote_lab-1.4.0.tar.gz
Algorithm Hash digest
SHA256 b0c5a55ecf9f00808054d57fac497a839f55b925e1b15c3ccdc5f25e02a12dc4
MD5 7f368784cf4bb39599e63ac731585bdb
BLAKE2b-256 b2f6f16f2e2954b4181d3150a483b4cb516c19399688fc7ad8b9f73f9b29a00c

See more details on using hashes here.

File details

Details for the file neops_remote_lab-1.4.0-py3-none-any.whl.

File metadata

  • Download URL: neops_remote_lab-1.4.0-py3-none-any.whl
  • Upload date:
  • Size: 30.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.8 {"installer":{"name":"uv","version":"0.11.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for neops_remote_lab-1.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 9ad4cd5a0183a0819f1f7cfa4a3fc769e27b59dfcd32abbec952f155d3583ad1
MD5 9f1109421840bd717d5fcb210532f86d
BLAKE2b-256 8fa5b69fe0f9f73fde4e410d3e4b89d0746b038d64b529211ee968bd7ab19ebc

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page