feat(enroll): decnet-updater now runs under systemd, not a --daemon fork
Bootstrap used to end with `decnet updater --daemon` which forks and detaches — invisible to systemctl, no auto-restart, dies on reboot. Ships a decnet-updater.service template matching the pattern of the other units (Restart=on-failure, log to /var/log/decnet/decnet.updater.log, certs from /etc/decnet/updater, install tree at /opt/decnet), bundles it alongside agent/forwarder/engine units, and the installer now `systemctl enable --now`s it when --with-updater is set.
This commit is contained in:
@@ -250,7 +250,7 @@ def _build_tarball(
|
|||||||
return buf.getvalue()
|
return buf.getvalue()
|
||||||
|
|
||||||
|
|
||||||
_SYSTEMD_UNITS = ("decnet-agent", "decnet-forwarder", "decnet-engine")
|
_SYSTEMD_UNITS = ("decnet-agent", "decnet-forwarder", "decnet-engine", "decnet-updater")
|
||||||
|
|
||||||
|
|
||||||
def _render_systemd_unit(name: str, agent_name: str, master_host: str) -> bytes:
|
def _render_systemd_unit(name: str, agent_name: str, master_host: str) -> bytes:
|
||||||
|
|||||||
18
decnet/web/templates/decnet-updater.service.j2
Normal file
18
decnet/web/templates/decnet-updater.service.j2
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=DECNET self-updater (accepts tarball pushes from master) — {{ agent_name }}
|
||||||
|
Documentation=https://github.com/anti/DECNET
|
||||||
|
After=network-online.target
|
||||||
|
Wants=network-online.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
WorkingDirectory=/opt/decnet
|
||||||
|
Environment=DECNET_SYSTEM_LOGS=/var/log/decnet/decnet.updater.log
|
||||||
|
ExecStart=/usr/local/bin/decnet updater --updater-dir /etc/decnet/updater --install-dir /opt/decnet --agent-dir /etc/decnet/agent
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=5
|
||||||
|
StandardOutput=append:/var/log/decnet/decnet.updater.log
|
||||||
|
StandardError=append:/var/log/decnet/decnet.updater.log
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
@@ -58,10 +58,15 @@ echo "[DECNET] installing systemd units..."
|
|||||||
install -Dm0644 etc/systemd/system/decnet-agent.service /etc/systemd/system/decnet-agent.service
|
install -Dm0644 etc/systemd/system/decnet-agent.service /etc/systemd/system/decnet-agent.service
|
||||||
install -Dm0644 etc/systemd/system/decnet-forwarder.service /etc/systemd/system/decnet-forwarder.service
|
install -Dm0644 etc/systemd/system/decnet-forwarder.service /etc/systemd/system/decnet-forwarder.service
|
||||||
install -Dm0644 etc/systemd/system/decnet-engine.service /etc/systemd/system/decnet-engine.service
|
install -Dm0644 etc/systemd/system/decnet-engine.service /etc/systemd/system/decnet-engine.service
|
||||||
systemctl daemon-reload
|
|
||||||
systemctl enable --now decnet-agent.service decnet-forwarder.service
|
|
||||||
|
|
||||||
if [[ "$WITH_UPDATER" == "true" ]]; then
|
if [[ "$WITH_UPDATER" == "true" ]]; then
|
||||||
/usr/local/bin/decnet updater --daemon
|
install -Dm0644 etc/systemd/system/decnet-updater.service /etc/systemd/system/decnet-updater.service
|
||||||
fi
|
fi
|
||||||
echo "[DECNET] agent {{ agent_name }} enrolled -> {{ master_host }}. Units: decnet-agent, decnet-forwarder active."
|
systemctl daemon-reload
|
||||||
|
|
||||||
|
ACTIVE_UNITS=(decnet-agent.service decnet-forwarder.service)
|
||||||
|
if [[ "$WITH_UPDATER" == "true" ]]; then
|
||||||
|
ACTIVE_UNITS+=(decnet-updater.service)
|
||||||
|
fi
|
||||||
|
systemctl enable --now "${ACTIVE_UNITS[@]}"
|
||||||
|
|
||||||
|
echo "[DECNET] agent {{ agent_name }} enrolled -> {{ master_host }}. Units: ${ACTIVE_UNITS[*]} active."
|
||||||
|
|||||||
@@ -197,7 +197,9 @@ async def test_systemd_units_shipped_and_installed(client, auth_token):
|
|||||||
master_host="10.9.8.7")).json()["token"]
|
master_host="10.9.8.7")).json()["token"]
|
||||||
sh = (await client.get(f"/api/v1/swarm/enroll-bundle/{sh_token}.sh")).text
|
sh = (await client.get(f"/api/v1/swarm/enroll-bundle/{sh_token}.sh")).text
|
||||||
assert "systemctl daemon-reload" in sh
|
assert "systemctl daemon-reload" in sh
|
||||||
assert "systemctl enable --now decnet-agent.service decnet-forwarder.service" in sh
|
# Agent + forwarder always enabled; updater conditional on WITH_UPDATER.
|
||||||
|
assert "decnet-agent.service decnet-forwarder.service" in sh
|
||||||
|
assert "decnet-updater.service" in sh
|
||||||
|
|
||||||
ini = tf.extractfile("etc/decnet/decnet.ini").read().decode()
|
ini = tf.extractfile("etc/decnet/decnet.ini").read().decode()
|
||||||
assert "log-directory = /var/log/decnet" in ini
|
assert "log-directory = /var/log/decnet" in ini
|
||||||
@@ -205,7 +207,7 @@ async def test_systemd_units_shipped_and_installed(client, auth_token):
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.anyio
|
@pytest.mark.anyio
|
||||||
async def test_updater_opt_in_ships_cert_and_starts_daemon(client, auth_token):
|
async def test_updater_opt_in_ships_cert_and_enables_systemd_unit(client, auth_token):
|
||||||
import io, tarfile
|
import io, tarfile
|
||||||
token = (await _post(client, auth_token, agent_name="up", with_updater=True)).json()["token"]
|
token = (await _post(client, auth_token, agent_name="up", with_updater=True)).json()["token"]
|
||||||
resp = await client.get(f"/api/v1/swarm/enroll-bundle/{token}.tgz")
|
resp = await client.get(f"/api/v1/swarm/enroll-bundle/{token}.tgz")
|
||||||
@@ -213,12 +215,20 @@ async def test_updater_opt_in_ships_cert_and_starts_daemon(client, auth_token):
|
|||||||
names = set(tf.getnames())
|
names = set(tf.getnames())
|
||||||
assert "home/.decnet/updater/updater.crt" in names
|
assert "home/.decnet/updater/updater.crt" in names
|
||||||
assert "home/.decnet/updater/updater.key" in names
|
assert "home/.decnet/updater/updater.key" in names
|
||||||
|
assert "etc/systemd/system/decnet-updater.service" in names
|
||||||
key_info = tf.getmember("home/.decnet/updater/updater.key")
|
key_info = tf.getmember("home/.decnet/updater/updater.key")
|
||||||
assert (key_info.mode & 0o777) == 0o600
|
assert (key_info.mode & 0o777) == 0o600
|
||||||
|
|
||||||
|
updater_unit = tf.extractfile("etc/systemd/system/decnet-updater.service").read().decode()
|
||||||
|
assert "DECNET_SYSTEM_LOGS=/var/log/decnet/decnet.updater.log" in updater_unit
|
||||||
|
assert "Restart=on-failure" in updater_unit
|
||||||
|
|
||||||
sh_token = (await _post(client, auth_token, agent_name="up2", with_updater=True)).json()["token"]
|
sh_token = (await _post(client, auth_token, agent_name="up2", with_updater=True)).json()["token"]
|
||||||
sh = (await client.get(f"/api/v1/swarm/enroll-bundle/{sh_token}.sh")).text
|
sh = (await client.get(f"/api/v1/swarm/enroll-bundle/{sh_token}.sh")).text
|
||||||
assert 'WITH_UPDATER="true"' in sh
|
assert 'WITH_UPDATER="true"' in sh
|
||||||
assert "decnet updater --daemon" in sh
|
assert "decnet-updater.service" in sh
|
||||||
|
# Old --daemon path is gone — updater is now a systemd service.
|
||||||
|
assert "decnet updater --daemon" not in sh
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.anyio
|
@pytest.mark.anyio
|
||||||
|
|||||||
Reference in New Issue
Block a user