diff --git a/ci.nix b/ci.nix index b4ee8da..4d37fb6 100644 --- a/ci.nix +++ b/ci.nix @@ -1,6 +1,6 @@ let nixpkgsSrc = builtins.fetchTarball "https://github.com/NixOS/nixpkgs/archive/master.tar.gz"; - pkgs = import nixpkgsSrc {}; + pkgs = import nixpkgsSrc { }; lib = pkgs.lib; @@ -8,4 +8,5 @@ let inherit pkgs lib; nixosPath = "${nixpkgsSrc}/nixos"; }; -in pkgs.recurseIntoAttrs release +in +pkgs.recurseIntoAttrs release diff --git a/default.nix b/default.nix index 0048e7b..ce6db8c 100644 --- a/default.nix +++ b/default.nix @@ -7,7 +7,6 @@ in }: with lib; - let kubenixLib = import ./lib { inherit lib pkgs; }; lib' = lib.extend (lib: self: import ./lib/extra.nix { inherit lib pkgs; }); @@ -18,46 +17,54 @@ let # evalModules with same interface as lib.evalModules and kubenix as # special argument - evalModules = { - module ? null, - modules ? [module], - specialArgs ? defaultSpecialArgs, ... - }@attrs: let - attrs' = filterAttrs (n: _: n != "module") attrs; - in lib'.evalModules (recursiveUpdate { - inherit specialArgs modules; - args = { - inherit pkgs; - name = "default"; - }; - } attrs'); + evalModules = + { module ? null + , modules ? [ module ] + , specialArgs ? defaultSpecialArgs + , ... + }@attrs: + let + attrs' = filterAttrs (n: _: n != "module") attrs; + in + lib'.evalModules (recursiveUpdate + { + inherit specialArgs modules; + args = { + inherit pkgs; + name = "default"; + }; + } + attrs'); modules = import ./modules; # legacy support for buildResources - buildResources = { - configuration ? {}, - writeJSON ? true, - writeHash ? true - }: let - evaled = evalModules { - modules = [ - configuration - modules.legacy - ]; - }; + buildResources = + { configuration ? { } + , writeJSON ? true + , writeHash ? true + }: + let + evaled = evalModules { + modules = [ + configuration + modules.legacy + ]; + }; - generated = evaled.config.kubernetes.generated; + generated = evaled.config.kubernetes.generated; - result = - if writeJSON - then pkgs.writeText "resources.json" (builtins.toJSON generated) - else generated; - in result; + result = + if writeJSON + then pkgs.writeText "resources.json" (builtins.toJSON generated) + else generated; + in + result; kubenix = { inherit evalModules buildResources modules; lib = kubenixLib; }; -in kubenix +in +kubenix diff --git a/examples/default.nix b/examples/default.nix index 3b705b7..3e0ee9d 100644 --- a/examples/default.nix +++ b/examples/default.nix @@ -1,4 +1,4 @@ -{ kubenix ? import ./.. {} }: +{ kubenix ? import ./.. { } }: { nginx-deployment = import ./nginx-deployment { inherit kubenix; }; diff --git a/examples/nginx-deployment/default.nix b/examples/nginx-deployment/default.nix index e3ecfd7..d47b1b0 100644 --- a/examples/nginx-deployment/default.nix +++ b/examples/nginx-deployment/default.nix @@ -1,4 +1,4 @@ -{ kubenix ? import ../.. {}, registry ? "docker.io/gatehub" }: +{ kubenix ? import ../.. { }, registry ? "docker.io/gatehub" }: with kubenix.lib; diff --git a/examples/nginx-deployment/image.nix b/examples/nginx-deployment/image.nix index 347d6d7..8f57b75 100644 --- a/examples/nginx-deployment/image.nix +++ b/examples/nginx-deployment/image.nix @@ -10,9 +10,9 @@ dockerTools.buildLayeredImage { echo "nginx:x:1000:nginx" > etc/group ''; config = { - Cmd = ["nginx" "-c" "/etc/nginx/nginx.conf"]; + Cmd = [ "nginx" "-c" "/etc/nginx/nginx.conf" ]; ExposedPorts = { - "80/tcp" = {}; + "80/tcp" = { }; }; }; } diff --git a/examples/nginx-deployment/module.nix b/examples/nginx-deployment/module.nix index aa0c2d3..ec20056 100644 --- a/examples/nginx-deployment/module.nix +++ b/examples/nginx-deployment/module.nix @@ -1,10 +1,10 @@ { config, lib, pkgs, kubenix, ... }: with lib; - let nginx = pkgs.callPackage ./image.nix { }; -in { +in +{ imports = with kubenix.modules; [ k8s docker ]; docker.images.nginx.image = nginx; diff --git a/generators/istio/default.nix b/generators/istio/default.nix index 9f6ef55..e09e02e 100644 --- a/generators/istio/default.nix +++ b/generators/istio/default.nix @@ -1,14 +1,16 @@ -{ pkgs ? import {}, lib ? pkgs.lib, spec ? ./istio-schema.json }: +{ pkgs ? import { }, lib ? pkgs.lib, spec ? ./istio-schema.json }: with lib; - let gen = rec { - mkMerge = values: ''mkMerge [${concatMapStrings (value: " + mkMerge = values: ''mkMerge [${concatMapStrings +(value: " ${value} - ") values}]''; + ") +values}]''; - toNixString = value: if isAttrs value || isList value + toNixString = value: + if isAttrs value || isList value then builtins.toJSON value else if isString value then ''"${value}"'' @@ -18,19 +20,19 @@ let removeEmptyLines = str: concatStringsSep "\n" (filter (l: (builtins.match "( |)+" l) == null) (splitString "\n" str)); - mkOption = { - description ? null, - type ? null, - default ? null, - apply ? null - }: removeEmptyLines ''mkOption { + mkOption = + { description ? null + , type ? null + , default ? null + , apply ? null + }: removeEmptyLines ''mkOption { ${optionalString (description != null) "description = ${builtins.toJSON description};"} ${optionalString (type != null) ''type = ${type};''} ${optionalString (default != null) ''default = ${toNixString default};''} ${optionalString (apply != null) ''apply = ${apply};''} }''; - mkOverride = priority: value: "mkOverride ${toString priority} ${toNixString value}"; + mkOverride = priority: value: "mkOverride ${toString priority} ${toNixString value}"; types = { unspecified = "types.unspecified"; @@ -49,7 +51,7 @@ let hasTypeMapping = def: hasAttr "type" def && - elem def.type ["string" "integer" "boolean"]; + elem def.type [ "string" "integer" "boolean" ]; mergeValuesByKey = mergeKey: ''(mergeValuesByKey "${mergeKey}")''; @@ -77,256 +79,282 @@ let refDefinition = attr: head (tail (tail (splitString "/" attr."$ref"))); }; - fixJSON = content: replaceStrings ["\\u"] ["u"] content; + fixJSON = content: replaceStrings [ "\\u" ] [ "u" ] content; fetchSpecs = path: builtins.fromJSON (fixJSON (builtins.readFile path)); - genDefinitions = swagger: with gen; (mapAttrs (name: definition: - # if $ref is in definition it means it's an alias of other definition - if hasAttr "$ref" definition - then definitions."${refDefinition definition}" + genDefinitions = swagger: with gen; (mapAttrs + (name: definition: + # if $ref is in definition it means it's an alias of other definition + if hasAttr "$ref" definition + then definitions."${refDefinition definition}" - else if !(hasAttr "properties" definition) - then { - type = mapType definition; - } + else if !(hasAttr "properties" definition) + then { + type = mapType definition; + } - else { - options = mapAttrs (propName: property: - let - isRequired = elem propName (definition.required or []); - requiredOrNot = type: if isRequired then type else types.nullOr type; - optionProperties = - # if $ref is in property it references other definition, - # but if other definition does not have properties, then just take it's type - if hasAttr "$ref" property then - if hasTypeMapping swagger.definitions.${refDefinition property} then { - type = requiredOrNot (mapType swagger.definitions.${refDefinition property}); - } - else { - type = requiredOrNot (submoduleOf definitions (refDefinition property)); - } + else { + options = mapAttrs + (propName: property: + let + isRequired = elem propName (definition.required or [ ]); + requiredOrNot = type: if isRequired then type else types.nullOr type; + optionProperties = + # if $ref is in property it references other definition, + # but if other definition does not have properties, then just take it's type + if hasAttr "$ref" property then + if hasTypeMapping swagger.definitions.${refDefinition property} then { + type = requiredOrNot (mapType swagger.definitions.${refDefinition property}); + } + else { + type = requiredOrNot (submoduleOf definitions (refDefinition property)); + } - else if !(hasAttr "type" property) then { - type = types.unspecified; - } - - # if property has an array type - else if property.type == "array" then - - # if reference is in items it can reference other type of another - # definition - if hasAttr "$ref" property.items then - - # if it is a reference to simple type - if hasTypeMapping swagger.definitions.${refDefinition property.items} - then { - type = requiredOrNot (types.listOf (mapType swagger.definitions.${refDefinition property.items}.type)); + else if !(hasAttr "type" property) then { + type = types.unspecified; } - # if a reference is to complex type - else - # if x-kubernetes-patch-merge-key is set then make it an - # attribute set of submodules - if hasAttr "x-kubernetes-patch-merge-key" property - then let - mergeKey = property."x-kubernetes-patch-merge-key"; - in { - type = requiredOrNot (coerceAttrsOfSubmodulesToListByKey (refDefinition property.items) mergeKey); - apply = attrsToList; - } + # if property has an array type + else if property.type == "array" then - # in other case it's a simple list + # if reference is in items it can reference other type of another + # definition + if hasAttr "$ref" property.items then + + # if it is a reference to simple type + if hasTypeMapping swagger.definitions.${refDefinition property.items} + then { + type = requiredOrNot (types.listOf (mapType swagger.definitions.${refDefinition property.items}.type)); + } + + # if a reference is to complex type + else + # if x-kubernetes-patch-merge-key is set then make it an + # attribute set of submodules + if hasAttr "x-kubernetes-patch-merge-key" property + then + let + mergeKey = property."x-kubernetes-patch-merge-key"; + in + { + type = requiredOrNot (coerceAttrsOfSubmodulesToListByKey (refDefinition property.items) mergeKey); + apply = attrsToList; + } + + # in other case it's a simple list + else { + type = requiredOrNot (types.listOf (submoduleOf definitions (refDefinition property.items))); + } + + # in other case it only references a simple type else { - type = requiredOrNot (types.listOf (submoduleOf definitions (refDefinition property.items))); + type = requiredOrNot (types.listOf (mapType property.items)); } - # in other case it only references a simple type - else { - type = requiredOrNot (types.listOf (mapType property.items)); - } + else if property.type == "object" && hasAttr "additionalProperties" property + then + # if it is a reference to simple type + if ( + hasAttr "$ref" property.additionalProperties && + hasTypeMapping swagger.definitions.${refDefinition property.additionalProperties} + ) then { + type = requiredOrNot (types.attrsOf (mapType swagger.definitions.${refDefinition property.additionalProperties})); + } - else if property.type == "object" && hasAttr "additionalProperties" property - then - # if it is a reference to simple type - if ( - hasAttr "$ref" property.additionalProperties && - hasTypeMapping swagger.definitions.${refDefinition property.additionalProperties} - ) then { - type = requiredOrNot (types.attrsOf (mapType swagger.definitions.${refDefinition property.additionalProperties})); - } + else if hasAttr "$ref" property.additionalProperties + then { + type = requiredOrNot types.attrs; + } - else if hasAttr "$ref" property.additionalProperties - then { - type = requiredOrNot types.attrs; - } + # if is an array + else if property.additionalProperties.type == "array" + then { + type = requiredOrNot (types.loaOf (mapType property.additionalProperties.items)); + } - # if is an array - else if property.additionalProperties.type == "array" - then { - type = requiredOrNot (types.loaOf (mapType property.additionalProperties.items)); - } + else { + type = requiredOrNot (types.attrsOf (mapType property.additionalProperties)); + } - else { - type = requiredOrNot (types.attrsOf (mapType property.additionalProperties)); - } + # just a simple property + else { + type = requiredOrNot (mapType property); + }; + in + mkOption ({ + description = property.description or ""; + } // optionProperties) + ) + definition.properties; + config = + let + optionalProps = filterAttrs + (propName: property: + !(elem propName (definition.required or [ ])) + ) + definition.properties; + in + mapAttrs (name: property: mkOverride 1002 null) optionalProps; + } + ) + swagger.definitions); - # just a simple property - else { - type = requiredOrNot (mapType property); - }; - in mkOption ({ - description = property.description or ""; - } // optionProperties) - ) definition.properties; - config = - let - optionalProps = filterAttrs (propName: property: - !(elem propName (definition.required or [])) - ) definition.properties; - in mapAttrs (name: property: mkOverride 1002 null) optionalProps; - } - ) swagger.definitions); - - genResources = swagger: (mapAttrsToList (name: property: rec { - splittedType = splitString "." (removePrefix "me.snowdrop.istio.api." property.javaType); - group = (concatStringsSep "." (take ((length splittedType) - 2) splittedType)) + ".istio.io"; - kind = removeSuffix "Spec" (last splittedType); - version = last (take ((length splittedType) - 1) splittedType); - ref = removePrefix "#/definitions/" property."$ref"; - }) - (filterAttrs (name: property: - (hasPrefix "me.snowdrop.istio.api" property.javaType) && - hasSuffix "Spec" property.javaType - ) swagger.properties)) ++ (mapAttrsToList (name: property: rec { - splittedType = splitString "." (removePrefix "me.snowdrop.istio.mixer." property.javaType); - group = "config.istio.io"; - version = "v1alpha2"; - kind = head (tail splittedType); - ref = removePrefix "#/definitions/" property."$ref"; - }) (filterAttrs (name: property: - (hasPrefix "me.snowdrop.istio.mixer" property.javaType) && - hasSuffix "Spec" property.javaType - ) swagger.properties)); + genResources = swagger: (mapAttrsToList + (name: property: rec { + splittedType = splitString "." (removePrefix "me.snowdrop.istio.api." property.javaType); + group = (concatStringsSep "." (take ((length splittedType) - 2) splittedType)) + ".istio.io"; + kind = removeSuffix "Spec" (last splittedType); + version = last (take ((length splittedType) - 1) splittedType); + ref = removePrefix "#/definitions/" property."$ref"; + }) + (filterAttrs + (name: property: + (hasPrefix "me.snowdrop.istio.api" property.javaType) && + hasSuffix "Spec" property.javaType + ) + swagger.properties)) ++ (mapAttrsToList + (name: property: rec { + splittedType = splitString "." (removePrefix "me.snowdrop.istio.mixer." property.javaType); + group = "config.istio.io"; + version = "v1alpha2"; + kind = head (tail splittedType); + ref = removePrefix "#/definitions/" property."$ref"; + }) + (filterAttrs + (name: property: + (hasPrefix "me.snowdrop.istio.mixer" property.javaType) && + hasSuffix "Spec" property.javaType + ) + swagger.properties)); swagger = fetchSpecs spec; definitions = genDefinitions swagger; -in pkgs.writeText "gen.nix" -"# This file was generated with kubenix k8s generator, do not edit -{lib, config, ... }: - -with lib; - -let - types = lib.types // rec { - str = mkOptionType { - name = \"str\"; - description = \"string\"; - check = isString; - merge = mergeEqualOption; +in +pkgs.writeText "gen.nix" '' + # This file was generated with kubenix k8s generator, do not edit + {lib, config, ... }: + + with lib; + + let + types = lib.types // rec { + str = mkOptionType { + name = \"str\"; + description = \"string\"; + check = isString; + merge = mergeEqualOption; + }; + + # Either value of type `finalType` or `coercedType`, the latter is + # converted to `finalType` using `coerceFunc`. + coercedTo = coercedType: coerceFunc: finalType: + mkOptionType rec { + name = \"coercedTo\"; + description = \"\${finalType.description} or \${coercedType.description}\"; + check = x: finalType.check x || coercedType.check x; + merge = loc: defs: + let + coerceVal = val: + if finalType.check val then val + else let + coerced = coerceFunc val; + in assert finalType.check coerced; coerced; + + in finalType.merge loc (map (def: def // { value = coerceVal def.value; }) defs); + getSubOptions = finalType.getSubOptions; + getSubModules = finalType.getSubModules; + substSubModules = m: coercedTo coercedType coerceFunc (finalType.substSubModules m); + typeMerge = t1: t2: null; + functor = (defaultFunctor name) // { wrapped = finalType; }; + }; }; - - # Either value of type `finalType` or `coercedType`, the latter is - # converted to `finalType` using `coerceFunc`. - coercedTo = coercedType: coerceFunc: finalType: - mkOptionType rec { - name = \"coercedTo\"; - description = \"\${finalType.description} or \${coercedType.description}\"; - check = x: finalType.check x || coercedType.check x; - merge = loc: defs: - let - coerceVal = val: - if finalType.check val then val - else let - coerced = coerceFunc val; - in assert finalType.check coerced; coerced; - - in finalType.merge loc (map (def: def // { value = coerceVal def.value; }) defs); - getSubOptions = finalType.getSubOptions; - getSubModules = finalType.getSubModules; - substSubModules = m: coercedTo coercedType coerceFunc (finalType.substSubModules m); - typeMerge = t1: t2: null; - functor = (defaultFunctor name) // { wrapped = finalType; }; + + mkOptionDefault = mkOverride 1001; + + extraOptions = { + kubenix = {}; }; - }; - - mkOptionDefault = mkOverride 1001; - - extraOptions = { - kubenix = {}; - }; - - mergeValuesByKey = mergeKey: values: - listToAttrs (map - (value: nameValuePair ( - if isAttrs value.\${mergeKey} - then toString value.\${mergeKey}.content - else (toString value.\${mergeKey}) - ) value) - values); - - submoduleOf = ref: types.submodule ({name, ...}: { - options = definitions.\"\${ref}\".options; - config = definitions.\"\${ref}\".config; - }); - - submoduleWithMergeOf = ref: mergeKey: types.submodule ({name, ...}: let - convertName = name: - if definitions.\"\${ref}\".options.\${mergeKey}.type == types.int - then toInt name - else name; - in { - options = definitions.\"\${ref}\".options; - config = definitions.\"\${ref}\".config // { - \${mergeKey} = mkOverride 1002 (convertName name); - }; - }); - - submoduleForDefinition = ref: resource: kind: group: version: - types.submodule ({name, ...}: { - options = definitions.\"\${ref}\".options // extraOptions; - config = mkMerge ([ - definitions.\"\${ref}\".config - { - kind = mkOptionDefault kind; - apiVersion = mkOptionDefault version; - - # metdata.name cannot use option default, due deep config - metadata.name = mkOptionDefault name; - } - ] ++ (config.defaults.\${resource} or []) - ++ (config.defaults.all or [])); + + mergeValuesByKey = mergeKey: values: + listToAttrs (map + (value: nameValuePair ( + if isAttrs value.\${mergeKey} + then toString value.\${mergeKey}.content + else (toString value.\${mergeKey}) + ) value) + values); + + submoduleOf = ref: types.submodule ({name, ...}: { + options = definitions.\"\${ref}\".options; + config = definitions.\"\${ref}\".config; }); - - coerceAttrsOfSubmodulesToListByKey = ref: mergeKey: (types.coercedTo - (types.listOf (submoduleOf ref)) - (mergeValuesByKey mergeKey) - (types.attrsOf (submoduleWithMergeOf ref mergeKey)) - ); - - definitions = { - ${concatStrings (mapAttrsToList (name: value: " - \"${name}\" = {${optionalString (hasAttr "options" value) " - options = {${concatStrings (mapAttrsToList (name: value: " - \"${name}\" = ${value}; - ") value.options)}}; - "}${optionalString (hasAttr "config" value) " - config = {${concatStrings (mapAttrsToList (name: value: " - \"${name}\" = ${value}; - ") value.config)}}; - "}}; - ") definitions)} - } // (import ./overrides.nix {inheirt definitions lib;})); -in { - kubernetes.customResources = [ - ${concatMapStrings (resource: ''{ - group = "${resource.group}"; - version = "${resource.version}"; - kind = "${resource.kind}"; - description = ""; - module = definitions."${resource.ref}"; - }'') (genResources swagger)} - ]; -} -" + + submoduleWithMergeOf = ref: mergeKey: types.submodule ({name, ...}: let + convertName = name: + if definitions.\"\${ref}\".options.\${mergeKey}.type == types.int + then toInt name + else name; + in { + options = definitions.\"\${ref}\".options; + config = definitions.\"\${ref}\".config // { + \${mergeKey} = mkOverride 1002 (convertName name); + }; + }); + + submoduleForDefinition = ref: resource: kind: group: version: + types.submodule ({name, ...}: { + options = definitions.\"\${ref}\".options // extraOptions; + config = mkMerge ([ + definitions.\"\${ref}\".config + { + kind = mkOptionDefault kind; + apiVersion = mkOptionDefault version; + + # metdata.name cannot use option default, due deep config + metadata.name = mkOptionDefault name; + } + ] ++ (config.defaults.\${resource} or []) + ++ (config.defaults.all or [])); + }); + + coerceAttrsOfSubmodulesToListByKey = ref: mergeKey: (types.coercedTo + (types.listOf (submoduleOf ref)) + (mergeValuesByKey mergeKey) + (types.attrsOf (submoduleWithMergeOf ref mergeKey)) + ); + + definitions = { + ${concatStrings (mapAttrsToList + (name: value: " + \"${name}\" = {${optionalString (hasAttr "options" value) " + options = {${concatStrings (mapAttrsToList + (name: value: " + \"${name}\" = ${value}; + ") + value.options)}}; + "}${optionalString (hasAttr "config" value) " + config = {${concatStrings (mapAttrsToList + (name: value: " + \"${name}\" = ${value}; + ") + value.config)}}; + "}}; + ") + definitions)} + } // (import ./overrides.nix {inheirt definitions lib;})); + in { + kubernetes.customResources = [ + ${concatMapStrings + (resource: ''{ + group = "${resource.group}"; + version = "${resource.version}"; + kind = "${resource.kind}"; + description = ""; + module = definitions."${resource.ref}"; + }'') + (genResources swagger)} + ]; + } +'' diff --git a/generators/k8s/default.nix b/generators/k8s/default.nix index d686124..74b0f65 100644 --- a/generators/k8s/default.nix +++ b/generators/k8s/default.nix @@ -1,18 +1,21 @@ { name ? "k8s" -, pkgs ? import {} +, pkgs ? import { } , lib ? pkgs.lib , spec ? ./specs/1.21/swagger.json -, ... }: +, ... +}: with lib; - let gen = rec { - mkMerge = values: ''mkMerge [${concatMapStrings (value: " + mkMerge = values: ''mkMerge [${concatMapStrings +(value: " ${value} - ") values}]''; + ") +values}]''; - toNixString = value: if isAttrs value || isList value + toNixString = value: + if isAttrs value || isList value then builtins.toJSON value else if isString value then ''"${value}"'' @@ -22,19 +25,19 @@ let removeEmptyLines = str: concatStringsSep "\n" (filter (l: (builtins.match "( |)+" l) == null) (splitString "\n" str)); - mkOption = { - description ? null, - type ? null, - default ? null, - apply ? null - }: removeEmptyLines ''mkOption { + mkOption = + { description ? null + , type ? null + , default ? null + , apply ? null + }: removeEmptyLines ''mkOption { ${optionalString (description != null) "description = ${builtins.toJSON description};"} ${optionalString (type != null) ''type = ${type};''} ${optionalString (default != null) ''default = ${toNixString default};''} ${optionalString (apply != null) ''apply = ${apply};''} }''; - mkOverride = priority: value: "mkOverride ${toString priority} ${toNixString value}"; + mkOverride = priority: value: "mkOverride ${toString priority} ${toNixString value}"; types = { unspecified = "types.unspecified"; @@ -53,7 +56,7 @@ let hasTypeMapping = def: hasAttr "type" def && - elem def.type ["string" "integer" "boolean"]; + elem def.type [ "string" "integer" "boolean" ]; mergeValuesByKey = mergeKey: ''(mergeValuesByKey "${mergeKey}")''; @@ -83,185 +86,220 @@ let refType = attr: head (tail (tail (splitString "/" attr."$ref"))); - compareVersions = ver1: ver2: let - getVersion = v: substring 1 10 v; - splitVersion = v: builtins.splitVersion (getVersion v); - isAlpha = v: elem "alpha" (splitVersion v); - patchVersion = v: - if isAlpha v then "" - else if length (splitVersion v) == 1 then "${getVersion v}prod" - else getVersion v; + compareVersions = ver1: ver2: + let + getVersion = v: substring 1 10 v; + splitVersion = v: builtins.splitVersion (getVersion v); + isAlpha = v: elem "alpha" (splitVersion v); + patchVersion = v: + if isAlpha v then "" + else if length (splitVersion v) == 1 then "${getVersion v}prod" + else getVersion v; - v1 = patchVersion ver1; - v2 = patchVersion ver2; - in builtins.compareVersions v1 v2; + v1 = patchVersion ver1; + v2 = patchVersion ver2; + in + builtins.compareVersions v1 v2; - fixJSON = content: replaceStrings ["\\u"] ["u"] content; + fixJSON = content: replaceStrings [ "\\u" ] [ "u" ] content; fetchSpecs = path: builtins.fromJSON (fixJSON (builtins.readFile path)); - genDefinitions = swagger: with gen; mapAttrs (name: definition: - # if $ref is in definition it means it's an alias of other definition - if hasAttr "$ref" definition - then definitions."${refDefinition definition}" + genDefinitions = swagger: with gen; mapAttrs + (name: definition: + # if $ref is in definition it means it's an alias of other definition + if hasAttr "$ref" definition + then definitions."${refDefinition definition}" - else if !(hasAttr "properties" definition) - then {} + else if !(hasAttr "properties" definition) + then { } - # in other case it's an actual definition - else { - options = mapAttrs (propName: property: - let - isRequired = elem propName (definition.required or []); - requiredOrNot = type: if isRequired then type else types.nullOr type; - optionProperties = + # in other case it's an actual definition + else { + options = mapAttrs + (propName: property: + let + isRequired = elem propName (definition.required or [ ]); + requiredOrNot = type: if isRequired then type else types.nullOr type; + optionProperties = - # if $ref is in property it references other definition, - # but if other definition does not have properties, then just take it's type - if hasAttr "$ref" property then - if hasTypeMapping swagger.definitions.${refDefinition property} then { - type = requiredOrNot (mapType swagger.definitions.${refDefinition property}); - } - else { - type = requiredOrNot (submoduleOf definitions (refDefinition property)); - } - - # if property has an array type - else if property.type == "array" then - - # if reference is in items it can reference other type of another - # definition - if hasAttr "$ref" property.items then - - # if it is a reference to simple type - if hasTypeMapping swagger.definitions.${refDefinition property.items} - then { - type = requiredOrNot (types.listOf (mapType swagger.definitions.${refDefinition property.items}.type)); - } - - # if a reference is to complex type - else - # if x-kubernetes-patch-merge-key is set then make it an - # attribute set of submodules - if hasAttr "x-kubernetes-patch-merge-key" property - then let - mergeKey = property."x-kubernetes-patch-merge-key"; - in { - type = requiredOrNot (coerceAttrsOfSubmodulesToListByKey (refDefinition property.items) mergeKey); - apply = attrsToList; + # if $ref is in property it references other definition, + # but if other definition does not have properties, then just take it's type + if hasAttr "$ref" property then + if hasTypeMapping swagger.definitions.${refDefinition property} then { + type = requiredOrNot (mapType swagger.definitions.${refDefinition property}); } - - # in other case it's a simple list else { - type = requiredOrNot (types.listOf (submoduleOf definitions (refDefinition property.items))); + type = requiredOrNot (submoduleOf definitions (refDefinition property)); } - # in other case it only references a simple type - else { - type = requiredOrNot (types.listOf (mapType property.items)); - } + # if property has an array type + else if property.type == "array" then - else if property.type == "object" && hasAttr "additionalProperties" property - then - # if it is a reference to simple type - if ( - hasAttr "$ref" property.additionalProperties && - hasTypeMapping swagger.definitions.${refDefinition property.additionalProperties} - ) then { - type = requiredOrNot (types.attrsOf (mapType swagger.definitions.${refDefinition property.additionalProperties})); - } + # if reference is in items it can reference other type of another + # definition + if hasAttr "$ref" property.items then - else if hasAttr "$ref" property.additionalProperties - then { - type = requiredOrNot types.attrs; - } + # if it is a reference to simple type + if hasTypeMapping swagger.definitions.${refDefinition property.items} + then { + type = requiredOrNot (types.listOf (mapType swagger.definitions.${refDefinition property.items}.type)); + } - # if is an array - else if property.additionalProperties.type == "array" - then { - type = requiredOrNot (types.loaOf (mapType property.additionalProperties.items)); - } + # if a reference is to complex type + else + # if x-kubernetes-patch-merge-key is set then make it an + # attribute set of submodules + if hasAttr "x-kubernetes-patch-merge-key" property + then + let + mergeKey = property."x-kubernetes-patch-merge-key"; + in + { + type = requiredOrNot (coerceAttrsOfSubmodulesToListByKey (refDefinition property.items) mergeKey); + apply = attrsToList; + } - else { - type = requiredOrNot (types.attrsOf (mapType property.additionalProperties)); - } + # in other case it's a simple list + else { + type = requiredOrNot (types.listOf (submoduleOf definitions (refDefinition property.items))); + } - # just a simple property - else { - type = requiredOrNot (mapType property); - }; - in mkOption ({ - description = property.description or ""; - } // optionProperties) - ) definition.properties; - config = - let - optionalProps = filterAttrs (propName: property: - !(elem propName (definition.required or [])) - ) definition.properties; - in mapAttrs (name: property: mkOverride 1002 null) optionalProps; - } - ) swagger.definitions; + # in other case it only references a simple type + else { + type = requiredOrNot (types.listOf (mapType property.items)); + } - mapCharPairs = f: s1: s2: concatStrings (imap0 (i: c1: - f i c1 (if i >= stringLength s2 then "" else elemAt (stringToCharacters s2) i) - ) (stringToCharacters s1)); + else if property.type == "object" && hasAttr "additionalProperties" property + then + # if it is a reference to simple type + if ( + hasAttr "$ref" property.additionalProperties && + hasTypeMapping swagger.definitions.${refDefinition property.additionalProperties} + ) then { + type = requiredOrNot (types.attrsOf (mapType swagger.definitions.${refDefinition property.additionalProperties})); + } + + else if hasAttr "$ref" property.additionalProperties + then { + type = requiredOrNot types.attrs; + } + + # if is an array + else if property.additionalProperties.type == "array" + then { + type = requiredOrNot (types.loaOf (mapType property.additionalProperties.items)); + } + + else { + type = requiredOrNot (types.attrsOf (mapType property.additionalProperties)); + } + + # just a simple property + else { + type = requiredOrNot (mapType property); + }; + in + mkOption ({ + description = property.description or ""; + } // optionProperties) + ) + definition.properties; + config = + let + optionalProps = filterAttrs + (propName: property: + !(elem propName (definition.required or [ ])) + ) + definition.properties; + in + mapAttrs (name: property: mkOverride 1002 null) optionalProps; + } + ) + swagger.definitions; + + mapCharPairs = f: s1: s2: concatStrings (imap0 + (i: c1: + f i c1 (if i >= stringLength s2 then "" else elemAt (stringToCharacters s2) i) + ) + (stringToCharacters s1)); getAttrName = resource: kind: - mapCharPairs (i: c1: c2: - if hasPrefix "API" kind && i == 0 then "A" - else if i == 0 then c1 - else if c2 == "" || (toLower c2) != c1 then c1 - else c2 - ) resource kind; + mapCharPairs + (i: c1: c2: + if hasPrefix "API" kind && i == 0 then "A" + else if i == 0 then c1 + else if c2 == "" || (toLower c2) != c1 then c1 + else c2 + ) + resource + kind; - genResourceTypes = swagger: mapAttrs' (name: path: let - ref = refType (head path.post.parameters).schema; - group' = path.post."x-kubernetes-group-version-kind".group; - version' = path.post."x-kubernetes-group-version-kind".version; - kind' = path.post."x-kubernetes-group-version-kind".kind; - name' = last (splitString "/" name); - attrName = getAttrName name' kind'; - in nameValuePair ref { - inherit ref attrName; + genResourceTypes = swagger: mapAttrs' + (name: path: + let + ref = refType (head path.post.parameters).schema; + group' = path.post."x-kubernetes-group-version-kind".group; + version' = path.post."x-kubernetes-group-version-kind".version; + kind' = path.post."x-kubernetes-group-version-kind".kind; + name' = last (splitString "/" name); + attrName = getAttrName name' kind'; + in + nameValuePair ref { + inherit ref attrName; - name = name'; - group = if group' == "" then "core" else group'; - version = version'; - kind = kind'; - description = swagger.definitions.${ref}.description; - defintion = refDefinition (head path.post.parameters).schema; - }) - (filterAttrs (name: path: - hasAttr "post" path && - path.post."x-kubernetes-action" == "post" - ) swagger.paths); + name = name'; + group = if group' == "" then "core" else group'; + version = version'; + kind = kind'; + description = swagger.definitions.${ref}.description; + defintion = refDefinition (head path.post.parameters).schema; + }) + (filterAttrs + (name: path: + hasAttr "post" path && + path.post."x-kubernetes-action" == "post" + ) + swagger.paths); swagger = fetchSpecs spec; definitions = genDefinitions swagger; resourceTypes = genResourceTypes swagger; - resourceTypesByKind = zipAttrs (mapAttrsToList (name: resourceType: { - ${resourceType.kind} = resourceType; - }) resourceTypes); + resourceTypesByKind = zipAttrs (mapAttrsToList + (name: resourceType: { + ${resourceType.kind} = resourceType; + }) + resourceTypes); - resourcesTypesByKindSortByVersion = mapAttrs (kind: resourceTypes: - reverseList (sort (r1: r2: - compareVersions r1.version r2.version > 0 - ) resourceTypes) - ) resourceTypesByKind; + resourcesTypesByKindSortByVersion = mapAttrs + (kind: resourceTypes: + reverseList (sort + (r1: r2: + compareVersions r1.version r2.version > 0 + ) + resourceTypes) + ) + resourceTypesByKind; latestResourceTypesByKind = mapAttrs (kind: resources: last resources) resourcesTypesByKindSortByVersion; genResourceOptions = resource: with gen; let - submoduleForDefinition' = definition: let - in submoduleForDefinition - definition.ref definition.name definition.kind definition.group definition.version; - in mkOption { + submoduleForDefinition' = definition: + let + in + submoduleForDefinition + definition.ref + definition.name + definition.kind + definition.group + definition.version; + in + mkOption { description = resource.description; type = types.attrsOf (submoduleForDefinition' resource); - default = {}; + default = { }; }; generated = '' @@ -415,7 +453,9 @@ let }; } ''; -in pkgs.runCommand "k8s-${name}-gen.nix" { +in +pkgs.runCommand "k8s-${name}-gen.nix" +{ buildInputs = [ pkgs.haskellPackages.nixfmt ]; } '' cp ${builtins.toFile "k8s-${name}-gen-raw.nix" generated} $out diff --git a/lib/docker.nix b/lib/docker.nix index c7ff120..e8ca74f 100644 --- a/lib/docker.nix +++ b/lib/docker.nix @@ -3,13 +3,15 @@ with lib; { - copyDockerImages = { images, dest, args ? "" }: - pkgs.writeScript "copy-docker-images.sh" (concatMapStrings (image: '' - #!${pkgs.runtimeShell} + copyDockerImages = { images, dest, args ? "" }: + pkgs.writeScript "copy-docker-images.sh" (concatMapStrings + (image: '' + #!${pkgs.runtimeShell} - set -e + set -e - echo "copying '${image.imageName}:${image.imageTag}' to '${dest}/${image.imageName}:${image.imageTag}'" - ${pkgs.skopeo}/bin/skopeo copy ${args} $@ docker-archive:${image} ${dest}/${image.imageName}:${image.imageTag} - '') images); + echo "copying '${image.imageName}:${image.imageTag}' to '${dest}/${image.imageName}:${image.imageTag}'" + ${pkgs.skopeo}/bin/skopeo copy ${args} $@ docker-archive:${image} ${dest}/${image.imageName}:${image.imageTag} + '') + images); } diff --git a/lib/extra.nix b/lib/extra.nix index 72cac9d..ec3f68a 100644 --- a/lib/extra.nix +++ b/lib/extra.nix @@ -21,31 +21,39 @@ rec { else mkOverride priority value; - loadYAML = path: importJSON (pkgs.runCommand "yaml-to-json" { - } "${pkgs.remarshal}/bin/remarshal -i ${path} -if yaml -of json > $out"); + loadYAML = path: importJSON (pkgs.runCommand "yaml-to-json" + { } "${pkgs.remarshal}/bin/remarshal -i ${path} -if yaml -of json > $out"); - toYAML = config: builtins.readFile (pkgs.runCommand "to-yaml" { - buildInputs = [pkgs.remarshal]; - } '' + toYAML = config: builtins.readFile (pkgs.runCommand "to-yaml" + { + buildInputs = [ pkgs.remarshal ]; + } '' remarshal -i ${pkgs.writeText "to-json" (builtins.toJSON config)} -if json -of yaml > $out ''); - toMultiDocumentYaml = name: documents: pkgs.runCommand name { - buildInputs = [ pkgs.remarshal ]; - } (concatMapStringsSep "\necho --- >> $out\n" (d: - "remarshal -i ${builtins.toFile "doc" (builtins.toJSON d)} -if json -of yaml >> $out" - ) documents); + toMultiDocumentYaml = name: documents: pkgs.runCommand name + { + buildInputs = [ pkgs.remarshal ]; + } + (concatMapStringsSep "\necho --- >> $out\n" + (d: + "remarshal -i ${builtins.toFile "doc" (builtins.toJSON d)} -if json -of yaml >> $out" + ) + documents); toBase64 = value: builtins.readFile - (pkgs.runCommand "value-to-b64" {} "echo -n '${value}' | ${pkgs.coreutils}/bin/base64 -w0 > $out"); + (pkgs.runCommand "value-to-b64" { } "echo -n '${value}' | ${pkgs.coreutils}/bin/base64 -w0 > $out"); exp = base: exp: foldr (value: acc: acc * base) 1 (range 1 exp); - octalToDecimal = value: (foldr (char: acc: { - i = acc.i + 1; - value = acc.value + (toInt char) * (exp 8 acc.i); - }) {i = 0; value = 0;} (stringToCharacters value)).value; + octalToDecimal = value: (foldr + (char: acc: { + i = acc.i + 1; + value = acc.value + (toInt char) * (exp 8 acc.i); + }) + { i = 0; value = 0; } + (stringToCharacters value)).value; submoduleWithSpecialArgs = opts: specialArgs: let @@ -58,13 +66,15 @@ rec { 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 { + 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; + { + 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 @@ -87,16 +97,19 @@ rec { 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: []; + payload = [ ]; + binOp = lhs: rhs: [ ]; }; }; - coerceListOfSubmodulesToAttrs = submodule: keyFn: let + coerceListOfSubmodulesToAttrs = submodule: keyFn: + let mergeValuesByFn = keyFn: values: - listToAttrs (map (value: - nameValuePair (toString (keyFn value)) value - ) values); + listToAttrs (map + (value: + nameValuePair (toString (keyFn value)) value + ) + values); # Either value of type `finalType` or `coercedType`, the latter is # converted to `finalType` using `coerceFunc`. @@ -113,14 +126,16 @@ rec { else let coerced = coerceFunc val; in assert finalType.check coerced; coerced; - in finalType.merge loc (map (def: def // { value = coerceVal def.value; }) defs); + in + finalType.merge loc (map (def: def // { value = coerceVal def.value; }) defs); getSubOptions = finalType.getSubOptions; getSubModules = finalType.getSubModules; substSubModules = m: coercedTo coercedType coerceFunc (finalType.substSubModules m); typeMerge = t1: t2: null; functor = (defaultFunctor name) // { wrapped = finalType; }; }; - in coercedTo + in + coercedTo (types.listOf (types.submodule submodule)) (mergeValuesByFn keyFn) (types.attrsOf (types.submodule submodule)); diff --git a/lib/helm/chart2json.nix b/lib/helm/chart2json.nix index 0e6212e..6b9b8ae 100644 --- a/lib/helm/chart2json.nix +++ b/lib/helm/chart2json.nix @@ -13,19 +13,22 @@ with lib; , namespace ? null # values to pass to chart -, values ? {} +, values ? { } # kubernetes version to template chart for -, kubeVersion ? null }: let +, kubeVersion ? null +}: +let valuesJsonFile = builtins.toFile "${name}-values.json" (builtins.toJSON values); -in stdenvNoCC.mkDerivation { +in +stdenvNoCC.mkDerivation { name = "${name}.json"; buildCommand = '' # template helm file and write resources to yaml helm template "${name}" \ ${optionalString (kubeVersion != null) "--api-versions ${kubeVersion}"} \ ${optionalString (namespace != null) "--namespace ${namespace}"} \ - ${optionalString (values != {}) "-f ${valuesJsonFile}"} \ + ${optionalString (values != { }) "-f ${valuesJsonFile}"} \ ${chart} >resources.yaml # split multy yaml file into multiple files diff --git a/lib/helm/fetchhelm.nix b/lib/helm/fetchhelm.nix index a92ecef..89fb546 100644 --- a/lib/helm/fetchhelm.nix +++ b/lib/helm/fetchhelm.nix @@ -1,9 +1,9 @@ { stdenvNoCC, lib, kubernetes-helm, cacert }: - let - cleanName = name: lib.replaceStrings ["/"] ["-"] name; + cleanName = name: lib.replaceStrings [ "/" ] [ "-" ] name; -in { +in +{ # name of the chart chart @@ -13,20 +13,21 @@ in { # version of the chart , version ? null -# chart hash + # chart hash , sha256 -# whether to extract chart + # whether to extract chart , untar ? true -# use custom charts repo + # use custom charts repo , repo ? null -# pass --verify to helm chart + # pass --verify to helm chart , verify ? false -# pass --devel to helm chart -, devel ? false }: stdenvNoCC.mkDerivation { + # pass --devel to helm chart +, devel ? false +}: stdenvNoCC.mkDerivation { name = "${cleanName chart}-${if version == null then "dev" else version}"; buildCommand = '' diff --git a/lib/helm/test.nix b/lib/helm/test.nix index 84c7754..e763bd7 100644 --- a/lib/helm/test.nix +++ b/lib/helm/test.nix @@ -1,9 +1,9 @@ -{ pkgs ? import {} }: - +{ pkgs ? import { } }: let - fetchhelm = pkgs.callPackage ./fetchhelm.nix { }; - chart2json = pkgs.callPackage ./chart2json.nix { }; -in rec { + fetchhelm = pkgs.callPackage ./fetchhelm.nix { }; + chart2json = pkgs.callPackage ./chart2json.nix { }; +in +rec { postgresql-chart = fetchhelm { chart = "stable/postgresql"; version = "0.18.1"; diff --git a/lib/k8s.nix b/lib/k8s.nix index 0cbffa3..306493f 100644 --- a/lib/k8s.nix +++ b/lib/k8s.nix @@ -4,7 +4,7 @@ with lib; rec { # TODO: refactor with mkOptionType - mkSecretOption = {description ? "", default ? {}, allowNull ? true}: mkOption { + mkSecretOption = { description ? "", default ? { }, allowNull ? true }: mkOption { inherit description; type = (if allowNull then types.nullOr else id) (types.submodule { options = { @@ -24,7 +24,7 @@ rec { })); }; }); - default = if default == null then null else {}; + default = if default == null then null else { }; }; secretToEnv = value: { @@ -34,7 +34,7 @@ rec { }; # Creates kubernetes list from a list of kubernetes objects - mkList = { items, labels ? {} }: { + mkList = { items, labels ? { } }: { kind = "List"; apiVersion = "v1"; @@ -42,19 +42,23 @@ rec { }; # Creates hashed kubernetes list from a list of kubernetes objects - mkHashedList = { items, labels ? {} }: let - hash = builtins.hashString "sha1" (builtins.toJSON items); + mkHashedList = { items, labels ? { } }: + let + hash = builtins.hashString "sha1" (builtins.toJSON items); - labeledItems = map (item: recursiveUpdate item { - metadata.labels."kubenix/hash" = hash; - }) items; + labeledItems = map + (item: recursiveUpdate item { + metadata.labels."kubenix/hash" = hash; + }) + items; - in mkList { - items = labeledItems; - labels = { - "kubenix/hash" = hash; - } // labels; - }; + in + mkList { + items = labeledItems; + labels = { + "kubenix/hash" = hash; + } // labels; + }; toBase64 = lib.toBase64; octalToDecimal = lib.octalToDecimal; diff --git a/modules/base.nix b/modules/base.nix index 7f61551..455aac0 100644 --- a/modules/base.nix +++ b/modules/base.nix @@ -13,27 +13,27 @@ with lib; _m.features = mkOption { description = "List of features exposed by module"; type = types.listOf types.str; - default = []; + default = [ ]; }; _m.propagate = mkOption { description = "Module propagation options"; - type = types.listOf (types.submodule ({config, ...}: { + type = types.listOf (types.submodule ({ config, ... }: { options = { features = mkOption { description = "List of features that submodule has to have to propagate module"; type = types.listOf types.str; - default = []; + default = [ ]; }; module = mkOption { description = "Module to propagate"; type = types.unspecified; - default = {}; + default = { }; }; }; })); - default = []; + default = [ ]; }; }; } diff --git a/modules/docker.nix b/modules/docker.nix index 7896508..e62c22d 100644 --- a/modules/docker.nix +++ b/modules/docker.nix @@ -1,10 +1,10 @@ { config, lib, pkgs, docker, ... }: with lib; - let cfg = config.docker; -in { +in +{ imports = [ ./base.nix ]; options.docker = { @@ -52,13 +52,13 @@ in { }; }; })); - default = {}; + default = { }; }; export = mkOption { description = "List of images to export"; type = types.listOf types.package; - default = []; + default = [ ]; }; copyScript = mkOption { @@ -73,7 +73,7 @@ in { config = { # define docker feature - _m.features = ["docker"]; + _m.features = [ "docker" ]; # propagate docker options if docker feature is enabled _m.propagate = [{ diff --git a/modules/helm.nix b/modules/helm.nix index 0e51a81..4eac6c4 100644 --- a/modules/helm.nix +++ b/modules/helm.nix @@ -4,7 +4,6 @@ { config, lib, pkgs, helm, ... }: with lib; - let cfg = config.kubernetes.helm; @@ -14,17 +13,20 @@ let name = "recursive-attrs"; description = "recursive attribute set"; check = isAttrs; - merge = loc: foldl' (res: def: recursiveUpdate res def.value) {}; + merge = loc: foldl' (res: def: recursiveUpdate res def.value) { }; }; - parseApiVersion = apiVersion: let - splitted = splitString "/" apiVersion; - in { - group = if length splitted == 1 then "core" else head splitted; - version = last splitted; - }; + parseApiVersion = apiVersion: + let + splitted = splitString "/" apiVersion; + in + { + group = if length splitted == 1 then "core" else head splitted; + version = last splitted; + }; -in { +in +{ imports = [ ./k8s.nix ]; options.kubernetes.helm = { @@ -52,7 +54,7 @@ in { values = mkOption { description = "Values to pass to chart"; type = recursiveAttrs; - default = {}; + default = { }; }; kubeVersion = mkOption { @@ -64,7 +66,7 @@ in { overrides = mkOption { description = "Overrides to apply to all chart resources"; type = types.listOf types.unspecified; - default = []; + default = [ ]; }; overrideNamespace = mkOption { @@ -76,7 +78,7 @@ in { objects = mkOption { description = "Generated kubernetes objects"; type = types.listOf types.attrs; - default = []; + default = [ ]; }; }; @@ -88,7 +90,7 @@ in { inherit (config) chart name namespace values kubeVersion; }); })); - default = {}; + default = { }; }; }; @@ -96,15 +98,21 @@ in { # expose helm helper methods as module argument _module.args.helm = import ../lib/helm { inherit pkgs; }; - kubernetes.api.resources = 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)); + kubernetes.api.resources = 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)); }; } diff --git a/modules/istio-overrides.nix b/modules/istio-overrides.nix index 97587d4..77e77d7 100644 --- a/modules/istio-overrides.nix +++ b/modules/istio-overrides.nix @@ -3,11 +3,12 @@ with lib; { - "istio_networking_v1alpha3_StringMatch" = recursiveUpdate (recursiveUpdate - definitions."istio_networking_v1alpha3_StringMatch_Exact" - definitions."istio_networking_v1alpha3_StringMatch_Prefix" - ) - definitions."istio_networking_v1alpha3_StringMatch_Regex"; + "istio_networking_v1alpha3_StringMatch" = recursiveUpdate + (recursiveUpdate + definitions."istio_networking_v1alpha3_StringMatch_Exact" + definitions."istio_networking_v1alpha3_StringMatch_Prefix" + ) + definitions."istio_networking_v1alpha3_StringMatch_Regex"; "istio_networking_v1alpha3_PortSelector" = recursiveUpdate definitions."istio_networking_v1alpha3_PortSelector_Name" diff --git a/modules/istio.nix b/modules/istio.nix index b019440..da10795 100644 --- a/modules/istio.nix +++ b/modules/istio.nix @@ -1,8 +1,7 @@ # This file was generated with kubenix k8s generator, do not edit -{lib, config, ... }: +{ lib, config, ... }: with lib; - let types = lib.types // rec { str = mkOptionType { @@ -15,61 +14,68 @@ let # Either value of type `finalType` or `coercedType`, the latter is # converted to `finalType` using `coerceFunc`. coercedTo = coercedType: coerceFunc: finalType: - mkOptionType rec { - name = "coercedTo"; - description = "${finalType.description} or ${coercedType.description}"; - check = x: finalType.check x || coercedType.check x; - merge = loc: defs: - let - coerceVal = val: - if finalType.check val then val - else let - coerced = coerceFunc val; - in assert finalType.check coerced; coerced; + mkOptionType rec { + name = "coercedTo"; + description = "${finalType.description} or ${coercedType.description}"; + check = x: finalType.check x || coercedType.check x; + merge = loc: defs: + let + coerceVal = val: + if finalType.check val then val + else + let + coerced = coerceFunc val; + in + assert finalType.check coerced; coerced; - in finalType.merge loc (map (def: def // { value = coerceVal def.value; }) defs); - getSubOptions = finalType.getSubOptions; - getSubModules = finalType.getSubModules; - substSubModules = m: coercedTo coercedType coerceFunc (finalType.substSubModules m); - typeMerge = t1: t2: null; - functor = (defaultFunctor name) // { wrapped = finalType; }; - }; + in + finalType.merge loc (map (def: def // { value = coerceVal def.value; }) defs); + getSubOptions = finalType.getSubOptions; + getSubModules = finalType.getSubModules; + substSubModules = m: coercedTo coercedType coerceFunc (finalType.substSubModules m); + typeMerge = t1: t2: null; + functor = (defaultFunctor name) // { wrapped = finalType; }; + }; }; mkOptionDefault = mkOverride 1001; extraOptions = { - kubenix = {}; + kubenix = { }; }; mergeValuesByKey = mergeKey: values: listToAttrs (map - (value: nameValuePair ( - if isAttrs value.${mergeKey} - then toString value.${mergeKey}.content - else (toString value.${mergeKey}) - ) value) - values); + (value: nameValuePair + ( + if isAttrs value.${mergeKey} + then toString value.${mergeKey}.content + else (toString value.${mergeKey}) + ) + value) + values); - submoduleOf = ref: types.submodule ({name, ...}: { + submoduleOf = ref: types.submodule ({ name, ... }: { options = definitions."${ref}".options; config = definitions."${ref}".config; }); - submoduleWithMergeOf = ref: mergeKey: types.submodule ({name, ...}: let - convertName = name: - if definitions."${ref}".options.${mergeKey}.type == types.int - then toInt name - else name; - in { - options = definitions."${ref}".options; - config = definitions."${ref}".config // { - ${mergeKey} = mkOverride 1002 (convertName name); - }; - }); + submoduleWithMergeOf = ref: mergeKey: types.submodule ({ name, ... }: + let + convertName = name: + if definitions."${ref}".options.${mergeKey}.type == types.int + then toInt name + else name; + in + { + options = definitions."${ref}".options; + config = definitions."${ref}".config // { + ${mergeKey} = mkOverride 1002 (convertName name); + }; + }); submoduleForDefinition = ref: resource: kind: group: version: - types.submodule ({name, ...}: { + types.submodule ({ name, ... }: { options = definitions."${ref}".options // extraOptions; config = mkMerge ([ definitions."${ref}".config @@ -80,8 +86,8 @@ let # metdata.name cannot use option default, due deep config metadata.name = mkOptionDefault name; } - ] ++ (config.defaults.${resource} or []) - ++ (config.defaults.all or [])); + ] ++ (config.defaults.${resource} or [ ]) + ++ (config.defaults.all or [ ])); }); coerceAttrsOfSubmodulesToListByKey = ref: mergeKey: (types.coercedTo @@ -2846,7 +2852,7 @@ let }; }; - "istio_mixer_v1_ReportResponse" = {}; + "istio_mixer_v1_ReportResponse" = { }; "istio_mixer_v1_RouteDirective" = { options = { @@ -4697,225 +4703,261 @@ let }; }; - } // (import ./istio-overrides.nix {inherit definitions lib;}); -in { + } // (import ./istio-overrides.nix { inherit definitions lib; }); +in +{ kubernetes.customResources = [ - { - group = "networking.istio.io"; - version = "v1alpha3"; - kind = "DestinationRule"; - description = ""; - module = definitions."istio_networking_v1alpha3_DestinationRule"; - }{ - group = "networking.istio.io"; - version = "v1alpha3"; - kind = "EnvoyFilter"; - description = ""; - module = definitions."istio_networking_v1alpha3_EnvoyFilter"; - }{ - group = "networking.istio.io"; - version = "v1alpha3"; - kind = "Gateway"; - description = ""; - module = definitions."istio_networking_v1alpha3_Gateway"; - }{ - group = "authentication.istio.io"; - version = "v1alpha1"; - kind = "Policy"; - description = ""; - module = definitions."istio_authentication_v1alpha1_Policy"; - }{ - group = "rbac.istio.io"; - version = "v1alpha1"; - kind = "RbacConfig"; - description = ""; - module = definitions."istio_rbac_v1alpha1_RbacConfig"; - }{ - group = "policy.istio.io"; - version = "v1beta1"; - kind = "Rule"; - description = ""; - module = definitions."istio_policy_v1beta1_Rule"; - }{ - group = "networking.istio.io"; - version = "v1alpha3"; - kind = "ServiceEntry"; - description = ""; - module = definitions."istio_networking_v1alpha3_ServiceEntry"; - }{ - group = "rbac.istio.io"; - version = "v1alpha1"; - kind = "ServiceRole"; - description = ""; - module = definitions."istio_rbac_v1alpha1_ServiceRole"; - }{ - group = "rbac.istio.io"; - version = "v1alpha1"; - kind = "ServiceRoleBinding"; - description = ""; - module = definitions."istio_rbac_v1alpha1_ServiceRoleBinding"; - }{ - group = "networking.istio.io"; - version = "v1alpha3"; - kind = "VirtualService"; - description = ""; - module = definitions."istio_networking_v1alpha3_VirtualService"; - }{ - group = "config.istio.io"; - version = "v1alpha2"; - kind = "apikey"; - description = ""; - module = definitions."istio_mixer_apikey_InstanceMsg"; - }{ - group = "config.istio.io"; - version = "v1alpha2"; - kind = "authorization"; - description = ""; - module = definitions."istio_mixer_authorization_InstanceMsg"; - }{ - group = "config.istio.io"; - version = "v1alpha2"; - kind = "bypass"; - description = ""; - module = definitions."istio_adapter_bypass_Params"; - }{ - group = "config.istio.io"; - version = "v1alpha2"; - kind = "checknothing"; - description = ""; - module = definitions."istio_mixer_checknothing_InstanceMsg"; - }{ - group = "config.istio.io"; - version = "v1alpha2"; - kind = "circonus"; - description = ""; - module = definitions."istio_adapter_circonus_Params"; - }{ - group = "config.istio.io"; - version = "v1alpha2"; - kind = "denier"; - description = ""; - module = definitions."istio_adapter_denier_Params"; - }{ - group = "config.istio.io"; - version = "v1alpha2"; - kind = "edge"; - description = ""; - module = definitions."istio_mixer_edge_InstanceMsg"; - }{ - group = "config.istio.io"; - version = "v1alpha2"; - kind = "fluentd"; - description = ""; - module = definitions."istio_adapter_fluentd_Params"; - }{ - group = "config.istio.io"; - version = "v1alpha2"; - kind = "kubernetesenv"; - description = ""; - module = definitions."istio_adapter_kubernetesenv_Params"; - }{ - group = "config.istio.io"; - version = "v1alpha2"; - kind = "listentry"; - description = ""; - module = definitions."istio_mixer_listentry_InstanceMsg"; - }{ - group = "config.istio.io"; - version = "v1alpha2"; - kind = "logentry"; - description = ""; - module = definitions."istio_mixer_logentry_InstanceMsg"; - }{ - group = "config.istio.io"; - version = "v1alpha2"; - kind = "memquota"; - description = ""; - module = definitions."istio_adapter_memquota_Params"; - }{ - group = "config.istio.io"; - version = "v1alpha2"; - kind = "metric"; - description = ""; - module = definitions."istio_mixer_metric_InstanceMsg"; - }{ - group = "config.istio.io"; - version = "v1alpha2"; - kind = "opa"; - description = ""; - module = definitions."istio_adapter_opa_Params"; - }{ - group = "config.istio.io"; - version = "v1alpha2"; - kind = "prometheus"; - description = ""; - module = definitions."istio_adapter_prometheus_Params"; - }{ - group = "config.istio.io"; - version = "v1alpha2"; - kind = "quota"; - description = ""; - module = definitions."istio_mixer_quota_InstanceMsg"; - }{ - group = "config.istio.io"; - version = "v1alpha2"; - kind = "rbac"; - description = ""; - module = definitions."istio_adapter_rbac_Params"; - }{ - group = "config.istio.io"; - version = "v1alpha2"; - kind = "redisquota"; - description = ""; - module = definitions."istio_adapter_redisquota_Params"; - }{ - group = "config.istio.io"; - version = "v1alpha2"; - kind = "reportnothing"; - description = ""; - module = definitions."istio_mixer_reportnothing_InstanceMsg"; - }{ - group = "config.istio.io"; - version = "v1alpha2"; - kind = "servicecontrol"; - description = ""; - module = definitions."istio_adapter_servicecontrol_Params"; - }{ - group = "config.istio.io"; - version = "v1alpha2"; - kind = "signalfx"; - description = ""; - module = definitions."istio_adapter_signalfx_Params"; - }{ - group = "config.istio.io"; - version = "v1alpha2"; - kind = "solarwinds"; - description = ""; - module = definitions."istio_adapter_solarwinds_Params"; - }{ - group = "config.istio.io"; - version = "v1alpha2"; - kind = "stackdriver"; - description = ""; - module = definitions."istio_adapter_stackdriver_Params"; - }{ - group = "config.istio.io"; - version = "v1alpha2"; - kind = "statsd"; - description = ""; - module = definitions."istio_adapter_statsd_Params"; - }{ - group = "config.istio.io"; - version = "v1alpha2"; - kind = "stdio"; - description = ""; - module = definitions."istio_adapter_stdio_Params"; - }{ - group = "config.istio.io"; - version = "v1alpha2"; - kind = "tracespan"; - description = ""; - module = definitions."istio_mixer_tracespan_InstanceMsg"; - } + { + group = "networking.istio.io"; + version = "v1alpha3"; + kind = "DestinationRule"; + description = ""; + module = definitions."istio_networking_v1alpha3_DestinationRule"; + } + { + group = "networking.istio.io"; + version = "v1alpha3"; + kind = "EnvoyFilter"; + description = ""; + module = definitions."istio_networking_v1alpha3_EnvoyFilter"; + } + { + group = "networking.istio.io"; + version = "v1alpha3"; + kind = "Gateway"; + description = ""; + module = definitions."istio_networking_v1alpha3_Gateway"; + } + { + group = "authentication.istio.io"; + version = "v1alpha1"; + kind = "Policy"; + description = ""; + module = definitions."istio_authentication_v1alpha1_Policy"; + } + { + group = "rbac.istio.io"; + version = "v1alpha1"; + kind = "RbacConfig"; + description = ""; + module = definitions."istio_rbac_v1alpha1_RbacConfig"; + } + { + group = "policy.istio.io"; + version = "v1beta1"; + kind = "Rule"; + description = ""; + module = definitions."istio_policy_v1beta1_Rule"; + } + { + group = "networking.istio.io"; + version = "v1alpha3"; + kind = "ServiceEntry"; + description = ""; + module = definitions."istio_networking_v1alpha3_ServiceEntry"; + } + { + group = "rbac.istio.io"; + version = "v1alpha1"; + kind = "ServiceRole"; + description = ""; + module = definitions."istio_rbac_v1alpha1_ServiceRole"; + } + { + group = "rbac.istio.io"; + version = "v1alpha1"; + kind = "ServiceRoleBinding"; + description = ""; + module = definitions."istio_rbac_v1alpha1_ServiceRoleBinding"; + } + { + group = "networking.istio.io"; + version = "v1alpha3"; + kind = "VirtualService"; + description = ""; + module = definitions."istio_networking_v1alpha3_VirtualService"; + } + { + group = "config.istio.io"; + version = "v1alpha2"; + kind = "apikey"; + description = ""; + module = definitions."istio_mixer_apikey_InstanceMsg"; + } + { + group = "config.istio.io"; + version = "v1alpha2"; + kind = "authorization"; + description = ""; + module = definitions."istio_mixer_authorization_InstanceMsg"; + } + { + group = "config.istio.io"; + version = "v1alpha2"; + kind = "bypass"; + description = ""; + module = definitions."istio_adapter_bypass_Params"; + } + { + group = "config.istio.io"; + version = "v1alpha2"; + kind = "checknothing"; + description = ""; + module = definitions."istio_mixer_checknothing_InstanceMsg"; + } + { + group = "config.istio.io"; + version = "v1alpha2"; + kind = "circonus"; + description = ""; + module = definitions."istio_adapter_circonus_Params"; + } + { + group = "config.istio.io"; + version = "v1alpha2"; + kind = "denier"; + description = ""; + module = definitions."istio_adapter_denier_Params"; + } + { + group = "config.istio.io"; + version = "v1alpha2"; + kind = "edge"; + description = ""; + module = definitions."istio_mixer_edge_InstanceMsg"; + } + { + group = "config.istio.io"; + version = "v1alpha2"; + kind = "fluentd"; + description = ""; + module = definitions."istio_adapter_fluentd_Params"; + } + { + group = "config.istio.io"; + version = "v1alpha2"; + kind = "kubernetesenv"; + description = ""; + module = definitions."istio_adapter_kubernetesenv_Params"; + } + { + group = "config.istio.io"; + version = "v1alpha2"; + kind = "listentry"; + description = ""; + module = definitions."istio_mixer_listentry_InstanceMsg"; + } + { + group = "config.istio.io"; + version = "v1alpha2"; + kind = "logentry"; + description = ""; + module = definitions."istio_mixer_logentry_InstanceMsg"; + } + { + group = "config.istio.io"; + version = "v1alpha2"; + kind = "memquota"; + description = ""; + module = definitions."istio_adapter_memquota_Params"; + } + { + group = "config.istio.io"; + version = "v1alpha2"; + kind = "metric"; + description = ""; + module = definitions."istio_mixer_metric_InstanceMsg"; + } + { + group = "config.istio.io"; + version = "v1alpha2"; + kind = "opa"; + description = ""; + module = definitions."istio_adapter_opa_Params"; + } + { + group = "config.istio.io"; + version = "v1alpha2"; + kind = "prometheus"; + description = ""; + module = definitions."istio_adapter_prometheus_Params"; + } + { + group = "config.istio.io"; + version = "v1alpha2"; + kind = "quota"; + description = ""; + module = definitions."istio_mixer_quota_InstanceMsg"; + } + { + group = "config.istio.io"; + version = "v1alpha2"; + kind = "rbac"; + description = ""; + module = definitions."istio_adapter_rbac_Params"; + } + { + group = "config.istio.io"; + version = "v1alpha2"; + kind = "redisquota"; + description = ""; + module = definitions."istio_adapter_redisquota_Params"; + } + { + group = "config.istio.io"; + version = "v1alpha2"; + kind = "reportnothing"; + description = ""; + module = definitions."istio_mixer_reportnothing_InstanceMsg"; + } + { + group = "config.istio.io"; + version = "v1alpha2"; + kind = "servicecontrol"; + description = ""; + module = definitions."istio_adapter_servicecontrol_Params"; + } + { + group = "config.istio.io"; + version = "v1alpha2"; + kind = "signalfx"; + description = ""; + module = definitions."istio_adapter_signalfx_Params"; + } + { + group = "config.istio.io"; + version = "v1alpha2"; + kind = "solarwinds"; + description = ""; + module = definitions."istio_adapter_solarwinds_Params"; + } + { + group = "config.istio.io"; + version = "v1alpha2"; + kind = "stackdriver"; + description = ""; + module = definitions."istio_adapter_stackdriver_Params"; + } + { + group = "config.istio.io"; + version = "v1alpha2"; + kind = "statsd"; + description = ""; + module = definitions."istio_adapter_statsd_Params"; + } + { + group = "config.istio.io"; + version = "v1alpha2"; + kind = "stdio"; + description = ""; + module = definitions."istio_adapter_stdio_Params"; + } + { + group = "config.istio.io"; + version = "v1alpha2"; + kind = "tracespan"; + description = ""; + module = definitions."istio_mixer_tracespan_InstanceMsg"; + } ]; } diff --git a/modules/k3s-airgap-images.nix b/modules/k3s-airgap-images.nix index ae8d250..bd33841 100644 --- a/modules/k3s-airgap-images.nix +++ b/modules/k3s-airgap-images.nix @@ -4,22 +4,24 @@ stdenv.mkDerivation rec { pname = "k3s-airgap-images"; version = k3s.version; - src = let - throwError = throw "Unsupported system ${stdenv.hostPlatform.system}"; - in { - x86_64-linux = fetchurl { - url = "https://github.com/rancher/k3s/releases/download/v${version}/k3s-airgap-images-amd64.tar"; - sha256 = "sha256-6kQmlpNV+4cU1Kn5lyZhutXYK5qYdey0jubzYRRF3vA="; - }; - aarch64-linux = fetchurl { - url = "https://github.com/rancher/k3s/releases/download/v${version}/k3s-airgap-images-arm64.tar"; - sha256 = "sha256-OlqqdAmBN+azT0kfjZ/Bd0CFbbW5hTg9/8T9U05N0zE="; - }; - armv7l-linux = fetchurl { - url = "https://github.com/rancher/k3s/releases/download/v${version}/k3s-airgap-images-arm.tar"; - sha256 = "sha256-j/ARBtHDnfRk/7BpOvavoHe7L5dmsCZe5+wuZ5t4V/k="; - }; - }.${stdenv.hostPlatform.system} or throwError; + src = + let + throwError = throw "Unsupported system ${stdenv.hostPlatform.system}"; + in + { + x86_64-linux = fetchurl { + url = "https://github.com/rancher/k3s/releases/download/v${version}/k3s-airgap-images-amd64.tar"; + sha256 = "sha256-6kQmlpNV+4cU1Kn5lyZhutXYK5qYdey0jubzYRRF3vA="; + }; + aarch64-linux = fetchurl { + url = "https://github.com/rancher/k3s/releases/download/v${version}/k3s-airgap-images-arm64.tar"; + sha256 = "sha256-OlqqdAmBN+azT0kfjZ/Bd0CFbbW5hTg9/8T9U05N0zE="; + }; + armv7l-linux = fetchurl { + url = "https://github.com/rancher/k3s/releases/download/v${version}/k3s-airgap-images-arm.tar"; + sha256 = "sha256-j/ARBtHDnfRk/7BpOvavoHe7L5dmsCZe5+wuZ5t4V/k="; + }; + }.${stdenv.hostPlatform.system} or throwError; preferLocalBuild = true; dontUnpack = true; diff --git a/modules/k8s.nix b/modules/k8s.nix index 1dd6ef4..6d9fff4 100644 --- a/modules/k8s.nix +++ b/modules/k8s.nix @@ -3,19 +3,20 @@ { options, config, lib, pkgs, k8s, ... }: with lib; - let cfg = config.kubernetes; gvkKeyFn = type: "${type.group}/${type.version}/${type.kind}"; getDefaults = resource: group: version: kind: - catAttrs "default" (filter (default: - (resource == null || default.resource == null || default.resource == resource) && - (default.group == null || default.group == group) && - (default.version == null || default.version == version) && - (default.kind == null || default.kind == kind) - ) cfg.api.defaults); + catAttrs "default" (filter + (default: + (resource == null || default.resource == null || default.resource == resource) && + (default.group == null || default.group == group) && + (default.version == null || default.version == version) && + (default.kind == null || default.kind == kind) + ) + cfg.api.defaults); moduleToAttrs = value: if isAttrs value @@ -34,7 +35,7 @@ let defaults = mkOption { description = "Kubernetes defaults to apply to resources"; - type = types.listOf (types.submodule ({config, ...}: { + type = types.listOf (types.submodule ({ config, ... }: { options = { group = mkOption { description = "Group to apply default to (all by default)"; @@ -69,45 +70,47 @@ let default = mkOption { description = "Default to apply"; type = types.unspecified; - default = {}; + default = { }; }; }; })); - default = []; + default = [ ]; apply = unique; }; types = mkOption { description = "List of registered kubernetes types"; - type = coerceListOfSubmodulesToAttrs { - options = { - group = mkOption { - description = "Resource type group"; - type = types.str; - }; + type = coerceListOfSubmodulesToAttrs + { + options = { + group = mkOption { + description = "Resource type group"; + type = types.str; + }; - version = mkOption { - description = "Resoruce type version"; - type = types.str; - }; + version = mkOption { + description = "Resoruce type version"; + type = types.str; + }; - kind = mkOption { - description = "Resource type kind"; - type = types.str; - }; + kind = mkOption { + description = "Resource type kind"; + type = types.str; + }; - name = mkOption { - description = "Resource type name"; - type = types.nullOr types.str; - }; + name = mkOption { + description = "Resource type name"; + type = types.nullOr types.str; + }; - attrName = mkOption { - description = "Name of the nixified attribute"; - type = types.str; + attrName = mkOption { + description = "Name of the nixified attribute"; + type = types.str; + }; }; - }; - } gvkKeyFn; - default = {}; + } + gvkKeyFn; + default = { }; }; }; @@ -120,24 +123,32 @@ let indexOf = lst: value: head (filter (v: v != -1) (imap0 (i: v: if v == value then i else -1) lst)); - compareVersions = ver1: ver2: let - getVersion = v: substring 1 10 v; - splittedVer1 = builtins.splitVersion (getVersion ver1); - splittedVer2 = builtins.splitVersion (getVersion ver2); + compareVersions = ver1: ver2: + let + getVersion = v: substring 1 10 v; + splittedVer1 = builtins.splitVersion (getVersion ver1); + splittedVer2 = builtins.splitVersion (getVersion ver2); - v1 = if length splittedVer1 == 1 then "${getVersion ver1}prod" else getVersion ver1; - v2 = if length splittedVer2 == 1 then "${getVersion ver2}prod" else getVersion ver2; - in builtins.compareVersions v1 v2; + v1 = if length splittedVer1 == 1 then "${getVersion ver1}prod" else getVersion ver1; + v2 = if length splittedVer2 == 1 then "${getVersion ver2}prod" else getVersion ver2; + in + builtins.compareVersions v1 v2; - customResourceTypesByAttrName = zipAttrs (mapAttrsToList (_: resourceType: { - ${resourceType.attrName} = resourceType; - }) cfg.customTypes); + customResourceTypesByAttrName = zipAttrs (mapAttrsToList + (_: resourceType: { + ${resourceType.attrName} = resourceType; + }) + cfg.customTypes); - customResourceTypesByAttrNameSortByVersion = mapAttrs (_: resourceTypes: - reverseList (sort (r1: r2: - compareVersions r1.version r2.version > 0 - ) resourceTypes) - ) customResourceTypesByAttrName; + customResourceTypesByAttrNameSortByVersion = mapAttrs + (_: resourceTypes: + reverseList (sort + (r1: r2: + compareVersions r1.version r2.version > 0 + ) + resourceTypes) + ) + customResourceTypesByAttrName; latestCustomResourceTypes = mapAttrsToList (_: resources: last resources) customResourceTypesByAttrNameSortByVersion; @@ -163,7 +174,7 @@ let spec = mkOption { description = "Module spec"; type = types.either types.attrs (types.submodule ct.module); - default = {}; + default = { }; }; }; @@ -174,34 +185,43 @@ let }; }; - customResourceOptions = (mapAttrsToList (_: ct: {config, ...}: let - module = customResourceModuleForType config ct; - in { - options.resources.${ct.group}.${ct.version}.${ct.kind} = mkOption { - description = ct.description; - type = types.attrsOf (types.submodule module); - default = {}; - }; - }) cfg.customTypes) ++ (map (ct: { options, config, ... }: let - module = customResourceModuleForType config ct; - in { - options.resources.${ct.attrName} = mkOption { - description = ct.description; - type = types.attrsOf (types.submodule module); - default = {}; - }; + customResourceOptions = (mapAttrsToList + (_: ct: { config, ... }: + let + module = customResourceModuleForType config ct; + in + { + options.resources.${ct.group}.${ct.version}.${ct.kind} = mkOption { + description = ct.description; + type = types.attrsOf (types.submodule module); + default = { }; + }; + }) + cfg.customTypes) ++ (map + (ct: { options, config, ... }: + let + module = customResourceModuleForType config ct; + in + { + options.resources.${ct.attrName} = mkOption { + description = ct.description; + type = types.attrsOf (types.submodule module); + default = { }; + }; - config.resources.${ct.group}.${ct.version}.${ct.kind} = - mkAliasDefinitions options.resources.${ct.attrName}; - }) latestCustomResourceTypes); + config.resources.${ct.group}.${ct.version}.${ct.kind} = + mkAliasDefinitions options.resources.${ct.attrName}; + }) + latestCustomResourceTypes); -in { +in +{ imports = [ ./base.nix ]; options.kubernetes = { version = mkOption { description = "Kubernetes version to use"; - type = types.enum ["1.19" "1.20" "1.21"]; + type = types.enum [ "1.19" "1.20" "1.21" ]; default = "1.21"; }; @@ -227,76 +247,80 @@ in { apiOptions ] ++ customResourceOptions; }; - default = {}; + default = { }; }; imports = mkOption { type = types.listOf (types.either types.package types.path); description = "List of resources to import"; - default = []; + default = [ ]; }; resources = mkOption { description = "Alias for `config.kubernetes.api.resources` options"; - default = {}; + default = { }; type = types.attrsOf types.attrs; }; customTypes = mkOption { description = "List of custom resource types to make API for"; - type = coerceListOfSubmodulesToAttrs { - options = { - group = mkOption { - description = "Custom type group"; - type = types.str; - }; + type = coerceListOfSubmodulesToAttrs + { + options = { + group = mkOption { + description = "Custom type group"; + type = types.str; + }; - version = mkOption { - description = "Custom type version"; - type = types.str; - }; + version = mkOption { + description = "Custom type version"; + type = types.str; + }; - kind = mkOption { - description = "Custom type kind"; - type = types.str; - }; + kind = mkOption { + description = "Custom type kind"; + type = types.str; + }; - name = mkOption { - description = "Custom type resource name"; - type = types.nullOr types.str; - default = null; - }; + name = mkOption { + description = "Custom type resource name"; + type = types.nullOr types.str; + default = null; + }; - attrName = mkOption { - description = "Name of the nixified attribute"; - type = types.str; - }; + attrName = mkOption { + description = "Name of the nixified attribute"; + type = types.str; + }; - description = mkOption { - description = "Custom type description"; - type = types.str; - default = ""; - }; + description = mkOption { + description = "Custom type description"; + type = types.str; + default = ""; + }; - module = mkOption { - description = "Custom type module"; - type = types.unspecified; - default = {}; + module = mkOption { + description = "Custom type module"; + type = types.unspecified; + default = { }; + }; }; - }; - } gvkKeyFn; - default = {}; + } + gvkKeyFn; + default = { }; }; 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 - ) (unique items); - default = []; + 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 + ) + (unique items); + default = [ ]; }; generated = mkOption { @@ -321,41 +345,44 @@ in { # module propagation options _m.propagate = [{ - features = ["k8s"]; + features = [ "k8s" ]; module = { config, ... }: { # propagate kubernetes version and namespace kubernetes.version = mkDefault cfg.version; kubernetes.namespace = mkDefault cfg.namespace; }; - } { - features = ["k8s" "submodule"]; - module = { config, ... }: { - # set module defaults - kubernetes.api.defaults = ( - # propagate defaults if default propagation is enabled - (filter (default: default.propagate) cfg.api.defaults) ++ + } + { + features = [ "k8s" "submodule" ]; + module = { config, ... }: { + # set module defaults + kubernetes.api.defaults = ( + # propagate defaults if default propagation is enabled + (filter (default: default.propagate) cfg.api.defaults) ++ - [ - # set module name and version for all kuberentes resources - { - default.metadata.labels = { - "kubenix/module-name" = config.submodule.name; - "kubenix/module-version" = config.submodule.version; - }; - } - ] - ); - }; - }]; + [ + # set module name and version for all kuberentes resources + { + default.metadata.labels = { + "kubenix/module-name" = config.submodule.name; + "kubenix/module-version" = config.submodule.version; + }; + } + ] + ); + }; + }]; # expose k8s helper methods as module argument _module.args.k8s = import ../lib/k8s.nix { inherit lib; }; kubernetes.api = mkMerge ([{ # register custom types - types = mapAttrsToList (_: cr: { - inherit (cr) name group version kind attrName; - }) cfg.customTypes; + types = mapAttrsToList + (_: cr: { + inherit (cr) name group version kind attrName; + }) + cfg.customTypes; defaults = [{ default = { @@ -373,24 +400,30 @@ in { }] ++ # import of yaml files - (map (i: let - # load yaml file - object = loadYAML i; - groupVersion = splitString "/" object.apiVersion; - name = object.metadata.name; - version = last groupVersion; - group = - if version == (head groupVersion) - then "core" else head groupVersion; - kind = object.kind; - in { - resources.${group}.${version}.${kind}.${name} = object; - }) cfg.imports)); + (map + (i: + let + # load yaml file + object = loadYAML i; + groupVersion = splitString "/" object.apiVersion; + name = object.metadata.name; + version = last groupVersion; + group = + if version == (head groupVersion) + then "core" else head groupVersion; + kind = object.kind; + in + { + resources.${group}.${version}.${kind}.${name} = object; + }) + cfg.imports)); - kubernetes.objects = flatten (mapAttrsToList (_: type: - mapAttrsToList (name: resource: moduleToAttrs resource) - cfg.api.resources.${type.group}.${type.version}.${type.kind} - ) cfg.api.types); + kubernetes.objects = flatten (mapAttrsToList + (_: type: + mapAttrsToList (name: resource: moduleToAttrs resource) + cfg.api.resources.${type.group}.${type.version}.${type.kind} + ) + cfg.api.types); kubernetes.generated = k8s.mkHashedList { items = config.kubernetes.objects; diff --git a/modules/legacy.nix b/modules/legacy.nix index 7acf63e..89d816d 100644 --- a/modules/legacy.nix +++ b/modules/legacy.nix @@ -3,7 +3,6 @@ { options, config, pkgs, lib, kubenix, ... }: with lib; - let parentModule = module; globalConfig = config; @@ -29,46 +28,50 @@ let else if isAttrs mkOptionDefault.module then module // attrs else module ); - in [ + in + [ { _module.args.name = module.name; _module.args.module = module; } ./k8s.nix ./legacy.nix - (injectModuleAttrs moduleDefinition.module {_file = file;}) + (injectModuleAttrs moduleDefinition.module { _file = file; }) { config.kubernetes.namespace = mkOptionDefault module.namespace; config.kubenix.project = mkOptionDefault config.kubenix.project; } - ] ++ config.kubernetes.defaultModuleConfiguration.all - ++ (optionals (hasAttr moduleDefinition.name config.kubernetes.defaultModuleConfiguration) - config.kubernetes.defaultModuleConfiguration.${moduleDefinition.name}); + ] ++ config.kubernetes.defaultModuleConfiguration.all + ++ (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: mapAttrs' (name: resource: nameValuePair "${serviceName}-${name}" resource) resources; # TODO: rewrite using mkOptionType - defaultModuleConfigurationOptions = mapAttrs (name: moduleDefinition: mkOption { - description = "Module default configuration for ${name} module"; - type = types.coercedTo types.unspecified (value: [value]) (types.listOf types.unspecified); - default = []; - apply = filter (v: v!=[]); - }) config.kubernetes.moduleDefinitions; + defaultModuleConfigurationOptions = mapAttrs + (name: moduleDefinition: mkOption { + description = "Module default configuration for ${name} module"; + type = types.coercedTo types.unspecified (value: [ value ]) (types.listOf types.unspecified); + default = [ ]; + apply = filter (v: v != [ ]); + }) + 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 { +in +{ imports = [ ./k8s.nix ]; options.kubernetes.moduleDefinitions = mkOption { description = "Legacy kubenix attribute set of module definitions"; - default = {}; - type = types.attrsOf (types.submodule ({name, ...}: { + default = { }; + type = types.attrsOf (types.submodule ({ name, ... }: { options = { name = mkOption { description = "Module definition name"; @@ -101,19 +104,19 @@ in { options = defaultModuleConfigurationOptions // { all = mkOption { description = "Module default configuration for all modules"; - type = types.coercedTo types.unspecified (value: [value]) (types.listOf types.unspecified); - default = []; - apply = filter (v: v != []); + type = types.coercedTo types.unspecified (value: [ value ]) (types.listOf types.unspecified); + default = [ ]; + apply = filter (v: v != [ ]); }; }; }; - default = {}; + default = { }; }; options.kubernetes.modules = mkOption { description = "Legacy kubenix attribute set of modules"; - default = {}; - type = types.attrsOf (types.submodule ({config, name, ...}: { + default = { }; + type = types.attrsOf (types.submodule ({ config, name, ... }: { options = { name = mkOption { description = "Module name"; @@ -130,17 +133,19 @@ in { labels = mkOption { description = "Attribute set of module lables"; type = types.attrsOf types.str; - default = {}; + default = { }; }; configuration = mkOption { description = "Module configuration"; - type = submoduleWithSpecialArgs { - imports = mkModuleOptions (getModuleDefinition config.module) config; - } { - inherit kubenix; - }; - default = {}; + type = submoduleWithSpecialArgs + { + imports = mkModuleOptions (getModuleDefinition config.module) config; + } + { + inherit kubenix; + }; + default = { }; }; module = mkOption { @@ -153,9 +158,9 @@ in { }; options.kubernetes.defaults = mkOption { - type = types.attrsOf (types.coercedTo types.attrs (value: [value]) (types.listOf types.attrs)); + type = types.attrsOf (types.coercedTo types.attrs (value: [ value ]) (types.listOf types.attrs)); description = "Legacy kubenix kubernetes defaults."; - default = {}; + default = { }; }; # for back compatibility with kubernetes.customResources @@ -163,50 +168,63 @@ in { config = { kubernetes = mkMerge [{ - api.defaults = mapAttrsToList (attrName: default: let - type = head (mapAttrsToList (_: v: v) (filterAttrs (_: type: type.attrName == attrName) config.kubernetes.api.types)); - in { - default = { imports = default; }; - } // (if (attrName == "all") then {} else { - resource = type.name; - })) config.kubernetes.defaults; + api.defaults = mapAttrsToList + (attrName: default: + let + type = head (mapAttrsToList (_: v: v) (filterAttrs (_: type: type.attrName == attrName) config.kubernetes.api.types)); + in + { + default = { imports = default; }; + } // (if (attrName == "all") then { } else { + resource = type.name; + })) + config.kubernetes.defaults; resources = mkMerge ( - mapAttrsToList (name: module: - mapAttrs' (_: type: let - moduleDefinition = getModuleDefinition module.module; + mapAttrsToList + (name: module: + mapAttrs' + (_: type: + let + moduleDefinition = getModuleDefinition module.module; - moduleResources = module.configuration.kubernetes.api.resources.${type.attrName} or {}; + moduleResources = module.configuration.kubernetes.api.resources.${type.attrName} or { }; - moduleConfig = - if moduleDefinition.prefixResources && type.kind != "CustomResourceDefinition" - then prefixResources (moduleToAttrs moduleResources) name - else moduleToAttrs moduleResources; - in nameValuePair type.attrName - (if moduleDefinition.assignAsDefaults - then mkAllDefault moduleConfig 1000 - else moduleConfig) - ) module.configuration.kubernetes.api.types - ) config.kubernetes.modules + moduleConfig = + if moduleDefinition.prefixResources && type.kind != "CustomResourceDefinition" + then prefixResources (moduleToAttrs moduleResources) name + else moduleToAttrs moduleResources; + in + nameValuePair type.attrName + (if moduleDefinition.assignAsDefaults + then mkAllDefault moduleConfig 1000 + else moduleConfig) + ) + module.configuration.kubernetes.api.types + ) + config.kubernetes.modules ); # custom types created from customResourceDefinitions customTypes = - mapAttrsToList (name: crd: { - group = crd.spec.group; - version = crd.spec.version; - kind = crd.spec.names.kind; - name = crd.spec.names.plural; - attrName = mkOptionDefault name; - }) (config.kubernetes.resources.customResourceDefinitions or {}); + mapAttrsToList + (name: crd: { + group = crd.spec.group; + version = crd.spec.version; + kind = crd.spec.names.kind; + name = crd.spec.names.plural; + attrName = mkOptionDefault name; + }) + (config.kubernetes.resources.customResourceDefinitions or { }); defaultModuleConfiguration.all = { _file = head options.kubernetes.defaultModuleConfiguration.files; config.kubernetes.version = mkDefault config.kubernetes.version; config.kubernetes.moduleDefinitions = config.kubernetes.moduleDefinitions; }; - } { - resources = mkAliasDefinitions options.kubernetes.customResources; - }]; + } + { + resources = mkAliasDefinitions options.kubernetes.customResources; + }]; }; } diff --git a/modules/submodule.nix b/modules/submodule.nix index 454cda8..2ae82bb 100644 --- a/modules/submodule.nix +++ b/modules/submodule.nix @@ -26,24 +26,24 @@ with lib; tags = mkOption { description = "List of submodule tags"; type = types.listOf types.str; - default = []; + default = [ ]; }; exports = mkOption { description = "Attribute set of functions to export"; type = types.attrs; - default = {}; + default = { }; }; passthru = mkOption { description = "Attribute set to passthru"; type = types.attrs; - default = {}; + default = { }; }; - args._empty = mkOption {}; + args._empty = mkOption { }; }; config._module.args.args = config.submodule.args; - config._m.features = ["submodule"]; + config._m.features = [ "submodule" ]; } diff --git a/modules/submodules.nix b/modules/submodules.nix index c87d214..1b66972 100644 --- a/modules/submodules.nix +++ b/modules/submodules.nix @@ -1,7 +1,6 @@ { config, options, kubenix, pkgs, lib, ... }: with lib; - let cfg = config.submodules; parentConfig = config; @@ -13,67 +12,82 @@ let else requiredVersion == version else true; - getDefaults = {name, version, tags, features}: - catAttrs "default" (filter (submoduleDefault: - (submoduleDefault.name == null || submoduleDefault.name == name) && - (matchesVersion submoduleDefault.version version) && - ( - (length submoduleDefault.tags == 0) || - (length (intersectLists submoduleDefault.tags tags)) > 0 - ) && - ( - (length submoduleDefault.features == 0) || - (length (intersectLists submoduleDefault.features features)) > 0 + getDefaults = { name, version, tags, features }: + catAttrs "default" (filter + (submoduleDefault: + (submoduleDefault.name == null || submoduleDefault.name == name) && + (matchesVersion submoduleDefault.version version) && + ( + (length submoduleDefault.tags == 0) || + (length (intersectLists submoduleDefault.tags tags)) > 0 + ) && + ( + (length submoduleDefault.features == 0) || + (length (intersectLists submoduleDefault.features features)) > 0 + ) ) - ) config.submodules.defaults); + config.submodules.defaults); specialArgs = cfg.specialArgs // { parentConfig = config; }; - findSubmodule = {name, version ? null, latest ? true}: let - matchingSubmodules = filter (el: - el.definition.name == name && - (matchesVersion version el.definition.version) - ) cfg.imports; + findSubmodule = { name, version ? null, latest ? true }: + let + matchingSubmodules = filter + (el: + el.definition.name == name && + (matchesVersion version el.definition.version) + ) + cfg.imports; - versionSortedSubmodules = sort (s1: s2: - if builtins.compareVersions s1.definition.version s2.definition.version > 0 - then true else false - ) matchingSubmodules; + versionSortedSubmodules = sort + (s1: s2: + if builtins.compareVersions s1.definition.version s2.definition.version > 0 + then true else false + ) + matchingSubmodules; - matchingModule = - if length versionSortedSubmodules == 0 - then throw "No module found ${name}/${if version == null then "latest" else version}" - else head versionSortedSubmodules; - in matchingModule; + matchingModule = + if length versionSortedSubmodules == 0 + then throw "No module found ${name}/${if version == null then "latest" else version}" + else head versionSortedSubmodules; + in + matchingModule; - passthruConfig = mapAttrsToList (name: opt: { - ${name} = mkMerge (mapAttrsToList (_: inst: - if inst.passthru.enable - then inst.config.submodule.passthru.${name} or {} - else {} - ) config.submodules.instances); + passthruConfig = mapAttrsToList + (name: opt: { + ${name} = mkMerge (mapAttrsToList + (_: inst: + if inst.passthru.enable + then inst.config.submodule.passthru.${name} or { } + else { } + ) + config.submodules.instances); - _module.args = mkMerge (mapAttrsToList (_: inst: - if inst.passthru.enable - then inst.config.submodule.passthru._module.args or {} - else {} - ) config.submodules.instances); - }) (removeAttrs options ["_definedNames" "_module" "_m" "submodules"]); -in { + _module.args = mkMerge (mapAttrsToList + (_: inst: + if inst.passthru.enable + then inst.config.submodule.passthru._module.args or { } + else { } + ) + config.submodules.instances); + }) + (removeAttrs options [ "_definedNames" "_module" "_m" "submodules" ]); +in +{ imports = [ ./base.nix ]; options = { submodules.specialArgs = mkOption { description = "Special args to pass to submodules. These arguments can be used for imports"; type = types.attrs; - default = {}; + default = { }; }; submodules.defaults = mkOption { description = "List of defaults to apply to submodule instances"; - type = types.listOf (types.submodule ({config, ...}: { + type = types.listOf (types.submodule ({ config, ... }: { options = { name = mkOption { description = "Name of the submodule to apply defaults for"; @@ -93,23 +107,23 @@ in { tags = mkOption { description = "List of tags to apply defaults for"; type = types.listOf types.str; - default = []; + default = [ ]; }; features = mkOption { description = "List of features that submodule has to have to apply defaults"; type = types.listOf types.str; - default = []; + default = [ ]; }; default = mkOption { description = "Default to apply to submodule instance"; type = types.unspecified; - default = {}; + default = { }; }; }; })); - default = []; + default = [ ]; }; submodules.propagate.enable = mkOption { @@ -123,139 +137,147 @@ in { type = types.listOf ( types.coercedTo types.path - (module: {inherit module;}) - (types.submodule ({name, config, ...}: let - evaledSubmodule' = evalModules { - inherit specialArgs; - modules = config.modules ++ [ ./base.nix ]; - check = false; - }; - - evaledSubmodule = - if (!(elem "submodule" evaledSubmodule'.config._m.features)) - then throw "no submodule defined" - else evaledSubmodule'; - in { - options = { - module = mkOption { - description = "Module defining submodule"; - type = types.unspecified; + (module: { inherit module; }) + (types.submodule ({ name, config, ... }: + let + evaledSubmodule' = evalModules { + inherit specialArgs; + modules = config.modules ++ [ ./base.nix ]; + check = false; }; - modules = mkOption { - description = "List of modules defining submodule"; - type = types.listOf types.unspecified; - default = [config.module]; + evaledSubmodule = + if (!(elem "submodule" evaledSubmodule'.config._m.features)) + then throw "no submodule defined" + else evaledSubmodule'; + in + { + options = { + module = mkOption { + description = "Module defining submodule"; + type = types.unspecified; + }; + + modules = mkOption { + description = "List of modules defining submodule"; + type = types.listOf types.unspecified; + default = [ config.module ]; + }; + + features = mkOption { + description = "List of features exposed by submodule"; + type = types.listOf types.str; + }; + + definition = mkOption { + description = "Submodule definition"; + type = types.attrs; + }; + + exportAs = mkOption { + description = "Name under which to register exports"; + type = types.nullOr types.str; + default = null; + }; }; - features = mkOption { - description = "List of features exposed by submodule"; - type = types.listOf types.str; - }; + config = { + definition = { + inherit (evaledSubmodule.config.submodule) name description version tags exports; + }; - definition = mkOption { - description = "Submodule definition"; - type = types.attrs; + features = evaledSubmodule.config._m.features; }; - - exportAs = mkOption { - description = "Name under which to register exports"; - type = types.nullOr types.str; - default = null; - }; - }; - - config = { - definition = { - inherit (evaledSubmodule.config.submodule) name description version tags exports; - }; - - features = evaledSubmodule.config._m.features; - }; - }) - ) + }) + ) ); - default = []; + default = [ ]; }; submodules.instances = mkOption { description = "Attribute set of submodule instances"; - default = {}; - type = types.attrsOf (types.submodule ({name, config, options, ...}: let - # submodule associated with - submodule = findSubmodule { - name = config.submodule; - version = config.version; - }; - - # definition of a submodule - submoduleDefinition = submodule.definition; - - # submodule defaults - defaults = getDefaults { - name = submoduleDefinition.name; - version = submoduleDefinition.version; - tags = submoduleDefinition.tags; - features = submodule.features; - }; - in { - options = { - name = mkOption { - description = "Submodule instance name"; - type = types.str; - default = name; + default = { }; + type = types.attrsOf (types.submodule ({ name, config, options, ... }: + let + # submodule associated with + submodule = findSubmodule { + name = config.submodule; + version = config.version; }; - submodule = mkOption { - description = "Name of the submodule to use"; - type = types.str; - default = name; - }; + # definition of a submodule + submoduleDefinition = submodule.definition; - version = mkOption { - description = '' - Version of submodule to use, if version starts with "~" it is - threated as regex pattern for example "~1.0.*" - ''; - type = types.nullOr types.str; - default = null; + # submodule defaults + defaults = getDefaults { + name = submoduleDefinition.name; + version = submoduleDefinition.version; + tags = submoduleDefinition.tags; + features = submodule.features; }; + in + { + options = { + name = mkOption { + description = "Submodule instance name"; + type = types.str; + default = name; + }; - passthru.enable = mkOption { - description = "Whether to passthru submodule resources"; - type = types.bool; - default = true; - }; + submodule = mkOption { + description = "Name of the submodule to use"; + type = types.str; + default = name; + }; - config = mkOption { - description = "Submodule instance ${config.name} for ${submoduleDefinition.name}:${submoduleDefinition.version} config"; - type = submoduleWithSpecialArgs ({...}: { - imports = submodule.modules ++ defaults ++ [ ./base.nix ]; - _module.args.pkgs = pkgs; - _module.args.name = config.name; - _module.args.submodule = config; - submodule.args = mkAliasDefinitions options.args; - }) specialArgs; - default = {}; - }; + version = mkOption { + description = '' + Version of submodule to use, if version starts with "~" it is + threated as regex pattern for example "~1.0.*" + ''; + type = types.nullOr types.str; + default = null; + }; - args = mkOption { - description = "Submodule arguments (alias of config.submodule.args)"; + 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 ++ [ ./base.nix ]; + _module.args.pkgs = pkgs; + _module.args.name = config.name; + _module.args.submodule = config; + submodule.args = mkAliasDefinitions options.args; + }) + specialArgs; + default = { }; + }; + + args = mkOption { + description = "Submodule arguments (alias of config.submodule.args)"; + }; }; - }; - })); + })); }; - default = {}; + default = { }; }; config = mkMerge ([ { # register exported functions as args - _module.args = mkMerge (map (submodule: { - ${submodule.exportAs} = submodule.definition.exports; - }) (filter (submodule: submodule.exportAs != null) cfg.imports)); + _module.args = mkMerge (map + (submodule: { + ${submodule.exportAs} = submodule.definition.exports; + }) + (filter (submodule: submodule.exportAs != null) cfg.imports)); - _m.features = ["submodules"]; + _m.features = [ "submodules" ]; submodules.specialArgs.kubenix = kubenix; @@ -267,17 +289,19 @@ in { }; }] - (map (propagate: { - features = propagate.features; - default = propagate.module; - }) config._m.propagate) + (map + (propagate: { + features = propagate.features; + default = propagate.module; + }) + config._m.propagate) ]; } (mkIf cfg.propagate.enable { # if propagate is enabled and submodule has submodules included propagage defaults and imports submodules.defaults = [{ - features = ["submodules"]; + features = [ "submodules" ]; default = { submodules = { defaults = cfg.defaults; diff --git a/modules/testing/default.nix b/modules/testing/default.nix index 72f3e7c..a09a9c3 100644 --- a/modules/testing/default.nix +++ b/modules/testing/default.nix @@ -1,7 +1,6 @@ { nixosPath, config, pkgs, lib, kubenix, ... }: with lib; - let cfg = config.testing; @@ -18,7 +17,8 @@ let isTestEnabled = test: (cfg.enabledTests == null || elem test.name cfg.enabledTests) && test.enable; -in { +in +{ imports = [ ./docker.nix ./driver/kubetest.nix @@ -40,30 +40,32 @@ in { defaults = mkOption { description = "List of defaults to apply to tests"; - type = types.listOf (types.submodule ({config, ...}: { + type = types.listOf (types.submodule ({ config, ... }: { options = { features = mkOption { description = "List of features that test has to have to apply defaults"; type = types.listOf types.str; - default = []; + default = [ ]; }; default = mkOption { description = "Default to apply to test"; type = types.unspecified; - default = {}; + default = { }; }; }; })); - default = []; + default = [ ]; }; tests = mkOption { description = "List of test cases"; - default = []; - type = types.listOf (types.coercedTo types.path (module: { - inherit module; - }) (types.submodule testModule)); + default = [ ]; + type = types.listOf (types.coercedTo types.path + (module: { + inherit module; + }) + (types.submodule testModule)); apply = tests: filter isTestEnabled tests; }; @@ -82,7 +84,7 @@ in { args = mkOption { description = "Attribute set of extra args passed to tests"; type = types.attrs; - default = {}; + default = { }; }; success = mkOption { diff --git a/modules/testing/docker.nix b/modules/testing/docker.nix index afa66b5..2f060f8 100644 --- a/modules/testing/docker.nix +++ b/modules/testing/docker.nix @@ -1,16 +1,16 @@ { config, lib, pkgs, ... }: with lib; -with import ../../lib/docker.nix { inherit lib pkgs; }; - +with import ../../lib/docker.nix { inherit lib pkgs; }; let testing = config.testing; - allImages = flatten (map (t: t.evaled.config.docker.export or []) testing.tests); + allImages = flatten (map (t: t.evaled.config.docker.export or [ ]) testing.tests); cfg = config.testing.docker; -in { +in +{ options.testing.docker = { registryUrl = mkOption { description = "Docker registry url"; @@ -38,7 +38,7 @@ in { }; config.testing.defaults = [{ - features = ["docker"]; + features = [ "docker" ]; default = { docker.registry.url = cfg.registryUrl; }; diff --git a/modules/testing/driver/kubetest.nix b/modules/testing/driver/kubetest.nix index 2da987c..a900ef1 100644 --- a/modules/testing/driver/kubetest.nix +++ b/modules/testing/driver/kubetest.nix @@ -1,12 +1,11 @@ { lib, config, pkgs, ... }: with lib; - let testing = config.testing; cfg = testing.driver.kubetest; - kubetest = import ./kubetestdrv.nix {inherit pkgs;}; + kubetest = import ./kubetestdrv.nix { inherit pkgs; }; pythonEnv = pkgs.python38.withPackages (ps: with ps; [ pytest @@ -16,18 +15,20 @@ let toTestScript = t: if isString t.script - then pkgs.writeText "${t.name}.py" '' - ${cfg.defaultHeader} - ${t.script} - '' + then + pkgs.writeText "${t.name}.py" '' + ${cfg.defaultHeader} + ${t.script} + '' else t.script; tests = pkgs.linkFarm "${testing.name}-tests" ( - map (t: { - path = toTestScript t; - name = "${t.name}_test.py"; - }) - ( filter (t: t.script != null) testing.tests ) + map + (t: { + path = toTestScript t; + name = "${t.name}_test.py"; + }) + (filter (t: t.script != null) testing.tests) ); testScript = pkgs.writeScript "test-${testing.name}.sh" '' @@ -35,7 +36,8 @@ let ${pythonEnv}/bin/pytest -p no:cacheprovider ${tests} $@ ''; -in { +in +{ options.testing.driver.kubetest = { defaultHeader = mkOption { type = types.lines; @@ -48,7 +50,7 @@ in { extraPackages = mkOption { type = types.listOf types.package; description = "Extra packages to pass to tests"; - default = []; + default = [ ]; }; }; diff --git a/modules/testing/evalTest.nix b/modules/testing/evalTest.nix index 3d2d28a..50a714e 100644 --- a/modules/testing/evalTest.nix +++ b/modules/testing/evalTest.nix @@ -1,7 +1,6 @@ { lib, config, testing, kubenix, ... }: with lib; - let modules = [ # testing module @@ -36,25 +35,29 @@ let # defaults that can be applied on tests defaults = - filter (d: - (intersectLists d.features testFeatures) == d.features || - (length d.features) == 0 - ) testing.defaults; + filter + (d: + (intersectLists d.features testFeatures) == d.features || + (length d.features) == 0 + ) + testing.defaults; # add default modules to all modules modulesWithDefaults = modules ++ (map (d: d.default) defaults); # evaled test - evaled = let - evaled' = kubenix.evalModules { - modules = modulesWithDefaults; - }; - in + evaled = + let + evaled' = kubenix.evalModules { + modules = modulesWithDefaults; + }; + in if testing.throwError then evaled' else if (builtins.tryEval evaled'.config.test.assertions).success then evaled' else null; -in { +in +{ options = { module = mkOption { description = "Module defining kubenix test"; @@ -97,7 +100,7 @@ in { description = "Test result"; type = types.unspecified; internal = true; - default = []; + default = [ ]; }; script = mkOption { diff --git a/modules/testing/runtime/local.nix b/modules/testing/runtime/local.nix index 335ea6d..070951c 100644 --- a/modules/testing/runtime/local.nix +++ b/modules/testing/runtime/local.nix @@ -1,7 +1,6 @@ { lib, config, pkgs, ... }: with lib; - let testing = config.testing; @@ -32,7 +31,8 @@ let echo "--> running tests" ${testing.testScript} --kube-config=$KUBECONFIG ''; -in { +in +{ options.testing.runtime.local = { script = mkOption { type = types.package; diff --git a/modules/testing/runtime/nixos-k8s.nix b/modules/testing/runtime/nixos-k8s.nix index f5bc8e1..33051de 100644 --- a/modules/testing/runtime/nixos-k8s.nix +++ b/modules/testing/runtime/nixos-k8s.nix @@ -9,7 +9,6 @@ }: with lib; - let testing = config.testing; kubeconfig = "/etc/${config.services.kubernetes.pki.etcClusterAdminKubeconfig}"; diff --git a/modules/testing/test-options.nix b/modules/testing/test-options.nix index 8108c7f..6785a06 100644 --- a/modules/testing/test-options.nix +++ b/modules/testing/test-options.nix @@ -1,11 +1,11 @@ { lib, config, pkgs, ... }: with lib; - let cfg = config.test; -in { +in +{ options.test = { name = mkOption { description = "Test name"; @@ -38,8 +38,8 @@ in { }; }; }); - default = []; - example = [ { assertion = false; message = "you can't enable this for some reason"; } ]; + default = [ ]; + example = [{ assertion = false; message = "you can't enable this for some reason"; }]; description = '' This option allows modules to express conditions that must hold for the evaluation of the system configuration to diff --git a/pkgs/applications/networking/cluster/kubectl/default.nix b/pkgs/applications/networking/cluster/kubectl/default.nix index a4e950b..ed94865 100644 --- a/pkgs/applications/networking/cluster/kubectl/default.nix +++ b/pkgs/applications/networking/cluster/kubectl/default.nix @@ -27,4 +27,3 @@ stdenv.mkDerivation { homepage = "https://github.com/kubernetes/kubectl"; }; } - diff --git a/release.nix b/release.nix index 93eb2a7..7f67f9b 100644 --- a/release.nix +++ b/release.nix @@ -8,7 +8,6 @@ in }: with lib; - let kubenix = import ./. { inherit pkgs; }; diff --git a/tests/default.nix b/tests/default.nix index f76bd8b..a99e87b 100644 --- a/tests/default.nix +++ b/tests/default.nix @@ -1,4 +1,4 @@ -{ pkgs ? import {} +{ pkgs ? import { } , lib ? pkgs.lib , kubenix ? import ../. { inherit pkgs lib; } @@ -7,12 +7,12 @@ , k8sVersion ? "1.21" , registryUrl ? throw "Registry url not defined" , throwError ? true # whether any testing error should throw an error -, enabledTests ? null }: +, enabledTests ? null +}: with lib; - let - images = pkgs.callPackage ./images.nix {}; + images = pkgs.callPackage ./images.nix { }; config = (kubenix.evalModules { modules = [ @@ -34,7 +34,7 @@ let #./legacy/k8s.nix #./legacy/crd.nix #./legacy/modules.nix - ./helm/simple.nix + # ./helm/simple.nix # ./istio/bookinfo.nix # infinite recursion ./submodules/simple.nix ./submodules/defaults.nix @@ -48,7 +48,7 @@ let docker.registryUrl = registryUrl; defaults = [ { - features = ["k8s"]; + features = [ "k8s" ]; default = { kubernetes.version = k8sVersion; }; @@ -64,4 +64,5 @@ let inherit kubenix nixosPath; }; }).config; -in pkgs.recurseIntoAttrs config.testing +in +pkgs.recurseIntoAttrs config.testing diff --git a/tests/helm/simple.nix b/tests/helm/simple.nix index 1f272a1..c363105 100644 --- a/tests/helm/simple.nix +++ b/tests/helm/simple.nix @@ -3,7 +3,6 @@ with lib; with kubenix.lib; with pkgs.dockerTools; - let corev1 = config.kubernetes.api.resources.core.v1; appsv1 = config.kubernetes.api.resources.apps.v1; @@ -31,7 +30,8 @@ let finalImageName = "docker.io/bitnami/bitnami-shell"; finalImageTag = "10"; }; -in { +in +{ imports = [ kubenix.modules.test kubenix.modules.helm kubenix.modules.k8s ]; test = { @@ -43,15 +43,17 @@ in { appsv1.StatefulSet ? "app-psql-postgresql-primary" && appsv1.StatefulSet ? "app-psql-postgresql-read" && corev1.Secret ? "app-psql-postgresql" && - corev1.Service ? "app-psql-postgresql-headless" ; - } { - message = "should have values passed"; - assertion = appsv1.StatefulSet.app-psql-postgresql-read.spec.replicas == 2; - } { - message = "should have namespace defined"; - assertion = - appsv1.StatefulSet.app-psql-postgresql-primary.metadata.namespace == "test"; - }]; + corev1.Service ? "app-psql-postgresql-headless"; + } + { + message = "should have values passed"; + assertion = appsv1.StatefulSet.app-psql-postgresql-read.spec.replicas == 2; + } + { + message = "should have namespace defined"; + assertion = + appsv1.StatefulSet.app-psql-postgresql-primary.metadata.namespace == "test"; + }]; testScript = '' kube.wait_until_succeeds("docker load < ${postgresql}") kube.wait_until_succeeds("docker load < ${postgresqlExporter}") @@ -61,7 +63,7 @@ in { ''; }; - kubernetes.resources.namespaces.test = {}; + kubernetes.resources.namespaces.test = { }; kubernetes.helm.instances.app-psql = { namespace = "test"; diff --git a/tests/images.nix b/tests/images.nix index 8b16e90..7f07469 100644 --- a/tests/images.nix +++ b/tests/images.nix @@ -10,47 +10,49 @@ with lib; contents = [ pkgs.bash pkgs.curl pkgs.cacert ]; }; - nginx = let - nginxPort = "80"; - nginxConf = pkgs.writeText "nginx.conf" '' - user nginx nginx; - daemon off; - error_log /dev/stdout info; - pid /dev/null; - events {} - http { - access_log /dev/stdout; - server { - listen ${nginxPort}; - index index.html; - location / { - root ${nginxWebRoot}; + nginx = + let + nginxPort = "80"; + nginxConf = pkgs.writeText "nginx.conf" '' + user nginx nginx; + daemon off; + error_log /dev/stdout info; + pid /dev/null; + events {} + http { + access_log /dev/stdout; + server { + listen ${nginxPort}; + index index.html; + location / { + root ${nginxWebRoot}; + } } } - } - ''; - nginxWebRoot = pkgs.writeTextDir "index.html" '' -

Hello from NGINX

- ''; - in dockerTools.buildLayeredImage { - name = "xtruder/nginx"; - tag = "latest"; - contents = [pkgs.nginx]; - extraCommands = '' - mkdir -p etc - chmod u+w etc - mkdir -p var/cache/nginx - chmod u+w var/cache/nginx - mkdir -p var/log/nginx - chmod u+w var/log/nginx - echo "nginx:x:1000:1000::/:" > etc/passwd - echo "nginx:x:1000:nginx" > etc/group - ''; - config = { - Cmd = ["nginx" "-c" nginxConf]; - ExposedPorts = { - "${nginxPort}/tcp" = {}; + ''; + nginxWebRoot = pkgs.writeTextDir "index.html" '' +

Hello from NGINX

+ ''; + in + dockerTools.buildLayeredImage { + name = "xtruder/nginx"; + tag = "latest"; + contents = [ pkgs.nginx ]; + extraCommands = '' + mkdir -p etc + chmod u+w etc + mkdir -p var/cache/nginx + chmod u+w var/cache/nginx + mkdir -p var/log/nginx + chmod u+w var/log/nginx + echo "nginx:x:1000:1000::/:" > etc/passwd + echo "nginx:x:1000:nginx" > etc/group + ''; + config = { + Cmd = [ "nginx" "-c" nginxConf ]; + ExposedPorts = { + "${nginxPort}/tcp" = { }; + }; }; }; - }; } diff --git a/tests/istio/bookinfo.nix b/tests/istio/bookinfo.nix index 269bca8..caea7bb 100644 --- a/tests/istio/bookinfo.nix +++ b/tests/istio/bookinfo.nix @@ -18,25 +18,28 @@ name = "http"; protocol = "HTTP"; }; - hosts = ["*"]; + hosts = [ "*" ]; }]; }; }; VirtualService.bookinfo = { spec = { - hosts = ["*"]; - gateways = ["bookinfo-gateway"]; + hosts = [ "*" ]; + gateways = [ "bookinfo-gateway" ]; http = [{ match = [{ uri.exact = "/productpage"; - } { - uri.exact = "/login"; - } { - uri.exact = "/logout"; - } { - uri.prefix = "/api/v1/products"; - }]; + } + { + uri.exact = "/login"; + } + { + uri.exact = "/logout"; + } + { + uri.prefix = "/api/v1/products"; + }]; route = [{ destination = { host = "productpage"; @@ -63,13 +66,15 @@ subsets = [{ name = "v1"; labels.version = "v1"; - } { - name = "v2"; - labels.version = "v2"; - } { - name = "v3"; - labels.version = "v3"; - }]; + } + { + name = "v2"; + labels.version = "v2"; + } + { + name = "v3"; + labels.version = "v3"; + }]; }; }; @@ -79,16 +84,19 @@ subsets = [{ name = "v1"; labels.version = "v1"; - } { - name = "v2"; - labels.version = "v2"; - } { - name = "v2-mysql"; - labels.version = "v2-mysql"; - } { - name = "v2-mysql-vm"; - labels.version = "v2-mysql-vm"; - }]; + } + { + name = "v2"; + labels.version = "v2"; + } + { + name = "v2-mysql"; + labels.version = "v2-mysql"; + } + { + name = "v2-mysql-vm"; + labels.version = "v2-mysql-vm"; + }]; }; }; @@ -98,10 +106,11 @@ subsets = [{ name = "v1"; labels.version = "v1"; - } { - name = "v2"; - labels.version = "v2"; - }]; + } + { + name = "v2"; + labels.version = "v2"; + }]; }; }; }; diff --git a/tests/k8s/crd.nix b/tests/k8s/crd.nix index 0a0230c..60b274d 100644 --- a/tests/k8s/crd.nix +++ b/tests/k8s/crd.nix @@ -1,10 +1,10 @@ { config, lib, kubenix, pkgs, ... }: with lib; - let latestCrontab = config.kubernetes.api.resources.cronTabs.latest; -in { +in +{ imports = with kubenix.modules; [ test k8s ]; test = { @@ -37,7 +37,8 @@ in { }; }; - } { + } + { group = "stable.example.com"; version = "v2"; kind = "CronTab"; @@ -56,7 +57,8 @@ in { }; }; }; - } { + } + { group = "stable.example.com"; version = "v3"; kind = "CronTab"; diff --git a/tests/k8s/defaults.nix b/tests/k8s/defaults.nix index 7a5a230..125a011 100644 --- a/tests/k8s/defaults.nix +++ b/tests/k8s/defaults.nix @@ -1,11 +1,11 @@ { config, lib, kubenix, ... }: with lib; - let pod1 = config.kubernetes.api.resources.pods.pod1; pod2 = config.kubernetes.api.resources.pods.pod2; -in { +in +{ imports = with kubenix.modules; [ test k8s ]; test = { @@ -14,16 +14,18 @@ in { assertions = [{ message = "Should have label set with resource"; assertion = pod1.metadata.labels.resource-label == "value"; - } { - message = "Should have default label set with group, version, kind"; - assertion = pod1.metadata.labels.gvk-label == "value"; - } { - message = "Should have conditional annotation set"; - assertion = pod2.metadata.annotations.conditional-annotation == "value"; - }]; + } + { + message = "Should have default label set with group, version, kind"; + assertion = pod1.metadata.labels.gvk-label == "value"; + } + { + message = "Should have conditional annotation set"; + assertion = pod2.metadata.annotations.conditional-annotation == "value"; + }]; }; - kubernetes.resources.pods.pod1 = {}; + kubernetes.resources.pods.pod1 = { }; kubernetes.resources.pods.pod2 = { metadata.labels.custom-label = "value"; @@ -32,17 +34,19 @@ in { kubernetes.api.defaults = [{ resource = "pods"; default.metadata.labels.resource-label = "value"; - } { - group = "core"; - kind = "Pod"; - version = "v1"; - default.metadata.labels.gvk-label = "value"; - } { - resource = "pods"; - default = { config, ... }: { - config.metadata.annotations = mkIf (config.metadata.labels ? "custom-label") { - conditional-annotation = "value"; + } + { + group = "core"; + kind = "Pod"; + version = "v1"; + default.metadata.labels.gvk-label = "value"; + } + { + resource = "pods"; + default = { config, ... }: { + config.metadata.annotations = mkIf (config.metadata.labels ? "custom-label") { + conditional-annotation = "value"; + }; }; - }; - }]; + }]; } diff --git a/tests/k8s/deployment.nix b/tests/k8s/deployment.nix index 7b60d40..ea38cf1 100644 --- a/tests/k8s/deployment.nix +++ b/tests/k8s/deployment.nix @@ -1,7 +1,6 @@ { config, lib, pkgs, kubenix, images, ... }: with lib; - let cfg = config.kubernetes.api.resources.deployments.nginx; image = images.nginx; @@ -16,12 +15,13 @@ let spec.containers = [{ name = "curl"; image = config.docker.images.curl.path; - args = ["curl" "--retry" "20" "--retry-connrefused" "http://nginx"]; + args = [ "curl" "--retry" "20" "--retry-connrefused" "http://nginx" ]; }]; spec.restartPolicy = "Never"; }); -in { +in +{ imports = [ kubenix.modules.test kubenix.modules.k8s kubenix.modules.docker ]; test = { @@ -35,13 +35,15 @@ in { else if ((builtins.compareVersions config.kubernetes.version "1.8") <= 0) then cfg.apiVersion == "apps/v1beta2" else cfg.apiVersion == "apps/v1"; - } { - message = "should have corrent kind set"; - assertion = cfg.kind == "Deployment"; - } { - message = "should have replicas set"; - assertion = cfg.spec.replicas == 3; - }]; + } + { + message = "should have corrent kind set"; + assertion = cfg.kind == "Deployment"; + } + { + message = "should have replicas set"; + assertion = cfg.spec.replicas == 3; + }]; script = '' import time diff --git a/tests/k8s/imports.nix b/tests/k8s/imports.nix index b4bd032..72b4b1d 100644 --- a/tests/k8s/imports.nix +++ b/tests/k8s/imports.nix @@ -1,11 +1,11 @@ { config, lib, kubenix, ... }: with lib; - let pod = config.kubernetes.api.resources.core.v1.Pod.test; deployment = config.kubernetes.api.resources.apps.v1.Deployment.nginx-deployment; -in { +in +{ imports = with kubenix.modules; [ test k8s ]; test = { @@ -15,10 +15,11 @@ in { assertions = [{ message = "Pod should have name set"; assertion = pod.metadata.name == "test"; - } { - message = "Deployment should have name set"; - assertion = deployment.metadata.name == "nginx-deployment"; - }]; + } + { + message = "Deployment should have name set"; + assertion = deployment.metadata.name == "nginx-deployment"; + }]; }; kubernetes.imports = [ diff --git a/tests/k8s/order.nix b/tests/k8s/order.nix index 9b01dcf..34d662e 100644 --- a/tests/k8s/order.nix +++ b/tests/k8s/order.nix @@ -1,10 +1,10 @@ { config, lib, kubenix, pkgs, ... }: with lib; - let cfg = config.kubernetes.api.resources.customResourceDefinitions.crontabs; -in { +in +{ imports = with kubenix.modules; [ test k8s ]; test = { @@ -34,7 +34,7 @@ in { plural = "crontabs"; singular = "crontab"; kind = "CronTab"; - shortNames = ["ct"]; + shortNames = [ "ct" ]; }; }; }; @@ -55,7 +55,7 @@ in { }; }]; - kubernetes.resources.namespaces.test = {}; + kubernetes.resources.namespaces.test = { }; kubernetes.resources."stable.example.com"."v1".CronTab.crontab.spec.schedule = "* * * * *"; } diff --git a/tests/k8s/simple.nix b/tests/k8s/simple.nix index 78f7277..ac7dd99 100644 --- a/tests/k8s/simple.nix +++ b/tests/k8s/simple.nix @@ -1,8 +1,8 @@ { config, kubenix, ... }: - let cfg = config.kubernetes.api.resources.pods.nginx; -in { +in +{ imports = [ kubenix.modules.test kubenix.modules.k8s ]; test = { @@ -11,11 +11,12 @@ in { assertions = [{ message = "should have apiVersion and kind set"; assertion = cfg.apiVersion == "v1" && cfg.kind == "Pod"; - } { - message = "should have name set"; - assertion = cfg.metadata.name == "nginx"; - }]; + } + { + message = "should have name set"; + assertion = cfg.metadata.name == "nginx"; + }]; }; - kubernetes.resources.pods.nginx = {}; + kubernetes.resources.pods.nginx = { }; } diff --git a/tests/k8s/submodule.nix b/tests/k8s/submodule.nix index 2dca0d4..416234c 100644 --- a/tests/k8s/submodule.nix +++ b/tests/k8s/submodule.nix @@ -1,10 +1,10 @@ { name, config, lib, kubenix, images, ... }: with lib; - let cfg = config.submodules.instances.passthru; -in { +in +{ imports = with kubenix.modules; [ test submodules k8s docker ]; test = { @@ -13,16 +13,17 @@ in { 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"; - }]; + } + { + message = "Should expose docker image"; + assertion = (head config.docker.export).imageName == "xtruder/nginx"; + }]; }; kubernetes.namespace = "test-namespace"; submodules.imports = [{ - module = {name, config, ...}: { + module = { name, config, ... }: { imports = with kubenix.modules; [ submodule k8s docker ]; config = { diff --git a/tests/legacy/crd.nix b/tests/legacy/crd.nix index 47146df..9fc7682 100644 --- a/tests/legacy/crd.nix +++ b/tests/legacy/crd.nix @@ -1,16 +1,18 @@ { options, config, lib, kubenix, pkgs, ... }: with lib; - let - findObject = { kind, name }: filter (object: - object.kind == kind && object.metadata.name == name - ) config.kubernetes.objects; + findObject = { kind, name }: filter + (object: + object.kind == kind && object.metadata.name == name + ) + config.kubernetes.objects; getObject = filter: head (findObject filter); hasObject = { kind, name }: length (findObject { inherit kind name; }) == 1; -in { +in +{ imports = with kubenix.modules; [ test k8s legacy ]; test = { @@ -20,12 +22,13 @@ in { assertions = [{ message = "should define crd in module"; assertion = - hasObject {kind = "SecretClaim"; name = "module-claim";}; - } { - message = "should define crd in root"; - assertion = - hasObject {kind = "SecretClaim"; name = "root-claim";}; - }]; + hasObject { kind = "SecretClaim"; name = "module-claim"; }; + } + { + message = "should define crd in root"; + assertion = + hasObject { kind = "SecretClaim"; name = "root-claim"; }; + }]; }; kubernetes.namespace = "test"; @@ -40,7 +43,7 @@ in { type = mkOption { description = "Type of the secret"; - type = types.enum ["Opaque" "kubernetes.io/tls"]; + type = types.enum [ "Opaque" "kubernetes.io/tls" ]; default = "Opaque"; }; @@ -62,7 +65,7 @@ in { }; }; - config = { + config = { kubernetes.resources.customResourceDefinitions.secret-claims = { kind = "CustomResourceDefinition"; apiVersion = "apiextensions.k8s.io/v1beta1"; @@ -74,7 +77,7 @@ in { names = { plural = "secretclaims"; kind = "SecretClaim"; - shortNames = ["scl"]; + shortNames = [ "scl" ]; }; }; }; diff --git a/tests/legacy/k8s.nix b/tests/legacy/k8s.nix index 940abc5..92f337f 100644 --- a/tests/legacy/k8s.nix +++ b/tests/legacy/k8s.nix @@ -1,10 +1,10 @@ { config, lib, kubenix, pkgs, ... }: with lib; - let cfg = config.kubernetes.api.resources.deployments.app; -in { +in +{ imports = with kubenix.modules; [ test k8s legacy ]; test = { @@ -15,13 +15,14 @@ in { assertion = cfg.kind == "Deployment" && cfg.metadata.name == "app"; - } { - message = "should have correct defaults set"; - assertion = - cfg.metadata.namespace == "test" && - cfg.metadata.labels.label1 == "value1" && - cfg.metadata.labels.label2 == "value2"; - }]; + } + { + message = "should have correct defaults set"; + assertion = + cfg.metadata.namespace == "test" && + cfg.metadata.labels.label1 == "value1" && + cfg.metadata.labels.label2 == "value2"; + }]; }; kubernetes.resources.deployments.app = { @@ -39,7 +40,7 @@ in { }; kubernetes.resources.configMaps.app = { - data."my-conf.json" = builtins.toJSON {}; + data."my-conf.json" = builtins.toJSON { }; }; kubernetes.defaults = { diff --git a/tests/legacy/modules.nix b/tests/legacy/modules.nix index 3c1e4f5..72312e9 100644 --- a/tests/legacy/modules.nix +++ b/tests/legacy/modules.nix @@ -1,16 +1,18 @@ { options, config, lib, kubenix, pkgs, ... }: with lib; - let - findObject = { kind, name }: filter (object: - object.kind == kind && object.metadata.name == name - ) config.kubernetes.objects; + findObject = { kind, name }: filter + (object: + object.kind == kind && object.metadata.name == name + ) + config.kubernetes.objects; getObject = filter: head (findObject filter); hasObject = { kind, name }: length (findObject { inherit kind name; }) == 1; -in { +in +{ imports = with kubenix.modules; [ test k8s legacy ]; test = { @@ -19,21 +21,21 @@ in { assertions = [{ message = "should have all objects"; assertion = - hasObject {kind = "Deployment"; name = "myapp";} && - hasObject {kind = "Deployment"; name = "myapp2";} && - hasObject {kind = "Deployment"; name = "myapp2-app2";}; - } { - message = "should have default labels set"; - assertion = - (getObject {kind = "Deployment"; name = "myapp2-app2";}) - .metadata.labels.module-label or false == "value" && - (getObject {kind = "Deployment"; name = "myapp2";}) - .metadata.labels.module-label or false == "value"; - } { - message = "should passthru resources to root module"; - assertion = - config.kubernetes.resources.deployments.myapp2-app2-app.metadata.labels.module-label or false == "value"; - }]; + hasObject { kind = "Deployment"; name = "myapp"; } && + hasObject { kind = "Deployment"; name = "myapp2"; } && + hasObject { kind = "Deployment"; name = "myapp2-app2"; }; + } + { + message = "should have default labels set"; + assertion = + (getObject { kind = "Deployment"; name = "myapp2-app2"; }).metadata.labels.module-label or false == "value" && + (getObject { kind = "Deployment"; name = "myapp2"; }).metadata.labels.module-label or false == "value"; + } + { + message = "should passthru resources to root module"; + assertion = + config.kubernetes.resources.deployments.myapp2-app2-app.metadata.labels.module-label or false == "value"; + }]; }; kubernetes.defaults.all.metadata.labels.module-label = "value"; diff --git a/tests/module.nix b/tests/module.nix index 2ed201c..19cbb52 100644 --- a/tests/module.nix +++ b/tests/module.nix @@ -1,11 +1,11 @@ { name, config, lib, kubenix, images, ... }: with lib; - let cfg = config.submodules.instances.test.config; deployment = cfg.kubernetes.api.deployments.nginx; -in { +in +{ imports = [ kubenix.modules.test kubenix.module ]; test = { @@ -14,13 +14,15 @@ in { assertions = [{ message = "Namespace not propagated"; assertion = deployment.metadata.namespace == "test"; - } { - message = "Version not propagated"; - assertion = cfg.kubernetes.version == config.kubernetes.version; - } { - message = "docker image should be added to exported images"; - assertion = (head config.docker.export) == images.nginx; - }]; + } + { + message = "Version not propagated"; + assertion = cfg.kubernetes.version == config.kubernetes.version; + } + { + message = "docker image should be added to exported images"; + assertion = (head config.docker.export) == images.nginx; + }]; testScript = '' kube.wait_until_succeeds("docker load < ${images.nginx}") kube.wait_until_succeeds("kubectl apply -f ${config.kubernetes.result}") @@ -31,7 +33,7 @@ in { }; submodules.imports = [{ - module = {name, config, ...}: { + module = { name, config, ... }: { submodule.name = "nginx"; kubernetes.api.deployments.nginx = { metadata = { @@ -55,7 +57,7 @@ in { }; }]; - kubernetes.api.namespaces.test = {}; + kubernetes.api.namespaces.test = { }; submodules.instances.test = { submodule = "nginx"; diff --git a/tests/submodules/defaults.nix b/tests/submodules/defaults.nix index 1398330..f27d873 100644 --- a/tests/submodules/defaults.nix +++ b/tests/submodules/defaults.nix @@ -1,7 +1,6 @@ { name, config, lib, kubenix, ... }: with lib; - let instance1 = config.submodules.instances.instance1; instance2 = config.submodules.instances.instance2; @@ -10,7 +9,7 @@ let instance5 = config.submodules.instances.instance5; versioned-submodule = config.submodules.instances.versioned-submodule; - submodule = {name, ...}: { + submodule = { name, ... }: { imports = [ kubenix.modules.submodule ]; options.submodule.args = { @@ -25,7 +24,8 @@ let }; }; }; -in { +in +{ imports = with kubenix.modules; [ test submodules ]; test = { @@ -34,95 +34,130 @@ in { assertions = [{ message = "should apply defaults by tag1"; assertion = instance1.config.submodule.args.value == "value1"; - } { - message = "should apply defaults by tag2"; - assertion = instance2.config.submodule.args.value == "value2"; - } { - message = "should apply defaults by tag2"; - assertion = instance3.config.submodule.args.value == "value2"; - } { - message = "should apply defaults to all"; - assertion = - instance1.config.submodule.args.defaultValue == "value" && - instance2.config.submodule.args.defaultValue == "value"; - } { - message = "instance1 and instance3 should have value of default-value"; - assertion = instance3.config.submodule.args.defaultValue == "default-value"; - } { - message = "should apply defaults by submodule name"; - assertion = instance4.config.submodule.args.value == "value4"; - } { - message = "should apply defaults by custom condition"; - assertion = instance5.config.submodule.args.defaultValue == "my-custom-value"; - } { - message = "should apply defaults to versioned submodule"; - assertion = versioned-submodule.config.submodule.args.defaultValue == "versioned-submodule"; - }]; + } + { + message = "should apply defaults by tag2"; + assertion = instance2.config.submodule.args.value == "value2"; + } + { + message = "should apply defaults by tag2"; + assertion = instance3.config.submodule.args.value == "value2"; + } + { + message = "should apply defaults to all"; + assertion = + instance1.config.submodule.args.defaultValue == "value" && + instance2.config.submodule.args.defaultValue == "value"; + } + { + message = "instance1 and instance3 should have value of default-value"; + assertion = instance3.config.submodule.args.defaultValue == "default-value"; + } + { + message = "should apply defaults by submodule name"; + assertion = instance4.config.submodule.args.value == "value4"; + } + { + message = "should apply defaults by custom condition"; + assertion = instance5.config.submodule.args.defaultValue == "my-custom-value"; + } + { + message = "should apply defaults to versioned submodule"; + assertion = versioned-submodule.config.submodule.args.defaultValue == "versioned-submodule"; + }]; }; submodules.imports = [{ - modules = [submodule { - submodule = { - name = "submodule1"; - tags = ["tag1"]; - }; + modules = [ + submodule + { + submodule = { + name = "submodule1"; + tags = [ "tag1" ]; + }; + } + ]; + } + { + modules = [ + submodule + { + submodule = { + name = "submodule2"; + tags = [ "tag2" ]; + }; + } + ]; + } + { + modules = [ + submodule + { + submodule = { + name = "submodule3"; + tags = [ "tag2" ]; + }; + } + ]; + } + { + modules = [ + submodule + { + submodule = { + name = "submodule4"; + }; + } + ]; + } + { + modules = [ + submodule + { + submodule = { + name = "submodule5"; + }; + submodule.args.value = "custom-value"; + } + ]; + } + { + modules = [ + submodule + { + submodule = { + name = "versioned-submodule"; + version = "2.0.0"; + }; + } + ]; }]; - } { - modules = [submodule { - submodule = { - name = "submodule2"; - tags = ["tag2"]; - }; - }]; - } { - modules = [submodule { - submodule = { - name = "submodule3"; - tags = ["tag2"]; - }; - }]; - } { - modules = [submodule { - submodule = { - name = "submodule4"; - }; - }]; - } { - modules = [submodule { - submodule = { - name = "submodule5"; - }; - submodule.args.value = "custom-value"; - }]; - } { - modules = [submodule { - submodule = { - name = "versioned-submodule"; - version = "2.0.0"; - }; - }]; - }]; submodules.defaults = [{ default.submodule.args.defaultValue = mkDefault "value"; - } { - tags = ["tag1"]; - default.submodule.args.value = mkDefault "value1"; - } { - tags = ["tag2"]; - default.submodule.args.value = mkDefault "value2"; - } { - name = "submodule4"; - default.submodule.args.value = mkDefault "value4"; - } { - default = {config, ...}: { - submodule.args.defaultValue = mkIf (config.submodule.args.value == "custom-value") "my-custom-value"; - }; - } { - name = "versioned-submodule"; - version = "2.0.0"; - default.submodule.args.value = mkDefault "versioned"; - }]; + } + { + tags = [ "tag1" ]; + default.submodule.args.value = mkDefault "value1"; + } + { + tags = [ "tag2" ]; + default.submodule.args.value = mkDefault "value2"; + } + { + name = "submodule4"; + default.submodule.args.value = mkDefault "value4"; + } + { + default = { config, ... }: { + submodule.args.defaultValue = mkIf (config.submodule.args.value == "custom-value") "my-custom-value"; + }; + } + { + name = "versioned-submodule"; + version = "2.0.0"; + default.submodule.args.value = mkDefault "versioned"; + }]; submodules.instances.instance1.submodule = "submodule1"; submodules.instances.instance2.submodule = "submodule2"; diff --git a/tests/submodules/exports.nix b/tests/submodules/exports.nix index 90ec487..f661db1 100644 --- a/tests/submodules/exports.nix +++ b/tests/submodules/exports.nix @@ -1,7 +1,6 @@ { name, config, lib, kubenix, subm-lib, ... }: with lib; - let submodule = { imports = [ kubenix.modules.submodule ]; @@ -13,7 +12,8 @@ let }; }; }; -in { +in +{ imports = with kubenix.modules; [ test submodules ]; test = { @@ -26,7 +26,7 @@ in { }; submodules.imports = [{ - modules = [submodule]; + modules = [ submodule ]; exportAs = "subm-lib"; }]; } diff --git a/tests/submodules/passthru.nix b/tests/submodules/passthru.nix index c529b81..5182348 100644 --- a/tests/submodules/passthru.nix +++ b/tests/submodules/passthru.nix @@ -1,7 +1,6 @@ { name, config, lib, kubenix, ... }: with lib; - let submodule = { name, ... }: { imports = [ kubenix.modules.submodule ]; @@ -11,14 +10,15 @@ let passthru.global.${name} = "true"; }; }; -in { +in +{ imports = with kubenix.modules; [ test submodules ]; options = { global = mkOption { description = "Global value"; type = types.attrs; - default = {}; + default = { }; }; }; @@ -29,17 +29,19 @@ in { assertions = [{ message = "should passthru values if passthru enabled"; assertion = hasAttr "inst1" config.global && config.global.inst1 == "true"; - } { - message = "should not passthru values if passthru not enabled"; - assertion = !(hasAttr "inst2" config.global); - } { - message = "should passthru by default"; - assertion = hasAttr "inst3" config.global && config.global.inst3 == "true"; - }]; + } + { + message = "should not passthru values if passthru not enabled"; + assertion = !(hasAttr "inst2" config.global); + } + { + message = "should passthru by default"; + assertion = hasAttr "inst3" config.global && config.global.inst3 == "true"; + }]; }; submodules.imports = [{ - modules = [submodule]; + modules = [ submodule ]; }]; submodules.instances.inst1 = { diff --git a/tests/submodules/simple.nix b/tests/submodules/simple.nix index 162f477..bc20fd1 100644 --- a/tests/submodules/simple.nix +++ b/tests/submodules/simple.nix @@ -1,11 +1,11 @@ { name, config, lib, kubenix, ... }: with lib; - let cfg = config.submodules.instances.instance; args = cfg.config.submodule.args; -in { +in +{ imports = with kubenix.modules; [ test submodules ]; test = { @@ -14,22 +14,27 @@ in { assertions = [{ message = "Submodule name is set"; assertion = cfg.name == "instance"; - } { - message = "Submodule version is set"; - assertion = cfg.version == null; - } { - message = "Submodule config has submodule definition"; - assertion = cfg.config.submodule.name == "submodule"; - } { - message = "Should have argument set"; - assertion = args.value == "test"; - } { - message = "Should have submodule name set"; - assertion = args.name == "instance"; - } { - message = "should have tag set"; - assertion = elem "tag" (cfg.config.submodule.tags); - }]; + } + { + message = "Submodule version is set"; + assertion = cfg.version == null; + } + { + message = "Submodule config has submodule definition"; + assertion = cfg.config.submodule.name == "submodule"; + } + { + message = "Should have argument set"; + assertion = args.value == "test"; + } + { + message = "Should have submodule name set"; + assertion = args.name == "instance"; + } + { + message = "should have tag set"; + assertion = elem "tag" (cfg.config.submodule.tags); + }]; }; submodules.propagate.enable = true; @@ -51,7 +56,7 @@ in { config = { submodule.name = "submodule"; - submodule.tags = ["tag"]; + submodule.tags = [ "tag" ]; }; }; }]; diff --git a/tests/submodules/versioning.nix b/tests/submodules/versioning.nix index 511a25c..5e5973e 100644 --- a/tests/submodules/versioning.nix +++ b/tests/submodules/versioning.nix @@ -1,7 +1,6 @@ { name, config, lib, kubenix, ... }: with lib; - let inst-exact = config.submodules.instances.inst-exact.config; inst-regex = config.submodules.instances.inst-regex.config; @@ -17,7 +16,8 @@ let config.submodule.name = "subm"; }; -in { +in +{ imports = with kubenix.modules; [ test submodules ]; test = { @@ -26,36 +26,45 @@ in { assertions = [{ message = "should select exact version"; assertion = inst-exact.version == "1.1.0"; - } { - message = "should select regex version"; - assertion = inst-regex.version == "1.2.1"; - } { - message = "should select latest version"; - assertion = inst-latest.version == "1.2.1"; - }]; + } + { + message = "should select regex version"; + assertion = inst-regex.version == "1.2.1"; + } + { + message = "should select latest version"; + assertion = inst-latest.version == "1.2.1"; + }]; }; submodules.imports = [{ modules = [{ config.submodule.version = "1.0.0"; config.version = "1.0.0"; - } submodule]; - } { - modules = [{ - config.submodule.version = "1.1.0"; - config.version = "1.1.0"; - } submodule]; - } { - modules = [{ - config.submodule.version = "1.2.0"; - config.version = "1.2.0"; - } submodule]; - } { - modules = [{ - config.submodule.version = "1.2.1"; - config.version = "1.2.1"; - } submodule]; - }]; + } + submodule]; + } + { + modules = [{ + config.submodule.version = "1.1.0"; + config.version = "1.1.0"; + } + submodule]; + } + { + modules = [{ + config.submodule.version = "1.2.0"; + config.version = "1.2.0"; + } + submodule]; + } + { + modules = [{ + config.submodule.version = "1.2.1"; + config.version = "1.2.1"; + } + submodule]; + }]; submodules.instances.inst-exact = { submodule = "subm";