From aaaf6d1aa228ab175983288578aacf55a2492de9 Mon Sep 17 00:00:00 2001 From: Michele Baldessari Date: Thu, 15 Jan 2026 11:37:59 +0100 Subject: [PATCH] Make clusterGroup.isHubCluster optional We can figure out if a node is the hub or not by omparing global.localClusterDomain and global.hubClusterDomain. If those are the same we're on the hub, if they are not we're not on the hub. Keep supporting the clusterGroup.isHubCluster variable with precedence in order to not break any existing pattern. Tested on 4.19 and 4.20 with mcg hub/spoke --- templates/_helpers.tpl | 22 ++ .../external-secrets-hub-secretstore.yaml | 2 +- .../external-secrets-hub-secretstore.yaml | 4 +- tests/README.md | 7 +- tests/ishubcluster_helper_test.yaml | 266 ++++++++++++++++++ values.yaml | 3 +- 6 files changed, 298 insertions(+), 6 deletions(-) create mode 100644 templates/_helpers.tpl create mode 100644 tests/ishubcluster_helper_test.yaml diff --git a/templates/_helpers.tpl b/templates/_helpers.tpl new file mode 100644 index 0000000..9fb89b2 --- /dev/null +++ b/templates/_helpers.tpl @@ -0,0 +1,22 @@ +{{/* +Determines if the current cluster is a hub cluster. +First checks if clusterGroup.isHubCluster is explicitly set and uses that value. +If not set, falls back to comparing global.localClusterDomain and global.hubClusterDomain. +If domains are equal or localClusterDomain is not set (defaults to hubClusterDomain), this is a hub cluster. +Usage: {{ include "ocp_eso.ishubcluster" . }} +Returns: "true" or "false" as a string +*/}} +{{- define "ocp_eso.ishubcluster" -}} +{{- if and (hasKey .Values.clusterGroup "isHubCluster") (not (kindIs "invalid" .Values.clusterGroup.isHubCluster)) -}} + {{- .Values.clusterGroup.isHubCluster | toString -}} +{{- else if $.Values.global.hubClusterDomain -}} + {{- $localDomain := coalesce $.Values.global.localClusterDomain $.Values.global.hubClusterDomain -}} + {{- if eq $localDomain $.Values.global.hubClusterDomain -}} +true + {{- else -}} +false + {{- end -}} +{{- else -}} +false +{{- end -}} +{{- end }} diff --git a/templates/kubernetes/external-secrets-hub-secretstore.yaml b/templates/kubernetes/external-secrets-hub-secretstore.yaml index 4f38381..a3745e5 100644 --- a/templates/kubernetes/external-secrets-hub-secretstore.yaml +++ b/templates/kubernetes/external-secrets-hub-secretstore.yaml @@ -12,7 +12,7 @@ spec: server: url: {{ .Values.ocpExternalSecrets.kubernetes.server.url }} {{- if .Values.ocpExternalSecrets.caProvider.enabled }} -{{- if .Values.clusterGroup.isHubCluster }} +{{- if (eq (include "ocp_eso.ishubcluster" .) "true") }} caProvider: type: {{ .Values.ocpExternalSecrets.caProvider.hostCluster.type }} name: {{ .Values.ocpExternalSecrets.caProvider.hostCluster.name }} diff --git a/templates/vault/external-secrets-hub-secretstore.yaml b/templates/vault/external-secrets-hub-secretstore.yaml index 18ee175..ebd6d34 100644 --- a/templates/vault/external-secrets-hub-secretstore.yaml +++ b/templates/vault/external-secrets-hub-secretstore.yaml @@ -21,7 +21,7 @@ spec: # Version of KV backend version: v2 {{- if .Values.ocpExternalSecrets.caProvider.enabled }} -{{ if or .Values.clusterGroup.isHubCluster $hashicorp_vault_found }} +{{- if or (eq (include "ocp_eso.ishubcluster" .) "true") $hashicorp_vault_found }} caProvider: type: {{ .Values.ocpExternalSecrets.caProvider.hostCluster.type }} name: {{ .Values.ocpExternalSecrets.caProvider.hostCluster.name }} @@ -37,7 +37,7 @@ spec: {{- end }} auth: kubernetes: -{{ if or .Values.clusterGroup.isHubCluster $hashicorp_vault_found }} +{{- if or (eq (include "ocp_eso.ishubcluster" .) "true") $hashicorp_vault_found }} mountPath: {{ .Values.ocpExternalSecrets.vault.mountPath }} role: {{ .Values.ocpExternalSecrets.rbac.rolename }} {{ else }} diff --git a/tests/README.md b/tests/README.md index 19c2de1..7ee2004 100644 --- a/tests/README.md +++ b/tests/README.md @@ -2,11 +2,12 @@ ## Testing documentation -The syntax for writing tests can be found [here](https://github.com/helm-unittest/helm-unittest/blob/main/DOCUMENT.md) +The syntax for writing tests can be found [at this place here](https://github.com/helm-unittest/helm-unittest/blob/main/DOCUMENT.md) ## Run tests The following will use a containerized version: + ```bash make helm-unittest ``` @@ -18,11 +19,13 @@ helm plugin install https://github.com/helm-unittest/helm-unittest.git ``` ### Run unittest with locally installed helm and helm plugin + ```bash helm unittest . ``` -## Run unittests with docker +## Run unittests with Docker + ```bash docker run -ti --rm -v $(pwd):/apps:z helmunittest/helm-unittest . ``` diff --git a/tests/ishubcluster_helper_test.yaml b/tests/ishubcluster_helper_test.yaml new file mode 100644 index 0000000..e279058 --- /dev/null +++ b/tests/ishubcluster_helper_test.yaml @@ -0,0 +1,266 @@ +suite: Test ocp_eso.ishubcluster helper function +templates: + - templates/vault/external-secrets-hub-secretstore.yaml +release: + name: release-test +tests: + # ============================================================================ + # Tests when clusterGroup.isHubCluster is EXPLICITLY SET + # These should take precedence over domain logic + # ============================================================================ + + - it: should use isHubCluster=true when explicitly set, ignoring domain logic + set: + clusterGroup: + isHubCluster: true + global: + hubClusterDomain: "hub.example.com" + localClusterDomain: "spoke.example.com" + clusterDomain: "spoke.example.com" + secretStore: + backend: "vault" + asserts: + - equal: + path: spec.provider.vault.auth.kubernetes.mountPath + value: hub + - equal: + path: spec.provider.vault.auth.kubernetes.role + value: hub-role + + - it: should use isHubCluster=false when explicitly set, ignoring matching domains + set: + clusterGroup: + isHubCluster: false + global: + hubClusterDomain: "hub.example.com" + localClusterDomain: "hub.example.com" + clusterDomain: "spoke.example.com" + secretStore: + backend: "vault" + asserts: + - equal: + path: spec.provider.vault.auth.kubernetes.mountPath + value: spoke.example.com + - equal: + path: spec.provider.vault.auth.kubernetes.role + value: spoke.example.com-role + + # ============================================================================ + # Tests when clusterGroup.isHubCluster is UNSET + # These should fall back to domain comparison logic + # ============================================================================ + + - it: should detect hub cluster when localClusterDomain equals hubClusterDomain + set: + clusterGroup: + isHubCluster: null + global: + hubClusterDomain: "hub.example.com" + localClusterDomain: "hub.example.com" + clusterDomain: "hub.example.com" + secretStore: + backend: "vault" + asserts: + - equal: + path: spec.provider.vault.auth.kubernetes.mountPath + value: hub + - equal: + path: spec.provider.vault.auth.kubernetes.role + value: hub-role + + - it: should detect spoke cluster when localClusterDomain differs from hubClusterDomain + set: + clusterGroup: + isHubCluster: null + global: + hubClusterDomain: "hub.example.com" + localClusterDomain: "spoke.example.com" + clusterDomain: "spoke.example.com" + secretStore: + backend: "vault" + asserts: + - equal: + path: spec.provider.vault.auth.kubernetes.mountPath + value: spoke.example.com + - equal: + path: spec.provider.vault.auth.kubernetes.role + value: spoke.example.com-role + + - it: should detect hub cluster when localClusterDomain is not set (defaults to hubClusterDomain) + set: + clusterGroup: + isHubCluster: null + global: + hubClusterDomain: "hub.example.com" + clusterDomain: "hub.example.com" + secretStore: + backend: "vault" + asserts: + - equal: + path: spec.provider.vault.auth.kubernetes.mountPath + value: hub + - equal: + path: spec.provider.vault.auth.kubernetes.role + value: hub-role + + - it: should detect spoke cluster when only hubClusterDomain set and clusterDomain differs + set: + clusterGroup: + isHubCluster: null + global: + hubClusterDomain: "hub.example.com" + clusterDomain: "spoke.example.com" + secretStore: + backend: "vault" + asserts: + - equal: + path: spec.provider.vault.auth.kubernetes.mountPath + value: hub + - equal: + path: spec.provider.vault.auth.kubernetes.role + value: hub-role + + - it: should default to false (spoke) when hubClusterDomain is not set + set: + clusterGroup: + isHubCluster: null + global: + hubClusterDomain: null + localClusterDomain: "spoke.example.com" + clusterDomain: "spoke.example.com" + secretStore: + backend: "vault" + asserts: + - equal: + path: spec.provider.vault.auth.kubernetes.mountPath + value: spoke.example.com + - equal: + path: spec.provider.vault.auth.kubernetes.role + value: spoke.example.com-role + + - it: should default to false (spoke) when no domain configuration is provided + set: + clusterGroup: + isHubCluster: null + global: + hubClusterDomain: null + clusterDomain: "spoke.example.com" + secretStore: + backend: "vault" + asserts: + - equal: + path: spec.provider.vault.auth.kubernetes.mountPath + value: spoke.example.com + - equal: + path: spec.provider.vault.auth.kubernetes.role + value: spoke.example.com-role + + # ============================================================================ + # Tests for caProvider selection based on ishubcluster result + # ============================================================================ + + - it: should use hostCluster caProvider when detected as hub via domain match + set: + clusterGroup: + isHubCluster: null + global: + hubClusterDomain: "hub.example.com" + localClusterDomain: "hub.example.com" + clusterDomain: "hub.example.com" + secretStore: + backend: "vault" + ocpExternalSecrets: + caProvider: + enabled: true + asserts: + - equal: + path: spec.provider.vault.caProvider.type + value: ConfigMap + - equal: + path: spec.provider.vault.caProvider.name + value: kube-root-ca.crt + + - it: should use clientCluster caProvider when detected as spoke via domain mismatch + set: + clusterGroup: + isHubCluster: null + global: + hubClusterDomain: "hub.example.com" + localClusterDomain: "spoke.example.com" + clusterDomain: "spoke.example.com" + secretStore: + backend: "vault" + ocpExternalSecrets: + caProvider: + enabled: true + asserts: + - equal: + path: spec.provider.vault.caProvider.type + value: Secret + - equal: + path: spec.provider.vault.caProvider.name + value: hub-ca + + # ============================================================================ + # Edge cases for domain comparison + # ============================================================================ + + - it: should handle domains with subdomains correctly - matching + set: + clusterGroup: + isHubCluster: null + global: + hubClusterDomain: "hub.apps.cluster.example.com" + localClusterDomain: "hub.apps.cluster.example.com" + clusterDomain: "hub.apps.cluster.example.com" + secretStore: + backend: "vault" + asserts: + - equal: + path: spec.provider.vault.auth.kubernetes.mountPath + value: hub + + - it: should handle domains with subdomains correctly - not matching + set: + clusterGroup: + isHubCluster: null + global: + hubClusterDomain: "hub.apps.cluster.example.com" + localClusterDomain: "spoke.apps.cluster.example.com" + clusterDomain: "spoke.apps.cluster.example.com" + secretStore: + backend: "vault" + asserts: + - equal: + path: spec.provider.vault.auth.kubernetes.mountPath + value: spoke.apps.cluster.example.com + + - it: should treat empty localClusterDomain as unset (default to hubClusterDomain) + set: + clusterGroup: + isHubCluster: null + global: + hubClusterDomain: "hub.example.com" + localClusterDomain: "" + clusterDomain: "hub.example.com" + secretStore: + backend: "vault" + asserts: + - equal: + path: spec.provider.vault.auth.kubernetes.mountPath + value: hub + + - it: should handle empty hubClusterDomain as unset (default to false) + set: + clusterGroup: + isHubCluster: null + global: + hubClusterDomain: "" + localClusterDomain: "spoke.example.com" + clusterDomain: "spoke.example.com" + secretStore: + backend: "vault" + asserts: + - equal: + path: spec.provider.vault.auth.kubernetes.mountPath + value: spoke.example.com diff --git a/values.yaml b/values.yaml index 200642c..3df2bb1 100644 --- a/values.yaml +++ b/values.yaml @@ -70,5 +70,6 @@ global: backend: "vault" clusterGroup: + applications: {} # -- The variable that defines when a cluster is the HUB - isHubCluster: true + # (Deprecated) isHubCluster: true