data model: add classes #7

Closed
kiara wants to merge 1 commit from data-model-add-classes into deployment-data-model-with-tests
Showing only changes of commit 9f596ad820 - Show all commits

View file

@ -11,12 +11,14 @@ let
attrTag attrTag
deferredModuleWith deferredModuleWith
submodule submodule
submoduleWith
optionType optionType
functionTo functionTo
; ;
functionType = import ./function.nix; functionType = import ./function.nix;
application-resources = submodule { application-resources = submodule {
_class = "fediversity-application-requirements";
options.resources = mkOption { options.resources = mkOption {
# TODO: maybe transpose, and group the resources by type instead # TODO: maybe transpose, and group the resources by type instead
type = attrsOf ( type = attrsOf (
@ -31,7 +33,6 @@ let
inputs.nixops4.modules.nixops4Deployment.default inputs.nixops4.modules.nixops4Deployment.default
{ {
_class = "nixops4Deployment";
_module.args = { _module.args = {
kiara marked this conversation as resolved Outdated

Very likely not needed, as noted in the other PR

Very likely not needed, as noted in the other PR
Outdated
Review

resolving until the upstream PR may supersede this, now #6 is merged

resolving until the upstream PR may supersede this, now #6 is merged
Outdated
Review

given this got merged upstream, i rebased to remove this now, ahead of our updating nixops4 (which i will consider out of scope for this PR, as i'm sure we will down the line)

given this got merged upstream, i rebased to remove this now, ahead of our updating nixops4 (which i will consider out of scope for this PR, as i'm sure we will down the line)
resourceProviderSystem = builtins.currentSystem; resourceProviderSystem = builtins.currentSystem;
resources = { }; resources = { };
@ -41,139 +42,163 @@ let
}; };
in in
{ {
_class = "fediversity-settings";
options = { options = {
resources = mkOption { resources = mkOption {
description = "Collection of deployment resources that can be required by applications and policed by hosting providers"; description = "Collection of deployment resources that can be required by applications and policed by hosting providers";
type = attrsOf ( type = attrsOf (submoduleWith {
submodule ( class = "fediversity-resource";
{ ... }: modules = [
{ (
_class = "fediversity-resource"; { ... }:
options = { {
description = mkOption { _class = "fediversity-resource";
description = "Description of the resource to help application module authors and hosting providers to work with it"; options = {
type = types.str; description = mkOption {
}; description = "Description of the resource to help application module authors and hosting providers to work with it";
request = mkOption { type = types.str;
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"; } ]; }; request = mkOption {
}; description = "Options for declaring resource requirements by an application, a description of how the resource is consumed or accessed";
policy = mkOption { type = deferredModuleWith { staticModules = [ { _class = "fediversity-resource-request"; } ]; };
description = "Options for configuring the resource policy for the hosting provider, a description of how the resource is made available"; };
type = deferredModuleWith { policy = mkOption {
staticModules = [ description = "Options for configuring the resource policy for the hosting provider, a description of how the resource is made available";
(policy: { type = deferredModuleWith {
_class = "fediversity-resource-policy"; staticModules = [
options.resource-type = mkOption { (policy: {
description = "The type of resource this policy configures"; _class = "fediversity-resource-policy";
type = types.optionType; options.resource-type = mkOption {
}; description = "The type of resource this policy configures";
# TODO(@fricklerhandwerk): we may want to make the function type explict here: `request -> resource-type` type = types.optionType;
# and then also rename this to be consistent with the application's resource mapping };
options.apply = mkOption { # TODO(@fricklerhandwerk): we may want to make the function type explict here: `request -> resource-type`
description = "Apply the policy to a request"; # and then also rename this to be consistent with the application's resource mapping
type = functionTo policy.config.resource-type; options.apply = mkOption {
}; description = "Apply the policy to a request";
}) type = functionTo policy.config.resource-type;
]; };
})
];
};
}; };
}; };
}; }
} )
) ];
); });
}; };
applications = mkOption { applications = mkOption {
description = "Collection of Fediversity applications"; description = "Collection of Fediversity applications";
type = attrsOf ( type = attrsOf (submoduleWith {
submodule (application: { class = "fediversity-application";
_class = "fediversity-application"; modules = [
options = { (application: {
description = mkOption { _class = "fediversity-application";
description = "Description to be shown in the application overview"; options = {
type = types.str; description = mkOption {
}; description = "Description to be shown in the application overview";
module = mkOption { type = types.str;
description = "Operator-facing configuration options for the application"; };
type = deferredModuleWith { staticModules = [ { _class = "fediversity-application-config"; } ]; }; module = mkOption {
}; description = "Operator-facing configuration options for the application";
implementation = mkOption { type = deferredModuleWith { staticModules = [ { _class = "fediversity-application-config"; } ]; };
description = "Mapping of application configuration to deployment resources, a description of what an application needs to run"; };
type = application.config.config-mapping.function-type; implementation = mkOption {
}; description = "Mapping of application configuration to deployment resources, a description of what an application needs to run";
resources = mkOption { type = application.config.config-mapping.function-type;
description = "Compute resources required by an application"; };
type = functionTo application.config.config-mapping.output-type; resources = mkOption {
readOnly = true; description = "Compute resources required by an application";
default = input: (application.config.implementation input).output; type = functionTo application.config.config-mapping.output-type;
}; readOnly = true;
# TODO(@fricklerhandwerk): this needs a better name, it's just the type default = input: (application.config.implementation input).output;
config-mapping = mkOption { };
description = "Function type for the mapping from application configuration to required resources"; # TODO(@fricklerhandwerk): this needs a better name, it's just the type
type = submodule functionType; config-mapping = mkOption {
readOnly = true; description = "Function type for the mapping from application configuration to required resources";
default = { type = submoduleWith {
input-type = submodule application.config.module; class = "module-function";
output-type = application-resources; modules = [ functionType ];
};
readOnly = true;
default = {
input-type = submodule application.config.module;
output-type = application-resources;
};
}; };
}; };
}; })
}) ];
); });
}; };
environments = mkOption { environments = mkOption {
description = "Run-time environments for Fediversity applications to be deployed to"; description = "Run-time environments for Fediversity applications to be deployed to";
type = attrsOf ( type = attrsOf (submoduleWith {
submodule (environment: { class = "fediversity-environment";
_class = "fediversity-environment"; modules = [

I don't think this is an improvement in readability

I don't think this is an improvement in readability
Outdated
Review

the PR's intent was semantic rather than just documentation - even if (as noted in Fediversity/Fediversity#481 (comment)) i haven't fully grasped the full extent of subModuleWith's class parameter.

the PR's intent was semantic rather than just documentation - even if (as noted in https://git.fediversity.eu/Fediversity/Fediversity/pulls/481#issuecomment-9183) i haven't fully grasped the full extent of `subModuleWith`'s `class` parameter.
Outdated
Review

looks like a lot of that pertains to merging logic - maybe the type checks are the main thing then

looks like a lot of that pertains to merging logic - maybe the type checks are the main thing then
options = { (environment: {
resources = mkOption { options = {
description = '' resources = mkOption {
Resources made available by the hosting provider, and their policies. 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-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;
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 { configuration = mkOption {
description = "Configuration type declaring options to be set by operators"; description = "Configuration type declaring options to be set by operators";
@ -188,7 +213,10 @@ in
_name: application: _name: application:
mkOption { mkOption {
description = application.description; description = application.description;
type = submodule application.module; type = submoduleWith {
class = "fediversity-application-config";
modules = [ application.module ];
};
default = { }; default = { };
} }
) config.applications; ) config.applications;