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