blob: 98d52b5c04a66480968eee14254a108d96e9d71e [file] [log] [blame]
#######################################################################################
# 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 KRM generator functions for various kinds of Kubernetes resources.
use ./convert.nu
use ./concatenate.nu
use ./patch.nu
use ./keypair.nu
# KRM generator function with input from a ResourceList.
# Works as generic generator function to insert any resource from a ResourceList, passed as parameter, into another ResourceList, passed from stdin.
export def "from resourcelist" [
rl: record
]: [
record -> record
] {
# Regularizes ResourceList from stdin
let list1: record = if $in == null { {} } else { $in }
# Regularizes the second ResourceList
let list2: record = if $rl == null { {} } else { $rl }
# Checks that both ResourceLists are actual ResourceLists
{stdin: $list1, "input parameter": $list2} | items { |name, rl|
if (
$rl != {}
and (
($rl | get -i kind) != "ResourceList"
or ($rl | get -i apiVersion) != "config.kubernetes.io/v1"
)
) {
error make {msg: $"Error: Expected a ResourceList, but received ($rl) from ($name)."}
}
}
# Merges both ResourceLists
$list1
| concatenate resourcelists $list2
}
# KRM generator function with input from a manifest
#
# Example of use: Generator from an encrypted secret:
#
# use ./keypair.nu
#
# let secret_value: string = "my_secret_value"
# let secret_name: string = "mysecret"
# let secret_key: string = "mykey"
# let public_key: string = "age1s236gmpr7myjjyqfrl6hwz0npqjgxa9t6tjj46yq28j2c4nk653saqreav"
#
# {}
# | generator from manifest (
# $secret_value
# | (^kubectl create secret generic ($secret_name)
# --from-file=($secret_key)=/dev/stdin
# --dry-run=client
# -o yaml)
# | keypair encrypt_secret_from_stdin $public_key
# | from yaml
# )
# | to yaml
#
# RESULT:
#
# apiVersion: config.kubernetes.io/v1
# kind: ResourceList
# items:
# - apiVersion: v1
# data:
# mykey: ENC[AES256_GCM,data:XKTW8X5ZI6c3yWYtyOPUP/UskKc=,iv:ZOkqLmSgXNCNCQrsMUq7iDL05rklDBuTaVS6E5Bgyl8=,tag:/2rLYqnh+RJWWH4OmEHJBA==,type:str]
# kind: Secret
# metadata:
# creationTimestamp: null
# name: mysecret
# sops:
# kms: []
# gcp_kms: []
# azure_kv: []
# hc_vault: []
# age:
# - recipient: age1s236gmpr7myjjyqfrl6hwz0npqjgxa9t6tjj46yq28j2c4nk653saqreav
# enc: |
# -----BEGIN AGE ENCRYPTED FILE-----
# YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSByNk9KWnhBa2xiMFpyT1Fj
# QWw3aGxRZnhHbUNOcXUvc05zZDZIckdPWWtNCm91VzUwU2l5NnVSajJyQkhBMldK
# ZkJYWXFTd1J5Q2Z1cTJ6MExkeVBWVXcKLS0tIHpKQ0EvdmpzNS9nZFFHK0JoV0Rx
# NXRyMXROK2p3bkpnOXowQ1RYdFk2blkKzsJiw31EA7hZbcRaHe0RkjsrSs7GQjXc
# YNAtoPquu0xaocX3pEUV/aojG/WejNY7peDXVDI43yfv8eJlO072Sw==
# -----END AGE ENCRYPTED FILE-----
# lastmodified: 2025-03-10T17:47:08Z
# mac: ENC[AES256_GCM,data:JZttY7AvtRmVaJpCIdJc4Tve7EykKpR7SETQoR7fSiFOVfm4EX+ZcwYoxQYiMsNWXnx/K/IAo8VKoT1+x/lsyFTFucP3YsZ35cfXtAPt43d+gi+IEYS9hfjDQL4BmLAlIiwmij0QGOzcWFFSDhatD717zIBzEDbs2qNGHTqc68E=,iv:Dtiwbvb7LPTyShw2DrnpM/EAWdLyxSDimh7Kk15Jox4=,tag:1VBGnQbotN5KDSmznvNPdg==,type:str]
# pgp: []
# encrypted_regex: ^(data|stringData)$
# version: 3.8.1
export def "from manifest" [
manifest: any
]: [
record -> record
nothing -> record
] {
# Keeps prior ResourceList, with regularization if needed
let in_rl: record = if $in == null { {} } else { $in }
# Regularizes the manifest in the parameter so that is is a list
let manifest1: list<any> = (if $manifest == null { [] }
else if ($manifest | describe | str starts-with "record") { [ $manifest ] }
else if ($manifest | describe | str starts-with "list") or ($manifest | describe | str starts-with "table") { $manifest }
else { error make {msg: $"Error: Expected a record or a list of records, but received ($manifest | describe)."}})
# Creates a ResourceList from the manifest and merges with ResourceList from stdin
$in_rl
| concatenate resourcelists ($manifest1 | convert manifest to resourcelist)
}
# KRM generator function for a ConfigMap
export def "configmap" [
--filename: string, # File name to keep the manifest
--index: int, # Number of the index in the file, for multi-resource manifests
key_pairs: record, # Key-value pairs to add to the ConfigMap
name: string,
namespace?: string = "default"
]: [
record -> record
nothing -> record
] {
# Regularizes ResourceList from stdin
let in_rl: record = if $in == null { {} } else { $in }
$in_rl
| ( from manifest
# ConfigMap manifest structure
{
apiVersion: v1,
kind: ConfigMap,
metadata: {
name: $name,
namespace: $namespace,
},
data: $key_pairs
}
)
# Add file name if required
| if ($filename | is-empty) {
$in
} else {
$in
| (patch resource filename set
--index $index
$filename
"v1"
"ConfigMap"
$name
$namespace
)
}
}
# KRM generator function for a Secret
export def "secret" [
--filename: string, # File name to keep the manifest
--index: int, # Number of the index in the file, for multi-resource manifests
--public-age-key: string # Age key to encrypt the contents of the Secret manifest
--type: string # Type of Kubernetes secret. Built-in types: `Opaque` (default), `kubernetes.io/service-account-token`, `kubernetes.io/dockercfg`, `kubernetes.io/dockerconfigjson`, `kubernetes.io/basic-auth`, `kubernetes.io/ssh-auth`, `kubernetes.io/tls`, `bootstrap.kubernetes.io/token`
key_pairs: record, # Key-value pairs to add to the Secret
name: string,
namespace?: string = "default"
]: [
record -> record
nothing -> record
] {
# Regularizes ResourceList from stdin
let in_rl: record = if $in == null { {} } else { $in }
# Encode the values with base64
let encoded_key_pairs: record = (
($key_pairs | columns)
| zip (
$key_pairs
| values
| each {$in | encode base64}
)
| reduce -f {} {|it, acc| $acc | upsert $it.0 $it.1 }
)
# Generate the secret
$in_rl
| ( from manifest
# ConfigMap manifest structure
(
{
apiVersion: v1,
kind: Secret,
metadata: {
name: $name,
namespace: $namespace,
},
data: $encoded_key_pairs
}
# Add Secret type if specified
| if ($type | is-empty) {
$in
} else {
$in
| insert type $type
}
# Encode if an age key was supplied
| if ($public_age_key | is-empty) {
$in
} else {
$in
| to yaml
| keypair encrypt_secret_from_stdin $public_age_key
| from yaml
}
)
)
# Add file name if required
| if ($filename | is-empty) {
$in
} else {
$in
| (patch resource filename set
--index $index
$filename
"v1"
"Secret"
$name
$namespace
)
}
}