From 91b5c7b1bd89bed98697295a0a23bb865dbfbcce Mon Sep 17 00:00:00 2001 From: Kiara Grouwstra Date: Sat, 19 Jul 2025 12:18:03 +0200 Subject: [PATCH] model: add classes --- deployment/data-model-test.nix | 10 ++ deployment/data-model.nix | 279 ++++++++++++++++++--------------- deployment/function.nix | 1 + 3 files changed, 166 insertions(+), 124 deletions(-) diff --git a/deployment/data-model-test.nix b/deployment/data-model-test.nix index 704abea9..6a5d7161 100644 --- a/deployment/data-model-test.nix +++ b/deployment/data-model-test.nix @@ -22,6 +22,7 @@ in fediversity = eval ( { config, ... }: { + _class = "fediversity-settings"; config = { resources.nixos-configuration = { description = "An entire NixOS configuration"; @@ -51,6 +52,7 @@ in }; }; resources.login-shell = { + _class = "fediversity-resource"; description = "The operator needs to be able to log into the shell"; request = { ... }: @@ -104,10 +106,12 @@ in applications.hello = { ... }: { + _class = "fediversity-application"; description = ''Command-line tool that will print "Hello, world!" on the terminal''; module = { ... }: { + _class = "fediversity-application-config"; options = { enable = lib.mkEnableOption "Hello in the shell"; }; @@ -115,21 +119,25 @@ in implementation = cfg: lib.optionalAttrs cfg.enable { + _class = "fediversity-application-requirements"; dummy.login-shell.packages.hello = pkgs.hello; }; }; environments.single-nixos-vm = { config, ... }: { + _class = "fediversity-environment"; resources.shell.login-shell.username = "operator"; implementation = requests: { providers, ... }: { + _class = "nixops4Deployment"; providers = { inherit (inputs.nixops4.modules.nixops4Provider) local; }; resources.the-machine = { + _class = "nixops4Resource"; type = providers.local.exec; imports = [ inputs.nixops4-nixos.modules.nixops4Resource.nixos @@ -137,6 +145,7 @@ in nixos.module = { ... }: { + _class = "nixos"; users.users = config.resources.shell.login-shell.apply ( lib.filterAttrs (_name: value: value ? login-shell) requests ); @@ -150,6 +159,7 @@ in type = config.configuration; readOnly = true; default = { + _class = "fediversity-configuration"; enable = true; applications.hello.enable = true; }; diff --git a/deployment/data-model.nix b/deployment/data-model.nix index 07b66d1a..a6f77fcc 100644 --- a/deployment/data-model.nix +++ b/deployment/data-model.nix @@ -10,13 +10,14 @@ let attrsOf attrTag deferredModuleWith - submodule + submoduleWith optionType functionTo ; functionType = import ./function.nix; - application-resources = { + application-requirements = { + _class = "fediversity-application-requirements"; options.resources = mkOption { # TODO: maybe transpose, and group the resources by type instead type = attrsOf ( @@ -26,79 +27,85 @@ let }; in { - _class = "nixops4Deployment"; - + _class = "fediversity-settings"; 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 = [ - { - _class = "fediversity-resource-policy"; - options.apply = mkOption { - description = "Apply the policy to a request"; - }; - } - ]; + type = attrsOf (submoduleWith { + class = "fediversity-resource"; + modules = [ + ( + { ... }: + { + 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 = submoduleWith { + class = "fediversity-resource-policy"; + modules = [ + { + options.apply = mkOption { + description = "Apply the policy to a request"; + }; + } + ]; + }; }; }; - }; - } - ) - ); + } + ) + ]; + }); }; applications = mkOption { description = "Collection of Fediversity applications"; - type = attrsOf ( - submodule (application: { - _class = "fediversity-application"; - options = { - description = mkOption { - description = "Description to be shown in the application overview"; - type = types.str; - }; - module = mkOption { - description = "Operator-facing configuration options for the application"; - type = deferredModuleWith { staticModules = [ { _class = "fediversity-application-config"; } ]; }; - }; - implementation = mkOption { - description = "Mapping of application configuration to deployment resources, a description of what an application needs to run"; - type = application.config.config-mapping.function-type; - }; - resources = mkOption { - description = "Compute resources required by an application"; - type = functionTo application.config.config-mapping.output-type; - readOnly = true; - default = input: (application.config.implementation input).output; - }; - 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; - output-type = application-resources; + type = attrsOf (submoduleWith { + class = "fediversity-application"; + modules = [ + (application: { + options = { + description = mkOption { + description = "Description to be shown in the application overview"; + type = types.str; + }; + module = mkOption { + description = "Operator-facing configuration options for the application"; + type = deferredModuleWith { staticModules = [ { _class = "fediversity-application-config"; } ]; }; + }; + implementation = mkOption { + description = "Mapping of application configuration to deployment resources, a description of what an application needs to run"; + type = application.config.config-mapping.function-type; + }; + resources = mkOption { + description = "Compute resources required by an application"; + type = functionTo application.config.config-mapping.output-type; + readOnly = true; + default = input: (application.config.implementation input).output; + }; + config-mapping = mkOption { + description = "Function type for the mapping from application configuration to required resources"; + type = submoduleWith { + class = "module-function"; + modules = [ functionType ]; + }; + readOnly = true; + default = { + input-type = application.config.module; + output-type = application-requirements; + }; }; }; - }; - }) - ); + }) + ]; + }); }; configuration = mkOption { description = "Configuration type declaring options to be set by operators"; @@ -122,73 +129,97 @@ 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. + type = attrsOf (submoduleWith { + class = "fediversity-environment"; + modules = [ + (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 = submoduleWith { + class = "fediversity-resource-policy"; + modules = [ 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 = submoduleWith { + class = "module-function"; + modules = [ functionType ]; + }; + readOnly = true; + default = { + input-type = application-requirements; + output-type = nixops4Deployment; + }; + }; + deployment = mkOption { + description = "Generate a deployment from a configuration"; + type = functionTo (submoduleWith { + class = "nixops4Deployment"; + modules = [ 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; - 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; }; }; - deployment = mkOption { - description = "Generate a deployment from a configuration"; - type = functionTo (submodule 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; readOnly = true; - default = submodule { - options = { - enable = lib.mkEnableOption { - description = "your Fediversity configuration"; - }; - applications = lib.mapAttrs ( - _name: application: - mkOption { - description = application.description; - type = submodule application.module; - default = { }; - } - ) config.applications; - }; + default = submoduleWith { + class = "fediversity-configuration"; + modules = [ + { + options = { + enable = lib.mkEnableOption { + description = "your Fediversity configuration"; + }; + applications = lib.mapAttrs ( + _name: application: + mkOption { + description = application.description; + type = submoduleWith { + class = "fediversity-application-config"; + modules = [ application.module ]; + }; + default = { }; + } + ) config.applications; + }; + } + ]; }; }; }; diff --git a/deployment/function.nix b/deployment/function.nix index d1a047f0..635cefa4 100644 --- a/deployment/function.nix +++ b/deployment/function.nix @@ -13,6 +13,7 @@ let in { options = { + _class = "module-function"; input-type = mkOption { type = deferredModule; };