kubenix/modules/k8s.nix

271 lines
8.2 KiB
Nix
Raw Normal View History

# K8S module defines kubernetes definitions for kubenix
2019-03-07 18:02:26 +01:00
{ config, lib, pkgs, k8s, ... }:
with lib;
let
2019-02-28 14:04:16 +01:00
cfg = config.kubernetes;
removeKubenixOptions = filterAttrs (name: attr: name != "kubenix");
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
moduleToAttrs = value:
if isAttrs value
then mapAttrs (n: v: moduleToAttrs v) (filterAttrs (n: v: !(hasPrefix "_" n) && v != null) value)
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;
};
default = mkOption {
description = "Default to apply";
type = types.unspecified;
default = {};
};
};
}));
default = [];
};
resources = mkOption {
type = types.listOf (types.submodule {
options = {
group = mkOption {
2019-02-26 21:22:03 +01:00
description = "Resoruce group";
type = types.str;
};
version = mkOption {
2019-02-26 21:22:03 +01:00
description = "Resoruce version";
type = types.str;
};
kind = mkOption {
2019-02-26 21:22:03 +01:00
description = "Resource kind";
type = types.str;
};
2019-02-26 21:22:03 +01:00
resource = mkOption {
description = "Resource name";
type = type.str;
};
};
});
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));
customResourceModules = map (cr: {config, ...}: let
module = {name, ...}: {
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";
type = types.submodule cr.module;
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;
in {
# expose k8s helper methods as module argument
config._module.args.k8s = import ../lib/k8s.nix { inherit lib; };
options.kubernetes.version = mkOption {
description = "Kubernetes version to use";
2019-02-13 17:04:13 +01:00
type = types.enum ["1.7" "1.8" "1.9" "1.10" "1.11" "1.12" "1.13"];
default = "1.13";
};
2019-02-28 14:04:47 +01:00
options.kubernetes.resourceOrder = mkOption {
description = "Preffered resource order";
type = types.listOf types.str;
default = [
"CustomResourceDefinition"
"Namespace"
];
};
options.kubernetes.api = mkOption {
type = types.submodule {
imports = [
2019-02-28 14:04:16 +01:00
(./generated + ''/v'' + cfg.version + ".nix")
apiOptions
] ++ customResourceModules;
};
default = {};
};
options.kubernetes.customResources = mkOption {
default = [];
2019-02-26 21:22:03 +01:00
description = "List of custom resource definitions to make API for";
type = types.listOf (types.submodule ({config, ...}: {
options = {
group = mkOption {
2019-02-26 21:22:03 +01:00
description = "Custom resource definition group";
type = types.str;
};
version = mkOption {
2019-02-26 21:22:03 +01:00
description = "Custom resource definition version";
type = types.str;
};
kind = mkOption {
2019-02-26 21:22:03 +01:00
description = "Custom resource definition kind";
type = types.str;
};
2019-02-26 21:22:03 +01:00
resource = mkOption {
description = "Custom resource definition resource name";
2019-02-27 14:18:38 +01:00
type = types.nullOr types.str;
default = null;
};
description = mkOption {
2019-02-26 21:22:03 +01:00
description = "Custom resource definition description";
type = types.str;
2019-02-13 17:05:18 +01:00
default = "";
};
module = mkOption {
2019-02-26 21:22:03 +01:00
description = "Custom resource definition module";
2019-02-13 17:05:18 +01:00
default = types.unspecified;
};
alias = mkOption {
description = "Alias to create for API";
type = types.nullOr types.str;
default = null;
};
};
}));
};
config.kubernetes.api.resources = map (cr: {
2019-02-26 21:22:03 +01:00
inherit (cr) group version kind resource;
2019-02-28 14:04:47 +01:00
}) cfg.customResources;
options.kubernetes.objects = mkOption {
2019-03-07 18:02:26 +01:00
description = "List of generated kubernetes objects";
type = types.listOf types.attrs;
apply = items: sort (r1: r2:
2019-02-28 14:04:47 +01:00
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 = [];
};
config.kubernetes.objects = flatten (map (gvk:
mapAttrsToList (name: resource:
removeKubenixOptions (moduleToAttrs resource)
2019-02-28 14:04:16 +01:00
) cfg.api.${gvk.group}.${gvk.version}.${gvk.kind}
) cfg.api.resources);
options.kubernetes.generated = mkOption {
2019-03-07 18:02:26 +01:00
description = "Generated kubernetes list object";
type = types.attrs;
};
2019-03-07 18:02:26 +01:00
config.kubernetes.generated = k8s.mkHashedList {
items = config.kubernetes.objects;
};
}