forked from Fediversity/Fediversity
note that i worked around the question of how to delegate part of the options to the consumer by creating aliases for different parts of the function slot filling. i've been pretty arbitrary about this so far tho, and mostly to preserve existing interfaces, rather than out of conscious UX design per se. so the interface can def change still, but at least the _user_'s side is more DRY now!
210 lines
8.1 KiB
Nix
210 lines
8.1 KiB
Nix
{
|
|
lib,
|
|
config,
|
|
inputs,
|
|
...
|
|
}:
|
|
let
|
|
inherit (lib) mkOption types;
|
|
inherit (lib.types)
|
|
attrsOf
|
|
attrTag
|
|
deferredModuleWith
|
|
submodule
|
|
optionType
|
|
functionTo
|
|
;
|
|
|
|
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
|
|
)
|
|
);
|
|
};
|
|
};
|
|
nixops4Deployment = types.deferredModuleWith {
|
|
staticModules = [
|
|
inputs.nixops4.modules.nixops4Deployment.default
|
|
|
|
{
|
|
_class = "nixops4Deployment";
|
|
_module.args = {
|
|
resourceProviderSystem = builtins.currentSystem;
|
|
resources = { };
|
|
};
|
|
}
|
|
];
|
|
};
|
|
in
|
|
{
|
|
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 = functionTo policy.config.resource-type;
|
|
};
|
|
})
|
|
];
|
|
};
|
|
};
|
|
};
|
|
}
|
|
)
|
|
);
|
|
};
|
|
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 = application.config.config-mapping.function-type;
|
|
readOnly = true;
|
|
default = application.config.config-mapping.apply;
|
|
};
|
|
# TODO(@fricklerhandwerk): this needs a better name
|
|
config-mapping = mkOption {
|
|
description = "Compute resources required by an application";
|
|
type = submodule functionType;
|
|
readOnly = true;
|
|
default = {
|
|
input-type = submodule application.config.module;
|
|
output-type = application-resources;
|
|
implementation = application.config.implementation;
|
|
};
|
|
};
|
|
};
|
|
})
|
|
);
|
|
};
|
|
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;
|
|
implementation = environment.config.implementation;
|
|
};
|
|
};
|
|
config-mapping = mkOption {
|
|
description = "Mapping from a configuration to a deployment";
|
|
type = submodule functionType;
|
|
readOnly = true;
|
|
default = {
|
|
input-type = config.configuration;
|
|
output-type = nixops4Deployment;
|
|
implementation =
|
|
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.resource-mapping.apply required-resources;
|
|
};
|
|
};
|
|
# 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 = environment.config.config-mapping.function-type;
|
|
readOnly = true;
|
|
default = environment.config.config-mapping.apply;
|
|
};
|
|
};
|
|
})
|
|
);
|
|
};
|
|
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;
|
|
};
|
|
};
|
|
};
|
|
};
|
|
}
|