feat(config): add swarmctl-host to INI, env, CLI; drop hardcoded bind from systemd unit
[swarm] swarmctl-host → DECNET_SWARMCTL_HOST so operators set the bind address once in decnet.ini; `decnet swarmctl` and the systemd unit both resolve it via envvar — no --host/--port pinned on ExecStart.
This commit is contained in:
@@ -74,6 +74,7 @@ _CONFIG_PLACEHOLDER = """\
|
|||||||
# master-host = 10.0.0.1
|
# master-host = 10.0.0.1
|
||||||
# syslog-port = 6514
|
# syslog-port = 6514
|
||||||
# swarmctl-port = 8770
|
# swarmctl-port = 8770
|
||||||
|
# swarmctl-host = 127.0.0.1
|
||||||
|
|
||||||
# [logging]
|
# [logging]
|
||||||
# system-log = /var/log/decnet/decnet.system.log
|
# system-log = /var/log/decnet/decnet.system.log
|
||||||
|
|||||||
@@ -16,8 +16,16 @@ from .utils import console, log
|
|||||||
def register(app: typer.Typer) -> None:
|
def register(app: typer.Typer) -> None:
|
||||||
@app.command()
|
@app.command()
|
||||||
def swarmctl(
|
def swarmctl(
|
||||||
port: int = typer.Option(8770, "--port", help="Port for the swarm controller"),
|
port: int = typer.Option(
|
||||||
host: str = typer.Option("127.0.0.1", "--host", help="Bind address for the swarm controller"),
|
8770, "--port",
|
||||||
|
envvar="DECNET_SWARMCTL_PORT",
|
||||||
|
help="Port for the swarm controller. Defaults to [swarm] swarmctl-port from /etc/decnet/decnet.ini, else 8770.",
|
||||||
|
),
|
||||||
|
host: str = typer.Option(
|
||||||
|
"127.0.0.1", "--host",
|
||||||
|
envvar="DECNET_SWARMCTL_HOST",
|
||||||
|
help="Bind address for the swarm controller. Defaults to [swarm] swarmctl-host from /etc/decnet/decnet.ini, else 127.0.0.1.",
|
||||||
|
),
|
||||||
daemon: bool = typer.Option(False, "--daemon", "-d", help="Detach to background as a daemon process"),
|
daemon: bool = typer.Option(False, "--daemon", "-d", help="Detach to background as a daemon process"),
|
||||||
no_listener: bool = typer.Option(False, "--no-listener", help="Do not auto-spawn the syslog-TLS listener alongside swarmctl"),
|
no_listener: bool = typer.Option(False, "--no-listener", help="Do not auto-spawn the syslog-TLS listener alongside swarmctl"),
|
||||||
tls: bool = typer.Option(False, "--tls", help="Serve over HTTPS with mTLS (required for cross-host worker heartbeats)"),
|
tls: bool = typer.Option(False, "--tls", help="Serve over HTTPS with mTLS (required for cross-host worker heartbeats)"),
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ Shape::
|
|||||||
master-host = 10.0.0.1 # required on agents
|
master-host = 10.0.0.1 # required on agents
|
||||||
syslog-port = 6514
|
syslog-port = 6514
|
||||||
swarmctl-port = 8770
|
swarmctl-port = 8770
|
||||||
|
swarmctl-host = 127.0.0.1 # bind address for `decnet swarmctl`
|
||||||
|
|
||||||
[logging]
|
[logging]
|
||||||
system-log = /var/log/decnet/decnet.system.log
|
system-log = /var/log/decnet/decnet.system.log
|
||||||
@@ -120,6 +121,7 @@ _DOMAIN_MAP: dict[str, dict[str, str]] = {
|
|||||||
"master-host": "DECNET_SWARM_MASTER_HOST",
|
"master-host": "DECNET_SWARM_MASTER_HOST",
|
||||||
"syslog-port": "DECNET_SWARM_SYSLOG_PORT",
|
"syslog-port": "DECNET_SWARM_SYSLOG_PORT",
|
||||||
"swarmctl-port": "DECNET_SWARMCTL_PORT",
|
"swarmctl-port": "DECNET_SWARMCTL_PORT",
|
||||||
|
"swarmctl-host": "DECNET_SWARMCTL_HOST",
|
||||||
},
|
},
|
||||||
"logging": {
|
"logging": {
|
||||||
"system-log": "DECNET_SYSTEM_LOGS",
|
"system-log": "DECNET_SYSTEM_LOGS",
|
||||||
|
|||||||
@@ -114,6 +114,11 @@ DECNET_SWARM_MASTER_HOST: str | None = os.environ.get("DECNET_SWARM_MASTER_HOST"
|
|||||||
DECNET_HOST_UUID: str | None = os.environ.get("DECNET_HOST_UUID")
|
DECNET_HOST_UUID: str | None = os.environ.get("DECNET_HOST_UUID")
|
||||||
DECNET_MASTER_HOST: str | None = os.environ.get("DECNET_MASTER_HOST")
|
DECNET_MASTER_HOST: str | None = os.environ.get("DECNET_MASTER_HOST")
|
||||||
DECNET_SWARMCTL_PORT: int = _port("DECNET_SWARMCTL_PORT", 8770)
|
DECNET_SWARMCTL_PORT: int = _port("DECNET_SWARMCTL_PORT", 8770)
|
||||||
|
# Bind address for the master-side swarm controller. Loopback by default —
|
||||||
|
# operators flip to 0.0.0.0 (or a specific NIC) on production masters where
|
||||||
|
# workers heartbeat in over mTLS from other hosts. Seeded by [swarm]
|
||||||
|
# swarmctl-host in /etc/decnet/decnet.ini.
|
||||||
|
DECNET_SWARMCTL_HOST: str = os.environ.get("DECNET_SWARMCTL_HOST", "127.0.0.1")
|
||||||
|
|
||||||
# Ingester batching: how many log rows to accumulate per commit, and the
|
# Ingester batching: how many log rows to accumulate per commit, and the
|
||||||
# max wait (ms) before flushing a partial batch. Larger batches reduce
|
# max wait (ms) before flushing a partial batch. Larger batches reduce
|
||||||
|
|||||||
@@ -10,10 +10,12 @@ User={{ user }}
|
|||||||
Group={{ group }}
|
Group={{ group }}
|
||||||
WorkingDirectory={{ install_dir }}
|
WorkingDirectory={{ install_dir }}
|
||||||
EnvironmentFile=-{{ install_dir }}/.env.local
|
EnvironmentFile=-{{ install_dir }}/.env.local
|
||||||
# Default bind is loopback — the controller is a master-local orchestrator
|
# Bind/port resolved from /etc/decnet/decnet.ini ([swarm] swarmctl-host /
|
||||||
# reached by the CLI and the web dashboard, not by workers.
|
# swarmctl-port) — falls back to 127.0.0.1:8770 when the keys are absent.
|
||||||
|
# Pass --host/--port on the ExecStart line only if you want to pin them
|
||||||
|
# regardless of what the INI says.
|
||||||
Environment=DECNET_SYSTEM_LOGS=/var/log/decnet/decnet.swarmctl.log
|
Environment=DECNET_SYSTEM_LOGS=/var/log/decnet/decnet.swarmctl.log
|
||||||
ExecStart={{ venv_dir }}/bin/decnet swarmctl --host 127.0.0.1 --port 8770
|
ExecStart={{ venv_dir }}/bin/decnet swarmctl
|
||||||
StandardOutput=append:/var/log/decnet/decnet.swarmctl.log
|
StandardOutput=append:/var/log/decnet/decnet.swarmctl.log
|
||||||
StandardError=append:/var/log/decnet/decnet.swarmctl.log
|
StandardError=append:/var/log/decnet/decnet.swarmctl.log
|
||||||
|
|
||||||
|
|||||||
@@ -302,3 +302,18 @@ swarmctl-port = 9999
|
|||||||
load_ini_config(ini)
|
load_ini_config(ini)
|
||||||
# [master] loaded first, [swarm] lost via setdefault
|
# [master] loaded first, [swarm] lost via setdefault
|
||||||
assert os.environ["DECNET_SWARMCTL_PORT"] == "9001"
|
assert os.environ["DECNET_SWARMCTL_PORT"] == "9001"
|
||||||
|
|
||||||
|
|
||||||
|
def test_swarm_section_seeds_swarmctl_host(monkeypatch, tmp_path):
|
||||||
|
"""[swarm] swarmctl-host → DECNET_SWARMCTL_HOST so the systemd unit and
|
||||||
|
`decnet swarmctl` CLI both pick up the operator's bind choice from the
|
||||||
|
INI without anyone passing --host on ExecStart."""
|
||||||
|
_scrub(monkeypatch, "DECNET_MODE", "DECNET_SWARMCTL_HOST", "DECNET_SWARMCTL_PORT")
|
||||||
|
ini = _write_ini(tmp_path, """
|
||||||
|
[swarm]
|
||||||
|
swarmctl-host = 0.0.0.0
|
||||||
|
swarmctl-port = 9000
|
||||||
|
""")
|
||||||
|
load_ini_config(ini)
|
||||||
|
assert os.environ["DECNET_SWARMCTL_HOST"] == "0.0.0.0"
|
||||||
|
assert os.environ["DECNET_SWARMCTL_PORT"] == "9000"
|
||||||
|
|||||||
Reference in New Issue
Block a user