Replaces LICENSE (GPLv3 -> AGPLv3) and prepends `SPDX-License-Identifier: AGPL-3.0-or-later` to every source file across decnet/, decnet_web/, tests/, scripts/, and tools/. Rationale: closes the GPLv3 ASP loophole so any party operating a modified DECNET as a network service must offer their modified source. Personal copyright (Samuel Paschuan) + inbound=outbound contributions make a future unilateral relicense infeasible. - LICENSE: full AGPL-3.0 text (gnu.org/licenses/agpl-3.0.txt) - COPYRIGHT: project copyright notice - tools/add_spdx_headers.py: idempotent header injector (shebang- and PEP 263-aware) Touches 1565 source files (.py, .ts, .tsx, .js, .jsx, .css, .sh). No behavior change; comments only.
69 lines
2.1 KiB
Python
69 lines
2.1 KiB
Python
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
"""DECNET SWARM Controller — master-side control plane.
|
|
|
|
Runs as an independent FastAPI/uvicorn process. Isolated from
|
|
``decnet.web.api`` so controller failure cannot cascade to the main API,
|
|
ingester, or dashboard (mirrors the existing pattern used by
|
|
``decnet api`` with ``start_new_session=True``).
|
|
|
|
Responsibilities:
|
|
* host enrollment (issues CA-signed worker bundles);
|
|
* dispatching DecnetConfig shards to worker agents over mTLS;
|
|
* active health probes of enrolled workers.
|
|
|
|
The controller *reuses* the same ``get_repo`` dependency as the main API,
|
|
so SwarmHost / DeckyShard state is visible to both processes via the
|
|
shared DB.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
from decnet.web import _uvicorn_tls_scope # noqa: F401 # patches uvicorn on import
|
|
|
|
from contextlib import asynccontextmanager
|
|
from typing import AsyncGenerator
|
|
|
|
from fastapi import FastAPI
|
|
from fastapi.responses import ORJSONResponse
|
|
|
|
from decnet.logging import get_logger
|
|
from decnet.swarm import pki
|
|
from decnet.swarm.client import ensure_master_identity
|
|
from decnet.web.dependencies import repo
|
|
from decnet.web.router.swarm import swarm_router
|
|
|
|
log = get_logger("swarm_api")
|
|
|
|
|
|
@asynccontextmanager
|
|
async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]:
|
|
log.info("swarm-controller starting up")
|
|
# Make sure the CA and master client cert exist before we accept any
|
|
# request — enrollment needs them and AgentClient needs them.
|
|
pki.ensure_ca()
|
|
ensure_master_identity()
|
|
await repo.initialize()
|
|
log.info("swarm-controller ready")
|
|
yield
|
|
log.info("swarm-controller shutdown")
|
|
|
|
|
|
app: FastAPI = FastAPI(
|
|
title="DECNET SWARM Controller",
|
|
version="0.1.0",
|
|
lifespan=lifespan,
|
|
default_response_class=ORJSONResponse,
|
|
# No interactive docs: the controller is an internal management plane,
|
|
# not a public surface. Enable explicitly in dev if needed.
|
|
docs_url=None,
|
|
redoc_url=None,
|
|
openapi_url=None,
|
|
)
|
|
|
|
app.include_router(swarm_router)
|
|
|
|
|
|
@app.get("/health")
|
|
async def root_health() -> dict[str, str]:
|
|
"""Top-level liveness probe (no DB I/O)."""
|
|
return {"status": "ok", "role": "swarm-controller"}
|