blob: 1fcaf0dd41c4332d7908ee48f412c319ca77b0f6 [file] [log] [blame]
garciadeblas83775ba2025-07-23 18:35:24 +02001#######################################################################################
2# Copyright ETSI Contributors and Others.
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
13# implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#######################################################################################
17
18# Module with custom commands to generate `overlay patches`, i.e., patches to a Kustomization that references the resources that we intend to patch at runtime.
19
20
21use ./patch.nu
22use ./jsonpatch.nu
23use ./strategicmergepatch.nu
24use ./generator.nu
25
26
27# Add overlay patch to Kustomization item (in a ResourceList) to modify a key in a referenced resource, using the JSON patch (patchJson6902) format
28export def "add patch" [
29 --ks-namespace: string, # Namespace of the Kustomization
30 kustomization_name: string, # Kustomization to add the patch to
31 target: record, # Target resource for the patch, as per <https://github.com/kubernetes-sigs/kustomize/blob/master/examples/patchMultipleObjects.md>
32 patch_value: record # Patch content as record type. It can be a JSON patch (patchJson6902) or a Strategic Merge Patch
33]: [
34 record -> record
35] {
36 let in_resourcelist: record = $in
37
38 let patch_content: record = (
39 {
40 target: $target,
41 patch: ($patch_value | to yaml)
42 }
43 )
44
45 $in_resourcelist
46 | (patch list append item
47 $.spec.patches
48 $patch_content
49 "kustomize.toolkit.fluxcd.io/v1"
50 "Kustomization"
51 $kustomization_name
52 $ks_namespace
53 )
54}
55
56
57# Add an overlay patch to a Kustomization item (in a ResourceList) to modify a key in a referenced resource, using the JSON patch (patchJson6902) format
58# This command provides a user-friendly interface to create a JSON patch with exactly ONE operation
59export def "add jsonpatch" [
60 --ks-namespace: string, # Namespace of the Kustomization
61 --operation: string = "add", # Operation types: "add", "remove", "replace", "move", "copy", or "test", as per RFC6902
62 kustomization_name: string, # Kustomization to add the patch to
63 target: record, # Target resource for the patch, as per <https://github.com/kubernetes-sigs/kustomize/blob/master/examples/patchMultipleObjects.md>
64 path: string, # JSON pointer path (format "/a/b/c") at the TARGET RESOURCE to be patched.
65 value?: any # Value to set in the target path (required for "add" and "replace" operations)
66 from?: string, # JSON pointer path (format "/a/b/c") at the TARGET RESOURCE to take as source in "copy" or "move" operations.
67]: [
68 record -> record
69] {
70 let in_resourcelist: record = $in
71
72 let operation_spec: record = (
73 if $operation in ["add", "replace"] {
74 {
75 op: $operation,
76 path: $path,
77 value: $value
78 }
79 } else if $operation in ["remove"] {
80 {
81 op: $operation,
82 path: $path
83 }
84 } else if $operation in ["move", "copy"] {
85 {
86 op: $operation,
87 from: $from,
88 path: $path
89 }
90 } else {
91 error make { msg: "Invalid operation type. Supported values are 'add', 'remove', 'replace', 'move', 'copy'. See RFC6902 for details" }
92 }
93 )
94
95 let patch_content: record = (
96 jsonpatch create
97 $target
98 $operation_spec
99 )
100
101 $in_resourcelist
102 | (patch list append item
103 $.spec.patches
104 $patch_content
105 "kustomize.toolkit.fluxcd.io/v1"
106 "Kustomization"
107 $kustomization_name
108 $ks_namespace
109 )
110}
111
112
113# Add a StrategicMergePatch to a Kustomization item (in a ResourceList) to modify a key in a referenced resource
114# This command provides a user-friendly interface to create a patch
115export def "add strategicmergepatch" [
116 --ks-namespace: string, # Namespace of the Kustomization
117 kustomization_name: string, # Kustomization to add the patch to
118 target: record, # Target resource for the patch, as per <https://github.com/kubernetes-sigs/kustomize/blob/master/examples/patchMultipleObjects.md>
119 patch: record, # Contents of the strategic patch in the format of a record
120]: [
121 record -> record
122] {
123 let in_resourcelist: record = $in
124
125 let patch_content: record = (
126 strategicmergepatch create
127 $target
128 $patch
129 )
130
131 $in_resourcelist
132 | (patch list append item
133 $.spec.patches
134 $patch_content
135 "kustomize.toolkit.fluxcd.io/v1"
136 "Kustomization"
137 $kustomization_name
138 $ks_namespace
139 )
140}
141
142
143# Modify a referenced HelmRelease to add inline values via an overlay patch in a Kustomization (in a ResourceList)
144export def "helmrelease add inline values" [
145 --ks-namespace: string, # Namespace of the Kustomization
146 --hr-namespace: string, # Namespace of the HelmRelease
147 --operation: string = "add", # Allowed operation types: "add", "replace". Default is "add"
148 kustomization_name: string, # Kustomization to add the patch to
149 helmrelease_name: string, # HelmRelease to add the values to
150 values: record # Helm values to include inline in the HelmRelease spec
151]: [
152 record -> record
153] {
154 let in_resourcelist: record = $in
155
156 # Exit if the operation is not supported
157 if $operation not-in ["add", "replace"] {
158 error make { msg: "Invalid operation type. Supported values are 'add', 'replace'. See RFC6902 for details" }
159 }
160
161 $in_resourcelist
162 | (add jsonpatch
163 --ks-namespace $ks_namespace
164 --operation $operation
165 $kustomization_name
166 (
167 if ($hr_namespace | is-empty) {
168 { kind: "HelmRelease", name: $helmrelease_name }
169 } else {
170 { kind: "HelmRelease", name: $helmrelease_name, namespace: $hr_namespace }
171 }
172 )
173 "/spec/values"
174 $values
175 )
176
177}
178
179
180# Modify a referenced HelmRelease to add values from a ConfigMap via an overlay patch in a Kustomization (in a ResourceList)
181export def "helmrelease add values from configmap" [
182 --ks-namespace: string, # Namespace of the Kustomization
183 --hr-namespace: string, # Namespace of the HelmRelease
184 --target-path: string, # Optional `targetPath` to merge the values to (optional)
185 --optional, # Optional flag to indicate if the values reference is optional
186 kustomization_name: string, # Kustomization to add the patch to
187 helmrelease_name: string, # HelmRelease to add the values to
188 cm_name: string # ConfigMap to read the values from
189 cm_key?: string = "values.yaml" # ConfigMap key to read the values from
190]: [
191 record -> record
192] {
193 let in_resourcelist: record = $in
194
195 # Record to reference the values in the ConfigMap and, optionally, specify on how to merge them
196 let full_reference: record = {
197 kind: "ConfigMap",
198 name: $cm_name,
199 valuesKey: $cm_key
200 }
201 | (
202 if ($target_path | is-empty) {
203 $in
204 } else {
205 $in | insert targetPath $target_path
206 }
207 ) | (
208 if $optional {
209 $in | insert optional true
210 } else {
211 $in
212 }
213 )
214
215 $in_resourcelist
216 | (
217 add strategicmergepatch
218 --ks-namespace $ks_namespace
219 $kustomization_name
220 (
221 if ($hr_namespace | is-empty) {
222 { kind: "HelmRelease", name: $helmrelease_name }
223 } else {
224 { kind: "HelmRelease", name: $helmrelease_name, namespace: $hr_namespace }
225 }
226 )
227 {
228 apiVersion: "helm.toolkit.fluxcd.io/v2",
229 kind: "HelmRelease",
230 metadata: (
231 if ($hr_namespace | is-empty) {
232 { name: $helmrelease_name }
233 } else {
234 { name: $helmrelease_name, namespace: $hr_namespace }
235 }
236 ),
237 spec: {
238 valuesFrom: [
239 $full_reference
240 ]
241 }
242 }
243 )
244}
245
246alias "helmrelease add values from cm" = helmrelease add values from configmap
247
248
249# Modify a referenced HelmRelease to add values from a Secret via an overlay patch in a Kustomization (in a ResourceList)
250export def "helmrelease add values from secret" [
251 --ks-namespace: string, # Namespace of the Kustomization
252 --hr-namespace: string, # Namespace of the HelmRelease
253 --target-path: string, # Optional `targetPath` to merge the values to (optional)
254 --optional, # Optional flag to indicate if the values reference is optional
255 kustomization_name: string, # Kustomization to add the patch to
256 helmrelease_name: string, # HelmRelease to add the values to
257 secret_name: string # Secret to read the values from
258 secret_key?: string = "values.yaml" # Secret key to read the values from
259]: [
260 record -> record
261] {
262 let in_resourcelist: record = $in
263
264 # Record to reference the values in the Secret and, optionally, specify on how to merge them
265 let full_reference: record = {
266 kind: "Secret",
267 name: $secret_name,
268 valuesKey: $secret_key
269 }
270 | (
271 if ($target_path | is-empty) {
272 $in
273 } else {
274 $in | insert targetPath $target_path
275 }
276 ) | (
277 if $optional {
278 $in | insert optional true
279 } else {
280 $in
281 }
282 )
283
284 $in_resourcelist
285 | (
286 add strategicmergepatch
287 --ks-namespace $ks_namespace
288 $kustomization_name
289 (
290 if ($hr_namespace | is-empty) {
291 { kind: "HelmRelease", name: $helmrelease_name }
292 } else {
293 { kind: "HelmRelease", name: $helmrelease_name, namespace: $hr_namespace }
294 }
295 )
296 {
297 apiVersion: "helm.toolkit.fluxcd.io/v2",
298 kind: "HelmRelease",
299 metadata: (
300 if ($hr_namespace | is-empty) {
301 { name: $helmrelease_name }
302 } else {
303 { name: $helmrelease_name, namespace: $hr_namespace }
304 }
305 ),
306 spec: {
307 valuesFrom: [
308 $full_reference
309 ]
310 }
311 }
312 )
313}
314
315
316# Umbrella command to add values to a HelmRelease via an overlay patch to a Kustomization, using either inline values, a reference to a ConfigMap and/or a reference to a Secret.
317# Parameters representing values (`inline_values`, `cm_name` or `secret_name`) that are empty will be skipped; only non-empty parameters will be used and add an overlay patch.
318export def "helmrelease set values" [
319 --ks-namespace: string, # Namespace of the Kustomization
320 --hr-namespace: string, # Namespace of the HelmRelease (optional)
321 --operation: string = "add", # Allowed operation types: "add", "replace". Default is "add"
322 --cm-key: string = "values.yaml", # ConfigMap key to reference values from (default: "values.yaml")
323 --cm-target-path: string, # Optional targetPath for ConfigMap values
324 --cm-optional, # Flag to mark ConfigMap values as optional (optional)
325 --create-cm-with-values: record, # Record with values to include in a new generated ConfigMap (default: empty, i.e., does not create a new ConfigMap).
326 --secret-key: string = "values.yaml", # Secret key to reference values from (default: "values.yaml")
327 --secret-target-path: string, # Optional targetPath for Secret values
328 --secret-optional, # Flag to mark Secret values as optional (optional)
329 --create-secret-with-values: record, # Record with values to include in a new generated Secret (default: empty, i.e., does not create a new Secret).
330 --public-age-key: string # Age key to encrypt the contents of the new Secret (if applicable)
331 kustomization_name: string, # Kustomization to add the patch to
332 helmrelease_name: string, # HelmRelease to modify
333 inline_values?: record, # Inline values to add to the HelmRelease spec (optional)
334 cm_name?: string, # ConfigMap name to reference values from (optional)
335 secret_name?: string # Secret name to reference values from (optional)
336]: [
337 record -> record
338] {
339 let in_resourcelist: record = $in
340
341 # Validate operation type
342 if $operation not-in ["add", "replace"] {
343 error make { msg: "Invalid operation type. Supported values are 'add', 'replace'. See RFC6902 for details" }
344 }
345
346 # === Transformations ===
347 $in_resourcelist
348 # Add inline values if provided and not empty
349 | if ($inline_values | is-empty) {
350 $in
351 } else {
352 $in
353 | (
354 helmrelease add inline values
355 --ks-namespace $ks_namespace
356 --hr-namespace $hr_namespace
357 --operation $operation
358 $kustomization_name
359 $helmrelease_name
360 $inline_values
361 )
362 }
363 # Add reference to ConfigMap-based values if cm_name is provided and not empty
364 | if ($cm_name | is-empty) {
365 $in
366 } else {
367 $in
368 | (
369 helmrelease add values from configmap
370 --ks-namespace $ks_namespace
371 --hr-namespace $hr_namespace
372 --target-path $cm_target_path
373 --optional=$cm_optional
374 $kustomization_name
375 $helmrelease_name
376 $cm_name
377 $cm_key
378 )
379 }
380 # Add reference to Secret-based values if secret_name is provided and not empty
381 | if ($secret_name | is-empty) {
382 $in
383 } else {
384 $in
385 | (
386 helmrelease add values from secret
387 --ks-namespace $ks_namespace
388 --hr-namespace $hr_namespace
389 --target-path $secret_target_path
390 --optional=$secret_optional
391 $kustomization_name
392 $helmrelease_name
393 $secret_name
394 $secret_key
395 )
396 }
397 # Generate a ConfigMap if required
398 | if ($create_cm_with_values | is-empty) or ($cm_name | is-empty) {
399 $in
400 } else {
401 $in
402 | (
403 generator configmap
404 --filename $"($cm_name).yaml"
405 { $cm_key: ($create_cm_with_values | to yaml | str trim)}
406 $cm_name
407 ($hr_namespace | default "default")
408 )
409 }
410 # Generate a Secret if required
411 | if ($create_secret_with_values | is-empty) or ($secret_name | is-empty) {
412 $in
413 } else {
414 # If there is an age key, it is used to encrypt the secret manifest; otherwise, it is kept clear
415 if ($public_age_key | is-empty) {
416 $in
417 | (
418 generator secret
419 --filename $"($secret_name).yaml"
420 { $secret_key: ($create_secret_with_values | to yaml | str trim)}
421 $secret_name
422 ($hr_namespace | default "default")
423 )
424 } else {
425 $in
426 | (
427 generator secret
428 --filename $"($secret_name).yaml"
429 --public-age-key $public_age_key
430 { $secret_key: ($create_secret_with_values | to yaml | str trim)}
431 $secret_name
432 ($hr_namespace | default "default")
433 )
434 }
435 }
436}