photoncloud-monorepo/nix/single-node/base.nix

421 lines
13 KiB
Nix

{ config, lib, pkgs, ... }:
let
cfg = config.ultracloud.quickstart;
surface = import ./surface.nix;
coreServices = surface.vmPlatformCore;
optionalBundles = surface.optionalBundles;
coreServiceNames = map (service: service.name) coreServices;
localChainfire = "127.0.0.1:${toString config.services.chainfire.port}";
localChainfireHttp = "http://127.0.0.1:${toString config.services.chainfire.httpPort}";
localFlaredb = "127.0.0.1:${toString config.services.flaredb.port}";
localIamGrpc = "127.0.0.1:${toString config.services.iam.port}";
localIamHttp = "http://127.0.0.1:${toString config.services.iam.httpPort}";
localPrismnetGrpc = "127.0.0.1:${toString config.services.prismnet.port}";
localPrismnetHttp = "http://127.0.0.1:${toString config.services.prismnet.httpPort}";
localPlasmavmcHttp = "http://127.0.0.1:${toString config.services.plasmavmc.httpPort}";
localLightningstorGrpc = "127.0.0.1:${toString config.services.lightningstor.port}";
localCreditserviceGrpc = "127.0.0.1:${toString config.services.creditservice.grpcPort}";
localFiberlbHttp = "http://127.0.0.1:${toString config.services.fiberlb.port}";
localFlashdnsHttp = "http://127.0.0.1:${toString config.services.flashdns.port}";
localCoronafsHttp = "http://127.0.0.1:${toString config.services.coronafs.port}";
bundleEnabled = bundle: cfg.${bundle.option};
selectedOptionalBundles = lib.filter bundleEnabled optionalBundles;
requiredPackages =
map (service: builtins.getAttr service.packageAttr pkgs) coreServices
++ (with pkgs; [
curl
iproute2
jq
qemu
]);
optionalPackages =
lib.concatMap
(bundle: map (service: builtins.getAttr service.packageAttr pkgs) bundle.services)
selectedOptionalBundles;
requiredUnits = map (service: service.unit) coreServices;
optionalUnits =
lib.concatMap
(bundle: map (service: service.unit) bundle.services)
selectedOptionalBundles;
readyUnitArgs = lib.escapeShellArgs (requiredUnits ++ optionalUnits);
healthChecks =
map
(service: {
inherit (service) name;
url = service.healthUrl;
})
(lib.filter (service: service ? healthUrl) coreServices)
++ lib.concatMap
(bundle:
map
(service: {
inherit (service) name;
url = service.healthUrl;
})
(lib.filter (service: service ? healthUrl) bundle.services))
selectedOptionalBundles;
tcpPortChecks =
map
(service: {
inherit (service) name;
port = service.tcpPort;
})
(lib.filter (service: service ? tcpPort) coreServices)
++ lib.concatMap
(bundle:
map
(service: {
inherit (service) name;
port = service.tcpPort;
})
(lib.filter (service: service ? tcpPort) bundle.services))
selectedOptionalBundles;
healthCheckScript = lib.concatMapStringsSep "\n" (check: ''
wait_for_health ${lib.escapeShellArg check.name} ${lib.escapeShellArg check.url}
'') healthChecks;
tcpCheckScript = lib.concatMapStringsSep "\n" (check: ''
wait_for_tcp ${lib.escapeShellArg check.name} ${toString check.port}
'') tcpPortChecks;
optionalBundleManifest =
map
(bundle: {
inherit (bundle) option name summary;
services = map (service: service.name) bundle.services;
}
// lib.optionalAttrs (bundle ? requires) {
requires = bundle.requires;
})
optionalBundles;
quickstartSurfaceManifest = {
profile = "single-node dev";
coreServices = map (service: builtins.removeAttrs service [ "packageAttr" "unit" ]) coreServices;
optionalBundles = optionalBundleManifest;
enabledOptionalBundles = map (bundle: bundle.name) selectedOptionalBundles;
responsibilityBoundaries = surface.responsibilityBoundaries;
easyTrial = surface.easyTrial;
};
in
{
options.ultracloud.quickstart = {
enable = lib.mkEnableOption "UltraCloud single-node quickstart profile";
hostName = lib.mkOption {
type = lib.types.str;
default = "single-node-quickstart";
description = "Hostname used by the single-node quickstart profile.";
};
nodeId = lib.mkOption {
type = lib.types.str;
default = "single01";
description = "Node identifier for the single-node quickstart profile.";
};
enableLightningStor = lib.mkEnableOption "LightningStor object/image storage add-on for the quickstart";
enableCoronafs = lib.mkEnableOption "CoronaFS shared-volume add-on for the quickstart";
enableFlashDNS = lib.mkEnableOption "FlashDNS add-on for the quickstart";
enableFiberLB = lib.mkEnableOption "FiberLB add-on for the quickstart";
enableApiGateway = lib.mkEnableOption "API gateway add-on for the quickstart";
enableNightlight = lib.mkEnableOption "Nightlight metrics add-on for the quickstart";
enableCreditService = lib.mkEnableOption "CreditService reference add-on for the quickstart";
enableK8sHost = lib.mkEnableOption "K8sHost add-on for the quickstart";
};
config = lib.mkIf cfg.enable {
assertions = [
{
assertion = !cfg.enableK8sHost || (cfg.enableFiberLB && cfg.enableFlashDNS);
message = "ultracloud.quickstart.enableK8sHost requires ultracloud.quickstart.enableFiberLB and ultracloud.quickstart.enableFlashDNS.";
}
];
networking.hostName = lib.mkDefault cfg.hostName;
networking.useDHCP = lib.mkDefault true;
networking.vswitches = lib.mkDefault {};
networking.firewall.allowedTCPPorts = [
22
2379
2380
2381
2479
2480
50080
50081
50082
8081
8082
8083
8084
8087
]
++ (lib.optionals cfg.enableLightningStor [ 50086 50090 9000 ])
++ (lib.optionals cfg.enableCoronafs [ 50088 ])
++ (lib.optionals cfg.enableFlashDNS [ 50084 ])
++ (lib.optionals cfg.enableFiberLB [ 50085 ])
++ (lib.optionals cfg.enableApiGateway [ 8080 ])
++ (lib.optionals cfg.enableNightlight [ 9091 9101 ])
++ (lib.optionals cfg.enableCreditService [ 3010 3011 ])
++ (lib.optionals cfg.enableK8sHost [ 50087 8085 ]);
networking.firewall.allowedUDPPorts =
[ 2381 4789 ]
++ (lib.optionals cfg.enableFlashDNS [ 5353 ]);
boot.kernelModules = [ "kvm-intel" "kvm-amd" "tun" ];
boot.extraModprobeConfig = ''
options kvm_intel nested=1
options kvm_amd nested=1
'';
boot.kernel.sysctl = {
"fs.file-max" = 1000000;
"net.core.netdev_max_backlog" = 5000;
"net.core.rmem_max" = 134217728;
"net.core.wmem_max" = 134217728;
"net.ipv4.ip_forward" = 1;
"net.ipv6.conf.all.forwarding" = 1;
"vm.swappiness" = 10;
};
services.chainfire = {
enable = true;
nodeId = cfg.nodeId;
port = 2379;
raftPort = 2380;
gossipPort = 2381;
httpPort = 8081;
initialPeers = [ "${cfg.nodeId}=127.0.0.1:2380" ];
};
services.flaredb = {
enable = true;
nodeId = cfg.nodeId;
port = 2479;
raftPort = 2480;
httpPort = 8082;
initialPeers = [ "${cfg.nodeId}=127.0.0.1:2479" ];
pdAddr = localChainfire;
};
services.iam = {
enable = true;
port = 50080;
httpPort = 8083;
chainfireAddr = localChainfire;
flaredbAddr = localFlaredb;
allowRandomSigningKey = true;
allowUnauthenticatedAdmin = true;
};
services.prismnet = {
enable = true;
port = 50081;
httpPort = 8087;
iamAddr = localIamGrpc;
chainfireAddr = localChainfire;
flaredbAddr = localFlaredb;
};
services.plasmavmc = {
enable = true;
mode = "all-in-one";
port = 50082;
httpPort = 8084;
prismnetAddr = localPrismnetGrpc;
iamAddr = localIamGrpc;
chainfireAddr = localChainfire;
flaredbAddr = localFlaredb;
lightningstorAddr = if cfg.enableLightningStor then localLightningstorGrpc else null;
coronafsControllerEndpoint = if cfg.enableCoronafs then localCoronafsHttp else null;
coronafsNodeEndpoint = if cfg.enableCoronafs then localCoronafsHttp else null;
};
services.lightningstor = lib.mkIf cfg.enableLightningStor {
enable = true;
mode = "all-in-one";
objectStorageBackend = "local_fs";
iamAddr = localIamGrpc;
chainfireAddr = localChainfire;
flaredbAddr = localFlaredb;
};
services.coronafs = lib.mkIf cfg.enableCoronafs {
enable = true;
metadataBackend = "chainfire";
chainfireApiUrl = localChainfireHttp;
advertiseHost = "127.0.0.1";
};
services.flashdns = lib.mkIf cfg.enableFlashDNS {
enable = true;
iamAddr = localIamGrpc;
chainfireAddr = localChainfire;
flaredbAddr = localFlaredb;
};
services.fiberlb = lib.mkIf cfg.enableFiberLB {
enable = true;
iamAddr = localIamGrpc;
chainfireAddr = localChainfire;
flaredbAddr = localFlaredb;
};
services.creditservice = lib.mkIf cfg.enableCreditService {
enable = true;
iamAddr = localIamGrpc;
chainfireAddr = localChainfire;
flaredbAddr = localFlaredb;
};
services.nightlight = lib.mkIf cfg.enableNightlight {
enable = true;
};
services.deployer.enable = lib.mkDefault false;
services.nix-agent.enable = lib.mkDefault false;
services.node-agent.enable = lib.mkDefault false;
services.fleet-scheduler.enable = lib.mkDefault false;
services.apigateway = lib.mkIf cfg.enableApiGateway {
enable = true;
authProviders = [
{
name = "iam";
providerType = "grpc";
endpoint = localIamHttp;
}
];
creditProviders = lib.optionals cfg.enableCreditService [
{
name = "creditservice";
providerType = "grpc";
endpoint = "http://${localCreditserviceGrpc}";
}
];
routes =
[
{
name = "iam-rest";
pathPrefix = "/iam";
upstream = localIamHttp;
stripPrefix = true;
auth = {
provider = "iam";
mode = "required";
};
}
]
++ lib.optionals cfg.enableCreditService [
{
name = "credit-rest";
pathPrefix = "/credit";
upstream = "http://127.0.0.1:${toString config.services.creditservice.httpPort}";
stripPrefix = true;
auth = {
provider = "iam";
mode = "required";
};
credit = {
provider = "creditservice";
mode = "optional";
units = 1;
commitOn = "success";
};
}
];
};
services.k8shost = lib.mkIf cfg.enableK8sHost {
enable = true;
iamAddr = localIamHttp;
chainfireAddr = "http://${localChainfire}";
prismnetAddr = localPrismnetHttp;
flaredbPdAddr = localChainfire;
flaredbDirectAddr = localFlaredb;
fiberlbAddr = localFiberlbHttp;
flashdnsAddr = localFlashdnsHttp;
creditserviceAddr =
if cfg.enableCreditService
then "http://${localCreditserviceGrpc}"
else null;
};
environment.systemPackages = requiredPackages ++ optionalPackages;
environment.etc."ultracloud-product-surface.json".text =
builtins.toJSON quickstartSurfaceManifest;
systemd.services.ultracloud-single-node-quickstart-ready = {
description = "Verify UltraCloud single-node quickstart readiness";
wantedBy = [ "multi-user.target" ];
after = requiredUnits ++ optionalUnits;
wants = requiredUnits ++ optionalUnits;
path = [ pkgs.coreutils pkgs.curl pkgs.jq pkgs.netcat pkgs.qemu pkgs.systemd ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
};
script = ''
set -euo pipefail
wait_for_health() {
local name="$1"
local url="$2"
local deadline=$((SECONDS + 180))
while true; do
if curl -fsS "$url" >/dev/null 2>&1; then
return 0
fi
if [ "$SECONDS" -ge "$deadline" ]; then
echo "timed out waiting for $name at $url" >&2
return 1
fi
sleep 1
done
}
wait_for_tcp() {
local name="$1"
local port="$2"
local deadline=$((SECONDS + 180))
while true; do
if nc -z 127.0.0.1 "$port" >/dev/null 2>&1; then
return 0
fi
if [ "$SECONDS" -ge "$deadline" ]; then
echo "timed out waiting for $name TCP listener on $port" >&2
return 1
fi
sleep 1
done
}
systemctl is-active ${readyUnitArgs}
${healthCheckScript}
${tcpCheckScript}
test -x ${pkgs.qemu}/bin/qemu-system-x86_64
test -x ${pkgs.qemu}/bin/qemu-img
test -c /dev/net/tun
jq -e '.coreServices | map(.name) == ${builtins.toJSON coreServiceNames}' /etc/ultracloud-product-surface.json >/dev/null
jq -e '.easyTrial.kind == "vm-appliance"' /etc/ultracloud-product-surface.json >/dev/null
if [ -e /dev/kvm ]; then
test -r /dev/kvm
fi
'';
};
system.stateVersion = "24.11";
};
}