diff --git a/deployment/check/common/data-model.nix b/deployment/check/common/data-model.nix deleted file mode 100644 index 81a798af..00000000 --- a/deployment/check/common/data-model.nix +++ /dev/null @@ -1,247 +0,0 @@ -{ - 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 - httpBackend - ; - inherit (lib) mkOption types; - inherit (pkgs.callPackage ../../utils.nix { inherit inputs; }) evalModel; - fediversity = evalModel ( - { 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: { - 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, - }: - { - 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 = - { - required-resources, - ... - }: - { - 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 required-resources; - _module.args = { inherit inputs sources; }; - inherit (deployment-config) nodeName pathToRoot pathFromRoot; - }; - }; - }; - }; - single-nixos-vm-tf = environment: { - resources."operator-environment".login-shell.username = "operator"; - implementation = - { - required-resources, - deployment-name, - }: - { - tf-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 httpBackend; - root-path = pathToRoot; - }; - }; - }; - }; - }; - 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"; - }; - }; - "tf-deployment" = - let - env = config.environments."single-nixos-vm-tf"; - in - mkOption { - type = env.resource-mapping.output-type; - default = env.deployment { - deployment-name = "tf-deployment"; - configuration = config."example-configuration"; - }; - }; - }; - } - ); -in -fediversity diff --git a/deployment/check/common/model.nix b/deployment/check/common/model.nix new file mode 100644 index 00000000..e0207893 --- /dev/null +++ b/deployment/check/common/model.nix @@ -0,0 +1,91 @@ +{ + config, + pkgs, + lib, + ... +}: +let + inherit (lib) mkOption types; +in +{ + 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: { + resources = lib.optionalAttrs cfg.enable { + hello.login-shell.packages.hello = pkgs.hello; + }; + }; + }; + + }; + options."example-configuration" = mkOption { + type = config.configuration; + default = { + enable = true; + applications.hello.enable = true; + }; + }; +} diff --git a/deployment/check/common/utils.nix b/deployment/check/common/utils.nix new file mode 100644 index 00000000..ba27c050 --- /dev/null +++ b/deployment/check/common/utils.nix @@ -0,0 +1,25 @@ +{ + lib, + sources ? import ../../../npins, + ... +}: +{ + mkNixosConfiguration = + environment: requests: + { ... }: + { + imports = [ + ../common/sharedOptions.nix + ../common/targetNode.nix + "${sources.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 + ); + }; + }; +} diff --git a/deployment/check/data-model-nixops4/data-model.nix b/deployment/check/data-model-nixops4/data-model.nix new file mode 100644 index 00000000..7ddbe3d9 --- /dev/null +++ b/deployment/check/data-model-nixops4/data-model.nix @@ -0,0 +1,64 @@ +{ + config, + system, + inputs, + sources ? import ../../../npins, + ... +}: +let + inherit (sources) nixpkgs; + pkgs = import nixpkgs { inherit system; }; + inherit (pkgs) lib; + inherit (pkgs.callPackage ../common/utils.nix { }) mkNixosConfiguration; + inherit (config) + nodeName + pathFromRoot + pathToRoot + ; +in +(pkgs.callPackage ../../utils.nix { inherit inputs; }).evalModel ( + { config, ... }: + { + imports = [ ../common/model.nix ]; + config = { + environments.default = environment: { + resources."operator-environment".login-shell.username = "operator"; + implementation = + { + required-resources, + ... + }: + { + 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 required-resources; + _module.args = { inherit inputs sources; }; + inherit nodeName pathToRoot pathFromRoot; + }; + }; + }; + }; + }; + options.default = + let + env = config.environments.default; + in + lib.mkOption { + type = env.resource-mapping.output-type; + default = env.deployment { + deployment-name = "default"; + configuration = config."example-configuration"; + }; + }; + } +) diff --git a/deployment/check/data-model-nixops4/flake-under-test.nix b/deployment/check/data-model-nixops4/flake-under-test.nix index 6a4ce06c..e9dbc484 100644 --- a/deployment/check/data-model-nixops4/flake-under-test.nix +++ b/deployment/check/data-model-nixops4/flake-under-test.nix @@ -17,13 +17,13 @@ ]; nixops4Deployments.check-deployment-model = - (import ./deployment/check/common/data-model.nix { + (import ./deployment/check/data-model-nixops4/data-model.nix { inherit system inputs; config = { inherit (import ./deployment/check/data-model-nixops4/constants.nix) pathToRoot pathFromRoot; nodeName = "nixops4"; }; - })."nixops4-deployment".nixops4; + }).default.nixops4; } ); } diff --git a/deployment/check/data-model-nixops4/nixosTest.nix b/deployment/check/data-model-nixops4/nixosTest.nix index e82bb8f5..79497a05 100644 --- a/deployment/check/data-model-nixops4/nixosTest.nix +++ b/deployment/check/data-model-nixops4/nixosTest.nix @@ -6,18 +6,15 @@ }: { _class = "nixosTest"; - imports = [ - ../common/data-model-options.nix - ]; - name = "deployment-model"; sourceFileset = lib.fileset.unions [ ../../data-model.nix ../../function.nix ../../utils.nix - ../common/data-model.nix - ../common/data-model-options.nix + ../common/model.nix + ../common/utils.nix ./constants.nix + ./data-model.nix (config.pathToCwd + "/flake-under-test.nix") ]; diff --git a/deployment/check/data-model-ssh/data-model.nix b/deployment/check/data-model-ssh/data-model.nix new file mode 100644 index 00000000..9245d7d1 --- /dev/null +++ b/deployment/check/data-model-ssh/data-model.nix @@ -0,0 +1,62 @@ +{ + config, + system, + sources ? import ../../../npins, + ... +}@args: +let + self = "deployment/check/data-model-ssh/data-model.nix"; + inherit (sources) nixpkgs; + pkgs = import nixpkgs { inherit system; }; + inherit (pkgs) lib; + inherit (pkgs.callPackage ../common/utils.nix { }) mkNixosConfiguration; + inherit (config) + nodeName + pathToRoot + targetSystem + sshOpts + ; +in +(pkgs.callPackage ../../utils.nix { }).evalModel ( + { config, ... }: + { + imports = [ ../common/model.nix ]; + config = { + environments.default = environment: { + resources."operator-environment".login-shell.username = "operator"; + implementation = + { + required-resources, + deployment-name, + ... + }: + { + 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; + }; + }; + }; + }; + options.default = + let + env = config.environments.default; + in + lib.mkOption { + type = env.resource-mapping.output-type; + default = env.deployment { + deployment-name = "default"; + configuration = config."example-configuration"; + }; + }; + } +) diff --git a/deployment/check/data-model-ssh/nixosTest.nix b/deployment/check/data-model-ssh/nixosTest.nix index 27743871..27e5bbb2 100644 --- a/deployment/check/data-model-ssh/nixosTest.nix +++ b/deployment/check/data-model-ssh/nixosTest.nix @@ -6,23 +6,21 @@ let inherit (pkgs) system; nodeName = "ssh"; - deployment-config = { - inherit nodeName; - inherit (import ./constants.nix) pathToRoot; - targetSystem = system; - sshOpts = [ ]; - }; deploy = - (import ../common/data-model.nix { + (import ./data-model.nix { inherit system; - config = deployment-config; - # opt not to pass `inputs`, as we could only pass serializable arguments through to its self-call - })."ssh-deployment".ssh-host.run; + config = { + inherit nodeName; + inherit (import ./constants.nix) pathToRoot; + targetSystem = system; + sshOpts = [ ]; + }; + }).default.ssh-host.run; in { _class = "nixosTest"; imports = [ - ../common/data-model-options.nix + ./options.nix ]; name = "deployment-model"; @@ -33,8 +31,7 @@ in ../../run/ssh-single-host/run.sh ../../../npins/default.nix ../../../npins/sources.json - ../common/data-model.nix - ../common/data-model-options.nix + ./options.nix ./constants.nix ]; diff --git a/deployment/check/data-model-ssh/options.nix b/deployment/check/data-model-ssh/options.nix new file mode 100644 index 00000000..34153b04 --- /dev/null +++ b/deployment/check/data-model-ssh/options.nix @@ -0,0 +1,15 @@ +{ + lib, + ... +}: +let + inherit (lib) mkOption types; +in +{ + options = { + targetSystem = mkOption { + type = types.str; + description = "name of the host to deploy to"; + }; + }; +} diff --git a/deployment/check/data-model-tf/data-model.nix b/deployment/check/data-model-tf/data-model.nix new file mode 100644 index 00000000..5b33d835 --- /dev/null +++ b/deployment/check/data-model-tf/data-model.nix @@ -0,0 +1,62 @@ +{ + config, + system, + sources ? import ../../../npins, + ... +}@args: +let + self = "deployment/check/data-model-tf/data-model.nix"; + inherit (sources) nixpkgs; + pkgs = import nixpkgs { inherit system; }; + inherit (pkgs) lib; + inherit (pkgs.callPackage ../common/utils.nix { }) mkNixosConfiguration; + inherit (config) + nodeName + pathToRoot + targetSystem + sshOpts + httpBackend + ; +in +(pkgs.callPackage ../../utils.nix { }).evalModel ( + { config, ... }: + { + imports = [ ../common/model.nix ]; + config = { + environments.default = environment: { + resources."operator-environment".login-shell.username = "operator"; + implementation = + { + required-resources, + deployment-name, + }: + { + tf-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 httpBackend; + root-path = pathToRoot; + }; + }; + }; + }; + options.default = + let + env = config.environments.default; + in + lib.mkOption { + type = env.resource-mapping.output-type; + default = env.deployment { + deployment-name = "default"; + configuration = config."example-configuration"; + }; + }; + } +) diff --git a/deployment/check/data-model-tf/nixosTest.nix b/deployment/check/data-model-tf/nixosTest.nix index 0246a4e3..b0ca8e20 100644 --- a/deployment/check/data-model-tf/nixosTest.nix +++ b/deployment/check/data-model-tf/nixosTest.nix @@ -9,29 +9,27 @@ let inherit (import ./constants.nix) pathToRoot; nodeName = "target"; backendPort = builtins.toString 8080; - deployment-config = { - inherit nodeName pathToRoot; - targetSystem = system; - sshOpts = [ ]; - httpBackend = rec { - TF_HTTP_USERNAME = "basic"; - TF_HTTP_PASSWORD = "fake-secret"; - TF_HTTP_ADDRESS = "http://localhost:${backendPort}/state/project1/example"; - TF_HTTP_LOCK_ADDRESS = TF_HTTP_ADDRESS; - TF_HTTP_UNLOCK_ADDRESS = TF_HTTP_ADDRESS; - }; - }; deploy = - (import ../common/data-model.nix { + (import ./data-model.nix { inherit system; - config = deployment-config; - # opt not to pass `inputs`, as we could only pass serializable arguments through to its self-call - })."tf-deployment".tf-host.run; + config = { + inherit nodeName pathToRoot; + targetSystem = system; + sshOpts = [ ]; + httpBackend = rec { + TF_HTTP_USERNAME = "basic"; + TF_HTTP_PASSWORD = "fake-secret"; + TF_HTTP_ADDRESS = "http://localhost:${backendPort}/state/project1/example"; + TF_HTTP_LOCK_ADDRESS = TF_HTTP_ADDRESS; + TF_HTTP_UNLOCK_ADDRESS = TF_HTTP_ADDRESS; + }; + }; + }).default.tf-host.run; in { _class = "nixosTest"; imports = [ - ../common/data-model-options.nix + ./options.nix ]; name = "deployment-model"; diff --git a/deployment/check/common/data-model-options.nix b/deployment/check/data-model-tf/options.nix similarity index 85% rename from deployment/check/common/data-model-options.nix rename to deployment/check/data-model-tf/options.nix index 63f306b3..0e415cf7 100644 --- a/deployment/check/common/data-model-options.nix +++ b/deployment/check/data-model-tf/options.nix @@ -7,10 +7,6 @@ let in { options = { - host = mkOption { - type = types.str; - description = "name of the host to deploy to"; - }; targetSystem = mkOption { type = types.str; description = "name of the host to deploy to"; diff --git a/deployment/data-model.nix b/deployment/data-model.nix index 12873107..3cc489f8 100644 --- a/deployment/data-model.nix +++ b/deployment/data-model.nix @@ -1,8 +1,8 @@ { + pkgs, lib, config, inputs, - pkgs, ... }: let @@ -36,6 +36,12 @@ let deployment-name, args, }: + # having a `module` location and (serializable) `args`, we know + # enough to call it again 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. builtins.toString ( pkgs.writers.writeText "configuration.nix" '' import ${root-path}/deployment/nixos.nix { @@ -126,6 +132,7 @@ let deployment-name = mkOption { description = "The name of the deployment for which to obtain the NixOS configuration."; type = types.str; + default = "default"; }; root-path = mkOption { description = "The path to the root of the repository."; @@ -451,9 +458,7 @@ in readOnly = true; default = submodule { options = { - enable = lib.mkEnableOption { - description = "your Fediversity configuration"; - }; + enable = lib.mkEnableOption "your Fediversity configuration"; applications = lib.mapAttrs ( _name: application: mkOption {