From f76d953b1f57492a419a00d8b58f0bce81ed7edd Mon Sep 17 00:00:00 2001 From: Valentin Gagarin Date: Tue, 29 Jul 2025 17:06:32 +0200 Subject: [PATCH 01/69] generalize function type --- deployment/data-model.nix | 9 ++++++--- deployment/function.nix | 9 ++++----- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/deployment/data-model.nix b/deployment/data-model.nix index 8f584af4..167e3c21 100644 --- a/deployment/data-model.nix +++ b/deployment/data-model.nix @@ -15,11 +15,13 @@ let ; functionType = import ./function.nix; - application-resources = { + application-resources = submodule { options.resources = mkOption { # TODO: maybe transpose, and group the resources by type instead type = attrsOf ( - attrTag (lib.mapAttrs (_name: resource: mkOption { type = resource.request; }) config.resources) + attrTag ( + lib.mapAttrs (_name: resource: mkOption { type = submodule resource.request; }) config.resources + ) ); }; }; @@ -52,12 +54,13 @@ in readOnly = true; default = input: (application.config.implementation input).output; }; + # TODO(@fricklerhandwerk): this needs a better name, it's just the type config-mapping = mkOption { description = "Function type for the mapping from application configuration to required resources"; type = submodule functionType; readOnly = true; default = { - input-type = application.config.module; + input-type = submodule application.config.module; output-type = application-resources; }; }; diff --git a/deployment/function.nix b/deployment/function.nix index d1a047f0..f0210a34 100644 --- a/deployment/function.nix +++ b/deployment/function.nix @@ -5,7 +5,6 @@ let inherit (lib) mkOption types; inherit (types) - deferredModule submodule functionTo optionType @@ -14,10 +13,10 @@ in { options = { input-type = mkOption { - type = deferredModule; + type = optionType; }; output-type = mkOption { - type = deferredModule; + type = optionType; }; function-type = mkOption { type = optionType; @@ -25,10 +24,10 @@ in default = functionTo (submodule { options = { input = mkOption { - type = submodule config.input-type; + type = config.input-type; }; output = mkOption { - type = submodule config.output-type; + type = config.output-type; }; }; }); -- 2.48.1 From 76a07a17ada2d83c10ce785f794b66c561ed4ed3 Mon Sep 17 00:00:00 2001 From: Valentin Gagarin Date: Tue, 29 Jul 2025 17:07:33 +0200 Subject: [PATCH 02/69] implement and test data model for runtime environments --- default.nix | 4 +- deployment/data-model-test.nix | 152 ++++++++++++++++++++++++++++++--- deployment/data-model.nix | 108 +++++++++++++++++++++++ 3 files changed, 250 insertions(+), 14 deletions(-) diff --git a/default.nix b/default.nix index 24b73cd2..e929e516 100644 --- a/default.nix +++ b/default.nix @@ -11,7 +11,8 @@ let ; inherit (pkgs) lib; inherit (import sources.flake-inputs) import-flake; - inherit ((import-flake { src = ./.; }).inputs) nixops4; + inputs = (import-flake { src = ./.; }).inputs; + inherit (inputs) nixops4; panel = import ./panel { inherit sources system; }; pre-commit-check = (import "${git-hooks}/nix" { @@ -78,6 +79,7 @@ in # re-export inputs so they can be overridden granularly # (they can't be accessed from the outside any other way) inherit + inputs sources system pkgs diff --git a/deployment/data-model-test.nix b/deployment/data-model-test.nix index ac35df39..72f05354 100644 --- a/deployment/data-model-test.nix +++ b/deployment/data-model-test.nix @@ -1,7 +1,7 @@ let inherit (import ../default.nix { }) pkgs inputs; inherit (pkgs) lib; - inherit (lib) mkOption; + inherit (lib) mkOption types; eval = module: (lib.evalModules { @@ -13,6 +13,8 @@ let ./data-model.nix ]; }).config; + nixops4Deployment = inputs.nixops4.modules.nixops4Deployment.default; + inherit (inputs.nixops4.lib) mkDeployment; in { _class = "nix-unit"; @@ -24,6 +26,59 @@ in { 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 + config.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 = { ... }: { @@ -31,15 +86,42 @@ in module = { ... }: { - options = { - enable = lib.mkEnableOption "Hello in the shell"; + options.enable = lib.mkEnableOption "Hello in the shell"; + }; + implementation = cfg: { + input = cfg; + output = lib.optionalAttrs cfg.enable { + resources.hello.login-shell.packages.hello = pkgs.hello; + }; + }; + }; + environments.single-nixos-vm = + { config, ... }: + { + resources.operator-environment.login-shell.username = "operator"; + implementation = requests: { + input = requests; + output = + { providers, ... }: + { + providers = { + inherit (inputs.nixops4.modules.nixops4Provider) local; + }; + resources.the-machine = { + type = providers.local.exec; + imports = [ + inputs.nixops4-nixos.modules.nixops4Resource.nixos + ]; + nixos.module = + { ... }: + { + users.users = config.resources.shell.login-shell.apply ( + lib.filterAttrs (_name: value: value ? login-shell) requests + ); + }; + }; }; - }; - implementation = - cfg: - lib.optionalAttrs cfg.enable { - dummy.login-shell.packages.hello = pkgs.hello; - }; + }; }; }; options = { @@ -51,20 +133,64 @@ in applications.hello.enable = true; }; }; + example-deployment = mkOption { + type = types.submodule nixops4Deployment; + readOnly = true; + default = config.environments.single-nixos-vm.deployment config.example-configuration; + }; }; } ); + resources = fediversity.applications.hello.resources fediversity.example-configuration.applications.hello; + hello-shell = (resources).resources.hello.login-shell; + environment = fediversity.environments.single-nixos-vm.resources.operator-environment.login-shell; + result = mkDeployment { + modules = [ + (fediversity.environments.single-nixos-vm.deployment fediversity.example-configuration) + ]; + }; + in - { - inherit (fediversity) - example-configuration - ; + rec { + number-of-resources = with lib; length (attrNames fediversity.resources); + inherit (fediversity) example-configuration; + hello-package-exists = hello-shell.packages ? hello; + wheel-required = hello-shell.wheel; + wheel-allowed = environment.wheel; + operator-shell = + let + operator = (environment.apply resources).operator; + in + { + inherit (operator) isNormalUser; + packages = with lib; map (p: "${p.pname}") operator.packages; + extraGroups = operator.extraGroups; + }; + deployment = { + inherit (result) _type; + deploymentFunction = lib.isFunction result.deploymentFunction; + getProviders = lib.isFunction result.getProviders; + }; }; expected = { + number-of-resources = 1; example-configuration = { enable = true; applications.hello.enable = true; }; + hello-package-exists = true; + wheel-required = false; + wheel-allowed = false; + operator-shell = { + isNormalUser = true; + packages = [ "hello" ]; + extraGroups = [ ]; + }; + deployment = { + _type = "nixops4Deployment"; + deploymentFunction = true; + getProviders = true; + }; }; }; } diff --git a/deployment/data-model.nix b/deployment/data-model.nix index 167e3c21..f005084b 100644 --- a/deployment/data-model.nix +++ b/deployment/data-model.nix @@ -1,6 +1,7 @@ { lib, config, + inputs, ... }: let @@ -25,11 +26,64 @@ let ); }; }; + nixops4Deployment = types.deferredModuleWith { + staticModules = [ + inputs.nixops4.modules.nixops4Deployment.default + + { + _module.args = { + resourceProviderSystem = builtins.currentSystem; + resources = { }; + }; + } + ]; + }; in { _class = "nixops4Deployment"; options = { + resources = mkOption { + description = "Collection of deployment resources that can be required by applications and policed by hosting providers"; + type = attrsOf ( + submodule ( + { ... }: + { + _class = "fediversity-resource"; + options = { + description = mkOption { + description = "Description of the resource to help application module authors and hosting providers to work with it"; + type = types.str; + }; + request = mkOption { + description = "Options for declaring resource requirements by an application, a description of how the resource is consumed or accessed"; + type = deferredModuleWith { staticModules = [ { _class = "fediversity-resource-request"; } ]; }; + }; + policy = mkOption { + description = "Options for configuring the resource policy for the hosting provider, a description of how the resource is made available"; + type = deferredModuleWith { + staticModules = [ + (policy: { + _class = "fediversity-resource-policy"; + options.resource-type = mkOption { + description = "The type of resource this policy configures"; + type = types.optionType; + }; + # TODO(@fricklerhandwerk): we may want to make the function type explict here: `request -> resource-type` + # and then also rename this to be consistent with the application's resource mapping + options.apply = mkOption { + description = "Apply the policy to a request"; + type = with types; functionTo policy.config.resource-type; + }; + }) + ]; + }; + }; + }; + } + ) + ); + }; applications = mkOption { description = "Collection of Fediversity applications"; type = attrsOf ( @@ -68,6 +122,60 @@ in }) ); }; + environments = mkOption { + description = "Run-time environments for Fediversity applications to be deployed to"; + type = attrsOf ( + submodule (environment: { + _class = "fediversity-environment"; + options = { + resources = mkOption { + description = '' + Resources made available by the hosting provider, and their policies. + + Setting this is optional, but provides a place to declare that information for programmatic use in the resource mapping. + ''; + # TODO: maybe transpose, and group the resources by type instead + type = attrsOf ( + attrTag ( + lib.mapAttrs (_name: resource: mkOption { type = submodule resource.policy; }) config.resources + ) + ); + }; + implementation = mkOption { + description = "Mapping of resources required by applications to available resources; the result can be deployed"; + type = environment.config.resource-mapping.function-type; + }; + resource-mapping = mkOption { + description = "Function type for the mapping from resources to a (NixOps4) deployment"; + type = submodule functionType; + readOnly = true; + default = { + input-type = application-resources; + output-type = nixops4Deployment; + }; + }; + # TODO(@fricklerhandwerk): maybe this should be a separate thing such as `fediversity-setup`, + # which makes explicit which applications and environments are available. + # then the deployments can simply be the result of the function application baked into this module. + deployment = mkOption { + description = "Generate a deployment from a configuration, by applying an environment's resource policies to the applications' resource mappings"; + type = functionTo (environment.config.resource-mapping.output-type); + readOnly = true; + default = + cfg: + # TODO: check cfg.enable.true + let + required-resources = lib.mapAttrs ( + name: application-settings: config.applications.${name}.resources application-settings + ) cfg.applications; + in + (environment.config.implementation required-resources).output; + + }; + }; + }) + ); + }; configuration = mkOption { description = "Configuration type declaring options to be set by operators"; type = optionType; -- 2.48.1 From d1d152d2df4c330b8e7d571e0aabfb08d33093d7 Mon Sep 17 00:00:00 2001 From: Valentin Gagarin Date: Tue, 29 Jul 2025 17:20:46 +0200 Subject: [PATCH 03/69] add explanatory comment --- deployment/data-model-test.nix | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/deployment/data-model-test.nix b/deployment/data-model-test.nix index 72f05354..2bb5de55 100644 --- a/deployment/data-model-test.nix +++ b/deployment/data-model-test.nix @@ -20,6 +20,15 @@ in _class = "nix-unit"; test-eval = { + /** + This tests a very simple arrangement that features all ingredients of the Fediversity business logic: + application, resource, environment, deployment; and wires it all up in one end-to-end exercise. + - The dummy resource is a login shell made available for some user. + - The dummy application is `hello` that requires a shell to be deployed. + - The dummy environment is a single NixOS VM that hosts one login shell, for the operator. + - The dummy configuration enables the `hello` application. + This will produce a NixOps4 deployment for a NixOS VM with a login shell for the operator and `hello` available. + */ expr = let fediversity = eval ( -- 2.48.1 From 1048ac674e643f089876b0a1bbc1f84ebe9420ff Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Thu, 31 Jul 2025 15:52:44 +0200 Subject: [PATCH 04/69] fix linter gripes --- deployment/data-model-test.nix | 6 +++--- deployment/data-model.nix | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/deployment/data-model-test.nix b/deployment/data-model-test.nix index 2bb5de55..cfce5db0 100644 --- a/deployment/data-model-test.nix +++ b/deployment/data-model-test.nix @@ -151,7 +151,7 @@ in } ); resources = fediversity.applications.hello.resources fediversity.example-configuration.applications.hello; - hello-shell = (resources).resources.hello.login-shell; + hello-shell = resources.resources.hello.login-shell; environment = fediversity.environments.single-nixos-vm.resources.operator-environment.login-shell; result = mkDeployment { modules = [ @@ -160,7 +160,7 @@ in }; in - rec { + { number-of-resources = with lib; length (attrNames fediversity.resources); inherit (fediversity) example-configuration; hello-package-exists = hello-shell.packages ? hello; @@ -172,7 +172,7 @@ in in { inherit (operator) isNormalUser; - packages = with lib; map (p: "${p.pname}") operator.packages; + packages = map (p: "${p.pname}") operator.packages; extraGroups = operator.extraGroups; }; deployment = { diff --git a/deployment/data-model.nix b/deployment/data-model.nix index f005084b..abe37e5e 100644 --- a/deployment/data-model.nix +++ b/deployment/data-model.nix @@ -73,7 +73,7 @@ in # and then also rename this to be consistent with the application's resource mapping options.apply = mkOption { description = "Apply the policy to a request"; - type = with types; functionTo policy.config.resource-type; + type = functionTo policy.config.resource-type; }; }) ]; -- 2.48.1 From c0b8dbbeeb88481aa05dc9f45a35cbebe0ecfd66 Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Thu, 31 Jul 2025 17:13:24 +0200 Subject: [PATCH 05/69] move nixops4Deployment class --- deployment/data-model.nix | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/deployment/data-model.nix b/deployment/data-model.nix index f005084b..d3977535 100644 --- a/deployment/data-model.nix +++ b/deployment/data-model.nix @@ -31,6 +31,7 @@ let inputs.nixops4.modules.nixops4Deployment.default { + _class = "nixops4Deployment"; _module.args = { resourceProviderSystem = builtins.currentSystem; resources = { }; @@ -40,8 +41,6 @@ let }; in { - _class = "nixops4Deployment"; - options = { resources = mkOption { description = "Collection of deployment resources that can be required by applications and policed by hosting providers"; -- 2.48.1 From e5b08faa1b7b524aa50e41a10d38338649557253 Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Thu, 31 Jul 2025 15:54:31 +0200 Subject: [PATCH 06/69] put `config` stuff in an attrset --- deployment/data-model-test.nix | 36 ++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/deployment/data-model-test.nix b/deployment/data-model-test.nix index cfce5db0..24d5cd6c 100644 --- a/deployment/data-model-test.nix +++ b/deployment/data-model-test.nix @@ -68,24 +68,26 @@ in default = false; }; }; - config.resource-type = types.raw; # TODO: splice out the user type from NixOS - config.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"; + 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 = -- 2.48.1 From d67f5a2b7df11f50091511948651d6feae7a8ece Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Sat, 9 Aug 2025 12:50:22 +0200 Subject: [PATCH 07/69] allow different deployment types --- deployment/data-model-test.nix | 7 +++---- deployment/data-model.nix | 10 ++++++++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/deployment/data-model-test.nix b/deployment/data-model-test.nix index 24d5cd6c..c65e37ae 100644 --- a/deployment/data-model-test.nix +++ b/deployment/data-model-test.nix @@ -13,7 +13,6 @@ let ./data-model.nix ]; }).config; - nixops4Deployment = inputs.nixops4.modules.nixops4Deployment.default; inherit (inputs.nixops4.lib) mkDeployment; in { @@ -32,7 +31,7 @@ in expr = let fediversity = eval ( - { config, ... }: + { config, options, ... }: { config = { resources.login-shell = { @@ -112,7 +111,7 @@ in resources.operator-environment.login-shell.username = "operator"; implementation = requests: { input = requests; - output = + output.nixops4 = { providers, ... }: { providers = { @@ -145,7 +144,7 @@ in }; }; example-deployment = mkOption { - type = types.submodule nixops4Deployment; + type = options.deployments.nestedType; readOnly = true; default = config.environments.single-nixos-vm.deployment config.example-configuration; }; diff --git a/deployment/data-model.nix b/deployment/data-model.nix index c3d5d53a..412f9bae 100644 --- a/deployment/data-model.nix +++ b/deployment/data-model.nix @@ -39,6 +39,12 @@ let } ]; }; + deployment = attrTag { + nixops4 = mkOption { + description = "A NixOps4 NixOS deployment. For an example, see https://github.com/nixops4/nixops4-nixos/blob/main/example/deployment.nix."; + type = nixops4Deployment; + }; + }; in { options = { @@ -145,12 +151,12 @@ in type = environment.config.resource-mapping.function-type; }; resource-mapping = mkOption { - description = "Function type for the mapping from resources to a (NixOps4) deployment"; + description = "Function type for the mapping from resources to a deployment"; type = submodule functionType; readOnly = true; default = { input-type = application-resources; - output-type = nixops4Deployment; + output-type = deployment; }; }; # TODO(@fricklerhandwerk): maybe this should be a separate thing such as `fediversity-setup`, -- 2.48.1 From b29b8bfb84791254d39ed1fcc78c5cc818872973 Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Fri, 1 Aug 2025 16:20:22 +0200 Subject: [PATCH 08/69] scaffold deployment/check/data-model from ./basic modelify --- .forgejo/workflows/ci.yaml | 6 + .../check/data-model/common-nixosTest.nix | 200 ++++++++++++++++++ deployment/check/data-model/constants.nix | 8 + deployment/check/data-model/default.nix | 14 ++ deployment/check/data-model/deployment.nix | 36 ++++ .../check/data-model/flake-under-test.nix | 22 ++ deployment/check/data-model/nixosTest.nix | 50 +++++ deployment/flake-part.nix | 5 + 8 files changed, 341 insertions(+) create mode 100644 deployment/check/data-model/common-nixosTest.nix create mode 100644 deployment/check/data-model/constants.nix create mode 100644 deployment/check/data-model/default.nix create mode 100644 deployment/check/data-model/deployment.nix create mode 100644 deployment/check/data-model/flake-under-test.nix create mode 100644 deployment/check/data-model/nixosTest.nix diff --git a/.forgejo/workflows/ci.yaml b/.forgejo/workflows/ci.yaml index 5015d407..629cce26 100644 --- a/.forgejo/workflows/ci.yaml +++ b/.forgejo/workflows/ci.yaml @@ -57,6 +57,12 @@ jobs: - uses: actions/checkout@v4 - run: nix build .#checks.x86_64-linux.deployment-panel -L + check-deployment-model: + runs-on: native + steps: + - uses: actions/checkout@v4 + - run: nix build .#checks.x86_64-linux.deployment-model -L + ## NOTE: NixOps4 does not provide a good “dry run” mode, so we instead check ## proxies for resources, namely whether their `.#vmOptions.` and ## `.#nixosConfigurations.` outputs evaluate and build correctly, and diff --git a/deployment/check/data-model/common-nixosTest.nix b/deployment/check/data-model/common-nixosTest.nix new file mode 100644 index 00000000..cb52ed9f --- /dev/null +++ b/deployment/check/data-model/common-nixosTest.nix @@ -0,0 +1,200 @@ +{ + inputs, + lib, + config, + hostPkgs, + sources, + ... +}: + +let + inherit (builtins) + concatStringsSep + toJSON + ; + inherit (lib) + types + fileset + mkOption + genAttrs + attrNames + optionalString + ; + inherit (hostPkgs) + runCommandNoCC + writeText + system + ; + + forConcat = xs: f: concatStringsSep "\n" (map f xs); + + ## We will need to override some inputs by the empty flake, so we make one. + emptyFlake = runCommandNoCC "empty-flake" { } '' + mkdir $out + echo "{ outputs = { self }: {}; }" > $out/flake.nix + ''; + +in +{ + _class = "nixosTest"; + + imports = [ + ./sharedOptions.nix + ]; + + options = { + ## FIXME: I wish I could just use `testScript` but with something like + ## `mkOrder` to put this module's string before something else. + extraTestScript = mkOption { }; + + sourceFileset = mkOption { + ## REVIEW: Upstream to nixpkgs? + type = types.mkOptionType { + name = "fileset"; + description = "fileset"; + descriptionClass = "noun"; + check = (x: (builtins.tryEval (fileset.unions [ x ])).success); + merge = (_: defs: fileset.unions (map (x: x.value) defs)); + }; + description = '' + A fileset that will be copied to the deployer node in the current + working directory. This should contain all the files that are + necessary to run that particular test, such as the NixOS + modules necessary to evaluate a deployment. + ''; + }; + }; + + config = { + sourceFileset = fileset.unions [ + # NOTE: not the flake itself; it will be overridden. + ../../../mkFlake.nix + ../../../flake.lock + ../../../npins + + ./sharedOptions.nix + ./targetNode.nix + ./targetResource.nix + + (config.pathToCwd + "/flake-under-test.nix") + ]; + + acmeNodeIP = config.nodes.acme.networking.primaryIPAddress; + + nodes = + { + deployer = { + imports = [ ./deployerNode.nix ]; + _module.args = { inherit inputs sources; }; + enableAcme = config.enableAcme; + acmeNodeIP = config.nodes.acme.networking.primaryIPAddress; + }; + } + + // + + ( + if config.enableAcme then + { + acme = { + ## FIXME: This makes `nodes.acme` into a local resolver. Maybe this will + ## break things once we play with DNS? + imports = [ "${inputs.nixpkgs}/nixos/tests/common/acme/server" ]; + ## We aren't testing ACME - we just want certificates. + systemd.services.pebble.environment.PEBBLE_VA_ALWAYS_VALID = "1"; + }; + } + else + { } + ) + + // + + genAttrs config.targetMachines (_: { + imports = [ ./targetNode.nix ]; + _module.args = { inherit inputs sources; }; + enableAcme = config.enableAcme; + acmeNodeIP = if config.enableAcme then config.nodes.acme.networking.primaryIPAddress else null; + }); + + testScript = '' + ${forConcat (attrNames config.nodes) (n: '' + ${n}.start() + '')} + + ${forConcat (attrNames config.nodes) (n: '' + ${n}.wait_for_unit("multi-user.target") + '')} + + ## A subset of the repository that is necessary for this test. It will be + ## copied inside the test. The smaller this set, the faster our CI, because we + ## won't need to re-run when things change outside of it. + with subtest("Unpacking"): + deployer.succeed("cp -r --no-preserve=mode ${ + fileset.toSource { + root = ../../..; + fileset = config.sourceFileset; + } + }/* .") + + with subtest("Configure the network"): + ${forConcat config.targetMachines ( + tm: + let + targetNetworkJSON = writeText "target-network.json" ( + toJSON config.nodes.${tm}.system.build.networkConfig + ); + in + '' + deployer.copy_from_host("${targetNetworkJSON}", "${config.pathFromRoot}/${tm}-network.json") + '' + )} + + with subtest("Configure the deployer key"): + deployer.succeed("""mkdir -p ~/.ssh && ssh-keygen -t rsa -N "" -f ~/.ssh/id_rsa""") + deployer_key = deployer.succeed("cat ~/.ssh/id_rsa.pub").strip() + ${forConcat config.targetMachines (tm: '' + ${tm}.succeed(f"mkdir -p /root/.ssh && echo '{deployer_key}' >> /root/.ssh/authorized_keys") + '')} + + with subtest("Configure the target host key"): + ${forConcat config.targetMachines (tm: '' + host_key = ${tm}.succeed("ssh-keyscan ${tm} | grep -v '^#' | cut -f 2- -d ' ' | head -n 1") + deployer.succeed(f"echo '{host_key}' > ${config.pathFromRoot}/${tm}_host_key.pub") + '')} + + ## NOTE: This is super slow. It could probably be optimised in Nix, for + ## instance by allowing to grab things directly from the host's store. + ## + ## NOTE: We use the repository as-is (cf `src` above), overriding only + ## `flake.nix` by our `flake-under-test.nix`. We also override the flake + ## lock file to use locally available inputs, as we cannot download them. + ## + with subtest("Override the flake and its lock"): + deployer.succeed("cp ${config.pathFromRoot}/flake-under-test.nix flake.nix") + deployer.succeed(""" + nix flake lock --extra-experimental-features 'flakes nix-command' \ + --offline -v \ + --override-input nixops4 ${inputs.nixops4.packages.${system}.flake-in-a-bottle} \ + \ + --override-input nixops4-nixos ${inputs.nixops4-nixos} \ + --override-input nixops4-nixos/flake-parts ${inputs.nixops4-nixos.inputs.flake-parts} \ + --override-input nixops4-nixos/flake-parts/nixpkgs-lib ${inputs.nixops4-nixos.inputs.flake-parts.inputs.nixpkgs-lib} \ + --override-input nixops4-nixos/nixops4-nixos ${emptyFlake} \ + --override-input nixops4-nixos/nixpkgs ${inputs.nixops4-nixos.inputs.nixpkgs} \ + --override-input nixops4-nixos/nixops4 ${ + inputs.nixops4-nixos.inputs.nixops4.packages.${system}.flake-in-a-bottle + } \ + --override-input nixops4-nixos/git-hooks-nix ${emptyFlake} \ + ; + """) + + ${optionalString config.enableAcme '' + with subtest("Set up handmade DNS"): + deployer.succeed("echo '${config.nodes.acme.networking.primaryIPAddress}' > ${config.pathFromRoot}/acme_server_ip") + ''} + + ${config.extraTestScript} + ''; + }; +} diff --git a/deployment/check/data-model/constants.nix b/deployment/check/data-model/constants.nix new file mode 100644 index 00000000..3cf28d8f --- /dev/null +++ b/deployment/check/data-model/constants.nix @@ -0,0 +1,8 @@ +{ + targetMachines = [ + "hello" + "cowsay" + ]; + pathToRoot = ../../..; + pathFromRoot = ./.; +} diff --git a/deployment/check/data-model/default.nix b/deployment/check/data-model/default.nix new file mode 100644 index 00000000..6479b6be --- /dev/null +++ b/deployment/check/data-model/default.nix @@ -0,0 +1,14 @@ +{ + runNixOSTest, + inputs, + sources, +}: + +runNixOSTest { + imports = [ + ../common/nixosTest.nix + ./nixosTest.nix + ]; + _module.args = { inherit inputs sources; }; + inherit (import ./constants.nix) targetMachines pathToRoot pathFromRoot; +} diff --git a/deployment/check/data-model/deployment.nix b/deployment/check/data-model/deployment.nix new file mode 100644 index 00000000..14a35ac6 --- /dev/null +++ b/deployment/check/data-model/deployment.nix @@ -0,0 +1,36 @@ +{ + inputs, + sources, + lib, + providers, + ... +}: + +let + inherit (import ./constants.nix) targetMachines pathToRoot pathFromRoot; +in + +{ + providers = { + inherit (inputs.nixops4.modules.nixops4Provider) local; + }; + + resources = lib.genAttrs targetMachines (nodeName: { + type = providers.local.exec; + + imports = [ + inputs.nixops4-nixos.modules.nixops4Resource.nixos + ../common/targetResource.nix + ]; + + _module.args = { inherit inputs sources; }; + + inherit nodeName pathToRoot pathFromRoot; + + nixos.module = + { pkgs, ... }: + { + environment.systemPackages = [ pkgs.${nodeName} ]; + }; + }); +} diff --git a/deployment/check/data-model/flake-under-test.nix b/deployment/check/data-model/flake-under-test.nix new file mode 100644 index 00000000..b9e3fb4b --- /dev/null +++ b/deployment/check/data-model/flake-under-test.nix @@ -0,0 +1,22 @@ +{ + inputs = { + nixops4.follows = "nixops4-nixos/nixops4"; + nixops4-nixos.url = "github:nixops4/nixops4-nixos"; + }; + + outputs = + inputs: + import ./mkFlake.nix inputs ( + { inputs, sources, ... }: + { + imports = [ + inputs.nixops4.modules.flake.default + ]; + + nixops4Deployments.check-deployment-basic = { + imports = [ ./deployment/check/basic/deployment.nix ]; + _module.args = { inherit inputs sources; }; + }; + } + ); +} diff --git a/deployment/check/data-model/nixosTest.nix b/deployment/check/data-model/nixosTest.nix new file mode 100644 index 00000000..d17ee833 --- /dev/null +++ b/deployment/check/data-model/nixosTest.nix @@ -0,0 +1,50 @@ +{ inputs, lib, ... }: + +{ + _class = "nixosTest"; + + name = "deployment-model"; + + sourceFileset = lib.fileset.unions [ + ../../data-model.nix + ../../function.nix + ./constants.nix + ./deployment.nix + ]; + + nodes.deployer = + { pkgs, ... }: + { + environment.systemPackages = [ + inputs.nixops4.packages.${pkgs.system}.default + ]; + + # FIXME: sad times + system.extraDependencies = with pkgs; [ + jq + jq.inputDerivation + ]; + + system.extraDependenciesFromModule = + { pkgs, ... }: + { + environment.systemPackages = with pkgs; [ + hello + cowsay + ]; + }; + }; + + extraTestScript = '' + with subtest("Check the status before deployment"): + hello.fail("hello 1>&2") + cowsay.fail("cowsay 1>&2") + + with subtest("Run the deployment"): + deployer.succeed("nixops4 apply check-deployment-basic --show-trace --no-interactive 1>&2") + + with subtest("Check the deployment"): + hello.succeed("hello 1>&2") + cowsay.succeed("cowsay hi 1>&2") + ''; +} diff --git a/deployment/flake-part.nix b/deployment/flake-part.nix index 952fc694..ca80f247 100644 --- a/deployment/flake-part.nix +++ b/deployment/flake-part.nix @@ -21,6 +21,11 @@ inherit (pkgs.testers) runNixOSTest; inherit inputs sources; }; + + deployment-model = import ./check/data-model { + inherit (pkgs.testers) runNixOSTest; + inherit inputs sources; + }; }; }; } -- 2.48.1 From 8e50fd675f293678b0f12b31e6ece8d72994cb87 Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Sat, 9 Aug 2025 23:31:25 +0200 Subject: [PATCH 09/69] un-nixops --- deployment/check/common/deployerNode.nix | 5 +- .../check/data-model/common-nixosTest.nix | 52 ++++------------- deployment/check/data-model/default.nix | 4 +- deployment/check/data-model/deployment.nix | 58 ++++++++++--------- .../check/data-model/flake-under-test.nix | 22 ------- deployment/check/data-model/nixosTest.nix | 8 +-- deployment/data-model.nix | 18 ------ 7 files changed, 49 insertions(+), 118 deletions(-) delete mode 100644 deployment/check/data-model/flake-under-test.nix diff --git a/deployment/check/common/deployerNode.nix b/deployment/check/common/deployerNode.nix index 987a0a7c..4e0dd2de 100644 --- a/deployment/check/common/deployerNode.nix +++ b/deployment/check/common/deployerNode.nix @@ -54,11 +54,8 @@ in system.extraDependencies = [ - inputs.nixops4 - inputs.nixops4-nixos - inputs.nixpkgs + sources.nixpkgs - sources.flake-parts sources.flake-inputs sources.git-hooks diff --git a/deployment/check/data-model/common-nixosTest.nix b/deployment/check/data-model/common-nixosTest.nix index cb52ed9f..aa912dc3 100644 --- a/deployment/check/data-model/common-nixosTest.nix +++ b/deployment/check/data-model/common-nixosTest.nix @@ -21,25 +21,17 @@ let optionalString ; inherit (hostPkgs) - runCommandNoCC writeText - system ; forConcat = xs: f: concatStringsSep "\n" (map f xs); - ## We will need to override some inputs by the empty flake, so we make one. - emptyFlake = runCommandNoCC "empty-flake" { } '' - mkdir $out - echo "{ outputs = { self }: {}; }" > $out/flake.nix - ''; - in { _class = "nixosTest"; imports = [ - ./sharedOptions.nix + ../common/sharedOptions.nix ]; options = { @@ -67,16 +59,15 @@ in config = { sourceFileset = fileset.unions [ - # NOTE: not the flake itself; it will be overridden. ../../../mkFlake.nix ../../../flake.lock ../../../npins + ../../data-model.nix + ../../function.nix - ./sharedOptions.nix - ./targetNode.nix - ./targetResource.nix - - (config.pathToCwd + "/flake-under-test.nix") + ../common/sharedOptions.nix + ../common/targetNode.nix + ../common/targetResource.nix ]; acmeNodeIP = config.nodes.acme.networking.primaryIPAddress; @@ -84,7 +75,7 @@ in nodes = { deployer = { - imports = [ ./deployerNode.nix ]; + imports = [ ../common/deployerNode.nix ]; _module.args = { inherit inputs sources; }; enableAcme = config.enableAcme; acmeNodeIP = config.nodes.acme.networking.primaryIPAddress; @@ -111,7 +102,7 @@ in // genAttrs config.targetMachines (_: { - imports = [ ./targetNode.nix ]; + imports = [ ../common/targetNode.nix ]; _module.args = { inherit inputs sources; }; enableAcme = config.enableAcme; acmeNodeIP = if config.enableAcme then config.nodes.acme.networking.primaryIPAddress else null; @@ -163,31 +154,8 @@ in deployer.succeed(f"echo '{host_key}' > ${config.pathFromRoot}/${tm}_host_key.pub") '')} - ## NOTE: This is super slow. It could probably be optimised in Nix, for - ## instance by allowing to grab things directly from the host's store. - ## - ## NOTE: We use the repository as-is (cf `src` above), overriding only - ## `flake.nix` by our `flake-under-test.nix`. We also override the flake - ## lock file to use locally available inputs, as we cannot download them. - ## - with subtest("Override the flake and its lock"): - deployer.succeed("cp ${config.pathFromRoot}/flake-under-test.nix flake.nix") - deployer.succeed(""" - nix flake lock --extra-experimental-features 'flakes nix-command' \ - --offline -v \ - --override-input nixops4 ${inputs.nixops4.packages.${system}.flake-in-a-bottle} \ - \ - --override-input nixops4-nixos ${inputs.nixops4-nixos} \ - --override-input nixops4-nixos/flake-parts ${inputs.nixops4-nixos.inputs.flake-parts} \ - --override-input nixops4-nixos/flake-parts/nixpkgs-lib ${inputs.nixops4-nixos.inputs.flake-parts.inputs.nixpkgs-lib} \ - --override-input nixops4-nixos/nixops4-nixos ${emptyFlake} \ - --override-input nixops4-nixos/nixpkgs ${inputs.nixops4-nixos.inputs.nixpkgs} \ - --override-input nixops4-nixos/nixops4 ${ - inputs.nixops4-nixos.inputs.nixops4.packages.${system}.flake-in-a-bottle - } \ - --override-input nixops4-nixos/git-hooks-nix ${emptyFlake} \ - ; - """) + # with subtest("Override the flake and its lock"): + # deployer.succeed("cp ${config.pathFromRoot}/flake-under-test.nix flake.nix") ${optionalString config.enableAcme '' with subtest("Set up handmade DNS"): diff --git a/deployment/check/data-model/default.nix b/deployment/check/data-model/default.nix index 6479b6be..5eafbbbc 100644 --- a/deployment/check/data-model/default.nix +++ b/deployment/check/data-model/default.nix @@ -6,7 +6,9 @@ runNixOSTest { imports = [ - ../common/nixosTest.nix + ../../data-model.nix + ../../function.nix + ./common-nixosTest.nix ./nixosTest.nix ]; _module.args = { inherit inputs sources; }; diff --git a/deployment/check/data-model/deployment.nix b/deployment/check/data-model/deployment.nix index 14a35ac6..2074edc0 100644 --- a/deployment/check/data-model/deployment.nix +++ b/deployment/check/data-model/deployment.nix @@ -1,36 +1,40 @@ { inputs, - sources, + # sources, lib, - providers, + # providers, ... }: let - inherit (import ./constants.nix) targetMachines pathToRoot pathFromRoot; -in - -{ - providers = { - inherit (inputs.nixops4.modules.nixops4Provider) local; - }; - - resources = lib.genAttrs targetMachines (nodeName: { - type = providers.local.exec; - - imports = [ - inputs.nixops4-nixos.modules.nixops4Resource.nixos - ../common/targetResource.nix - ]; - - _module.args = { inherit inputs sources; }; - - inherit nodeName pathToRoot pathFromRoot; - - nixos.module = - { pkgs, ... }: - { - environment.systemPackages = [ pkgs.${nodeName} ]; + # inherit (import ./constants.nix) targetMachines pathToRoot pathFromRoot; + eval = + module: + (lib.evalModules { + specialArgs = { + inherit inputs; }; - }); + modules = [ + module + ../../data-model.nix + ]; + }).config; + fediversity = eval ( + { ... }: + { + config = { + environments.single-nixos-vm = + { ... }: + { + implementation = requests: { + input = requests; + output = { }; + }; + }; + }; + } + ); +in +fediversity.environments.single-nixos-vm.deployment { + enable = true; } diff --git a/deployment/check/data-model/flake-under-test.nix b/deployment/check/data-model/flake-under-test.nix deleted file mode 100644 index b9e3fb4b..00000000 --- a/deployment/check/data-model/flake-under-test.nix +++ /dev/null @@ -1,22 +0,0 @@ -{ - inputs = { - nixops4.follows = "nixops4-nixos/nixops4"; - nixops4-nixos.url = "github:nixops4/nixops4-nixos"; - }; - - outputs = - inputs: - import ./mkFlake.nix inputs ( - { inputs, sources, ... }: - { - imports = [ - inputs.nixops4.modules.flake.default - ]; - - nixops4Deployments.check-deployment-basic = { - imports = [ ./deployment/check/basic/deployment.nix ]; - _module.args = { inherit inputs sources; }; - }; - } - ); -} diff --git a/deployment/check/data-model/nixosTest.nix b/deployment/check/data-model/nixosTest.nix index d17ee833..b07b376f 100644 --- a/deployment/check/data-model/nixosTest.nix +++ b/deployment/check/data-model/nixosTest.nix @@ -1,4 +1,7 @@ -{ inputs, lib, ... }: +{ + lib, + ... +}: { _class = "nixosTest"; @@ -15,9 +18,6 @@ nodes.deployer = { pkgs, ... }: { - environment.systemPackages = [ - inputs.nixops4.packages.${pkgs.system}.default - ]; # FIXME: sad times system.extraDependencies = with pkgs; [ diff --git a/deployment/data-model.nix b/deployment/data-model.nix index 412f9bae..dd7ada19 100644 --- a/deployment/data-model.nix +++ b/deployment/data-model.nix @@ -1,7 +1,6 @@ { lib, config, - inputs, ... }: let @@ -26,24 +25,7 @@ let ); }; }; - nixops4Deployment = types.deferredModuleWith { - staticModules = [ - inputs.nixops4.modules.nixops4Deployment.default - - { - _class = "nixops4Deployment"; - _module.args = { - resourceProviderSystem = builtins.currentSystem; - resources = { }; - }; - } - ]; - }; deployment = attrTag { - nixops4 = mkOption { - description = "A NixOps4 NixOS deployment. For an example, see https://github.com/nixops4/nixops4-nixos/blob/main/example/deployment.nix."; - type = nixops4Deployment; - }; }; in { -- 2.48.1 From 5c47da3b0b50cb760e32e5c686d20c6ecb3b0a1b Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Sun, 10 Aug 2025 13:18:44 +0200 Subject: [PATCH 10/69] add deployment method: ssh --- deployment/check/data-model/deployment.nix | 17 ++++++- deployment/data-model.nix | 53 ++++++++++++++++++++-- 2 files changed, 65 insertions(+), 5 deletions(-) diff --git a/deployment/check/data-model/deployment.nix b/deployment/check/data-model/deployment.nix index 2074edc0..135b9944 100644 --- a/deployment/check/data-model/deployment.nix +++ b/deployment/check/data-model/deployment.nix @@ -2,7 +2,7 @@ inputs, # sources, lib, - # providers, + config, ... }: @@ -28,7 +28,20 @@ let { implementation = requests: { input = requests; - output = { }; + output.ssh-host = { + ssh = { + host = "localhost"; + username = "root"; + authentication.password = "password"; + }; + nixos-configuration = + { ... }: + { + users.users = config.resources.shell.login-shell.apply ( + lib.filterAttrs (_name: value: value ? login-shell) requests + ); + }; + }; }; }; }; diff --git a/deployment/data-model.nix b/deployment/data-model.nix index dd7ada19..230e18f1 100644 --- a/deployment/data-model.nix +++ b/deployment/data-model.nix @@ -6,12 +6,15 @@ let inherit (lib) mkOption types; inherit (lib.types) - attrsOf attrTag + attrsOf deferredModuleWith - submodule - optionType functionTo + nullOr + optionType + raw + str + submodule ; functionType = import ./function.nix; @@ -25,7 +28,51 @@ let ); }; }; + nixos-configuration = mkOption { + description = "A NixOS configuration."; + type = raw; + }; + host-ssh = mkOption { + description = "SSH connection info to connect to a single host."; + type = submodule { + options = { + host = mkOption { + description = "the host to access by SSH"; + type = str; + }; + username = mkOption { + description = "the SSH user to use"; + type = nullOr str; + default = null; + }; + authentication = mkOption { + description = "authentication method"; + type = attrTag { + private-key = mkOption { + description = "path to the user's SSH private key"; + type = str; + example = "/root/.ssh/id_ed25519"; + }; + password = mkOption { + description = "SSH password"; + # TODO: mark as sensitive + type = str; + }; + }; + }; + }; + }; + }; deployment = attrTag { + ssh-host = { + description = "A Terraform deployment by SSH to update a single existing NixOS host."; + type = submodule { + options = { + inherit nixos-configuration; + ssh = host-ssh; + }; + }; + }; }; in { -- 2.48.1 From 0d36f32190d302d3e7df51b01ebb00b1da2d5d4a Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Thu, 14 Aug 2025 10:44:36 +0200 Subject: [PATCH 11/69] wip: use ssh in test --- deployment/check/data-model/nixosTest.nix | 83 ++++++++++++++++++++++- deployment/nixos.nix | 14 ++++ 2 files changed, 94 insertions(+), 3 deletions(-) create mode 100644 deployment/nixos.nix diff --git a/deployment/check/data-model/nixosTest.nix b/deployment/check/data-model/nixosTest.nix index b07b376f..beaa9c20 100644 --- a/deployment/check/data-model/nixosTest.nix +++ b/deployment/check/data-model/nixosTest.nix @@ -1,8 +1,12 @@ { lib, + config, + sources, ... }: - +let + inherit (import ./constants.nix) targetMachines pathToRoot; +in { _class = "nixosTest"; @@ -19,6 +23,10 @@ { pkgs, ... }: { + environment.systemPackages = with pkgs; [ + jq + ]; + # FIXME: sad times system.extraDependencies = with pkgs; [ jq @@ -40,8 +48,77 @@ hello.fail("hello 1>&2") cowsay.fail("cowsay 1>&2") - with subtest("Run the deployment"): - deployer.succeed("nixops4 apply check-deployment-basic --show-trace --no-interactive 1>&2") + ${lib.concatStringsSep "\n" ( + lib.lists.map (nodeName: '' + with subtest("Run the deployment for ${nodeName}"): + deployer.succeed(""" + set -euo pipefail + + # INSTANTIATE + command=( + nix-instantiate + --expr + + ' + let + system = builtins.currentSystem; + configuration = { pkgs, config, ... }: { + imports = [ + ${pathToRoot}/deployment/check/common/sharedOptions.nix + ${pathToRoot}/deployment/check/common/targetNode.nix + ]; + + _module.args = builtins.fromJSON "${ + lib.replaceStrings [ "\"" ] [ "\\\\\"" ] ( + lib.strings.toJSON { + inherit sources; + } + ) + }"; + enableAcme = ${lib.strings.toJSON config.enableAcme}; + acmeNodeIP = if config.enableAcme then config.nodes.acme.networking.primaryIPAddress else null; + + # environment.systemPackages = [ pkgs.hello ]; + }; + os = import "${sources.nixpkgs}/nixos" { inherit system configuration; }; + in + # import "${pathToRoot}/deployment/nixos.nix" {} + { + substituters = builtins.concatStringsSep " " os.config.nix.settings.substituters; + trusted_public_keys = builtins.concatStringsSep " " os.config.nix.settings.trusted-public-keys; + drv_path = os.config.system.build.toplevel.drvPath; + out_path = os.config.system.build.toplevel; + } + ' + ) + # instantiate the config in /nix/store + "''${command[@]}" -A out_path + # get the other info + json="$("''${command[@]}" --eval --strict --json)" + + # DEPLOY + declare substituters trusted_public_keys drv_path + # set our variables using the json object + eval "export $(echo $json | jq -r 'to_entries | map("\(.key)=\(.value)") | @sh')" + host="root@${nodeName}" + buildArgs=( + --option extra-binary-caches https://cache.nixos.org/ + --option substituters $substituters + --option trusted-public-keys $trusted_public_keys + ) + sshOpts=( + -o BatchMode=yes + -o StrictHostKeyChecking=no + ) + # get the realized derivation to deploy + outPath=$(nix-store --realize "$drv_path" "''${buildArgs[@]}") + # deploy the config by nix-copy-closure + NIX_SSHOPTS="''${sshOpts[*]}" nix-copy-closure --to "$host" "$outPath" --gzip --use-substitutes + # switch the remote host to the config + ssh "''${sshOpts[@]}" "$host" "nix-env --profile /nix/var/nix/profiles/system --set $outPath; $outPath/bin/switch-to-configuration switch" + """) + '') targetMachines + )} with subtest("Check the deployment"): hello.succeed("hello 1>&2") diff --git a/deployment/nixos.nix b/deployment/nixos.nix new file mode 100644 index 00000000..f2f0d019 --- /dev/null +++ b/deployment/nixos.nix @@ -0,0 +1,14 @@ +{ + configuration, + system ? builtins.currentSystem, +}: +let + sources = import ../npins; + os = import "${sources.nixpkgs}/nixos" { inherit system configuration; }; +in +{ + substituters = builtins.concatStringsSep " " os.config.nix.settings.substituters; + trusted_public_keys = builtins.concatStringsSep " " os.config.nix.settings.trusted-public-keys; + drv_path = os.config.system.build.toplevel.drvPath; + out_path = os.config.system.build.toplevel; +} -- 2.48.1 From 458e565e4e6d6af66a0f4533103fafc65ac59c96 Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Mon, 18 Aug 2025 12:47:05 +0200 Subject: [PATCH 12/69] add keys --- deployment/check/common/targetNode.nix | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/deployment/check/common/targetNode.nix b/deployment/check/common/targetNode.nix index a346d873..8e760888 100644 --- a/deployment/check/common/targetNode.nix +++ b/deployment/check/common/targetNode.nix @@ -42,6 +42,18 @@ in ## Test VMs don't have a bootloader by default. boot.loader.grub.enable = false; + + users.users.root.openssh.authorizedKeys.keys = + let + keys = import ../../../keys; + in + lib.attrValues keys.contributors + ++ [ + # allow our panel vm access to the test machines + keys.panel + # allow continuous deployment access + keys.cd + ]; } (mkIf config.enableAcme { -- 2.48.1 From b7e34de8354af372f30a58ce264a242c72784841 Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Tue, 19 Aug 2025 12:00:35 +0200 Subject: [PATCH 13/69] pasteable command for trying without rebuilding vm --- paste | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 paste diff --git a/paste b/paste new file mode 100644 index 00000000..4a115c24 --- /dev/null +++ b/paste @@ -0,0 +1,59 @@ +declare substituters trusted_public_keys drv_path + +host="root@fedi203.abundos.eu" + +sshOpts=( + -o BatchMode=yes + -o StrictHostKeyChecking=no +) + +command=(nix-instantiate --expr ' + let + sources = import ./npins; + configuration = { + imports = [ + ./infra/common/proxmox-qemu-vm.nix + ./infra/common/nixos/users.nix + ./deployment/check/common/sharedOptions.nix + ./deployment/check/common/targetNode.nix + "${sources.disko}/module.nix" + ]; + }; + eval = import "${sources.nixpkgs}/nixos/lib/eval-config.nix" { + system = builtins.currentSystem; + specialArgs = { + inherit sources; + }; + modules = [ configuration ]; + }; + os = { + inherit (eval) pkgs config options; + system = eval.config.system.build.toplevel; + inherit (eval.config.system.build) vm vmWithBootLoader; + }; + in + { + substituters = builtins.concatStringsSep " " os.config.nix.settings.substituters; + trusted_public_keys = builtins.concatStringsSep " " os.config.nix.settings.trusted-public-keys; + drv_path = os.config.system.build.toplevel.drvPath; + out_path = os.config.system.build.toplevel; + } +') + +buildArgs=( + --option extra-binary-caches https://cache.nixos.org/ + --option substituters "$substituters" + --option trusted-public-keys "$trusted_public_keys" +) + +"${command[@]}" -A out_path + +json="$("${command[@]}" --eval --strict --json)" + +eval "export $(echo $json | jq -r 'to_entries | map("\(.key)=\(.value)") | @sh')" + +outPath=$(nix-store --realize "$drv_path" "${buildArgs[@]}") + +NIX_SSHOPTS="${sshOpts[*]}" nix-copy-closure --to "$host" "$outPath" --gzip --use-substitutes + +ssh "${sshOpts[@]}" "$host" "nix-env --profile /nix/var/nix/profiles/system --set $outPath; $outPath/bin/switch-to-configuration switch" -- 2.48.1 From ae06cfc4175b742bf47bf8c8c66e1ab94a9ac124 Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Sat, 23 Aug 2025 12:10:45 +0200 Subject: [PATCH 14/69] ditch superfluous substituters --- deployment/check/data-model/nixosTest.nix | 11 ++--------- paste | 21 ++------------------- 2 files changed, 4 insertions(+), 28 deletions(-) diff --git a/deployment/check/data-model/nixosTest.nix b/deployment/check/data-model/nixosTest.nix index beaa9c20..2a85a0a8 100644 --- a/deployment/check/data-model/nixosTest.nix +++ b/deployment/check/data-model/nixosTest.nix @@ -84,8 +84,6 @@ in in # import "${pathToRoot}/deployment/nixos.nix" {} { - substituters = builtins.concatStringsSep " " os.config.nix.settings.substituters; - trusted_public_keys = builtins.concatStringsSep " " os.config.nix.settings.trusted-public-keys; drv_path = os.config.system.build.toplevel.drvPath; out_path = os.config.system.build.toplevel; } @@ -97,21 +95,16 @@ in json="$("''${command[@]}" --eval --strict --json)" # DEPLOY - declare substituters trusted_public_keys drv_path + declare drv_path # set our variables using the json object eval "export $(echo $json | jq -r 'to_entries | map("\(.key)=\(.value)") | @sh')" host="root@${nodeName}" - buildArgs=( - --option extra-binary-caches https://cache.nixos.org/ - --option substituters $substituters - --option trusted-public-keys $trusted_public_keys - ) sshOpts=( -o BatchMode=yes -o StrictHostKeyChecking=no ) # get the realized derivation to deploy - outPath=$(nix-store --realize "$drv_path" "''${buildArgs[@]}") + outPath=$(nix-store --realize "$drv_path") # deploy the config by nix-copy-closure NIX_SSHOPTS="''${sshOpts[*]}" nix-copy-closure --to "$host" "$outPath" --gzip --use-substitutes # switch the remote host to the config diff --git a/paste b/paste index 4a115c24..25e6190f 100644 --- a/paste +++ b/paste @@ -1,12 +1,9 @@ -declare substituters trusted_public_keys drv_path - +declare drv_path host="root@fedi203.abundos.eu" - sshOpts=( -o BatchMode=yes -o StrictHostKeyChecking=no ) - command=(nix-instantiate --expr ' let sources = import ./npins; @@ -33,27 +30,13 @@ command=(nix-instantiate --expr ' }; in { - substituters = builtins.concatStringsSep " " os.config.nix.settings.substituters; - trusted_public_keys = builtins.concatStringsSep " " os.config.nix.settings.trusted-public-keys; drv_path = os.config.system.build.toplevel.drvPath; out_path = os.config.system.build.toplevel; } ') - -buildArgs=( - --option extra-binary-caches https://cache.nixos.org/ - --option substituters "$substituters" - --option trusted-public-keys "$trusted_public_keys" -) - "${command[@]}" -A out_path - json="$("${command[@]}" --eval --strict --json)" - eval "export $(echo $json | jq -r 'to_entries | map("\(.key)=\(.value)") | @sh')" - -outPath=$(nix-store --realize "$drv_path" "${buildArgs[@]}") - +outPath=$(nix-store --realize "$drv_path") NIX_SSHOPTS="${sshOpts[*]}" nix-copy-closure --to "$host" "$outPath" --gzip --use-substitutes - ssh "${sshOpts[@]}" "$host" "nix-env --profile /nix/var/nix/profiles/system --set $outPath; $outPath/bin/switch-to-configuration switch" -- 2.48.1 From d51f8fcf162ecd393156a203ac2a49735a578fcf Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Sat, 23 Aug 2025 12:54:56 +0200 Subject: [PATCH 15/69] move imports from paste to targetNode to increase parity between paste and nixosTest --- deployment/check/common/targetNode.nix | 4 ++++ paste | 4 ---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/deployment/check/common/targetNode.nix b/deployment/check/common/targetNode.nix index 8e760888..7c24aa1e 100644 --- a/deployment/check/common/targetNode.nix +++ b/deployment/check/common/targetNode.nix @@ -3,6 +3,7 @@ config, lib, modulesPath, + sources, ... }: @@ -17,7 +18,10 @@ in imports = [ (modulesPath + "/profiles/qemu-guest.nix") (modulesPath + "/../lib/testing/nixos-test-base.nix") + "${sources.disko}/module.nix" + ../../../infra/common/proxmox-qemu-vm.nix ./sharedOptions.nix + ../../../infra/common/nixos/users.nix ]; config = mkMerge [ diff --git a/paste b/paste index 25e6190f..89b3ed52 100644 --- a/paste +++ b/paste @@ -9,11 +9,7 @@ command=(nix-instantiate --expr ' sources = import ./npins; configuration = { imports = [ - ./infra/common/proxmox-qemu-vm.nix - ./infra/common/nixos/users.nix - ./deployment/check/common/sharedOptions.nix ./deployment/check/common/targetNode.nix - "${sources.disko}/module.nix" ]; }; eval = import "${sources.nixpkgs}/nixos/lib/eval-config.nix" { -- 2.48.1 From 85cbdd945bb8e747863ded2ddf105e0e4d616384 Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Sun, 24 Aug 2025 18:13:22 +0200 Subject: [PATCH 16/69] settle for hello, ditching cowsay --- deployment/check/data-model/constants.nix | 1 - deployment/check/data-model/nixosTest.nix | 6 +----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/deployment/check/data-model/constants.nix b/deployment/check/data-model/constants.nix index 3cf28d8f..0c8576a7 100644 --- a/deployment/check/data-model/constants.nix +++ b/deployment/check/data-model/constants.nix @@ -1,7 +1,6 @@ { targetMachines = [ "hello" - "cowsay" ]; pathToRoot = ../../..; pathFromRoot = ./.; diff --git a/deployment/check/data-model/nixosTest.nix b/deployment/check/data-model/nixosTest.nix index 2a85a0a8..127b2e2d 100644 --- a/deployment/check/data-model/nixosTest.nix +++ b/deployment/check/data-model/nixosTest.nix @@ -46,7 +46,6 @@ in extraTestScript = '' with subtest("Check the status before deployment"): hello.fail("hello 1>&2") - cowsay.fail("cowsay 1>&2") ${lib.concatStringsSep "\n" ( lib.lists.map (nodeName: '' @@ -110,11 +109,8 @@ in # switch the remote host to the config ssh "''${sshOpts[@]}" "$host" "nix-env --profile /nix/var/nix/profiles/system --set $outPath; $outPath/bin/switch-to-configuration switch" """) + ${nodeName}.succeed("${nodeName} 1>&2") '') targetMachines )} - - with subtest("Check the deployment"): - hello.succeed("hello 1>&2") - cowsay.succeed("cowsay hi 1>&2") ''; } -- 2.48.1 From 3ae12354613137a0094c118a5ccdba9de6244021 Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Sun, 24 Aug 2025 18:14:26 +0200 Subject: [PATCH 17/69] reduce download attempts in test --- deployment/check/common/deployerNode.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/deployment/check/common/deployerNode.nix b/deployment/check/common/deployerNode.nix index 4e0dd2de..fbf04332 100644 --- a/deployment/check/common/deployerNode.nix +++ b/deployment/check/common/deployerNode.nix @@ -49,6 +49,7 @@ in substituters = mkForce [ ]; hashed-mirrors = null; connect-timeout = 1; + download-attempts = 1; extra-experimental-features = "flakes"; }; -- 2.48.1 From 081ae1ad0706cb81b5328924746679546bc377bb Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Sun, 24 Aug 2025 18:15:36 +0200 Subject: [PATCH 18/69] ensure availability of needed inputs --- deployment/check/common/deployerNode.nix | 32 +++++++++++++++++++++++ deployment/check/data-model/nixosTest.nix | 6 +++++ 2 files changed, 38 insertions(+) diff --git a/deployment/check/common/deployerNode.nix b/deployment/check/common/deployerNode.nix index fbf04332..8c584fcf 100644 --- a/deployment/check/common/deployerNode.nix +++ b/deployment/check/common/deployerNode.nix @@ -62,6 +62,10 @@ in pkgs.stdenv pkgs.stdenvNoCC + pkgs.automake + pkgs.autoconf + pkgs.binutils + pkgs.bison ] ++ ( let @@ -93,7 +97,35 @@ in machine.system.build.vm.inputDerivation machine.system.build.bootStage1.inputDerivation machine.system.build.bootStage2.inputDerivation + pkgs.automake.inputDerivation + pkgs.autoconf.inputDerivation + pkgs.bash.inputDerivation + pkgs.binutils.inputDerivation + pkgs.bison.inputDerivation ] + ++ concatLists ( + lib.lists.map ( + pkg: + if + pkg ? inputDerivation + # error: output '/nix/store/dki9d3vldafg9ydrfm7x0g0rr0qljk98-sudo-1.9.16p2' is not allowed to refer to the following paths: + # /nix/store/2xdmps65ryklmbf025bm4pxv16gb8ajv-sudo-1.9.16p2.tar.gz + # /nix/store/58br4vk3q5akf4g8lx0pqzfhn47k3j8d-bash-5.2p37 + # /nix/store/8v6k283dpbc0qkdq81nb6mrxrgcb10i1-gcc-wrapper-14-20241116 + # /nix/store/9r1nl9ksiyszy4qzzg6y2gcdkca0xmhy-stdenv-linux + # /nix/store/a4rmp6in7igbl1wbz9pli5nq0wiclq0y-groff-1.23.0 + # /nix/store/dki9d3vldafg9ydrfm7x0g0rr0qljk98-sudo-1.9.16p2 + # /nix/store/f5y58qz2fzpzgkhp0nizixi10x04ppyy-linux-pam-1.6.1 + # /nix/store/shkw4qm9qcw5sc5n1k5jznc83ny02r39-default-builder.sh + # /nix/store/vj1c3wf9c11a0qs6p3ymfvrnsdgsdcbq-source-stdenv.sh + # /nix/store/yh6qg1nsi5h2xblcr67030pz58fsaxx3-coreutils-9.6 + && !(lib.strings.hasInfix "sudo" (builtins.toString pkg)) + then + [ pkg.inputDerivation ] + else + [ ] + ) machine.environment.systemPackages + ) ++ concatLists ( lib.mapAttrsToList ( _k: v: if v ? source.inputDerivation then [ v.source.inputDerivation ] else [ ] diff --git a/deployment/check/data-model/nixosTest.nix b/deployment/check/data-model/nixosTest.nix index 127b2e2d..ffc49ab4 100644 --- a/deployment/check/data-model/nixosTest.nix +++ b/deployment/check/data-model/nixosTest.nix @@ -25,12 +25,16 @@ in environment.systemPackages = with pkgs; [ jq + automake + autoconf ]; # FIXME: sad times system.extraDependencies = with pkgs; [ jq jq.inputDerivation + automake + autoconf ]; system.extraDependenciesFromModule = @@ -39,6 +43,8 @@ in environment.systemPackages = with pkgs; [ hello cowsay + automake + autoconf ]; }; }; -- 2.48.1 From fe0edd897b7648f61c87e0581e8c1ba258c6e81b Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Sun, 24 Aug 2025 18:18:26 +0200 Subject: [PATCH 19/69] move stuff not needed in test out --- deployment/check/common/targetNode.nix | 3 --- paste | 34 ++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/deployment/check/common/targetNode.nix b/deployment/check/common/targetNode.nix index 7c24aa1e..55320160 100644 --- a/deployment/check/common/targetNode.nix +++ b/deployment/check/common/targetNode.nix @@ -3,7 +3,6 @@ config, lib, modulesPath, - sources, ... }: @@ -18,8 +17,6 @@ in imports = [ (modulesPath + "/profiles/qemu-guest.nix") (modulesPath + "/../lib/testing/nixos-test-base.nix") - "${sources.disko}/module.nix" - ../../../infra/common/proxmox-qemu-vm.nix ./sharedOptions.nix ../../../infra/common/nixos/users.nix ]; diff --git a/paste b/paste index 89b3ed52..9fdae1b9 100644 --- a/paste +++ b/paste @@ -10,7 +10,41 @@ command=(nix-instantiate --expr ' configuration = { imports = [ ./deployment/check/common/targetNode.nix + "${sources.nixpkgs}/nixos/modules/profiles/qemu-guest.nix" + "${sources.disko}/module.nix" ]; + disabledModules = [ "virtualisation/qemu-vm.nix" ]; + config = { + nix.nixPath = lib.mapAttrsToList (k: v: k + "=" + v) sources; + networking = { + nameservers = [ + "95.215.185.6" + "95.215.185.7" + "2a00:51c0::5fd7:b906" + "2a00:51c0::5fd7:b907" + ]; + interfaces.eth0.ipv4.addresses = [ + { + address = "95.215.187.203"; + prefixLength = 24; + } + ]; + interfaces.eth0.ipv6.addresses = [ + { + address = "2a00:51c0:13:1305::203"; + prefixLength = 64; + } + ]; + defaultGateway = { + address = "95.215.187.1"; + interface = "eth0"; + }; + defaultGateway6 = { + address = "2a00:51c0:13:1305::1"; + interface = "eth0"; + }; + }; + }; }; eval = import "${sources.nixpkgs}/nixos/lib/eval-config.nix" { system = builtins.currentSystem; -- 2.48.1 From ee6b99014445c72e6637ad2e0fc6ce075a527789 Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Sun, 24 Aug 2025 18:18:49 +0200 Subject: [PATCH 20/69] rm paste --- paste | 72 ----------------------------------------------------------- 1 file changed, 72 deletions(-) delete mode 100644 paste diff --git a/paste b/paste deleted file mode 100644 index 9fdae1b9..00000000 --- a/paste +++ /dev/null @@ -1,72 +0,0 @@ -declare drv_path -host="root@fedi203.abundos.eu" -sshOpts=( - -o BatchMode=yes - -o StrictHostKeyChecking=no -) -command=(nix-instantiate --expr ' - let - sources = import ./npins; - configuration = { - imports = [ - ./deployment/check/common/targetNode.nix - "${sources.nixpkgs}/nixos/modules/profiles/qemu-guest.nix" - "${sources.disko}/module.nix" - ]; - disabledModules = [ "virtualisation/qemu-vm.nix" ]; - config = { - nix.nixPath = lib.mapAttrsToList (k: v: k + "=" + v) sources; - networking = { - nameservers = [ - "95.215.185.6" - "95.215.185.7" - "2a00:51c0::5fd7:b906" - "2a00:51c0::5fd7:b907" - ]; - interfaces.eth0.ipv4.addresses = [ - { - address = "95.215.187.203"; - prefixLength = 24; - } - ]; - interfaces.eth0.ipv6.addresses = [ - { - address = "2a00:51c0:13:1305::203"; - prefixLength = 64; - } - ]; - defaultGateway = { - address = "95.215.187.1"; - interface = "eth0"; - }; - defaultGateway6 = { - address = "2a00:51c0:13:1305::1"; - interface = "eth0"; - }; - }; - }; - }; - eval = import "${sources.nixpkgs}/nixos/lib/eval-config.nix" { - system = builtins.currentSystem; - specialArgs = { - inherit sources; - }; - modules = [ configuration ]; - }; - os = { - inherit (eval) pkgs config options; - system = eval.config.system.build.toplevel; - inherit (eval.config.system.build) vm vmWithBootLoader; - }; - in - { - drv_path = os.config.system.build.toplevel.drvPath; - out_path = os.config.system.build.toplevel; - } -') -"${command[@]}" -A out_path -json="$("${command[@]}" --eval --strict --json)" -eval "export $(echo $json | jq -r 'to_entries | map("\(.key)=\(.value)") | @sh')" -outPath=$(nix-store --realize "$drv_path") -NIX_SSHOPTS="${sshOpts[*]}" nix-copy-closure --to "$host" "$outPath" --gzip --use-substitutes -ssh "${sshOpts[@]}" "$host" "nix-env --profile /nix/var/nix/profiles/system --set $outPath; $outPath/bin/switch-to-configuration switch" -- 2.48.1 From b7cf39534fa4fc4f7e3708b3ce99a0ddcda5507a Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Sun, 24 Aug 2025 18:19:53 +0200 Subject: [PATCH 21/69] ensure inputs --- deployment/check/data-model/nixosTest.nix | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/deployment/check/data-model/nixosTest.nix b/deployment/check/data-model/nixosTest.nix index ffc49ab4..45c7201f 100644 --- a/deployment/check/data-model/nixosTest.nix +++ b/deployment/check/data-model/nixosTest.nix @@ -83,7 +83,11 @@ in enableAcme = ${lib.strings.toJSON config.enableAcme}; acmeNodeIP = if config.enableAcme then config.nodes.acme.networking.primaryIPAddress else null; - # environment.systemPackages = [ pkgs.hello ]; + environment.systemPackages = with pkgs; [ + hello + automake + autoconf + ]; }; os = import "${sources.nixpkgs}/nixos" { inherit system configuration; }; in -- 2.48.1 From 10ba2ee1e6ef48b8ec9b438a8271f96cbb7996c1 Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Sun, 24 Aug 2025 18:21:38 +0200 Subject: [PATCH 22/69] nix in tests: download-attempts = 1 --- deployment/check/common/targetNode.nix | 3 +++ 1 file changed, 3 insertions(+) diff --git a/deployment/check/common/targetNode.nix b/deployment/check/common/targetNode.nix index 55320160..5ec8f47d 100644 --- a/deployment/check/common/targetNode.nix +++ b/deployment/check/common/targetNode.nix @@ -32,6 +32,9 @@ in ## Not used; save a large copy operation channel.enable = false; registry = lib.mkForce { }; + settings = { + download-attempts = 1; + }; }; services.openssh = { -- 2.48.1 From 9769e1714c1753d81c557ccf9c216499e96a1a2c Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Sun, 24 Aug 2025 18:25:00 +0200 Subject: [PATCH 23/69] specialArgs: sources --- deployment/check/data-model/nixosTest.nix | 29 ++++++++++++++++------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/deployment/check/data-model/nixosTest.nix b/deployment/check/data-model/nixosTest.nix index 45c7201f..0e5b3a6a 100644 --- a/deployment/check/data-model/nixosTest.nix +++ b/deployment/check/data-model/nixosTest.nix @@ -66,20 +66,20 @@ in ' let - system = builtins.currentSystem; + args = builtins.fromJSON "${ + lib.replaceStrings [ "\"" ] [ "\\\\\"" ] ( + lib.strings.toJSON { + inherit sources; + } + ) + }"; + inherit (args) sources; configuration = { pkgs, config, ... }: { imports = [ ${pathToRoot}/deployment/check/common/sharedOptions.nix ${pathToRoot}/deployment/check/common/targetNode.nix ]; - _module.args = builtins.fromJSON "${ - lib.replaceStrings [ "\"" ] [ "\\\\\"" ] ( - lib.strings.toJSON { - inherit sources; - } - ) - }"; enableAcme = ${lib.strings.toJSON config.enableAcme}; acmeNodeIP = if config.enableAcme then config.nodes.acme.networking.primaryIPAddress else null; @@ -89,7 +89,18 @@ in autoconf ]; }; - os = import "${sources.nixpkgs}/nixos" { inherit system configuration; }; + eval = import "${sources.nixpkgs}/nixos/lib/eval-config.nix" { + system = builtins.currentSystem; + specialArgs = { + inherit sources; + }; + modules = [ configuration ]; + }; + os = { + inherit (eval) pkgs config options; + system = eval.config.system.build.toplevel; + inherit (eval.config.system.build) vm vmWithBootLoader; + }; in # import "${pathToRoot}/deployment/nixos.nix" {} { -- 2.48.1 From 03cbb4738d4160438ac28d363072d4c7fefa1b62 Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Sun, 24 Aug 2025 18:26:42 +0200 Subject: [PATCH 24/69] handle test outcome --- deployment/check/data-model/nixosTest.nix | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/deployment/check/data-model/nixosTest.nix b/deployment/check/data-model/nixosTest.nix index 0e5b3a6a..050fb0ad 100644 --- a/deployment/check/data-model/nixosTest.nix +++ b/deployment/check/data-model/nixosTest.nix @@ -122,14 +122,27 @@ in sshOpts=( -o BatchMode=yes -o StrictHostKeyChecking=no + -o "ConnectionAttempts=1" + -o "ConnectTimeout=1" + -o "ServerAliveCountMax=1" + -o "ServerAliveInterval=1" ) # get the realized derivation to deploy outPath=$(nix-store --realize "$drv_path") # deploy the config by nix-copy-closure NIX_SSHOPTS="''${sshOpts[*]}" nix-copy-closure --to "$host" "$outPath" --gzip --use-substitutes # switch the remote host to the config - ssh "''${sshOpts[@]}" "$host" "nix-env --profile /nix/var/nix/profiles/system --set $outPath; $outPath/bin/switch-to-configuration switch" + output=$(ssh "''${sshOpts[@]}" "$host" "nix-env --profile /nix/var/nix/profiles/system --set $outPath; nohup $outPath/bin/switch-to-configuration switch &" 2>&1) || echo "status code: $?" + echo "output: $output" + if [[ $output != *"Timeout, server ${nodeName} not responding"* ]]; then + echo "non-timeout error: $output" + exit 1 + else + exit 0 + fi """) + ${nodeName}.wait_for_unit("multi-user.target") + ${nodeName}.succeed("systemctl is-active sshd") ${nodeName}.succeed("${nodeName} 1>&2") '') targetMachines )} -- 2.48.1 From 4b85628ab1c6af3520fbb565c0dce1a2602edfc9 Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Sun, 24 Aug 2025 18:27:19 +0200 Subject: [PATCH 25/69] users --- deployment/check/common/targetNode.nix | 28 ++++++++++++++++---------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/deployment/check/common/targetNode.nix b/deployment/check/common/targetNode.nix index 5ec8f47d..30299b0d 100644 --- a/deployment/check/common/targetNode.nix +++ b/deployment/check/common/targetNode.nix @@ -47,17 +47,23 @@ in ## Test VMs don't have a bootloader by default. boot.loader.grub.enable = false; - users.users.root.openssh.authorizedKeys.keys = - let - keys = import ../../../keys; - in - lib.attrValues keys.contributors - ++ [ - # allow our panel vm access to the test machines - keys.panel - # allow continuous deployment access - keys.cd - ]; + users.mutableUsers = false; + users.users.root = { + password = "password"; + hashedPassword = null; + hashedPasswordFile = null; + openssh.authorizedKeys.keys = + let + keys = import ../../../keys; + in + lib.attrValues keys.contributors + ++ [ + # allow our panel vm access to the test machines + keys.panel + # allow continuous deployment access + keys.cd + ]; + }; } (mkIf config.enableAcme { -- 2.48.1 From 20557422e912fcf65b4ab6352f35a433306feb07 Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Sun, 24 Aug 2025 18:30:43 +0200 Subject: [PATCH 26/69] networking --- deployment/check/common/targetNode.nix | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/deployment/check/common/targetNode.nix b/deployment/check/common/targetNode.nix index 30299b0d..e3d0c40b 100644 --- a/deployment/check/common/targetNode.nix +++ b/deployment/check/common/targetNode.nix @@ -42,7 +42,10 @@ in settings.PermitRootLogin = "yes"; }; - networking.firewall.allowedTCPPorts = [ 22 ]; + networking = { + firewall.enable = false; + enableIPv6 = false; + }; ## Test VMs don't have a bootloader by default. boot.loader.grub.enable = false; -- 2.48.1 From 2af6817cd8942d0820459df8a930399d3185e3ba Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Sun, 24 Aug 2025 18:30:52 +0200 Subject: [PATCH 27/69] auto login --- deployment/check/common/targetNode.nix | 2 ++ 1 file changed, 2 insertions(+) diff --git a/deployment/check/common/targetNode.nix b/deployment/check/common/targetNode.nix index e3d0c40b..3db097b8 100644 --- a/deployment/check/common/targetNode.nix +++ b/deployment/check/common/targetNode.nix @@ -47,6 +47,8 @@ in enableIPv6 = false; }; + services.getty.autologinUser = lib.mkForce "root"; + ## Test VMs don't have a bootloader by default. boot.loader.grub.enable = false; -- 2.48.1 From 5a02027d483ddad8dfaeeaa40f259ddec93fde5f Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Sun, 24 Aug 2025 18:31:34 +0200 Subject: [PATCH 28/69] grub --- deployment/check/common/targetNode.nix | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/deployment/check/common/targetNode.nix b/deployment/check/common/targetNode.nix index 3db097b8..c5986a28 100644 --- a/deployment/check/common/targetNode.nix +++ b/deployment/check/common/targetNode.nix @@ -50,7 +50,20 @@ in services.getty.autologinUser = lib.mkForce "root"; ## Test VMs don't have a bootloader by default. - boot.loader.grub.enable = false; + # boot.loader = { + # # GRUB enabled: installation of GRUB on /dev/disk/by-id/virtio-root failed: No such file or directory + # grub.enable = false; + # # systemd boot enabled: '/boot' is not a mounted partition. Is the path configured correctly? + # systemd-boot.enable = true; + # efi.canTouchEfiVariables = true; + # }; + # # same issue as no bootloader + # boot.loader.generic-extlinux-compatible.enable = false; + # builds but won't boot back up + boot.loader.grub.forceInstall = true; + # # builds but won't boot back up + # # to be used with --no-bootloader, which i could only find for flakes + # boot.loader.grub.enable = false; users.mutableUsers = false; users.users.root = { -- 2.48.1 From 50e1a768e7c156c5d8c477a8b7cec43e090813a6 Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Sun, 24 Aug 2025 18:32:12 +0200 Subject: [PATCH 29/69] qemu guest --- deployment/check/data-model/nixosTest.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/deployment/check/data-model/nixosTest.nix b/deployment/check/data-model/nixosTest.nix index 050fb0ad..5a7de78b 100644 --- a/deployment/check/data-model/nixosTest.nix +++ b/deployment/check/data-model/nixosTest.nix @@ -78,6 +78,7 @@ in imports = [ ${pathToRoot}/deployment/check/common/sharedOptions.nix ${pathToRoot}/deployment/check/common/targetNode.nix + ${sources.nixpkgs}/nixos/modules/profiles/qemu-guest.nix ]; enableAcme = ${lib.strings.toJSON config.enableAcme}; -- 2.48.1 From cbec8fa3fc965205530c910fb15cfb04e315dcde Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Sun, 24 Aug 2025 19:26:16 +0200 Subject: [PATCH 30/69] dedupe nixosTest.nix --- deployment/check/basic/constants.nix | 1 + deployment/check/basic/nixosTest.nix | 8 +- deployment/check/cli/constants.nix | 1 + deployment/check/cli/nixosTest.nix | 2 + deployment/check/common/nixosTest.nix | 59 +++--- deployment/check/common/sharedOptions.nix | 2 + .../check/data-model/common-nixosTest.nix | 168 ------------------ deployment/check/data-model/default.nix | 2 +- deployment/check/panel/constants.nix | 1 + deployment/check/panel/nixosTest.nix | 1 + 10 files changed, 48 insertions(+), 197 deletions(-) delete mode 100644 deployment/check/data-model/common-nixosTest.nix diff --git a/deployment/check/basic/constants.nix b/deployment/check/basic/constants.nix index 3cf28d8f..f2573fb8 100644 --- a/deployment/check/basic/constants.nix +++ b/deployment/check/basic/constants.nix @@ -5,4 +5,5 @@ ]; pathToRoot = ../../..; pathFromRoot = ./.; + useFlake = true; } diff --git a/deployment/check/basic/nixosTest.nix b/deployment/check/basic/nixosTest.nix index 93c8ad23..10ed196f 100644 --- a/deployment/check/basic/nixosTest.nix +++ b/deployment/check/basic/nixosTest.nix @@ -1,4 +1,9 @@ -{ inputs, lib, ... }: +{ + inputs, + lib, + config, + ... +}: { _class = "nixosTest"; @@ -8,6 +13,7 @@ sourceFileset = lib.fileset.unions [ ./constants.nix ./deployment.nix + (config.pathToCwd + "/flake-under-test.nix") ]; nodes.deployer = diff --git a/deployment/check/cli/constants.nix b/deployment/check/cli/constants.nix index ce3b5e4d..a48d9076 100644 --- a/deployment/check/cli/constants.nix +++ b/deployment/check/cli/constants.nix @@ -8,4 +8,5 @@ pathToRoot = ../../..; pathFromRoot = ./.; enableAcme = true; + useFlake = true; } diff --git a/deployment/check/cli/nixosTest.nix b/deployment/check/cli/nixosTest.nix index d171a182..f7f1cf2d 100644 --- a/deployment/check/cli/nixosTest.nix +++ b/deployment/check/cli/nixosTest.nix @@ -1,6 +1,7 @@ { inputs, hostPkgs, + config, lib, ... }: @@ -19,6 +20,7 @@ in sourceFileset = lib.fileset.unions [ ./constants.nix ./deployments.nix + (config.pathToCwd + "/flake-under-test.nix") # REVIEW: I would like to be able to grab all of `/deployment` minus # `/deployment/check`, but I can't because there is a bunch of other files diff --git a/deployment/check/common/nixosTest.nix b/deployment/check/common/nixosTest.nix index bc30edba..93bd3fef 100644 --- a/deployment/check/common/nixosTest.nix +++ b/deployment/check/common/nixosTest.nix @@ -76,8 +76,6 @@ in ./sharedOptions.nix ./targetNode.nix ./targetResource.nix - - (config.pathToCwd + "/flake-under-test.nix") ]; acmeNodeIP = config.nodes.acme.networking.primaryIPAddress; @@ -164,31 +162,38 @@ in deployer.succeed(f"echo '{host_key}' > ${config.pathFromRoot}/${tm}_host_key.pub") '')} - ## NOTE: This is super slow. It could probably be optimised in Nix, for - ## instance by allowing to grab things directly from the host's store. - ## - ## NOTE: We use the repository as-is (cf `src` above), overriding only - ## `flake.nix` by our `flake-under-test.nix`. We also override the flake - ## lock file to use locally available inputs, as we cannot download them. - ## - with subtest("Override the flake and its lock"): - deployer.succeed("cp ${config.pathFromRoot}/flake-under-test.nix flake.nix") - deployer.succeed(""" - nix flake lock --extra-experimental-features 'flakes nix-command' \ - --offline -v \ - --override-input nixops4 ${inputs.nixops4.packages.${system}.flake-in-a-bottle} \ - \ - --override-input nixops4-nixos ${inputs.nixops4-nixos} \ - --override-input nixops4-nixos/flake-parts ${inputs.nixops4-nixos.inputs.flake-parts} \ - --override-input nixops4-nixos/flake-parts/nixpkgs-lib ${inputs.nixops4-nixos.inputs.flake-parts.inputs.nixpkgs-lib} \ - --override-input nixops4-nixos/nixops4-nixos ${emptyFlake} \ - --override-input nixops4-nixos/nixpkgs ${inputs.nixops4-nixos.inputs.nixpkgs} \ - --override-input nixops4-nixos/nixops4 ${ - inputs.nixops4-nixos.inputs.nixops4.packages.${system}.flake-in-a-bottle - } \ - --override-input nixops4-nixos/git-hooks-nix ${emptyFlake} \ - ; - """) + ${ + if config.useFlake then + '' + ## NOTE: This is super slow. It could probably be optimised in Nix, for + ## instance by allowing to grab things directly from the host's store. + ## + ## NOTE: We use the repository as-is (cf `src` above), overriding only + ## `flake.nix` by our `flake-under-test.nix`. We also override the flake + ## lock file to use locally available inputs, as we cannot download them. + ## + with subtest("Override the flake and its lock"): + deployer.succeed("cp ${config.pathFromRoot}/flake-under-test.nix flake.nix") + deployer.succeed(""" + nix flake lock --extra-experimental-features 'flakes nix-command' \ + --offline -v \ + --override-input nixops4 ${inputs.nixops4.packages.${system}.flake-in-a-bottle} \ + \ + --override-input nixops4-nixos ${inputs.nixops4-nixos} \ + --override-input nixops4-nixos/flake-parts ${inputs.nixops4-nixos.inputs.flake-parts} \ + --override-input nixops4-nixos/flake-parts/nixpkgs-lib ${inputs.nixops4-nixos.inputs.flake-parts.inputs.nixpkgs-lib} \ + --override-input nixops4-nixos/nixops4-nixos ${emptyFlake} \ + --override-input nixops4-nixos/nixpkgs ${inputs.nixops4-nixos.inputs.nixpkgs} \ + --override-input nixops4-nixos/nixops4 ${ + inputs.nixops4-nixos.inputs.nixops4.packages.${system}.flake-in-a-bottle + } \ + --override-input nixops4-nixos/git-hooks-nix ${emptyFlake} \ + ; + """) + '' + else + "" + } ${optionalString config.enableAcme '' with subtest("Set up handmade DNS"): diff --git a/deployment/check/common/sharedOptions.nix b/deployment/check/common/sharedOptions.nix index 7201a8f5..c0efc6cf 100644 --- a/deployment/check/common/sharedOptions.nix +++ b/deployment/check/common/sharedOptions.nix @@ -64,5 +64,7 @@ in during the test to the correct value. ''; }; + + useFlake = lib.mkEnableOption "Use a flake in the test."; }; } diff --git a/deployment/check/data-model/common-nixosTest.nix b/deployment/check/data-model/common-nixosTest.nix deleted file mode 100644 index aa912dc3..00000000 --- a/deployment/check/data-model/common-nixosTest.nix +++ /dev/null @@ -1,168 +0,0 @@ -{ - inputs, - lib, - config, - hostPkgs, - sources, - ... -}: - -let - inherit (builtins) - concatStringsSep - toJSON - ; - inherit (lib) - types - fileset - mkOption - genAttrs - attrNames - optionalString - ; - inherit (hostPkgs) - writeText - ; - - forConcat = xs: f: concatStringsSep "\n" (map f xs); - -in -{ - _class = "nixosTest"; - - imports = [ - ../common/sharedOptions.nix - ]; - - options = { - ## FIXME: I wish I could just use `testScript` but with something like - ## `mkOrder` to put this module's string before something else. - extraTestScript = mkOption { }; - - sourceFileset = mkOption { - ## REVIEW: Upstream to nixpkgs? - type = types.mkOptionType { - name = "fileset"; - description = "fileset"; - descriptionClass = "noun"; - check = (x: (builtins.tryEval (fileset.unions [ x ])).success); - merge = (_: defs: fileset.unions (map (x: x.value) defs)); - }; - description = '' - A fileset that will be copied to the deployer node in the current - working directory. This should contain all the files that are - necessary to run that particular test, such as the NixOS - modules necessary to evaluate a deployment. - ''; - }; - }; - - config = { - sourceFileset = fileset.unions [ - ../../../mkFlake.nix - ../../../flake.lock - ../../../npins - ../../data-model.nix - ../../function.nix - - ../common/sharedOptions.nix - ../common/targetNode.nix - ../common/targetResource.nix - ]; - - acmeNodeIP = config.nodes.acme.networking.primaryIPAddress; - - nodes = - { - deployer = { - imports = [ ../common/deployerNode.nix ]; - _module.args = { inherit inputs sources; }; - enableAcme = config.enableAcme; - acmeNodeIP = config.nodes.acme.networking.primaryIPAddress; - }; - } - - // - - ( - if config.enableAcme then - { - acme = { - ## FIXME: This makes `nodes.acme` into a local resolver. Maybe this will - ## break things once we play with DNS? - imports = [ "${inputs.nixpkgs}/nixos/tests/common/acme/server" ]; - ## We aren't testing ACME - we just want certificates. - systemd.services.pebble.environment.PEBBLE_VA_ALWAYS_VALID = "1"; - }; - } - else - { } - ) - - // - - genAttrs config.targetMachines (_: { - imports = [ ../common/targetNode.nix ]; - _module.args = { inherit inputs sources; }; - enableAcme = config.enableAcme; - acmeNodeIP = if config.enableAcme then config.nodes.acme.networking.primaryIPAddress else null; - }); - - testScript = '' - ${forConcat (attrNames config.nodes) (n: '' - ${n}.start() - '')} - - ${forConcat (attrNames config.nodes) (n: '' - ${n}.wait_for_unit("multi-user.target") - '')} - - ## A subset of the repository that is necessary for this test. It will be - ## copied inside the test. The smaller this set, the faster our CI, because we - ## won't need to re-run when things change outside of it. - with subtest("Unpacking"): - deployer.succeed("cp -r --no-preserve=mode ${ - fileset.toSource { - root = ../../..; - fileset = config.sourceFileset; - } - }/* .") - - with subtest("Configure the network"): - ${forConcat config.targetMachines ( - tm: - let - targetNetworkJSON = writeText "target-network.json" ( - toJSON config.nodes.${tm}.system.build.networkConfig - ); - in - '' - deployer.copy_from_host("${targetNetworkJSON}", "${config.pathFromRoot}/${tm}-network.json") - '' - )} - - with subtest("Configure the deployer key"): - deployer.succeed("""mkdir -p ~/.ssh && ssh-keygen -t rsa -N "" -f ~/.ssh/id_rsa""") - deployer_key = deployer.succeed("cat ~/.ssh/id_rsa.pub").strip() - ${forConcat config.targetMachines (tm: '' - ${tm}.succeed(f"mkdir -p /root/.ssh && echo '{deployer_key}' >> /root/.ssh/authorized_keys") - '')} - - with subtest("Configure the target host key"): - ${forConcat config.targetMachines (tm: '' - host_key = ${tm}.succeed("ssh-keyscan ${tm} | grep -v '^#' | cut -f 2- -d ' ' | head -n 1") - deployer.succeed(f"echo '{host_key}' > ${config.pathFromRoot}/${tm}_host_key.pub") - '')} - - # with subtest("Override the flake and its lock"): - # deployer.succeed("cp ${config.pathFromRoot}/flake-under-test.nix flake.nix") - - ${optionalString config.enableAcme '' - with subtest("Set up handmade DNS"): - deployer.succeed("echo '${config.nodes.acme.networking.primaryIPAddress}' > ${config.pathFromRoot}/acme_server_ip") - ''} - - ${config.extraTestScript} - ''; - }; -} diff --git a/deployment/check/data-model/default.nix b/deployment/check/data-model/default.nix index 5eafbbbc..11c1fb37 100644 --- a/deployment/check/data-model/default.nix +++ b/deployment/check/data-model/default.nix @@ -8,7 +8,7 @@ runNixOSTest { imports = [ ../../data-model.nix ../../function.nix - ./common-nixosTest.nix + ../common/nixosTest.nix ./nixosTest.nix ]; _module.args = { inherit inputs sources; }; diff --git a/deployment/check/panel/constants.nix b/deployment/check/panel/constants.nix index ce3b5e4d..a48d9076 100644 --- a/deployment/check/panel/constants.nix +++ b/deployment/check/panel/constants.nix @@ -8,4 +8,5 @@ pathToRoot = ../../..; pathFromRoot = ./.; enableAcme = true; + useFlake = true; } diff --git a/deployment/check/panel/nixosTest.nix b/deployment/check/panel/nixosTest.nix index ffcb8e53..fddad457 100644 --- a/deployment/check/panel/nixosTest.nix +++ b/deployment/check/panel/nixosTest.nix @@ -128,6 +128,7 @@ in sourceFileset = lib.fileset.unions [ ./constants.nix ./deployment.nix + (config.pathToCwd + "/flake-under-test.nix") # REVIEW: I would like to be able to grab all of `/deployment` minus # `/deployment/check`, but I can't because there is a bunch of other files -- 2.48.1 From 0217b292c85792cf11e00ceddbd825f524cf3c00 Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Sun, 24 Aug 2025 19:45:40 +0200 Subject: [PATCH 31/69] restore imports --- deployment/check/common/deployerNode.nix | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/deployment/check/common/deployerNode.nix b/deployment/check/common/deployerNode.nix index 8c584fcf..3debfe3b 100644 --- a/deployment/check/common/deployerNode.nix +++ b/deployment/check/common/deployerNode.nix @@ -55,6 +55,11 @@ in system.extraDependencies = [ + inputs.nixops4 + inputs.nixops4-nixos + inputs.nixpkgs + + sources.flake-parts sources.nixpkgs sources.flake-inputs -- 2.48.1 From a2f8527f83a5669eaad3c6fd3baafb78d07068d0 Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Sun, 24 Aug 2025 19:45:45 +0200 Subject: [PATCH 32/69] rm comment --- deployment/check/data-model/nixosTest.nix | 1 - 1 file changed, 1 deletion(-) diff --git a/deployment/check/data-model/nixosTest.nix b/deployment/check/data-model/nixosTest.nix index 5a7de78b..238a8b1e 100644 --- a/deployment/check/data-model/nixosTest.nix +++ b/deployment/check/data-model/nixosTest.nix @@ -103,7 +103,6 @@ in inherit (eval.config.system.build) vm vmWithBootLoader; }; in - # import "${pathToRoot}/deployment/nixos.nix" {} { drv_path = os.config.system.build.toplevel.drvPath; out_path = os.config.system.build.toplevel; -- 2.48.1 From aa0e7e2a4258b9678e54872aeb6bd578af0dfbad Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Sun, 24 Aug 2025 19:53:30 +0200 Subject: [PATCH 33/69] download-attempts: settle for just targetNode --- deployment/check/common/deployerNode.nix | 1 - 1 file changed, 1 deletion(-) diff --git a/deployment/check/common/deployerNode.nix b/deployment/check/common/deployerNode.nix index 3debfe3b..c15ebe83 100644 --- a/deployment/check/common/deployerNode.nix +++ b/deployment/check/common/deployerNode.nix @@ -49,7 +49,6 @@ in substituters = mkForce [ ]; hashed-mirrors = null; connect-timeout = 1; - download-attempts = 1; extra-experimental-features = "flakes"; }; -- 2.48.1 From 33da4d6e46ccf400dc9f803be90521470513c566 Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Sun, 24 Aug 2025 20:00:09 +0200 Subject: [PATCH 34/69] mv attempts --- deployment/check/common/targetNode.nix | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/deployment/check/common/targetNode.nix b/deployment/check/common/targetNode.nix index c5986a28..1a0c221d 100644 --- a/deployment/check/common/targetNode.nix +++ b/deployment/check/common/targetNode.nix @@ -29,12 +29,11 @@ in system.switch.enable = true; nix = { + # short-cut network time-outs + settings.download-attempts = 1; ## Not used; save a large copy operation channel.enable = false; registry = lib.mkForce { }; - settings = { - download-attempts = 1; - }; }; services.openssh = { -- 2.48.1 From 975cf8a20047df55042a5b82c85e11f2778c7ea8 Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Sun, 24 Aug 2025 20:00:13 +0200 Subject: [PATCH 35/69] rm getty --- deployment/check/common/targetNode.nix | 2 -- 1 file changed, 2 deletions(-) diff --git a/deployment/check/common/targetNode.nix b/deployment/check/common/targetNode.nix index 1a0c221d..609a3366 100644 --- a/deployment/check/common/targetNode.nix +++ b/deployment/check/common/targetNode.nix @@ -46,8 +46,6 @@ in enableIPv6 = false; }; - services.getty.autologinUser = lib.mkForce "root"; - ## Test VMs don't have a bootloader by default. # boot.loader = { # # GRUB enabled: installation of GRUB on /dev/disk/by-id/virtio-root failed: No such file or directory -- 2.48.1 From e0908843529a15e201a0fed3d9b5045be7477498 Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Sun, 24 Aug 2025 20:00:23 +0200 Subject: [PATCH 36/69] rm comments --- deployment/check/data-model/deployment.nix | 2 -- 1 file changed, 2 deletions(-) diff --git a/deployment/check/data-model/deployment.nix b/deployment/check/data-model/deployment.nix index 135b9944..a6cf51f8 100644 --- a/deployment/check/data-model/deployment.nix +++ b/deployment/check/data-model/deployment.nix @@ -1,13 +1,11 @@ { inputs, - # sources, lib, config, ... }: let - # inherit (import ./constants.nix) targetMachines pathToRoot pathFromRoot; eval = module: (lib.evalModules { -- 2.48.1 From 94a0e930e7d4c48ae2eb6ea6132e845a8a0539ee Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Sun, 24 Aug 2025 20:04:02 +0200 Subject: [PATCH 37/69] reenable firewall --- deployment/check/common/targetNode.nix | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/deployment/check/common/targetNode.nix b/deployment/check/common/targetNode.nix index 609a3366..689fe08d 100644 --- a/deployment/check/common/targetNode.nix +++ b/deployment/check/common/targetNode.nix @@ -41,10 +41,8 @@ in settings.PermitRootLogin = "yes"; }; - networking = { - firewall.enable = false; - enableIPv6 = false; - }; + networking.firewall.allowedTCPPorts = [ 22 ]; + networking.enableIPv6 = false; ## Test VMs don't have a bootloader by default. # boot.loader = { -- 2.48.1 From 9dca16d6b762cdf9ccdc792bd79c8c38e7837e42 Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Sun, 24 Aug 2025 20:07:08 +0200 Subject: [PATCH 38/69] reenable ipv6 --- deployment/check/common/targetNode.nix | 1 - 1 file changed, 1 deletion(-) diff --git a/deployment/check/common/targetNode.nix b/deployment/check/common/targetNode.nix index 689fe08d..01dd1f3a 100644 --- a/deployment/check/common/targetNode.nix +++ b/deployment/check/common/targetNode.nix @@ -42,7 +42,6 @@ in }; networking.firewall.allowedTCPPorts = [ 22 ]; - networking.enableIPv6 = false; ## Test VMs don't have a bootloader by default. # boot.loader = { -- 2.48.1 From fb13af9260048cd6b602c41dc191cf3b73605131 Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Sun, 24 Aug 2025 20:10:44 +0200 Subject: [PATCH 39/69] rm users --- deployment/check/common/targetNode.nix | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/deployment/check/common/targetNode.nix b/deployment/check/common/targetNode.nix index 01dd1f3a..35c17345 100644 --- a/deployment/check/common/targetNode.nix +++ b/deployment/check/common/targetNode.nix @@ -58,24 +58,6 @@ in # # builds but won't boot back up # # to be used with --no-bootloader, which i could only find for flakes # boot.loader.grub.enable = false; - - users.mutableUsers = false; - users.users.root = { - password = "password"; - hashedPassword = null; - hashedPasswordFile = null; - openssh.authorizedKeys.keys = - let - keys = import ../../../keys; - in - lib.attrValues keys.contributors - ++ [ - # allow our panel vm access to the test machines - keys.panel - # allow continuous deployment access - keys.cd - ]; - }; } (mkIf config.enableAcme { -- 2.48.1 From 55912c0c353130a61128392a12d4b7df2f765a11 Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Sun, 24 Aug 2025 20:14:54 +0200 Subject: [PATCH 40/69] simplify grub --- deployment/check/common/targetNode.nix | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/deployment/check/common/targetNode.nix b/deployment/check/common/targetNode.nix index 35c17345..d6497fd0 100644 --- a/deployment/check/common/targetNode.nix +++ b/deployment/check/common/targetNode.nix @@ -44,20 +44,7 @@ in networking.firewall.allowedTCPPorts = [ 22 ]; ## Test VMs don't have a bootloader by default. - # boot.loader = { - # # GRUB enabled: installation of GRUB on /dev/disk/by-id/virtio-root failed: No such file or directory - # grub.enable = false; - # # systemd boot enabled: '/boot' is not a mounted partition. Is the path configured correctly? - # systemd-boot.enable = true; - # efi.canTouchEfiVariables = true; - # }; - # # same issue as no bootloader - # boot.loader.generic-extlinux-compatible.enable = false; - # builds but won't boot back up - boot.loader.grub.forceInstall = true; - # # builds but won't boot back up - # # to be used with --no-bootloader, which i could only find for flakes - # boot.loader.grub.enable = false; + boot.loader.grub.enable = false; } (mkIf config.enableAcme { -- 2.48.1 From 167d38ab9a471ef94a492cf0b75055386c8ce84f Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Sun, 24 Aug 2025 20:15:22 +0200 Subject: [PATCH 41/69] rm users --- deployment/check/common/targetNode.nix | 1 - 1 file changed, 1 deletion(-) diff --git a/deployment/check/common/targetNode.nix b/deployment/check/common/targetNode.nix index d6497fd0..e88be811 100644 --- a/deployment/check/common/targetNode.nix +++ b/deployment/check/common/targetNode.nix @@ -18,7 +18,6 @@ in (modulesPath + "/profiles/qemu-guest.nix") (modulesPath + "/../lib/testing/nixos-test-base.nix") ./sharedOptions.nix - ../../../infra/common/nixos/users.nix ]; config = mkMerge [ -- 2.48.1 From 6257ad5bd10cb87e492545cadccb3ff21883682d Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Sun, 24 Aug 2025 20:27:54 +0200 Subject: [PATCH 42/69] factor out to nixos.nix --- deployment/check/data-model/nixosTest.nix | 17 +---------------- deployment/nixos.nix | 15 ++++++++++++--- 2 files changed, 13 insertions(+), 19 deletions(-) diff --git a/deployment/check/data-model/nixosTest.nix b/deployment/check/data-model/nixosTest.nix index 238a8b1e..52d6f70e 100644 --- a/deployment/check/data-model/nixosTest.nix +++ b/deployment/check/data-model/nixosTest.nix @@ -90,23 +90,8 @@ in autoconf ]; }; - eval = import "${sources.nixpkgs}/nixos/lib/eval-config.nix" { - system = builtins.currentSystem; - specialArgs = { - inherit sources; - }; - modules = [ configuration ]; - }; - os = { - inherit (eval) pkgs config options; - system = eval.config.system.build.toplevel; - inherit (eval.config.system.build) vm vmWithBootLoader; - }; in - { - drv_path = os.config.system.build.toplevel.drvPath; - out_path = os.config.system.build.toplevel; - } + import ${pathToRoot}/deployment/nixos.nix { inherit configuration; } ' ) # instantiate the config in /nix/store diff --git a/deployment/nixos.nix b/deployment/nixos.nix index f2f0d019..65c5fe4b 100644 --- a/deployment/nixos.nix +++ b/deployment/nixos.nix @@ -4,11 +4,20 @@ }: let sources = import ../npins; - os = import "${sources.nixpkgs}/nixos" { inherit system configuration; }; + eval = import "${sources.nixpkgs}/nixos/lib/eval-config.nix" { + inherit system; + specialArgs = { + inherit sources; + }; + modules = [ configuration ]; + }; + os = { + inherit (eval) pkgs config options; + system = eval.config.system.build.toplevel; + inherit (eval.config.system.build) vm vmWithBootLoader; + }; in { - substituters = builtins.concatStringsSep " " os.config.nix.settings.substituters; - trusted_public_keys = builtins.concatStringsSep " " os.config.nix.settings.trusted-public-keys; drv_path = os.config.system.build.toplevel.drvPath; out_path = os.config.system.build.toplevel; } -- 2.48.1 From c33107022b6c5f907ead25b1241b351ecc5ba833 Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Sun, 24 Aug 2025 20:30:06 +0200 Subject: [PATCH 43/69] remove unused JSON-serialized args (sources) --- deployment/check/data-model/nixosTest.nix | 8 -------- 1 file changed, 8 deletions(-) diff --git a/deployment/check/data-model/nixosTest.nix b/deployment/check/data-model/nixosTest.nix index 52d6f70e..13b8ad25 100644 --- a/deployment/check/data-model/nixosTest.nix +++ b/deployment/check/data-model/nixosTest.nix @@ -66,14 +66,6 @@ in ' let - args = builtins.fromJSON "${ - lib.replaceStrings [ "\"" ] [ "\\\\\"" ] ( - lib.strings.toJSON { - inherit sources; - } - ) - }"; - inherit (args) sources; configuration = { pkgs, config, ... }: { imports = [ ${pathToRoot}/deployment/check/common/sharedOptions.nix -- 2.48.1 From d836710cb699f65195b35d2e35feb071c2fef910 Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Sun, 24 Aug 2025 20:31:47 +0200 Subject: [PATCH 44/69] rm cowsay --- deployment/check/data-model/nixosTest.nix | 1 - 1 file changed, 1 deletion(-) diff --git a/deployment/check/data-model/nixosTest.nix b/deployment/check/data-model/nixosTest.nix index 13b8ad25..27bba96e 100644 --- a/deployment/check/data-model/nixosTest.nix +++ b/deployment/check/data-model/nixosTest.nix @@ -42,7 +42,6 @@ in { environment.systemPackages = with pkgs; [ hello - cowsay automake autoconf ]; -- 2.48.1 From 5c38d5ed6715e11709c36754b353a4ad42830f50 Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Sun, 24 Aug 2025 21:46:30 +0200 Subject: [PATCH 45/69] dedupe inputDerivations --- deployment/check/common/deployerNode.nix | 5 ----- 1 file changed, 5 deletions(-) diff --git a/deployment/check/common/deployerNode.nix b/deployment/check/common/deployerNode.nix index c15ebe83..694a9eee 100644 --- a/deployment/check/common/deployerNode.nix +++ b/deployment/check/common/deployerNode.nix @@ -60,16 +60,11 @@ in sources.flake-parts sources.nixpkgs - sources.flake-inputs sources.git-hooks pkgs.stdenv pkgs.stdenvNoCC - pkgs.automake - pkgs.autoconf - pkgs.binutils - pkgs.bison ] ++ ( let -- 2.48.1 From 8860c18e03387b12a9294dff4f47584155edae3d Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Sun, 24 Aug 2025 22:05:27 +0200 Subject: [PATCH 46/69] rm unused ssh settings --- deployment/check/data-model/nixosTest.nix | 2 -- 1 file changed, 2 deletions(-) diff --git a/deployment/check/data-model/nixosTest.nix b/deployment/check/data-model/nixosTest.nix index 27bba96e..5f45174e 100644 --- a/deployment/check/data-model/nixosTest.nix +++ b/deployment/check/data-model/nixosTest.nix @@ -98,9 +98,7 @@ in sshOpts=( -o BatchMode=yes -o StrictHostKeyChecking=no - -o "ConnectionAttempts=1" -o "ConnectTimeout=1" - -o "ServerAliveCountMax=1" -o "ServerAliveInterval=1" ) # get the realized derivation to deploy -- 2.48.1 From 3a78837932d0bf2a0207d6636005da171e71c9c2 Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Sun, 24 Aug 2025 22:14:46 +0200 Subject: [PATCH 47/69] - BatchMode --- deployment/check/data-model/nixosTest.nix | 1 - 1 file changed, 1 deletion(-) diff --git a/deployment/check/data-model/nixosTest.nix b/deployment/check/data-model/nixosTest.nix index 5f45174e..cf6692f3 100644 --- a/deployment/check/data-model/nixosTest.nix +++ b/deployment/check/data-model/nixosTest.nix @@ -96,7 +96,6 @@ in eval "export $(echo $json | jq -r 'to_entries | map("\(.key)=\(.value)") | @sh')" host="root@${nodeName}" sshOpts=( - -o BatchMode=yes -o StrictHostKeyChecking=no -o "ConnectTimeout=1" -o "ServerAliveInterval=1" -- 2.48.1 From e5eb0cadb04607786b0c0242d2fff10cabdd6501 Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Sun, 24 Aug 2025 22:17:24 +0200 Subject: [PATCH 48/69] move fail in --- deployment/check/data-model/nixosTest.nix | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/deployment/check/data-model/nixosTest.nix b/deployment/check/data-model/nixosTest.nix index cf6692f3..830ce714 100644 --- a/deployment/check/data-model/nixosTest.nix +++ b/deployment/check/data-model/nixosTest.nix @@ -49,11 +49,11 @@ in }; extraTestScript = '' - with subtest("Check the status before deployment"): - hello.fail("hello 1>&2") - ${lib.concatStringsSep "\n" ( lib.lists.map (nodeName: '' + with subtest("Check the status before deployment"): + ${nodeName}.fail("${nodeName} 1>&2") + with subtest("Run the deployment for ${nodeName}"): deployer.succeed(""" set -euo pipefail -- 2.48.1 From 347bb7b2422fe3c387cf0d8f47a1a019678ed86a Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Sun, 24 Aug 2025 22:26:17 +0200 Subject: [PATCH 49/69] - auto --- deployment/check/data-model/nixosTest.nix | 8 -------- 1 file changed, 8 deletions(-) diff --git a/deployment/check/data-model/nixosTest.nix b/deployment/check/data-model/nixosTest.nix index 830ce714..98656a08 100644 --- a/deployment/check/data-model/nixosTest.nix +++ b/deployment/check/data-model/nixosTest.nix @@ -25,16 +25,12 @@ in environment.systemPackages = with pkgs; [ jq - automake - autoconf ]; # FIXME: sad times system.extraDependencies = with pkgs; [ jq jq.inputDerivation - automake - autoconf ]; system.extraDependenciesFromModule = @@ -42,8 +38,6 @@ in { environment.systemPackages = with pkgs; [ hello - automake - autoconf ]; }; }; @@ -77,8 +71,6 @@ in environment.systemPackages = with pkgs; [ hello - automake - autoconf ]; }; in -- 2.48.1 From ac1fa31b14f450cd8f9a23b88d6637893a0433c9 Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Sun, 24 Aug 2025 22:41:12 +0200 Subject: [PATCH 50/69] skip is-active sshd --- deployment/check/data-model/nixosTest.nix | 1 - 1 file changed, 1 deletion(-) diff --git a/deployment/check/data-model/nixosTest.nix b/deployment/check/data-model/nixosTest.nix index 98656a08..b58af9b7 100644 --- a/deployment/check/data-model/nixosTest.nix +++ b/deployment/check/data-model/nixosTest.nix @@ -107,7 +107,6 @@ in fi """) ${nodeName}.wait_for_unit("multi-user.target") - ${nodeName}.succeed("systemctl is-active sshd") ${nodeName}.succeed("${nodeName} 1>&2") '') targetMachines )} -- 2.48.1 From ed1518a7c52614a971bebd83bbd710733875a19a Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Sun, 24 Aug 2025 22:58:17 +0200 Subject: [PATCH 51/69] simplify deployment --- deployment/check/data-model/nixosTest.nix | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/deployment/check/data-model/nixosTest.nix b/deployment/check/data-model/nixosTest.nix index b58af9b7..e9f57e2d 100644 --- a/deployment/check/data-model/nixosTest.nix +++ b/deployment/check/data-model/nixosTest.nix @@ -77,23 +77,18 @@ in import ${pathToRoot}/deployment/nixos.nix { inherit configuration; } ' ) - # instantiate the config in /nix/store - "''${command[@]}" -A out_path - # get the other info - json="$("''${command[@]}" --eval --strict --json)" # DEPLOY - declare drv_path - # set our variables using the json object - eval "export $(echo $json | jq -r 'to_entries | map("\(.key)=\(.value)") | @sh')" host="root@${nodeName}" sshOpts=( -o StrictHostKeyChecking=no -o "ConnectTimeout=1" -o "ServerAliveInterval=1" ) + # instantiate the config in /nix/store + "''${command[@]}" -A out_path # get the realized derivation to deploy - outPath=$(nix-store --realize "$drv_path") + outPath=$(nix-store --realize "$("''${command[@]}" --eval --strict --json | jq -r '.drv_path')") # deploy the config by nix-copy-closure NIX_SSHOPTS="''${sshOpts[*]}" nix-copy-closure --to "$host" "$outPath" --gzip --use-substitutes # switch the remote host to the config -- 2.48.1 From f90ee627a3733a6e1ef760a0a4ced5442478f141 Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Mon, 25 Aug 2025 00:21:54 +0200 Subject: [PATCH 52/69] simplify inputDerivations --- deployment/check/common/deployerNode.nix | 28 ----------------------- deployment/check/data-model/nixosTest.nix | 5 ++++ 2 files changed, 5 insertions(+), 28 deletions(-) diff --git a/deployment/check/common/deployerNode.nix b/deployment/check/common/deployerNode.nix index 694a9eee..dcb5deef 100644 --- a/deployment/check/common/deployerNode.nix +++ b/deployment/check/common/deployerNode.nix @@ -96,35 +96,7 @@ in machine.system.build.vm.inputDerivation machine.system.build.bootStage1.inputDerivation machine.system.build.bootStage2.inputDerivation - pkgs.automake.inputDerivation - pkgs.autoconf.inputDerivation - pkgs.bash.inputDerivation - pkgs.binutils.inputDerivation - pkgs.bison.inputDerivation ] - ++ concatLists ( - lib.lists.map ( - pkg: - if - pkg ? inputDerivation - # error: output '/nix/store/dki9d3vldafg9ydrfm7x0g0rr0qljk98-sudo-1.9.16p2' is not allowed to refer to the following paths: - # /nix/store/2xdmps65ryklmbf025bm4pxv16gb8ajv-sudo-1.9.16p2.tar.gz - # /nix/store/58br4vk3q5akf4g8lx0pqzfhn47k3j8d-bash-5.2p37 - # /nix/store/8v6k283dpbc0qkdq81nb6mrxrgcb10i1-gcc-wrapper-14-20241116 - # /nix/store/9r1nl9ksiyszy4qzzg6y2gcdkca0xmhy-stdenv-linux - # /nix/store/a4rmp6in7igbl1wbz9pli5nq0wiclq0y-groff-1.23.0 - # /nix/store/dki9d3vldafg9ydrfm7x0g0rr0qljk98-sudo-1.9.16p2 - # /nix/store/f5y58qz2fzpzgkhp0nizixi10x04ppyy-linux-pam-1.6.1 - # /nix/store/shkw4qm9qcw5sc5n1k5jznc83ny02r39-default-builder.sh - # /nix/store/vj1c3wf9c11a0qs6p3ymfvrnsdgsdcbq-source-stdenv.sh - # /nix/store/yh6qg1nsi5h2xblcr67030pz58fsaxx3-coreutils-9.6 - && !(lib.strings.hasInfix "sudo" (builtins.toString pkg)) - then - [ pkg.inputDerivation ] - else - [ ] - ) machine.environment.systemPackages - ) ++ concatLists ( lib.mapAttrsToList ( _k: v: if v ? source.inputDerivation then [ v.source.inputDerivation ] else [ ] diff --git a/deployment/check/data-model/nixosTest.nix b/deployment/check/data-model/nixosTest.nix index e9f57e2d..6f4dd3cf 100644 --- a/deployment/check/data-model/nixosTest.nix +++ b/deployment/check/data-model/nixosTest.nix @@ -31,6 +31,11 @@ in system.extraDependencies = with pkgs; [ jq jq.inputDerivation + automake.inputDerivation + autoconf.inputDerivation + bash.inputDerivation + binutils.inputDerivation + bison.inputDerivation ]; system.extraDependenciesFromModule = -- 2.48.1 From 57c0a434b33fd5fe5bb7a4b156635eff2e477298 Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Mon, 25 Aug 2025 00:28:41 +0200 Subject: [PATCH 53/69] unimport qemu-guest --- deployment/check/data-model/nixosTest.nix | 2 -- 1 file changed, 2 deletions(-) diff --git a/deployment/check/data-model/nixosTest.nix b/deployment/check/data-model/nixosTest.nix index 6f4dd3cf..0facf0c7 100644 --- a/deployment/check/data-model/nixosTest.nix +++ b/deployment/check/data-model/nixosTest.nix @@ -1,7 +1,6 @@ { lib, config, - sources, ... }: let @@ -68,7 +67,6 @@ in imports = [ ${pathToRoot}/deployment/check/common/sharedOptions.nix ${pathToRoot}/deployment/check/common/targetNode.nix - ${sources.nixpkgs}/nixos/modules/profiles/qemu-guest.nix ]; enableAcme = ${lib.strings.toJSON config.enableAcme}; -- 2.48.1 From 58bd670d5be8dc4e0ef17bb826f7362d6e6572ab Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Mon, 25 Aug 2025 00:31:38 +0200 Subject: [PATCH 54/69] simplify imputDerivations --- deployment/check/data-model/nixosTest.nix | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/deployment/check/data-model/nixosTest.nix b/deployment/check/data-model/nixosTest.nix index 0facf0c7..3d260ab2 100644 --- a/deployment/check/data-model/nixosTest.nix +++ b/deployment/check/data-model/nixosTest.nix @@ -26,17 +26,6 @@ in jq ]; - # FIXME: sad times - system.extraDependencies = with pkgs; [ - jq - jq.inputDerivation - automake.inputDerivation - autoconf.inputDerivation - bash.inputDerivation - binutils.inputDerivation - bison.inputDerivation - ]; - system.extraDependenciesFromModule = { pkgs, ... }: { -- 2.48.1 From ce39bbe8a85df2dbd546e1ba9e995b2874e56960 Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Mon, 25 Aug 2025 00:45:30 +0200 Subject: [PATCH 55/69] spacing --- deployment/check/data-model/nixosTest.nix | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/deployment/check/data-model/nixosTest.nix b/deployment/check/data-model/nixosTest.nix index 3d260ab2..7c7f1ee0 100644 --- a/deployment/check/data-model/nixosTest.nix +++ b/deployment/check/data-model/nixosTest.nix @@ -8,9 +8,7 @@ let in { _class = "nixosTest"; - name = "deployment-model"; - sourceFileset = lib.fileset.unions [ ../../data-model.nix ../../function.nix @@ -21,11 +19,9 @@ in nodes.deployer = { pkgs, ... }: { - environment.systemPackages = with pkgs; [ jq ]; - system.extraDependenciesFromModule = { pkgs, ... }: { @@ -46,30 +42,22 @@ in set -euo pipefail # INSTANTIATE - command=( - nix-instantiate - --expr - - ' + command=(nix-instantiate --expr ' let configuration = { pkgs, config, ... }: { imports = [ ${pathToRoot}/deployment/check/common/sharedOptions.nix ${pathToRoot}/deployment/check/common/targetNode.nix ]; - enableAcme = ${lib.strings.toJSON config.enableAcme}; acmeNodeIP = if config.enableAcme then config.nodes.acme.networking.primaryIPAddress else null; - environment.systemPackages = with pkgs; [ hello ]; }; in import ${pathToRoot}/deployment/nixos.nix { inherit configuration; } - ' - ) - + ') # DEPLOY host="root@${nodeName}" sshOpts=( -- 2.48.1 From d4e697aa9792bfbbe7e70ae9cf69e7c6c15a2ad9 Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Mon, 25 Aug 2025 11:20:38 +0200 Subject: [PATCH 56/69] try and use deployment --- deployment/check/data-model/deployment.nix | 21 +++++++++++++++++--- deployment/check/data-model/nixosTest.nix | 23 ++++++++++------------ 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/deployment/check/data-model/deployment.nix b/deployment/check/data-model/deployment.nix index a6cf51f8..f843dbb0 100644 --- a/deployment/check/data-model/deployment.nix +++ b/deployment/check/data-model/deployment.nix @@ -1,11 +1,13 @@ { - inputs, - lib, config, + inputs ? (import ../../../default.nix { }).inputs, + sources ? import ../../../npins, ... }: let + inherit (sources) nixpkgs; + lib = import "${nixpkgs}/lib"; eval = module: (lib.evalModules { @@ -33,8 +35,21 @@ let authentication.password = "password"; }; nixos-configuration = - { ... }: + { pkgs, ... }: { + imports = [ + ../common/sharedOptions.nix + ../common/targetNode.nix + "${nixpkgs}/nixos/modules/profiles/qemu-guest.nix" + ]; + + inherit (config) enableAcme; + acmeNodeIP = if config.enableAcme then config.nodes.acme.networking.primaryIPAddress else null; + + environment.systemPackages = with pkgs; [ + hello + ]; + users.users = config.resources.shell.login-shell.apply ( lib.filterAttrs (_name: value: value ? login-shell) requests ); diff --git a/deployment/check/data-model/nixosTest.nix b/deployment/check/data-model/nixosTest.nix index 7c7f1ee0..3b6991eb 100644 --- a/deployment/check/data-model/nixosTest.nix +++ b/deployment/check/data-model/nixosTest.nix @@ -5,6 +5,7 @@ }: let inherit (import ./constants.nix) targetMachines pathToRoot; + escapedJson = v: lib.replaceStrings [ "\"" ] [ "\\\\\"" ] (lib.strings.toJSON v); in { _class = "nixosTest"; @@ -43,20 +44,16 @@ in # INSTANTIATE command=(nix-instantiate --expr ' - let - configuration = { pkgs, config, ... }: { - imports = [ - ${pathToRoot}/deployment/check/common/sharedOptions.nix - ${pathToRoot}/deployment/check/common/targetNode.nix - ]; - enableAcme = ${lib.strings.toJSON config.enableAcme}; - acmeNodeIP = if config.enableAcme then config.nodes.acme.networking.primaryIPAddress else null; - environment.systemPackages = with pkgs; [ - hello - ]; + import ${pathToRoot}/deployment/nixos.nix { + configuration = import ${pathToRoot}/deployment/check/data-model/deployment.nix { + config = builtins.fromJSON "${ + escapedJson { + inherit (config) enableAcme; + acmeNodeIP = if config.enableAcme then config.nodes.acme.networking.primaryIPAddress else null; + } + }"; }; - in - import ${pathToRoot}/deployment/nixos.nix { inherit configuration; } + } ') # DEPLOY host="root@${nodeName}" -- 2.48.1 From b6bae49678305f188debedcaaadd5f2b79f14edd Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Mon, 25 Aug 2025 17:14:45 +0200 Subject: [PATCH 57/69] fix a bug of mismatching names in data model test matches the name of `shell` to `operator-environment`. --- deployment/data-model-test.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deployment/data-model-test.nix b/deployment/data-model-test.nix index c65e37ae..f3a6c7a4 100644 --- a/deployment/data-model-test.nix +++ b/deployment/data-model-test.nix @@ -125,7 +125,7 @@ in nixos.module = { ... }: { - users.users = config.resources.shell.login-shell.apply ( + users.users = config.resources.operator-environment.login-shell.apply ( lib.filterAttrs (_name: value: value ? login-shell) requests ); }; -- 2.48.1 From 5cb2ff605461a84d9d4bb9dc8b5e576d8be9a664 Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Mon, 25 Aug 2025 17:16:59 +0200 Subject: [PATCH 58/69] stylize user-specified names by quotes to clarify their status --- deployment/data-model-test.nix | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/deployment/data-model-test.nix b/deployment/data-model-test.nix index f3a6c7a4..8757939e 100644 --- a/deployment/data-model-test.nix +++ b/deployment/data-model-test.nix @@ -108,7 +108,7 @@ in environments.single-nixos-vm = { config, ... }: { - resources.operator-environment.login-shell.username = "operator"; + resources."operator-environment".login-shell.username = "operator"; implementation = requests: { input = requests; output.nixops4 = @@ -125,7 +125,7 @@ in nixos.module = { ... }: { - users.users = config.resources.operator-environment.login-shell.apply ( + users.users = config.resources."operator-environment".login-shell.apply ( lib.filterAttrs (_name: value: value ? login-shell) requests ); }; @@ -135,7 +135,7 @@ in }; }; options = { - example-configuration = mkOption { + "example-configuration" = mkOption { type = config.configuration; readOnly = true; default = { @@ -143,20 +143,22 @@ in applications.hello.enable = true; }; }; - example-deployment = mkOption { + "example-deployment" = mkOption { type = options.deployments.nestedType; readOnly = true; - default = config.environments.single-nixos-vm.deployment config.example-configuration; + default = config.environments.single-nixos-vm.deployment config."example-configuration"; }; }; } ); - resources = fediversity.applications.hello.resources fediversity.example-configuration.applications.hello; + resources = + fediversity.applications.hello.resources + fediversity."example-configuration".applications.hello; hello-shell = resources.resources.hello.login-shell; - environment = fediversity.environments.single-nixos-vm.resources.operator-environment.login-shell; + environment = fediversity.environments.single-nixos-vm.resources."operator-environment".login-shell; result = mkDeployment { modules = [ - (fediversity.environments.single-nixos-vm.deployment fediversity.example-configuration) + (fediversity.environments.single-nixos-vm.deployment fediversity."example-configuration") ]; }; -- 2.48.1 From b8c77fa7e3dd892371dfc98730fbde8ce172d9dc Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Mon, 25 Aug 2025 17:18:22 +0200 Subject: [PATCH 59/69] wrap application resources to match the input of `apply` --- deployment/data-model-test.nix | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/deployment/data-model-test.nix b/deployment/data-model-test.nix index 8757939e..b875a324 100644 --- a/deployment/data-model-test.nix +++ b/deployment/data-model-test.nix @@ -125,9 +125,9 @@ in nixos.module = { ... }: { - users.users = config.resources."operator-environment".login-shell.apply ( - lib.filterAttrs (_name: value: value ? login-shell) requests - ); + users.users = config.resources."operator-environment".login-shell.apply { + resources = lib.filterAttrs (_name: value: value ? login-shell) requests; + }; }; }; }; -- 2.48.1 From 793d34fbcc375b1d396d8f52c0cc4f26f96c23c0 Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Mon, 25 Aug 2025 18:12:02 +0200 Subject: [PATCH 60/69] fix attrTag by adding mkOption --- deployment/data-model.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deployment/data-model.nix b/deployment/data-model.nix index 230e18f1..73d67f32 100644 --- a/deployment/data-model.nix +++ b/deployment/data-model.nix @@ -64,7 +64,7 @@ let }; }; deployment = attrTag { - ssh-host = { + ssh-host = mkOption { description = "A Terraform deployment by SSH to update a single existing NixOS host."; type = submodule { options = { -- 2.48.1 From 209981280ca47d615ef1f2208f6b1a9564d391f8 Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Mon, 25 Aug 2025 18:12:35 +0200 Subject: [PATCH 61/69] rename deployment to deployment-type, disambiguating from environments' deployment --- deployment/data-model.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deployment/data-model.nix b/deployment/data-model.nix index 73d67f32..e41c4030 100644 --- a/deployment/data-model.nix +++ b/deployment/data-model.nix @@ -63,7 +63,7 @@ let }; }; }; - deployment = attrTag { + deployment-type = attrTag { ssh-host = mkOption { description = "A Terraform deployment by SSH to update a single existing NixOS host."; type = submodule { @@ -185,7 +185,7 @@ in readOnly = true; default = { input-type = application-resources; - output-type = deployment; + output-type = deployment-type; }; }; # TODO(@fricklerhandwerk): maybe this should be a separate thing such as `fediversity-setup`, -- 2.48.1 From ab2a31263d58559b49c01687db30e7e614151a2e Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Mon, 25 Aug 2025 19:40:48 +0200 Subject: [PATCH 62/69] simplify auth to not accept password --- deployment/check/data-model/deployment.nix | 2 +- deployment/data-model.nix | 18 ++++-------------- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/deployment/check/data-model/deployment.nix b/deployment/check/data-model/deployment.nix index f843dbb0..78893e97 100644 --- a/deployment/check/data-model/deployment.nix +++ b/deployment/check/data-model/deployment.nix @@ -32,7 +32,7 @@ let ssh = { host = "localhost"; username = "root"; - authentication.password = "password"; + key-file = null; }; nixos-configuration = { pkgs, ... }: diff --git a/deployment/data-model.nix b/deployment/data-model.nix index e41c4030..581daa8a 100644 --- a/deployment/data-model.nix +++ b/deployment/data-model.nix @@ -45,20 +45,10 @@ let type = nullOr str; default = null; }; - authentication = mkOption { - description = "authentication method"; - type = attrTag { - private-key = mkOption { - description = "path to the user's SSH private key"; - type = str; - example = "/root/.ssh/id_ed25519"; - }; - password = mkOption { - description = "SSH password"; - # TODO: mark as sensitive - type = str; - }; - }; + key-file = mkOption { + description = "path to the user's SSH private key"; + type = nullOr str; + example = "/root/.ssh/id_ed25519"; }; }; }; -- 2.48.1 From 53ffe295f0a0698b02f01da14fbb62d0e95ec7dd Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Mon, 25 Aug 2025 19:42:38 +0200 Subject: [PATCH 63/69] update deployment --- deployment/check/data-model/deployment.nix | 153 ++++++++++++++++----- deployment/check/data-model/options.nix | 15 ++ 2 files changed, 135 insertions(+), 33 deletions(-) create mode 100644 deployment/check/data-model/options.nix diff --git a/deployment/check/data-model/deployment.nix b/deployment/check/data-model/deployment.nix index 78893e97..8c6b1f47 100644 --- a/deployment/check/data-model/deployment.nix +++ b/deployment/check/data-model/deployment.nix @@ -8,6 +8,8 @@ let inherit (sources) nixpkgs; lib = import "${nixpkgs}/lib"; + deployment-config = config; + inherit (lib) mkOption types; eval = module: (lib.evalModules { @@ -20,47 +22,132 @@ let ]; }).config; fediversity = eval ( - { ... }: + { config, ... }: { config = { - environments.single-nixos-vm = - { ... }: - { - implementation = requests: { - input = requests; - output.ssh-host = { - ssh = { - host = "localhost"; - username = "root"; - key-file = null; + 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; }; - nixos-configuration = - { pkgs, ... }: - { - imports = [ - ../common/sharedOptions.nix - ../common/targetNode.nix - "${nixpkgs}/nixos/modules/profiles/qemu-guest.nix" - ]; - - inherit (config) enableAcme; - acmeNodeIP = if config.enableAcme then config.nodes.acme.networking.primaryIPAddress else null; - - environment.systemPackages = with pkgs; [ - hello - ]; - - users.users = config.resources.shell.login-shell.apply ( - lib.filterAttrs (_name: value: value ? login-shell) requests - ); + 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 = + { pkgs, ... }: + { + 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 = lib.optionalAttrs cfg.enable { + resources.hello.login-shell.packages.hello = pkgs.hello; + }; + }; }; + environments.single-nixos-vm = environment: { + resources."operator-environment".login-shell.username = "operator"; + implementation = requests: { + input = requests; + output.ssh-host = { + ssh = { + username = "root"; + inherit (deployment-config) host; + key-file = null; + }; + nixos-configuration = + { pkgs, ... }: + { + imports = [ + ./options.nix + ../common/sharedOptions.nix + ../common/targetNode.nix + "${nixpkgs}/nixos/modules/profiles/qemu-guest.nix" + ]; + + inherit (deployment-config) enableAcme; + acmeNodeIP = + if deployment-config.enableAcme then + deployment-config.nodes.acme.networking.primaryIPAddress + else + null; + + environment.systemPackages = with pkgs; [ + hello + ]; + + users.users = environment.config.resources."operator-environment".login-shell.apply { + resources = lib.filterAttrs (_name: value: value ? login-shell) requests; + }; + }; + }; + }; + }; + }; + options = { + "example-configuration" = mkOption { + type = config.configuration; + default = { + enable = true; + applications.hello.enable = true; + }; + }; + "example-deployment" = mkOption { + default = config.environments.single-nixos-vm.deployment config."example-configuration"; + }; }; } ); in -fediversity.environments.single-nixos-vm.deployment { - enable = true; -} +fediversity."example-deployment" diff --git a/deployment/check/data-model/options.nix b/deployment/check/data-model/options.nix new file mode 100644 index 00000000..8492bee3 --- /dev/null +++ b/deployment/check/data-model/options.nix @@ -0,0 +1,15 @@ +{ + lib, + ... +}: +let + inherit (lib) types; +in +{ + options = { + host = lib.mkOption { + type = types.str; + description = "name of the host to deploy to"; + }; + }; +} -- 2.48.1 From 5e3ab713b8d5227f1c43a413683baceb3b8ea574 Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Mon, 25 Aug 2025 19:45:04 +0200 Subject: [PATCH 64/69] update test --- deployment/check/data-model/nixosTest.nix | 113 +++++++++++++--------- 1 file changed, 67 insertions(+), 46 deletions(-) diff --git a/deployment/check/data-model/nixosTest.nix b/deployment/check/data-model/nixosTest.nix index 3b6991eb..ead89210 100644 --- a/deployment/check/data-model/nixosTest.nix +++ b/deployment/check/data-model/nixosTest.nix @@ -9,6 +9,10 @@ let in { _class = "nixosTest"; + imports = [ + ./options.nix + ]; + name = "deployment-model"; sourceFileset = lib.fileset.unions [ ../../data-model.nix @@ -34,53 +38,70 @@ in extraTestScript = '' ${lib.concatStringsSep "\n" ( - lib.lists.map (nodeName: '' - with subtest("Check the status before deployment"): - ${nodeName}.fail("${nodeName} 1>&2") - - with subtest("Run the deployment for ${nodeName}"): - deployer.succeed(""" - set -euo pipefail - - # INSTANTIATE - command=(nix-instantiate --expr ' - import ${pathToRoot}/deployment/nixos.nix { - configuration = import ${pathToRoot}/deployment/check/data-model/deployment.nix { - config = builtins.fromJSON "${ - escapedJson { - inherit (config) enableAcme; - acmeNodeIP = if config.enableAcme then config.nodes.acme.networking.primaryIPAddress else null; - } - }"; - }; - } - ') - # DEPLOY - host="root@${nodeName}" - sshOpts=( - -o StrictHostKeyChecking=no - -o "ConnectTimeout=1" - -o "ServerAliveInterval=1" + lib.lists.map ( + nodeName: + let + deployment-config = { + inherit (config) enableAcme; + acmeNodeIP = if config.enableAcme then config.nodes.acme.networking.primaryIPAddress else null; + host = nodeName; + }; + inherit + ((import ./deployment.nix { + config = deployment-config; + }).ssh-host.ssh ) - # instantiate the config in /nix/store - "''${command[@]}" -A out_path - # get the realized derivation to deploy - outPath=$(nix-store --realize "$("''${command[@]}" --eval --strict --json | jq -r '.drv_path')") - # deploy the config by nix-copy-closure - NIX_SSHOPTS="''${sshOpts[*]}" nix-copy-closure --to "$host" "$outPath" --gzip --use-substitutes - # switch the remote host to the config - output=$(ssh "''${sshOpts[@]}" "$host" "nix-env --profile /nix/var/nix/profiles/system --set $outPath; nohup $outPath/bin/switch-to-configuration switch &" 2>&1) || echo "status code: $?" - echo "output: $output" - if [[ $output != *"Timeout, server ${nodeName} not responding"* ]]; then - echo "non-timeout error: $output" - exit 1 - else - exit 0 - fi - """) - ${nodeName}.wait_for_unit("multi-user.target") - ${nodeName}.succeed("${nodeName} 1>&2") - '') targetMachines + host + username + key-file + ; + in + '' + with subtest("Check the status before deployment"): + ${nodeName}.fail("${nodeName} 1>&2") + + with subtest("Run the deployment for ${nodeName}"): + deployer.succeed(""" + set -euo pipefail + + # INSTANTIATE + command=(nix-instantiate --show-trace --expr ' + import ${pathToRoot}/deployment/nixos.nix { + configuration = ( + import ${pathToRoot}/deployment/check/data-model/deployment.nix { + config = builtins.fromJSON "${escapedJson deployment-config}"; + } + ).ssh-host.nixos-configuration; + } + ') + # DEPLOY + host="${lib.defaultTo "root" username}@${host}" + sshOpts=( + ${if key-file == null then "" else "-i ${key-file}"} + -o StrictHostKeyChecking=no + -o "ConnectTimeout=1" + -o "ServerAliveInterval=1" + ) + # instantiate the config in /nix/store + "''${command[@]}" --show-trace -A out_path + # get the realized derivation to deploy + outPath=$(nix-store --realize "$("''${command[@]}" --show-trace --eval --strict --json | jq -r '.drv_path')") + # deploy the config by nix-copy-closure + NIX_SSHOPTS="''${sshOpts[*]}" nix-copy-closure --to "$host" "$outPath" --gzip --use-substitutes + # switch the remote host to the config + output=$(ssh "''${sshOpts[@]}" "$host" "nix-env --profile /nix/var/nix/profiles/system --set $outPath; nohup $outPath/bin/switch-to-configuration switch &" 2>&1) || echo "status code: $?" + echo "output: $output" + if [[ $output != *"Timeout, server ${nodeName} not responding"* ]]; then + echo "non-timeout error: $output" + exit 1 + else + exit 0 + fi + """) + ${nodeName}.wait_for_unit("multi-user.target") + ${nodeName}.succeed("${nodeName} 1>&2") + '' + ) targetMachines )} ''; } -- 2.48.1 From 0b06f51113c80cabee610e9096d8c2a9247b245b Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Tue, 26 Aug 2025 17:15:23 +0200 Subject: [PATCH 65/69] pass system --- deployment/check/data-model/deployment.nix | 8 +++++--- deployment/check/data-model/nixosTest.nix | 7 +++++++ deployment/nixos.nix | 4 ++-- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/deployment/check/data-model/deployment.nix b/deployment/check/data-model/deployment.nix index 8c6b1f47..b7fbfdd2 100644 --- a/deployment/check/data-model/deployment.nix +++ b/deployment/check/data-model/deployment.nix @@ -1,5 +1,6 @@ { config, + system, inputs ? (import ../../../default.nix { }).inputs, sources ? import ../../../npins, ... @@ -7,7 +8,8 @@ let inherit (sources) nixpkgs; - lib = import "${nixpkgs}/lib"; + pkgs = import nixpkgs { inherit system; }; + inherit (pkgs) lib; deployment-config = config; inherit (lib) mkOption types; eval = @@ -81,7 +83,7 @@ let }; }; applications.hello = - { pkgs, ... }: + { ... }: { description = ''Command-line tool that will print "Hello, world!" on the terminal''; module = @@ -107,7 +109,7 @@ let key-file = null; }; nixos-configuration = - { pkgs, ... }: + { ... }: { imports = [ ./options.nix diff --git a/deployment/check/data-model/nixosTest.nix b/deployment/check/data-model/nixosTest.nix index ead89210..a0b95cdc 100644 --- a/deployment/check/data-model/nixosTest.nix +++ b/deployment/check/data-model/nixosTest.nix @@ -1,6 +1,7 @@ { lib, config, + pkgs, ... }: let @@ -48,6 +49,7 @@ in }; inherit ((import ./deployment.nix { + inherit (pkgs) system; config = deployment-config; }).ssh-host.ssh ) @@ -66,9 +68,14 @@ in # INSTANTIATE command=(nix-instantiate --show-trace --expr ' + let + system = "${pkgs.system}"; # FIXME: what system are we deploying to? + in import ${pathToRoot}/deployment/nixos.nix { + inherit system; configuration = ( import ${pathToRoot}/deployment/check/data-model/deployment.nix { + inherit system; config = builtins.fromJSON "${escapedJson deployment-config}"; } ).ssh-host.nixos-configuration; diff --git a/deployment/nixos.nix b/deployment/nixos.nix index 65c5fe4b..c5228106 100644 --- a/deployment/nixos.nix +++ b/deployment/nixos.nix @@ -1,9 +1,9 @@ { configuration, - system ? builtins.currentSystem, + system, + sources ? import ../npins, }: let - sources = import ../npins; eval = import "${sources.nixpkgs}/nixos/lib/eval-config.nix" { inherit system; specialArgs = { -- 2.48.1 From 16133d7fe84fe3d8328b89111c0170a1980869f7 Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Tue, 26 Aug 2025 17:29:32 +0200 Subject: [PATCH 66/69] actually rely on user package from data model --- deployment/check/data-model/deployment.nix | 4 ---- deployment/check/data-model/nixosTest.nix | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/deployment/check/data-model/deployment.nix b/deployment/check/data-model/deployment.nix index b7fbfdd2..27de537b 100644 --- a/deployment/check/data-model/deployment.nix +++ b/deployment/check/data-model/deployment.nix @@ -125,10 +125,6 @@ let else null; - environment.systemPackages = with pkgs; [ - hello - ]; - users.users = environment.config.resources."operator-environment".login-shell.apply { resources = lib.filterAttrs (_name: value: value ? login-shell) requests; }; diff --git a/deployment/check/data-model/nixosTest.nix b/deployment/check/data-model/nixosTest.nix index a0b95cdc..11c0e3a6 100644 --- a/deployment/check/data-model/nixosTest.nix +++ b/deployment/check/data-model/nixosTest.nix @@ -106,7 +106,7 @@ in fi """) ${nodeName}.wait_for_unit("multi-user.target") - ${nodeName}.succeed("${nodeName} 1>&2") + ${nodeName}.succeed("su - operator -c ${nodeName} 1>&2") '' ) targetMachines )} -- 2.48.1 From ede5b4db111b49182d37e2c6667c42225a09fea4 Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Tue, 26 Aug 2025 17:31:53 +0200 Subject: [PATCH 67/69] simpler data model, not sure it's desirable but at least it's consistent --- deployment/check/data-model/deployment.nix | 14 +++++++------- deployment/data-model-test.nix | 16 ++++++++-------- deployment/data-model.nix | 20 ++++++++------------ 3 files changed, 23 insertions(+), 27 deletions(-) diff --git a/deployment/check/data-model/deployment.nix b/deployment/check/data-model/deployment.nix index 27de537b..76abe204 100644 --- a/deployment/check/data-model/deployment.nix +++ b/deployment/check/data-model/deployment.nix @@ -66,9 +66,7 @@ let 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; + validRequests = lib.filterAttrs (_name: req: !req.login-shell.wheel || config.wheel) requests; in lib.optionalAttrs (validRequests != { }) { ${config.username} = { @@ -94,7 +92,7 @@ let implementation = cfg: { input = cfg; output = lib.optionalAttrs cfg.enable { - resources.hello.login-shell.packages.hello = pkgs.hello; + "my".login-shell.packages.hello = pkgs.hello; }; }; }; @@ -125,9 +123,11 @@ let else null; - users.users = environment.config.resources."operator-environment".login-shell.apply { - resources = lib.filterAttrs (_name: value: value ? login-shell) requests; - }; + users.users = environment.config.resources."operator-environment".login-shell.apply ( + lib.filterAttrs (_name: value: value ? login-shell) ( + lib.concatMapAttrs (k': lib.mapAttrs' (k: v: lib.nameValuePair "${k'}.${k}" v)) requests + ) + ); }; }; }; diff --git a/deployment/data-model-test.nix b/deployment/data-model-test.nix index b875a324..69a4408c 100644 --- a/deployment/data-model-test.nix +++ b/deployment/data-model-test.nix @@ -73,9 +73,7 @@ in 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; + validRequests = lib.filterAttrs (_name: req: !req.login-shell.wheel || config.wheel) requests; in lib.optionalAttrs (validRequests != { }) { ${config.username} = { @@ -101,7 +99,7 @@ in implementation = cfg: { input = cfg; output = lib.optionalAttrs cfg.enable { - resources.hello.login-shell.packages.hello = pkgs.hello; + "my".login-shell.packages.hello = pkgs.hello; }; }; }; @@ -125,9 +123,11 @@ in nixos.module = { ... }: { - users.users = config.resources."operator-environment".login-shell.apply { - resources = lib.filterAttrs (_name: value: value ? login-shell) requests; - }; + users.users = config.resources."operator-environment".login-shell.apply ( + lib.filterAttrs (_name: value: value ? login-shell) ( + lib.concatMapAttrs (k': lib.mapAttrs' (k: v: lib.nameValuePair "${k'}.${k}" v)) requests + ) + ); }; }; }; @@ -154,7 +154,7 @@ in resources = fediversity.applications.hello.resources fediversity."example-configuration".applications.hello; - hello-shell = resources.resources.hello.login-shell; + hello-shell = resources."my".login-shell; environment = fediversity.environments.single-nixos-vm.resources."operator-environment".login-shell; result = mkDeployment { modules = [ diff --git a/deployment/data-model.nix b/deployment/data-model.nix index 581daa8a..21ad803e 100644 --- a/deployment/data-model.nix +++ b/deployment/data-model.nix @@ -18,16 +18,12 @@ let ; functionType = import ./function.nix; - application-resources = submodule { - options.resources = mkOption { - # TODO: maybe transpose, and group the resources by type instead - type = attrsOf ( - attrTag ( - lib.mapAttrs (_name: resource: mkOption { type = submodule resource.request; }) config.resources - ) - ); - }; - }; + # TODO: maybe transpose, and group the resources by type instead + application-resources = attrsOf ( + attrTag ( + lib.mapAttrs (_name: resource: mkOption { type = submodule resource.request; }) config.resources + ) + ); nixos-configuration = mkOption { description = "A NixOS configuration."; type = raw; @@ -93,7 +89,7 @@ in description = "The type of resource this policy configures"; type = types.optionType; }; - # TODO(@fricklerhandwerk): we may want to make the function type explict here: `request -> resource-type` + # TODO(@fricklerhandwerk): we may want to make the function type explicit here: `attrsOf request -> resource-type` # and then also rename this to be consistent with the application's resource mapping options.apply = mkOption { description = "Apply the policy to a request"; @@ -174,7 +170,7 @@ in type = submodule functionType; readOnly = true; default = { - input-type = application-resources; + input-type = attrsOf application-resources; output-type = deployment-type; }; }; -- 2.48.1 From 3fa1756feb5944711a5a39c3516c6090d1640eb6 Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Tue, 26 Aug 2025 23:31:48 +0200 Subject: [PATCH 68/69] restore data model with { resources } wrappers, this time working --- deployment/check/data-model/deployment.nix | 20 ++++++++++++-------- deployment/data-model-test.nix | 22 +++++++++++++--------- deployment/data-model.nix | 19 +++++++++++-------- 3 files changed, 36 insertions(+), 25 deletions(-) diff --git a/deployment/check/data-model/deployment.nix b/deployment/check/data-model/deployment.nix index 76abe204..36f9013b 100644 --- a/deployment/check/data-model/deployment.nix +++ b/deployment/check/data-model/deployment.nix @@ -66,7 +66,9 @@ let 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; + validRequests = lib.filterAttrs ( + _name: req: !req.login-shell.wheel || config.wheel + ) requests.resources; in lib.optionalAttrs (validRequests != { }) { ${config.username} = { @@ -91,8 +93,8 @@ let }; implementation = cfg: { input = cfg; - output = lib.optionalAttrs cfg.enable { - "my".login-shell.packages.hello = pkgs.hello; + output.resources = lib.optionalAttrs cfg.enable { + hello.login-shell.packages.hello = pkgs.hello; }; }; }; @@ -123,11 +125,13 @@ let else null; - users.users = environment.config.resources."operator-environment".login-shell.apply ( - lib.filterAttrs (_name: value: value ? login-shell) ( - lib.concatMapAttrs (k': lib.mapAttrs' (k: v: lib.nameValuePair "${k'}.${k}" v)) requests - ) - ); + 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/data-model-test.nix b/deployment/data-model-test.nix index 69a4408c..d72baf11 100644 --- a/deployment/data-model-test.nix +++ b/deployment/data-model-test.nix @@ -73,7 +73,9 @@ in 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; + validRequests = lib.filterAttrs ( + _name: req: !req.login-shell.wheel || config.wheel + ) requests.resources; in lib.optionalAttrs (validRequests != { }) { ${config.username} = { @@ -98,8 +100,8 @@ in }; implementation = cfg: { input = cfg; - output = lib.optionalAttrs cfg.enable { - "my".login-shell.packages.hello = pkgs.hello; + output.resources = lib.optionalAttrs cfg.enable { + hello.login-shell.packages.hello = pkgs.hello; }; }; }; @@ -123,11 +125,13 @@ in nixos.module = { ... }: { - users.users = config.resources."operator-environment".login-shell.apply ( - lib.filterAttrs (_name: value: value ? login-shell) ( - lib.concatMapAttrs (k': lib.mapAttrs' (k: v: lib.nameValuePair "${k'}.${k}" v)) requests - ) - ); + users.users = 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 + ); + }; }; }; }; @@ -154,7 +158,7 @@ in resources = fediversity.applications.hello.resources fediversity."example-configuration".applications.hello; - hello-shell = resources."my".login-shell; + hello-shell = resources.resources.hello.login-shell; environment = fediversity.environments.single-nixos-vm.resources."operator-environment".login-shell; result = mkDeployment { modules = [ diff --git a/deployment/data-model.nix b/deployment/data-model.nix index 21ad803e..90d3b0d2 100644 --- a/deployment/data-model.nix +++ b/deployment/data-model.nix @@ -18,12 +18,16 @@ let ; functionType = import ./function.nix; - # TODO: maybe transpose, and group the resources by type instead - application-resources = attrsOf ( - attrTag ( - lib.mapAttrs (_name: resource: mkOption { type = submodule resource.request; }) config.resources - ) - ); + application-resources = submodule { + options.resources = mkOption { + # TODO: maybe transpose, and group the resources by type instead + type = attrsOf ( + attrTag ( + lib.mapAttrs (_name: resource: mkOption { type = submodule resource.request; }) config.resources + ) + ); + }; + }; nixos-configuration = mkOption { description = "A NixOS configuration."; type = raw; @@ -89,8 +93,7 @@ in description = "The type of resource this policy configures"; type = types.optionType; }; - # TODO(@fricklerhandwerk): we may want to make the function type explicit here: `attrsOf request -> resource-type` - # and then also rename this to be consistent with the application's resource mapping + # TODO(@fricklerhandwerk): we may want to make the function type explicit here: `application-resources -> resource-type` options.apply = mkOption { description = "Apply the policy to a request"; type = functionTo policy.config.resource-type; -- 2.48.1 From 2283a62ae93992a7c92cac5d2fc18ed8ea7464a9 Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Tue, 26 Aug 2025 23:47:03 +0200 Subject: [PATCH 69/69] adjust deployment type this is a cop-out possible until https://git.fediversity.eu/fricklerhandwerk/Fediversity/pulls/15. after that, this will require actually figuring out how to get `options` for `deployment.nix` - which may need `evalModules` with `data-model.nix`. --- deployment/check/data-model/deployment.nix | 1 + deployment/data-model-test.nix | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/deployment/check/data-model/deployment.nix b/deployment/check/data-model/deployment.nix index 36f9013b..69380519 100644 --- a/deployment/check/data-model/deployment.nix +++ b/deployment/check/data-model/deployment.nix @@ -146,6 +146,7 @@ let }; }; "example-deployment" = mkOption { + type = config.environments.single-nixos-vm.resource-mapping.output-type; default = config.environments.single-nixos-vm.deployment config."example-configuration"; }; }; diff --git a/deployment/data-model-test.nix b/deployment/data-model-test.nix index d72baf11..e754bc03 100644 --- a/deployment/data-model-test.nix +++ b/deployment/data-model-test.nix @@ -31,7 +31,7 @@ in expr = let fediversity = eval ( - { config, options, ... }: + { config, ... }: { config = { resources.login-shell = { @@ -148,7 +148,7 @@ in }; }; "example-deployment" = mkOption { - type = options.deployments.nestedType; + type = config.environments.single-nixos-vm.resource-mapping.output-type; readOnly = true; default = config.environments.single-nixos-vm.deployment config."example-configuration"; }; -- 2.48.1