Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ description: A Helm chart to configure Advanced Cluster Manager for OpenShift.
keywords:
- pattern
name: acm
version: 0.2.11
version: 0.2.12
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# acm

![Version: 0.2.11](https://img.shields.io/badge/Version-0.2.11-informational?style=flat-square)
![Version: 0.2.12](https://img.shields.io/badge/Version-0.2.12-informational?style=flat-square)

A Helm chart to configure Advanced Cluster Manager for OpenShift.

Expand All @@ -12,6 +12,7 @@ This chart is used by the Validated Patterns to configure ACM and manage remote
|-----|------|---------|-------------|
| acm.customArgoYaml | object | empty dict (no overrides) | Custom overrides for the spoke ArgoCD instance spec. Keys are deep-merged into the default spec (maps merge, lists replace). |
| acm.extraResourceHealthChecks | list | empty list | Extra resource health checks to add to the spoke ArgoCD instance. Each entry needs group, kind, and check (Lua script) fields. |
| acm.importedClusters | list | empty list (feature disabled) | Bring-your-own clusters to auto-import into ACM using kubeconfigs from Vault. Each entry needs secretName (must end with `_cluster_kubeconfig`) and clusterGroup (value for the ManagedCluster `clusterGroup` label). The ManagedCluster name is derived by stripping the `_cluster_kubeconfig` suffix from secretName. Example: - secretName: mcg-primary_cluster_kubeconfig clusterGroup: group-one |
| acm.mce_operator | object | Uses the official redhat sources | Just used for IIB testing, drives the source and channel for the MCE subscription triggered by ACM |
| acm.mch_spec | object | `{}` | MultiClusterHub spec (empty by default) |
| acm.spokeGitops.channel | string | `"gitops-1.21"` | Default gitops channel to install on remote clusters |
Expand Down
98 changes: 98 additions & 0 deletions templates/_helpers.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -470,3 +470,101 @@ sso:
tls:
ca: {}
{{- end }}

{{/*
Derive ManagedCluster name from a values-secret name by stripping _cluster_kubeconfig.
Fails if the secret name does not end with that suffix.
*/}}
{{- define "acm.imported.clusterName" -}}
{{- $secretName := . -}}
{{- $suffix := "_cluster_kubeconfig" -}}
{{- if not (hasSuffix $suffix $secretName) -}}
{{- fail (printf "acm.importedClusters secretName %q must end with %q" $secretName $suffix) -}}
{{- end -}}
{{- trimSuffix $suffix $secretName -}}
{{- end -}}

{{/*
Validate a single acm.importedClusters entry has secretName and clusterGroup.
*/}}
{{- define "acm.imported.validateEntry" -}}
{{- if or (not .secretName) (eq .secretName "") -}}
{{- fail "acm.importedClusters entry is missing required field secretName" -}}
{{- end -}}
{{- if or (not .clusterGroup) (eq .clusterGroup "") -}}
{{- fail (printf "acm.importedClusters entry for secretName %q is missing required field clusterGroup" .secretName) -}}
{{- end -}}
{{- end -}}

{{/*
Render a ManagedCluster used by both clusterDeployments and importedClusters.

Expected dict keys:
- name (required)
- labels (required map)
- syncOptions (optional; default includes SkipDryRunOnMissingResource + RespectIgnoreDifferences)
- leaseDurationSeconds (optional; default 60)
*/}}
{{- define "acm.managedCluster" -}}
apiVersion: cluster.open-cluster-management.io/v1
kind: ManagedCluster
metadata:
name: {{ .name }}
labels:
{{- range $k, $v := .labels }}
{{ $k }}: {{ $v }}
{{- end }}
annotations:
argocd.argoproj.io/sync-options: {{ .syncOptions | default "SkipDryRunOnMissingResource=true,RespectIgnoreDifferences=true" }}
spec:
hubAcceptsClient: true
leaseDurationSeconds: {{ .leaseDurationSeconds | default 60 }}
{{- end -}}

{{/*
Build ManagedCluster labels for a managedClusterGroups entry used by clusterDeployments.
Always sets clusterset to the group name. Uses acmlabels when present; otherwise
sets clusterGroup to the group name.
*/}}
{{- define "acm.managedCluster.labels.fromGroup" -}}
{{- $labels := dict "cluster.open-cluster-management.io/clusterset" .name -}}
{{- if or (not .acmlabels) (eq (len .acmlabels) 0) -}}
{{- $_ := set $labels "clusterGroup" .name -}}
{{- else -}}
{{- range .acmlabels -}}
{{- $_ := set $labels .name .value -}}
{{- end -}}
{{- end -}}
{{- mustToJson $labels -}}
{{- end -}}

{{/*
Render a KlusterletAddonConfig with ACM console-like default addons enabled.
Used by both clusterDeployments and importedClusters.

Expected dict keys:
- name (required; used for metadata name/namespace and spec.clusterName/clusterNamespace)
*/}}
{{- define "acm.klusterletAddonConfig" -}}
apiVersion: agent.open-cluster-management.io/v1
kind: KlusterletAddonConfig
metadata:
name: {{ .name }}
namespace: {{ .name }}
annotations:
argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true
spec:
clusterName: {{ .name }}
clusterNamespace: {{ .name }}
clusterLabels:
cloud: auto-detect
vendor: auto-detect
applicationManager:
enabled: true
policyController:
enabled: true
searchCollector:
enabled: true
certPolicyController:
enabled: true
{{- end -}}
23 changes: 4 additions & 19 deletions templates/provision/clusterdeployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -60,24 +60,9 @@ spec:
name: {{ $deploymentName }}-pull-secret

---
apiVersion: cluster.open-cluster-management.io/v1
kind: ManagedCluster
metadata:
labels:
cluster.open-cluster-management.io/clusterset: {{ $group.name }}
{{- if (not $group.acmlabels) }}
clusterGroup: {{ $group.name }}
{{- else if eq (len $group.acmlabels) 0 }}
clusterGroup: {{ $group.name }}
{{- else }}
{{- range $group.acmlabels }}
{{ .name }}: {{ .value }}
{{- end }}
{{- end }}
name: {{ $deploymentName }}
annotations:
argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true
spec:
hubAcceptsClient: true
{{- $mcLabels := include "acm.managedCluster.labels.fromGroup" $group | fromJson }}
{{ include "acm.managedCluster" (dict "name" $deploymentName "labels" $mcLabels) }}
---
{{ include "acm.klusterletAddonConfig" (dict "name" $deploymentName) }}
{{- end }}{{- /* range $group.clusterDeployments */}}
{{- end }}{{- /* range .Values.clusterGroup.managedClusterGroups */}}
43 changes: 43 additions & 0 deletions templates/provision/imported-clusters.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{{- range .Values.acm.importedClusters }}
{{- include "acm.imported.validateEntry" . }}
{{- $secretName := .secretName }}
{{- $clusterGroup := .clusterGroup }}
{{- $clusterName := include "acm.imported.clusterName" $secretName }}
---
apiVersion: v1
kind: Namespace
metadata:
name: {{ $clusterName }}
---
{{/* Only manage clusterGroup here. ACM overwrites cloud/vendor and adds discovery/addon labels after import. */}}
{{ include "acm.managedCluster" (dict "name" $clusterName "labels" (dict "clusterGroup" $clusterGroup)) }}
---
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: {{ $clusterName }}-auto-import
namespace: {{ $clusterName }}
annotations:
argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true
spec:
data:
- secretKey: kubeconfig
remoteRef:
key: secret/data/hub/{{ $secretName }}
property: kubeconfig
refreshInterval: 1h0m0s
secretStoreRef:
name: {{ $.Values.secretStore.name }}
kind: {{ $.Values.secretStore.kind }}
target:
name: auto-import-secret
creationPolicy: Owner
template:
type: Opaque
data:
autoImportRetry: "5"
kubeconfig: |-
{{ "{{ .kubeconfig | toString }}" }}
---
{{ include "acm.klusterletAddonConfig" (dict "name" $clusterName) }}
{{- end }}
49 changes: 39 additions & 10 deletions tests/clusterdeployment_test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ tests:
- hasDocuments:
count: 0

- it: should render Namespace, ClusterDeployment, and ManagedCluster for AWS
- it: should render Namespace, ClusterDeployment, ManagedCluster, and KlusterletAddonConfig for AWS
set:
clusterGroup:
managedClusterGroups:
Expand All @@ -30,7 +30,7 @@ tests:
region: us-east-1
asserts:
- hasDocuments:
count: 3
count: 4
- documentIndex: 0
isKind:
of: Namespace
Expand Down Expand Up @@ -81,6 +81,21 @@ tests:
equal:
path: spec.pullSecretRef.name
value: cluster1-region-one-pull-secret
- documentIndex: 3
isKind:
of: KlusterletAddonConfig
- documentIndex: 3
equal:
path: metadata.name
value: cluster1-region-one
- documentIndex: 3
equal:
path: metadata.namespace
value: cluster1-region-one
- documentIndex: 3
equal:
path: spec.policyController.enabled
value: true

- it: should render correctly for Azure platform
set:
Expand All @@ -99,7 +114,7 @@ tests:
region: eastus
asserts:
- hasDocuments:
count: 3
count: 4
- documentIndex: 1
equal:
path: spec.platform.azure.region
Expand Down Expand Up @@ -139,6 +154,14 @@ tests:
equal:
path: spec.hubAcceptsClient
value: true
- documentIndex: 2
equal:
path: spec.leaseDurationSeconds
value: 60
- documentIndex: 2
equal:
path: metadata.annotations["argocd.argoproj.io/sync-options"]
value: SkipDryRunOnMissingResource=true,RespectIgnoreDifferences=true

- it: should use acmlabels on ManagedCluster when specified as list
set:
Expand Down Expand Up @@ -213,7 +236,7 @@ tests:
region: us-west-2
asserts:
- hasDocuments:
count: 6
count: 8

- it: should render resources for multiple managedClusterGroups
set:
Expand Down Expand Up @@ -242,7 +265,7 @@ tests:
region: westus2
asserts:
- hasDocuments:
count: 6
count: 8
- documentIndex: 0
isKind:
of: Namespace
Expand All @@ -265,23 +288,29 @@ tests:
path: metadata.labels["cluster.open-cluster-management.io/clusterset"]
value: east
- documentIndex: 3
isKind:
of: KlusterletAddonConfig
- documentIndex: 4
isKind:
of: Namespace
- documentIndex: 3
- documentIndex: 4
equal:
path: metadata.name
value: cluster-west-west
- documentIndex: 4
- documentIndex: 5
isKind:
of: ClusterDeployment
- documentIndex: 4
- documentIndex: 5
equal:
path: spec.platform.azure.region
value: westus2
- documentIndex: 5
- documentIndex: 6
isKind:
of: ManagedCluster
- documentIndex: 5
- documentIndex: 6
equal:
path: metadata.labels["cluster.open-cluster-management.io/clusterset"]
value: west
- documentIndex: 7
isKind:
of: KlusterletAddonConfig
Loading
Loading