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/operations/brick.nu b/docker/osm-nushell-krm-functions/operations/brick.nu
new file mode 100644
index 0000000..f0c7f64
--- /dev/null
+++ b/docker/osm-nushell-krm-functions/operations/brick.nu
@@ -0,0 +1,398 @@
+#######################################################################################
+# 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 functions to manage the transformations and generations associated to the different types of Building Blocks supported by OSM.
+#
+# Supported Brick types are:
+#
+# - `basic`. Basic transformation of the ResourceList. It performs a cleanup and regularization of the target Kustomization (enforce the right path in the repo, ensure that `wait` is enabled, etc.), unless specified otherwise. In addition, it also supports the commonest transformations for a Kustomization, such as addition of optional components, extra labels and/or annotations, hot replacement of image names and tags, etc. For more details, check out the help for the `brick transform basic` command.
+# - `helmreleaseset`. Transformations for a ResourceList with a set of HelmReleases, so that values injected into the specific HelmReleases. It is a superset of the `basic` Brick, and its transformations are applied right after the corresponding basic transformations. For more details, check out the help for the `brick transform helmreleaseset` command.
+# - `custom`. Transformation of the ResourceList with a custom (user-provided) "create" transformation after a `basic` regularization is applied. For more details, check out the help for the `custom create` command.
+# - `custom-hr`. Transformation of the ResourceList with a custom (user-provided) "create" transformation after a `helmreleaseset` transformation (including `basic` regularizations) is applied. For more details, check out the help for the `custom create` command.
+# - `custom-full`. Transformation of the ResourceList with a custom (user-provided) "create" transformation. **No `basic` regularization is applied**, so any regularization (if needed) should be implemented in the custom command. For more details, check out the help for the `custom create` command.
+
+
+use ../krm *
+use ./location.nu
+use custom
+
+
+# Apply the `basic` transformation to ResourceList received from stdin according to the specification of the Brick.
+# The `basic` Brick transformation just does a cleanup and regularization of the target Kustomization
+export def "transform basic" [
+ brick: record # Brick specification
+]: [
+ record -> record
+] {
+ let rl: record = $in
+
+ # Get the key parts
+ let brick_name: string = ($brick | get -i name | default "untitled-brick")
+ let kustomization_name: string = ($brick | get $.kustomization.name)
+ let kustomization_namespace: string = ($brick | get -i $.kustomization.namespace | default "flux-system")
+ let src: string = ($brick | get source | location from base path)
+ let options: record = ($brick | get -i options | default {})
+ ## Should it avoid path regularization?
+ let keep_path: bool = ($options | get -i keep-path | default false)
+ ## Should it avoid enforcing the wait?
+ let enforce_wait: bool = ($options | get -i enforce-wait | default true)
+ ## Should it avoid enforcing the prune?
+ let enforce_prune: bool = ($options | get -i enforce-prune | default true)
+ ## Should it enable (or append) some `components`?
+ let components: list = ($options | get -i components | default [])
+ ## Should it set or overwrite `targetNamespace`?
+ let targetNamespace: string = ($options | get -i targetNamespace | default "")
+ ## Should it overwrite `interval`?
+ let interval: string = ($options | get -i interval | default "")
+ ## Should it set or overwrite `retryInterval`?
+ let retryInterval: string = ($options | get -i retryInterval | default "")
+ ## Should it set or overwrite `serviceAccountName`?
+ let serviceAccountName: string = ($options | get -i serviceAccountName | default "")
+ ## Should it add custom `healthChecks`?
+ let healthChecks: list = ($options | get -i healthChecks | default [])
+ ## Should it add custom `healthCheckExprs`?
+ let healthCheckExprs: list = ($options | get -i healthCheckExprs | default [])
+ ## Should it set or overwrite a `namePrefix`?
+ let namePrefix: string = ($options | get -i namePrefix | default "")
+ ## Should it set or overwrite a `nameSuffix`?
+ let nameSuffix: string = ($options | get -i nameSuffix | default "")
+ ## Should it append additional `.metadata.labels` and `.spec.commonMetadata.labels`?
+ let new_labels: record = ($options | get -i new_labels | default {})
+ ## Should it append additional `.metadata.annotations` and `.spec.commonMetadata.annotations`?
+ let new_annotations: record = ($options | get -i new_annotations | default {})
+ ## Should it append additional `.spec.images` replacements?
+ let images: list = ($options | get -i images | default [])
+
+ # Transform as per the basic Brick model
+ $rl
+ # Path regularization, if applicable
+ | if $keep_path { $in } else {
+ $in
+ | (
+ patch resource update key
+ $.spec.path $src
+ "kustomize.toolkit.fluxcd.io/v1" Kustomization $kustomization_name $kustomization_namespace
+ )
+ }
+ # Enforce the wait, if applicable
+ | if $enforce_wait {
+ $in
+ | (
+ patch resource upsert key
+ $.spec.wait $enforce_wait
+ "kustomize.toolkit.fluxcd.io/v1" Kustomization $kustomization_name $kustomization_namespace
+ )
+ } else { $in }
+ # Enforce the prune, if applicable
+ | if $enforce_prune {
+ $in
+ | (
+ patch resource upsert key
+ $.spec.prune $enforce_prune
+ "kustomize.toolkit.fluxcd.io/v1" Kustomization $kustomization_name $kustomization_namespace
+ )
+ } else { $in }
+ # Enable (or append) some `components`, if applicable
+ | if ($components | is-not-empty) {
+ let tmp_rl: record = $in
+ let existing_components: list = (
+ $tmp_rl
+ | (
+ patch resource keep
+ "kustomize.toolkit.fluxcd.io/v1" Kustomization $kustomization_name $kustomization_namespace
+ )
+ | get -i $.items.0.spec.components
+ | default []
+ )
+ let all_components: list = ($existing_components ++ $components) | uniq
+
+ $tmp_rl
+ | (
+ patch resource upsert key
+ $.spec.components $all_components
+ "kustomize.toolkit.fluxcd.io/v1" Kustomization $kustomization_name $kustomization_namespace
+ )
+ } else { $in }
+ # Set or overwrite `targetNamespace`, if applicable
+ | if ($targetNamespace | is-not-empty) {
+ $in
+ | (
+ patch resource upsert key
+ $.spec.targetNamespace $targetNamespace
+ "kustomize.toolkit.fluxcd.io/v1" Kustomization $kustomization_name $kustomization_namespace
+ )
+ } else { $in }
+ # Overwrite `interval`, if applicable
+ | if ($interval | is-not-empty) {
+ $in
+ | (
+ patch resource update key
+ $.spec.interval $interval
+ "kustomize.toolkit.fluxcd.io/v1" Kustomization $kustomization_name $kustomization_namespace
+ )
+ } else { $in }
+ # Set or overwrite `retryInterval`, if applicable
+ | if ($retryInterval | is-not-empty) {
+ $in
+ | (
+ patch resource upsert key
+ $.spec.retryInterval $retryInterval
+ "kustomize.toolkit.fluxcd.io/v1" Kustomization $kustomization_name $kustomization_namespace
+ )
+ } else { $in }
+ # Set or overwrite `serviceAccountName`, if applicable
+ | if ($serviceAccountName | is-not-empty) {
+ $in
+ | (
+ patch resource upsert key
+ $.spec.serviceAccountName $serviceAccountName
+ "kustomize.toolkit.fluxcd.io/v1" Kustomization $kustomization_name $kustomization_namespace
+ )
+ } else { $in }
+ # Enable (or append) some `healthChecks`, if applicable
+ | if ($healthChecks | is-not-empty) {
+ let tmp_rl: record = $in
+ let existing_healthChecks: list = ($tmp_rl | get -i $.spec.healthChecks | default [])
+ let all_healthChecks: list = ($existing_healthChecks ++ $healthChecks) | uniq
+
+ $tmp_rl
+ | (
+ patch resource upsert key
+ $.spec.healthChecks $all_healthChecks
+ "kustomize.toolkit.fluxcd.io/v1" Kustomization $kustomization_name $kustomization_namespace
+ )
+ } else { $in }
+ # Enable (or append) some `healthCheckExprs`, if applicable
+ | if ($healthCheckExprs | is-not-empty) {
+ let tmp_rl: record = $in
+ let existing_healthCheckExprs: list = ($tmp_rl | get -i $.spec.healthCheckExprs | default [])
+ let all_healthCheckExprs: list = ($existing_healthCheckExprs ++ $healthCheckExprs) | uniq
+
+ $tmp_rl
+ | (
+ patch resource upsert key
+ $.spec.healthCheckExprs $all_healthCheckExprs
+ "kustomize.toolkit.fluxcd.io/v1" Kustomization $kustomization_name $kustomization_namespace
+ )
+ } else { $in }
+ # Set or overwrite `namePrefix`, if applicable
+ | if ($namePrefix | is-not-empty) {
+ $in
+ | (
+ patch resource upsert key
+ $.spec.namePrefix $namePrefix
+ "kustomize.toolkit.fluxcd.io/v1" Kustomization $kustomization_name $kustomization_namespace
+ )
+ } else { $in }
+ # Set or overwrite `nameSuffix`, if applicable
+ | if ($nameSuffix | is-not-empty) {
+ $in
+ | (
+ patch resource upsert key
+ $.spec.nameSuffix $nameSuffix
+ "kustomize.toolkit.fluxcd.io/v1" Kustomization $kustomization_name $kustomization_namespace
+ )
+ } else { $in }
+ # Enable (or append) some `.metadata.labels` and `.spec.commonMetadata.labels`, if applicable
+ | if ($new_labels | is-not-empty) {
+ let tmp_rl: record = $in
+ let existing_labels: list = ($tmp_rl | get -i $.metadata.labels | default [])
+ let existing_common_labels: list = ($tmp_rl | get -i $.spec.commonMetadata.labels | default [])
+ let all_labels: list = ($existing_labels | merge $new_labels)
+ let all_common_labels: list = ($existing_common_labels | merge $new_labels)
+
+ $tmp_rl
+ | (
+ patch resource upsert key
+ $.metadata.labels
+ $all_labels
+ "kustomize.toolkit.fluxcd.io/v1" Kustomization $kustomization_name $kustomization_namespace
+ )
+ | (
+ patch resource upsert key
+ $.spec.commonMetadata.labels
+ $all_common_labels
+ "kustomize.toolkit.fluxcd.io/v1" Kustomization $kustomization_name $kustomization_namespace
+ )
+ } else { $in }
+ # Enable (or append) some `.metadata.annotations` and `.spec.commonMetadata.annotations`, if applicable
+ | if ($new_annotations | is-not-empty) {
+ let tmp_rl: record = $in
+ let existing_annotations: list = ($tmp_rl | get -i $.metadata.annotations | default [])
+ let existing_common_annotations: list = ($tmp_rl | get -i $.spec.commonMetadata.annotations | default [])
+ let all_annotations: list = ($existing_annotations | merge $new_annotations)
+ let all_common_annotations: list = ($existing_common_annotations | merge $new_annotations)
+
+ $tmp_rl
+ | (
+ patch resource upsert key
+ $.metadata.annotations
+ $all_annotations
+ "kustomize.toolkit.fluxcd.io/v1" Kustomization $kustomization_name $kustomization_namespace
+ )
+ | (
+ patch resource upsert key
+ $.spec.commonMetadata.annotations
+ $all_common_annotations
+ "kustomize.toolkit.fluxcd.io/v1" Kustomization $kustomization_name $kustomization_namespace
+ )
+ } else { $in }
+ # Enable (or append) some `.spec.images` replacements, if applicable
+ | if ($images | is-not-empty) {
+ let tmp_rl: record = $in
+ let existing_images: list = ($tmp_rl | get -i $.spec.images | default [])
+ let all_images: list = ($existing_images ++ $images) | uniq
+
+ $tmp_rl
+ | (
+ patch resource upsert key
+ $.spec.images $all_images
+ "kustomize.toolkit.fluxcd.io/v1" Kustomization $kustomization_name $kustomization_namespace
+ )
+ } else { $in }
+}
+
+
+# Apply the `helmreleaseset` transformation to ResourceList received from stdin according to the specification of the Brick.
+# The `basic` Brick transformation just does a cleanup and regularization of the target Kustomization
+export def "transform helmreleaseset" [
+ brick: record # Brick specification
+]: [
+ record -> record
+] {
+ # Input ReleaseList after basic transformations
+ let rl: record = $in
+
+ # Get the key parts
+ let brick_name: string = ($brick | get -i name | default "untitled-brick")
+ let kustomization_name: string = ($brick | get $.kustomization.name)
+ let kustomization_namespace: string = ($brick | get -i $.kustomization.namespace | default "flux-system")
+ let hrset_values: list<record> = ($brick | get "hrset-values" | default [])
+ let public_age_key: string = ($brick | get -i $.public-age-key | default "")
+
+ # Apply HelmRelease-specific transformations
+ $hrset_values
+ | reduce --fold $rl {|elt, acc|
+ $acc
+ | (
+ overlaypatch helmrelease set values
+ # --ks-namespace: string
+ --ks-namespace $kustomization_namespace
+ # --hr-namespace: string
+ --hr-namespace ($elt | get $.HelmRelease.namespace)
+ # --operation: string = "add"
+ # --cm-key: string = "values.yaml"
+ --cm-key ($elt | get -i $.valuesFrom.configMapKeyRef.key | default "values.yaml")
+ # --cm-target-path: string
+ # --cm-optional
+ # --create-cm-with-values: record
+ --create-cm-with-values ($elt | get -i "create-cm" | default {})
+ # --secret-key: string = "values.yaml"
+ --secret-key ($elt | get -i $.valuesFrom.secretKeyRef.key | default "values.yaml")
+ # --secret-target-path: string
+ # --secret-optional
+ # --create-secret-with-values: record
+ --create-secret-with-values (
+ $env
+ | get -i ($elt | get -i $.create-secret.env-values-reference | default "")
+ | default {}
+ )
+ # --public-age-key: string
+ --public-age-key $public_age_key
+ # kustomization_name: string
+ $kustomization_name
+ # helmrelease_name: string
+ ($elt | get $.HelmRelease.name)
+ # inline_values?: record
+ ($elt | get -i "inline-values" | default {})
+ # cm_name?: string
+ ($elt | get -i $.valuesFrom.configMapKeyRef.name | default "")
+ # secret_name?: string
+ ($elt | get -i $.valuesFrom.secretKeyRef.name | default "")
+ )
+ }
+}
+
+
+# Transform the ResourceList received from stdin according to the specification of a Brick transformation.
+#
+export def transform [
+ brick: record # Brick specification
+ environment: record = {} # Record with environment variables to load
+]: [
+ record -> record
+] {
+ # Get input ResourceList
+ let rl: record = $in
+
+ # Get the brick name
+ let brick_name: string = ($brick | get -i name | default "untitled-brick")
+
+ # Update the environment to include the brick name
+ let updated_environment: record = (
+ $environment
+ | upsert $.BRICK_NAME $brick_name
+ )
+
+ # Update the brick record accordingly
+ let updated_brick: record = (
+ $brick
+ | replace vars $updated_environment
+ )
+
+ # Get other key parts
+ let brick_type: string = ($updated_brick | get -i type | default "basic" | str downcase)
+
+ # Apply transformation according to the brick type
+ with-env $updated_environment {
+ match $brick_type {
+ "basic" => {
+ # Basic transformation of the ResourceList (just cleanup and regularization)
+ $rl
+ | transform basic $updated_brick
+ },
+ "helmreleaseset" => {
+ # Transformation of the ResourceList with a set of HelmReleases
+ $rl
+ | transform basic $updated_brick
+ | transform helmreleaseset $updated_brick
+ },
+ "custom-full" => {
+ # Transformation of the ResourceList with a custom "create" transformation
+ $rl
+ | custom brick create $updated_brick $updated_environment
+ },
+ "custom" => {
+ # Transformation of the ResourceList with a custom "create" transformation, after a basic cleanup and regularization
+ $rl
+ | transform basic $updated_brick
+ | custom brick create $updated_brick $updated_environment
+ },
+ "custom-hr" => {
+ # Transformation of the ResourceList with a custom "create" transformation, after a `helmreleaseset` transformation
+ $rl
+ | transform basic $updated_brick
+ | transform helmreleaseset $updated_brick
+ | custom brick create $updated_brick $updated_environment
+ },
+ _ => {
+ # Unknown brick type, throw an error
+ error make { msg: $"Error: Unknown Brick type: ($updated_brick | get type)" }
+ }
+ }
+ }
+}