{ config, lib, pkgs, ... }: let cfg = config.services.fleet-scheduler; in { options.services.fleet-scheduler = { enable = lib.mkEnableOption "fleet-scheduler service"; chainfireEndpoint = lib.mkOption { type = lib.types.str; default = "http://127.0.0.1:7000"; description = "ChainFire endpoint used by fleet-scheduler"; }; clusterNamespace = lib.mkOption { type = lib.types.str; default = "photoncloud"; description = "Cluster namespace prefix"; }; clusterId = lib.mkOption { type = lib.types.str; description = "Cluster ID to reconcile"; example = "plasmacloud-vm-cluster"; }; intervalSecs = lib.mkOption { type = lib.types.int; default = 15; description = "Scheduler reconciliation interval in seconds"; }; heartbeatTimeoutSecs = lib.mkOption { type = lib.types.int; default = 300; description = "Maximum node heartbeat age before a node becomes ineligible"; }; dryRun = lib.mkOption { type = lib.types.bool; default = false; description = "Log desired mutations without writing to ChainFire"; }; iamEndpoint = lib.mkOption { type = lib.types.nullOr lib.types.str; default = null; description = "IAM endpoint used for service publication"; }; fiberlbEndpoint = lib.mkOption { type = lib.types.nullOr lib.types.str; default = null; description = "FiberLB endpoint used for service publication"; }; flashdnsEndpoint = lib.mkOption { type = lib.types.nullOr lib.types.str; default = null; description = "FlashDNS endpoint used for service publication"; }; publishAddress = lib.mkOption { type = lib.types.nullOr lib.types.str; default = null; description = "Fallback address published into DNS when FiberLB does not allocate a VIP"; }; defaultOrgId = lib.mkOption { type = lib.types.str; default = "default-org"; description = "Default org_id used when service publication omits one"; }; defaultProjectId = lib.mkOption { type = lib.types.str; default = "default-project"; description = "Default project_id used when service publication omits one"; }; controllerPrincipalId = lib.mkOption { type = lib.types.str; default = "fleet-scheduler"; description = "Service-account principal used for publication controller tokens"; }; package = lib.mkOption { type = lib.types.package; default = pkgs.fleet-scheduler or (throw "fleet-scheduler package not found"); description = "Package to use for fleet-scheduler"; }; }; config = lib.mkIf cfg.enable { users.users.fleet-scheduler = { isSystemUser = true; group = "fleet-scheduler"; description = "Fleet scheduler service user"; home = "/var/lib/fleet-scheduler"; }; users.groups.fleet-scheduler = { }; systemd.services.fleet-scheduler = { description = "PhotonCloud Fleet Scheduler"; wantedBy = [ "multi-user.target" ]; after = [ "network-online.target" ]; wants = [ "network-online.target" ]; serviceConfig = { Type = "simple"; User = "fleet-scheduler"; Group = "fleet-scheduler"; Restart = "on-failure"; RestartSec = "5s"; StateDirectory = "fleet-scheduler"; StateDirectoryMode = "0750"; NoNewPrivileges = true; PrivateTmp = true; ProtectSystem = "strict"; ProtectHome = true; ExecStart = '' ${cfg.package}/bin/fleet-scheduler \ --chainfire-endpoint ${lib.escapeShellArg cfg.chainfireEndpoint} \ --cluster-namespace ${lib.escapeShellArg cfg.clusterNamespace} \ --cluster-id ${lib.escapeShellArg cfg.clusterId} \ --interval-secs ${toString cfg.intervalSecs} \ --heartbeat-timeout-secs ${toString cfg.heartbeatTimeoutSecs} \ ${lib.optionalString (cfg.iamEndpoint != null) "--iam-endpoint ${lib.escapeShellArg cfg.iamEndpoint}"} \ ${lib.optionalString (cfg.fiberlbEndpoint != null) "--fiberlb-endpoint ${lib.escapeShellArg cfg.fiberlbEndpoint}"} \ ${lib.optionalString (cfg.flashdnsEndpoint != null) "--flashdns-endpoint ${lib.escapeShellArg cfg.flashdnsEndpoint}"} \ ${lib.optionalString (cfg.publishAddress != null) "--publish-address ${lib.escapeShellArg cfg.publishAddress}"} \ --default-org-id ${lib.escapeShellArg cfg.defaultOrgId} \ --default-project-id ${lib.escapeShellArg cfg.defaultProjectId} \ --controller-principal-id ${lib.escapeShellArg cfg.controllerPrincipalId} \ ${lib.optionalString cfg.dryRun "--dry-run"} ''; }; }; }; }