Created
October 13, 2025 11:13
-
-
Save Lillecarl/a3b7368964fd3b9f64417395bea03a97 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| From b39df2392ba95b50d6a4864188063ee354313170 Mon Sep 17 00:00:00 2001 | |
| From: Carl Andersson <[email protected]> | |
| Date: Mon, 13 Oct 2025 13:08:24 +0200 | |
| Subject: [PATCH] Add namespacing to kubernetes.resources | |
| This way we can't collide when rendering manifests and such. | |
| I took too much inspiration from kubenix when putting the original API together! | |
| --- | |
| cluster-config/cilium.nix | 2 +- | |
| cluster-config/cnpg.nix | 2 +- | |
| cluster-config/coredns.nix | 5 ++- | |
| cluster-config/hccm.nix | 11 ++----- | |
| cluster-config/hcsi.nix | 10 ++---- | |
| cluster-config/nginx.nix | 4 +-- | |
| cluster-config/victoriametrics.nix | 4 +-- | |
| easykubenix/default.nix | 1 + | |
| easykubenix/demo.nix | 13 +++----- | |
| easykubenix/helm.nix | 2 +- | |
| easykubenix/importyaml.nix | 2 +- | |
| easykubenix/kubernetes.nix | 49 +++++++++++++++++------------- | |
| hetzner-capi.nix | 2 +- | |
| hetzner-init.nix | 4 +-- | |
| 14 files changed, 48 insertions(+), 63 deletions(-) | |
| diff --git a/cluster-config/cilium.nix b/cluster-config/cilium.nix | |
| index 8357b31..9edfd8b 100644 | |
| --- a/cluster-config/cilium.nix | |
| +++ b/cluster-config/cilium.nix | |
| @@ -24,7 +24,7 @@ in | |
| }; | |
| }; | |
| config = lib.mkIf cfg.enable { | |
| - kubernetes.resources.Namespace.${cfg.namespace} = { }; | |
| + kubernetes.resources.none.Namespace.${cfg.namespace} = { }; | |
| helm.releases.${moduleName} = { | |
| namespace = cfg.namespace; | |
| diff --git a/cluster-config/cnpg.nix b/cluster-config/cnpg.nix | |
| index 12a669c..38075e5 100644 | |
| --- a/cluster-config/cnpg.nix | |
| +++ b/cluster-config/cnpg.nix | |
| @@ -25,7 +25,7 @@ in | |
| overrideNamespace = cfg.namespace; | |
| }; | |
| kubernetes = { | |
| - resources.Cluster.pg0 = { | |
| + resources.default.Cluster.pg0 = { | |
| spec = { | |
| instances = 1; | |
| storage.size = "1Gi"; | |
| diff --git a/cluster-config/coredns.nix b/cluster-config/coredns.nix | |
| index d64984a..6dab0f1 100644 | |
| --- a/cluster-config/coredns.nix | |
| +++ b/cluster-config/coredns.nix | |
| @@ -29,9 +29,8 @@ in | |
| }; | |
| config = lib.mkIf cfg.enable { | |
| # Create coredns namespace | |
| - kubernetes.resources.Namespace.${cfg.namespace} = { }; | |
| - kubernetes.resources.ConfigMap.coredns = { | |
| - metadata.namespace = cfg.namespace; | |
| + kubernetes.resources.none.Namespace.${cfg.namespace} = { }; | |
| + kubernetes.resources.${cfg.namespace}.ConfigMap.coredns = { | |
| data.Corefile = '' | |
| .:53 { | |
| errors | |
| diff --git a/cluster-config/hccm.nix b/cluster-config/hccm.nix | |
| index 5680f82..6e63111 100644 | |
| --- a/cluster-config/hccm.nix | |
| +++ b/cluster-config/hccm.nix | |
| @@ -25,15 +25,8 @@ in | |
| }; | |
| }; | |
| config = lib.mkIf cfg.enable { | |
| - kubernetes.resources.Namespace.${cfg.namespace} = { }; | |
| - kubernetes.resources.Secret.hccm = { | |
| - metadata = { | |
| - name = "hcloud"; | |
| - namespace = cfg.namespace; | |
| - }; | |
| - type = "Opaque"; | |
| - stringData.token = cfg.apiToken; | |
| - }; | |
| + kubernetes.resources.none.Namespace.${cfg.namespace} = { }; | |
| + kubernetes.resources.${cfg.namespace}.Secret.hcloud.stringData.token = cfg.apiToken; | |
| helm.releases.${moduleName} = { | |
| namespace = cfg.namespace; | |
| diff --git a/cluster-config/hcsi.nix b/cluster-config/hcsi.nix | |
| index 674f663..1e924eb 100644 | |
| --- a/cluster-config/hcsi.nix | |
| +++ b/cluster-config/hcsi.nix | |
| @@ -27,13 +27,7 @@ in | |
| src = cfg.url; | |
| overrideNamespace = cfg.namespace; | |
| }; | |
| - kubernetes.resources.Namespace.${cfg.namespace} = { }; | |
| - kubernetes.resources.Secret.hcloud-csi = { | |
| - metadata = { | |
| - name = "hcloud"; | |
| - namespace = cfg.namespace; | |
| - }; | |
| - stringData.token = cfg.apiToken; | |
| - }; | |
| + kubernetes.resources.none.Namespace.${cfg.namespace} = { }; | |
| + kubernetes.resources.${cfg.namespace}.Secret.hcloud.stringData.token = cfg.apiToken; | |
| }; | |
| } | |
| diff --git a/cluster-config/nginx.nix b/cluster-config/nginx.nix | |
| index 07da089..d4fa1b7 100644 | |
| --- a/cluster-config/nginx.nix | |
| +++ b/cluster-config/nginx.nix | |
| @@ -9,7 +9,7 @@ let | |
| cfg = config.${moduleName}; | |
| in | |
| { | |
| - options.${moduleName}= { | |
| + options.${moduleName} = { | |
| enable = lib.mkEnableOption moduleName; | |
| namespace = lib.mkOption { | |
| type = lib.types.str; | |
| @@ -21,7 +21,7 @@ in | |
| }; | |
| }; | |
| config = lib.mkIf cfg.enable { | |
| - kubernetes.resources.Namespace.${cfg.namespace} = { }; | |
| + kubernetes.resources.none.Namespace.${cfg.namespace} = { }; | |
| helm.releases.${moduleName} = { | |
| namespace = cfg.namespace; | |
| diff --git a/cluster-config/victoriametrics.nix b/cluster-config/victoriametrics.nix | |
| index 1c5f01b..d56e1a9 100644 | |
| --- a/cluster-config/victoriametrics.nix | |
| +++ b/cluster-config/victoriametrics.nix | |
| @@ -24,9 +24,7 @@ in | |
| src = "https://github.com/VictoriaMetrics/operator/releases/download/${cfg.version}/install-no-webhook.yaml"; | |
| }; | |
| kubernetes = { | |
| - resources = { | |
| - VMSingle.vm0 = { }; | |
| - }; | |
| + resources.default.VMSingle.vm0 = { }; | |
| apiMappings = { | |
| VLAgent = "operator.victoriametrics.com/v1"; | |
| VLCluster = "operator.victoriametrics.com/v1"; | |
| diff --git a/easykubenix/default.nix b/easykubenix/default.nix | |
| index 677bc15..b0b6f91 100644 | |
| --- a/easykubenix/default.nix | |
| +++ b/easykubenix/default.nix | |
| @@ -36,6 +36,7 @@ let | |
| in | |
| { | |
| inherit (eval.config.internal) | |
| + manifestAttrs | |
| manifestJSON | |
| manifestJSONFile | |
| manifestYAML | |
| diff --git a/easykubenix/demo.nix b/easykubenix/demo.nix | |
| index cf4294e..c44f70f 100644 | |
| --- a/easykubenix/demo.nix | |
| +++ b/easykubenix/demo.nix | |
| @@ -6,11 +6,7 @@ | |
| { helm, ... }: | |
| { | |
| config = { | |
| - kluctl = { | |
| - enable = true; | |
| - discriminator = "easykubenix-demo"; | |
| - }; | |
| - resources.Secret.hcloud = { | |
| + kubernetes.resources.kube-system.Secret.hcloud = { | |
| metadata = { | |
| name = "hcloud"; | |
| namespace = "kube-system"; | |
| @@ -19,7 +15,7 @@ | |
| data.token = "OXdZaU9zNHhhZE9JWVFvYTNRY2MzWXFtSmp1ODQzdUg4aDZaNTZ6MmtzNWt4YVNXV1djTzRxc2lLZDdqQWZGcA=="; | |
| }; | |
| helm.releases.hccm = { | |
| - namespace = "kube-system"; | |
| + namespace = "hccm-system"; | |
| chart = helm.fetch { | |
| repo = "https://charts.hetzner.cloud"; | |
| @@ -46,12 +42,11 @@ | |
| { ... }: | |
| { | |
| config = { | |
| - resources.ConfigMap."my-app-config" = { | |
| + kubernetes.resources.default.ConfigMap."my-app-config" = { | |
| metadata = { | |
| - namespace = "default"; | |
| labels.app = "my-app"; | |
| }; | |
| - data = { | |
| + stringData = { | |
| "config.yaml" = "some-value"; | |
| "storePath" = toString pkgs.fishMinimal; | |
| }; | |
| diff --git a/easykubenix/helm.nix b/easykubenix/helm.nix | |
| index ba06732..011baab 100644 | |
| --- a/easykubenix/helm.nix | |
| +++ b/easykubenix/helm.nix | |
| @@ -137,7 +137,7 @@ in | |
| mapAttrsToList ( | |
| _: release: | |
| map (object: { | |
| - ${object.kind}."${object.metadata.name}" = mkMerge ( | |
| + ${object.metadata.namespace or "none"}.${object.kind}."${object.metadata.name}" = mkMerge ( | |
| [ | |
| object | |
| ] | |
| diff --git a/easykubenix/importyaml.nix b/easykubenix/importyaml.nix | |
| index 1dfc6f6..613d946 100644 | |
| --- a/easykubenix/importyaml.nix | |
| +++ b/easykubenix/importyaml.nix | |
| @@ -118,7 +118,7 @@ in | |
| mapAttrsToList ( | |
| _: yaml: | |
| map (object: { | |
| - ${object.kind}."${object.metadata.name}" = mkMerge ( | |
| + ${object.metadata.namespace or "none"}.${object.kind}."${object.metadata.name}" = mkMerge ( | |
| [ | |
| object | |
| ] | |
| diff --git a/easykubenix/kubernetes.nix b/easykubenix/kubernetes.nix | |
| index 9132761..717c6ef 100644 | |
| --- a/easykubenix/kubernetes.nix | |
| +++ b/easykubenix/kubernetes.nix | |
| @@ -49,10 +49,11 @@ let | |
| in | |
| { | |
| options.kubernetes = { | |
| + # In your options definition | |
| resources = lib.mkOption { | |
| - type = lib.types.attrsOf (lib.types.attrsOf resourceBody); | |
| + type = lib.types.attrsOf (lib.types.attrsOf (lib.types.attrsOf resourceBody)); | |
| default = { }; | |
| - description = "Kubernetes resources, grouped by kind."; | |
| + description = "Kubernetes resources, grouped by namespace, then kind."; | |
| }; | |
| apiMappings = lib.mkOption { | |
| @@ -96,28 +97,34 @@ in | |
| generated = | |
| let | |
| - # Update apiVersion and kind if they're unset. This way kind name | |
| - # collisions don't matter, and collisions are rare anyways. | |
| + cleanedResources = lib.filterAttrsRecursive (n: v: v != null) cfg.resources; | |
| mappedResources = lib.mapAttrs ( | |
| - kind: resourcesByName: | |
| + namespace: resourcesByKind: | |
| lib.mapAttrs ( | |
| - name: attrs: | |
| - attrs | |
| - // { | |
| - apiVersion = if attrs.apiVersion != null then attrs.apiVersion else cfg.apiMappings.${kind}; | |
| - kind = if attrs.kind != null then attrs.kind else kind; | |
| - } | |
| - ) resourcesByName | |
| - ) cfg.resources; | |
| + kind: resourcesByName: | |
| + lib.mapAttrs ( | |
| + name: attrs: | |
| + # Provide a base set of attributes. `recursiveUpdate` will merge `attrs` on top, | |
| + # so any user-defined values for these fields will take precedence. | |
| + lib.recursiveUpdate ( | |
| + { | |
| + apiVersion = cfg.apiMappings.${kind}; | |
| + kind = kind; | |
| + metadata.name = name; | |
| + } | |
| + // lib.optionalAttrs (namespace != "none") { | |
| + metadata.namespace = namespace; | |
| + } | |
| + ) attrs | |
| + ) resourcesByName | |
| + ) resourcesByKind | |
| + ) cleanedResources; | |
| - resourceList = lib.pipe mappedResources [ | |
| - # Remove nulls | |
| - (lib.filterAttrsRecursive (n: v: v != null)) | |
| - # Extract resource attributes into a list | |
| - lib.attrValues | |
| - (listOfAttrSets: lib.map (kindResources: lib.attrValues kindResources) listOfAttrSets) | |
| - lib.flatten | |
| - ]; | |
| + resourceList = lib.flatten ( | |
| + lib.mapAttrsToList ( | |
| + nsName: kinds: lib.mapAttrsToList (kindName: names: lib.attrValues names) kinds | |
| + ) mappedResources | |
| + ); | |
| in | |
| resourceList; | |
| }; | |
| diff --git a/hetzner-capi.nix b/hetzner-capi.nix | |
| index c2b0d20..0fd0b4c 100644 | |
| --- a/hetzner-capi.nix | |
| +++ b/hetzner-capi.nix | |
| @@ -37,7 +37,7 @@ import ./easykubenix { | |
| ( | |
| { config, ... }: | |
| { | |
| - config.kubernetes.resources = | |
| + config.kubernetes.resources.none = | |
| let | |
| kubeletExtraArgs = { | |
| "fail-swap-on" = "false"; | |
| diff --git a/hetzner-init.nix b/hetzner-init.nix | |
| index 35c119e..b88cb2e 100644 | |
| --- a/hetzner-init.nix | |
| +++ b/hetzner-init.nix | |
| @@ -28,9 +28,7 @@ import ./easykubenix { | |
| config = { | |
| clusterName = "hetzner-test"; | |
| # Create a ConfigMap indicating the cluster is already initialized | |
| - kubernetes.resources.ConfigMap.initialized = { | |
| - metadata.namespace = "kube-public"; | |
| - }; | |
| + kubernetes.resources.kube-public.ConfigMap.initialized = { }; | |
| cilium = { | |
| enable = true; | |
| k8sServiceHost = builtins.getEnv "K8S_SERVICE_HOST"; | |
| -- | |
| 2.51.0 | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment