From ff59c7d9051970cd361cfbdf8f83ace6890f5f8a Mon Sep 17 00:00:00 2001 From: Jaka Hudoklin Date: Fri, 27 Sep 2019 18:29:54 +0200 Subject: [PATCH] feat: initial back compatibility for kubenix 1.0 --- modules/v1/modules.nix | 169 +++++++++++++++++++++++++++++++++++++++ tests/default.nix | 1 + tests/k8s/v1/modules.nix | 33 ++++++++ 3 files changed, 203 insertions(+) create mode 100644 modules/v1/modules.nix create mode 100644 tests/k8s/v1/modules.nix diff --git a/modules/v1/modules.nix b/modules/v1/modules.nix new file mode 100644 index 0000000..3e0673a --- /dev/null +++ b/modules/v1/modules.nix @@ -0,0 +1,169 @@ +{ config, pkgs, lib, ... }: + +with lib; +with import ../../lib/modules.nix { inherit lib; }; + +let + parentModule = module; + + mkModuleOptions = moduleDefinition: module: + let + # gets file where module is defined by looking into moduleDefinitions + # option. + file = + elemAt options.kubernetes.moduleDefinitions.files ( + (findFirst (i: i > 0) 0 + (imap + (i: def: if hasAttr module.module def then i else 0) + options.kubernetes.moduleDefinitions.definitions + ) + ) - 1 + ); + + injectModuleAttrs = module: attrs: ( + if isFunction module then args: (applyIfFunction file module args) // attrs + else if isAttrs mkOptionDefault.module then module // attrs + else module + ); + in [ + { + _module.args.name = module.name; + _module.args.module = module; + } + ../k8s.nix + ./modules.nix + (injectModuleAttrs moduleDefinition.module {_file = file;}) + { + config.kubernetes.api.defaults = [{ + default.metadata.namespace = mkOptionDefault module.namespace; + }]; + } + ] ++ config.kubernetes.defaultModuleConfiguration.all + ++ (optionals (hasAttr moduleDefinition.name config.kubernetes.defaultModuleConfiguration) + config.kubernetes.defaultModuleConfiguration.${moduleDefinition.name}); + + prefixResources = resources: serviceName: map (resource: resource // { + metadata = resource.metadata // { + name = "${serviceName}-${resource.metadata.name}"; + }; + }) resources; + + defaultModuleConfigurationOptions = mapAttrs (name: moduleDefinition: mkOption { + description = "Module default configuration for ${name} module"; + type = types.coercedTo types.unspecified (value: [value]) (types.listOf types.unspecified); + default = []; + }) config.kubernetes.moduleDefinitions; + + getModuleDefinition = name: + if hasAttr name config.kubernetes.moduleDefinitions + then config.kubernetes.moduleDefinitions.${name} + else throw ''requested kubernetes moduleDefinition with name "${name}" does not exist''; + +in { + imports = [ ../k8s.nix ]; + + options.kubernetes.moduleDefinitions = mkOption { + description = "Attribute set of module definitions"; + default = {}; + type = types.attrsOf (types.submodule ({name, ...}: { + options = { + name = mkOption { + description = "Module definition name"; + type = types.str; + default = name; + }; + + prefixResources = mkOption { + description = "Whether resources should be automatically prefixed with module name"; + type = types.bool; + default = true; + }; + + assignAsDefaults = mkOption { + description = "Whether to assign resources as defaults, this is usefull for module that add some functionality"; + type = types.bool; + default = false; + }; + + module = mkOption { + description = "Module definition"; + }; + }; + })); + }; + + options.kubernetes.defaultModuleConfiguration = mkOption { + description = "Module default options"; + type = types.submodule { + options = defaultModuleConfigurationOptions // { + all = mkOption { + description = "Module default configuration for all modules"; + type = types.coercedTo types.unspecified (value: [value]) (types.listOf types.unspecified); + default = []; + }; + }; + }; + default = {}; + }; + + options.kubernetes.modules = mkOption { + description = "Attribute set of modules"; + default = {}; + type = types.attrsOf (types.submodule ({config, name, ...}: { + options = { + name = mkOption { + description = "Module name"; + type = types.str; + default = name; + }; + + namespace = mkOption { + description = "Namespace where to deploy module"; + type = types.str; + default = + if parentModule != null + then parentModule.namespace + else "default"; + }; + + labels = mkOption { + description = "Attribute set of module lables"; + type = types.attrsOf types.str; + default = {}; + }; + + configuration = mkOption { + description = "Module configuration"; + type = types.submodule { + imports = mkModuleOptions (getModuleDefinition config.module) config; + }; + default = {}; + }; + + module = mkOption { + description = "Name of the module to use"; + type = types.str; + default = config.name; + }; + }; + })); + }; + + config = { + kubernetes.objects = mkMerge ( + mapAttrsToList (name: module: let + moduleDefinition = getModuleDefinition module.module; + in + if moduleDefinition.prefixResources + then prefixResources (module.configuration.kubernetes.objects) module.name + else module.configuration.kubernetes.objects + ) config.kubernetes.modules + ); + + kubernetes.defaultModuleConfiguration.all = { + _file = head options.kubernetes.defaultModuleConfiguration.files; + config.kubernetes.version = mkDefault config.kubernetes.version; + config.kubernetes.moduleDefinitions = config.kubernetes.moduleDefinitions; + }; + }; +} diff --git a/tests/default.nix b/tests/default.nix index 93f7132..efdf09f 100644 --- a/tests/default.nix +++ b/tests/default.nix @@ -30,6 +30,7 @@ let ./k8s/order.nix ./k8s/submodule.nix ./k8s/imports.nix + ./k8s/v1/modules.nix ./helm/simple.nix ./istio/bookinfo.nix ./submodules/simple.nix diff --git a/tests/k8s/v1/modules.nix b/tests/k8s/v1/modules.nix new file mode 100644 index 0000000..8dfd1e7 --- /dev/null +++ b/tests/k8s/v1/modules.nix @@ -0,0 +1,33 @@ +{ config, lib, kubenix, pkgs, k8sVersion, ... }: { + + imports = with kubenix.modules; [ test k8s v1.modules ]; + + test = { + name = "k8s-v1-modules"; + description = "Simple test tesing CRD"; + assertions = []; + }; + + kubernetes.version = k8sVersion; + + kubernetes.moduleDefinitions.app.module = { config, k8s, ... }: { + kubernetes.resources.deployments.app = { + spec = { + replicas = 2; + selector = { + matchLabels.app = "app"; + }; + template.spec = { + containers.app = { + image = "hello-world"; + }; + }; + }; + }; + }; + + kubernetes.modules.myapp = { + module = "app"; + namespace = "test"; + }; +}