From f8d1be9f6e5b16d98284b098635ce887a942b34e Mon Sep 17 00:00:00 2001 From: Valentin Gagarin Date: Wed, 2 Jul 2025 01:20:35 +0200 Subject: [PATCH] WIP: implement mappings --- deployment/data-model-test.nix | 46 +++++++++++++++------- deployment/data-model.nix | 71 ++++++++++++++++++++++++---------- deployment/function.nix | 30 ++++++++++++++ deployment/interface.nix | 49 ----------------------- 4 files changed, 114 insertions(+), 82 deletions(-) create mode 100644 deployment/function.nix delete mode 100644 deployment/interface.nix diff --git a/deployment/data-model-test.nix b/deployment/data-model-test.nix index 92b20d88..76b643b2 100644 --- a/deployment/data-model-test.nix +++ b/deployment/data-model-test.nix @@ -1,6 +1,7 @@ let inherit (import ../default.nix { }) pkgs inputs; inherit (pkgs) lib; + inherit (lib) mkOption types; eval = module: (lib.evalModules { @@ -12,6 +13,7 @@ let ./data-model.nix ]; }).config; + nixops4Deployment = inputs.nixops4.modules.nixops4Deployment.default; in { test-eval = { @@ -20,18 +22,35 @@ in fediversity = eval ( { config, ... }: { - resources.nixos = { - + config = { + resources.nixos = { + # TODO: consumer = ? + # TODO: provider = ? + }; + applications.hello = { + description = ''Command-line tool that will print "Hello, world!" on the terminal''; + # TODO: module = ? + # TODO: config=mapping = ? + }; + environments.single-nixos-vm = { + # TODO: resources = ? + # TODO: resource-mapping = ? + }; }; - applications.hello = { - - }; - environments.single-nixos-vm = { - - }; - configurations.example = { - enable = true; - applications.hello.enable = true; + options = { + example-configuration = mkOption { + type = config.configuration; + readOnly = true; + default = { + enable = true; + applications.hello.enable = true; + }; + }; + example-deployment = mkOption { + type = nixops4Deployment; + readOnly = true; + default = config.environments.single-nixos-vm.deployment config.example-configuration; + }; }; } ); @@ -39,7 +58,8 @@ in { }; - expected = { - }; + expected = + { + }; }; } diff --git a/deployment/data-model.nix b/deployment/data-model.nix index 82a1e165..9f2a7e9f 100644 --- a/deployment/data-model.nix +++ b/deployment/data-model.nix @@ -12,9 +12,11 @@ let deferredModuleWith submoduleWith submodule + optionType + functionTo ; - functionType = import ./interface.nix; + functionType = import ./function.nix; application-resources = { options.resources = mkOption { type = attrsOf ( @@ -39,11 +41,11 @@ in _class = "fediversity-resource"; options = { consumer = mkOption { - description = "Configuration of the resource by an application, a description of how the resource is consumed"; + description = "Options for declaring resource requirements by an application, a description of how the resource is consumed"; type = deferredModuleWith { staticModules = [ { _class = "fediversity-resource-consumer"; } ]; }; }; provider = mkOption { - description = "Configuration of the resource by the hosting provider, a description of how the resource is made available"; + description = "Options for configuring the resource for the hosting provider, a description of how the resource is made available"; type = deferredModuleWith { staticModules = [ { _class = "fediversity-resource-provider"; } ]; }; }; }; @@ -57,18 +59,25 @@ in 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"; } ]; }; }; - config-mapping = mkOption { + implementation = mkOption { description = "Mapping of application configuration to deployment resources, a description of what an application needs to run"; - type = application.config.function.implementation; + type = application.config.config-mapping.function-type; }; - # TODO: somewhere we still need to - # - apply = { implementation = config-mapping; input = ; } - # - apply.output (applications required by resources) - function = mkOption { + 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; @@ -97,35 +106,57 @@ in ) ); }; - resource-mapping = mkOption { + implementation = mkOption { description = "Mapping of resources required by applications to available resources; the result can be deployed"; - type = environment.config.function.implementation; + type = environment.config.resource-mapping.function-type; }; - # TODO: somewhere we still need to - # - apply = { implementation = resource-mapping; input = ; } - # - apply.output (deployment) - function = mkOption { + 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 = submodule nixops4Deployment; + output-type = nixops4Deployment; }; }; + deployment = mkOption { + description = "Generate a deployment from a configuration"; + 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; + + }; }; }) ); }; - configurations = mkOption { - description = "Application configurations set by operators"; - type = attrsOf (submodule { + configuration = mkOption { + description = "Configuration type declaring options to be set by operators"; + type = optionType; + readOnly = true; + default = submodule (configuration: { options = { enable = mkOption { description = "Whether to enable the configuration"; type = types.bool; + default = false; }; - applications = mapAttrs (name: application: submodule application.module) config.applications; + applications = lib.mapAttrs ( + name: application: + mkOption { + description = application.description; + type = submodule application.module; + default = { }; + } + ) config.applications; }; }); }; diff --git a/deployment/function.nix b/deployment/function.nix new file mode 100644 index 00000000..b6a208f0 --- /dev/null +++ b/deployment/function.nix @@ -0,0 +1,30 @@ +/** + Modular function type +*/ +{ config, ... }: +{ + options = { + input-type = mkOption { + type = deferredModule; + }; + output-type = mkOption { + type = deferredModule; + }; + function-type = mkOption { + type = optionType; + readOnly = true; + default = functionTo ( + submodule (function: { + options = { + input = mkOption { + type = submodule config.input-type; + }; + output = mkOption { + type = submodule config.output-type; + }; + }; + }) + ); + }; + }; +} diff --git a/deployment/interface.nix b/deployment/interface.nix deleted file mode 100644 index 225526d1..00000000 --- a/deployment/interface.nix +++ /dev/null @@ -1,49 +0,0 @@ -/** - Modular function type -*/ -{ config, ... }: -{ - options = { - input-type = mkOption { - type = deferredModule; - }; - output-type = mkOption { - type = deferredModule; - }; - implementation = mkOption { - type = optionType; - readOnly = true; - default = implementationTo ( - submodule (implementation: { - options = { - input = mkOption { - type = submodule config.input-type; - }; - output = mkOption { - type = submodule config.output-type; - }; - }; - }) - ); - }; - apply = mkOption { - type = optionType; - readOnly = true; - default = submodule (apply: { - options = { - implementation = mkOption { - type = config.implementation; - }; - input = mkOption { - type = submodule config.input-type; - }; - output = mkOption { - type = submodule config.output-type; - readOnly = true; - default = (apply.config.implementation apply.config.input).output; - }; - }; - }); - }; - }; -}