diff --git a/modules/systemd-networkd/module.json b/modules/systemd-networkd/module.json index 370cf1d..9e12003 100644 --- a/modules/systemd-networkd/module.json +++ b/modules/systemd-networkd/module.json @@ -2,7 +2,6 @@ "module": "systemd-networkd", "version": "1", "capabilities": [ - "package-manager", "service-manager", "uplink-systemd-networkd" ], @@ -13,17 +12,12 @@ } ], "resources": [ - { - "id": "package", - "type": "package", - "package": "systemd" - }, { "id": "config", "type": "file", "path": "/etc/systemd/network/00-mesh0.network", "mode": "0644", - "content": "# Managed by the mesh (module systemd-networkd). Replaced on every push; edit\n# the catalogue instead.\n#\n# This machine's uplink is systemd-networkd's, and the mesh asks one thing of it\n# here (novox/hq ADR 0117): leave the private network's interface alone. mesh0\n# is the mesh's; the mesh brings it up and configures it itself. The mesh never\n# declares a link, an address, a route, a wireless network or its credentials,\n# nor a network file for any of this machine's own interfaces \u2014 those are\n# the operator's, and the link they make is the only channel the mesh reaches\n# this machine over.\n#\n# 00-: networkd applies the first .network file, in alphanumeric order across\n# every directory, that matches an interface, and ignores every later one even\n# if it matches too (systemd.network(5), [Match]). A catch-all of the operator's\n# \u2014 Name=*, Type=ether, a file with no [Match] at all \u2014 sorted before\n# this one would claim mesh0 first. 00 sorts before every numbered prefix the\n# man page recommends.\n#\n# Unmanaged=yes: \"no attempts are made to bring up or configure matching links,\n# equivalent to when there are no matching network files\" (systemd.network(5),\n# [Link], since 233). A match that ends the search, and does nothing else.\n#\n# No DNS setting, because none is needed: networkd never writes\n# /etc/resolv.conf. What it learns from a lease it hands only to\n# systemd-resolved, and the resolver file stays whatever resolv-conf wrote.\n# Whether resolved runs, and what it does with that, is the resolver\n# configuration's question, not the uplink's.\n#\n# The service is reloaded when this file changes, never restarted: a restart\n# drops the links networkd holds, this machine's channel to the mesh among them.\n[Match]\nName=mesh0\n\n[Link]\nUnmanaged=yes\n" + "content": "# Managed by the mesh (module systemd-networkd). Replaced on every push; edit\n# the catalogue instead.\n#\n# This machine's uplink is systemd-networkd's, and the mesh asks one thing of it\n# here (novox/hq ADR 0117): leave the private network's interface alone. mesh0\n# is the mesh's; the mesh brings it up and configures it itself. The mesh never\n# declares a link, an address, a route, a wireless network or its credentials,\n# nor a network file for any of this machine's own interfaces — those are\n# the operator's, and the link they make is the only channel the mesh reaches\n# this machine over.\n#\n# 00-: networkd applies the first .network file, in alphanumeric order across\n# every directory, that matches an interface, and ignores every later one even\n# if it matches too (systemd.network(5), [Match]). A catch-all of the operator's\n# — Name=*, Type=ether, a file with no [Match] at all — sorted before\n# this one would claim mesh0 first. 00 sorts before every numbered prefix the\n# man page recommends.\n#\n# Unmanaged=yes: \"no attempts are made to bring up or configure matching links,\n# equivalent to when there are no matching network files\" (systemd.network(5),\n# [Link], since 233). A match that ends the search, and does nothing else.\n#\n# No DNS setting, because none is needed: networkd never writes\n# /etc/resolv.conf. What it learns from a lease it hands only to\n# systemd-resolved, and the resolver file stays whatever resolv-conf wrote.\n# Whether resolved runs, and what it does with that, is the resolver\n# configuration's question, not the uplink's.\n#\n# The service is reloaded when this file changes, never restarted: a restart\n# drops the links networkd holds, this machine's channel to the mesh among them.\n[Match]\nName=mesh0\n\n[Link]\nUnmanaged=yes\n" }, { "id": "service", diff --git a/modules/systemd/module.json b/modules/systemd/module.json index c07ff3f..f2715aa 100644 --- a/modules/systemd/module.json +++ b/modules/systemd/module.json @@ -2,7 +2,8 @@ "module": "systemd", "version": "1", "capabilities": [ - "service-manager" + "service-manager", + "package-manager" ], "claims": [ { @@ -34,5 +35,12 @@ ] } ] - } + }, + "resources": [ + { + "id": "package", + "type": "package", + "package": "systemd" + } + ] } diff --git a/modules/systemd/test/client.test.ts b/modules/systemd/test/client.test.ts index 9aa767d..19317e1 100644 --- a/modules/systemd/test/client.test.ts +++ b/modules/systemd/test/client.test.ts @@ -156,9 +156,12 @@ test("a unit's name is never an option", async () => { assert.deepEqual(calls[0].args.slice(-2), ["--", "-x*"]); }); -test("the manifest declares no package — the service manager is always there, and networkd declares it too", () => { +test("the manifest owns the systemd package — the service manager's own, never a component module's", () => { const m = JSON.parse(readFileSync(new URL("../module.json", import.meta.url), "utf8")); - assert.ok(!(m.resources ?? []).some((r: { type: string }) => r.type === "package")); - assert.ok(!m.capabilities.includes("package-manager")); + assert.ok((m.resources ?? []).some((r: { type: string; package?: string }) => r.type === "package" && r.package === "systemd")); + assert.ok(m.capabilities.includes("package-manager")); + // networkd is a component of systemd and configures it; it never claims the package. + const networkd = JSON.parse(readFileSync(new URL("../../systemd-networkd/module.json", import.meta.url), "utf8")); + assert.ok(!(networkd.resources ?? []).some((r: { type: string; package?: string }) => r.type === "package" && r.package === "systemd")); assert.deepEqual(m.claims[0].serves, ["units", "status", "start", "stop", "restart", "enable", "disable", "journal"]); });