{ config, system, inputs ? (import ../../../default.nix { }).inputs, # XXX can't be serialized sources ? import ../../../npins, ... }@args: let # having this module's location (`self`) and (serializable) `args`, we know # enough to make it re-call itself to extract different info elsewhere later. # we use this to make a deployment script using the desired nixos config, # which would otherwise not be serializable, while nix also makes it hard to # produce its derivation to pass thru without a `nix-instantiate` call, # which in turn would need to be passed the (unserializable) nixos config. self = "deployment/check/common/data-model.nix"; inherit (sources) nixpkgs; pkgs = import nixpkgs { inherit system; }; inherit (pkgs) lib; deployment-config = config; inherit (deployment-config) nodeName pathToRoot targetSystem sshOpts ; inherit (lib) mkOption types; eval = module: (lib.evalModules { specialArgs = { inherit pkgs inputs; }; modules = [ module ../../data-model.nix ]; }).config; fediversity = eval ( { config, ... }: { config = { resources.login-shell = { description = "The operator needs to be able to log into the shell"; request = { ... }: { _class = "fediversity-resource-request"; options = { wheel = mkOption { description = "Whether the login user needs root permissions"; type = types.bool; default = false; }; packages = mkOption { description = "Packages that need to be available in the user environment"; type = with types; attrsOf package; }; }; }; policy = { config, ... }: { _class = "fediversity-resource-policy"; options = { username = mkOption { description = "Username for the operator"; type = types.str; # TODO: use the proper constraints from NixOS }; wheel = mkOption { description = "Whether to allow login with root permissions"; type = types.bool; default = false; }; }; config = { resource-type = types.raw; # TODO: splice out the user type from NixOS apply = requests: let # Filter out requests that need wheel if policy doesn't allow it validRequests = lib.filterAttrs ( _name: req: !req.login-shell.wheel || config.wheel ) requests.resources; in lib.optionalAttrs (validRequests != { }) { ${config.username} = { isNormalUser = true; packages = with lib; attrValues (concatMapAttrs (_name: request: request.login-shell.packages) validRequests); extraGroups = lib.optional config.wheel "wheel"; }; }; }; }; }; applications.hello = { ... }: { description = ''Command-line tool that will print "Hello, world!" on the terminal''; module = { ... }: { options.enable = lib.mkEnableOption "Hello in the shell"; }; implementation = cfg: { input = cfg; output.resources = lib.optionalAttrs cfg.enable { hello.login-shell.packages.hello = pkgs.hello; }; }; }; environments = let mkNixosConfiguration = environment: requests: { ... }: { imports = [ ./data-model-options.nix ../common/sharedOptions.nix ../common/targetNode.nix "${nixpkgs}/nixos/modules/profiles/qemu-guest.nix" ]; users.users = environment.config.resources."operator-environment".login-shell.apply { resources = lib.filterAttrs (_name: value: value ? login-shell) ( lib.concatMapAttrs ( k': req: lib.mapAttrs' (k: lib.nameValuePair "${k'}.${k}") req.resources ) requests ); }; }; in { single-nixos-vm-ssh = environment: { resources."operator-environment".login-shell.username = "operator"; implementation = { required-resources, deployment-name, }: { input = required-resources; output.ssh-host = { nixos-configuration = mkNixosConfiguration environment required-resources; system = targetSystem; ssh = { username = "root"; host = nodeName; key-file = null; inherit sshOpts; }; module = self; inherit args deployment-name; root-path = pathToRoot; }; }; }; single-nixos-vm-nixops4 = environment: { resources."operator-environment".login-shell.username = "operator"; implementation = requests: { input = requests; output.nixops4 = { providers, ... }: { providers = { inherit (inputs.nixops4.modules.nixops4Provider) local; }; resources.${nodeName} = { type = providers.local.exec; imports = [ inputs.nixops4-nixos.modules.nixops4Resource.nixos ../common/targetResource.nix ]; nixos.module = mkNixosConfiguration environment requests; _module.args = { inherit inputs sources; }; inherit (deployment-config) nodeName pathToRoot pathFromRoot; }; }; }; }; }; }; options = { "example-configuration" = mkOption { type = config.configuration; default = { enable = true; applications.hello.enable = true; }; }; "ssh-deployment" = let env = config.environments."single-nixos-vm-ssh"; in mkOption { type = env.resource-mapping.output-type; default = env.deployment { deployment-name = "ssh-deployment"; configuration = config."example-configuration"; }; }; "nixops4-deployment" = let env = config.environments."single-nixos-vm-nixops4"; in mkOption { type = env.resource-mapping.output-type; default = env.deployment { deployment-name = "nixops4-deployment"; configuration = config."example-configuration"; }; }; }; } ); in fediversity