mirror of
https://github.com/TECHNOFAB11/kubenix.git
synced 2025-12-12 16:10:05 +01:00
Refactor:
- Support for module features - Remove kubenix.module and rather use explicit modules - Make tests framework independent of k8s module - Remove metacontroller submodule, which will go to kubenix-modules - Improved submodule propagation and passthru - Added additional test for k8s-submodule
This commit is contained in:
parent
b670139906
commit
6183fcc190
30 changed files with 513 additions and 508 deletions
|
|
@ -3,4 +3,4 @@ script:
|
|||
- nix-env -iA nixpkgs.jq
|
||||
- nix build -f ./release.nix test-results --arg e2e false
|
||||
- cat result | jq '.'
|
||||
- nix eval -f ./release.nix --arg e2e false tests-check
|
||||
- nix eval -f ./release.nix --arg e2e false test-check
|
||||
|
|
|
|||
|
|
@ -13,19 +13,20 @@ kubernetes resources very easyly.
|
|||
### Building tests
|
||||
|
||||
```shell
|
||||
nix-build release.nix -A tests.results --show-trace
|
||||
nix-build release.nix -A tests-results --show-trace
|
||||
```
|
||||
|
||||
**Building single e2e test**
|
||||
|
||||
```
|
||||
nix-build release.nix -A tests.tests.v1_10.testing.testsByName.<name>.script
|
||||
cd tests
|
||||
nix-build release.nix -A tests.k8s-1_10.testsByName.<test-name>.test
|
||||
```
|
||||
|
||||
**Debugging e2e test**
|
||||
|
||||
```
|
||||
nix-build release.nix -A tests.tests.v1_10.testing.testsByName.<name>.script.driver
|
||||
nix-build release.nix -A tests.k8s-1_10.testsByName.<test-name>.test.driver
|
||||
resut/bin/nixos-test-driver
|
||||
testScript;
|
||||
```
|
||||
|
|
|
|||
|
|
@ -32,6 +32,5 @@ let
|
|||
inherit evalModules modules;
|
||||
|
||||
lib = kubenixLib;
|
||||
module = modules.module;
|
||||
};
|
||||
in kubenix
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ with lib;
|
|||
let
|
||||
nginx = pkgs.callPackage ./image.nix { };
|
||||
in {
|
||||
imports = [ kubenix.module ];
|
||||
imports = with kubenix.modules; [ k8s docker ];
|
||||
|
||||
docker.images.nginx.image = nginx;
|
||||
|
||||
|
|
|
|||
|
|
@ -12,8 +12,6 @@ rec {
|
|||
|
||||
else value;
|
||||
|
||||
mkOptionDefault = mkOverride 1001;
|
||||
|
||||
mkAllDefault = value: priority:
|
||||
if isAttrs value
|
||||
then mapAttrs (n: v: mkAllDefault v priority) value
|
||||
|
|
|
|||
19
modules/base.nix
Normal file
19
modules/base.nix
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
{ config, lib, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
{
|
||||
options._module.features = mkOption {
|
||||
description = "List of features exposed by module";
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
};
|
||||
|
||||
options.kubenix = {
|
||||
project = mkOption {
|
||||
description = "Name of the project";
|
||||
type = types.str;
|
||||
default = "kubenix";
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
@ -2,9 +2,9 @@
|
|||
k8s = ./k8s.nix;
|
||||
istio = ./istio.nix;
|
||||
submodules = ./submodules.nix;
|
||||
submodule = ./submodule.nix;
|
||||
helm = ./helm.nix;
|
||||
docker = ./docker.nix;
|
||||
metacontroller = ./metacontroller;
|
||||
testing = ./testing.nix;
|
||||
test = ./test.nix;
|
||||
module = ./module.nix;
|
||||
|
|
|
|||
|
|
@ -3,61 +3,77 @@
|
|||
with lib;
|
||||
|
||||
let
|
||||
globalConfig = config;
|
||||
cfg = config.docker;
|
||||
in {
|
||||
options.docker.registry.url = mkOption {
|
||||
description = "Default registry url where images are published";
|
||||
type = types.str;
|
||||
default = "";
|
||||
options.docker = {
|
||||
registry.url = mkOption {
|
||||
description = "Default registry url where images are published";
|
||||
type = types.str;
|
||||
default = "";
|
||||
};
|
||||
|
||||
images = mkOption {
|
||||
description = "Attribute set of docker images that should be published";
|
||||
type = types.attrsOf (types.submodule ({ name, config, ... }: {
|
||||
options = {
|
||||
image = mkOption {
|
||||
description = "Docker image to publish";
|
||||
type = types.nullOr types.package;
|
||||
default = null;
|
||||
};
|
||||
|
||||
name = mkOption {
|
||||
description = "Desired docker image name";
|
||||
type = types.str;
|
||||
default = builtins.unsafeDiscardStringContext config.image.imageName;
|
||||
};
|
||||
|
||||
tag = mkOption {
|
||||
description = "Desired docker image tag";
|
||||
type = types.str;
|
||||
default = builtins.unsafeDiscardStringContext config.image.imageTag;
|
||||
};
|
||||
|
||||
registry = mkOption {
|
||||
description = "Docker registry url where image is published";
|
||||
type = types.str;
|
||||
default = cfg.registry.url;
|
||||
};
|
||||
|
||||
path = mkOption {
|
||||
description = "Full docker image path";
|
||||
type = types.str;
|
||||
default =
|
||||
if config.registry != ""
|
||||
then "${config.registry}/${config.name}:${config.tag}"
|
||||
else "${config.name}:${config.tag}";
|
||||
};
|
||||
};
|
||||
}));
|
||||
default = {};
|
||||
};
|
||||
|
||||
export = mkOption {
|
||||
description = "List of images to export";
|
||||
type = types.listOf (types.package);
|
||||
default = [];
|
||||
};
|
||||
};
|
||||
|
||||
options.docker.images = mkOption {
|
||||
description = "Attribute set of docker images that should be published";
|
||||
type = types.attrsOf (types.submodule ({ name, config, ... }: {
|
||||
options = {
|
||||
image = mkOption {
|
||||
description = "Docker image to publish";
|
||||
type = types.nullOr types.package;
|
||||
default = null;
|
||||
};
|
||||
config = {
|
||||
_module.features = ["docker"];
|
||||
|
||||
name = mkOption {
|
||||
description = "Desired docker image name";
|
||||
type = types.str;
|
||||
default = builtins.unsafeDiscardStringContext config.image.imageName;
|
||||
};
|
||||
docker.export = mkMerge [
|
||||
(mapAttrsToList (_: i: i.image)
|
||||
(filterAttrs (_: i: i.registry != null) config.docker.images))
|
||||
|
||||
tag = mkOption {
|
||||
description = "Desired docker image tag";
|
||||
type = types.str;
|
||||
default = builtins.unsafeDiscardStringContext config.image.imageTag;
|
||||
};
|
||||
|
||||
registry = mkOption {
|
||||
description = "Docker registry url where image is published";
|
||||
type = types.str;
|
||||
default = globalConfig.docker.registry.url;
|
||||
};
|
||||
|
||||
path = mkOption {
|
||||
description = "Full docker image path";
|
||||
type = types.str;
|
||||
default =
|
||||
if config.registry != ""
|
||||
then "${config.registry}/${config.name}:${config.tag}"
|
||||
else "${config.name}:${config.tag}";
|
||||
};
|
||||
};
|
||||
}));
|
||||
default = {};
|
||||
# passthru of docker exported images if passthru is enabled on submodule
|
||||
# and submodule has docker module loaded
|
||||
(flatten (mapAttrsToList (_: submodule:
|
||||
optionals
|
||||
(submodule.passthru.enable && (elem "docker" submodule.config._module.features))
|
||||
submodule.config.docker.export
|
||||
) config.submodules.instances))
|
||||
];
|
||||
};
|
||||
|
||||
options.docker.export = mkOption {
|
||||
description = "List of images to export";
|
||||
type = types.listOf (types.package);
|
||||
default = [];
|
||||
};
|
||||
|
||||
config.docker.export = mapAttrsToList (_: i: i.image)
|
||||
(filterAttrs (_: i: i.registry != null)config.docker.images);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,9 +27,6 @@ let
|
|||
in {
|
||||
imports = [ ./k8s.nix ];
|
||||
|
||||
# expose helm helper methods as module argument
|
||||
config._module.args.helm = import ../lib/helm { inherit pkgs; };
|
||||
|
||||
options.kubernetes.helm = {
|
||||
instances = mkOption {
|
||||
description = "Attribute set of helm instances";
|
||||
|
|
@ -84,7 +81,7 @@ in {
|
|||
};
|
||||
|
||||
config.overrides = mkIf (config.overrideNamespace && config.namespace != null) [{
|
||||
metadata.namespace = mkDefault config.namespace;
|
||||
metadata.namespace = config.namespace;
|
||||
}];
|
||||
|
||||
config.objects = importJSON (helm.chart2json {
|
||||
|
|
@ -94,14 +91,19 @@ in {
|
|||
};
|
||||
};
|
||||
|
||||
config.kubernetes.api = mkMerge (flatten (mapAttrsToList (_: instance:
|
||||
map (object: let
|
||||
apiVersion = parseApiVersion object.apiVersion;
|
||||
name = object.metadata.name;
|
||||
in {
|
||||
"${apiVersion.group}"."${apiVersion.version}".${object.kind}."${name}" = mkMerge ([
|
||||
object
|
||||
] ++ instance.overrides);
|
||||
}) instance.objects
|
||||
) cfg.instances));
|
||||
config = {
|
||||
# expose helm helper methods as module argument
|
||||
_module.args.helm = import ../lib/helm { inherit pkgs; };
|
||||
|
||||
kubernetes.api = mkMerge (flatten (mapAttrsToList (_: instance:
|
||||
map (object: let
|
||||
apiVersion = parseApiVersion object.apiVersion;
|
||||
name = object.metadata.name;
|
||||
in {
|
||||
"${apiVersion.group}"."${apiVersion.version}".${object.kind}."${name}" = mkMerge ([
|
||||
object
|
||||
] ++ instance.overrides);
|
||||
}) instance.objects
|
||||
) cfg.instances));
|
||||
};
|
||||
}
|
||||
|
|
|
|||
241
modules/k8s.nix
241
modules/k8s.nix
|
|
@ -68,6 +68,12 @@ let
|
|||
default = null;
|
||||
};
|
||||
|
||||
propagate = mkOption {
|
||||
description = "Whether to propagate default";
|
||||
type = types.bool;
|
||||
default = false;
|
||||
};
|
||||
|
||||
default = mkOption {
|
||||
description = "Default to apply";
|
||||
type = types.unspecified;
|
||||
|
|
@ -164,107 +170,162 @@ let
|
|||
};
|
||||
}) cfg.customResources;
|
||||
in {
|
||||
# expose k8s helper methods as module argument
|
||||
config._module.args.k8s = import ../lib/k8s.nix { inherit lib; };
|
||||
imports = [ ./base.nix ./submodules.nix ];
|
||||
|
||||
options.kubernetes.version = mkOption {
|
||||
description = "Kubernetes version to use";
|
||||
type = types.enum ["1.7" "1.8" "1.9" "1.10" "1.11" "1.12" "1.13"];
|
||||
default = "1.13";
|
||||
};
|
||||
|
||||
options.kubernetes.resourceOrder = mkOption {
|
||||
description = "Preffered resource order";
|
||||
type = types.listOf types.str;
|
||||
default = [
|
||||
"CustomResourceDefinition"
|
||||
"Namespace"
|
||||
];
|
||||
};
|
||||
|
||||
options.kubernetes.api = mkOption {
|
||||
type = types.submodule {
|
||||
imports = [
|
||||
(./generated + ''/v'' + cfg.version + ".nix")
|
||||
apiOptions
|
||||
] ++ customResourceOptions;
|
||||
options.kubernetes = {
|
||||
version = mkOption {
|
||||
description = "Kubernetes version to use";
|
||||
type = types.enum ["1.7" "1.8" "1.9" "1.10" "1.11" "1.12" "1.13"];
|
||||
default = "1.13";
|
||||
};
|
||||
default = {};
|
||||
};
|
||||
|
||||
options.kubernetes.customResources = mkOption {
|
||||
default = [];
|
||||
description = "List of custom resource definitions to make API for";
|
||||
type = types.listOf (types.submodule ({config, ...}: {
|
||||
options = {
|
||||
group = mkOption {
|
||||
description = "Custom resource definition group";
|
||||
type = types.str;
|
||||
};
|
||||
namespace = mkOption {
|
||||
description = "Default namespace where to deploy kubernetes resources";
|
||||
type = types.str;
|
||||
default = "default";
|
||||
};
|
||||
|
||||
version = mkOption {
|
||||
description = "Custom resource definition version";
|
||||
type = types.str;
|
||||
};
|
||||
resourceOrder = mkOption {
|
||||
description = "Preffered resource order";
|
||||
type = types.listOf types.str;
|
||||
default = [
|
||||
"CustomResourceDefinition"
|
||||
"Namespace"
|
||||
];
|
||||
};
|
||||
|
||||
kind = mkOption {
|
||||
description = "Custom resource definition kind";
|
||||
type = types.str;
|
||||
};
|
||||
|
||||
resource = mkOption {
|
||||
description = "Custom resource definition resource name";
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
};
|
||||
|
||||
description = mkOption {
|
||||
description = "Custom resource definition description";
|
||||
type = types.str;
|
||||
default = "";
|
||||
};
|
||||
|
||||
module = mkOption {
|
||||
description = "Custom resource definition module";
|
||||
default = types.unspecified;
|
||||
};
|
||||
|
||||
alias = mkOption {
|
||||
description = "Alias to create for API";
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
};
|
||||
api = mkOption {
|
||||
type = types.submodule {
|
||||
imports = [
|
||||
(./generated + ''/v'' + cfg.version + ".nix")
|
||||
apiOptions
|
||||
] ++ customResourceOptions;
|
||||
};
|
||||
}));
|
||||
default = {};
|
||||
};
|
||||
|
||||
customResources = mkOption {
|
||||
default = [];
|
||||
description = "List of custom resource definitions to make API for";
|
||||
type = types.listOf (types.submodule ({config, ...}: {
|
||||
options = {
|
||||
group = mkOption {
|
||||
description = "Custom resource definition group";
|
||||
type = types.str;
|
||||
};
|
||||
|
||||
version = mkOption {
|
||||
description = "Custom resource definition version";
|
||||
type = types.str;
|
||||
};
|
||||
|
||||
kind = mkOption {
|
||||
description = "Custom resource definition kind";
|
||||
type = types.str;
|
||||
};
|
||||
|
||||
resource = mkOption {
|
||||
description = "Custom resource definition resource name";
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
};
|
||||
|
||||
description = mkOption {
|
||||
description = "Custom resource definition description";
|
||||
type = types.str;
|
||||
default = "";
|
||||
};
|
||||
|
||||
module = mkOption {
|
||||
description = "Custom resource definition module";
|
||||
default = types.unspecified;
|
||||
};
|
||||
|
||||
alias = mkOption {
|
||||
description = "Alias to create for API";
|
||||
type = types.nullOr types.str;
|
||||
default = null;
|
||||
};
|
||||
};
|
||||
}));
|
||||
};
|
||||
|
||||
objects = mkOption {
|
||||
description = "List of generated kubernetes objects";
|
||||
type = types.listOf types.attrs;
|
||||
apply = items: sort (r1: r2:
|
||||
if elem r1.kind cfg.resourceOrder && elem r2.kind cfg.resourceOrder
|
||||
then indexOf cfg.resourceOrder r1.kind < indexOf cfg.resourceOrder r2.kind
|
||||
else if elem r1.kind cfg.resourceOrder then true else false
|
||||
) (moduleToAttrs (unique items));
|
||||
default = [];
|
||||
};
|
||||
|
||||
generated = mkOption {
|
||||
description = "Generated kubernetes list object";
|
||||
type = types.attrs;
|
||||
};
|
||||
};
|
||||
|
||||
config.kubernetes.api.resources = map (cr: {
|
||||
inherit (cr) group version kind resource;
|
||||
}) cfg.customResources;
|
||||
config = {
|
||||
# expose k8s helper methods as module argument
|
||||
_module.args.k8s = import ../lib/k8s.nix { inherit lib; };
|
||||
|
||||
options.kubernetes.objects = mkOption {
|
||||
description = "List of generated kubernetes objects";
|
||||
type = types.listOf types.attrs;
|
||||
apply = items: sort (r1: r2:
|
||||
if elem r1.kind cfg.resourceOrder && elem r2.kind cfg.resourceOrder
|
||||
then indexOf cfg.resourceOrder r1.kind < indexOf cfg.resourceOrder r2.kind
|
||||
else if elem r1.kind cfg.resourceOrder then true else false
|
||||
) (moduleToAttrs (unique items));
|
||||
default = [];
|
||||
};
|
||||
_module.features = [ "k8s" ];
|
||||
|
||||
config.kubernetes.objects = flatten (map (gvk:
|
||||
mapAttrsToList (name: resource:
|
||||
removeKubenixOptions (moduleToAttrs resource)
|
||||
) cfg.api.${gvk.group}.${gvk.version}.${gvk.kind}
|
||||
) cfg.api.resources);
|
||||
kubernetes.api.resources = map (cr: {
|
||||
inherit (cr) group version kind resource;
|
||||
}) cfg.customResources;
|
||||
|
||||
options.kubernetes.generated = mkOption {
|
||||
description = "Generated kubernetes list object";
|
||||
type = types.attrs;
|
||||
};
|
||||
kubernetes.objects = mkMerge [
|
||||
# gvk resources
|
||||
(flatten (map (gvk:
|
||||
mapAttrsToList (name: resource:
|
||||
removeKubenixOptions (moduleToAttrs resource)
|
||||
) cfg.api.${gvk.group}.${gvk.version}.${gvk.kind}
|
||||
) cfg.api.resources))
|
||||
|
||||
config.kubernetes.generated = k8s.mkHashedList {
|
||||
items = config.kubernetes.objects;
|
||||
# passthru of child kubernetes objects if passthru is enabled on submodule
|
||||
# and submodule has k8s module loaded
|
||||
(flatten (mapAttrsToList (_: submodule:
|
||||
optionals
|
||||
(submodule.passthru.enable && (elem "k8s" submodule.config._module.features))
|
||||
submodule.config.kubernetes.objects
|
||||
) config.submodules.instances))
|
||||
];
|
||||
|
||||
kubernetes.generated = k8s.mkHashedList {
|
||||
items = config.kubernetes.objects;
|
||||
labels."kubenix/project-name" = config.kubenix.project;
|
||||
};
|
||||
|
||||
kubernetes.api.defaults = [{
|
||||
default = {
|
||||
metadata.namespace = mkDefault config.kubernetes.namespace;
|
||||
metadata.labels = mkMerge [
|
||||
{
|
||||
"kubenix/project-name" = config.kubenix.project;
|
||||
}
|
||||
|
||||
# if we are inside submodule, define additional labels
|
||||
(mkIf (elem "submodule" config._module.features) {
|
||||
"kubenix/module-name" = config.submodule.name;
|
||||
"kubenix/module-version" = config.submodule.version;
|
||||
})
|
||||
];
|
||||
};
|
||||
}];
|
||||
|
||||
submodules.defaults = [{
|
||||
features = [ "k8s" ];
|
||||
default = { config, name, ... }: {
|
||||
# propagate kubernetes version and namespace
|
||||
kubernetes.version = mkDefault cfg.version;
|
||||
kubernetes.namespace = mkDefault cfg.namespace;
|
||||
|
||||
# propagate defaults if default propagation is enabled
|
||||
kubernetes.api.defaults = filter (default: default.propagate) cfg.api.defaults;
|
||||
};
|
||||
}];
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,139 +0,0 @@
|
|||
{ config, lib, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
{
|
||||
options = {
|
||||
parentResource = {
|
||||
apiVersion = mkOption {
|
||||
description = "Parent resource apiVersion";
|
||||
type = types.str;
|
||||
example = "apps/v1";
|
||||
};
|
||||
|
||||
resource = mkOption {
|
||||
description = "The canonical, lowercase, plural name of the parent resource";
|
||||
type = types.str;
|
||||
example = "deployments";
|
||||
};
|
||||
|
||||
revisionHistory = mkOption {
|
||||
description = "A list of field path strings specifying which parent fields trigger rolling updates of children";
|
||||
type = types.listOf types.str;
|
||||
default = ["spec"];
|
||||
example = ["spec.template"];
|
||||
};
|
||||
};
|
||||
|
||||
childResources = mkOption {
|
||||
description = "A list of resource rules specifying the child resources";
|
||||
type = types.listOf (types.submodule ({ config, ... }: {
|
||||
options = {
|
||||
apiVersion = mkOption {
|
||||
description = "The API group/version of the child resource, or just version for core APIs";
|
||||
type = types.str;
|
||||
example = "apps/v1";
|
||||
};
|
||||
|
||||
resource = mkOption {
|
||||
description = "The canonical, lowercase, plural name of the child resource";
|
||||
type = types.str;
|
||||
example = "deployments";
|
||||
};
|
||||
|
||||
updateStrategy = {
|
||||
method = mkOption {
|
||||
description = ''
|
||||
A string indicating the overall method that should be used for updating this type of child resource.
|
||||
The default is OnDelete, which means don't try to update children that already exist.
|
||||
|
||||
- OnDelete: Don't update existing children unless they get deleted by some other agent.
|
||||
- Recreate: Immediately delete any children that differ from the desired state, and recreate them in the desired state.
|
||||
- InPlace: Immediately update any children that differ from the desired state.
|
||||
- RollingRecreate: Delete each child that differs from the desired state, one at a time,
|
||||
and recreate each child before moving on to the next one.
|
||||
Pause the rollout if at any time one of the children that have already been updated fails one or more status checks.
|
||||
- RollingInPlace: Update each child that differs from the desired state, one at a time. Pause the rollout if at any time
|
||||
one of the children that have already been updated fails one or more status checks.
|
||||
'';
|
||||
type = types.enum [
|
||||
"OnDelete"
|
||||
"Recreate"
|
||||
"InPlace"
|
||||
"RollingRecreate"
|
||||
"RollingInPlace"
|
||||
];
|
||||
default = "OnDelete";
|
||||
};
|
||||
|
||||
statusChecks.conditions = mkOption {
|
||||
description = ''
|
||||
A list of status condition checks that must all pass on already-updated
|
||||
children for the rollout to continue.
|
||||
'';
|
||||
type = types.listOf (types.submodule ({ config, ... }: {
|
||||
options = {
|
||||
type = mkOption {
|
||||
description = "A string specifying the status condition type to check.";
|
||||
type = types.str;
|
||||
};
|
||||
|
||||
status = mkOption {
|
||||
description = ''
|
||||
A string specifying the required status of the given status condition.
|
||||
If none is specified, the condition's status is not checked.
|
||||
'';
|
||||
type = types.str;
|
||||
default = "";
|
||||
};
|
||||
|
||||
reason = mkOption {
|
||||
description = ''
|
||||
A string specifying the required reason of the given status condition.
|
||||
If none is specified, the condition's reason is not checked.
|
||||
'';
|
||||
type = types.str;
|
||||
default = "";
|
||||
};
|
||||
};
|
||||
}));
|
||||
default = [];
|
||||
};
|
||||
};
|
||||
};
|
||||
}));
|
||||
default = [];
|
||||
};
|
||||
|
||||
resyncPeriodSeconds = mkOption {
|
||||
description = ''
|
||||
How often, in seconds, you want every parent object to be resynced,
|
||||
even if no changes are detected.
|
||||
'';
|
||||
type = types.int;
|
||||
default = 0;
|
||||
};
|
||||
|
||||
generateSelector = mkOption {
|
||||
description = ''
|
||||
If true, ignore the selector in each parent object and instead generate
|
||||
a unique selector that prevents overlap with other objects.
|
||||
'';
|
||||
type = types.bool;
|
||||
default = false;
|
||||
};
|
||||
|
||||
hooks = {
|
||||
sync.webhook.url = mkOption {
|
||||
description = "Webhook URL where to send sync request";
|
||||
type = types.str;
|
||||
};
|
||||
|
||||
finalize.webhook.url = mkOption {
|
||||
description = "Webhook URL where to send finalize request";
|
||||
type = types.str;
|
||||
default = "";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
{ config, lib, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
{
|
||||
imports = [ ../k8s.nix ];
|
||||
|
||||
options.metacontroller = {
|
||||
compositeControllers = mkOption {
|
||||
type = types.attrsOf (types.submodule ({ name, config, ... }: {
|
||||
imports = [ ./compositecontroller.nix ];
|
||||
|
||||
options = {
|
||||
name = mkOption {
|
||||
description = "Name of the composite controller";
|
||||
type = types.str;
|
||||
default = name;
|
||||
};
|
||||
};
|
||||
}));
|
||||
default = {};
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
kubernetes.customResources = [{
|
||||
group = "metacontroller.k8s.io";
|
||||
version = "v1alpha1";
|
||||
kind = "CompositeController";
|
||||
resource = "compositecontrollers";
|
||||
description = "Composite controller";
|
||||
alias = "compositecontrollers";
|
||||
module.imports = [ ./compositecontroller.nix ];
|
||||
}];
|
||||
};
|
||||
}
|
||||
|
|
@ -1,75 +0,0 @@
|
|||
# module.nix defines default kubenix module with additional helper options
|
||||
# and preincluded kubenix module definitions for kubernetes, docker and
|
||||
# kubenix submodules
|
||||
|
||||
{ config, lib, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
parentConfig = config;
|
||||
in {
|
||||
imports = [ ./k8s.nix ./docker.nix ./submodules.nix ];
|
||||
|
||||
options = {
|
||||
kubenix.release = mkOption {
|
||||
description = "Name of the release";
|
||||
type = types.str;
|
||||
default = "default";
|
||||
};
|
||||
|
||||
kubernetes.propagateDefaults = mkOption {
|
||||
description = "Whether to propagate child defaults to submodules";
|
||||
type = types.bool;
|
||||
default = true;
|
||||
};
|
||||
|
||||
submodules.instances = mkOption {
|
||||
type = types.attrsOf (types.submodule ({config, ...}: {
|
||||
options = {
|
||||
namespace = mkOption {
|
||||
description = "Default kubernetes namespace";
|
||||
type = types.str;
|
||||
default = "default";
|
||||
};
|
||||
};
|
||||
|
||||
config.config = {
|
||||
kubernetes.api.defaults = [{
|
||||
default.metadata.namespace = mkDefault config.namespace;
|
||||
}];
|
||||
};
|
||||
}));
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
submodules.defaults = [{
|
||||
default = {
|
||||
imports = [ ./module.nix ];
|
||||
kubernetes.version = mkDefault config.kubernetes.version;
|
||||
kubernetes.api.defaults =
|
||||
mkIf config.kubernetes.propagateDefaults config.kubernetes.api.defaults;
|
||||
};
|
||||
} {
|
||||
default = ({config, ...}: {
|
||||
kubenix.release = parentConfig.kubenix.release;
|
||||
kubernetes.api.defaults = [{
|
||||
default.metadata.labels = {
|
||||
"kubenix/release-name" = config.kubenix.release;
|
||||
"kubenix/module-name" = config.submodule.name;
|
||||
"kubenix/module-version" = config.submodule.version;
|
||||
};
|
||||
}];
|
||||
});
|
||||
}];
|
||||
|
||||
kubernetes.objects = mkMerge (mapAttrsToList (_: submodule:
|
||||
submodule.config.kubernetes.objects
|
||||
) config.submodules.instances);
|
||||
|
||||
docker.export = mkMerge (mapAttrsToList (_: submodule:
|
||||
submodule.config.docker.export
|
||||
) config.submodules.instances);
|
||||
};
|
||||
}
|
||||
40
modules/submodule.nix
Normal file
40
modules/submodule.nix
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
{ config, lib, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
{
|
||||
imports = [ ./base.nix ];
|
||||
|
||||
options.submodule = {
|
||||
name = mkOption {
|
||||
description = "Module name";
|
||||
type = types.str;
|
||||
};
|
||||
|
||||
description = mkOption {
|
||||
description = "Module description";
|
||||
type = types.str;
|
||||
default = "";
|
||||
};
|
||||
|
||||
version = mkOption {
|
||||
description = "Module version";
|
||||
type = types.str;
|
||||
default = "1.0.0";
|
||||
};
|
||||
|
||||
tags = mkOption {
|
||||
description = "List of submodule tags";
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
};
|
||||
|
||||
passthru = mkOption {
|
||||
description = "Attribute set to passthru to parent";
|
||||
default = {};
|
||||
type = types.attrs;
|
||||
};
|
||||
};
|
||||
|
||||
config._module.features = ["submodule"];
|
||||
}
|
||||
|
|
@ -4,13 +4,18 @@ with lib;
|
|||
|
||||
let
|
||||
cfg = config.submodules;
|
||||
parentConfig = config;
|
||||
|
||||
getDefaults = name: tags:
|
||||
getDefaults = {name, tags, features}:
|
||||
catAttrs "default" (filter (submodule:
|
||||
(submodule.name == null || submodule.name == name) &&
|
||||
(
|
||||
(length submodule.tags == 0) ||
|
||||
(length (intersectLists submodule.tags tags)) > 0
|
||||
) &&
|
||||
(
|
||||
(length submodule.features == 0) ||
|
||||
(length (intersectLists submodule.features features)) > 0
|
||||
)
|
||||
) config.submodules.defaults);
|
||||
|
||||
|
|
@ -59,35 +64,6 @@ let
|
|||
};
|
||||
};
|
||||
|
||||
submoduleDefinitionOptions = {
|
||||
name = mkOption {
|
||||
description = "Module name";
|
||||
type = types.str;
|
||||
};
|
||||
|
||||
description = mkOption {
|
||||
description = "Module description";
|
||||
type = types.str;
|
||||
default = "";
|
||||
};
|
||||
|
||||
version = mkOption {
|
||||
description = "Module version";
|
||||
type = types.str;
|
||||
default = "1.0.0";
|
||||
};
|
||||
|
||||
tags = mkOption {
|
||||
description = "List of submodule tags";
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
};
|
||||
};
|
||||
|
||||
submoduleOptions = {
|
||||
options.submodule = submoduleDefinitionOptions;
|
||||
};
|
||||
|
||||
specialArgs = cfg.specialArgs // {
|
||||
parentConfig = config;
|
||||
};
|
||||
|
|
@ -113,6 +89,8 @@ let
|
|||
else head versionSortedSubmodules;
|
||||
in matchingModule;
|
||||
in {
|
||||
imports = [ ./base.nix ];
|
||||
|
||||
options = {
|
||||
submodules.specialArgs = mkOption {
|
||||
description = "Special args to pass to submodules. These arguments can be used for imports";
|
||||
|
|
@ -136,6 +114,12 @@ in {
|
|||
default = [];
|
||||
};
|
||||
|
||||
features = mkOption {
|
||||
description = "List of features that submodule has to have to apply defaults";
|
||||
type = types.listOf types.str;
|
||||
default = [];
|
||||
};
|
||||
|
||||
default = mkOption {
|
||||
description = "Default to apply to submodule instance";
|
||||
type = types.unspecified;
|
||||
|
|
@ -146,10 +130,10 @@ in {
|
|||
default = [];
|
||||
};
|
||||
|
||||
submodules.propagate = mkOption {
|
||||
description = "Whether to propagate defaults and imports to submodule's submodules";
|
||||
submodules.propagate.enable = mkOption {
|
||||
description = "Whether to propagate defaults and imports from parent to child";
|
||||
type = types.bool;
|
||||
default = false;
|
||||
default = true;
|
||||
};
|
||||
|
||||
submodules.imports = mkOption {
|
||||
|
|
@ -159,11 +143,16 @@ in {
|
|||
types.path
|
||||
(module: {inherit module;})
|
||||
(types.submodule ({name, config, ...}: let
|
||||
submoduleDefinition = (evalModules {
|
||||
evaledSubmodule' = (evalModules {
|
||||
inherit specialArgs;
|
||||
modules = config.modules ++ [submoduleOptions];
|
||||
modules = config.modules ++ [ ./base.nix ];
|
||||
check = false;
|
||||
}).config.submodule;
|
||||
}).config;
|
||||
|
||||
evaledSubmodule =
|
||||
if (!(elem "submodule" evaledSubmodule'._module.features))
|
||||
then throw "no submodule defined"
|
||||
else evaledSubmodule';
|
||||
in {
|
||||
options = {
|
||||
module = mkOption {
|
||||
|
|
@ -177,11 +166,23 @@ in {
|
|||
default = [config.module];
|
||||
};
|
||||
|
||||
definition = submoduleDefinitionOptions;
|
||||
features = mkOption {
|
||||
description = "List of features exposed by submodule";
|
||||
type = types.listOf types.str;
|
||||
};
|
||||
|
||||
definition = mkOption {
|
||||
description = "Submodule definition";
|
||||
type = types.attrs;
|
||||
};
|
||||
};
|
||||
|
||||
config.definition = {
|
||||
inherit (submoduleDefinition) name description version tags;
|
||||
config = {
|
||||
definition = {
|
||||
inherit (evaledSubmodule.submodule) name description version tags;
|
||||
};
|
||||
|
||||
features = evaledSubmodule._module.features;
|
||||
};
|
||||
})
|
||||
)
|
||||
|
|
@ -203,7 +204,11 @@ in {
|
|||
submoduleDefinition = submodule.definition;
|
||||
|
||||
# submodule defaults
|
||||
defaults = getDefaults submoduleDefinition.name submoduleDefinition.tags;
|
||||
defaults = getDefaults {
|
||||
name = submoduleDefinition.name;
|
||||
tags = submoduleDefinition.tags;
|
||||
features = submodule.features;
|
||||
};
|
||||
in {
|
||||
options = {
|
||||
name = mkOption {
|
||||
|
|
@ -227,10 +232,16 @@ in {
|
|||
default = null;
|
||||
};
|
||||
|
||||
passthru.enable = mkOption {
|
||||
description = "Whether to passthru submodule resources";
|
||||
type = types.bool;
|
||||
default = true;
|
||||
};
|
||||
|
||||
config = mkOption {
|
||||
description = "Submodule instance ${config.name} for ${submoduleDefinition.name}:${submoduleDefinition.version} config";
|
||||
type = submoduleWithSpecialArgs ({...}: {
|
||||
imports = submodule.modules ++ defaults ++ [submoduleOptions];
|
||||
imports = submodule.modules ++ defaults ++ [ ./base.nix ];
|
||||
_module.args.pkgs = pkgs;
|
||||
_module.args.name = config.name;
|
||||
_module.args.submodule = config;
|
||||
|
|
@ -243,16 +254,31 @@ in {
|
|||
default = {};
|
||||
};
|
||||
|
||||
config = {
|
||||
submodules.specialArgs.kubenix = kubenix;
|
||||
submodules.defaults = [(mkIf cfg.propagate {
|
||||
default = {
|
||||
imports = [./submodules.nix];
|
||||
submodules = {
|
||||
defaults = cfg.defaults;
|
||||
imports = cfg.imports;
|
||||
config = mkMerge [
|
||||
{
|
||||
_module.features = ["submodules"];
|
||||
|
||||
submodules.specialArgs.kubenix = kubenix;
|
||||
|
||||
# passthru kubenix.project to submodules
|
||||
submodules.defaults = [{
|
||||
default = {
|
||||
kubenix.project = parentConfig.kubenix.project;
|
||||
};
|
||||
};
|
||||
})];
|
||||
};
|
||||
}];
|
||||
}
|
||||
|
||||
(mkIf cfg.propagate.enable {
|
||||
# if propagate is enabled and submodule has submodules included propagage defaults and imports
|
||||
submodules.defaults = [{
|
||||
features = ["submodules"];
|
||||
default = {
|
||||
submodules = {
|
||||
defaults = cfg.defaults;
|
||||
imports = cfg.imports;
|
||||
};
|
||||
};
|
||||
}];
|
||||
})
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ with lib;
|
|||
|
||||
let
|
||||
cfg = config.testing;
|
||||
parentConfig = config;
|
||||
|
||||
nixosTesting = import <nixpkgs/nixos/lib/testing.nix> {
|
||||
inherit pkgs;
|
||||
|
|
@ -110,7 +109,9 @@ let
|
|||
|
||||
testOptions = {config, ...}: let
|
||||
modules = [config.module ./test.nix {
|
||||
config._module.args.test = config;
|
||||
config._module.args = {
|
||||
test = config;
|
||||
} // cfg.args;
|
||||
}] ++ cfg.defaults;
|
||||
|
||||
test = (kubenix.evalModules {
|
||||
|
|
@ -229,6 +230,12 @@ in {
|
|||
apply = tests: filter (test: test.enable) tests;
|
||||
};
|
||||
|
||||
testing.args = mkOption {
|
||||
description = "Attribute set of extra args passed to tests";
|
||||
type = types.attrs;
|
||||
default = {};
|
||||
};
|
||||
|
||||
testing.testsByName = mkOption {
|
||||
description = "Tests by name";
|
||||
type = types.attrsOf types.attrs;
|
||||
|
|
@ -249,6 +256,7 @@ in {
|
|||
tests = map (test: {
|
||||
inherit (test) name description success test;
|
||||
assertions = moduleToAttrs test.assertions;
|
||||
generated = test.generated;
|
||||
}) (filter (test: test.enable) cfg.tests);
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ in rec {
|
|||
results = mapAttrs (_: test: test.result) tests;
|
||||
});
|
||||
|
||||
tests-check =
|
||||
test-check =
|
||||
if !(all (test: test.success) (attrValues tests))
|
||||
then throw "tests failed"
|
||||
else true;
|
||||
|
|
|
|||
|
|
@ -26,19 +26,16 @@ let
|
|||
./k8s/1.13/crd.nix
|
||||
./k8s/defaults.nix
|
||||
./k8s/order.nix
|
||||
./k8s/submodule.nix
|
||||
./helm/simple.nix
|
||||
./istio/bookinfo.nix
|
||||
./submodules/simple.nix
|
||||
./submodules/defaults.nix
|
||||
./submodules/versioning.nix
|
||||
./module.nix
|
||||
./metacontroller/compositecontroller.nix
|
||||
];
|
||||
testing.defaults = ({kubenix, ...}: {
|
||||
imports = [kubenix.modules.k8s];
|
||||
kubernetes.version = k8sVersion;
|
||||
_module.args.images = images;
|
||||
});
|
||||
testing.args = {
|
||||
inherit images k8sVersion;
|
||||
};
|
||||
}
|
||||
];
|
||||
args = {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
{ config, lib, pkgs, kubenix, helm, ... }:
|
||||
{ config, lib, pkgs, kubenix, helm, k8sVersion, ... }:
|
||||
|
||||
with lib;
|
||||
with kubenix.lib;
|
||||
|
|
@ -60,6 +60,8 @@ in {
|
|||
'';
|
||||
};
|
||||
|
||||
kubernetes.version = k8sVersion;
|
||||
|
||||
kubernetes.api.namespaces.test = {};
|
||||
|
||||
kubernetes.helm.instances.app-psql = {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
{ config, kubenix, ... }:
|
||||
{ config, kubenix, k8sVersion, ... }:
|
||||
|
||||
{
|
||||
imports = with kubenix.modules; [ test k8s istio ];
|
||||
|
|
@ -8,6 +8,8 @@
|
|||
description = "Simple istio bookinfo application (WIP)";
|
||||
};
|
||||
|
||||
kubernetes.version = k8sVersion;
|
||||
|
||||
kubernetes.api."networking.istio.io"."v1alpha3" = {
|
||||
Gateway."bookinfo-gateway" = {
|
||||
spec = {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
{ config, lib, kubenix, ... }:
|
||||
{ config, lib, kubenix, k8sVersion, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
|
|
@ -17,6 +17,8 @@ in {
|
|||
}];
|
||||
};
|
||||
|
||||
kubernetes.version = k8sVersion;
|
||||
|
||||
kubernetes.api.customresourcedefinitions.crontabs = {
|
||||
metadata.name = "crontabs.stable.example.com";
|
||||
spec = {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
{ config, lib, kubenix, pkgs, ... }:
|
||||
{ config, lib, kubenix, pkgs, k8sVersion, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
|
|
@ -22,6 +22,8 @@ in {
|
|||
'';
|
||||
};
|
||||
|
||||
kubernetes.version = k8sVersion;
|
||||
|
||||
kubernetes.api.customresourcedefinitions.crontabs = {
|
||||
metadata.name = "crontabs.stable.example.com";
|
||||
spec = {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
{ config, lib, kubenix, ... }:
|
||||
{ config, lib, kubenix, k8sVersion, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
|
|
@ -23,6 +23,8 @@ in {
|
|||
}];
|
||||
};
|
||||
|
||||
kubernetes.version = k8sVersion;
|
||||
|
||||
kubernetes.api.pods.pod1 = {};
|
||||
|
||||
kubernetes.api.pods.pod2 = {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
{ config, lib, pkgs, kubenix, images, ... }:
|
||||
{ config, lib, pkgs, kubenix, images, k8sVersion, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
|
|
@ -41,6 +41,8 @@ in {
|
|||
|
||||
docker.images.nginx.image = image;
|
||||
|
||||
kubernetes.version = k8sVersion;
|
||||
|
||||
kubernetes.api.deployments.nginx = {
|
||||
spec = {
|
||||
replicas = 10;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
{ config, lib, kubenix, pkgs, ... }:
|
||||
{ config, lib, kubenix, pkgs, k8sVersion, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
|
|
@ -20,6 +20,8 @@ in {
|
|||
}];
|
||||
};
|
||||
|
||||
kubernetes.version = k8sVersion;
|
||||
|
||||
kubernetes.api.customresourcedefinitions.crontabs = {
|
||||
metadata.name = "crontabs.stable.example.com";
|
||||
spec = {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
{ config, kubenix, ... }:
|
||||
{ config, kubenix, k8sVersion, ... }:
|
||||
|
||||
let
|
||||
cfg = config.kubernetes.api.pods.nginx;
|
||||
|
|
@ -17,5 +17,7 @@ in {
|
|||
}];
|
||||
};
|
||||
|
||||
kubernetes.version = k8sVersion;
|
||||
|
||||
kubernetes.api.pods.nginx = {};
|
||||
}
|
||||
|
|
|
|||
56
tests/k8s/submodule.nix
Normal file
56
tests/k8s/submodule.nix
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
{ name, config, lib, kubenix, images, ... }:
|
||||
|
||||
with lib;
|
||||
|
||||
let
|
||||
cfg = config.submodules.instances.passthru;
|
||||
in {
|
||||
imports = with kubenix.modules; [ test submodules k8s docker ];
|
||||
|
||||
test = {
|
||||
name = "k8s-submodule";
|
||||
description = "Simple k8s submodule test";
|
||||
assertions = [{
|
||||
message = "Submodule has correct name set";
|
||||
assertion = (head config.kubernetes.objects).metadata.name == "passthru";
|
||||
} {
|
||||
message = "Should expose docker image";
|
||||
assertion = (head config.docker.export).imageName == "xtruder/nginx";
|
||||
}];
|
||||
};
|
||||
|
||||
kubenix.project = "test-release";
|
||||
|
||||
kubernetes.namespace = "test-namespace";
|
||||
|
||||
submodules.imports = [{
|
||||
module = {name, config, ...}: {
|
||||
imports = with kubenix.modules; [ submodule k8s docker ];
|
||||
|
||||
config = {
|
||||
submodule.name = "test-submodule";
|
||||
|
||||
kubernetes.api.pods.nginx = {
|
||||
metadata.name = name;
|
||||
spec.containers.nginx.image = config.docker.images.nginx.path;
|
||||
};
|
||||
|
||||
docker.images.nginx.image = images.nginx;
|
||||
};
|
||||
};
|
||||
}];
|
||||
|
||||
kubernetes.api.defaults = [{
|
||||
propagate = true;
|
||||
default.metadata.labels.my-label = "my-value";
|
||||
}];
|
||||
|
||||
submodules.instances.passthru = {
|
||||
submodule = "test-submodule";
|
||||
};
|
||||
|
||||
submodules.instances.no-passthru = {
|
||||
submodule = "test-submodule";
|
||||
passthru.enable = false;
|
||||
};
|
||||
}
|
||||
|
|
@ -9,23 +9,27 @@ let
|
|||
instance4 = config.submodules.instances.instance4;
|
||||
instance5 = config.submodules.instances.instance5;
|
||||
|
||||
module = {name, ...}: {
|
||||
options.args.value = mkOption {
|
||||
description = "Submodule value";
|
||||
type = types.str;
|
||||
};
|
||||
submodule = {name, ...}: {
|
||||
imports = [ kubenix.modules.submodule ];
|
||||
|
||||
options.args.defaultValue = mkOption {
|
||||
description = "Submodule default value";
|
||||
type = types.str;
|
||||
options = {
|
||||
args.value = mkOption {
|
||||
description = "Submodule value";
|
||||
type = types.str;
|
||||
};
|
||||
|
||||
args.defaultValue = mkOption {
|
||||
description = "Submodule default value";
|
||||
type = types.str;
|
||||
};
|
||||
};
|
||||
};
|
||||
in {
|
||||
imports = with kubenix.modules; [ test submodules ];
|
||||
|
||||
test = {
|
||||
name = "submodules-defatuls";
|
||||
description = "Simple k8s submodule test";
|
||||
name = "submodules-defaults";
|
||||
description = "Simple submodule test";
|
||||
assertions = [{
|
||||
message = "should apply defaults by tag1";
|
||||
assertion = instance1.config.args.value == "value1";
|
||||
|
|
@ -53,34 +57,34 @@ in {
|
|||
};
|
||||
|
||||
submodules.imports = [{
|
||||
modules = [module {
|
||||
modules = [submodule {
|
||||
submodule = {
|
||||
name = "submodule1";
|
||||
tags = ["tag1"];
|
||||
};
|
||||
}];
|
||||
} {
|
||||
modules = [module {
|
||||
modules = [submodule {
|
||||
submodule = {
|
||||
name = "submodule2";
|
||||
tags = ["tag2"];
|
||||
};
|
||||
}];
|
||||
} {
|
||||
modules = [module {
|
||||
modules = [submodule {
|
||||
submodule = {
|
||||
name = "submodule3";
|
||||
tags = ["tag2"];
|
||||
};
|
||||
}];
|
||||
} {
|
||||
modules = [module {
|
||||
modules = [submodule {
|
||||
submodule = {
|
||||
name = "submodule4";
|
||||
};
|
||||
}];
|
||||
} {
|
||||
modules = [module {
|
||||
modules = [submodule {
|
||||
submodule = {
|
||||
name = "submodule5";
|
||||
};
|
||||
|
|
|
|||
|
|
@ -25,20 +25,30 @@ in {
|
|||
} {
|
||||
message = "Should have submodule name set";
|
||||
assertion = cfg.config.args.name == "instance";
|
||||
} {
|
||||
message = "should have tag set";
|
||||
assertion = elem "tag" (cfg.config.submodule.tags);
|
||||
}];
|
||||
};
|
||||
|
||||
submodules.propagate.enable = true;
|
||||
submodules.imports = [{
|
||||
module = {name, ...}: {
|
||||
config.submodule.name = "submodule";
|
||||
options.args.value = mkOption {
|
||||
description = "Submodule argument";
|
||||
type = types.str;
|
||||
imports = [ kubenix.modules.submodule ];
|
||||
config = {
|
||||
submodule.name = "submodule";
|
||||
submodule.tags = ["tag"];
|
||||
};
|
||||
options.args.name = mkOption {
|
||||
description = "Submodule name";
|
||||
type = types.str;
|
||||
default = name;
|
||||
options = {
|
||||
args.value = mkOption {
|
||||
description = "Submodule argument";
|
||||
type = types.str;
|
||||
};
|
||||
args.name = mkOption {
|
||||
description = "Submodule name";
|
||||
type = types.str;
|
||||
default = name;
|
||||
};
|
||||
};
|
||||
};
|
||||
}];
|
||||
|
|
|
|||
|
|
@ -8,12 +8,14 @@ let
|
|||
inst-latest = config.submodules.instances.inst-latest.config;
|
||||
|
||||
submodule = {
|
||||
config.submodule.name = "subm";
|
||||
imports = [ kubenix.modules.submodule ];
|
||||
|
||||
options.version = mkOption {
|
||||
type = types.str;
|
||||
default = "undefined";
|
||||
};
|
||||
|
||||
config.submodule.name = "subm";
|
||||
};
|
||||
in {
|
||||
imports = with kubenix.modules; [ test submodules ];
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue