From b9383241ea857802e85e2a41badbd4d174ac2b0d Mon Sep 17 00:00:00 2001 From: Michele Baldessari Date: Wed, 19 Nov 2025 16:32:21 +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 | 23 +++ templates/policies/acm-hub-ca-policy.yaml | 4 +- templates/policies/private-repo-policies.yaml | 4 +- ...hub_cluster_additional_scenarios_test.yaml | 140 ++++++++++++++++ ...b_cluster_detection_private_repo_test.yaml | 130 +++++++++++++++ tests/hub_cluster_detection_test.yaml | 155 ++++++++++++++++++ values.yaml | 4 + 7 files changed, 456 insertions(+), 4 deletions(-) create mode 100644 tests/hub_cluster_additional_scenarios_test.yaml create mode 100644 tests/hub_cluster_detection_private_repo_test.yaml create mode 100644 tests/hub_cluster_detection_test.yaml diff --git a/templates/_helpers.tpl b/templates/_helpers.tpl index 606b13d..ed0d518 100644 --- a/templates/_helpers.tpl +++ b/templates/_helpers.tpl @@ -196,3 +196,26 @@ health_status.status = "Progressing" health_status.message = "An install plan for a subscription is pending installation" return health_status {{- end }} {{- /*acm.subscription.healthcheck.lua */}} + +{{/* +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 "acm.ishubcluster" . }} +Returns: "true" or "false" as a string +*/}} +{{- define "acm.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/policies/acm-hub-ca-policy.yaml b/templates/policies/acm-hub-ca-policy.yaml index 143e7d4..9612814 100644 --- a/templates/policies/acm-hub-ca-policy.yaml +++ b/templates/policies/acm-hub-ca-policy.yaml @@ -1,5 +1,5 @@ # This pushes out the HUB's Certificate Authorities on to the imported clusters -{{- if .Values.clusterGroup.isHubCluster }} +{{- if eq (include "acm.ishubcluster" .) "true" }} {{- range .Values.clusterGroup.managedClusterGroups }} {{- $group := . }} --- @@ -217,4 +217,4 @@ spec: {{- end }}{{/* if (eq ((($.Values.global).secretStore).backend) "vault") */}} {{- end }}{{/* range .Values.clusterGroup.managedClusterGroups */}} -{{- end }}{{/* isHubCluster */}} +{{- end }}{{/* ishubcluster */}} diff --git a/templates/policies/private-repo-policies.yaml b/templates/policies/private-repo-policies.yaml index 007d683..aa86b9f 100644 --- a/templates/policies/private-repo-policies.yaml +++ b/templates/policies/private-repo-policies.yaml @@ -84,7 +84,7 @@ spec: "group" $group ) | nindent 2 }} {{- end }}{{- /* range .Values.clusterGroup.managedClusterGroups */}} -{{ if $.Values.clusterGroup.isHubCluster }} +{{ if eq (include "acm.ishubcluster" $) "true" }} --- apiVersion: policy.open-cluster-management.io/v1 kind: Policy @@ -153,5 +153,5 @@ spec: values: - 'true' --- -{{ end }}{{- /* if .Values.clusterGroup.isHubCluster */}} +{{ end }}{{- /* if ishubcluster */}} {{- end }}{{- /* if $.Values.global.privateRepo */}} diff --git a/tests/hub_cluster_additional_scenarios_test.yaml b/tests/hub_cluster_additional_scenarios_test.yaml new file mode 100644 index 0000000..13a5b6e --- /dev/null +++ b/tests/hub_cluster_additional_scenarios_test.yaml @@ -0,0 +1,140 @@ +suite: Test Hub Cluster Detection Additional Scenarios +templates: + - templates/policies/acm-hub-ca-policy.yaml +release: + name: release-test +tests: + # Test subdomain variations (domain-based detection) + - it: should differentiate between similar domains + set: + global: + repoURL: https://github.com/test/repo + hubClusterDomain: "apps.hub.example.com" + localClusterDomain: "apps.hub-spoke.example.com" # Similar but different + secretStore: + backend: "vault" + pattern: "test-pattern" + clusterGroup: + isHubCluster: null # Explicitly unset to enable domain-based detection + managedClusterGroups: + test: + name: test-cluster + asserts: + - hasDocuments: + count: 0 + + # Test with special characters (domain-based detection) + - it: should handle domains with special characters + set: + global: + repoURL: https://github.com/test/repo + hubClusterDomain: "apps.hub-cluster_1.example-domain.com" + localClusterDomain: "apps.hub-cluster_1.example-domain.com" + secretStore: + backend: "vault" + pattern: "test-pattern" + clusterGroup: + isHubCluster: null # Explicitly unset to enable domain-based detection + managedClusterGroups: + test: + name: test-cluster + asserts: + - hasDocuments: + count: 9 + + # Test with missing managedClusterGroups + - it: should handle missing managedClusterGroups gracefully + set: + global: + repoURL: https://github.com/test/repo + hubClusterDomain: "apps.hub.example.com" + localClusterDomain: "apps.hub.example.com" + secretStore: + backend: "vault" + pattern: "test-pattern" + clusterGroup: + isHubCluster: null # Explicitly unset to enable domain-based detection + managedClusterGroups: null # Explicitly unset + asserts: + - hasDocuments: + count: 0 # No managed cluster groups means no policies + + # Test with empty managedClusterGroups + - it: should handle empty managedClusterGroups + set: + global: + repoURL: https://github.com/test/repo + hubClusterDomain: "apps.hub.example.com" + localClusterDomain: "apps.hub.example.com" + secretStore: + backend: "vault" + pattern: "test-pattern" + clusterGroup: + isHubCluster: null # Explicitly unset to enable domain-based detection + managedClusterGroups: {} # Empty + asserts: + - hasDocuments: + count: 0 # Empty managed cluster groups means no policies + + # Test explicit isHubCluster takes precedence over domain-based detection + - it: should respect explicit isHubCluster even when domains match + set: + global: + repoURL: https://github.com/test/migration + hubClusterDomain: "apps.migration-hub.example.com" + localClusterDomain: "apps.migration-hub.example.com" + secretStore: + backend: "vault" + pattern: "migration-test" + clusterGroup: + # Explicit isHubCluster takes precedence over domain-based detection + isHubCluster: false # Explicitly set to false, should be respected + managedClusterGroups: + migrationTarget: + name: migration-target + labels: + - name: migration + value: in-progress + asserts: + # Explicit isHubCluster: false is respected even though domains match + - hasDocuments: + count: 0 + + # Test multiple cluster groups with domain-based logic (no explicit isHubCluster) + - it: should handle multiple cluster groups with domain-based hub detection + set: + global: + repoURL: https://github.com/test/multi-cluster + hubClusterDomain: "apps.prod-hub.company.com" + localClusterDomain: "apps.prod-hub.company.com" + secretStore: + backend: "vault" + pattern: "multi-cluster-test" + clusterGroup: + isHubCluster: null # Explicitly unset to enable domain-based detection + managedClusterGroups: + prodEast: + name: prod-east + labels: + - name: environment + value: production + stagingWest: + name: staging-west + labels: + - name: environment + value: staging + asserts: + # Should have CA policies for 2 cluster groups (9 docs each) + - hasDocuments: + count: 18 + # Verify specific policies exist + - documentSelector: + path: metadata.name + value: hub-argo-ca-prod-east-policy + isKind: + of: Policy + - documentSelector: + path: metadata.name + value: hub-argo-ca-staging-west-policy + isKind: + of: Policy diff --git a/tests/hub_cluster_detection_private_repo_test.yaml b/tests/hub_cluster_detection_private_repo_test.yaml new file mode 100644 index 0000000..ba67a64 --- /dev/null +++ b/tests/hub_cluster_detection_private_repo_test.yaml @@ -0,0 +1,130 @@ +suite: Test Hub Cluster Detection Logic - Private Repo Policies +templates: + - templates/policies/private-repo-policies.yaml +release: + name: release-test +tests: + # Test 1: Hub cluster when localClusterDomain equals hubClusterDomain (includes private hub policy) + - it: should render private hub policy when localClusterDomain equals hubClusterDomain + set: + global: + repoURL: https://github.com/validatedpatterns/multicloud-gitops + hubClusterDomain: "apps.hub.example.com" + localClusterDomain: "apps.hub.example.com" + privateRepo: true + pattern: "test-pattern" + clusterGroup: + isHubCluster: null # Explicitly unset to enable domain-based detection + managedClusterGroups: + testRegion: + name: region-one + labels: + - name: clusterGroup + value: region-one + asserts: + - documentSelector: + path: metadata.name + value: vp-private-hub-policy + isKind: + of: Policy + - hasDocuments: + count: 6 + + # Test 2: Not hub cluster when localClusterDomain differs from hubClusterDomain (no private hub policy) + - it: should not render private hub policy when localClusterDomain differs from hubClusterDomain + set: + global: + repoURL: https://github.com/validatedpatterns/multicloud-gitops + hubClusterDomain: "apps.hub.example.com" + localClusterDomain: "apps.spoke.example.com" + privateRepo: true + pattern: "test-pattern" + clusterGroup: + isHubCluster: null # Explicitly unset to enable domain-based detection + managedClusterGroups: + testRegion: + name: region-one + labels: + - name: clusterGroup + value: region-one + asserts: + # Should have the managed cluster policies but not the hub policy + - documentSelector: + path: metadata.name + value: private-region-one-policy + isKind: + of: Policy + - hasDocuments: + count: 3 + + # Test 3: Fallback to isHubCluster when domains are not set (true) + - it: should render private hub policy when fallback to isHubCluster true + set: + global: + repoURL: https://github.com/validatedpatterns/multicloud-gitops + # No domain configuration provided + privateRepo: true + pattern: "test-pattern" + clusterGroup: + isHubCluster: true + managedClusterGroups: + testRegion: + name: region-one + labels: + - name: clusterGroup + value: region-one + asserts: + - documentSelector: + path: metadata.name + value: vp-private-hub-policy + isKind: + of: Policy + - hasDocuments: + count: 6 + + # Test 4: Fallback to isHubCluster false when no domain configuration is provided + - it: should not render private hub policy when fallback to isHubCluster false + set: + global: + repoURL: https://github.com/validatedpatterns/multicloud-gitops + # No domain configuration provided + privateRepo: true + pattern: "test-pattern" + clusterGroup: + isHubCluster: false + managedClusterGroups: + testRegion: + name: region-one + labels: + - name: clusterGroup + value: region-one + asserts: + # Should have the managed cluster policies but not the hub policy + - documentSelector: + path: metadata.name + value: private-region-one-policy + isKind: + of: Policy + - hasDocuments: + count: 3 + + # Test 5: No policies when privateRepo is false + - it: should not render any private repo policies when privateRepo is false + set: + global: + repoURL: https://github.com/validatedpatterns/multicloud-gitops + hubClusterDomain: "apps.hub.example.com" + localClusterDomain: "apps.hub.example.com" + privateRepo: false + pattern: "test-pattern" + clusterGroup: + isHubCluster: true + managedClusterGroups: + testRegion: + name: region-one + labels: + - name: clusterGroup + value: region-one + asserts: + - hasDocuments: + count: 0 \ No newline at end of file diff --git a/tests/hub_cluster_detection_test.yaml b/tests/hub_cluster_detection_test.yaml new file mode 100644 index 0000000..1e342aa --- /dev/null +++ b/tests/hub_cluster_detection_test.yaml @@ -0,0 +1,155 @@ +suite: Test Hub Cluster Detection Logic +templates: + - templates/policies/acm-hub-ca-policy.yaml +release: + name: release-test +tests: + # Test 1: Hub cluster when localClusterDomain equals hubClusterDomain + - it: should render acm hub ca policy when localClusterDomain equals hubClusterDomain + set: + global: + repoURL: https://github.com/validatedpatterns/multicloud-gitops + hubClusterDomain: "apps.hub.example.com" + localClusterDomain: "apps.hub.example.com" + secretStore: + backend: "vault" + pattern: "test-pattern" + clusterGroup: + isHubCluster: null # Explicitly unset to enable domain-based detection + managedClusterGroups: + testRegion: + name: region-one + labels: + - name: clusterGroup + value: region-one + asserts: + - documentSelector: + path: metadata.name + value: hub-argo-ca-region-one-policy + isKind: + of: Policy + - hasDocuments: + count: 9 + + # Test 2: Not hub cluster when localClusterDomain differs from hubClusterDomain + - it: should not render acm hub ca policy when localClusterDomain differs from hubClusterDomain + set: + global: + repoURL: https://github.com/validatedpatterns/multicloud-gitops + hubClusterDomain: "apps.hub.example.com" + localClusterDomain: "apps.spoke.example.com" + secretStore: + backend: "vault" + pattern: "test-pattern" + clusterGroup: + isHubCluster: null # Explicitly unset to enable domain-based detection + managedClusterGroups: + testRegion: + name: region-one + labels: + - name: clusterGroup + value: region-one + asserts: + - hasDocuments: + count: 0 + + # Test 3: Hub cluster when localClusterDomain is unset (defaults to hubClusterDomain) + - it: should render acm hub ca policy when localClusterDomain is unset (defaults to hubClusterDomain) + set: + global: + repoURL: https://github.com/validatedpatterns/multicloud-gitops + hubClusterDomain: "apps.hub.example.com" + # localClusterDomain is intentionally not set + secretStore: + backend: "vault" + pattern: "test-pattern" + clusterGroup: + isHubCluster: null # Explicitly unset to enable domain-based detection + managedClusterGroups: + testRegion: + name: region-one + labels: + - name: clusterGroup + value: region-one + asserts: + - documentSelector: + path: metadata.name + value: hub-argo-ca-region-one-policy + isKind: + of: Policy + - hasDocuments: + count: 9 + + # Test 4: Explicit isHubCluster true takes precedence when set + - it: should use explicit isHubCluster true when no domain configuration is provided + set: + global: + repoURL: https://github.com/validatedpatterns/multicloud-gitops + # No domain configuration provided + secretStore: + backend: "vault" + pattern: "test-pattern" + clusterGroup: + isHubCluster: true # Explicit setting takes precedence + managedClusterGroups: + testRegion: + name: region-one + labels: + - name: clusterGroup + value: region-one + asserts: + - documentSelector: + path: metadata.name + value: hub-argo-ca-region-one-policy + isKind: + of: Policy + - hasDocuments: + count: 9 + + # Test 5: Explicit isHubCluster false takes precedence when set + - it: should use explicit isHubCluster false when no domain configuration is provided + set: + global: + repoURL: https://github.com/validatedpatterns/multicloud-gitops + # No domain configuration provided + secretStore: + backend: "vault" + pattern: "test-pattern" + clusterGroup: + isHubCluster: false # Explicit setting takes precedence + managedClusterGroups: + testRegion: + name: region-one + labels: + - name: clusterGroup + value: region-one + asserts: + - hasDocuments: + count: 0 + + # Test 6: Hub cluster detection with only hubClusterDomain set (no explicit isHubCluster) + - it: should detect hub cluster when only hubClusterDomain is provided + set: + global: + repoURL: https://github.com/validatedpatterns/multicloud-gitops + hubClusterDomain: "apps.hub.example.com" + # localClusterDomain intentionally not set, should default to hubClusterDomain + secretStore: + backend: "vault" + pattern: "test-pattern" + clusterGroup: + isHubCluster: null # Explicitly unset to enable domain-based detection + managedClusterGroups: + testRegion: + name: region-one + labels: + - name: clusterGroup + value: region-one + asserts: + - documentSelector: + path: metadata.name + value: hub-argo-ca-region-one-policy + isKind: + of: Policy + - hasDocuments: + count: 9 \ No newline at end of file diff --git a/values.yaml b/values.yaml index 2d81d26..29520ff 100644 --- a/values.yaml +++ b/values.yaml @@ -20,6 +20,10 @@ global: # -- Dictionary of all the clustergroups of the pattern # @default -- depends on the individual settings clusterGroup: + # DEPRECATED: isHubCluster is deprecated. Use global.localClusterDomain and global.hubClusterDomain instead. + # When both domain values are set, hub cluster detection will be based on whether they are equal. + # This field is kept for backwards compatibility when domain values are not set. + # isHubCluster: true # -- Dictionary of subscriptions for this specific clusterGroup subscriptions: # -- Name of the subscription