Skip to content

Commit bdd7111

Browse files
authored
CP-33495: make sure labels/annotations are configurable for all resources (#486)
* CP-33495: add configurable labels and annotations for config-loader and helmless jobs Allow users to set custom labels and annotations on the config-loader and helmless Job resources via values.yaml. These component-specific settings are merged with defaults.labels and defaults.annotations, with component-specific values taking precedence. Changes: - Add components.miscellaneous.configLoader.labels field - Add components.miscellaneous.configLoader.annotations field - Add components.miscellaneous.helmless.labels field - Add components.miscellaneous.helmless.annotations field - Update config-loader-job.yaml template to merge annotations/labels - Update helmless-job.yaml template to merge annotations/labels - Add schema validation for new fields in values.schema.yaml - Add comprehensive Helm unittest coverage (24 new test cases) - Add schema validation tests (8 test files: 4 pass, 4 fail cases) Breaking Change: This commit changes the app.kubernetes.io/component label for these jobs to provide clearer resource identification: - config-loader Job: "webhook-server" → "config-loader" - config-loader Pod: "<hash>" → "config-loader" - helmless Job: (none) → "helmless" - helmless Pod: (none) → "helmless" The previous behavior was inconsistent (Job used "webhook-server", Pod used a hash of the job name). The new behavior provides consistent, meaningful component labels that accurately reflect the actual component identity Testing: - All existing tests pass - New Helm unittests verify label/annotation merging behavior - New Helm unittests verify component-specific overrides - New Helm unittests verify empty/null handling - Schema tests verify correct type validation - Schema tests verify invalid inputs are rejected Documentation: - Added inline comments in values.yaml for new fields - Added descriptions in values.schema.yaml * Ensure all Helm resources inherit defaults.labels and defaults.annotations Fixed PodDisruptionBudgets, aggregator-service, and webhook-serviceaccount templates to properly inherit defaults.labels and defaults.annotations. Modified templates: - helm/templates/_helpers.tpl: Updated generatePodDisruptionBudget helper to accept componentName parameter and use generateLabels/generateAnnotations - helm/templates/agent-pdb.yaml: Pass componentName to helper - helm/templates/aggregator-pdb.yaml: Pass componentName to helper - helm/templates/webhook-pdb.yaml: Pass componentName to helper - helm/templates/aggregator-service.yaml: Added generateAnnotations call - helm/templates/webhook-serviceaccount.yaml: Added generateAnnotations call When implementing configurable labels/annotations for config-loader and helmless jobs, created a comprehensive test that validates all resources inherit defaults.labels and defaults.annotations. The test revealed PDBs and two other templates were not inheriting defaults, causing inconsistent metadata across deployed resources. New test helm/tests/defaults_labels_annotations_all_resources_test.yaml validates 28 templates properly inherit defaults by setting sentinel values (foo: "bar") and verifying they appear in all resource metadata. Test enables optional features (federation, webhook, persistentVolume) to render conditional templates.
1 parent c4619e4 commit bdd7111

26 files changed

+744
-19
lines changed

app/functions/helmless/default-values.yaml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,14 @@ components:
293293
# For details, see the Kubernetes documentation on security contexts:
294294
# https://kubernetes.io/docs/tasks/configure-pod-container/security-context/
295295
securityContext: {}
296+
# Annotations to add to the config loader job.
297+
#
298+
# These annotations are merged with defaults.annotations.
299+
annotations: {}
300+
# Labels to add to the config loader job.
301+
#
302+
# These labels are merged with defaults.labels.
303+
labels: {}
296304
# The helmless job component generates configuration without Helm.
297305
helmless:
298306
# Resource requirements and limits for the helmless job component.
@@ -311,6 +319,14 @@ components:
311319
# For details, see the Kubernetes documentation on security contexts:
312320
# https://kubernetes.io/docs/tasks/configure-pod-container/security-context/
313321
securityContext: {}
322+
# Annotations to add to the helmless job.
323+
#
324+
# These annotations are merged with defaults.annotations.
325+
annotations: {}
326+
# Labels to add to the helmless job.
327+
#
328+
# These labels are merged with defaults.labels.
329+
labels: {}
314330
# The init cert job component initializes TLS certificates.
315331
initCert:
316332
# Resource requirements and limits for the init cert job component.

helm/templates/_helpers.tpl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -912,6 +912,8 @@ kind: PodDisruptionBudget
912912
metadata:
913913
name: {{ .name }}
914914
namespace: {{ .root.Release.Namespace }}
915+
{{- include "cloudzero-agent.generateLabels" (dict "globals" .root "component" .componentName) | nindent 2 }}
916+
{{- include "cloudzero-agent.generateAnnotations" .root.Values.defaults.annotations | nindent 2 }}
915917
spec:
916918
{{- if $pdb.minAvailable }}
917919
{{- if lt $replicas (int $pdb.minAvailable) -}}

helm/templates/agent-pdb.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{{ include "cloudzero-agent.generatePodDisruptionBudget" (dict
22
"component" .Values.components.agent
3+
"componentName" .Values.server.name
34
"name" (include "cloudzero-agent.server.fullname" .)
45
"matchLabels" (include "cloudzero-agent.server.matchLabels" .)
56
"root" .

helm/templates/aggregator-pdb.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{{ include "cloudzero-agent.generatePodDisruptionBudget" (dict
22
"component" .Values.components.aggregator
3+
"componentName" "aggregator"
34
"name" (include "cloudzero-agent.aggregator.name" .)
45
"matchLabels" (include "cloudzero-agent.aggregator.matchLabels" .)
56
"root" .

helm/templates/aggregator-service.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ metadata:
55
name: {{ include "cloudzero-agent.aggregator.name" . }}
66
labels:
77
{{- include "cloudzero-agent.aggregator.labels" . | nindent 4 }}
8+
{{- include "cloudzero-agent.generateAnnotations" .Values.defaults.annotations | nindent 2 }}
89
spec:
910
selector:
1011
{{- include "cloudzero-agent.aggregator.matchLabels" . | nindent 4 }}

helm/templates/config-loader-job.yaml

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,21 @@ metadata:
44
name: {{ include "cloudzero-agent.configLoaderJobName" . }}
55
namespace: {{ .Release.Namespace }}
66
{{- include "cloudzero-agent.generateAnnotations" (merge
7-
(deepCopy .Values.defaults.annotations)
87
(dict "checksum/values" (include "cloudzero-agent.configurationChecksum" .))
8+
(.Values.components.miscellaneous.configLoader.annotations | default (dict))
9+
(deepCopy .Values.defaults.annotations)
910
) | nindent 2 }}
10-
labels:
11-
{{- include "cloudzero-agent.insightsController.labels" . | nindent 4 }}
11+
{{- include "cloudzero-agent.generateLabels" (dict "globals" . "component" "config-loader" "labels" .Values.components.miscellaneous.configLoader.labels) | nindent 2 }}
1212
spec:
1313
template:
1414
metadata:
1515
name: {{ include "cloudzero-agent.configLoaderJobName" . }}
1616
namespace: {{ .Release.Namespace }}
17-
labels:
18-
{{- include "cloudzero-agent.insightsController.validatorJob.matchLabels" . | nindent 8 }}
19-
{{- include "cloudzero-agent.generateAnnotations" .Values.defaults.annotations | nindent 6 }}
17+
{{- include "cloudzero-agent.generateLabels" (dict "globals" . "component" "config-loader" "labels" .Values.components.miscellaneous.configLoader.labels) | nindent 6 }}
18+
{{- include "cloudzero-agent.generateAnnotations" (merge
19+
(.Values.components.miscellaneous.configLoader.annotations | default (dict))
20+
(deepCopy .Values.defaults.annotations)
21+
) | nindent 6 }}
2022
spec:
2123
{{- include "cloudzero-agent.generateImagePullSecrets" (dict "root" . "image" .Values.validator.image) | nindent 6 }}
2224
serviceAccountName: {{ include "cloudzero-agent.serviceAccountName" . }}

helm/templates/helmless-job.yaml

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,21 @@ kind: Job
33
metadata:
44
name: {{ include "cloudzero-agent.helmlessJobName" . }}
55
namespace: {{ .Release.Namespace }}
6-
{{- include "cloudzero-agent.generateAnnotations" .Values.defaults.annotations | nindent 2 }}
7-
{{- include "cloudzero-agent.generateLabels" (dict "globals" . "component" "helmless") | nindent 2 }}
6+
{{- include "cloudzero-agent.generateAnnotations" (merge
7+
(.Values.components.miscellaneous.helmless.annotations | default (dict))
8+
(deepCopy .Values.defaults.annotations)
9+
) | nindent 2 }}
10+
{{- include "cloudzero-agent.generateLabels" (dict "globals" . "component" "helmless" "labels" .Values.components.miscellaneous.helmless.labels) | nindent 2 }}
811
spec:
912
template:
1013
metadata:
1114
name: {{ include "cloudzero-agent.helmlessJobName" . }}
1215
namespace: {{ .Release.Namespace }}
13-
{{- include "cloudzero-agent.generateLabels" (dict "globals" . "component" "helmless") | nindent 6 }}
14-
{{- include "cloudzero-agent.generateAnnotations" .Values.defaults.annotations | nindent 6 }}
16+
{{- include "cloudzero-agent.generateLabels" (dict "globals" . "component" "helmless" "labels" .Values.components.miscellaneous.helmless.labels) | nindent 6 }}
17+
{{- include "cloudzero-agent.generateAnnotations" (merge
18+
(.Values.components.miscellaneous.helmless.annotations | default (dict))
19+
(deepCopy .Values.defaults.annotations)
20+
) | nindent 6 }}
1521
spec:
1622
restartPolicy: OnFailure
1723
{{- include "cloudzero-agent.generateImagePullSecrets" (dict "root" . "image" .Values.components.agent.image) | nindent 6 }}

helm/templates/webhook-pdb.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{{ include "cloudzero-agent.generatePodDisruptionBudget" (dict
22
"component" .Values.components.webhookServer
3+
"componentName" .Values.insightsController.server.name
34
"name" (include "cloudzero-agent.insightsController.deploymentName" .)
45
"matchLabels" (include "cloudzero-agent.insightsController.server.matchLabels" .)
56
"replicas" (.Values.insightsController.server.replicaCount | default .Values.components.webhookServer.replicas)

helm/templates/webhook-serviceaccount.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ kind: ServiceAccount
44
metadata:
55
labels:
66
{{- include "cloudzero-agent.insightsController.labels" . | nindent 4 }}
7+
{{- include "cloudzero-agent.generateAnnotations" .Values.defaults.annotations | nindent 2 }}
78
name: {{ template "cloudzero-agent.initCertJob.serviceAccountName" . }}
89
namespace: {{ include "cloudzero-agent.namespace" . }}
910
{{- end }}
Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
suite: test config-loader job labels and annotations
2+
templates:
3+
- templates/config-loader-job.yaml
4+
tests:
5+
# Test default labels are applied
6+
- it: should apply default labels to Job metadata
7+
set:
8+
defaults.labels:
9+
custom-label: "default-value"
10+
team: "platform"
11+
asserts:
12+
- equal:
13+
path: metadata.labels["custom-label"]
14+
value: "default-value"
15+
- equal:
16+
path: metadata.labels["team"]
17+
value: "platform"
18+
19+
# Test default labels are applied to Pod template
20+
- it: should apply default labels to Pod template metadata
21+
set:
22+
defaults.labels:
23+
custom-label: "default-value"
24+
team: "platform"
25+
asserts:
26+
- equal:
27+
path: spec.template.metadata.labels["custom-label"]
28+
value: "default-value"
29+
- equal:
30+
path: spec.template.metadata.labels["team"]
31+
value: "platform"
32+
33+
# Test component-specific labels override defaults
34+
- it: should merge component-specific labels with defaults on Job metadata
35+
set:
36+
defaults.labels:
37+
custom-label: "default-value"
38+
team: "platform"
39+
components.miscellaneous.configLoader.labels:
40+
custom-label: "overridden-value"
41+
environment: "production"
42+
asserts:
43+
- equal:
44+
path: metadata.labels["custom-label"]
45+
value: "overridden-value"
46+
- equal:
47+
path: metadata.labels["team"]
48+
value: "platform"
49+
- equal:
50+
path: metadata.labels["environment"]
51+
value: "production"
52+
53+
# Test component-specific labels override defaults on Pod template
54+
- it: should merge component-specific labels with defaults on Pod template metadata
55+
set:
56+
defaults.labels:
57+
custom-label: "default-value"
58+
team: "platform"
59+
components.miscellaneous.configLoader.labels:
60+
custom-label: "overridden-value"
61+
environment: "production"
62+
asserts:
63+
- equal:
64+
path: spec.template.metadata.labels["custom-label"]
65+
value: "overridden-value"
66+
- equal:
67+
path: spec.template.metadata.labels["team"]
68+
value: "platform"
69+
- equal:
70+
path: spec.template.metadata.labels["environment"]
71+
value: "production"
72+
73+
# Test default annotations are applied
74+
- it: should apply default annotations to Job metadata
75+
set:
76+
defaults.annotations:
77+
prometheus.io/scrape: "true"
78+
monitoring.io/alert: "critical"
79+
asserts:
80+
- equal:
81+
path: metadata.annotations["prometheus.io/scrape"]
82+
value: "true"
83+
- equal:
84+
path: metadata.annotations["monitoring.io/alert"]
85+
value: "critical"
86+
87+
# Test default annotations are applied to Pod template
88+
- it: should apply default annotations to Pod template metadata
89+
set:
90+
defaults.annotations:
91+
prometheus.io/scrape: "true"
92+
monitoring.io/alert: "critical"
93+
asserts:
94+
- equal:
95+
path: spec.template.metadata.annotations["prometheus.io/scrape"]
96+
value: "true"
97+
- equal:
98+
path: spec.template.metadata.annotations["monitoring.io/alert"]
99+
value: "critical"
100+
101+
# Test component-specific annotations override defaults
102+
- it: should merge component-specific annotations with defaults on Job metadata
103+
set:
104+
defaults.annotations:
105+
prometheus.io/scrape: "true"
106+
monitoring.io/alert: "critical"
107+
components.miscellaneous.configLoader.annotations:
108+
prometheus.io/scrape: "false"
109+
custom.io/annotation: "value"
110+
asserts:
111+
- equal:
112+
path: metadata.annotations["prometheus.io/scrape"]
113+
value: "false"
114+
- equal:
115+
path: metadata.annotations["monitoring.io/alert"]
116+
value: "critical"
117+
- equal:
118+
path: metadata.annotations["custom.io/annotation"]
119+
value: "value"
120+
121+
# Test component-specific annotations override defaults on Pod template
122+
- it: should merge component-specific annotations with defaults on Pod template metadata
123+
set:
124+
defaults.annotations:
125+
prometheus.io/scrape: "true"
126+
monitoring.io/alert: "critical"
127+
components.miscellaneous.configLoader.annotations:
128+
prometheus.io/scrape: "false"
129+
custom.io/annotation: "value"
130+
asserts:
131+
- equal:
132+
path: spec.template.metadata.annotations["prometheus.io/scrape"]
133+
value: "false"
134+
- equal:
135+
path: spec.template.metadata.annotations["monitoring.io/alert"]
136+
value: "critical"
137+
- equal:
138+
path: spec.template.metadata.annotations["custom.io/annotation"]
139+
value: "value"
140+
141+
# Test empty labels and annotations
142+
- it: should work with empty labels and annotations
143+
set:
144+
defaults.labels: {}
145+
defaults.annotations: {}
146+
components.miscellaneous.configLoader.labels: {}
147+
components.miscellaneous.configLoader.annotations: {}
148+
asserts:
149+
- isKind:
150+
of: Job
151+
152+
# Test only component-specific labels without defaults
153+
- it: should apply only component-specific labels when defaults are empty
154+
set:
155+
defaults.labels: {}
156+
components.miscellaneous.configLoader.labels:
157+
component-label: "config-loader"
158+
version: "1.0"
159+
asserts:
160+
- equal:
161+
path: metadata.labels["component-label"]
162+
value: "config-loader"
163+
- equal:
164+
path: metadata.labels["version"]
165+
value: "1.0"
166+
167+
# Test only component-specific annotations without defaults
168+
- it: should apply only component-specific annotations when defaults are empty
169+
set:
170+
defaults.annotations: {}
171+
components.miscellaneous.configLoader.annotations:
172+
component-annotation: "config-loader"
173+
build: "12345"
174+
asserts:
175+
- equal:
176+
path: metadata.annotations["component-annotation"]
177+
value: "config-loader"
178+
- equal:
179+
path: metadata.annotations["build"]
180+
value: "12345"
181+
182+
# Test checksum annotation is preserved
183+
- it: should preserve checksum annotation along with custom annotations
184+
set:
185+
defaults.annotations:
186+
custom: "value"
187+
components.miscellaneous.configLoader.annotations:
188+
another: "annotation"
189+
asserts:
190+
- isNotEmpty:
191+
path: metadata.annotations["checksum/values"]
192+
- equal:
193+
path: metadata.annotations["custom"]
194+
value: "value"
195+
- equal:
196+
path: metadata.annotations["another"]
197+
value: "annotation"
198+
199+
# Test app.kubernetes.io/component label is set correctly
200+
- it: should set app.kubernetes.io/component label to config-loader
201+
asserts:
202+
- equal:
203+
path: metadata.labels["app.kubernetes.io/component"]
204+
value: "config-loader"
205+
- equal:
206+
path: spec.template.metadata.labels["app.kubernetes.io/component"]
207+
value: "config-loader"

0 commit comments

Comments
 (0)