Watch
0
0
Fork
You've already forked hyperhive
0

swarm builder: the all-swarm-services switch turns it on, like every other swarm service

deploy.builder.enable defaults on under deploy.allSwarmServices (mkDefault),
where the host has the builder's store identity pair, as for the review
classifier. An explicit false still wins.
This commit is contained in:
atlas 2026-10-14 22:33:57 +02:00 • committed by mara
commit d24dbaeadf
7 changed files with 68 additions and 26 deletions

View file

@ -694,13 +694,13 @@ in
this host's nix daemon, and swarm-controller writes the result as a
`swarm-builder` commit status on the PR.
Not derived from
{option}`services.hyperhive.deploy.allSwarmServices`: the builder
evaluates and builds unreviewed config PRs on this host's nix daemon,
so running one is a decision of its own, as for the CI runner. It needs
the builder's store identity
({option}`services.hyperhive.deploy.bao.builderClientCertFile` and
`builderClientKeyFile`), which the store's host mints.
On by default where
{option}`services.hyperhive.deploy.allSwarmServices` is set and this
host has the builder's store identity (the pair
{option}`services.hyperhive.deploy.bao.builderClientCertFile` and
`builderClientKeyFile`, minted on the store's host). It evaluates
unreviewed config PRs and builds them through this host's nix daemon,
from a container with its own network namespace.
'';
};

View file

@ -1,5 +1,6 @@
# The swarm builder, in a `swarm-builder` container on the host that sets
# `deploy.builder.enable`, which nothing turns on for the operator: it runs
# `deploy.builder.enable`, which `deploy.allSwarmServices` defaults on where the
# host has the builder's store identity (./swarm-required-services.nix). It runs
# unreviewed config PRs through the host's nix daemon. It builds agent configs
# for swarm-controller: the controller sends a config PR's head over the
# queue, and the daemon builds that config on this host's agent base and

View file

@ -117,4 +117,13 @@ in
&& deployCfg.bao.reviewClassifierClientCertFile != null
&& deployCfg.bao.reviewClassifierClientKeyFile != null
);
# The builder, by the same rule and for the same reason: its module asserts
# the builder's store identity. It evaluates unreviewed config PRs, which is
# why ./swarm-builder.nix gives it a container with its own netns.
config.services.hyperhive.deploy.builder.enable = lib.mkDefault (
deployCfg.allSwarmServices
&& deployCfg.bao.builderClientCertFile != null
&& deployCfg.bao.builderClientKeyFile != null
);
}

View file

@ -32,6 +32,10 @@ let
};
servicesHere = hiveWithController { deploy.allSwarmServices = true; };
# Short-circuits on `assertion`, so only a failing one has its message read.
refusedWithoutIdentity =
m:
lib.any (a: !a.assertion && lib.hasInfix "deploy.builder.enable requires" a.message) m.assertions;
natsHere = hive {
swarm.nats.enable = true;
@ -54,13 +58,17 @@ let
ok = !(bare.containers ? swarm-builder) && withBuilder.containers ? swarm-builder;
}
{
# It runs unreviewed config PRs through the host's nix daemon, so hosting
# the shared services, even with the store's leaf here, does not turn it
# on. `nats` is the control that the switch is on at all.
name = "hosting the shared services leaves the builder off";
# The store's host mints the builder's leaf, so the switch needs no
# manual identity step: the pair is set and the module's identity
# assertion, which nothing else reads in this fixture, passes. `nats` is
# the control that the switch is on.
name = "hosting the shared services turns the builder on, with its store identity";
ok =
!servicesHere.services.hyperhive.deploy.builder.enable
&& !(servicesHere.containers ? swarm-builder)
servicesHere.services.hyperhive.deploy.builder.enable
&& servicesHere.containers ? swarm-builder
&& servicesHere.services.hyperhive.deploy.bao.builderClientCertFile != null
&& servicesHere.services.hyperhive.deploy.bao.builderClientKeyFile != null
&& !(refusedWithoutIdentity servicesHere)
&& servicesHere.services.hyperhive.deploy.bao.enable
&& servicesHere.services.hyperhive.deploy.nats.enable;
}

View file

@ -90,10 +90,12 @@ let
# swarm-required-services.nix documents the switch for.
swarmServicesHere = hiveWithController { deploy.allSwarmServices = true; };
# Same, with the operator opting out of the classifier alone.
swarmServicesWithoutClassifier = hiveWithController {
# Same, with the operator opting out of the classifier and the builder,
# which the switch defaults on and everything else it owns stays on.
swarmServicesOptedOut = hiveWithController {
deploy.allSwarmServices = true;
deploy.review-classifier.enable = false;
deploy.builder.enable = false;
};
# Same, with one of those services placed on another host. Every derivation
@ -161,8 +163,8 @@ let
lib.filter (l: swarmServiceLinkDomains ? ${l.label}) cfg.services.hyperhive.swarm.controller.links;
# Every service container at once: the services-only host plus the CI
# runner. The CI runner, the review classifier and the metrics store are the
# three containers on a netns of their own.
# runner. The CI runner, the review classifier, the builder and the metrics
# store are the four containers on a netns of their own.
serviceContainersWithCi = hive {
deploy.hive-controller.enable = false;
deploy.allSwarmServices = true;
@ -212,9 +214,19 @@ let
# without the line is the control.
name = "an explicit false keeps the review classifier off where the shared services are hosted";
ok =
!swarmServicesWithoutClassifier.services.hyperhive.deploy.review-classifier.enable
&& !(swarmServicesWithoutClassifier.containers ? swarm-review-classifier)
&& swarmServicesWithoutClassifier.services.hyperhive.deploy.nats.enable;
!swarmServicesOptedOut.services.hyperhive.deploy.review-classifier.enable
&& !(swarmServicesOptedOut.containers ? swarm-review-classifier)
&& swarmServicesOptedOut.services.hyperhive.deploy.nats.enable;
}
{
# Same as the classifier's case above, for the builder: the opt-out is
# the only difference from `swarmServicesHere`, which has the container.
name = "an explicit false keeps the swarm builder off where the shared services are hosted";
ok =
!swarmServicesOptedOut.services.hyperhive.deploy.builder.enable
&& !(swarmServicesOptedOut.containers ? swarm-builder)
&& swarmServicesHere.containers ? swarm-builder
&& swarmServicesOptedOut.services.hyperhive.deploy.nats.enable;
}
{
# The classifier's module asserts a store identity that only the store's
@ -226,6 +238,15 @@ let
&& !(swarmServicesBaoElsewhere.containers ? swarm-review-classifier)
&& swarmServicesBaoElsewhere.services.hyperhive.deploy.nats.enable;
}
{
# The builder's module asserts its own store identity, so the same
# holds for it. `nats` is the control.
name = "the swarm builder stays off where the shared services are hosted without the store";
ok =
!swarmServicesBaoElsewhere.services.hyperhive.deploy.builder.enable
&& !(swarmServicesBaoElsewhere.containers ? swarm-builder)
&& swarmServicesBaoElsewhere.services.hyperhive.deploy.nats.enable;
}
{
# The switch fills in for an operator who has not spoken and yields to
# one who has — that is what keeps a shared service placeable on a host
@ -489,7 +510,7 @@ let
# that lost a container can't pass by comparing fewer of them.
name = "every service container restates its host-side privateNetwork";
ok =
lib.length (lib.attrNames serviceContainers) == 11
lib.length (lib.attrNames serviceContainers) == 12
&& lib.all (
c: c.privateNetwork == (c.config.services.hyperhive.swarmContainer.privateNetwork or null)
) (lib.attrValues serviceContainers);