Skip to content

Latest commit

 

History

262 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Argus

Test Backend Test pingsvc

A network device monitoring system. It continuously pings devices, tracks up/down state in Redis, and streams live status changes to clients over WebSockets — deployable either as a single stack, or split across independent zones (e.g. one per building or site) that each run their own local monitoring and push aggregated, signed status snapshots to a central dashboard.

This document covers what Argus is and how to get a single stack running (via Compose or Docker Swarm). For local development workflows (including the full multi-zone client/server walkthrough) see development.md; for production deployment see deployment.md.

Architecture

flowchart TB
    subgraph Zone["argus-client — one per zone/site"]
        Devices[("network devices")]
        Pingsvc["pingsvc (Go)<br/>role=both"]
        ZRedis[("Redis")]
        ZBackend["backend (FastAPI)"]
        WS(["WebSocket clients<br/>/ws/pings"])
        Spool[("local spool<br/>signed snapshots")]

        Devices -- ICMP --> Pingsvc
        Pingsvc -- "state change<br/>(Lua, atomic)" --> ZRedis
        ZRedis -- "pub/sub" --> ZBackend
        ZBackend --> WS
        Pingsvc -- "every 30s" --> Spool
    end

    Spool -- "push (Ed25519-signed)" --> S3[("S3-compatible<br/>object storage")]

    subgraph Server["argus-server — central"]
        SBackend["backend (FastAPI)<br/>ingestion_task"]
        SPostgres[("PostgreSQL<br/>ClientSnapshot / ZoneSummary")]
        API(["GET /api/v1/zones/summary"])

        SBackend -- "verify signature<br/>& upsert" --> SPostgres
        SPostgres --> API
    end

    S3 -- "poll" --> SBackend
Loading

A single-zone deployment is just an argus-client with nothing configured to push anywhere — that's what the Quick Start below sets up. Splitting into zones + a central server only requires setting a handful of environment variables (see development.md for a fully worked local example, or deployment.md for production).

Services

Service Description
backend FastAPI REST API + WebSocket server (Python). Runs as either an argus-client's local API or the central argus-server's ingestion + dashboard API, depending on whether S3_BUCKET is configured.
pingsvc Concurrent ICMP ping daemon (Go). Its -role flag (pingsvc / exporter / both) determines whether it just pings, just exports/pushes snapshots, or both — both is what makes a deployment an argus-client.
db PostgreSQL 16 database
redis Pub/sub message bus between pingsvc and backend, local to each zone
frontend React + Vite + TypeScript operator dashboard. Runs in Docker (dev target, hot reload) or locally via npm -- see Quick Start below.

Quick Start

Prerequisites: Docker and Docker Compose.

# 1. Copy and configure environment
cp .env.example .env          # then edit .env with your secrets

# 2. Bring up the right stack for this machine's role
./scripts/run.sh client       # a zone: backend + redis + pingsvc + frontend
# ./scripts/run.sh server     # central argus-server: backend + frontend only

scripts/run.sh client generates pingsvc/targets.txt automatically if it doesn't exist yet. server mode never starts redis/pingsvc at all (a central argus-server has no local devices to ping) -- see Environment Variables for what ROLE controls, and note that tearing a client stack back down needs the same profile flag: docker compose --profile client down.

Note (Apple Silicon): The Dockerfiles are multi-platform and build natively for ARM64. No extra flags needed.

Local URLs once running:

The first run may take a minute while the backend waits for PostgreSQL and runs migrations. Log in with FIRST_SUPERUSER/FIRST_SUPERUSER_PASSWORD from your .env (defaults from .env.example: admin@example.com / changethis).

client mode brings up a single zone with nothing configured to export anywhere — the ping pipeline, Redis, REST API, and WebSocket stream all work exactly as a single-stack deployment. To see the full multi-zone argus-client → object storage → argus-server pipeline running end-to-end in your own terminal, see development.md.

To exercise device discovery (SNMP infra polling, plan/device-discovery-v1.md) without real network hardware, add --with-mock-lan:

./scripts/run.sh client --with-mock-lan

This joins a small fixture environment (three ICMP-only "devices" plus an snmpsim mock router) onto pingsvc's own network as part of the same stack — no extra setup for the fixture itself. Discovery does need pingsvc's backend connection turned on first though (ARGUS_BACKEND_URL/PINGSVC_SYNC_TOKEN in .env — off by default, same as target hot-reload); see the full walkthrough in development.md for that one-time step, adding the Infrastructure Target, and reviewing what discovery finds on the Discovered Devices page. Standalone usage (without the rest of the app stack) is still available via scripts/mock-lan/{up,down,smoke-test}.sh — see compose.mock-lan.yml's header comment.

Prefer to skip scripts/run.sh and run the underlying docker compose commands yourself? See development.md's Docker Compose basics.

Docker Swarm Quick Start

An alternative to the Quick Start above: run argus-server and one or more argus-client zones as independent Docker Swarm stacks behind one shared Traefik — closer to how staging/production are actually topology-separated, and lets you run multiple zones side by side locally. Can't run at the same time as the Compose stack above (they share ports 80/8090, and traefik-public needs a different network driver in each).

docker compose --profile client down   # if the Compose stack above is running
./scripts/swarm/dev-setup.sh           # swarm init, Traefik + MinIO, build images, argus-server-1 + argus-client-1

Local URLs once running:

Add another zone with ARGUS_SWARM_DEV=1 ARGUS_SCHEME=http ./scripts/swarm/deploy.sh client 2; tear everything down with ./scripts/swarm/teardown-dev.sh. See swarm/README.md for the full picture — the edit/rebuild/redeploy dev loop (there's no hot reload here, unlike Compose above) and how to verify the client → MinIO → server pipeline end to end.

Environment Variables

All config is in .env (root); .env.example documents every variable, including the optional multi-zone client/server settings. Key ones to know:

Variable Description
POSTGRES_SERVER PostgreSQL host (default: db)
POSTGRES_PASSWORD PostgreSQL password
POSTGRES_DB Database name (default: argus)
REDIS_URL Redis connection URL
SECRET_KEY JWT signing key — change before deploying
FIRST_SUPERUSER Admin email created on first startup
FIRST_SUPERUSER_PASSWORD Admin password — change before deploying
ENVIRONMENT local / staging / production
ROLE Backend role: client (default, a zone's local API + ping pipeline) / server (central argus-server, no local devices). Set automatically by scripts/run.sh client|server.
ARGUS_ROLE pingsvc's role: pingsvc (ping only, default) / exporter / both (full argus-client)
S3_BUCKET Set on the backend to enable argus-server ingestion; unset = plain zone backend

Generate a secure secret key:

python -c "import secrets; print(secrets.token_urlsafe(32))"

How It Works

pingsvc (Go) concurrently ICMPs all devices in a worker pool. On a state change (up→down or down→up), it runs a Lua script in Redis that atomically updates the device's state, increments per-node/room/building counters, and publishes a JSON event to pings:events (or scoped node/room/building channels). With -role=both (or ARGUS_ROLE=both), it also runs an independent exporter goroutine that periodically builds a signed, gzipped snapshot of the current aggregate state and pushes it to S3-compatible object storage.

The backend subscribes to Redis on startup and fans incoming events out to all connected WebSocket clients at /ws/pings. The current snapshot of all device states is also queryable via REST at /state and /state_scan. If S3_BUCKET is configured, the backend additionally runs a background ingestion task that polls that bucket, verifies each snapshot's signature against a registered per-zone key, and upserts the results into ClientSnapshot/ZoneSummary — queryable at GET /api/v1/zones/summary, including a computed is_stale flag for zones that have stopped pushing.

Devices can additionally be organized into an arbitrary-depth, per-tenant hierarchy (Node/NodeType, /api/v1/nodes, /api/v1/node-types, /api/v1/devices) instead of a flat target list — see hierarchy.md for the full walkthrough: defining the shape (hierarchy.yaml or the frontend), creating Nodes, assigning devices, and pushing that assignment into pingsvc's target file.

Frontend

The dashboard (frontend/) is a Vite app. scripts/run.sh/docker compose runs it in a container by default (frontend/Dockerfile's dev target: hot reload, source bind-mounted from the host), or run it locally with npm instead:

cd frontend
npm install
npm run dev      # dev server at http://localhost:5173, proxies /api to :8000
npm test         # vitest
npm run build    # tsc --build + production build
npm run lint     # oxlint

It expects a running backend (via docker compose, see Quick Start) to talk to -- there's no mock/offline mode. frontend/Dockerfile also has a prod target (multi-stage build served by nginx, proxying /api to the backend service) for non-dev deployments.

Database Migrations

Migrations run automatically on startup via the prestart service. To create a new migration manually:

cd backend
alembic revision --autogenerate -m "describe the change"
alembic upgrade head

CI/CD

Every push/PR runs two independent GitHub Actions workflows: Test Backend (pytest) and Test pingsvc (go vet + go test).

Push to mainDeploy to Staging (gated on both test workflows passing for that commit). Publish a GitHub release → Deploy to Production. See deployment.md for the full Traefik setup, multi-zone production configuration, and required GitHub secrets.

Connecting to Running Services

bash scripts/db-connect.sh       # PostgreSQL shell inside the db container
bash scripts/backend-connect.sh  # bash shell inside the backend container
bash scripts/redis-connect.sh    # redis-cli inside the redis container
bash scripts/pingsvc-connect.sh  # sh inside the pingsvc container

Pass a Swarm stack name to target that zone/server instead of the Compose stack — e.g. bash scripts/db-connect.sh argus-client-2 (see swarm/README.md).

To subscribe to live ping events:

bash scripts/redis-connect.sh
SUBSCRIBE pings:events

Logs

docker compose logs -f backend          # tail one service
docker compose logs -f backend pingsvc  # tail multiple services at once
docker compose logs -f                  # tail everything

docker compose watch backend (used in Quick Start) also streams the container's logs live to your terminal for as long as it's running, in addition to syncing code changes for hot reload.

See development.md for the full local development workflow (running services outside Docker, lint/test commands, and the multi-zone end-to-end walkthrough) and deployment.md for production/staging deployment.

About

A minimal distributed ICMP health checker.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages