run the platform containers' root check through a build-independent path
This commit is contained in:
parent
700279026f
commit
29c57e058a
4 changed files with 34 additions and 11 deletions
|
|
@ -418,7 +418,10 @@ until the next collection. A drop-in written by an older hive-priv has no
|
||||||
**Hyperhive's platform containers: warn only.** The forge, the matrix server and
|
**Hyperhive's platform containers: warn only.** The forge, the matrix server and
|
||||||
the swarm services (15 containers, declared by their own modules) run the same
|
the swarm services (15 containers, declared by their own modules) run the same
|
||||||
check as `hive-priv check-rootfs --warn-only <name>`, from `ExecStartPre=` on
|
check as `hive-priv check-rootfs --warn-only <name>`, from `ExecStartPre=` on
|
||||||
their own `container@<name>` unit. It evaluates every rule, logs each violation
|
their own `container@<name>` unit, through the symlink `/run/hive-rootfs-check`
|
||||||
|
that `hive-priv.nix` points at the current build, so a new hyperhive build does
|
||||||
|
not change the unit or restart the container. It evaluates every rule, logs each
|
||||||
|
violation
|
||||||
as a warning, and exits 0, so the container starts either way. The line reads
|
as a warning, and exits 0, so the container starts either way. The line reads
|
||||||
`rootfs check (warn-only): <name>: <message>` with journald's warning priority.
|
`rootfs check (warn-only): <name>: <message>` with journald's warning priority.
|
||||||
Strict refusal needs the live roots of all 15 to pass first, and the warnings
|
Strict refusal needs the live roots of all 15 to pass first, and the warnings
|
||||||
|
|
|
||||||
|
|
@ -9,13 +9,19 @@
|
||||||
}:
|
}:
|
||||||
let
|
let
|
||||||
controllerCfg = config.services.hyperhive.deploy.hive-controller;
|
controllerCfg = config.services.hyperhive.deploy.hive-controller;
|
||||||
|
rootfsCheck = import ./lib/container-rootfs-check.nix { inherit config; };
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
config = lib.mkIf config.services.hyperhive.deploy.hive-controller.enable {
|
config = lib.mkIf config.services.hyperhive.deploy.hive-controller.enable {
|
||||||
# The parent of every agent socket dir. hive-priv is its only writer
|
# The parent of every agent socket dir. hive-priv is its only writer
|
||||||
# (`EnsureAgentSocketDir`), and its unit lists it in `ReadWritePaths`,
|
# (`EnsureAgentSocketDir`), and its unit lists it in `ReadWritePaths`,
|
||||||
# which fails the unit when the path is missing.
|
# which fails the unit when the path is missing.
|
||||||
systemd.tmpfiles.rules = [ "d /run/hive-agent 0755 root root - -" ];
|
systemd.tmpfiles.rules = [
|
||||||
|
"d /run/hive-agent 0755 root root - -"
|
||||||
|
# The platform containers run their warn-only root check by this path
|
||||||
|
# (`lib/container-rootfs-check.nix`), so their units carry no store path.
|
||||||
|
"L+ ${rootfsCheck.hivePriv} - - - - ${controllerCfg.package}/bin/hive-priv"
|
||||||
|
];
|
||||||
|
|
||||||
# Socket unit for hive-priv — the narrow root helper that executes
|
# Socket unit for hive-priv — the narrow root helper that executes
|
||||||
# privileged operations on behalf of hive-c0re. Systemd creates and
|
# privileged operations on behalf of hive-c0re. Systemd creates and
|
||||||
|
|
|
||||||
|
|
@ -23,12 +23,19 @@
|
||||||
# `container@<name>` unit (`nixos-containers.nix`, the `mapAttrsToList` that
|
# `container@<name>` unit (`nixos-containers.nix`, the `mapAttrsToList` that
|
||||||
# builds `container@${name}`), so a setting on that unit reaches that
|
# builds `container@${name}`), so a setting on that unit reaches that
|
||||||
# container only.
|
# container only.
|
||||||
{ config }:
|
#
|
||||||
{
|
# The binary is run through `hivePriv`, a path that does not change with the hyperhive
|
||||||
|
# build. `hive-priv.nix` points the symlink at the current package, so the
|
||||||
|
# unit text is the same across builds and a switch does not restart the
|
||||||
|
# container for it.
|
||||||
|
{ ... }:
|
||||||
|
rec {
|
||||||
|
hivePriv = "/run/hive-rootfs-check";
|
||||||
|
|
||||||
# Attributes for `systemd.services."container@<name>"`.
|
# Attributes for `systemd.services."container@<name>"`.
|
||||||
warnOnly = name: {
|
warnOnly = name: {
|
||||||
serviceConfig.ExecStartPre = [
|
serviceConfig.ExecStartPre = [
|
||||||
"-${config.services.hyperhive.deploy.hive-controller.package}/bin/hive-priv check-rootfs --warn-only ${name}"
|
"-${hivePriv} check-rootfs --warn-only ${name}"
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1814,7 +1814,7 @@ let
|
||||||
# their own unit, warn-only. Every container in these fixtures is one of
|
# their own unit, warn-only. Every container in these fixtures is one of
|
||||||
# hyperhive's, so the names are read off the fixture: a container added
|
# hyperhive's, so the names are read off the fixture: a container added
|
||||||
# without the check breaks the list, which is the point. The unit's own
|
# without the check breaks the list, which is the point. The unit's own
|
||||||
# pre-start script is not a `hive-priv` entry, so the count is the check
|
# pre-start script is not a `check-rootfs` entry, so the count is the check
|
||||||
# alone.
|
# alone.
|
||||||
name = "every hyperhive container runs the root check warn-only from its own unit, and no hyperhive container is left out";
|
name = "every hyperhive container runs the root check warn-only from its own unit, and no hyperhive container is left out";
|
||||||
ok =
|
ok =
|
||||||
|
|
@ -1824,13 +1824,13 @@ let
|
||||||
let
|
let
|
||||||
pre = m.systemd.services."container@${name}".serviceConfig.ExecStartPre or [ ];
|
pre = m.systemd.services."container@${name}".serviceConfig.ExecStartPre or [ ];
|
||||||
in
|
in
|
||||||
builtins.filter (lib.hasInfix "hive-priv") (
|
builtins.filter (lib.hasInfix "check-rootfs") (
|
||||||
map (p: builtins.unsafeDiscardStringContext (toString p)) pre
|
map (p: builtins.unsafeDiscardStringContext (toString p)) pre
|
||||||
);
|
);
|
||||||
carries =
|
carries =
|
||||||
m: name:
|
m: name:
|
||||||
checks m name == [
|
checks m name == [
|
||||||
(builtins.unsafeDiscardStringContext "-${m.services.hyperhive.deploy.hive-controller.package}/bin/hive-priv check-rootfs --warn-only ${name}")
|
"-/run/hive-rootfs-check check-rootfs --warn-only ${name}"
|
||||||
];
|
];
|
||||||
names = lib.attrNames allLocal.containers;
|
names = lib.attrNames allLocal.containers;
|
||||||
in
|
in
|
||||||
|
|
@ -1853,6 +1853,13 @@ let
|
||||||
&& lib.all (carries allLocal) names
|
&& lib.all (carries allLocal) names
|
||||||
&& withCi.containers ? swarm-ci-runner
|
&& withCi.containers ? swarm-ci-runner
|
||||||
&& lib.all (carries withCi) (lib.attrNames withCi.containers)
|
&& lib.all (carries withCi) (lib.attrNames withCi.containers)
|
||||||
|
# The line holds no store path, so a new hyperhive build leaves the
|
||||||
|
# unit text alone. Presence control: the lookup does find the line,
|
||||||
|
# and a line with a store path is caught by the same test.
|
||||||
|
&& lib.all (n: !(lib.hasInfix "/nix/store" (lib.head (checks allLocal n)))) names
|
||||||
|
&& lib.hasInfix "/nix/store" "-/nix/store/x-hyperhive/bin/hive-priv check-rootfs --warn-only x"
|
||||||
|
# The stable path is a link to the current package's hive-priv.
|
||||||
|
&& lib.elem "L+ /run/hive-rootfs-check - - - - ${allLocal.services.hyperhive.deploy.hive-controller.package}/bin/hive-priv" allLocal.systemd.tmpfiles.rules
|
||||||
# Control: a name with no unit finds nothing.
|
# Control: a name with no unit finds nothing.
|
||||||
&& checks allLocal "swarm-nope" == [ ];
|
&& checks allLocal "swarm-nope" == [ ];
|
||||||
}
|
}
|
||||||
|
|
@ -1868,7 +1875,7 @@ let
|
||||||
let
|
let
|
||||||
hivePrivLines =
|
hivePrivLines =
|
||||||
m: name:
|
m: name:
|
||||||
builtins.filter (lib.hasInfix "hive-priv") (
|
builtins.filter (lib.hasInfix "check-rootfs") (
|
||||||
map (p: builtins.unsafeDiscardStringContext (toString p)) (
|
map (p: builtins.unsafeDiscardStringContext (toString p)) (
|
||||||
m.systemd.services."container@${name}".serviceConfig.ExecStartPre or [ ]
|
m.systemd.services."container@${name}".serviceConfig.ExecStartPre or [ ]
|
||||||
)
|
)
|
||||||
|
|
@ -1881,7 +1888,7 @@ let
|
||||||
&& lib.all ignored (allLines allLocal)
|
&& lib.all ignored (allLines allLocal)
|
||||||
&& lib.all ignored (allLines withCi)
|
&& lib.all ignored (allLines withCi)
|
||||||
# Control: the test discriminates, a line without the prefix is not ignored.
|
# Control: the test discriminates, a line without the prefix is not ignored.
|
||||||
&& !(ignored "/nix/store/x-hyperhive/bin/hive-priv check-rootfs --warn-only x");
|
&& !(ignored "/run/hive-rootfs-check check-rootfs --warn-only x");
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
# The operator's other containers are not hyperhive's to touch: a
|
# The operator's other containers are not hyperhive's to touch: a
|
||||||
|
|
@ -1893,7 +1900,7 @@ let
|
||||||
let
|
let
|
||||||
checks =
|
checks =
|
||||||
name:
|
name:
|
||||||
builtins.filter (lib.hasInfix "hive-priv") (
|
builtins.filter (lib.hasInfix "check-rootfs") (
|
||||||
map (p: builtins.unsafeDiscardStringContext (toString p)) (
|
map (p: builtins.unsafeDiscardStringContext (toString p)) (
|
||||||
withForeignContainer.systemd.services."container@${name}".serviceConfig.ExecStartPre or [ ]
|
withForeignContainer.systemd.services."container@${name}".serviceConfig.ExecStartPre or [ ]
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue