Introduces the `decnet webhook` long-running worker that consumes the
internal bus and POSTs matching events to configured subscriptions.
Design: one task per (subscription, pattern) pair. Each task opens
its own bus subscription, iterates events, and dispatches via the
shared deliver() client. No intermediate queue, no in-memory filter
matching — the bus's own pattern matcher is the filter. Reloads on
`system.webhook.subscriptions_changed` signals from the CRUD router,
with a 60s fallback timer in case a signal is lost.
Shutdown propagates via CancelledError on the outer task; all inner
subscription tasks are cancelled and awaited in a finally block.
Bus unavailable → worker stays up in idle mode per the DEBT-031
pattern, logging one warning.
Registered as a master-only CLI command (agents don't configure
webhooks — the subscription store lives on master). systemd unit
mirrors the profiler template; added to decnet.target Wants= list so
`systemctl start decnet.target` brings it up alongside everything
else. `decnet init` auto-picks up the new .service.j2 via its
existing `glob("decnet-*.service.j2")` sweep.
87 lines
1.9 KiB
Python
87 lines
1.9 KiB
Python
"""
|
|
DECNET CLI — entry point for all commands.
|
|
|
|
Usage:
|
|
decnet deploy --mode unihost --deckies 5 --randomize-services
|
|
decnet status
|
|
decnet teardown [--all | --id decky-01]
|
|
decnet services
|
|
|
|
Layout: each command module exports ``register(app)`` which attaches its
|
|
commands to the passed Typer app. ``__init__.py`` builds the root app,
|
|
calls every module's ``register`` in order, then runs the master-only
|
|
gate. The gate must fire LAST so it sees the fully-populated dispatch
|
|
table before filtering.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import typer
|
|
|
|
from . import (
|
|
agent,
|
|
api,
|
|
bus,
|
|
db,
|
|
deploy,
|
|
forwarder,
|
|
geoip,
|
|
init,
|
|
inventory,
|
|
lifecycle,
|
|
listener,
|
|
profiler,
|
|
sniffer,
|
|
swarm,
|
|
swarmctl,
|
|
topology,
|
|
updater,
|
|
web,
|
|
webhook,
|
|
workers,
|
|
)
|
|
from .gating import _gate_commands_by_mode
|
|
from .utils import console as console, log as log
|
|
|
|
app = typer.Typer(
|
|
name="decnet",
|
|
help="Deploy a deception network of honeypot deckies on your LAN.",
|
|
no_args_is_help=True,
|
|
)
|
|
|
|
# Order matches the old flat layout so `decnet --help` reads the same.
|
|
for _mod in (
|
|
api, swarmctl, agent, updater, listener, forwarder,
|
|
swarm,
|
|
deploy, lifecycle, workers, inventory,
|
|
web, profiler, sniffer, db,
|
|
topology, bus, geoip, init, webhook,
|
|
):
|
|
_mod.register(app)
|
|
|
|
_gate_commands_by_mode(app)
|
|
|
|
# Backwards-compat re-exports. Tests and third-party tooling import these
|
|
# directly from ``decnet.cli``; the refactor must keep them resolvable.
|
|
from .db import _db_reset_mysql_async # noqa: E402,F401
|
|
from .gating import ( # noqa: E402,F401
|
|
MASTER_ONLY_COMMANDS,
|
|
MASTER_ONLY_GROUPS,
|
|
_agent_mode_active,
|
|
_require_master_mode,
|
|
)
|
|
from .utils import ( # noqa: E402,F401
|
|
_daemonize,
|
|
_http_request,
|
|
_is_running,
|
|
_kill_all_services,
|
|
_pid_dir,
|
|
_service_registry,
|
|
_spawn_detached,
|
|
_swarmctl_base_url,
|
|
)
|
|
|
|
|
|
if __name__ == "__main__": # pragma: no cover
|
|
app()
|