Browse Source

feat(charts): add global values for common deployment configurations (#5652)

Gabriel Melo 4 months ago
parent
commit
0e22d748e4

+ 4 - 0
deploy/charts/external-secrets/README.md

@@ -117,7 +117,11 @@ The command removes all the Kubernetes components associated with the chart and
 | genericTargets.resources | list | `[]` | List of additional resource types to grant permissions for. Each entry should specify apiGroup, resources, and verbs. Example: resources:   - apiGroup: "argoproj.io"     resources: ["applications"]     verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] |
 | global.affinity | object | `{}` |  |
 | global.compatibility.openshift.adaptSecurityContext | string | `"auto"` | Manages the securityContext properties to make them compatible with OpenShift. Possible values: auto - Apply configurations if it is detected that OpenShift is the target platform. force - Always apply configurations. disabled - No modification applied. |
+| global.imagePullSecrets | list | `[]` | Global imagePullSecrets to be applied to all deployments |
 | global.nodeSelector | object | `{}` |  |
+| global.podAnnotations | object | `{}` | Global pod annotations to be applied to all deployments |
+| global.podLabels | object | `{}` | Global pod labels to be applied to all deployments |
+| global.repository | string | `""` | Global image repository to be applied to all deployments |
 | global.tolerations | list | `[]` |  |
 | global.topologySpreadConstraints | list | `[]` |  |
 | grafanaDashboard.annotations | object | `{}` | Annotations that ConfigMaps can have to get configured in Grafana, See: sidecar.dashboards.folderAnnotation for specifying the dashboard folder. https://github.com/grafana/helm-charts/tree/main/charts/grafana |

+ 8 - 2
deploy/charts/external-secrets/templates/_helpers.tpl

@@ -173,10 +173,16 @@ Create the name of the service account to use
 Determine the image to use, including if using a flavour.
 */}}
 {{- define "external-secrets.image" -}}
+{{- $repository := "" -}}
+{{- if .context.Values.global.repository -}}
+{{- $repository = .context.Values.global.repository -}}
+{{- else -}}
+{{- $repository = .image.repository -}}
+{{- end -}}
 {{- if .image.flavour -}}
-{{ printf "%s:%s-%s" .image.repository (.image.tag | default .chartAppVersion) .image.flavour }}
+{{ printf "%s:%s-%s" $repository (.image.tag | default .chartAppVersion) .image.flavour }}
 {{- else }}
-{{ printf "%s:%s" .image.repository (.image.tag | default .chartAppVersion) }}
+{{ printf "%s:%s" $repository (.image.tag | default .chartAppVersion) }}
 {{- end }}
 {{- end }}
 

+ 15 - 7
deploy/charts/external-secrets/templates/cert-controller-deployment.yaml

@@ -22,19 +22,27 @@ spec:
   {{- end }}
   template:
     metadata:
-      {{- with .Values.certController.podAnnotations }}
+      {{- if .Values.certController.podAnnotations }}
       annotations:
-        {{- toYaml . | nindent 8 }}
+        {{- toYaml .Values.certController.podAnnotations | nindent 8 }}
+      {{- else if .Values.global.podAnnotations }}
+      annotations:
+        {{- toYaml .Values.global.podAnnotations | nindent 8 }}
       {{- end }}
       labels:
         {{- include "external-secrets-cert-controller.labels" . | nindent 8 }}
-        {{- with .Values.certController.podLabels }}
-          {{- toYaml . | nindent 8 }}
+        {{- if .Values.certController.podLabels }}
+        {{- toYaml .Values.certController.podLabels | nindent 8 }}
+        {{- else if .Values.global.podLabels }}
+        {{- toYaml .Values.global.podLabels | nindent 8 }}
         {{- end }}
     spec:
-      {{- with .Values.certController.imagePullSecrets }}
+      {{- if .Values.certController.imagePullSecrets }}
       imagePullSecrets:
-        {{- toYaml . | nindent 8 }}
+        {{- toYaml .Values.certController.imagePullSecrets | nindent 8 }}
+      {{- else if .Values.global.imagePullSecrets }}
+      imagePullSecrets:
+        {{- toYaml .Values.global.imagePullSecrets | nindent 8 }}
       {{- end }}
       serviceAccountName: {{ include "external-secrets-cert-controller.serviceAccountName" . }}
       automountServiceAccountToken: {{ .Values.certController.serviceAccount.automount }}
@@ -53,7 +61,7 @@ spec:
             {{- include "external-secrets.renderSecurityContext" (dict "securityContext" . "context" $) | nindent 12 }}
           {{- end }}
           {{- end }}
-          image: {{ include "external-secrets.image" (dict "chartAppVersion" .Chart.AppVersion "image" .Values.certController.image) | trim }}
+          image: {{ include "external-secrets.image" (dict "chartAppVersion" .Chart.AppVersion "image" .Values.certController.image "context" .) | trim }}
           imagePullPolicy: {{ .Values.certController.image.pullPolicy }}
           args:
           - certcontroller

+ 15 - 7
deploy/charts/external-secrets/templates/deployment.yaml

@@ -23,19 +23,27 @@ spec:
   {{- end }}
   template:
     metadata:
-      {{- with .Values.podAnnotations }}
+      {{- if .Values.podAnnotations }}
       annotations:
-        {{- toYaml . | nindent 8 }}
+        {{- toYaml .Values.podAnnotations | nindent 8 }}
+      {{- else if .Values.global.podAnnotations }}
+      annotations:
+        {{- toYaml .Values.global.podAnnotations | nindent 8 }}
       {{- end }}
       labels:
         {{- include "external-secrets.labels" . | nindent 8 }}
-        {{- with .Values.podLabels }}
-          {{- toYaml . | nindent 8 }}
+        {{- if .Values.podLabels }}
+        {{- toYaml .Values.podLabels | nindent 8 }}
+        {{- else if .Values.global.podLabels }}
+        {{- toYaml .Values.global.podLabels | nindent 8 }}
         {{- end }}
     spec:
-      {{- with .Values.imagePullSecrets }}
+      {{- if .Values.imagePullSecrets }}
       imagePullSecrets:
-        {{- toYaml . | nindent 8 }}
+        {{- toYaml .Values.imagePullSecrets | nindent 8 }}
+      {{- else if .Values.global.imagePullSecrets }}
+      imagePullSecrets:
+        {{- toYaml .Values.global.imagePullSecrets | nindent 8 }}
       {{- end }}
       serviceAccountName: {{ include "external-secrets.serviceAccountName" . }}
       automountServiceAccountToken: {{ .Values.serviceAccount.automount }}
@@ -54,7 +62,7 @@ spec:
             {{- include "external-secrets.renderSecurityContext" (dict "securityContext" . "context" $) | nindent 12 }}
           {{- end }}
           {{- end }}
-          image: {{ include "external-secrets.image" (dict "chartAppVersion" .Chart.AppVersion "image" .Values.image) | trim }}
+          image: {{ include "external-secrets.image" (dict "chartAppVersion" .Chart.AppVersion "image" .Values.image "context" .) | trim }}
           imagePullPolicy: {{ .Values.image.pullPolicy }}
           {{- if or (.Values.leaderElect) (.Values.scopedNamespace) (.Values.processClusterStore) (.Values.processClusterExternalSecret) (.Values.processClusterPushSecret) (.Values.concurrent) (.Values.extraArgs) }}
           args:

+ 15 - 7
deploy/charts/external-secrets/templates/webhook-deployment.yaml

@@ -22,19 +22,27 @@ spec:
   {{- end }}
   template:
     metadata:
-      {{- with .Values.webhook.podAnnotations }}
+      {{- if .Values.webhook.podAnnotations }}
       annotations:
-        {{- toYaml . | nindent 8 }}
+        {{- toYaml .Values.webhook.podAnnotations | nindent 8 }}
+      {{- else if .Values.global.podAnnotations }}
+      annotations:
+        {{- toYaml .Values.global.podAnnotations | nindent 8 }}
       {{- end }}
       labels:
         {{- include "external-secrets-webhook.labels" . | nindent 8 }}
-        {{- with .Values.webhook.podLabels }}
-          {{- toYaml . | nindent 8 }}
+        {{- if .Values.webhook.podLabels }}
+        {{- toYaml .Values.webhook.podLabels | nindent 8 }}
+        {{- else if .Values.global.podLabels }}
+        {{- toYaml .Values.global.podLabels | nindent 8 }}
         {{- end }}
     spec:
-      {{- with .Values.webhook.imagePullSecrets }}
+      {{- if .Values.webhook.imagePullSecrets }}
       imagePullSecrets:
-        {{- toYaml . | nindent 8 }}
+        {{- toYaml .Values.webhook.imagePullSecrets | nindent 8 }}
+      {{- else if .Values.global.imagePullSecrets }}
+      imagePullSecrets:
+        {{- toYaml .Values.global.imagePullSecrets | nindent 8 }}
       {{- end }}
       hostNetwork: {{ .Values.webhook.hostNetwork}}
       serviceAccountName: {{ include "external-secrets-webhook.serviceAccountName" . }}
@@ -53,7 +61,7 @@ spec:
             {{- include "external-secrets.renderSecurityContext" (dict "securityContext" . "context" $) | nindent 12 }}
           {{- end }}
           {{- end }}
-          image: {{ include "external-secrets.image" (dict "chartAppVersion" .Chart.AppVersion "image" .Values.webhook.image) | trim }}
+          image: {{ include "external-secrets.image" (dict "chartAppVersion" .Chart.AppVersion "image" .Values.webhook.image "context" .) | trim }}
           imagePullPolicy: {{ .Values.webhook.image.pullPolicy }}
           args:
           - webhook

+ 67 - 0
deploy/charts/external-secrets/tests/global_values_schema_test.yaml

@@ -0,0 +1,67 @@
+suite: test global values schema validation
+# This test validates that the JSON schema correctly defines the new global values
+templates:
+  - deployment.yaml
+tests:
+  - it: should accept valid global.podLabels
+    set:
+      global.podLabels:
+        app: "myapp"
+        environment: "production"
+    asserts:
+      - isKind:
+          of: Deployment
+
+  - it: should accept valid global.podAnnotations
+    set:
+      global.podAnnotations:
+        prometheus.io/scrape: "true"
+        custom-annotation: "value"
+    asserts:
+      - isKind:
+          of: Deployment
+
+  - it: should accept valid global.imagePullSecrets
+    set:
+      global.imagePullSecrets:
+        - name: "my-registry-secret"
+        - name: "another-secret"
+    asserts:
+      - isKind:
+          of: Deployment
+
+  - it: should accept valid global.repository as string
+    set:
+      global.repository: "my-registry.io/org/external-secrets"
+    asserts:
+      - isKind:
+          of: Deployment
+
+  - it: should accept empty global.repository string
+    set:
+      global.repository: ""
+    asserts:
+      - isKind:
+          of: Deployment
+
+  - it: should accept all global values together
+    set:
+      global.repository: "my-registry.io/org/external-secrets"
+      global.imagePullSecrets:
+        - name: "global-secret"
+      global.podLabels:
+        team: "platform"
+      global.podAnnotations:
+        version: "1.0.0"
+    asserts:
+      - isKind:
+          of: Deployment
+      - equal:
+          path: spec.template.metadata.labels.team
+          value: "platform"
+      - equal:
+          path: spec.template.metadata.annotations.version
+          value: "1.0.0"
+      - equal:
+          path: spec.template.spec.imagePullSecrets[0].name
+          value: "global-secret"

+ 376 - 0
deploy/charts/external-secrets/tests/global_values_test.yaml

@@ -0,0 +1,376 @@
+suite: test global values
+# This test suite validates the global values functionality for:
+# - global.podLabels: Global pod labels applied to all deployments
+# - global.podAnnotations: Global pod annotations applied to all deployments
+# - global.imagePullSecrets: Global image pull secrets applied to all deployments
+# - global.repository: Global image repository applied to all deployments
+#
+# Test coverage:
+# 1. Verify global values are used when local values are not set
+# 2. Verify local values take precedence over global values
+# 3. Verify all three deployments (controller, webhook, cert-controller) respect the logic
+# 4. Verify combined scenarios with multiple global values
+templates:
+  - deployment.yaml
+  - webhook-deployment.yaml
+  - cert-controller-deployment.yaml
+tests:
+  # Test global.podLabels
+  - it: should use global podLabels when local podLabels not set (controller)
+    template: deployment.yaml
+    set:
+      global.podLabels:
+        globalLabel: "global-value"
+        environment: "production"
+    asserts:
+      - equal:
+          path: spec.template.metadata.labels.globalLabel
+          value: "global-value"
+      - equal:
+          path: spec.template.metadata.labels.environment
+          value: "production"
+
+  - it: should use local podLabels over global podLabels (controller)
+    template: deployment.yaml
+    set:
+      global.podLabels:
+        globalLabel: "global-value"
+      podLabels:
+        localLabel: "local-value"
+    asserts:
+      - equal:
+          path: spec.template.metadata.labels.localLabel
+          value: "local-value"
+      - notExists:
+          path: spec.template.metadata.labels.globalLabel
+
+  - it: should use global podLabels when local podLabels not set (webhook)
+    template: webhook-deployment.yaml
+    set:
+      global.podLabels:
+        globalLabel: "global-value"
+        environment: "production"
+    asserts:
+      - equal:
+          path: spec.template.metadata.labels.globalLabel
+          value: "global-value"
+      - equal:
+          path: spec.template.metadata.labels.environment
+          value: "production"
+
+  - it: should use local podLabels over global podLabels (webhook)
+    template: webhook-deployment.yaml
+    set:
+      global.podLabels:
+        globalLabel: "global-value"
+      webhook.podLabels:
+        localLabel: "local-value"
+    asserts:
+      - equal:
+          path: spec.template.metadata.labels.localLabel
+          value: "local-value"
+      - notExists:
+          path: spec.template.metadata.labels.globalLabel
+
+  - it: should use global podLabels when local podLabels not set (cert-controller)
+    template: cert-controller-deployment.yaml
+    set:
+      global.podLabels:
+        globalLabel: "global-value"
+        environment: "production"
+    asserts:
+      - equal:
+          path: spec.template.metadata.labels.globalLabel
+          value: "global-value"
+      - equal:
+          path: spec.template.metadata.labels.environment
+          value: "production"
+
+  - it: should use local podLabels over global podLabels (cert-controller)
+    template: cert-controller-deployment.yaml
+    set:
+      global.podLabels:
+        globalLabel: "global-value"
+      certController.podLabels:
+        localLabel: "local-value"
+    asserts:
+      - equal:
+          path: spec.template.metadata.labels.localLabel
+          value: "local-value"
+      - notExists:
+          path: spec.template.metadata.labels.globalLabel
+
+  # Test global.podAnnotations
+  - it: should use global podAnnotations when local podAnnotations not set (controller)
+    template: deployment.yaml
+    set:
+      global.podAnnotations:
+        globalAnnotation: "global-value"
+        environment: "production"
+    asserts:
+      - equal:
+          path: spec.template.metadata.annotations.globalAnnotation
+          value: "global-value"
+      - equal:
+          path: spec.template.metadata.annotations.environment
+          value: "production"
+
+  - it: should use local podAnnotations over global podAnnotations (controller)
+    template: deployment.yaml
+    set:
+      global.podAnnotations:
+        globalAnnotation: "global-value"
+      podAnnotations:
+        localAnnotation: "local-value"
+    asserts:
+      - equal:
+          path: spec.template.metadata.annotations.localAnnotation
+          value: "local-value"
+      - notExists:
+          path: spec.template.metadata.annotations.globalAnnotation
+
+  - it: should use global podAnnotations when local podAnnotations not set (webhook)
+    template: webhook-deployment.yaml
+    set:
+      global.podAnnotations:
+        globalAnnotation: "global-value"
+        environment: "production"
+    asserts:
+      - equal:
+          path: spec.template.metadata.annotations.globalAnnotation
+          value: "global-value"
+      - equal:
+          path: spec.template.metadata.annotations.environment
+          value: "production"
+
+  - it: should use local podAnnotations over global podAnnotations (webhook)
+    template: webhook-deployment.yaml
+    set:
+      global.podAnnotations:
+        globalAnnotation: "global-value"
+      webhook.podAnnotations:
+        localAnnotation: "local-value"
+    asserts:
+      - equal:
+          path: spec.template.metadata.annotations.localAnnotation
+          value: "local-value"
+      - notExists:
+          path: spec.template.metadata.annotations.globalAnnotation
+
+  - it: should use global podAnnotations when local podAnnotations not set (cert-controller)
+    template: cert-controller-deployment.yaml
+    set:
+      global.podAnnotations:
+        globalAnnotation: "global-value"
+        environment: "production"
+    asserts:
+      - equal:
+          path: spec.template.metadata.annotations.globalAnnotation
+          value: "global-value"
+      - equal:
+          path: spec.template.metadata.annotations.environment
+          value: "production"
+
+  - it: should use local podAnnotations over global podAnnotations (cert-controller)
+    template: cert-controller-deployment.yaml
+    set:
+      global.podAnnotations:
+        globalAnnotation: "global-value"
+      certController.podAnnotations:
+        localAnnotation: "local-value"
+    asserts:
+      - equal:
+          path: spec.template.metadata.annotations.localAnnotation
+          value: "local-value"
+      - notExists:
+          path: spec.template.metadata.annotations.globalAnnotation
+
+  # Test global.imagePullSecrets
+  - it: should use global imagePullSecrets when local imagePullSecrets not set (controller)
+    template: deployment.yaml
+    set:
+      global.imagePullSecrets:
+        - name: global-registry-secret
+        - name: another-global-secret
+      imagePullSecrets: []
+    asserts:
+      - equal:
+          path: spec.template.spec.imagePullSecrets[0].name
+          value: global-registry-secret
+      - equal:
+          path: spec.template.spec.imagePullSecrets[1].name
+          value: another-global-secret
+
+  - it: should use local imagePullSecrets over global imagePullSecrets (controller)
+    template: deployment.yaml
+    set:
+      global.imagePullSecrets:
+        - name: global-registry-secret
+      imagePullSecrets:
+        - name: local-registry-secret
+    asserts:
+      - equal:
+          path: spec.template.spec.imagePullSecrets[0].name
+          value: local-registry-secret
+      - lengthEqual:
+          path: spec.template.spec.imagePullSecrets
+          count: 1
+
+  - it: should use global imagePullSecrets when local imagePullSecrets not set (webhook)
+    template: webhook-deployment.yaml
+    set:
+      global.imagePullSecrets:
+        - name: global-registry-secret
+        - name: another-global-secret
+      webhook.imagePullSecrets: []
+    asserts:
+      - equal:
+          path: spec.template.spec.imagePullSecrets[0].name
+          value: global-registry-secret
+      - equal:
+          path: spec.template.spec.imagePullSecrets[1].name
+          value: another-global-secret
+
+  - it: should use local imagePullSecrets over global imagePullSecrets (webhook)
+    template: webhook-deployment.yaml
+    set:
+      global.imagePullSecrets:
+        - name: global-registry-secret
+      webhook.imagePullSecrets:
+        - name: local-registry-secret
+    asserts:
+      - equal:
+          path: spec.template.spec.imagePullSecrets[0].name
+          value: local-registry-secret
+      - lengthEqual:
+          path: spec.template.spec.imagePullSecrets
+          count: 1
+
+  - it: should use global imagePullSecrets when local imagePullSecrets not set (cert-controller)
+    template: cert-controller-deployment.yaml
+    set:
+      global.imagePullSecrets:
+        - name: global-registry-secret
+        - name: another-global-secret
+      certController.imagePullSecrets: []
+    asserts:
+      - equal:
+          path: spec.template.spec.imagePullSecrets[0].name
+          value: global-registry-secret
+      - equal:
+          path: spec.template.spec.imagePullSecrets[1].name
+          value: another-global-secret
+
+  - it: should use local imagePullSecrets over global imagePullSecrets (cert-controller)
+    template: cert-controller-deployment.yaml
+    set:
+      global.imagePullSecrets:
+        - name: global-registry-secret
+      certController.imagePullSecrets:
+        - name: local-registry-secret
+    asserts:
+      - equal:
+          path: spec.template.spec.imagePullSecrets[0].name
+          value: local-registry-secret
+      - lengthEqual:
+          path: spec.template.spec.imagePullSecrets
+          count: 1
+
+  # Test global.repository
+  - it: should use global repository when set (controller)
+    template: deployment.yaml
+    set:
+      global.repository: "my-registry.io/custom/external-secrets"
+    asserts:
+      - matchRegex:
+          path: spec.template.spec.containers[0].image
+          pattern: ^my-registry\.io/custom/external-secrets:.*
+
+  - it: should use local repository when global repository not set (controller)
+    template: deployment.yaml
+    set:
+      global.repository: ""
+      image.repository: "ghcr.io/external-secrets/external-secrets"
+    asserts:
+      - matchRegex:
+          path: spec.template.spec.containers[0].image
+          pattern: ^ghcr\.io/external-secrets/external-secrets:.*
+
+  - it: should use global repository when set (webhook)
+    template: webhook-deployment.yaml
+    set:
+      global.repository: "my-registry.io/custom/external-secrets"
+    asserts:
+      - matchRegex:
+          path: spec.template.spec.containers[0].image
+          pattern: ^my-registry\.io/custom/external-secrets:.*
+
+  - it: should use local repository when global repository not set (webhook)
+    template: webhook-deployment.yaml
+    set:
+      global.repository: ""
+      webhook.image.repository: "ghcr.io/external-secrets/external-secrets"
+    asserts:
+      - matchRegex:
+          path: spec.template.spec.containers[0].image
+          pattern: ^ghcr\.io/external-secrets/external-secrets:.*
+
+  - it: should use global repository when set (cert-controller)
+    template: cert-controller-deployment.yaml
+    set:
+      global.repository: "my-registry.io/custom/external-secrets"
+    asserts:
+      - matchRegex:
+          path: spec.template.spec.containers[0].image
+          pattern: ^my-registry\.io/custom/external-secrets:.*
+
+  - it: should use local repository when global repository not set (cert-controller)
+    template: cert-controller-deployment.yaml
+    set:
+      global.repository: ""
+      certController.image.repository: "ghcr.io/external-secrets/external-secrets"
+    asserts:
+      - matchRegex:
+          path: spec.template.spec.containers[0].image
+          pattern: ^ghcr\.io/external-secrets/external-secrets:.*
+
+  # Combined test - all global values set
+  - it: should apply all global values when local values not set (controller)
+    template: deployment.yaml
+    set:
+      global.repository: "my-registry.io/custom/external-secrets"
+      global.imagePullSecrets:
+        - name: global-secret
+      global.podLabels:
+        globalLabel: "global-value"
+      global.podAnnotations:
+        globalAnnotation: "global-value"
+    asserts:
+      - matchRegex:
+          path: spec.template.spec.containers[0].image
+          pattern: ^my-registry\.io/custom/external-secrets:.*
+      - equal:
+          path: spec.template.spec.imagePullSecrets[0].name
+          value: global-secret
+      - equal:
+          path: spec.template.metadata.labels.globalLabel
+          value: "global-value"
+      - equal:
+          path: spec.template.metadata.annotations.globalAnnotation
+          value: "global-value"
+
+  # No values set - should use only default helm labels
+  - it: should have only default helm labels when no custom values are set (controller)
+    template: deployment.yaml
+    set:
+      global.podLabels: {}
+      global.podAnnotations: {}
+      global.imagePullSecrets: []
+      podLabels: {}
+      podAnnotations: {}
+      imagePullSecrets: []
+    asserts:
+      - exists:
+          path: spec.template.metadata.labels
+      - notExists:
+          path: spec.template.spec.imagePullSecrets

+ 12 - 0
deploy/charts/external-secrets/values.schema.json

@@ -371,9 +371,21 @@
                         }
                     }
                 },
+                "imagePullSecrets": {
+                    "type": "array"
+                },
                 "nodeSelector": {
                     "type": "object"
                 },
+                "podAnnotations": {
+                    "type": "object"
+                },
+                "podLabels": {
+                    "type": "object"
+                },
+                "repository": {
+                    "type": "string"
+                },
                 "tolerations": {
                     "type": "array"
                 },

+ 8 - 0
deploy/charts/external-secrets/values.yaml

@@ -14,6 +14,14 @@ global:
   #    matchLabelKeys:
   #      - pod-template-hash
   affinity: {}
+  # -- Global pod labels to be applied to all deployments
+  podLabels: {}
+  # -- Global pod annotations to be applied to all deployments
+  podAnnotations: {}
+  # -- Global imagePullSecrets to be applied to all deployments
+  imagePullSecrets: []
+  # -- Global image repository to be applied to all deployments
+  repository: ""
   compatibility:
     openshift:
       # -- Manages the securityContext properties to make them compatible with OpenShift.