2019-03-07 23:23:07 +01:00
|
|
|
# K8S module defines kubernetes definitions for kubenix
|
|
|
|
|
|
2019-03-07 18:02:26 +01:00
|
|
|
{ config, lib, pkgs, k8s, ... }:
|
2019-02-10 21:03:47 +01:00
|
|
|
|
|
|
|
|
with lib;
|
|
|
|
|
|
|
|
|
|
let
|
2019-02-28 14:04:16 +01:00
|
|
|
cfg = config.kubernetes;
|
|
|
|
|
|
2019-02-26 21:22:03 +01:00
|
|
|
getDefaults = resource: group: version: kind:
|
|
|
|
|
catAttrs "default" (filter (default:
|
2019-02-27 14:18:38 +01:00
|
|
|
(resource == null || default.resource == null || default.resource == resource) &&
|
2019-02-26 21:22:03 +01:00
|
|
|
(default.group == null || default.group == group) &&
|
|
|
|
|
(default.version == null || default.version == version) &&
|
|
|
|
|
(default.kind == null || default.kind == kind)
|
2019-02-28 14:04:16 +01:00
|
|
|
) cfg.api.defaults);
|
2019-02-26 21:22:03 +01:00
|
|
|
|
2019-02-10 21:03:47 +01:00
|
|
|
moduleToAttrs = value:
|
|
|
|
|
if isAttrs value
|
2019-03-13 10:15:07 +01:00
|
|
|
then mapAttrs (n: v: moduleToAttrs v) (filterAttrs (n: v: v != null && !(hasPrefix "_" n)) value)
|
2019-02-10 21:03:47 +01:00
|
|
|
|
|
|
|
|
else if isList value
|
|
|
|
|
then map (v: moduleToAttrs v) value
|
|
|
|
|
|
|
|
|
|
else value;
|
|
|
|
|
|
|
|
|
|
flattenResources = resources: flatten (
|
|
|
|
|
mapAttrsToList (groupName: versions:
|
|
|
|
|
mapAttrsToList (versionName: kinds:
|
|
|
|
|
builtins.trace versionName kinds
|
|
|
|
|
) versions
|
|
|
|
|
) resources
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
apiOptions = { config, ... }: {
|
|
|
|
|
options = {
|
|
|
|
|
definitions = mkOption {
|
|
|
|
|
description = "Attribute set of kubernetes definitions";
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
defaults = mkOption {
|
2019-02-26 21:22:03 +01:00
|
|
|
description = "Kubernetes defaults to apply to resources";
|
|
|
|
|
type = types.listOf (types.submodule ({config, ...}: {
|
|
|
|
|
options = {
|
|
|
|
|
resource = mkOption {
|
|
|
|
|
description = "Resource to apply default to (all by default)";
|
|
|
|
|
type = types.nullOr types.str;
|
|
|
|
|
default = null;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
group = mkOption {
|
|
|
|
|
description = "Group to apply default to (all by default)";
|
|
|
|
|
type = types.nullOr types.str;
|
|
|
|
|
default = null;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
version = mkOption {
|
|
|
|
|
description = "Version to apply default to (all by default)";
|
|
|
|
|
type = types.nullOr types.str;
|
|
|
|
|
default = null;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
kind = mkOption {
|
|
|
|
|
description = "Kind to apply default to (all by default)";
|
|
|
|
|
type = types.nullOr types.str;
|
|
|
|
|
default = null;
|
|
|
|
|
};
|
|
|
|
|
|
2019-03-12 20:33:56 +01:00
|
|
|
propagate = mkOption {
|
|
|
|
|
description = "Whether to propagate default";
|
|
|
|
|
type = types.bool;
|
|
|
|
|
default = false;
|
|
|
|
|
};
|
|
|
|
|
|
2019-02-26 21:22:03 +01:00
|
|
|
default = mkOption {
|
|
|
|
|
description = "Default to apply";
|
|
|
|
|
type = types.unspecified;
|
|
|
|
|
default = {};
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
}));
|
|
|
|
|
default = [];
|
2019-02-10 21:03:47 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
resources = mkOption {
|
|
|
|
|
type = types.listOf (types.submodule {
|
|
|
|
|
options = {
|
|
|
|
|
group = mkOption {
|
2019-02-26 21:22:03 +01:00
|
|
|
description = "Resoruce group";
|
2019-02-10 21:03:47 +01:00
|
|
|
type = types.str;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
version = mkOption {
|
2019-02-26 21:22:03 +01:00
|
|
|
description = "Resoruce version";
|
2019-02-10 21:03:47 +01:00
|
|
|
type = types.str;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
kind = mkOption {
|
2019-02-26 21:22:03 +01:00
|
|
|
description = "Resource kind";
|
2019-02-10 21:03:47 +01:00
|
|
|
type = types.str;
|
|
|
|
|
};
|
|
|
|
|
|
2019-02-26 21:22:03 +01:00
|
|
|
resource = mkOption {
|
|
|
|
|
description = "Resource name";
|
2019-03-13 10:15:54 +01:00
|
|
|
type = types.str;
|
2019-02-10 21:03:47 +01:00
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
});
|
|
|
|
|
default = [];
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
};
|
2019-02-28 14:04:47 +01:00
|
|
|
|
|
|
|
|
indexOf = lst: value:
|
|
|
|
|
head (filter (v: v != -1) (imap0 (i: v: if v == value then i else -1) lst));
|
2019-03-08 23:26:11 +01:00
|
|
|
|
2019-03-08 23:28:48 +01:00
|
|
|
customResourceOptions = map (cr: {config, ...}: let
|
2019-03-13 18:02:52 +01:00
|
|
|
module = { name, ... }: {
|
2019-03-08 23:26:11 +01:00
|
|
|
imports = getDefaults cr.resource cr.group cr.version cr.kind;
|
|
|
|
|
options = {
|
|
|
|
|
apiVersion = mkOption {
|
|
|
|
|
description = "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#resources";
|
|
|
|
|
type = types.nullOr types.str;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
kind = mkOption {
|
|
|
|
|
description = "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds";
|
|
|
|
|
type = types.nullOr types.str;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
metadata = mkOption {
|
|
|
|
|
description = "Standard object metadata; More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#metadata.";
|
|
|
|
|
type = types.nullOr (types.submodule config.definitions."io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta");
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
spec = mkOption {
|
|
|
|
|
description = "Module spec";
|
2019-03-13 18:04:02 +01:00
|
|
|
type = types.either types.attrs (types.submodule cr.module);
|
2019-03-08 23:26:11 +01:00
|
|
|
default = {};
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
config = {
|
|
|
|
|
apiVersion = mkOptionDefault "${cr.group}/${cr.version}";
|
|
|
|
|
kind = mkOptionDefault cr.kind;
|
|
|
|
|
metadata.name = mkOptionDefault name;
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
in if cr.alias != null then {
|
|
|
|
|
options.${cr.group}.${cr.version}.${cr.kind} = mkOption {
|
|
|
|
|
description = cr.description;
|
|
|
|
|
type = types.attrsOf (types.submodule module);
|
|
|
|
|
default = {};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
options.${cr.alias} = mkOption {
|
|
|
|
|
description = cr.description;
|
|
|
|
|
type = types.attrsOf (types.submodule module);
|
|
|
|
|
default = {};
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
config.${cr.group}.${cr.version}.${cr.kind} = config.${cr.alias};
|
|
|
|
|
} else {
|
|
|
|
|
options.${cr.group}.${cr.version}.${cr.kind} = mkOption {
|
|
|
|
|
description = cr.description;
|
|
|
|
|
type = types.attrsOf (types.submodule module);
|
|
|
|
|
default = {};
|
|
|
|
|
};
|
|
|
|
|
}) cfg.customResources;
|
2019-02-10 21:03:47 +01:00
|
|
|
in {
|
2019-03-12 20:33:56 +01:00
|
|
|
imports = [ ./base.nix ./submodules.nix ];
|
2019-02-10 21:03:47 +01:00
|
|
|
|
2019-03-12 20:33:56 +01:00
|
|
|
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";
|
|
|
|
|
};
|
2019-02-10 21:03:47 +01:00
|
|
|
|
2019-03-12 20:33:56 +01:00
|
|
|
namespace = mkOption {
|
|
|
|
|
description = "Default namespace where to deploy kubernetes resources";
|
|
|
|
|
type = types.str;
|
|
|
|
|
default = "default";
|
|
|
|
|
};
|
2019-02-28 14:04:47 +01:00
|
|
|
|
2019-03-12 20:33:56 +01:00
|
|
|
resourceOrder = mkOption {
|
|
|
|
|
description = "Preffered resource order";
|
|
|
|
|
type = types.listOf types.str;
|
|
|
|
|
default = [
|
|
|
|
|
"CustomResourceDefinition"
|
|
|
|
|
"Namespace"
|
|
|
|
|
];
|
2019-02-10 21:03:47 +01:00
|
|
|
};
|
|
|
|
|
|
2019-03-12 20:33:56 +01:00
|
|
|
api = mkOption {
|
|
|
|
|
type = types.submodule {
|
|
|
|
|
imports = [
|
|
|
|
|
(./generated + ''/v'' + cfg.version + ".nix")
|
|
|
|
|
apiOptions
|
|
|
|
|
] ++ customResourceOptions;
|
|
|
|
|
};
|
|
|
|
|
default = {};
|
|
|
|
|
};
|
2019-02-10 21:03:47 +01:00
|
|
|
|
2019-03-12 20:33:56 +01:00
|
|
|
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;
|
|
|
|
|
};
|
2019-02-10 21:03:47 +01:00
|
|
|
|
2019-03-12 20:33:56 +01:00
|
|
|
version = mkOption {
|
|
|
|
|
description = "Custom resource definition version";
|
|
|
|
|
type = types.str;
|
|
|
|
|
};
|
2019-02-10 21:03:47 +01:00
|
|
|
|
2019-03-12 20:33:56 +01:00
|
|
|
kind = mkOption {
|
|
|
|
|
description = "Custom resource definition kind";
|
|
|
|
|
type = types.str;
|
|
|
|
|
};
|
2019-02-10 21:03:47 +01:00
|
|
|
|
2019-03-12 20:33:56 +01:00
|
|
|
resource = mkOption {
|
|
|
|
|
description = "Custom resource definition resource name";
|
|
|
|
|
type = types.nullOr types.str;
|
|
|
|
|
default = null;
|
|
|
|
|
};
|
2019-02-10 21:03:47 +01:00
|
|
|
|
2019-03-12 20:33:56 +01:00
|
|
|
description = mkOption {
|
|
|
|
|
description = "Custom resource definition description";
|
|
|
|
|
type = types.str;
|
|
|
|
|
default = "";
|
|
|
|
|
};
|
2019-03-08 23:26:11 +01:00
|
|
|
|
2019-03-12 20:33:56 +01:00
|
|
|
module = mkOption {
|
|
|
|
|
description = "Custom resource definition module";
|
2019-03-13 18:04:22 +01:00
|
|
|
type = types.unspecified;
|
|
|
|
|
default = {};
|
2019-03-12 20:33:56 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
alias = mkOption {
|
|
|
|
|
description = "Alias to create for API";
|
|
|
|
|
type = types.nullOr types.str;
|
|
|
|
|
default = null;
|
|
|
|
|
};
|
2019-03-08 23:26:11 +01:00
|
|
|
};
|
2019-03-12 20:33:56 +01:00
|
|
|
}));
|
|
|
|
|
};
|
2019-02-10 21:03:47 +01:00
|
|
|
|
2019-03-12 20:33:56 +01:00
|
|
|
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
|
2019-03-13 10:15:07 +01:00
|
|
|
) (unique items);
|
2019-03-12 20:33:56 +01:00
|
|
|
default = [];
|
|
|
|
|
};
|
2019-02-10 21:03:47 +01:00
|
|
|
|
2019-03-12 20:33:56 +01:00
|
|
|
generated = mkOption {
|
|
|
|
|
description = "Generated kubernetes list object";
|
|
|
|
|
type = types.attrs;
|
|
|
|
|
};
|
2019-02-10 21:03:47 +01:00
|
|
|
};
|
|
|
|
|
|
2019-03-12 20:33:56 +01:00
|
|
|
config = {
|
|
|
|
|
# expose k8s helper methods as module argument
|
|
|
|
|
_module.args.k8s = import ../lib/k8s.nix { inherit lib; };
|
|
|
|
|
|
|
|
|
|
_module.features = [ "k8s" ];
|
|
|
|
|
|
|
|
|
|
kubernetes.api.resources = map (cr: {
|
|
|
|
|
inherit (cr) group version kind resource;
|
|
|
|
|
}) cfg.customResources;
|
|
|
|
|
|
|
|
|
|
kubernetes.objects = mkMerge [
|
|
|
|
|
# gvk resources
|
|
|
|
|
(flatten (map (gvk:
|
|
|
|
|
mapAttrsToList (name: resource:
|
2019-03-13 10:15:39 +01:00
|
|
|
moduleToAttrs resource
|
2019-03-12 20:33:56 +01:00
|
|
|
) cfg.api.${gvk.group}.${gvk.version}.${gvk.kind}
|
|
|
|
|
) cfg.api.resources))
|
|
|
|
|
|
2019-03-13 10:15:07 +01:00
|
|
|
(flatten (map (gvk:
|
|
|
|
|
mapAttrsToList (name: resource:
|
|
|
|
|
moduleToAttrs resource
|
|
|
|
|
) cfg.api.${gvk.resource}
|
|
|
|
|
) cfg.api.resources))
|
|
|
|
|
|
2019-03-12 20:33:56 +01:00
|
|
|
# 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))
|
|
|
|
|
];
|
2019-02-10 21:03:47 +01:00
|
|
|
|
2019-03-12 20:33:56 +01:00
|
|
|
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;
|
|
|
|
|
})
|
|
|
|
|
];
|
|
|
|
|
};
|
|
|
|
|
}];
|
2019-02-10 21:03:47 +01:00
|
|
|
|
2019-03-12 20:33:56 +01:00
|
|
|
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;
|
|
|
|
|
};
|
|
|
|
|
}];
|
2019-02-20 09:33:33 +01:00
|
|
|
};
|
2019-02-10 21:03:47 +01:00
|
|
|
}
|