From 9f05cd56b19a3256d6ca7d77e0c9ddca32aab380 Mon Sep 17 00:00:00 2001 From: Jaka Hudoklin Date: Sun, 6 Oct 2019 21:39:10 +0200 Subject: [PATCH] feat(legacy): refactor legacy kubenix support --- lib/extra.nix | 45 ++++++++++++++++++++ lib/modules.nix | 50 ---------------------- modules/default.nix | 4 +- modules/{v1/modules.nix => legacy.nix} | 42 +++++++++++++++---- modules/submodules.nix | 3 +- tests/default.nix | 2 +- tests/k8s/legacy.nix | 58 ++++++++++++++++++++++++++ tests/k8s/v1/modules.nix | 33 --------------- 8 files changed, 139 insertions(+), 98 deletions(-) delete mode 100644 lib/modules.nix rename modules/{v1/modules.nix => legacy.nix} (78%) create mode 100644 tests/k8s/legacy.nix delete mode 100644 tests/k8s/v1/modules.nix diff --git a/lib/extra.nix b/lib/extra.nix index dd6e583..fd2c467 100644 --- a/lib/extra.nix +++ b/lib/extra.nix @@ -40,4 +40,49 @@ rec { i = acc.i + 1; value = acc.value + (toInt char) * (exp 8 acc.i); }) {i = 0; value = 0;} (stringToCharacters value)).value; + + submoduleWithSpecialArgs = opts: specialArgs: + let + opts' = toList opts; + inherit (lib.modules) evalModules; + in + mkOptionType rec { + name = "submodule"; + check = x: isAttrs x || isFunction x; + merge = loc: defs: + let + coerce = def: if isFunction def then def else { config = def; }; + modules = opts' ++ map (def: { _file = def.file; imports = [(coerce def.value)]; }) defs; + in (evalModules { + inherit modules specialArgs; + prefix = loc; + }).config; + getSubOptions = prefix: (evalModules + { modules = opts'; inherit prefix specialArgs; + # This is a work-around due to the fact that some sub-modules, + # such as the one included in an attribute set, expects a "args" + # attribute to be given to the sub-module. As the option + # evaluation does not have any specific attribute name, we + # provide a default one for the documentation. + # + # This is mandatory as some option declaration might use the + # "name" attribute given as argument of the submodule and use it + # as the default of option declarations. + # + # Using lookalike unicode single angle quotation marks because + # of the docbook transformation the options receive. In all uses + # > and < wouldn't be encoded correctly so the encoded values + # would be used, and use of `<` and `>` would break the XML document. + # It shouldn't cause an issue since this is cosmetic for the manual. + args.name = "‹name›"; + }).options; + getSubModules = opts'; + substSubModules = m: submoduleWithSpecialArgs m specialArgs; + functor = (defaultFunctor name) // { + # Merging of submodules is done as part of mergeOptionDecls, as we have to annotate + # each submodule with its location. + payload = []; + binOp = lhs: rhs: []; + }; + }; } diff --git a/lib/modules.nix b/lib/modules.nix deleted file mode 100644 index 00b4fd2..0000000 --- a/lib/modules.nix +++ /dev/null @@ -1,50 +0,0 @@ -{ lib }: - -with lib; - -rec { - submoduleWithSpecialArgs = opts: specialArgs: - let - opts' = toList opts; - inherit (lib.modules) evalModules; - in - mkOptionType rec { - name = "submodule"; - check = x: isAttrs x || isFunction x; - merge = loc: defs: - let - coerce = def: if isFunction def then def else { config = def; }; - modules = opts' ++ map (def: { _file = def.file; imports = [(coerce def.value)]; }) defs; - in (evalModules { - inherit modules specialArgs; - prefix = loc; - }).config; - getSubOptions = prefix: (evalModules - { modules = opts'; inherit prefix specialArgs; - # This is a work-around due to the fact that some sub-modules, - # such as the one included in an attribute set, expects a "args" - # attribute to be given to the sub-module. As the option - # evaluation does not have any specific attribute name, we - # provide a default one for the documentation. - # - # This is mandatory as some option declaration might use the - # "name" attribute given as argument of the submodule and use it - # as the default of option declarations. - # - # Using lookalike unicode single angle quotation marks because - # of the docbook transformation the options receive. In all uses - # > and < wouldn't be encoded correctly so the encoded values - # would be used, and use of `<` and `>` would break the XML document. - # It shouldn't cause an issue since this is cosmetic for the manual. - args.name = "‹name›"; - }).options; - getSubModules = opts'; - substSubModules = m: submoduleWithSpecialArgs m specialArgs; - functor = (defaultFunctor name) // { - # Merging of submodules is done as part of mergeOptionDecls, as we have to annotate - # each submodule with its location. - payload = []; - binOp = lhs: rhs: []; - }; - }; -} diff --git a/modules/default.nix b/modules/default.nix index 86259d3..ad574b1 100644 --- a/modules/default.nix +++ b/modules/default.nix @@ -8,7 +8,5 @@ testing = ./testing.nix; test = ./test.nix; module = ./module.nix; - v1 = { - modules = ./v1/modules.nix; - }; + legacy = ./legacy.nix; } diff --git a/modules/v1/modules.nix b/modules/legacy.nix similarity index 78% rename from modules/v1/modules.nix rename to modules/legacy.nix index 3e0673a..f0648ca 100644 --- a/modules/v1/modules.nix +++ b/modules/legacy.nix @@ -1,7 +1,8 @@ -{ config, pkgs, lib, ... }: +# support for legacy kubenix + +{ options, config, pkgs, lib, kubenix, ... }: with lib; -with import ../../lib/modules.nix { inherit lib; }; let parentModule = module; @@ -30,8 +31,8 @@ let _module.args.name = module.name; _module.args.module = module; } - ../k8s.nix - ./modules.nix + ./k8s.nix + ./legacy.nix (injectModuleAttrs moduleDefinition.module {_file = file;}) { config.kubernetes.api.defaults = [{ @@ -42,6 +43,7 @@ let ++ (optionals (hasAttr moduleDefinition.name config.kubernetes.defaultModuleConfiguration) config.kubernetes.defaultModuleConfiguration.${moduleDefinition.name}); + # prefix kubernetes objects with ${serviceName}, this magic was removed in new kubenix prefixResources = resources: serviceName: map (resource: resource // { metadata = resource.metadata // { name = "${serviceName}-${resource.metadata.name}"; @@ -60,10 +62,10 @@ let else throw ''requested kubernetes moduleDefinition with name "${name}" does not exist''; in { - imports = [ ../k8s.nix ]; + imports = [ ./k8s.nix ]; options.kubernetes.moduleDefinitions = mkOption { - description = "Attribute set of module definitions"; + description = "Legacy kubenix attribute set of module definitions"; default = {}; type = types.attrsOf (types.submodule ({name, ...}: { options = { @@ -93,7 +95,7 @@ in { }; options.kubernetes.defaultModuleConfiguration = mkOption { - description = "Module default options"; + description = "Legacy kubenix module default options"; type = types.submodule { options = defaultModuleConfigurationOptions // { all = mkOption { @@ -107,7 +109,7 @@ in { }; options.kubernetes.modules = mkOption { - description = "Attribute set of modules"; + description = "Legacy kubenix attribute set of modules"; default = {}; type = types.attrsOf (types.submodule ({config, name, ...}: { options = { @@ -134,8 +136,10 @@ in { configuration = mkOption { description = "Module configuration"; - type = types.submodule { + type = submoduleWithSpecialArgs { imports = mkModuleOptions (getModuleDefinition config.module) config; + } { + inherit kubenix; }; default = {}; }; @@ -149,7 +153,24 @@ in { })); }; + options.kubernetes.defaults = mkOption { + type = types.attrsOf (types.coercedTo types.unspecified (value: [value]) (types.listOf types.unspecified)); + description = "Legacy kubenix kubernetes defaults."; + default = {}; + }; + + # for back compatibility with kubernetes.customResources + options.kubernetes.customResources = options.kubernetes.resources; + config = { + kubernetes.api.defaults = mapAttrsToList (attrName: default: let + type = head (filter (type: type.attrName == attrName) config.kubernetes.api.types); + in { + default = { imports = default; }; + } // (if (attrName == "all") then {} else { + resource = type.name; + })) config.kubernetes.defaults; + kubernetes.objects = mkMerge ( mapAttrsToList (name: module: let moduleDefinition = getModuleDefinition module.module; @@ -160,6 +181,9 @@ in { ) config.kubernetes.modules ); + # custom resources are now included in normal resources, so just make an alias + kubernetes.customResources = mkAliasDefinitions options.kubernetes.resources; + kubernetes.defaultModuleConfiguration.all = { _file = head options.kubernetes.defaultModuleConfiguration.files; config.kubernetes.version = mkDefault config.kubernetes.version; diff --git a/modules/submodules.nix b/modules/submodules.nix index e457ef0..aa3dfd6 100644 --- a/modules/submodules.nix +++ b/modules/submodules.nix @@ -1,7 +1,6 @@ -{ config, kubenix, pkgs, lib, ... }: +{ config, options, kubenix, pkgs, lib, ... }: with lib; -with import ../lib/modules.nix { inherit lib; }; let cfg = config.submodules; diff --git a/tests/default.nix b/tests/default.nix index efdf09f..26ee633 100644 --- a/tests/default.nix +++ b/tests/default.nix @@ -30,7 +30,7 @@ let ./k8s/order.nix ./k8s/submodule.nix ./k8s/imports.nix - ./k8s/v1/modules.nix + ./k8s/legacy.nix ./helm/simple.nix ./istio/bookinfo.nix ./submodules/simple.nix diff --git a/tests/k8s/legacy.nix b/tests/k8s/legacy.nix new file mode 100644 index 0000000..1ab4234 --- /dev/null +++ b/tests/k8s/legacy.nix @@ -0,0 +1,58 @@ +{ config, lib, kubenix, pkgs, k8sVersion, ... }: + +with lib; + +{ + + imports = with kubenix.modules; [ test k8s legacy ]; + + test = { + name = "k8s-legacy"; + description = "Simple test tesing kubenix legacy support"; + assertions = []; + }; + + kubernetes.version = k8sVersion; + + kubernetes.moduleDefinitions.app.module = { config, k8s, ... }: { + options = { + replicas = mkOption { + description = "Number of replicas to run"; + type = types.int; + default = 2; + }; + }; + + config.kubernetes.defaults = { + all = [{ + metadata.labels.default = "value"; + }]; + + deployments = [{ + metadata.labels.default2 = "value2"; + } { + metadata.labels.default3 = "value3"; + }]; + }; + + config.kubernetes.resources.deployments.app = { + spec = { + replicas = config.replicas; + selector = { + matchLabels.app = "app"; + }; + template.spec = { + containers.app = { + image = "hello-world"; + }; + }; + }; + }; + }; + + kubernetes.modules.myapp = { + module = "app"; + namespace = "test"; + configuration.replicas = 3; + }; +} diff --git a/tests/k8s/v1/modules.nix b/tests/k8s/v1/modules.nix deleted file mode 100644 index 8dfd1e7..0000000 --- a/tests/k8s/v1/modules.nix +++ /dev/null @@ -1,33 +0,0 @@ -{ 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"; - }; -}