Feature 11074: Enhanced OSM declarative modelling for applications. OSM's SDK for intent manipulation
Change-Id: I6d03faa143eafcf30380b3b854c54f177dcf8f25
Signed-off-by: garciadeblas <gerardo.garciadeblas@telefonica.com>
diff --git a/docker/osm-nushell-krm-functions/krm/overlaypatch.nu b/docker/osm-nushell-krm-functions/krm/overlaypatch.nu
new file mode 100644
index 0000000..1fcaf0d
--- /dev/null
+++ b/docker/osm-nushell-krm-functions/krm/overlaypatch.nu
@@ -0,0 +1,436 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# Licensed 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.
+#######################################################################################
+
+# 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.
+
+
+use ./patch.nu
+use ./jsonpatch.nu
+use ./strategicmergepatch.nu
+use ./generator.nu
+
+
+# Add overlay patch to Kustomization item (in a ResourceList) to modify a key in a referenced resource, using the JSON patch (patchJson6902) format
+export def "add patch" [
+ --ks-namespace: string, # Namespace of the Kustomization
+ kustomization_name: string, # Kustomization to add the patch to
+ target: record, # Target resource for the patch, as per <https://github.com/kubernetes-sigs/kustomize/blob/master/examples/patchMultipleObjects.md>
+ patch_value: record # Patch content as record type. It can be a JSON patch (patchJson6902) or a Strategic Merge Patch
+]: [
+ record -> record
+] {
+ let in_resourcelist: record = $in
+
+ let patch_content: record = (
+ {
+ target: $target,
+ patch: ($patch_value | to yaml)
+ }
+ )
+
+ $in_resourcelist
+ | (patch list append item
+ $.spec.patches
+ $patch_content
+ "kustomize.toolkit.fluxcd.io/v1"
+ "Kustomization"
+ $kustomization_name
+ $ks_namespace
+ )
+}
+
+
+# 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
+# This command provides a user-friendly interface to create a JSON patch with exactly ONE operation
+export def "add jsonpatch" [
+ --ks-namespace: string, # Namespace of the Kustomization
+ --operation: string = "add", # Operation types: "add", "remove", "replace", "move", "copy", or "test", as per RFC6902
+ kustomization_name: string, # Kustomization to add the patch to
+ target: record, # Target resource for the patch, as per <https://github.com/kubernetes-sigs/kustomize/blob/master/examples/patchMultipleObjects.md>
+ path: string, # JSON pointer path (format "/a/b/c") at the TARGET RESOURCE to be patched.
+ value?: any # Value to set in the target path (required for "add" and "replace" operations)
+ from?: string, # JSON pointer path (format "/a/b/c") at the TARGET RESOURCE to take as source in "copy" or "move" operations.
+]: [
+ record -> record
+] {
+ let in_resourcelist: record = $in
+
+ let operation_spec: record = (
+ if $operation in ["add", "replace"] {
+ {
+ op: $operation,
+ path: $path,
+ value: $value
+ }
+ } else if $operation in ["remove"] {
+ {
+ op: $operation,
+ path: $path
+ }
+ } else if $operation in ["move", "copy"] {
+ {
+ op: $operation,
+ from: $from,
+ path: $path
+ }
+ } else {
+ error make { msg: "Invalid operation type. Supported values are 'add', 'remove', 'replace', 'move', 'copy'. See RFC6902 for details" }
+ }
+ )
+
+ let patch_content: record = (
+ jsonpatch create
+ $target
+ $operation_spec
+ )
+
+ $in_resourcelist
+ | (patch list append item
+ $.spec.patches
+ $patch_content
+ "kustomize.toolkit.fluxcd.io/v1"
+ "Kustomization"
+ $kustomization_name
+ $ks_namespace
+ )
+}
+
+
+# Add a StrategicMergePatch to a Kustomization item (in a ResourceList) to modify a key in a referenced resource
+# This command provides a user-friendly interface to create a patch
+export def "add strategicmergepatch" [
+ --ks-namespace: string, # Namespace of the Kustomization
+ kustomization_name: string, # Kustomization to add the patch to
+ target: record, # Target resource for the patch, as per <https://github.com/kubernetes-sigs/kustomize/blob/master/examples/patchMultipleObjects.md>
+ patch: record, # Contents of the strategic patch in the format of a record
+]: [
+ record -> record
+] {
+ let in_resourcelist: record = $in
+
+ let patch_content: record = (
+ strategicmergepatch create
+ $target
+ $patch
+ )
+
+ $in_resourcelist
+ | (patch list append item
+ $.spec.patches
+ $patch_content
+ "kustomize.toolkit.fluxcd.io/v1"
+ "Kustomization"
+ $kustomization_name
+ $ks_namespace
+ )
+}
+
+
+# Modify a referenced HelmRelease to add inline values via an overlay patch in a Kustomization (in a ResourceList)
+export def "helmrelease add inline values" [
+ --ks-namespace: string, # Namespace of the Kustomization
+ --hr-namespace: string, # Namespace of the HelmRelease
+ --operation: string = "add", # Allowed operation types: "add", "replace". Default is "add"
+ kustomization_name: string, # Kustomization to add the patch to
+ helmrelease_name: string, # HelmRelease to add the values to
+ values: record # Helm values to include inline in the HelmRelease spec
+]: [
+ record -> record
+] {
+ let in_resourcelist: record = $in
+
+ # Exit if the operation is not supported
+ if $operation not-in ["add", "replace"] {
+ error make { msg: "Invalid operation type. Supported values are 'add', 'replace'. See RFC6902 for details" }
+ }
+
+ $in_resourcelist
+ | (add jsonpatch
+ --ks-namespace $ks_namespace
+ --operation $operation
+ $kustomization_name
+ (
+ if ($hr_namespace | is-empty) {
+ { kind: "HelmRelease", name: $helmrelease_name }
+ } else {
+ { kind: "HelmRelease", name: $helmrelease_name, namespace: $hr_namespace }
+ }
+ )
+ "/spec/values"
+ $values
+ )
+
+}
+
+
+# Modify a referenced HelmRelease to add values from a ConfigMap via an overlay patch in a Kustomization (in a ResourceList)
+export def "helmrelease add values from configmap" [
+ --ks-namespace: string, # Namespace of the Kustomization
+ --hr-namespace: string, # Namespace of the HelmRelease
+ --target-path: string, # Optional `targetPath` to merge the values to (optional)
+ --optional, # Optional flag to indicate if the values reference is optional
+ kustomization_name: string, # Kustomization to add the patch to
+ helmrelease_name: string, # HelmRelease to add the values to
+ cm_name: string # ConfigMap to read the values from
+ cm_key?: string = "values.yaml" # ConfigMap key to read the values from
+]: [
+ record -> record
+] {
+ let in_resourcelist: record = $in
+
+ # Record to reference the values in the ConfigMap and, optionally, specify on how to merge them
+ let full_reference: record = {
+ kind: "ConfigMap",
+ name: $cm_name,
+ valuesKey: $cm_key
+ }
+ | (
+ if ($target_path | is-empty) {
+ $in
+ } else {
+ $in | insert targetPath $target_path
+ }
+ ) | (
+ if $optional {
+ $in | insert optional true
+ } else {
+ $in
+ }
+ )
+
+ $in_resourcelist
+ | (
+ add strategicmergepatch
+ --ks-namespace $ks_namespace
+ $kustomization_name
+ (
+ if ($hr_namespace | is-empty) {
+ { kind: "HelmRelease", name: $helmrelease_name }
+ } else {
+ { kind: "HelmRelease", name: $helmrelease_name, namespace: $hr_namespace }
+ }
+ )
+ {
+ apiVersion: "helm.toolkit.fluxcd.io/v2",
+ kind: "HelmRelease",
+ metadata: (
+ if ($hr_namespace | is-empty) {
+ { name: $helmrelease_name }
+ } else {
+ { name: $helmrelease_name, namespace: $hr_namespace }
+ }
+ ),
+ spec: {
+ valuesFrom: [
+ $full_reference
+ ]
+ }
+ }
+ )
+}
+
+alias "helmrelease add values from cm" = helmrelease add values from configmap
+
+
+# Modify a referenced HelmRelease to add values from a Secret via an overlay patch in a Kustomization (in a ResourceList)
+export def "helmrelease add values from secret" [
+ --ks-namespace: string, # Namespace of the Kustomization
+ --hr-namespace: string, # Namespace of the HelmRelease
+ --target-path: string, # Optional `targetPath` to merge the values to (optional)
+ --optional, # Optional flag to indicate if the values reference is optional
+ kustomization_name: string, # Kustomization to add the patch to
+ helmrelease_name: string, # HelmRelease to add the values to
+ secret_name: string # Secret to read the values from
+ secret_key?: string = "values.yaml" # Secret key to read the values from
+]: [
+ record -> record
+] {
+ let in_resourcelist: record = $in
+
+ # Record to reference the values in the Secret and, optionally, specify on how to merge them
+ let full_reference: record = {
+ kind: "Secret",
+ name: $secret_name,
+ valuesKey: $secret_key
+ }
+ | (
+ if ($target_path | is-empty) {
+ $in
+ } else {
+ $in | insert targetPath $target_path
+ }
+ ) | (
+ if $optional {
+ $in | insert optional true
+ } else {
+ $in
+ }
+ )
+
+ $in_resourcelist
+ | (
+ add strategicmergepatch
+ --ks-namespace $ks_namespace
+ $kustomization_name
+ (
+ if ($hr_namespace | is-empty) {
+ { kind: "HelmRelease", name: $helmrelease_name }
+ } else {
+ { kind: "HelmRelease", name: $helmrelease_name, namespace: $hr_namespace }
+ }
+ )
+ {
+ apiVersion: "helm.toolkit.fluxcd.io/v2",
+ kind: "HelmRelease",
+ metadata: (
+ if ($hr_namespace | is-empty) {
+ { name: $helmrelease_name }
+ } else {
+ { name: $helmrelease_name, namespace: $hr_namespace }
+ }
+ ),
+ spec: {
+ valuesFrom: [
+ $full_reference
+ ]
+ }
+ }
+ )
+}
+
+
+# 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.
+# 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.
+export def "helmrelease set values" [
+ --ks-namespace: string, # Namespace of the Kustomization
+ --hr-namespace: string, # Namespace of the HelmRelease (optional)
+ --operation: string = "add", # Allowed operation types: "add", "replace". Default is "add"
+ --cm-key: string = "values.yaml", # ConfigMap key to reference values from (default: "values.yaml")
+ --cm-target-path: string, # Optional targetPath for ConfigMap values
+ --cm-optional, # Flag to mark ConfigMap values as optional (optional)
+ --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).
+ --secret-key: string = "values.yaml", # Secret key to reference values from (default: "values.yaml")
+ --secret-target-path: string, # Optional targetPath for Secret values
+ --secret-optional, # Flag to mark Secret values as optional (optional)
+ --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).
+ --public-age-key: string # Age key to encrypt the contents of the new Secret (if applicable)
+ kustomization_name: string, # Kustomization to add the patch to
+ helmrelease_name: string, # HelmRelease to modify
+ inline_values?: record, # Inline values to add to the HelmRelease spec (optional)
+ cm_name?: string, # ConfigMap name to reference values from (optional)
+ secret_name?: string # Secret name to reference values from (optional)
+]: [
+ record -> record
+] {
+ let in_resourcelist: record = $in
+
+ # Validate operation type
+ if $operation not-in ["add", "replace"] {
+ error make { msg: "Invalid operation type. Supported values are 'add', 'replace'. See RFC6902 for details" }
+ }
+
+ # === Transformations ===
+ $in_resourcelist
+ # Add inline values if provided and not empty
+ | if ($inline_values | is-empty) {
+ $in
+ } else {
+ $in
+ | (
+ helmrelease add inline values
+ --ks-namespace $ks_namespace
+ --hr-namespace $hr_namespace
+ --operation $operation
+ $kustomization_name
+ $helmrelease_name
+ $inline_values
+ )
+ }
+ # Add reference to ConfigMap-based values if cm_name is provided and not empty
+ | if ($cm_name | is-empty) {
+ $in
+ } else {
+ $in
+ | (
+ helmrelease add values from configmap
+ --ks-namespace $ks_namespace
+ --hr-namespace $hr_namespace
+ --target-path $cm_target_path
+ --optional=$cm_optional
+ $kustomization_name
+ $helmrelease_name
+ $cm_name
+ $cm_key
+ )
+ }
+ # Add reference to Secret-based values if secret_name is provided and not empty
+ | if ($secret_name | is-empty) {
+ $in
+ } else {
+ $in
+ | (
+ helmrelease add values from secret
+ --ks-namespace $ks_namespace
+ --hr-namespace $hr_namespace
+ --target-path $secret_target_path
+ --optional=$secret_optional
+ $kustomization_name
+ $helmrelease_name
+ $secret_name
+ $secret_key
+ )
+ }
+ # Generate a ConfigMap if required
+ | if ($create_cm_with_values | is-empty) or ($cm_name | is-empty) {
+ $in
+ } else {
+ $in
+ | (
+ generator configmap
+ --filename $"($cm_name).yaml"
+ { $cm_key: ($create_cm_with_values | to yaml | str trim)}
+ $cm_name
+ ($hr_namespace | default "default")
+ )
+ }
+ # Generate a Secret if required
+ | if ($create_secret_with_values | is-empty) or ($secret_name | is-empty) {
+ $in
+ } else {
+ # If there is an age key, it is used to encrypt the secret manifest; otherwise, it is kept clear
+ if ($public_age_key | is-empty) {
+ $in
+ | (
+ generator secret
+ --filename $"($secret_name).yaml"
+ { $secret_key: ($create_secret_with_values | to yaml | str trim)}
+ $secret_name
+ ($hr_namespace | default "default")
+ )
+ } else {
+ $in
+ | (
+ generator secret
+ --filename $"($secret_name).yaml"
+ --public-age-key $public_age_key
+ { $secret_key: ($create_secret_with_values | to yaml | str trim)}
+ $secret_name
+ ($hr_namespace | default "default")
+ )
+ }
+ }
+}