From 71446a891f8a912771b62b1a26662c01d992725a Mon Sep 17 00:00:00 2001 From: Valentin Gagarin Date: Wed, 2 Jul 2025 03:39:36 +0200 Subject: [PATCH] WIP: (broken) implement test --- deployment/data-model-test.nix | 78 ++++++++++++++++++++++++++++++++++ deployment/data-model.nix | 49 ++++++++++++++++++--- 2 files changed, 121 insertions(+), 6 deletions(-) diff --git a/deployment/data-model-test.nix b/deployment/data-model-test.nix index 5e4879d3..d0c2a91d 100644 --- a/deployment/data-model-test.nix +++ b/deployment/data-model-test.nix @@ -23,6 +23,57 @@ 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; + }; + apply = mkOption { + type = with types; functionTo raw; # TODO: splice out the user type from NixOS + default = + requests: + let + # Filter out requests that need wheel if policy doesn't allow it + validRequests = lib.filterAttrs (name: req: !req.wheel || config.wheel) requests; + in + lib.optionalAttrs (validRequests != { }) { + ${config.username} = { + isNormalUser = true; + packages = with lib; concatMapAttrs (name: request: attrValues request.packages) validRequests; + extraGroups = lib.optional config.wheel "wheel"; + }; + }; + }; + }; + }; + }; applications.hello = { ... }: { @@ -40,6 +91,32 @@ in dummy.login-shell.packages.hello = pkgs.hello; }; }; + environments.single-nixos-vm = + { config, ... }: + { + resources.shell.login-shell.username = "operator"; + implementation = + requests: + { providers, ... }: + { + providers = { + inherit (inputs.nixops4.modules.nixops4Provider) local; + }; + resources.the-machine = { + type = providers.local.exec; + imports = [ + inputs.nixops4-nixos.modules.nixops4Resource.nixos + ]; + nixos.module = + { pkgs, ... }: + { + users.users = config.resources.shell.login-shell.apply ( + lib.filterAttrs (name: value: value ? login-shell) requests + ); + }; + }; + }; + }; }; options = { example-configuration = mkOption { @@ -57,6 +134,7 @@ in configurations.example = { enable = true; applications.hello.enable = true; + # default = config.environments.single-nixos-vm.deployment config.example-configuration; }; } ); diff --git a/deployment/data-model.nix b/deployment/data-model.nix index 0d3868ee..a7692232 100644 --- a/deployment/data-model.nix +++ b/deployment/data-model.nix @@ -29,6 +29,40 @@ 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 ( + { config, ... }: + { + _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 = [ + { + _class = "fediversity-resource-policy"; + options.apply = mkOption { + desciption = "Apply the policy to a request"; + }; + } + ]; + }; + }; + }; + } + ) + ); + }; applications = mkOption { description = "Collection of Fediversity applications"; type = attrsOf ( @@ -93,11 +127,16 @@ in _class = "fediversity-environment"; options = { resources = mkOption { - description = "Resources made available by the hosting provider"; + 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: { - ${name} = mkOption { type = resource.provider; }; + ${name} = mkOption { type = resource.policy; }; }) config.resources ) ); @@ -140,10 +179,8 @@ in readOnly = true; default = submodule (configuration: { options = { - enable = mkOption { - description = "Whether to enable the configuration"; - type = types.bool; - default = false; + enable = lib.mkEnableOption { + description = "your Fediversity configuration"; }; applications = lib.mapAttrs ( name: application: