The orgs agent-configs/internal/agents (plus mirror owners), the operators team in agents and agent-configs, the pull-mirrors, internal/docs, internal/knowledge (public, README-seeded) and the agent-configs org avatar are one set per forge. hive-c0re ensured them in its boot sweep, as the core admin, and only on the hive co-located with the forge container. swarm-controller now reconciles them at start and every 5 minutes (forge/objects.rs: observe -> pure plan -> apply). A failed object logs a warn line plus a pass summary and is retried next tick. create_repo ensures the agent-configs org and its operators team first, so a config repo's merge gate never depends on the periodic pass having run. hive-c0re drops ensure_org, SEEDED_ORGS, ensure_mirrors/ensure_mirror_repo, ensure_operators_team, ensure_shared_docs_repo, ensure_knowledge_repo/ set_repo_public, seed_readme, ensure_config_org_avatar and the one-shot knowledge::remove_webhook cleanup, with their now-unused helpers. nix: the mirror list moves from the hive-c0re unit (HYPERHIVE_FORGE_MIRRORS) to the swarm-controller unit (SWARM_CONTROLLER_FORGE_MIRRORS), with an eval warning when mirrors are declared on a host that runs no controller. c0re.orgAvatarPng is renamed to deploy.swarm-controller.configOrgAvatarPng. Refs #3782
163 lines
6.5 KiB
Nix
163 lines
6.5 KiB
Nix
# `checks.module-eval-swarm-services-switch` — see ./lib.nix for the shared
|
|
# rationale (why this suite exists, naming convention, "evaluates
|
|
# not executes").
|
|
{
|
|
pkgs,
|
|
lib,
|
|
self,
|
|
nixosSystem,
|
|
}:
|
|
let
|
|
inherit
|
|
(import ./lib.nix {
|
|
inherit
|
|
pkgs
|
|
lib
|
|
self
|
|
nixosSystem
|
|
;
|
|
})
|
|
hive
|
|
runGroup
|
|
bridgePortsOrNone
|
|
swarmServiceEnables
|
|
;
|
|
|
|
# The swarm-services toggle with the central one off, so the only thing
|
|
# that can enable the gateway/resolver/bridge here is that toggle's own
|
|
# module — every other module that asserts them is behind `enable`.
|
|
swarmServicesOnly = hive {
|
|
enable = false;
|
|
deploy.allSwarmServices = true;
|
|
};
|
|
|
|
# Ports asked for on such a host. The request is the whole condition: the
|
|
# firewall hole exists because an operator named a port, not because the
|
|
# hive is running, and an agent reaching a host service is a claim about
|
|
# the host's own listeners either way.
|
|
exposedPortsNoHive = hive {
|
|
enable = false;
|
|
network.exposeHostPorts = [ 5432 ];
|
|
};
|
|
|
|
# The swarm UI where its own toggle is on — the control the absence arm
|
|
# needs, since nothing else in this suite renders this vhost and an arm
|
|
# saying "it is not there" would hold just as well if it were never there.
|
|
# Package stubbed per this file's header: the vhost roots at it.
|
|
swarmUiHere = hive {
|
|
deploy.swarm-ui.enable = true;
|
|
deploy.swarm-ui.package = pkgs.emptyDirectory;
|
|
};
|
|
|
|
# The swarm's shared services hosted HERE without the all-local mode — a
|
|
# services box with hives elsewhere, the shape ./host-modules/
|
|
# swarm-required-services.nix documents the switch for.
|
|
swarmServicesHere = hive { deploy.allSwarmServices = true; };
|
|
|
|
# Same, with one of those services placed on another host. Every derivation
|
|
# in that module is `mkDefault` so this stays expressible.
|
|
swarmServicesBaoElsewhere = hive {
|
|
deploy.allSwarmServices = true;
|
|
deploy.bao.enable = false;
|
|
};
|
|
|
|
# The swarm-wide forge objects are the controller's (forge/objects.rs), so
|
|
# the mirror list and the org avatar go to its unit, not hive-c0re's.
|
|
aMirror = {
|
|
upstream = "https://example.invalid/tool";
|
|
dest = "mirrors/tool";
|
|
};
|
|
controllerWithMirrors = hive {
|
|
deploy.swarm-controller.enable = true;
|
|
deploy.forgejo.mirrors = [ aMirror ];
|
|
c0re.orgAvatarPng = "/etc/marker-avatar.png";
|
|
};
|
|
mirrorsNoController = hive { deploy.forgejo.mirrors = [ aMirror ]; };
|
|
cases = [
|
|
{
|
|
# `lib.all` over an empty set holds vacuously, so the roster is counted
|
|
# before it is read: a helper that lost a member would otherwise turn
|
|
# this case green by measuring nothing.
|
|
name = "hosting the swarm's shared services turns on every service that switch owns";
|
|
ok =
|
|
let
|
|
es = swarmServiceEnables swarmServicesHere;
|
|
in
|
|
lib.length (lib.attrNames es) == 9 && lib.all lib.id (lib.attrValues es);
|
|
}
|
|
{
|
|
# 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
|
|
# of its own. A plain assignment or `mkForce` would satisfy both cases
|
|
# above and break this one. `nats` is the control: without it the case
|
|
# also passes on a fixture where nothing came on at all.
|
|
name = "placing one shared service elsewhere survives the switch that would enable it";
|
|
ok =
|
|
let
|
|
es = swarmServiceEnables swarmServicesBaoElsewhere;
|
|
in
|
|
!es.bao && es.nats;
|
|
}
|
|
{
|
|
# The controller sits on the OTHER tier: `singleHostSwarm` places it
|
|
# (./host-modules/local-defaults.nix) and swarm-ui follows the
|
|
# controller. Pinned so that moving a service between tiers is a
|
|
# decision someone makes rather than a merge nobody reads.
|
|
name = "hosting the swarm's shared services does not make a hive the swarm's control plane";
|
|
ok =
|
|
!swarmServicesHere.services.hyperhive.deploy.swarm-controller.enable
|
|
&& !swarmServicesHere.services.hyperhive.deploy.swarm-ui.enable;
|
|
}
|
|
{
|
|
# Control for the arm above, and the one place this slice is not inert:
|
|
# the ports are opened because they were named, on a host that never
|
|
# turned the hive on. The bridge firewall is the host's own, so there is
|
|
# nothing here for the hive toggle to have been protecting.
|
|
name = "a named exposeHostPorts opens its bridge port on the host's own say-so";
|
|
ok = builtins.elem 5432 (bridgePortsOrNone exposedPortsNoHive);
|
|
}
|
|
{
|
|
name = "the swarm UI claims the swarm apex where this host serves it";
|
|
ok = swarmUiHere.services.nginx.virtualHosts ? "t.local";
|
|
}
|
|
{
|
|
# The swarm-services toggle enables them explicitly, from its own
|
|
# module rather than from any of their defaults.
|
|
name = "the swarm-services toggle turns on the gateway, resolver and bridge by itself";
|
|
ok =
|
|
swarmServicesOnly.services.hyperhive.gateway.enable
|
|
&& swarmServicesOnly.services.hyperhive.gateway.dns.enable
|
|
&& swarmServicesOnly.services.hyperhive.network.enable;
|
|
}
|
|
{
|
|
# An operator's explicit `false` beats every `mkDefault` assertion,
|
|
# which is what keeps "asserted by whoever needs it" from being a
|
|
# setting the operator cannot turn off.
|
|
name = "an explicit gateway.enable = false wins over the modules asserting it";
|
|
ok = !(hive { gateway.enable = false; }).services.nginx.enable;
|
|
}
|
|
{
|
|
name = "declared forge mirrors reach the swarm-controller, not hive-c0re";
|
|
ok =
|
|
builtins.fromJSON controllerWithMirrors.systemd.services.swarm-controller.environment.SWARM_CONTROLLER_FORGE_MIRRORS
|
|
== [ aMirror ]
|
|
&& !(controllerWithMirrors.systemd.services.hive-c0re.environment ? HYPERHIVE_FORGE_MIRRORS);
|
|
}
|
|
{
|
|
name = "forge mirrors on a host without the controller warn that nothing seeds them";
|
|
ok =
|
|
let
|
|
warns = cfg: lib.any (lib.hasInfix "declare them on the swarm-controller's host") cfg.warnings;
|
|
in
|
|
warns mirrorsNoController && !(warns controllerWithMirrors);
|
|
}
|
|
{
|
|
name = "the old c0re org-avatar option lands on the controller's unit";
|
|
ok =
|
|
controllerWithMirrors.systemd.services.swarm-controller.environment.SWARM_CONTROLLER_CONFIG_ORG_AVATAR_PNG
|
|
== "/etc/marker-avatar.png"
|
|
&& !(controllerWithMirrors.systemd.services.hive-c0re.environment ? HIVE_ORG_AVATAR_PNG);
|
|
}
|
|
];
|
|
in
|
|
runGroup "swarm-services-switch" cases
|