247 lines
8.4 KiB
Nix
247 lines
8.4 KiB
Nix
{ defaultPackage }:
|
|
{ config, lib, ... }:
|
|
let
|
|
cfg = config.services.lightscale-server;
|
|
meshEnabled =
|
|
cfg.meshServerId != null
|
|
|| cfg.meshListen != null
|
|
|| cfg.meshPeers != [ ]
|
|
|| cfg.meshCaCert != null
|
|
|| cfg.meshCert != null
|
|
|| cfg.meshKey != null;
|
|
|
|
args =
|
|
[ "--listen" cfg.listen ]
|
|
++ lib.optionals (cfg.dbUrl == null && cfg.dbUrlFile == null) [ "--state" cfg.stateFile ]
|
|
++ lib.optionals (cfg.dbUrl != null) [ "--db-url" cfg.dbUrl ]
|
|
++ lib.optionals (cfg.dbUrlFile != null) [ "--db-url-file" cfg.dbUrlFile ]
|
|
++ lib.optionals (cfg.adminToken != null) [ "--admin-token" cfg.adminToken ]
|
|
++ lib.optionals (cfg.stunServers != [ ]) [ "--stun" (lib.concatStringsSep "," cfg.stunServers) ]
|
|
++ lib.optionals (cfg.turnServers != [ ]) [ "--turn" (lib.concatStringsSep "," cfg.turnServers) ]
|
|
++ lib.optionals (cfg.streamRelayServers != [ ]) [ "--stream-relay" (lib.concatStringsSep "," cfg.streamRelayServers) ]
|
|
++ lib.optionals (cfg.udpRelayServers != [ ]) [ "--udp-relay" (lib.concatStringsSep "," cfg.udpRelayServers) ]
|
|
++ lib.optionals (cfg.udpRelayListen != null) [ "--udp-relay-listen" cfg.udpRelayListen ]
|
|
++ lib.optionals (cfg.streamRelayListen != null) [ "--stream-relay-listen" cfg.streamRelayListen ]
|
|
++ lib.optionals (cfg.meshServerId != null) [ "--mesh-server-id" cfg.meshServerId ]
|
|
++ lib.optionals (cfg.meshListen != null) [ "--mesh-listen" cfg.meshListen ]
|
|
++ lib.optionals (cfg.meshPeers != [ ]) [ "--mesh-peer" (lib.concatStringsSep "," cfg.meshPeers) ]
|
|
++ lib.optionals (cfg.meshCaCert != null) [ "--mesh-ca-cert" cfg.meshCaCert ]
|
|
++ lib.optionals (cfg.meshCert != null) [ "--mesh-cert" cfg.meshCert ]
|
|
++ lib.optionals (cfg.meshKey != null) [ "--mesh-key" cfg.meshKey ]
|
|
++ lib.optionals meshEnabled [ "--mesh-max-hops" (toString cfg.meshMaxHops) ]
|
|
++ cfg.extraArgs;
|
|
|
|
startCmd = "${lib.getExe' cfg.package "lightscale-server"} ${lib.escapeShellArgs args}";
|
|
in
|
|
{
|
|
options.services.lightscale-server = {
|
|
enable = lib.mkEnableOption "lightscale control-plane server";
|
|
|
|
package = lib.mkOption {
|
|
type = lib.types.package;
|
|
default = defaultPackage;
|
|
description = "lightscale-server package.";
|
|
};
|
|
|
|
listen = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = "0.0.0.0:8080";
|
|
description = "Listen address for the control plane.";
|
|
};
|
|
|
|
stateFile = lib.mkOption {
|
|
type = lib.types.str;
|
|
default = "/var/lib/lightscale-server/state.json";
|
|
description = "State file path when dbUrl is not set.";
|
|
};
|
|
|
|
dbUrl = lib.mkOption {
|
|
type = lib.types.nullOr lib.types.str;
|
|
default = null;
|
|
description = "Postgres/CockroachDB URL. If set, stateFile is ignored.";
|
|
};
|
|
|
|
dbUrlFile = lib.mkOption {
|
|
type = lib.types.nullOr lib.types.str;
|
|
default = null;
|
|
description = "Path to a file containing Postgres/CockroachDB URL. If set, stateFile is ignored.";
|
|
};
|
|
|
|
adminToken = lib.mkOption {
|
|
type = lib.types.nullOr lib.types.str;
|
|
default = null;
|
|
description = "Admin token passed via CLI. Prefer environmentFiles for secret handling.";
|
|
};
|
|
|
|
environmentFiles = lib.mkOption {
|
|
type = lib.types.listOf lib.types.str;
|
|
default = [ ];
|
|
description = "systemd EnvironmentFile entries (for LIGHTSCALE_ADMIN_TOKEN, etc.).";
|
|
};
|
|
|
|
environment = lib.mkOption {
|
|
type = lib.types.attrsOf lib.types.str;
|
|
default = { };
|
|
description = "Additional environment variables for the server service.";
|
|
};
|
|
|
|
stunServers = lib.mkOption {
|
|
type = lib.types.listOf lib.types.str;
|
|
default = [ ];
|
|
description = "STUN servers advertised to clients.";
|
|
};
|
|
|
|
turnServers = lib.mkOption {
|
|
type = lib.types.listOf lib.types.str;
|
|
default = [ ];
|
|
description = "TURN servers advertised to clients.";
|
|
};
|
|
|
|
streamRelayServers = lib.mkOption {
|
|
type = lib.types.listOf lib.types.str;
|
|
default = [ ];
|
|
description = "Stream relay servers advertised to clients.";
|
|
};
|
|
|
|
udpRelayServers = lib.mkOption {
|
|
type = lib.types.listOf lib.types.str;
|
|
default = [ ];
|
|
description = "UDP relay servers advertised to clients.";
|
|
};
|
|
|
|
udpRelayListen = lib.mkOption {
|
|
type = lib.types.nullOr lib.types.str;
|
|
default = null;
|
|
description = "UDP relay listen address.";
|
|
};
|
|
|
|
streamRelayListen = lib.mkOption {
|
|
type = lib.types.nullOr lib.types.str;
|
|
default = null;
|
|
description = "Stream relay listen address.";
|
|
};
|
|
|
|
meshServerId = lib.mkOption {
|
|
type = lib.types.nullOr lib.types.str;
|
|
default = null;
|
|
description = "Server id used for authenticated relay mesh.";
|
|
};
|
|
|
|
meshListen = lib.mkOption {
|
|
type = lib.types.nullOr lib.types.str;
|
|
default = null;
|
|
description = "Relay mesh listen address (mTLS).";
|
|
};
|
|
|
|
meshPeers = lib.mkOption {
|
|
type = lib.types.listOf lib.types.str;
|
|
default = [ ];
|
|
description = "Relay mesh peers in ID=HOST:PORT form.";
|
|
};
|
|
|
|
meshCaCert = lib.mkOption {
|
|
type = lib.types.nullOr lib.types.str;
|
|
default = null;
|
|
description = "Path to relay mesh CA certificate PEM.";
|
|
};
|
|
|
|
meshCert = lib.mkOption {
|
|
type = lib.types.nullOr lib.types.str;
|
|
default = null;
|
|
description = "Path to this server's relay mesh certificate PEM.";
|
|
};
|
|
|
|
meshKey = lib.mkOption {
|
|
type = lib.types.nullOr lib.types.str;
|
|
default = null;
|
|
description = "Path to this server's relay mesh private key PEM.";
|
|
};
|
|
|
|
meshMaxHops = lib.mkOption {
|
|
type = lib.types.ints.positive;
|
|
default = 4;
|
|
description = "Maximum relay mesh forwarding hops.";
|
|
};
|
|
|
|
extraArgs = lib.mkOption {
|
|
type = lib.types.listOf lib.types.str;
|
|
default = [ ];
|
|
description = "Additional CLI arguments for lightscale-server.";
|
|
};
|
|
|
|
openFirewall = lib.mkOption {
|
|
type = lib.types.bool;
|
|
default = false;
|
|
description = "Open firewall ports listed in firewallTCPPorts/firewallUDPPorts.";
|
|
};
|
|
|
|
firewallTCPPorts = lib.mkOption {
|
|
type = lib.types.listOf lib.types.port;
|
|
default = [ 8080 ];
|
|
description = "TCP ports to open when openFirewall=true.";
|
|
};
|
|
|
|
firewallUDPPorts = lib.mkOption {
|
|
type = lib.types.listOf lib.types.port;
|
|
default = [ ];
|
|
description = "UDP ports to open when openFirewall=true.";
|
|
};
|
|
};
|
|
|
|
config = lib.mkIf cfg.enable {
|
|
assertions = [
|
|
{
|
|
assertion = !(cfg.dbUrl != null && cfg.dbUrlFile != null);
|
|
message = "services.lightscale-server: set only one of dbUrl and dbUrlFile.";
|
|
}
|
|
{
|
|
assertion = cfg.adminToken != null || cfg.environment ? LIGHTSCALE_ADMIN_TOKEN || cfg.environmentFiles != [ ];
|
|
message = "services.lightscale-server: provide LIGHTSCALE_ADMIN_TOKEN via adminToken, environment, or environmentFiles.";
|
|
}
|
|
{
|
|
assertion = !meshEnabled || (
|
|
cfg.meshServerId != null
|
|
&& cfg.meshListen != null
|
|
&& cfg.meshCaCert != null
|
|
&& cfg.meshCert != null
|
|
&& cfg.meshKey != null
|
|
);
|
|
message = "services.lightscale-server: mesh requires meshServerId, meshListen, meshCaCert, meshCert, and meshKey.";
|
|
}
|
|
{
|
|
assertion = !meshEnabled || (cfg.streamRelayListen != null || cfg.udpRelayListen != null);
|
|
message = "services.lightscale-server: mesh forwarding requires streamRelayListen or udpRelayListen.";
|
|
}
|
|
];
|
|
|
|
users.groups.lightscale = { };
|
|
users.users.lightscale = {
|
|
isSystemUser = true;
|
|
group = "lightscale";
|
|
};
|
|
|
|
systemd.services.lightscale-server = {
|
|
description = "lightscale control-plane server";
|
|
wantedBy = [ "multi-user.target" ];
|
|
after = [ "network-online.target" ];
|
|
wants = [ "network-online.target" ];
|
|
environment = cfg.environment;
|
|
serviceConfig = {
|
|
Type = "simple";
|
|
ExecStart = startCmd;
|
|
Restart = "on-failure";
|
|
RestartSec = 2;
|
|
User = "lightscale";
|
|
Group = "lightscale";
|
|
WorkingDirectory = "/var/lib/lightscale-server";
|
|
StateDirectory = "lightscale-server";
|
|
RuntimeDirectory = "lightscale-server";
|
|
EnvironmentFile = cfg.environmentFiles;
|
|
NoNewPrivileges = true;
|
|
};
|
|
};
|
|
|
|
networking.firewall.allowedTCPPorts = lib.mkIf cfg.openFirewall cfg.firewallTCPPorts;
|
|
networking.firewall.allowedUDPPorts = lib.mkIf cfg.openFirewall cfg.firewallUDPPorts;
|
|
};
|
|
}
|