From 559dd60239d7c6a4a2373e9ecb28954d1ff1b970 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Costa?= Date: Thu, 18 Sep 2025 09:42:06 +0000 Subject: [PATCH 1/8] feat(helm): Pass custom labels to redis, statsd and dagProcessor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Gonçalo --- .../dag-processor-deployment.yaml | 4 ++-- .../dag-processor-serviceaccount.yaml | 4 ++-- .../templates/redis/redis-networkpolicy.yaml | 4 ++-- chart/templates/redis/redis-service.yaml | 4 ++-- .../templates/redis/redis-serviceaccount.yaml | 4 ++-- chart/templates/redis/redis-statefulset.yaml | 4 ++-- chart/templates/statsd/statsd-deployment.yaml | 4 ++-- chart/templates/statsd/statsd-ingress.yaml | 4 ++-- .../statsd/statsd-networkpolicy.yaml | 4 ++-- chart/templates/statsd/statsd-service.yaml | 4 ++-- .../statsd/statsd-serviceaccount.yaml | 4 ++-- chart/values.schema.json | 24 +++++++++++++++++++ chart/values.yaml | 10 ++++++++ 13 files changed, 56 insertions(+), 22 deletions(-) diff --git a/chart/templates/dag-processor/dag-processor-deployment.yaml b/chart/templates/dag-processor/dag-processor-deployment.yaml index b5490fcfe2c32..c62b57e1c2978 100644 --- a/chart/templates/dag-processor/dag-processor-deployment.yaml +++ b/chart/templates/dag-processor/dag-processor-deployment.yaml @@ -71,8 +71,8 @@ spec: tier: airflow component: dag-processor release: {{ .Release.Name }} - {{- with .Values.labels }} - {{- toYaml . | nindent 8 }} + {{- if or (.Values.labels) (.Values.dagProcessor.labels) }} + {{- mustMerge .Values.dagProcessor.labels .Values.labels | toYaml | nindent 8 }} {{- end }} annotations: checksum/metadata-secret: {{ include (print $.Template.BasePath "/secrets/metadata-connection-secret.yaml") . | sha256sum }} diff --git a/chart/templates/dag-processor/dag-processor-serviceaccount.yaml b/chart/templates/dag-processor/dag-processor-serviceaccount.yaml index 8fdae4abe1f32..1dd6493e12c20 100644 --- a/chart/templates/dag-processor/dag-processor-serviceaccount.yaml +++ b/chart/templates/dag-processor/dag-processor-serviceaccount.yaml @@ -37,8 +37,8 @@ metadata: release: {{ .Release.Name }} chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" heritage: {{ .Release.Service }} - {{- with .Values.labels }} - {{- toYaml . | nindent 4 }} + {{- if or (.Values.labels) (.Values.dagProcessor.labels) }} + {{- mustMerge .Values.dagProcessor.labels .Values.labels | toYaml | nindent 4 }} {{- end }} {{- with .Values.dagProcessor.serviceAccount.annotations}} annotations: {{- toYaml . | nindent 4 }} diff --git a/chart/templates/redis/redis-networkpolicy.yaml b/chart/templates/redis/redis-networkpolicy.yaml index 6a186a4b6855c..5a4b01db243d5 100644 --- a/chart/templates/redis/redis-networkpolicy.yaml +++ b/chart/templates/redis/redis-networkpolicy.yaml @@ -31,8 +31,8 @@ metadata: release: {{ .Release.Name }} chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" heritage: {{ .Release.Service }} - {{- with .Values.labels }} - {{- toYaml . | nindent 4 }} + {{- if or (.Values.labels) (.Values.redis.labels) }} + {{- mustMerge .Values.redis.labels .Values.labels | toYaml | nindent 4 }} {{- end }} spec: podSelector: diff --git a/chart/templates/redis/redis-service.yaml b/chart/templates/redis/redis-service.yaml index 40424a7313e99..75f445c74dfe4 100644 --- a/chart/templates/redis/redis-service.yaml +++ b/chart/templates/redis/redis-service.yaml @@ -31,8 +31,8 @@ metadata: release: {{ .Release.Name }} chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" heritage: {{ .Release.Service }} - {{- with .Values.labels }} - {{- toYaml . | nindent 4 }} + {{- if or (.Values.labels) (.Values.redis.labels) }} + {{- mustMerge .Values.redis.labels .Values.labels | toYaml | nindent 4 }} {{- end }} spec: {{- if eq .Values.redis.service.type "ClusterIP" }} diff --git a/chart/templates/redis/redis-serviceaccount.yaml b/chart/templates/redis/redis-serviceaccount.yaml index 06f33e12f5d38..c750d4420814b 100644 --- a/chart/templates/redis/redis-serviceaccount.yaml +++ b/chart/templates/redis/redis-serviceaccount.yaml @@ -32,8 +32,8 @@ metadata: release: {{ .Release.Name }} chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" heritage: {{ .Release.Service }} - {{- with .Values.labels }} - {{- toYaml . | nindent 4 }} + {{- if or (.Values.labels) (.Values.redis.labels) }} + {{- mustMerge .Values.redis.labels .Values.labels | toYaml | nindent 4 }} {{- end }} {{- with .Values.redis.serviceAccount.annotations }} annotations: {{- toYaml . | nindent 4 }} diff --git a/chart/templates/redis/redis-statefulset.yaml b/chart/templates/redis/redis-statefulset.yaml index d1e1edef808eb..96d41adb790e0 100644 --- a/chart/templates/redis/redis-statefulset.yaml +++ b/chart/templates/redis/redis-statefulset.yaml @@ -57,8 +57,8 @@ spec: tier: airflow component: redis release: {{ .Release.Name }} - {{- with .Values.labels }} - {{- toYaml . | nindent 8 }} + {{- if or (.Values.labels) (.Values.redis.labels) }} + {{- mustMerge .Values.redis.labels .Values.labels | toYaml | nindent 8 }} {{- end }} {{- if or .Values.redis.safeToEvict .Values.redis.podAnnotations }} annotations: diff --git a/chart/templates/statsd/statsd-deployment.yaml b/chart/templates/statsd/statsd-deployment.yaml index 1eab1fda8b8aa..865275716436b 100644 --- a/chart/templates/statsd/statsd-deployment.yaml +++ b/chart/templates/statsd/statsd-deployment.yaml @@ -61,8 +61,8 @@ spec: tier: airflow component: statsd release: {{ .Release.Name }} - {{- with .Values.labels }} - {{- toYaml . | nindent 8 }} + {{- if or (.Values.labels) (.Values.statsd.labels) }} + {{- mustMerge .Values.statsd.labels .Values.labels | toYaml | nindent 8 }} {{- end }} {{- if or .Values.statsd.extraMappings .Values.statsd.podAnnotations }} annotations: diff --git a/chart/templates/statsd/statsd-ingress.yaml b/chart/templates/statsd/statsd-ingress.yaml index c01792643c487..44b8f3311cf7d 100644 --- a/chart/templates/statsd/statsd-ingress.yaml +++ b/chart/templates/statsd/statsd-ingress.yaml @@ -32,8 +32,8 @@ metadata: release: {{ .Release.Name }} chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" heritage: {{ .Release.Service }} - {{- with .Values.labels }} - {{- toYaml . | nindent 4 }} + {{- if or (.Values.labels) (.Values.statsd.labels) }} + {{- mustMerge .Values.statsd.labels .Values.labels | toYaml | nindent 4 }} {{- end }} {{- with .Values.ingress.statsd.annotations }} annotations: {{- toYaml . | nindent 4 }} diff --git a/chart/templates/statsd/statsd-networkpolicy.yaml b/chart/templates/statsd/statsd-networkpolicy.yaml index 3690cda897155..2fd7ebef4f1fa 100644 --- a/chart/templates/statsd/statsd-networkpolicy.yaml +++ b/chart/templates/statsd/statsd-networkpolicy.yaml @@ -31,8 +31,8 @@ metadata: release: {{ .Release.Name }} chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" heritage: {{ .Release.Service }} - {{- with .Values.labels }} - {{- toYaml . | nindent 4 }} + {{- if or (.Values.labels) (.Values.statsd.labels) }} + {{- mustMerge .Values.statsd.labels .Values.labels | toYaml | nindent 4 }} {{- end }} spec: podSelector: diff --git a/chart/templates/statsd/statsd-service.yaml b/chart/templates/statsd/statsd-service.yaml index 2486264c5cb77..00e9d285d54d3 100644 --- a/chart/templates/statsd/statsd-service.yaml +++ b/chart/templates/statsd/statsd-service.yaml @@ -31,8 +31,8 @@ metadata: release: {{ .Release.Name }} chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" heritage: {{ .Release.Service }} - {{- with .Values.labels }} - {{- toYaml . | nindent 4 }} + {{- if or (.Values.labels) (.Values.statsd.labels) }} + {{- mustMerge .Values.statsd.labels .Values.labels | toYaml | nindent 4 }} {{- end }} annotations: prometheus.io/scrape: "true" diff --git a/chart/templates/statsd/statsd-serviceaccount.yaml b/chart/templates/statsd/statsd-serviceaccount.yaml index 838cbdd857cac..91d9ddc4c6a80 100644 --- a/chart/templates/statsd/statsd-serviceaccount.yaml +++ b/chart/templates/statsd/statsd-serviceaccount.yaml @@ -32,8 +32,8 @@ metadata: release: {{ .Release.Name }} chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" heritage: {{ .Release.Service }} - {{- with .Values.labels }} - {{- toYaml . | nindent 4 }} + {{- if or (.Values.labels) (.Values.statsd.labels) }} + {{- mustMerge .Values.statsd.labels .Values.labels | toYaml | nindent 4 }} {{- end }} {{- with .Values.statsd.serviceAccount.annotations }} annotations: {{- toYaml . | nindent 4 }} diff --git a/chart/values.schema.json b/chart/values.schema.json index d1bc354468e9a..0ed3298631403 100644 --- a/chart/values.schema.json +++ b/chart/values.schema.json @@ -4192,6 +4192,14 @@ } } }, + "labels": { + "description": "Labels specific to dag processor objects and pods", + "type": "object", + "default": {}, + "additionalProperties": { + "type": "string" + } + }, "env": { "description": "Add additional env vars to dag processor.", "type": "array", @@ -7317,6 +7325,14 @@ "--statsd.mapping-config=/etc/statsd-exporter/mappings.yml" ] }, + "labels": { + "description": "Labels specific to statsd objects and pods", + "type": "object", + "default": {}, + "additionalProperties": { + "type": "string" + } + }, "env": { "description": "Add additional env vars to statsd container.", "type": "array", @@ -8306,6 +8322,14 @@ } } }, + "labels": { + "description": "Labels to add to the redis objects and pods.", + "type": "object", + "default": {}, + "additionalProperties": { + "type": "string" + } + }, "uid": { "description": "Redis run as user parameter.", "type": "integer", diff --git a/chart/values.yaml b/chart/values.yaml index 904c0594c1ae5..8c1dde843aa3e 100644 --- a/chart/values.yaml +++ b/chart/values.yaml @@ -2174,6 +2174,9 @@ dagProcessor: securityContexts: container: {} + # Labels specific to dag processor objects and pods + labels: {} + # Environment variables to add to dag processor container env: [] # Flower settings @@ -2404,6 +2407,10 @@ statsd: overrideMappings: [] podAnnotations: {} + + # Labels specific to statsd objects and pods + labels: {} + # Environment variables to add to statsd container env: [] # PgBouncer settings @@ -2717,6 +2724,9 @@ redis: # container level lifecycle hooks containerLifecycleHooks: {} + # Labels specific to redis objects and pods + labels: {} + podAnnotations: {} # Auth secret for a private registry # This is used if pulling airflow images from a private registry From 6a131cd287854dadfe5e6b9d7ac2c6cdf60ea1b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Costa?= Date: Thu, 18 Sep 2025 12:07:16 +0000 Subject: [PATCH 2/8] docs(helm): Write helm labels customization doc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Gonçalo --- chart/docs/customizing-labels.rst | 62 +++++++++++++++++++++++++++++++ chart/docs/index.rst | 1 + 2 files changed, 63 insertions(+) create mode 100644 chart/docs/customizing-labels.rst diff --git a/chart/docs/customizing-labels.rst b/chart/docs/customizing-labels.rst new file mode 100644 index 0000000000000..b9f7e12f26165 --- /dev/null +++ b/chart/docs/customizing-labels.rst @@ -0,0 +1,62 @@ +.. Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + +.. http://www.apache.org/licenses/LICENSE-2.0 + +.. Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. + +Customizing Labels for Pods +--------------------------- + +The Helm chart allows you to customize labels for your Airflow objects. You can set global labels that apply to all objects and pods defined in the chart, as well as component-specific labels for individual Airflow components. + +Global Labels +~~~~~~~~~~~~~ + +Global labels can be set using the ``labels`` parameter in your values file. These labels will be applied to all Airflow objects and pods defined in the chart: + +.. code-block:: yaml + + labels: + environment: production + +Component-Specific Labels +~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can also set specific labels for individual Airflow components. These labels will be merged with the global labels, with component-specific labels taking precedence. + +For example, to add specific labels to different components: + +.. code-block:: yaml + + # Global labels applied to all pods + labels: + environment: production + + # Scheduler specific labels + scheduler: + labels: + role: scheduler + + # Worker specific labels + workers: + labels: + role: worker + + # Webserver specific labels + webserver: + labels: + role: ui + +.. note:: + Component-specific labels take precedence over global labels when there are conflicts. This allows you to override global labels for specific components when needed. diff --git a/chart/docs/index.rst b/chart/docs/index.rst index 68be09bbedfda..9ce59d74779cd 100644 --- a/chart/docs/index.rst +++ b/chart/docs/index.rst @@ -35,6 +35,7 @@ Helm Chart for Apache Airflow keda using-additional-containers customizing-workers + customizing-labels Installing from sources Extending the Chart From c3ff2b2f4ba8463a969ab78382a421c5bc1ace50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo?= <9543211+goncalo-m-c@users.noreply.github.com> Date: Thu, 16 Oct 2025 10:57:28 +0200 Subject: [PATCH 3/8] feat(helm): Clarify dagProcessor values.yaml comments MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Przemysław Mirowski --- chart/values.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/chart/values.yaml b/chart/values.yaml index 8c1dde843aa3e..0a92348cd56b0 100644 --- a/chart/values.yaml +++ b/chart/values.yaml @@ -2174,8 +2174,9 @@ dagProcessor: securityContexts: container: {} - # Labels specific to dag processor objects and pods + # Labels specific to dag processor objects labels: {} + # Environment variables to add to dag processor container env: [] From 6117cafc3e9d798b88a8c6ef13a4cf9be51e5c81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Costa?= Date: Thu, 16 Oct 2025 09:05:46 +0000 Subject: [PATCH 4/8] docs(helm): Clarify component-specific labels override behavior --- chart/docs/customizing-labels.rst | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/chart/docs/customizing-labels.rst b/chart/docs/customizing-labels.rst index b9f7e12f26165..47e06009854d9 100644 --- a/chart/docs/customizing-labels.rst +++ b/chart/docs/customizing-labels.rst @@ -33,7 +33,7 @@ Global labels can be set using the ``labels`` parameter in your values file. The Component-Specific Labels ~~~~~~~~~~~~~~~~~~~~~~~~~ -You can also set specific labels for individual Airflow components. These labels will be merged with the global labels, with component-specific labels taking precedence. +You can also set specific labels for individual Airflow components, which will be merged with the global labels. Component-specific labels take precedence over global labels, allowing you to override them as needed. For example, to add specific labels to different components: @@ -57,6 +57,3 @@ For example, to add specific labels to different components: webserver: labels: role: ui - -.. note:: - Component-specific labels take precedence over global labels when there are conflicts. This allows you to override global labels for specific components when needed. From e285095362103f2e466ecacc4c7ae845b13e041d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Costa?= Date: Thu, 16 Oct 2025 09:23:08 +0000 Subject: [PATCH 5/8] feat(helm): Remove parenthesis from label checks --- chart/templates/dag-processor/dag-processor-deployment.yaml | 2 +- chart/templates/dag-processor/dag-processor-serviceaccount.yaml | 2 +- chart/templates/redis/redis-networkpolicy.yaml | 2 +- chart/templates/redis/redis-service.yaml | 2 +- chart/templates/redis/redis-serviceaccount.yaml | 2 +- chart/templates/redis/redis-statefulset.yaml | 2 +- chart/templates/statsd/statsd-deployment.yaml | 2 +- chart/templates/statsd/statsd-ingress.yaml | 2 +- chart/templates/statsd/statsd-networkpolicy.yaml | 2 +- chart/templates/statsd/statsd-service.yaml | 2 +- chart/templates/statsd/statsd-serviceaccount.yaml | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/chart/templates/dag-processor/dag-processor-deployment.yaml b/chart/templates/dag-processor/dag-processor-deployment.yaml index c62b57e1c2978..f628d94627d50 100644 --- a/chart/templates/dag-processor/dag-processor-deployment.yaml +++ b/chart/templates/dag-processor/dag-processor-deployment.yaml @@ -71,7 +71,7 @@ spec: tier: airflow component: dag-processor release: {{ .Release.Name }} - {{- if or (.Values.labels) (.Values.dagProcessor.labels) }} + {{- if or .Values.labels .Values.dagProcessor.labels }} {{- mustMerge .Values.dagProcessor.labels .Values.labels | toYaml | nindent 8 }} {{- end }} annotations: diff --git a/chart/templates/dag-processor/dag-processor-serviceaccount.yaml b/chart/templates/dag-processor/dag-processor-serviceaccount.yaml index 1dd6493e12c20..acca4a6ec6791 100644 --- a/chart/templates/dag-processor/dag-processor-serviceaccount.yaml +++ b/chart/templates/dag-processor/dag-processor-serviceaccount.yaml @@ -37,7 +37,7 @@ metadata: release: {{ .Release.Name }} chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" heritage: {{ .Release.Service }} - {{- if or (.Values.labels) (.Values.dagProcessor.labels) }} + {{- if or .Values.labels .Values.dagProcessor.labels }} {{- mustMerge .Values.dagProcessor.labels .Values.labels | toYaml | nindent 4 }} {{- end }} {{- with .Values.dagProcessor.serviceAccount.annotations}} diff --git a/chart/templates/redis/redis-networkpolicy.yaml b/chart/templates/redis/redis-networkpolicy.yaml index 5a4b01db243d5..8ae08e01f87a2 100644 --- a/chart/templates/redis/redis-networkpolicy.yaml +++ b/chart/templates/redis/redis-networkpolicy.yaml @@ -31,7 +31,7 @@ metadata: release: {{ .Release.Name }} chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" heritage: {{ .Release.Service }} - {{- if or (.Values.labels) (.Values.redis.labels) }} + {{- if or .Values.labels .Values.redis.labels }} {{- mustMerge .Values.redis.labels .Values.labels | toYaml | nindent 4 }} {{- end }} spec: diff --git a/chart/templates/redis/redis-service.yaml b/chart/templates/redis/redis-service.yaml index 75f445c74dfe4..3ade825f28d52 100644 --- a/chart/templates/redis/redis-service.yaml +++ b/chart/templates/redis/redis-service.yaml @@ -31,7 +31,7 @@ metadata: release: {{ .Release.Name }} chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" heritage: {{ .Release.Service }} - {{- if or (.Values.labels) (.Values.redis.labels) }} + {{- if or .Values.labels .Values.redis.labels }} {{- mustMerge .Values.redis.labels .Values.labels | toYaml | nindent 4 }} {{- end }} spec: diff --git a/chart/templates/redis/redis-serviceaccount.yaml b/chart/templates/redis/redis-serviceaccount.yaml index c750d4420814b..f645b4ee2f4e1 100644 --- a/chart/templates/redis/redis-serviceaccount.yaml +++ b/chart/templates/redis/redis-serviceaccount.yaml @@ -32,7 +32,7 @@ metadata: release: {{ .Release.Name }} chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" heritage: {{ .Release.Service }} - {{- if or (.Values.labels) (.Values.redis.labels) }} + {{- if or .Values.labels .Values.redis.labels }} {{- mustMerge .Values.redis.labels .Values.labels | toYaml | nindent 4 }} {{- end }} {{- with .Values.redis.serviceAccount.annotations }} diff --git a/chart/templates/redis/redis-statefulset.yaml b/chart/templates/redis/redis-statefulset.yaml index 96d41adb790e0..b8374d81e9d63 100644 --- a/chart/templates/redis/redis-statefulset.yaml +++ b/chart/templates/redis/redis-statefulset.yaml @@ -57,7 +57,7 @@ spec: tier: airflow component: redis release: {{ .Release.Name }} - {{- if or (.Values.labels) (.Values.redis.labels) }} + {{- if or .Values.labels .Values.redis.labels }} {{- mustMerge .Values.redis.labels .Values.labels | toYaml | nindent 8 }} {{- end }} {{- if or .Values.redis.safeToEvict .Values.redis.podAnnotations }} diff --git a/chart/templates/statsd/statsd-deployment.yaml b/chart/templates/statsd/statsd-deployment.yaml index 865275716436b..ecbd1f80f4123 100644 --- a/chart/templates/statsd/statsd-deployment.yaml +++ b/chart/templates/statsd/statsd-deployment.yaml @@ -61,7 +61,7 @@ spec: tier: airflow component: statsd release: {{ .Release.Name }} - {{- if or (.Values.labels) (.Values.statsd.labels) }} + {{- if or .Values.labels .Values.statsd.labels }} {{- mustMerge .Values.statsd.labels .Values.labels | toYaml | nindent 8 }} {{- end }} {{- if or .Values.statsd.extraMappings .Values.statsd.podAnnotations }} diff --git a/chart/templates/statsd/statsd-ingress.yaml b/chart/templates/statsd/statsd-ingress.yaml index 44b8f3311cf7d..d48ec29085a30 100644 --- a/chart/templates/statsd/statsd-ingress.yaml +++ b/chart/templates/statsd/statsd-ingress.yaml @@ -32,7 +32,7 @@ metadata: release: {{ .Release.Name }} chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" heritage: {{ .Release.Service }} - {{- if or (.Values.labels) (.Values.statsd.labels) }} + {{- if or .Values.labels .Values.statsd.labels }} {{- mustMerge .Values.statsd.labels .Values.labels | toYaml | nindent 4 }} {{- end }} {{- with .Values.ingress.statsd.annotations }} diff --git a/chart/templates/statsd/statsd-networkpolicy.yaml b/chart/templates/statsd/statsd-networkpolicy.yaml index 2fd7ebef4f1fa..9d4ccde72db7f 100644 --- a/chart/templates/statsd/statsd-networkpolicy.yaml +++ b/chart/templates/statsd/statsd-networkpolicy.yaml @@ -31,7 +31,7 @@ metadata: release: {{ .Release.Name }} chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" heritage: {{ .Release.Service }} - {{- if or (.Values.labels) (.Values.statsd.labels) }} + {{- if or .Values.labels .Values.statsd.labels }} {{- mustMerge .Values.statsd.labels .Values.labels | toYaml | nindent 4 }} {{- end }} spec: diff --git a/chart/templates/statsd/statsd-service.yaml b/chart/templates/statsd/statsd-service.yaml index 00e9d285d54d3..c7bee0ea3f414 100644 --- a/chart/templates/statsd/statsd-service.yaml +++ b/chart/templates/statsd/statsd-service.yaml @@ -31,7 +31,7 @@ metadata: release: {{ .Release.Name }} chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" heritage: {{ .Release.Service }} - {{- if or (.Values.labels) (.Values.statsd.labels) }} + {{- if or .Values.labels .Values.statsd.labels }} {{- mustMerge .Values.statsd.labels .Values.labels | toYaml | nindent 4 }} {{- end }} annotations: diff --git a/chart/templates/statsd/statsd-serviceaccount.yaml b/chart/templates/statsd/statsd-serviceaccount.yaml index 91d9ddc4c6a80..e2659769516dc 100644 --- a/chart/templates/statsd/statsd-serviceaccount.yaml +++ b/chart/templates/statsd/statsd-serviceaccount.yaml @@ -32,7 +32,7 @@ metadata: release: {{ .Release.Name }} chart: "{{ .Chart.Name }}-{{ .Chart.Version }}" heritage: {{ .Release.Service }} - {{- if or (.Values.labels) (.Values.statsd.labels) }} + {{- if or .Values.labels .Values.statsd.labels }} {{- mustMerge .Values.statsd.labels .Values.labels | toYaml | nindent 4 }} {{- end }} {{- with .Values.statsd.serviceAccount.annotations }} From 3e046a82eb0b134000c2e65446cf27364e9029e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Costa?= Date: Wed, 29 Oct 2025 10:36:54 +0000 Subject: [PATCH 6/8] tests(helm): Add label tests for redis, statsd and dagprocessor --- .../tests/helm_tests/dagprocessor/__init__.py | 17 +++ .../dagprocessor/test_labels_deployment.py | 105 +++++++++++++++ .../test_labels_service_account.py | 100 ++++++++++++++ helm-tests/tests/helm_tests/redis/__init__.py | 17 +++ .../redis/test_labels_networkpolicy.py | 108 +++++++++++++++ .../helm_tests/redis/test_labels_service.py | 104 +++++++++++++++ .../redis/test_labels_serviceaccount.py | 110 +++++++++++++++ .../redis/test_labels_statefulset.py | 125 ++++++++++++++++++ .../tests/helm_tests/statsd/__init__.py | 17 +++ .../statsd/test_labels_deployment.py | 119 +++++++++++++++++ .../helm_tests/statsd/test_labels_ingress.py | 103 +++++++++++++++ .../statsd/test_labels_networkpolicy.py | 103 +++++++++++++++ .../helm_tests/statsd/test_labels_service.py | 99 ++++++++++++++ .../statsd/test_labels_serviceaccount.py | 99 ++++++++++++++ 14 files changed, 1226 insertions(+) create mode 100644 helm-tests/tests/helm_tests/dagprocessor/__init__.py create mode 100644 helm-tests/tests/helm_tests/dagprocessor/test_labels_deployment.py create mode 100644 helm-tests/tests/helm_tests/dagprocessor/test_labels_service_account.py create mode 100644 helm-tests/tests/helm_tests/redis/__init__.py create mode 100644 helm-tests/tests/helm_tests/redis/test_labels_networkpolicy.py create mode 100644 helm-tests/tests/helm_tests/redis/test_labels_service.py create mode 100644 helm-tests/tests/helm_tests/redis/test_labels_serviceaccount.py create mode 100644 helm-tests/tests/helm_tests/redis/test_labels_statefulset.py create mode 100644 helm-tests/tests/helm_tests/statsd/__init__.py create mode 100644 helm-tests/tests/helm_tests/statsd/test_labels_deployment.py create mode 100644 helm-tests/tests/helm_tests/statsd/test_labels_ingress.py create mode 100644 helm-tests/tests/helm_tests/statsd/test_labels_networkpolicy.py create mode 100644 helm-tests/tests/helm_tests/statsd/test_labels_service.py create mode 100644 helm-tests/tests/helm_tests/statsd/test_labels_serviceaccount.py diff --git a/helm-tests/tests/helm_tests/dagprocessor/__init__.py b/helm-tests/tests/helm_tests/dagprocessor/__init__.py new file mode 100644 index 0000000000000..245692337bc3f --- /dev/null +++ b/helm-tests/tests/helm_tests/dagprocessor/__init__.py @@ -0,0 +1,17 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + diff --git a/helm-tests/tests/helm_tests/dagprocessor/test_labels_deployment.py b/helm-tests/tests/helm_tests/dagprocessor/test_labels_deployment.py new file mode 100644 index 0000000000000..430d6a100a2a1 --- /dev/null +++ b/helm-tests/tests/helm_tests/dagprocessor/test_labels_deployment.py @@ -0,0 +1,105 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +from __future__ import annotations + +import jmespath +from chart_utils.helm_template_generator import render_chart + + +class TestDagProcessorDeployment: + """Tests dag-processor deployment labels.""" + + AIRFLOW_VERSION = "3.0.0" + TEMPLATE_FILE = "templates/dag-processor/dag-processor-deployment.yaml" + + def test_should_add_global_labels(self): + """Test adding only .Values.labels.""" + docs = render_chart( + values={ + "airflowVersion": self.AIRFLOW_VERSION, + "labels": {"test_global_label": "test_global_label_value"}, + }, + show_only=[self.TEMPLATE_FILE], + ) + + assert "test_global_label" in jmespath.search("spec.template.metadata.labels", docs[0]) + assert ( + jmespath.search("spec.template.metadata.labels", docs[0])["test_global_label"] + == "test_global_label_value" + ) + + def test_should_add_component_specific_labels(self): + """Test adding only .Values.dagProcessor.labels.""" + docs = render_chart( + values={ + "airflowVersion": self.AIRFLOW_VERSION, + "dagProcessor": { + "labels": {"test_component_label": "test_component_label_value"}, + }, + }, + show_only=[self.TEMPLATE_FILE], + ) + + assert "test_component_label" in jmespath.search("spec.template.metadata.labels", docs[0]) + assert ( + jmespath.search("spec.template.metadata.labels", docs[0])["test_component_label"] + == "test_component_label_value" + ) + + def test_should_merge_global_and_component_specific_labels(self): + """Test adding both .Values.labels and .Values.dagProcessor.labels.""" + docs = render_chart( + values={ + "airflowVersion": self.AIRFLOW_VERSION, + "labels": {"test_global_label": "test_global_label_value"}, + "dagProcessor": { + "labels": {"test_component_label": "test_component_label_value"}, + }, + }, + show_only=[self.TEMPLATE_FILE], + ) + + assert "test_global_label" in jmespath.search("spec.template.metadata.labels", docs[0]) + assert ( + jmespath.search("spec.template.metadata.labels", docs[0])["test_global_label"] + == "test_global_label_value" + ) + assert "test_component_label" in jmespath.search("spec.template.metadata.labels", docs[0]) + assert ( + jmespath.search("spec.template.metadata.labels", docs[0])["test_component_label"] + == "test_component_label_value" + ) + + def test_component_specific_labels_should_override_global_labels(self): + """Test that component-specific labels take precedence over global labels with the same key.""" + docs = render_chart( + values={ + "airflowVersion": self.AIRFLOW_VERSION, + "labels": {"common_label": "global_value"}, + "dagProcessor": { + "labels": {"common_label": "component_value"}, + }, + }, + show_only=[self.TEMPLATE_FILE], + ) + + assert "common_label" in jmespath.search("spec.template.metadata.labels", docs[0]) + assert ( + jmespath.search("spec.template.metadata.labels", docs[0])["common_label"] + == "component_value" + ) + diff --git a/helm-tests/tests/helm_tests/dagprocessor/test_labels_service_account.py b/helm-tests/tests/helm_tests/dagprocessor/test_labels_service_account.py new file mode 100644 index 0000000000000..dcbd46e1e7e33 --- /dev/null +++ b/helm-tests/tests/helm_tests/dagprocessor/test_labels_service_account.py @@ -0,0 +1,100 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +from __future__ import annotations + +import jmespath +from chart_utils.helm_template_generator import render_chart + + +class TestDagProcessorServiceAccount: + """Tests dag-processor service account labels.""" + + AIRFLOW_VERSION = "3.0.0" + TEMPLATE_FILE = "templates/dag-processor/dag-processor-serviceaccount.yaml" + + def test_should_add_global_labels(self): + """Test adding only .Values.labels.""" + docs = render_chart( + values={ + "airflowVersion": self.AIRFLOW_VERSION, + "labels": {"test_global_label": "test_global_label_value"}, + }, + show_only=[self.TEMPLATE_FILE], + ) + + assert "test_global_label" in jmespath.search("metadata.labels", docs[0]) + assert ( + jmespath.search("metadata.labels", docs[0])["test_global_label"] == "test_global_label_value" + ) + + def test_should_add_component_specific_labels(self): + """Test adding only .Values.dagProcessor.labels.""" + docs = render_chart( + values={ + "airflowVersion": self.AIRFLOW_VERSION, + "dagProcessor": { + "labels": {"test_component_label": "test_component_label_value"}, + }, + }, + show_only=[self.TEMPLATE_FILE], + ) + + assert "test_component_label" in jmespath.search("metadata.labels", docs[0]) + assert ( + jmespath.search("metadata.labels", docs[0])["test_component_label"] + == "test_component_label_value" + ) + + def test_should_merge_global_and_component_specific_labels(self): + """Test adding both .Values.labels and .Values.dagProcessor.labels.""" + docs = render_chart( + values={ + "airflowVersion": self.AIRFLOW_VERSION, + "labels": {"test_global_label": "test_global_label_value"}, + "dagProcessor": { + "labels": {"test_component_label": "test_component_label_value"}, + }, + }, + show_only=[self.TEMPLATE_FILE], + ) + + assert "test_global_label" in jmespath.search("metadata.labels", docs[0]) + assert ( + jmespath.search("metadata.labels", docs[0])["test_global_label"] == "test_global_label_value" + ) + assert "test_component_label" in jmespath.search("metadata.labels", docs[0]) + assert ( + jmespath.search("metadata.labels", docs[0])["test_component_label"] + == "test_component_label_value" + ) + + def test_component_specific_labels_should_override_global_labels(self): + """Test that component-specific labels take precedence over global labels with the same key.""" + docs = render_chart( + values={ + "airflowVersion": self.AIRFLOW_VERSION, + "labels": {"common_label": "global_value"}, + "dagProcessor": { + "labels": {"common_label": "component_value"}, + }, + }, + show_only=[self.TEMPLATE_FILE], + ) + + assert "common_label" in jmespath.search("metadata.labels", docs[0]) + assert jmespath.search("metadata.labels", docs[0])["common_label"] == "component_value" + diff --git a/helm-tests/tests/helm_tests/redis/__init__.py b/helm-tests/tests/helm_tests/redis/__init__.py new file mode 100644 index 0000000000000..245692337bc3f --- /dev/null +++ b/helm-tests/tests/helm_tests/redis/__init__.py @@ -0,0 +1,17 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + diff --git a/helm-tests/tests/helm_tests/redis/test_labels_networkpolicy.py b/helm-tests/tests/helm_tests/redis/test_labels_networkpolicy.py new file mode 100644 index 0000000000000..68bf50881487f --- /dev/null +++ b/helm-tests/tests/helm_tests/redis/test_labels_networkpolicy.py @@ -0,0 +1,108 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +from __future__ import annotations + +import jmespath +from chart_utils.helm_template_generator import render_chart + + +class TestRedisNetworkPolicy: + """Tests redis network policy labels.""" + + AIRFLOW_EXECUTOR = "CeleryExecutor" + TEMPLATE_FILE = "templates/redis/redis-networkpolicy.yaml" + + def test_should_add_global_labels(self): + """Test adding only .Values.labels.""" + docs = render_chart( + values={ + "executor": self.AIRFLOW_EXECUTOR, + "redis": {"enabled": True}, + "networkPolicies": {"enabled": True}, + "labels": {"test_global_label": "test_global_label_value"}, + }, + show_only=[self.TEMPLATE_FILE], + ) + + assert "test_global_label" in jmespath.search("metadata.labels", docs[0]) + assert ( + jmespath.search("metadata.labels", docs[0])["test_global_label"] == "test_global_label_value" + ) + + def test_should_add_component_specific_labels(self): + """Test adding only .Values.redis.labels.""" + docs = render_chart( + values={ + "executor": self.AIRFLOW_EXECUTOR, + "redis": { + "enabled": True, + "labels": {"test_component_label": "test_component_label_value"}, + }, + "networkPolicies": {"enabled": True}, + }, + show_only=[self.TEMPLATE_FILE], + ) + + assert "test_component_label" in jmespath.search("metadata.labels", docs[0]) + assert ( + jmespath.search("metadata.labels", docs[0])["test_component_label"] + == "test_component_label_value" + ) + + def test_should_merge_global_and_component_specific_labels(self): + """Test adding both .Values.labels and .Values.redis.labels.""" + docs = render_chart( + values={ + "executor": self.AIRFLOW_EXECUTOR, + "redis": { + "enabled": True, + "labels": {"test_component_label": "test_component_label_value"}, + }, + "networkPolicies": {"enabled": True}, + "labels": {"test_global_label": "test_global_label_value"}, + }, + show_only=[self.TEMPLATE_FILE], + ) + + assert "test_global_label" in jmespath.search("metadata.labels", docs[0]) + assert ( + jmespath.search("metadata.labels", docs[0])["test_global_label"] == "test_global_label_value" + ) + assert "test_component_label" in jmespath.search("metadata.labels", docs[0]) + assert ( + jmespath.search("metadata.labels", docs[0])["test_component_label"] + == "test_component_label_value" + ) + + def test_component_specific_labels_should_override_global_labels(self): + """Test that component-specific labels take precedence over global labels with the same key.""" + docs = render_chart( + values={ + "executor": self.AIRFLOW_EXECUTOR, + "redis": { + "enabled": True, + "labels": {"common_label": "component_value"}, + }, + "networkPolicies": {"enabled": True}, + "labels": {"common_label": "global_value"}, + }, + show_only=[self.TEMPLATE_FILE], + ) + + assert "common_label" in jmespath.search("metadata.labels", docs[0]) + assert jmespath.search("metadata.labels", docs[0])["common_label"] == "component_value" + diff --git a/helm-tests/tests/helm_tests/redis/test_labels_service.py b/helm-tests/tests/helm_tests/redis/test_labels_service.py new file mode 100644 index 0000000000000..4eaf376f39999 --- /dev/null +++ b/helm-tests/tests/helm_tests/redis/test_labels_service.py @@ -0,0 +1,104 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +from __future__ import annotations + +import jmespath +from chart_utils.helm_template_generator import render_chart + + +class TestRedisService: + """Tests redis service labels.""" + + AIRFLOW_EXECUTOR = "CeleryExecutor" + TEMPLATE_FILE = "templates/redis/redis-service.yaml" + + def test_should_add_global_labels(self): + """Test adding only .Values.labels.""" + docs = render_chart( + values={ + "executor": self.AIRFLOW_EXECUTOR, + "redis": {"enabled": True}, + "labels": {"test_global_label": "test_global_label_value"}, + }, + show_only=[self.TEMPLATE_FILE], + ) + + assert "test_global_label" in jmespath.search("metadata.labels", docs[0]) + assert ( + jmespath.search("metadata.labels", docs[0])["test_global_label"] == "test_global_label_value" + ) + + def test_should_add_component_specific_labels(self): + """Test adding only .Values.redis.labels.""" + docs = render_chart( + values={ + "executor": self.AIRFLOW_EXECUTOR, + "redis": { + "enabled": True, + "labels": {"test_component_label": "test_component_label_value"}, + }, + }, + show_only=[self.TEMPLATE_FILE], + ) + + assert "test_component_label" in jmespath.search("metadata.labels", docs[0]) + assert ( + jmespath.search("metadata.labels", docs[0])["test_component_label"] + == "test_component_label_value" + ) + + def test_should_merge_global_and_component_specific_labels(self): + """Test adding both .Values.labels and .Values.redis.labels.""" + docs = render_chart( + values={ + "executor": self.AIRFLOW_EXECUTOR, + "redis": { + "enabled": True, + "labels": {"test_component_label": "test_component_label_value"}, + }, + "labels": {"test_global_label": "test_global_label_value"}, + }, + show_only=[self.TEMPLATE_FILE], + ) + + assert "test_global_label" in jmespath.search("metadata.labels", docs[0]) + assert ( + jmespath.search("metadata.labels", docs[0])["test_global_label"] == "test_global_label_value" + ) + assert "test_component_label" in jmespath.search("metadata.labels", docs[0]) + assert ( + jmespath.search("metadata.labels", docs[0])["test_component_label"] + == "test_component_label_value" + ) + + def test_component_specific_labels_should_override_global_labels(self): + """Test that component-specific labels take precedence over global labels with the same key.""" + docs = render_chart( + values={ + "executor": self.AIRFLOW_EXECUTOR, + "redis": { + "enabled": True, + "labels": {"common_label": "component_value"}, + }, + "labels": {"common_label": "global_value"}, + }, + show_only=[self.TEMPLATE_FILE], + ) + + assert "common_label" in jmespath.search("metadata.labels", docs[0]) + assert jmespath.search("metadata.labels", docs[0])["common_label"] == "component_value" + diff --git a/helm-tests/tests/helm_tests/redis/test_labels_serviceaccount.py b/helm-tests/tests/helm_tests/redis/test_labels_serviceaccount.py new file mode 100644 index 0000000000000..e244dcda8b362 --- /dev/null +++ b/helm-tests/tests/helm_tests/redis/test_labels_serviceaccount.py @@ -0,0 +1,110 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +from __future__ import annotations + +import jmespath +from chart_utils.helm_template_generator import render_chart + + +class TestRedisServiceAccount: + """Tests redis service account labels.""" + + AIRFLOW_EXECUTOR = "CeleryExecutor" + TEMPLATE_FILE = "templates/redis/redis-serviceaccount.yaml" + + def test_should_add_global_labels(self): + """Test adding only .Values.labels.""" + docs = render_chart( + values={ + "executor": self.AIRFLOW_EXECUTOR, + "redis": { + "enabled": True, + "serviceAccount": {"create": True}, + }, + "labels": {"test_global_label": "test_global_label_value"}, + }, + show_only=[self.TEMPLATE_FILE], + ) + + assert "test_global_label" in jmespath.search("metadata.labels", docs[0]) + assert ( + jmespath.search("metadata.labels", docs[0])["test_global_label"] == "test_global_label_value" + ) + + def test_should_add_component_specific_labels(self): + """Test adding only .Values.redis.labels.""" + docs = render_chart( + values={ + "executor": self.AIRFLOW_EXECUTOR, + "redis": { + "enabled": True, + "serviceAccount": {"create": True}, + "labels": {"test_component_label": "test_component_label_value"}, + }, + }, + show_only=[self.TEMPLATE_FILE], + ) + + assert "test_component_label" in jmespath.search("metadata.labels", docs[0]) + assert ( + jmespath.search("metadata.labels", docs[0])["test_component_label"] + == "test_component_label_value" + ) + + def test_should_merge_global_and_component_specific_labels(self): + """Test adding both .Values.labels and .Values.redis.labels.""" + docs = render_chart( + values={ + "executor": self.AIRFLOW_EXECUTOR, + "redis": { + "enabled": True, + "serviceAccount": {"create": True}, + "labels": {"test_component_label": "test_component_label_value"}, + }, + "labels": {"test_global_label": "test_global_label_value"}, + }, + show_only=[self.TEMPLATE_FILE], + ) + + assert "test_global_label" in jmespath.search("metadata.labels", docs[0]) + assert ( + jmespath.search("metadata.labels", docs[0])["test_global_label"] == "test_global_label_value" + ) + assert "test_component_label" in jmespath.search("metadata.labels", docs[0]) + assert ( + jmespath.search("metadata.labels", docs[0])["test_component_label"] + == "test_component_label_value" + ) + + def test_component_specific_labels_should_override_global_labels(self): + """Test that component-specific labels take precedence over global labels with the same key.""" + docs = render_chart( + values={ + "executor": self.AIRFLOW_EXECUTOR, + "redis": { + "enabled": True, + "serviceAccount": {"create": True}, + "labels": {"common_label": "component_value"}, + }, + "labels": {"common_label": "global_value"}, + }, + show_only=[self.TEMPLATE_FILE], + ) + + assert "common_label" in jmespath.search("metadata.labels", docs[0]) + assert jmespath.search("metadata.labels", docs[0])["common_label"] == "component_value" + diff --git a/helm-tests/tests/helm_tests/redis/test_labels_statefulset.py b/helm-tests/tests/helm_tests/redis/test_labels_statefulset.py new file mode 100644 index 0000000000000..fd729cc1f5080 --- /dev/null +++ b/helm-tests/tests/helm_tests/redis/test_labels_statefulset.py @@ -0,0 +1,125 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +from __future__ import annotations + +import jmespath +from chart_utils.helm_template_generator import render_chart + + +class TestRedisStatefulSet: + """Tests redis statefulset labels.""" + + AIRFLOW_EXECUTOR = "CeleryExecutor" + TEMPLATE_FILE = "templates/redis/redis-statefulset.yaml" + + def test_should_add_global_labels_to_metadata(self): + """Test adding only .Values.labels to metadata.labels.""" + docs = render_chart( + values={ + "executor": self.AIRFLOW_EXECUTOR, + "redis": {"enabled": True}, + "labels": {"test_global_label": "test_global_label_value"}, + }, + show_only=[self.TEMPLATE_FILE], + ) + + assert "test_global_label" in jmespath.search("metadata.labels", docs[0]) + assert ( + jmespath.search("metadata.labels", docs[0])["test_global_label"] == "test_global_label_value" + ) + + def test_should_add_global_labels_to_pod_template(self): + """Test adding only .Values.labels to spec.template.metadata.labels.""" + docs = render_chart( + values={ + "executor": self.AIRFLOW_EXECUTOR, + "redis": {"enabled": True}, + "labels": {"test_global_label": "test_global_label_value"}, + }, + show_only=[self.TEMPLATE_FILE], + ) + + assert "test_global_label" in jmespath.search("spec.template.metadata.labels", docs[0]) + assert ( + jmespath.search("spec.template.metadata.labels", docs[0])["test_global_label"] + == "test_global_label_value" + ) + + def test_should_add_component_specific_labels_to_pod_template(self): + """Test adding only .Values.redis.labels to spec.template.metadata.labels.""" + docs = render_chart( + values={ + "executor": self.AIRFLOW_EXECUTOR, + "redis": { + "enabled": True, + "labels": {"test_component_label": "test_component_label_value"}, + }, + }, + show_only=[self.TEMPLATE_FILE], + ) + + assert "test_component_label" in jmespath.search("spec.template.metadata.labels", docs[0]) + assert ( + jmespath.search("spec.template.metadata.labels", docs[0])["test_component_label"] + == "test_component_label_value" + ) + + def test_should_merge_global_and_component_specific_labels_in_pod_template(self): + """Test adding both .Values.labels and .Values.redis.labels to spec.template.metadata.labels.""" + docs = render_chart( + values={ + "executor": self.AIRFLOW_EXECUTOR, + "redis": { + "enabled": True, + "labels": {"test_component_label": "test_component_label_value"}, + }, + "labels": {"test_global_label": "test_global_label_value"}, + }, + show_only=[self.TEMPLATE_FILE], + ) + + assert "test_global_label" in jmespath.search("spec.template.metadata.labels", docs[0]) + assert ( + jmespath.search("spec.template.metadata.labels", docs[0])["test_global_label"] + == "test_global_label_value" + ) + assert "test_component_label" in jmespath.search("spec.template.metadata.labels", docs[0]) + assert ( + jmespath.search("spec.template.metadata.labels", docs[0])["test_component_label"] + == "test_component_label_value" + ) + + def test_component_specific_labels_should_override_global_labels(self): + """Test that component-specific labels take precedence over global labels with the same key.""" + docs = render_chart( + values={ + "executor": self.AIRFLOW_EXECUTOR, + "redis": { + "enabled": True, + "labels": {"common_label": "component_value"}, + }, + "labels": {"common_label": "global_value"}, + }, + show_only=[self.TEMPLATE_FILE], + ) + + assert "common_label" in jmespath.search("spec.template.metadata.labels", docs[0]) + assert ( + jmespath.search("spec.template.metadata.labels", docs[0])["common_label"] + == "component_value" + ) + diff --git a/helm-tests/tests/helm_tests/statsd/__init__.py b/helm-tests/tests/helm_tests/statsd/__init__.py new file mode 100644 index 0000000000000..245692337bc3f --- /dev/null +++ b/helm-tests/tests/helm_tests/statsd/__init__.py @@ -0,0 +1,17 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + diff --git a/helm-tests/tests/helm_tests/statsd/test_labels_deployment.py b/helm-tests/tests/helm_tests/statsd/test_labels_deployment.py new file mode 100644 index 0000000000000..78bda9fdc32ff --- /dev/null +++ b/helm-tests/tests/helm_tests/statsd/test_labels_deployment.py @@ -0,0 +1,119 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +from __future__ import annotations + +import jmespath +from chart_utils.helm_template_generator import render_chart + + +class TestStatsdDeployment: + """Tests statsd deployment labels.""" + + TEMPLATE_FILE = "templates/statsd/statsd-deployment.yaml" + + def test_should_add_global_labels_to_metadata(self): + """Test adding only .Values.labels to metadata.labels.""" + docs = render_chart( + values={ + "statsd": {"enabled": True}, + "labels": {"test_global_label": "test_global_label_value"}, + }, + show_only=[self.TEMPLATE_FILE], + ) + + assert "test_global_label" in jmespath.search("metadata.labels", docs[0]) + assert ( + jmespath.search("metadata.labels", docs[0])["test_global_label"] == "test_global_label_value" + ) + + def test_should_add_global_labels_to_pod_template(self): + """Test adding only .Values.labels to spec.template.metadata.labels.""" + docs = render_chart( + values={ + "statsd": {"enabled": True}, + "labels": {"test_global_label": "test_global_label_value"}, + }, + show_only=[self.TEMPLATE_FILE], + ) + + assert "test_global_label" in jmespath.search("spec.template.metadata.labels", docs[0]) + assert ( + jmespath.search("spec.template.metadata.labels", docs[0])["test_global_label"] + == "test_global_label_value" + ) + + def test_should_add_component_specific_labels_to_pod_template(self): + """Test adding only .Values.statsd.labels to spec.template.metadata.labels.""" + docs = render_chart( + values={ + "statsd": { + "enabled": True, + "labels": {"test_component_label": "test_component_label_value"}, + }, + }, + show_only=[self.TEMPLATE_FILE], + ) + + assert "test_component_label" in jmespath.search("spec.template.metadata.labels", docs[0]) + assert ( + jmespath.search("spec.template.metadata.labels", docs[0])["test_component_label"] + == "test_component_label_value" + ) + + def test_should_merge_global_and_component_specific_labels_in_pod_template(self): + """Test adding both .Values.labels and .Values.statsd.labels to spec.template.metadata.labels.""" + docs = render_chart( + values={ + "statsd": { + "enabled": True, + "labels": {"test_component_label": "test_component_label_value"}, + }, + "labels": {"test_global_label": "test_global_label_value"}, + }, + show_only=[self.TEMPLATE_FILE], + ) + + assert "test_global_label" in jmespath.search("spec.template.metadata.labels", docs[0]) + assert ( + jmespath.search("spec.template.metadata.labels", docs[0])["test_global_label"] + == "test_global_label_value" + ) + assert "test_component_label" in jmespath.search("spec.template.metadata.labels", docs[0]) + assert ( + jmespath.search("spec.template.metadata.labels", docs[0])["test_component_label"] + == "test_component_label_value" + ) + + def test_component_specific_labels_should_override_global_labels(self): + """Test that component-specific labels take precedence over global labels with the same key.""" + docs = render_chart( + values={ + "statsd": { + "enabled": True, + "labels": {"common_label": "component_value"}, + }, + "labels": {"common_label": "global_value"}, + }, + show_only=[self.TEMPLATE_FILE], + ) + + assert "common_label" in jmespath.search("spec.template.metadata.labels", docs[0]) + assert ( + jmespath.search("spec.template.metadata.labels", docs[0])["common_label"] + == "component_value" + ) + diff --git a/helm-tests/tests/helm_tests/statsd/test_labels_ingress.py b/helm-tests/tests/helm_tests/statsd/test_labels_ingress.py new file mode 100644 index 0000000000000..b4ad4550588ff --- /dev/null +++ b/helm-tests/tests/helm_tests/statsd/test_labels_ingress.py @@ -0,0 +1,103 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +from __future__ import annotations + +import jmespath +from chart_utils.helm_template_generator import render_chart + + +class TestStatsdIngress: + """Tests statsd ingress labels.""" + + TEMPLATE_FILE = "templates/statsd/statsd-ingress.yaml" + + def test_should_add_global_labels(self): + """Test adding only .Values.labels.""" + docs = render_chart( + values={ + "statsd": {"enabled": True}, + "ingress": {"statsd": {"enabled": True}}, + "labels": {"test_global_label": "test_global_label_value"}, + }, + show_only=[self.TEMPLATE_FILE], + ) + + assert "test_global_label" in jmespath.search("metadata.labels", docs[0]) + assert ( + jmespath.search("metadata.labels", docs[0])["test_global_label"] == "test_global_label_value" + ) + + def test_should_add_component_specific_labels(self): + """Test adding only .Values.statsd.labels.""" + docs = render_chart( + values={ + "statsd": { + "enabled": True, + "labels": {"test_component_label": "test_component_label_value"}, + }, + "ingress": {"statsd": {"enabled": True}}, + }, + show_only=[self.TEMPLATE_FILE], + ) + + assert "test_component_label" in jmespath.search("metadata.labels", docs[0]) + assert ( + jmespath.search("metadata.labels", docs[0])["test_component_label"] + == "test_component_label_value" + ) + + def test_should_merge_global_and_component_specific_labels(self): + """Test adding both .Values.labels and .Values.statsd.labels.""" + docs = render_chart( + values={ + "statsd": { + "enabled": True, + "labels": {"test_component_label": "test_component_label_value"}, + }, + "ingress": {"statsd": {"enabled": True}}, + "labels": {"test_global_label": "test_global_label_value"}, + }, + show_only=[self.TEMPLATE_FILE], + ) + + assert "test_global_label" in jmespath.search("metadata.labels", docs[0]) + assert ( + jmespath.search("metadata.labels", docs[0])["test_global_label"] == "test_global_label_value" + ) + assert "test_component_label" in jmespath.search("metadata.labels", docs[0]) + assert ( + jmespath.search("metadata.labels", docs[0])["test_component_label"] + == "test_component_label_value" + ) + + def test_component_specific_labels_should_override_global_labels(self): + """Test that component-specific labels take precedence over global labels with the same key.""" + docs = render_chart( + values={ + "statsd": { + "enabled": True, + "labels": {"common_label": "component_value"}, + }, + "ingress": {"statsd": {"enabled": True}}, + "labels": {"common_label": "global_value"}, + }, + show_only=[self.TEMPLATE_FILE], + ) + + assert "common_label" in jmespath.search("metadata.labels", docs[0]) + assert jmespath.search("metadata.labels", docs[0])["common_label"] == "component_value" + diff --git a/helm-tests/tests/helm_tests/statsd/test_labels_networkpolicy.py b/helm-tests/tests/helm_tests/statsd/test_labels_networkpolicy.py new file mode 100644 index 0000000000000..fc000fce8a602 --- /dev/null +++ b/helm-tests/tests/helm_tests/statsd/test_labels_networkpolicy.py @@ -0,0 +1,103 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +from __future__ import annotations + +import jmespath +from chart_utils.helm_template_generator import render_chart + + +class TestStatsdNetworkPolicy: + """Tests statsd network policy labels.""" + + TEMPLATE_FILE = "templates/statsd/statsd-networkpolicy.yaml" + + def test_should_add_global_labels(self): + """Test adding only .Values.labels.""" + docs = render_chart( + values={ + "statsd": {"enabled": True}, + "networkPolicies": {"enabled": True}, + "labels": {"test_global_label": "test_global_label_value"}, + }, + show_only=[self.TEMPLATE_FILE], + ) + + assert "test_global_label" in jmespath.search("metadata.labels", docs[0]) + assert ( + jmespath.search("metadata.labels", docs[0])["test_global_label"] == "test_global_label_value" + ) + + def test_should_add_component_specific_labels(self): + """Test adding only .Values.statsd.labels.""" + docs = render_chart( + values={ + "statsd": { + "enabled": True, + "labels": {"test_component_label": "test_component_label_value"}, + }, + "networkPolicies": {"enabled": True}, + }, + show_only=[self.TEMPLATE_FILE], + ) + + assert "test_component_label" in jmespath.search("metadata.labels", docs[0]) + assert ( + jmespath.search("metadata.labels", docs[0])["test_component_label"] + == "test_component_label_value" + ) + + def test_should_merge_global_and_component_specific_labels(self): + """Test adding both .Values.labels and .Values.statsd.labels.""" + docs = render_chart( + values={ + "statsd": { + "enabled": True, + "labels": {"test_component_label": "test_component_label_value"}, + }, + "networkPolicies": {"enabled": True}, + "labels": {"test_global_label": "test_global_label_value"}, + }, + show_only=[self.TEMPLATE_FILE], + ) + + assert "test_global_label" in jmespath.search("metadata.labels", docs[0]) + assert ( + jmespath.search("metadata.labels", docs[0])["test_global_label"] == "test_global_label_value" + ) + assert "test_component_label" in jmespath.search("metadata.labels", docs[0]) + assert ( + jmespath.search("metadata.labels", docs[0])["test_component_label"] + == "test_component_label_value" + ) + + def test_component_specific_labels_should_override_global_labels(self): + """Test that component-specific labels take precedence over global labels with the same key.""" + docs = render_chart( + values={ + "statsd": { + "enabled": True, + "labels": {"common_label": "component_value"}, + }, + "networkPolicies": {"enabled": True}, + "labels": {"common_label": "global_value"}, + }, + show_only=[self.TEMPLATE_FILE], + ) + + assert "common_label" in jmespath.search("metadata.labels", docs[0]) + assert jmespath.search("metadata.labels", docs[0])["common_label"] == "component_value" + diff --git a/helm-tests/tests/helm_tests/statsd/test_labels_service.py b/helm-tests/tests/helm_tests/statsd/test_labels_service.py new file mode 100644 index 0000000000000..17feda1a78bc4 --- /dev/null +++ b/helm-tests/tests/helm_tests/statsd/test_labels_service.py @@ -0,0 +1,99 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +from __future__ import annotations + +import jmespath +from chart_utils.helm_template_generator import render_chart + + +class TestStatsdService: + """Tests statsd service labels.""" + + TEMPLATE_FILE = "templates/statsd/statsd-service.yaml" + + def test_should_add_global_labels(self): + """Test adding only .Values.labels.""" + docs = render_chart( + values={ + "statsd": {"enabled": True}, + "labels": {"test_global_label": "test_global_label_value"}, + }, + show_only=[self.TEMPLATE_FILE], + ) + + assert "test_global_label" in jmespath.search("metadata.labels", docs[0]) + assert ( + jmespath.search("metadata.labels", docs[0])["test_global_label"] == "test_global_label_value" + ) + + def test_should_add_component_specific_labels(self): + """Test adding only .Values.statsd.labels.""" + docs = render_chart( + values={ + "statsd": { + "enabled": True, + "labels": {"test_component_label": "test_component_label_value"}, + }, + }, + show_only=[self.TEMPLATE_FILE], + ) + + assert "test_component_label" in jmespath.search("metadata.labels", docs[0]) + assert ( + jmespath.search("metadata.labels", docs[0])["test_component_label"] + == "test_component_label_value" + ) + + def test_should_merge_global_and_component_specific_labels(self): + """Test adding both .Values.labels and .Values.statsd.labels.""" + docs = render_chart( + values={ + "statsd": { + "enabled": True, + "labels": {"test_component_label": "test_component_label_value"}, + }, + "labels": {"test_global_label": "test_global_label_value"}, + }, + show_only=[self.TEMPLATE_FILE], + ) + + assert "test_global_label" in jmespath.search("metadata.labels", docs[0]) + assert ( + jmespath.search("metadata.labels", docs[0])["test_global_label"] == "test_global_label_value" + ) + assert "test_component_label" in jmespath.search("metadata.labels", docs[0]) + assert ( + jmespath.search("metadata.labels", docs[0])["test_component_label"] + == "test_component_label_value" + ) + + def test_component_specific_labels_should_override_global_labels(self): + """Test that component-specific labels take precedence over global labels with the same key.""" + docs = render_chart( + values={ + "statsd": { + "enabled": True, + "labels": {"common_label": "component_value"}, + }, + "labels": {"common_label": "global_value"}, + }, + show_only=[self.TEMPLATE_FILE], + ) + + assert "common_label" in jmespath.search("metadata.labels", docs[0]) + assert jmespath.search("metadata.labels", docs[0])["common_label"] == "component_value" + diff --git a/helm-tests/tests/helm_tests/statsd/test_labels_serviceaccount.py b/helm-tests/tests/helm_tests/statsd/test_labels_serviceaccount.py new file mode 100644 index 0000000000000..17feda1a78bc4 --- /dev/null +++ b/helm-tests/tests/helm_tests/statsd/test_labels_serviceaccount.py @@ -0,0 +1,99 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +from __future__ import annotations + +import jmespath +from chart_utils.helm_template_generator import render_chart + + +class TestStatsdService: + """Tests statsd service labels.""" + + TEMPLATE_FILE = "templates/statsd/statsd-service.yaml" + + def test_should_add_global_labels(self): + """Test adding only .Values.labels.""" + docs = render_chart( + values={ + "statsd": {"enabled": True}, + "labels": {"test_global_label": "test_global_label_value"}, + }, + show_only=[self.TEMPLATE_FILE], + ) + + assert "test_global_label" in jmespath.search("metadata.labels", docs[0]) + assert ( + jmespath.search("metadata.labels", docs[0])["test_global_label"] == "test_global_label_value" + ) + + def test_should_add_component_specific_labels(self): + """Test adding only .Values.statsd.labels.""" + docs = render_chart( + values={ + "statsd": { + "enabled": True, + "labels": {"test_component_label": "test_component_label_value"}, + }, + }, + show_only=[self.TEMPLATE_FILE], + ) + + assert "test_component_label" in jmespath.search("metadata.labels", docs[0]) + assert ( + jmespath.search("metadata.labels", docs[0])["test_component_label"] + == "test_component_label_value" + ) + + def test_should_merge_global_and_component_specific_labels(self): + """Test adding both .Values.labels and .Values.statsd.labels.""" + docs = render_chart( + values={ + "statsd": { + "enabled": True, + "labels": {"test_component_label": "test_component_label_value"}, + }, + "labels": {"test_global_label": "test_global_label_value"}, + }, + show_only=[self.TEMPLATE_FILE], + ) + + assert "test_global_label" in jmespath.search("metadata.labels", docs[0]) + assert ( + jmespath.search("metadata.labels", docs[0])["test_global_label"] == "test_global_label_value" + ) + assert "test_component_label" in jmespath.search("metadata.labels", docs[0]) + assert ( + jmespath.search("metadata.labels", docs[0])["test_component_label"] + == "test_component_label_value" + ) + + def test_component_specific_labels_should_override_global_labels(self): + """Test that component-specific labels take precedence over global labels with the same key.""" + docs = render_chart( + values={ + "statsd": { + "enabled": True, + "labels": {"common_label": "component_value"}, + }, + "labels": {"common_label": "global_value"}, + }, + show_only=[self.TEMPLATE_FILE], + ) + + assert "common_label" in jmespath.search("metadata.labels", docs[0]) + assert jmespath.search("metadata.labels", docs[0])["common_label"] == "component_value" + From ecb44e9c40032e96a881691720581b0ffc8ce898 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Costa?= Date: Thu, 30 Oct 2025 13:34:06 +0000 Subject: [PATCH 7/8] tests(helm): Fix tests formatting --- helm-tests/tests/helm_tests/dagprocessor/__init__.py | 1 - .../helm_tests/dagprocessor/test_labels_deployment.py | 6 +----- .../dagprocessor/test_labels_service_account.py | 9 ++------- helm-tests/tests/helm_tests/redis/__init__.py | 1 - .../helm_tests/redis/test_labels_networkpolicy.py | 9 ++------- .../tests/helm_tests/redis/test_labels_service.py | 9 ++------- .../helm_tests/redis/test_labels_serviceaccount.py | 9 ++------- .../tests/helm_tests/redis/test_labels_statefulset.py | 10 ++-------- helm-tests/tests/helm_tests/statsd/__init__.py | 1 - .../tests/helm_tests/statsd/test_labels_deployment.py | 10 ++-------- .../tests/helm_tests/statsd/test_labels_ingress.py | 9 ++------- .../helm_tests/statsd/test_labels_networkpolicy.py | 9 ++------- .../tests/helm_tests/statsd/test_labels_service.py | 9 ++------- .../helm_tests/statsd/test_labels_serviceaccount.py | 9 ++------- 14 files changed, 21 insertions(+), 80 deletions(-) diff --git a/helm-tests/tests/helm_tests/dagprocessor/__init__.py b/helm-tests/tests/helm_tests/dagprocessor/__init__.py index 245692337bc3f..13a83393a9124 100644 --- a/helm-tests/tests/helm_tests/dagprocessor/__init__.py +++ b/helm-tests/tests/helm_tests/dagprocessor/__init__.py @@ -14,4 +14,3 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. - diff --git a/helm-tests/tests/helm_tests/dagprocessor/test_labels_deployment.py b/helm-tests/tests/helm_tests/dagprocessor/test_labels_deployment.py index 430d6a100a2a1..7a044783353b9 100644 --- a/helm-tests/tests/helm_tests/dagprocessor/test_labels_deployment.py +++ b/helm-tests/tests/helm_tests/dagprocessor/test_labels_deployment.py @@ -98,8 +98,4 @@ def test_component_specific_labels_should_override_global_labels(self): ) assert "common_label" in jmespath.search("spec.template.metadata.labels", docs[0]) - assert ( - jmespath.search("spec.template.metadata.labels", docs[0])["common_label"] - == "component_value" - ) - + assert jmespath.search("spec.template.metadata.labels", docs[0])["common_label"] == "component_value" diff --git a/helm-tests/tests/helm_tests/dagprocessor/test_labels_service_account.py b/helm-tests/tests/helm_tests/dagprocessor/test_labels_service_account.py index dcbd46e1e7e33..6f8bb8bf8b4be 100644 --- a/helm-tests/tests/helm_tests/dagprocessor/test_labels_service_account.py +++ b/helm-tests/tests/helm_tests/dagprocessor/test_labels_service_account.py @@ -37,9 +37,7 @@ def test_should_add_global_labels(self): ) assert "test_global_label" in jmespath.search("metadata.labels", docs[0]) - assert ( - jmespath.search("metadata.labels", docs[0])["test_global_label"] == "test_global_label_value" - ) + assert jmespath.search("metadata.labels", docs[0])["test_global_label"] == "test_global_label_value" def test_should_add_component_specific_labels(self): """Test adding only .Values.dagProcessor.labels.""" @@ -73,9 +71,7 @@ def test_should_merge_global_and_component_specific_labels(self): ) assert "test_global_label" in jmespath.search("metadata.labels", docs[0]) - assert ( - jmespath.search("metadata.labels", docs[0])["test_global_label"] == "test_global_label_value" - ) + assert jmespath.search("metadata.labels", docs[0])["test_global_label"] == "test_global_label_value" assert "test_component_label" in jmespath.search("metadata.labels", docs[0]) assert ( jmespath.search("metadata.labels", docs[0])["test_component_label"] @@ -97,4 +93,3 @@ def test_component_specific_labels_should_override_global_labels(self): assert "common_label" in jmespath.search("metadata.labels", docs[0]) assert jmespath.search("metadata.labels", docs[0])["common_label"] == "component_value" - diff --git a/helm-tests/tests/helm_tests/redis/__init__.py b/helm-tests/tests/helm_tests/redis/__init__.py index 245692337bc3f..13a83393a9124 100644 --- a/helm-tests/tests/helm_tests/redis/__init__.py +++ b/helm-tests/tests/helm_tests/redis/__init__.py @@ -14,4 +14,3 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. - diff --git a/helm-tests/tests/helm_tests/redis/test_labels_networkpolicy.py b/helm-tests/tests/helm_tests/redis/test_labels_networkpolicy.py index 68bf50881487f..54b324eb495c5 100644 --- a/helm-tests/tests/helm_tests/redis/test_labels_networkpolicy.py +++ b/helm-tests/tests/helm_tests/redis/test_labels_networkpolicy.py @@ -39,9 +39,7 @@ def test_should_add_global_labels(self): ) assert "test_global_label" in jmespath.search("metadata.labels", docs[0]) - assert ( - jmespath.search("metadata.labels", docs[0])["test_global_label"] == "test_global_label_value" - ) + assert jmespath.search("metadata.labels", docs[0])["test_global_label"] == "test_global_label_value" def test_should_add_component_specific_labels(self): """Test adding only .Values.redis.labels.""" @@ -79,9 +77,7 @@ def test_should_merge_global_and_component_specific_labels(self): ) assert "test_global_label" in jmespath.search("metadata.labels", docs[0]) - assert ( - jmespath.search("metadata.labels", docs[0])["test_global_label"] == "test_global_label_value" - ) + assert jmespath.search("metadata.labels", docs[0])["test_global_label"] == "test_global_label_value" assert "test_component_label" in jmespath.search("metadata.labels", docs[0]) assert ( jmespath.search("metadata.labels", docs[0])["test_component_label"] @@ -105,4 +101,3 @@ def test_component_specific_labels_should_override_global_labels(self): assert "common_label" in jmespath.search("metadata.labels", docs[0]) assert jmespath.search("metadata.labels", docs[0])["common_label"] == "component_value" - diff --git a/helm-tests/tests/helm_tests/redis/test_labels_service.py b/helm-tests/tests/helm_tests/redis/test_labels_service.py index 4eaf376f39999..d8f6cd0c46503 100644 --- a/helm-tests/tests/helm_tests/redis/test_labels_service.py +++ b/helm-tests/tests/helm_tests/redis/test_labels_service.py @@ -38,9 +38,7 @@ def test_should_add_global_labels(self): ) assert "test_global_label" in jmespath.search("metadata.labels", docs[0]) - assert ( - jmespath.search("metadata.labels", docs[0])["test_global_label"] == "test_global_label_value" - ) + assert jmespath.search("metadata.labels", docs[0])["test_global_label"] == "test_global_label_value" def test_should_add_component_specific_labels(self): """Test adding only .Values.redis.labels.""" @@ -76,9 +74,7 @@ def test_should_merge_global_and_component_specific_labels(self): ) assert "test_global_label" in jmespath.search("metadata.labels", docs[0]) - assert ( - jmespath.search("metadata.labels", docs[0])["test_global_label"] == "test_global_label_value" - ) + assert jmespath.search("metadata.labels", docs[0])["test_global_label"] == "test_global_label_value" assert "test_component_label" in jmespath.search("metadata.labels", docs[0]) assert ( jmespath.search("metadata.labels", docs[0])["test_component_label"] @@ -101,4 +97,3 @@ def test_component_specific_labels_should_override_global_labels(self): assert "common_label" in jmespath.search("metadata.labels", docs[0]) assert jmespath.search("metadata.labels", docs[0])["common_label"] == "component_value" - diff --git a/helm-tests/tests/helm_tests/redis/test_labels_serviceaccount.py b/helm-tests/tests/helm_tests/redis/test_labels_serviceaccount.py index e244dcda8b362..2c90b3d20be7f 100644 --- a/helm-tests/tests/helm_tests/redis/test_labels_serviceaccount.py +++ b/helm-tests/tests/helm_tests/redis/test_labels_serviceaccount.py @@ -41,9 +41,7 @@ def test_should_add_global_labels(self): ) assert "test_global_label" in jmespath.search("metadata.labels", docs[0]) - assert ( - jmespath.search("metadata.labels", docs[0])["test_global_label"] == "test_global_label_value" - ) + assert jmespath.search("metadata.labels", docs[0])["test_global_label"] == "test_global_label_value" def test_should_add_component_specific_labels(self): """Test adding only .Values.redis.labels.""" @@ -81,9 +79,7 @@ def test_should_merge_global_and_component_specific_labels(self): ) assert "test_global_label" in jmespath.search("metadata.labels", docs[0]) - assert ( - jmespath.search("metadata.labels", docs[0])["test_global_label"] == "test_global_label_value" - ) + assert jmespath.search("metadata.labels", docs[0])["test_global_label"] == "test_global_label_value" assert "test_component_label" in jmespath.search("metadata.labels", docs[0]) assert ( jmespath.search("metadata.labels", docs[0])["test_component_label"] @@ -107,4 +103,3 @@ def test_component_specific_labels_should_override_global_labels(self): assert "common_label" in jmespath.search("metadata.labels", docs[0]) assert jmespath.search("metadata.labels", docs[0])["common_label"] == "component_value" - diff --git a/helm-tests/tests/helm_tests/redis/test_labels_statefulset.py b/helm-tests/tests/helm_tests/redis/test_labels_statefulset.py index fd729cc1f5080..e4e189e2c9fe0 100644 --- a/helm-tests/tests/helm_tests/redis/test_labels_statefulset.py +++ b/helm-tests/tests/helm_tests/redis/test_labels_statefulset.py @@ -38,9 +38,7 @@ def test_should_add_global_labels_to_metadata(self): ) assert "test_global_label" in jmespath.search("metadata.labels", docs[0]) - assert ( - jmespath.search("metadata.labels", docs[0])["test_global_label"] == "test_global_label_value" - ) + assert jmespath.search("metadata.labels", docs[0])["test_global_label"] == "test_global_label_value" def test_should_add_global_labels_to_pod_template(self): """Test adding only .Values.labels to spec.template.metadata.labels.""" @@ -118,8 +116,4 @@ def test_component_specific_labels_should_override_global_labels(self): ) assert "common_label" in jmespath.search("spec.template.metadata.labels", docs[0]) - assert ( - jmespath.search("spec.template.metadata.labels", docs[0])["common_label"] - == "component_value" - ) - + assert jmespath.search("spec.template.metadata.labels", docs[0])["common_label"] == "component_value" diff --git a/helm-tests/tests/helm_tests/statsd/__init__.py b/helm-tests/tests/helm_tests/statsd/__init__.py index 245692337bc3f..13a83393a9124 100644 --- a/helm-tests/tests/helm_tests/statsd/__init__.py +++ b/helm-tests/tests/helm_tests/statsd/__init__.py @@ -14,4 +14,3 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. - diff --git a/helm-tests/tests/helm_tests/statsd/test_labels_deployment.py b/helm-tests/tests/helm_tests/statsd/test_labels_deployment.py index 78bda9fdc32ff..867facb0fd337 100644 --- a/helm-tests/tests/helm_tests/statsd/test_labels_deployment.py +++ b/helm-tests/tests/helm_tests/statsd/test_labels_deployment.py @@ -36,9 +36,7 @@ def test_should_add_global_labels_to_metadata(self): ) assert "test_global_label" in jmespath.search("metadata.labels", docs[0]) - assert ( - jmespath.search("metadata.labels", docs[0])["test_global_label"] == "test_global_label_value" - ) + assert jmespath.search("metadata.labels", docs[0])["test_global_label"] == "test_global_label_value" def test_should_add_global_labels_to_pod_template(self): """Test adding only .Values.labels to spec.template.metadata.labels.""" @@ -112,8 +110,4 @@ def test_component_specific_labels_should_override_global_labels(self): ) assert "common_label" in jmespath.search("spec.template.metadata.labels", docs[0]) - assert ( - jmespath.search("spec.template.metadata.labels", docs[0])["common_label"] - == "component_value" - ) - + assert jmespath.search("spec.template.metadata.labels", docs[0])["common_label"] == "component_value" diff --git a/helm-tests/tests/helm_tests/statsd/test_labels_ingress.py b/helm-tests/tests/helm_tests/statsd/test_labels_ingress.py index b4ad4550588ff..fb7c72365fe22 100644 --- a/helm-tests/tests/helm_tests/statsd/test_labels_ingress.py +++ b/helm-tests/tests/helm_tests/statsd/test_labels_ingress.py @@ -37,9 +37,7 @@ def test_should_add_global_labels(self): ) assert "test_global_label" in jmespath.search("metadata.labels", docs[0]) - assert ( - jmespath.search("metadata.labels", docs[0])["test_global_label"] == "test_global_label_value" - ) + assert jmespath.search("metadata.labels", docs[0])["test_global_label"] == "test_global_label_value" def test_should_add_component_specific_labels(self): """Test adding only .Values.statsd.labels.""" @@ -75,9 +73,7 @@ def test_should_merge_global_and_component_specific_labels(self): ) assert "test_global_label" in jmespath.search("metadata.labels", docs[0]) - assert ( - jmespath.search("metadata.labels", docs[0])["test_global_label"] == "test_global_label_value" - ) + assert jmespath.search("metadata.labels", docs[0])["test_global_label"] == "test_global_label_value" assert "test_component_label" in jmespath.search("metadata.labels", docs[0]) assert ( jmespath.search("metadata.labels", docs[0])["test_component_label"] @@ -100,4 +96,3 @@ def test_component_specific_labels_should_override_global_labels(self): assert "common_label" in jmespath.search("metadata.labels", docs[0]) assert jmespath.search("metadata.labels", docs[0])["common_label"] == "component_value" - diff --git a/helm-tests/tests/helm_tests/statsd/test_labels_networkpolicy.py b/helm-tests/tests/helm_tests/statsd/test_labels_networkpolicy.py index fc000fce8a602..0fbf3bb680b28 100644 --- a/helm-tests/tests/helm_tests/statsd/test_labels_networkpolicy.py +++ b/helm-tests/tests/helm_tests/statsd/test_labels_networkpolicy.py @@ -37,9 +37,7 @@ def test_should_add_global_labels(self): ) assert "test_global_label" in jmespath.search("metadata.labels", docs[0]) - assert ( - jmespath.search("metadata.labels", docs[0])["test_global_label"] == "test_global_label_value" - ) + assert jmespath.search("metadata.labels", docs[0])["test_global_label"] == "test_global_label_value" def test_should_add_component_specific_labels(self): """Test adding only .Values.statsd.labels.""" @@ -75,9 +73,7 @@ def test_should_merge_global_and_component_specific_labels(self): ) assert "test_global_label" in jmespath.search("metadata.labels", docs[0]) - assert ( - jmespath.search("metadata.labels", docs[0])["test_global_label"] == "test_global_label_value" - ) + assert jmespath.search("metadata.labels", docs[0])["test_global_label"] == "test_global_label_value" assert "test_component_label" in jmespath.search("metadata.labels", docs[0]) assert ( jmespath.search("metadata.labels", docs[0])["test_component_label"] @@ -100,4 +96,3 @@ def test_component_specific_labels_should_override_global_labels(self): assert "common_label" in jmespath.search("metadata.labels", docs[0]) assert jmespath.search("metadata.labels", docs[0])["common_label"] == "component_value" - diff --git a/helm-tests/tests/helm_tests/statsd/test_labels_service.py b/helm-tests/tests/helm_tests/statsd/test_labels_service.py index 17feda1a78bc4..73ff5b49912df 100644 --- a/helm-tests/tests/helm_tests/statsd/test_labels_service.py +++ b/helm-tests/tests/helm_tests/statsd/test_labels_service.py @@ -36,9 +36,7 @@ def test_should_add_global_labels(self): ) assert "test_global_label" in jmespath.search("metadata.labels", docs[0]) - assert ( - jmespath.search("metadata.labels", docs[0])["test_global_label"] == "test_global_label_value" - ) + assert jmespath.search("metadata.labels", docs[0])["test_global_label"] == "test_global_label_value" def test_should_add_component_specific_labels(self): """Test adding only .Values.statsd.labels.""" @@ -72,9 +70,7 @@ def test_should_merge_global_and_component_specific_labels(self): ) assert "test_global_label" in jmespath.search("metadata.labels", docs[0]) - assert ( - jmespath.search("metadata.labels", docs[0])["test_global_label"] == "test_global_label_value" - ) + assert jmespath.search("metadata.labels", docs[0])["test_global_label"] == "test_global_label_value" assert "test_component_label" in jmespath.search("metadata.labels", docs[0]) assert ( jmespath.search("metadata.labels", docs[0])["test_component_label"] @@ -96,4 +92,3 @@ def test_component_specific_labels_should_override_global_labels(self): assert "common_label" in jmespath.search("metadata.labels", docs[0]) assert jmespath.search("metadata.labels", docs[0])["common_label"] == "component_value" - diff --git a/helm-tests/tests/helm_tests/statsd/test_labels_serviceaccount.py b/helm-tests/tests/helm_tests/statsd/test_labels_serviceaccount.py index 17feda1a78bc4..73ff5b49912df 100644 --- a/helm-tests/tests/helm_tests/statsd/test_labels_serviceaccount.py +++ b/helm-tests/tests/helm_tests/statsd/test_labels_serviceaccount.py @@ -36,9 +36,7 @@ def test_should_add_global_labels(self): ) assert "test_global_label" in jmespath.search("metadata.labels", docs[0]) - assert ( - jmespath.search("metadata.labels", docs[0])["test_global_label"] == "test_global_label_value" - ) + assert jmespath.search("metadata.labels", docs[0])["test_global_label"] == "test_global_label_value" def test_should_add_component_specific_labels(self): """Test adding only .Values.statsd.labels.""" @@ -72,9 +70,7 @@ def test_should_merge_global_and_component_specific_labels(self): ) assert "test_global_label" in jmespath.search("metadata.labels", docs[0]) - assert ( - jmespath.search("metadata.labels", docs[0])["test_global_label"] == "test_global_label_value" - ) + assert jmespath.search("metadata.labels", docs[0])["test_global_label"] == "test_global_label_value" assert "test_component_label" in jmespath.search("metadata.labels", docs[0]) assert ( jmespath.search("metadata.labels", docs[0])["test_component_label"] @@ -96,4 +92,3 @@ def test_component_specific_labels_should_override_global_labels(self): assert "common_label" in jmespath.search("metadata.labels", docs[0]) assert jmespath.search("metadata.labels", docs[0])["common_label"] == "component_value" - From 65cc457fb4f12b8e5a41bd7fcecc1c430bebf28a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Costa?= Date: Mon, 3 Nov 2025 08:32:12 +0000 Subject: [PATCH 8/8] fix(docs): Update breeze output docs --- dev/breeze/doc/images/output-commands.svg | 4 +- .../doc/images/output_testing_helm-tests.svg | 54 ++++++++++--------- .../doc/images/output_testing_helm-tests.txt | 2 +- 3 files changed, 32 insertions(+), 28 deletions(-) diff --git a/dev/breeze/doc/images/output-commands.svg b/dev/breeze/doc/images/output-commands.svg index 84ee1aa8caeab..d8ec4f40c1d95 100644 --- a/dev/breeze/doc/images/output-commands.svg +++ b/dev/breeze/doc/images/output-commands.svg @@ -345,8 +345,8 @@ localstack | mongo | mssql | openlineage | otel | pinot | qdrant | redis | redis | statsd | tinkerpop | trino | ydb)                                                    ---standalone-dag-processor/--no-standalone-dag-process…Run standalone dag processor for start-airflow          -(required for Airflow 3).                               +--standalone-dag-processor/--no-standalone-dag-processoRun standalone dag processor for start-airflow          +r(required for Airflow 3).                               [default: standalone-dag-processor]                     --auth-managerSpecify the auth manager to set        (>SimpleAuthManager< | FabAuthManager) diff --git a/dev/breeze/doc/images/output_testing_helm-tests.svg b/dev/breeze/doc/images/output_testing_helm-tests.svg index b5532a7ea1560..133234e5d15b1 100644 --- a/dev/breeze/doc/images/output_testing_helm-tests.svg +++ b/dev/breeze/doc/images/output_testing_helm-tests.svg @@ -1,4 +1,4 @@ - + Run Helm chart tests. ╭─ Flags for helms-tests command ──────────────────────────────────────────────────────────────────────────────────────╮ ---test-typeType of helm tests to run                                                     -(All | airflow_aux | airflow_core | apiserver | other | security | webserver) -[default: All]                                                                ---test-timeoutTest timeout in seconds. Set the pytest setup, execution and teardown timeouts to this value -(INTEGER RANGE)                                                                              -[default: 60; x>=0]                                                                          ---use-xdistUse xdist plugin for pytest ---parallelismMaximum number of processes to use while running the operation in parallel.(INTEGER RANGE) -[default: 4; 1<=x<=8]                                                       -╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ -╭─ Advanced flag for helm-test command ────────────────────────────────────────────────────────────────────────────────╮ ---github-repository-gGitHub repository used to pull, push run images.(TEXT)[default: apache/airflow] ---mount-sourcesChoose scope of local sources that should be mounted, skipped, or removed (default =        -selected).                                                                                  -(selected | all | skip | remove | tests | providers-and-tests)                              -[default: selected]                                                                         -╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ -╭─ Common options ─────────────────────────────────────────────────────────────────────────────────────────────────────╮ ---verbose-vPrint verbose information about performed steps. ---dry-run-DIf dry-run is set, commands are only printed, not executed. ---help-hShow this message and exit. -╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ +--test-typeType of helm tests to run                                                                          +(All | airflow_aux | airflow_core | apiserver | dagprocessor | other | redis | security | statsd | +webserver)                                                                                         +[default: All]                                                                                     +--test-timeoutTest timeout in seconds. Set the pytest setup, execution and teardown timeouts to this value +(INTEGER RANGE)                                                                              +[default: 60; x>=0]                                                                          +--use-xdistUse xdist plugin for pytest +--parallelismMaximum number of processes to use while running the operation in parallel.(INTEGER RANGE) +[default: 4; 1<=x<=8]                                                       +╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ +╭─ Advanced flag for helm-test command ────────────────────────────────────────────────────────────────────────────────╮ +--github-repository-gGitHub repository used to pull, push run images.(TEXT)[default: apache/airflow] +--mount-sourcesChoose scope of local sources that should be mounted, skipped, or removed (default =        +selected).                                                                                  +(selected | all | skip | remove | tests | providers-and-tests)                              +[default: selected]                                                                         +╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ +╭─ Common options ─────────────────────────────────────────────────────────────────────────────────────────────────────╮ +--verbose-vPrint verbose information about performed steps. +--dry-run-DIf dry-run is set, commands are only printed, not executed. +--help-hShow this message and exit. +╰──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯ diff --git a/dev/breeze/doc/images/output_testing_helm-tests.txt b/dev/breeze/doc/images/output_testing_helm-tests.txt index 14ca452d17ba6..cfa0314542d30 100644 --- a/dev/breeze/doc/images/output_testing_helm-tests.txt +++ b/dev/breeze/doc/images/output_testing_helm-tests.txt @@ -1 +1 @@ -f67f6341ee5ef1786505b25152a278cc +33c785aec11cf1a774057a69bb8364ba