Advance forge rollout, Ethereum rails, and NBC sources

This commit is contained in:
every.channel 2026-04-01 15:58:49 -07:00
parent be26313225
commit 7d84510eac
No known key found for this signature in database
88 changed files with 11230 additions and 302 deletions

338
nix/modules/ec-netboot.nix Normal file
View file

@ -0,0 +1,338 @@
{ lib, config, pkgs, ... }:
let
cfg = config.services.every-channel.netboot;
scriptsRoot = ../..;
boolString = v: if v then "true" else "false";
mkExport = name: value: "export ${name}=${lib.escapeShellArg value}";
optionalExport = name: value:
if value == null then "" else mkExport name value;
optionalFileExport = name: path:
if path == null then ""
else ''
if [[ ! -r ${lib.escapeShellArg path} ]]; then
echo "error: required file is not readable: ${path}" >&2
exit 2
fi
export ${name}="$(tr -d '\\r\\n' < ${lib.escapeShellArg path})"
'';
stageToolchain = with pkgs; [
bash
coreutils
curl
gawk
gnugrep
gnused
gnutar
gzip
python3
];
ipxeToolchain = with pkgs; [
git
gnumake
gcc
binutils
perl
mtools
docker-client
];
in
{
options.services.every-channel.netboot = {
enable = lib.mkEnableOption "every.channel persistent netboot stage/serve services";
listenIP = lib.mkOption {
type = lib.types.str;
example = "10.20.30.2";
description = "IP address bound for TFTP/HTTP on the provisioning VLAN.";
};
interface = lib.mkOption {
type = lib.types.str;
example = "enp3s0";
description = "Network interface name on the provisioning VLAN.";
};
hostname = lib.mkOption {
type = lib.types.str;
default = "boot.every.channel";
description = "Boot server hostname advertised to DHCP/iPXE clients.";
};
rootDir = lib.mkOption {
type = lib.types.str;
default = "/var/lib/every-channel-netboot";
description = "Persistent root directory containing staged HTTP and TFTP artifacts.";
};
httpPort = lib.mkOption {
type = lib.types.port;
default = 8080;
description = "HTTP port used for kernel/initrd/netboot script serving.";
};
tftpBootFilename = lib.mkOption {
type = lib.types.str;
default = "ec-ipxe.efi";
description = "Filename served via TFTP (DHCP option 67 in UniFi-only mode).";
};
chainTokenFile = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
example = "/run/agenix/every-channel-netboot-chain-token";
description = "Optional file containing netboot chain token passed to stage/serve scripts.";
};
httpAllowedCIDRs = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
example = [ "10.20.30.0/24" ];
description = "Optional CIDR allowlist for HTTP artifact serving.";
};
openFirewall = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Open firewall ports for TFTP/HTTP (and ProxyDHCP ports when enabled).";
};
stageOnBoot = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Start the stage oneshot service during boot before serving.";
};
release = {
host = lib.mkOption {
type = lib.types.str;
default = "https://git.every.channel";
description = "Forge host used to fetch netboot release assets.";
};
repo = lib.mkOption {
type = lib.types.str;
default = "every-channel/every.channel";
description = "Forge repository containing netboot release assets.";
};
tag = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = "Optional release tag to stage; defaults to latest release.";
};
localTarball = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = "Optional local netboot tarball path; bypasses release API download when set.";
};
tokenFile = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = "Optional file containing Forge API token for private release access.";
};
verifyChecksums = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Verify staged release tarball using SHA256SUMS.txt when available.";
};
};
ipxe = {
buildEmbedded = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Build embedded iPXE (ec-ipxe.efi) before staging artifacts.";
};
path = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = "Optional prebuilt iPXE EFI binary path; used when buildEmbedded is false.";
};
allowRemoteDownload = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Allow remote iPXE URL download during staging. Disabled by default.";
};
sha256 = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = "Optional SHA256 digest expected for selected iPXE EFI binary.";
};
repo = lib.mkOption {
type = lib.types.str;
default = "https://github.com/ipxe/ipxe.git";
description = "iPXE source repository used for embedded EFI builds.";
};
ref = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = "Optional git ref/commit for iPXE build reproducibility.";
};
useDocker = lib.mkOption {
type = lib.types.enum [ "auto" "true" "false" ];
default = "auto";
description = "Container fallback mode for iPXE builds (auto/true/false).";
};
dockerImage = lib.mkOption {
type = lib.types.str;
default = "ubuntu:24.04";
description = "Docker image used when iPXE build runs in container mode.";
};
dockerPlatform = lib.mkOption {
type = lib.types.str;
default = "linux/amd64";
description = "Docker platform used for containerized iPXE build.";
};
};
proxyDhcp = {
enable = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Enable dnsmasq ProxyDHCP chainloading mode.";
};
subnet = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
example = "10.20.30.0/24";
description = "ProxyDHCP subnet (required when proxyDhcp.enable is true).";
};
};
};
config = lib.mkIf cfg.enable {
assertions = [
{
assertion = cfg.proxyDhcp.enable -> cfg.proxyDhcp.subnet != null;
message = "services.every-channel.netboot.proxyDhcp.subnet must be set when proxyDhcp.enable is true";
}
{
assertion = cfg.ipxe.buildEmbedded || cfg.ipxe.path != null || cfg.ipxe.allowRemoteDownload;
message = "Set ipxe.buildEmbedded=true, or provide ipxe.path, or allow ipxe.allowRemoteDownload=true";
}
];
systemd.tmpfiles.rules = [
"d ${cfg.rootDir} 0750 root root -"
"d ${cfg.rootDir}/http 0750 root root -"
"d ${cfg.rootDir}/tftp 0750 root root -"
];
systemd.services.every-channel-netboot-ipxe = lib.mkIf cfg.ipxe.buildEmbedded {
description = "every.channel netboot embedded iPXE build";
after = [ "network-online.target" ];
wants = [ "network-online.target" ];
wantedBy = lib.mkIf cfg.stageOnBoot [ "multi-user.target" ];
path = stageToolchain ++ ipxeToolchain;
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
script = ''
set -euo pipefail
${mkExport "EVERY_CHANNEL_NETBOOT_ROOT" cfg.rootDir}
${mkExport "EVERY_CHANNEL_NETBOOT_HOSTNAME" cfg.hostname}
${mkExport "EVERY_CHANNEL_NETBOOT_HTTP_PORT" (toString cfg.httpPort)}
${mkExport "EVERY_CHANNEL_NETBOOT_IPXE_FILENAME" cfg.tftpBootFilename}
${mkExport "EVERY_CHANNEL_NETBOOT_IPXE_REPO" cfg.ipxe.repo}
${optionalExport "EVERY_CHANNEL_NETBOOT_IPXE_REF" cfg.ipxe.ref}
${mkExport "EVERY_CHANNEL_NETBOOT_IPXE_USE_DOCKER" cfg.ipxe.useDocker}
${mkExport "EVERY_CHANNEL_NETBOOT_IPXE_DOCKER_IMAGE" cfg.ipxe.dockerImage}
${mkExport "EVERY_CHANNEL_NETBOOT_IPXE_DOCKER_PLATFORM" cfg.ipxe.dockerPlatform}
${optionalFileExport "EVERY_CHANNEL_NETBOOT_CHAIN_TOKEN" cfg.chainTokenFile}
${scriptsRoot}/scripts/netboot-build-ipxe.sh
'';
};
systemd.services.every-channel-netboot-stage = {
description = "every.channel netboot artifact stage";
requires = lib.optionals cfg.ipxe.buildEmbedded [ "every-channel-netboot-ipxe.service" ];
after = [ "network-online.target" ] ++ lib.optionals cfg.ipxe.buildEmbedded [ "every-channel-netboot-ipxe.service" ];
wants = [ "network-online.target" ] ++ lib.optionals cfg.ipxe.buildEmbedded [ "every-channel-netboot-ipxe.service" ];
wantedBy = lib.mkIf cfg.stageOnBoot [ "multi-user.target" ];
path = stageToolchain;
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
script = ''
set -euo pipefail
${mkExport "EVERY_CHANNEL_NETBOOT_ROOT" cfg.rootDir}
${mkExport "EVERY_CHANNEL_NETBOOT_HOSTNAME" cfg.hostname}
${mkExport "EVERY_CHANNEL_NETBOOT_HTTP_PORT" (toString cfg.httpPort)}
${mkExport "EVERY_CHANNEL_FORGE_HOST" cfg.release.host}
${mkExport "EVERY_CHANNEL_FORGE_REPO" cfg.release.repo}
${optionalExport "EVERY_CHANNEL_NETBOOT_RELEASE_TAG" cfg.release.tag}
${optionalExport "EVERY_CHANNEL_NETBOOT_TARBALL" cfg.release.localTarball}
${mkExport "EVERY_CHANNEL_NETBOOT_VERIFY_RELEASE_CHECKSUMS" (boolString cfg.release.verifyChecksums)}
${mkExport "EVERY_CHANNEL_NETBOOT_ALLOW_REMOTE_IPXE" (boolString cfg.ipxe.allowRemoteDownload)}
${mkExport "EVERY_CHANNEL_IPXE_EFI_FILENAME" cfg.tftpBootFilename}
${optionalExport "EVERY_CHANNEL_IPXE_EFI_SHA256" cfg.ipxe.sha256}
${optionalFileExport "EVERY_CHANNEL_FORGE_TOKEN" cfg.release.tokenFile}
${optionalFileExport "EVERY_CHANNEL_NETBOOT_CHAIN_TOKEN" cfg.chainTokenFile}
${lib.optionalString cfg.ipxe.buildEmbedded (mkExport "EVERY_CHANNEL_IPXE_EFI_PATH" "${cfg.rootDir}/tftp/${cfg.tftpBootFilename}")}
${lib.optionalString (!cfg.ipxe.buildEmbedded && cfg.ipxe.path != null) (mkExport "EVERY_CHANNEL_IPXE_EFI_PATH" cfg.ipxe.path)}
${scriptsRoot}/scripts/netboot-stage.sh
'';
};
systemd.services.every-channel-netboot = {
description = "every.channel netboot HTTP + TFTP service";
requires = [ "every-channel-netboot-stage.service" ];
after = [ "network-online.target" "every-channel-netboot-stage.service" ];
wants = [ "network-online.target" "every-channel-netboot-stage.service" ];
wantedBy = lib.mkIf cfg.stageOnBoot [ "multi-user.target" ];
path = stageToolchain ++ [ pkgs.dnsmasq ];
serviceConfig = {
Type = "simple";
Restart = "always";
RestartSec = "5s";
};
script = ''
set -euo pipefail
${mkExport "EVERY_CHANNEL_NETBOOT_ROOT" cfg.rootDir}
${mkExport "EVERY_CHANNEL_NETBOOT_LISTEN_IP" cfg.listenIP}
${mkExport "EVERY_CHANNEL_NETBOOT_INTERFACE" cfg.interface}
${mkExport "EVERY_CHANNEL_NETBOOT_HOSTNAME" cfg.hostname}
${mkExport "EVERY_CHANNEL_NETBOOT_HTTP_PORT" (toString cfg.httpPort)}
${mkExport "EVERY_CHANNEL_NETBOOT_PROXY_DHCP" (boolString cfg.proxyDhcp.enable)}
${optionalExport "EVERY_CHANNEL_NETBOOT_PROXY_SUBNET" cfg.proxyDhcp.subnet}
${mkExport "EVERY_CHANNEL_NETBOOT_TFTP_BOOT_FILENAME" cfg.tftpBootFilename}
${mkExport "EVERY_CHANNEL_NETBOOT_HTTP_ALLOWED_CIDRS" (lib.concatStringsSep "," cfg.httpAllowedCIDRs)}
${optionalFileExport "EVERY_CHANNEL_NETBOOT_CHAIN_TOKEN" cfg.chainTokenFile}
${scriptsRoot}/scripts/netboot-serve.sh
'';
};
networking.firewall.allowedTCPPorts = lib.mkIf cfg.openFirewall [ cfg.httpPort ];
networking.firewall.allowedUDPPorts = lib.mkIf cfg.openFirewall (
[ 69 ] ++ lib.optionals cfg.proxyDhcp.enable [ 67 4011 ]
);
};
}