421 lines
13 KiB
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";
|
|
};
|
|
}
|