#!/bin/bash set -e if [[ -a ".env" ]]; then source .env fi function help() { echo echo "task [options]" echo echo "commands:" echo # Define column widths CMD_WIDTH=26 OPT_WIDTH=14 DESC_WIDTH=50 COLUMN="| %-${CMD_WIDTH}s | %-${OPT_WIDTH}s | %-${DESC_WIDTH}s |\n" # Print table header printf "$COLUMN" "Command" "Option" "Description" echo "|$(printf '%*s' $((CMD_WIDTH + 2)) '' | tr ' ' '-')|$(printf '%*s' $((OPT_WIDTH + 2)) '' | tr ' ' '-')|$(printf '%*s' $((DESC_WIDTH + 2)) '' | tr ' ' '-')|" # Env printf "$COLUMN" "version" "" "Show version of required tools." printf "$COLUMN" "info" "" "Show info about env." printf "$COLUMN" "template-dotenv" "" "Generate .env from .env.template." printf "$COLUMN" "export-kubeconfig" "[user][path]" "Export kubeconfig file for service account." printf "$COLUMN" "load-kubeconfig" "[ctx]" "Load kubeconfig file from pass." printf "$COLUMN" "load-dotenv" "" "Restore content to .env from pass entry." printf "$COLUMN" "save-kubeconfig" "[ctx]" "Save kubeconfig file in pass." printf "$COLUMN" "save-dotenv" "" "Store content of .env in pass entry." # Docs printf "$COLUMN" "install-vitepress" "" "Install node dependencies." printf "$COLUMN" "docs" "" "Generate Helm chart readmes." printf "$COLUMN" "lint" "" "Lint Helm charts." printf "$COLUMN" "dev-vitepress" "" "Start VitePress dev server." printf "$COLUMN" "build-vitepress" "" "Build site with VitePress." printf "$COLUMN" "preview-vitepress" "" "Server VitePress build." # Host printf "$COLUMN" "start-kind" "" "Start kind Kubernetes cluster." printf "$COLUMN" "load-images" "" "Load Docker images into kind cluster." printf "$COLUMN" "delete-kind" "" "Delete kind Kubernetes cluster." printf "$COLUMN" "start-minikube" "" "Start minikube Kubernetes cluster." printf "$COLUMN" "setup-hosts" "" "Update hosts file." printf "$COLUMN" "forward" "[chart]" "Forward port." # Chart printf "$COLUMN" "list-charts" "" "List local Helm charts." printf "$COLUMN" "list-external-charts" "" "List external Helm charts." printf "$COLUMN" "list-cluster" "" "List contexts." printf "$COLUMN" "switch-cluster" "" "Switch kubeconfig file." printf "$COLUMN" "show-context" "" "Show active kubeconfig." printf "$COLUMN" "get-context-alias" "" "Get alias of current context." printf "$COLUMN" "update-dependencies" "[chart]" "Update dependencies for a chart." printf "$COLUMN" "install-chart" "[chart][values]" "Install Helm chart." printf "$COLUMN" "upgrade-release" "[chart][values]" "Upgrade Helm release." printf "$COLUMN" "uninstall-release" "[release]" "Uninstall Helm release." # kubectl printf "$COLUMN" "get-secrets" "[chart]" "Show secrets for chart." printf "$COLUMN" "exec-bash" "[chart]" "Open bash shell in container." printf "$COLUMN" "logs" "[grep]" "Select pods with grep and show logs." printf "$COLUMN" "logs-haproxy-ingress" "" "Show haproxy-ingress logs." printf "$COLUMN" "logs-ingress-nginx" "" "Show ingress-nginx logs." printf "$COLUMN" "list" "" "List Helm deployments." printf "$COLUMN" "get-pods" "" "List all pods." printf "$COLUMN" "login-oc" "" "Refresh the auth token for OpenShift." # Helm printf "$COLUMN" "add-repos" "" "Add the required Helm repos." printf "$COLUMN" "template-manifest" "[chart][values]" "Template all charts with Helm." printf "$COLUMN" "package-repo" "[chart]" "Package Helm charts." printf "$COLUMN" "index-repo" "" "Index Helm chart." printf "$COLUMN" "publish-repo" "" "Copy Helm chart files to dist." printf "$COLUMN" "remove-repo" "" "Remove the kubernetes-build repo." printf "$COLUMN" "commit" "" "Commit .tgz files." # LLM printf "$COLUMN" "commit-with-llm" "" "Commit with llm generated commit message." printf "$COLUMN" "update-with-llm" "[glob][prompt]" "Feed files matching glob to LLM and apply changes." # Test printf "$COLUMN" "test-chart-clusterIssuer" "" "Test cluster issuer." printf "$COLUMN" "test-chart-odoo" "[clean]" "Setup Odoo chart and dependencies." } # Default vars OC_PROJECT=${OC_PROJECT:="odoo"} CONTAINER_REGISTRY=${CONTAINER_REGISTRY:="mintsystem/"} CONTAINER_CONFIG="$HOME/.docker/$CONTAINER_REGISTRY" # Dynamic vars PASS_ENTRY=$(echo "env/${PWD##*/}" | tr '[:upper:]' '[:lower:]') if kubectl &> /dev/null; then CURRENT_CONTEXT=$(kubectl config current-context 2> /dev/null) || CURRENT_CONTEXT="" fi if kubens &> /dev/null; then NAMESPACE=$(kubens -c) fi function get-context-alias() { echo "$(basename "$(readlink "$HOME/.kube/config")" | cut -d '.' -f 2)" } CONTEXT_ALIAS=$(get-context-alias) # Import commands function clone-taskfile(){ if [ ! -d "$HOME/taskfile.build" ]; then echo -e "\033[38;5;214mGit\033[0m: Clone taskfile repo" git clone https://git.taskfile.build "$HOME/taskfile.build" else echo -e "\033[38;5;214mGit\033[0m: Pull taskfile repo" git -C "$HOME/taskfile.build" pull fi } if [ -d "$HOME/taskfile.build/bin" ]; then for file in "$HOME/taskfile.build/bin/"*; do if [ -f "$file" ]; then source "$file" fi done fi # Env Commands function version() { minikube version kind version helm version } function info() { echo "OpenShift-Project: $OC_PROJECT" echo "Current-Context: $CURRENT_CONTEXT" echo "Context-Alias: $CONTEXT_ALIAS" echo "Namespace: $NAMESPACE" } function install-vitepress() { pnpm install } function setup-hosts() { echo "Adding entries to /etc/hosts ..." grep -qxF '127.0.0.1 knd.local' /etc/hosts || echo "127.0.0.1 knd.local" | sudo tee -a /etc/hosts > /dev/null grep -qxF "127.0.0.1 odoo.knd.local" /etc/hosts || echo "127.0.0.1 odoo.knd.local" | sudo tee -a /etc/hosts > /dev/null grep -qxF "127.0.0.1 odoo.local" /etc/hosts || echo "127.0.0.1 odoo.local" | sudo tee -a /etc/hosts > /dev/null grep -qxF "127.0.0.1 hugo.knd.local" /etc/hosts || echo "127.0.0.1 hugo.knd.local" | sudo tee -a /etc/hosts > /dev/null grep -qxF "127.0.0.1 vuepress.knd.local" /etc/hosts || echo "127.0.0.1 vuepress.knd.local" | sudo tee -a /etc/hosts > /dev/null } function test-chart-odoo() { if [ "$1" = "clean" ]; then echo "Cleanup environment" delete-kind else start-kind add-repos info install-chart ingress-nginx install-chart cnpg kubectl wait --namespace cnpg-system --for=condition=Available --timeout=60s deployments/cnpg-cloudnative-pg update-dependencies odoo install-chart odoo values/odoo.knd.local.yaml fi } function save-kubeconfig() { PASS_KUBECONFIG_ENTRY=$(echo "env/kubeconfig_$USER" | tr '[:upper:]' '[:lower:]') KUBECONFIG_FILE="$HOME/.kube/config" if [ -n"$1" ]; then PASS_KUBECONFIG_ENTRY=$(echo "env/kubeconfig_$1" | tr '[:upper:]' '[:lower:]') KUBECONFIG_FILE="$HOME/.kube/config.$1" fi if [ -f "$KUBECONFIG_FILE" ]; then echo "Store $KUBECONFIG_FILE file in pass: $PASS_KUBECONFIG_ENTRY" echo -e "\n$(cat $KUBECONFIG_FILE)" | pass insert -m -f "$PASS_KUBECONFIG_ENTRY" else echo "No $KUBECONFIG_FILE file found." fi } function load-kubeconfig() { PASS_KUBECONFIG_ENTRY=$(echo "env/kubeconfig_$USER" | tr '[:upper:]' '[:lower:]') KUBECONFIG_FILE="$HOME/.kube/config" if [ -n"$1" ]; then PASS_KUBECONFIG_ENTRY=$(echo "env/kubeconfig_$1" | tr '[:upper:]' '[:lower:]') KUBECONFIG_FILE="$HOME/.kube/config.$1" fi if pass find "$PASS_KUBECONFIG_ENTRY" >/dev/null; then echo "Load $KUBECONFIG_FILE file from pass: $PASS_KUBECONFIG_ENTRY" mkdir -p "$HOME/.kube/" pass show "$PASS_KUBECONFIG_ENTRY" | tail -n +2 > "$KUBECONFIG_FILE" else echo "Pass entry not found." fi } export-kubeconfig() { if test -z "$1"; then echo "\$1 is empty."; exit; fi if test -z "$2"; then echo "\$2 is empty."; exit; fi KUBE_USER=$1 KUBE_OUTPUT_FILE=$2 kubectl config set-cluster default --server=https://k3s.raspberrypi.build --kubeconfig=$KUBE_OUTPUT_FILE kubectl config set-context default --cluster=default --user=$KUBE_USER --kubeconfig=$KUBE_OUTPUT_FILE kubectl config set-credentials "$KUBE_USER" --token=$(kubectl create token $KUBE_USER --duration=87600h) --kubeconfig=$KUBE_OUTPUT_FILE kubectl config use-context default --kubeconfig=$KUBE_OUTPUT_FILE echo "Kubeconfig exported for user $KUBE_USER to file $KUBE_OUTPUT_FILE" } # Host Commands function start-kind() { echo "Start kind." kind create cluster } function load-images() { if kind &> /dev/null && kind get clusters | grep -q "kind"; then echo "Kind cluster is available. Checking for local Docker images..." if docker images -q "janikvonrotz/janikvonrotz.ch:latest" > /dev/null; then echo "Loading local Hugo image into Kind cluster..." kind load docker-image "janikvonrotz/janikvonrotz.ch:latest" fi if docker images -q "mintsystem/odoo:18.0.20250725" > /dev/null; then echo "Loading local Odoo image into Kind cluster..." kind load docker-image "mintsystem/odoo:18.0.20250725" fi fi } function delete-kind() { echo "Delete kind." kind delete cluster } function start-minikube() { echo "Start minikube." minikube start } function forward() { if test -z "$1"; then echo "\$1 is empty."; exit; fi "forward-$1" } function forward-postgres() { PORT=5432 echo "Connect to http://localhost:$PORT url in your browser." kubectl port-forward service/postgres $PORT:5432 } function forward-odoo() { PORT=8069 echo "Open http://localhost:$PORT url in your browser." kubectl port-forward service/odoo $PORT:8069 } function forward-ingress-nginx() { PORT=8080 echo "Open http://odoo.knd.local:$PORT or http://odoo.local:$PORT url in your browser." kubectl port-forward -n ingress-nginx svc/ingress-nginx-controller $PORT:80 } function forward-haproxy-ingress() { PORT=8080 echo "Open http://odoo.knd.local:$PORT or http://odoo.local:$POR url in your browser." kubectl port-forward -n haproxy-ingress svc/haproxy-ingress $PORT:80 } # Chart Commands function list-charts() { for DIR in */; do DIR_NAME="${DIR%/}" if [[ ! "$DIR_NAME" =~ ^(public|values)$ ]] && ! git check-ignore -q "$DIR_NAME" 2>/dev/null; then echo "$DIR_NAME" fi done } function list-external-charts() { echo "cert-manager" echo "cnpg" echo "haproxy-ingress" echo "ingress-nginx" echo "k8up" } function list-cluster() { for FILE in values/*.yaml; do KIND=$(yq eval '.kind' "$FILE") ALIAS=$(yq eval '.alias' "$FILE") if [[ -n "$KIND" && "$KIND" = "cluster" ]]; then BASE=$(basename "$FILE" .yaml) printf '%s (%s)\n' "$ALIAS" "$BASE" fi done | sort } function switch-cluster() { if test -z "$1"; then echo "\$1 is empty."; exit; fi LINK_NAME="$HOME/.kube/config" echo "Remove $LINK_NAME" rm "$LINK_NAME" || true TARGET="$HOME/.kube/config.$1" touch "$TARGET" echo "Setup symlink from $LINK_NAME to $TARGET" ln -s "$TARGET" "$LINK_NAME" chmod 0644 "$TARGET" echo "Select namespace" kubens } function show-context() { basename "$(readlink "$HOME/.kube/config")" | cut -d. -f2 } function update-dependencies() { if test -z "$1"; then echo "\$1 is empty."; exit; fi helm dependency update "$1" } function install-chart() { if test -z "$1"; then echo "\$1 is empty."; exit; fi if [ "$(get-context-alias)" = "axo" ]; then echo "Set oc project to $OC_PROJECT." oc project "$OC_PROJECT" fi RELEASE_NAME="$(echo "$1" | tr '[:upper:]' '[:lower:]')" if [ "$1" = "clusterIssuer" ]; then "install-$1" "$2" elif list-charts | grep -q "$1"; then echo "Install chart $1 as release $RELEASE_NAME:" helm install "$RELEASE_NAME" "$1" \ --values "$2" else "install-$1" "$2" fi } function install-k8up() { echo "Install k8up-io/k8up." helm install k8up k8up-io/k8up } function install-cnpg() { echo "Install cnpg/cloudnative-pg." helm upgrade --install cnpg \ --namespace cnpg-system \ --create-namespace \ cnpg/cloudnative-pg } function install-ingress-nginx() { echo "Install ingress-nginx/ingress-nginx:" helm install ingress-nginx ingress-nginx/ingress-nginx \ --create-namespace --namespace ingress-nginx # --set controller.service.externalIPs[0]=$EXTERNAL_IP echo "External IP:" kubectl get svc -n ingress-nginx } function install-cert-manager() { echo "Install jetstack/cert-manager." helm install \ cert-manager jetstack/cert-manager \ --namespace cert-manager \ --create-namespace \ --version v1.18.2 \ --set crds.enabled=true \ --set config.featureGates.ACMEHTTP01IngressPathTypeExact=false # https://github.com/Infomaniak/cert-manager-webhook-infomaniak echo "Apply Infomaniak webhook" kubectl apply -f https://github.com/Infomaniak/cert-manager-webhook-infomaniak/releases/download/v0.3.1/rendered-manifest.yaml } function install-clusterIssuer() { echo "Install clusterissuer." helm install clusterissuer clusterIssuer \ --namespace cert-manager \ --values "$1" } function install-haproxy-ingress() { echo "Install haproxy-ingress/haproxy-ingress." kubectl apply -f - < manifest.yaml elif list-charts | grep -q "$1"; then helm --debug template "$RELEASE_NAME" "$1" \ --values "$2" fi } function list() { helm list } function package-repo() { if [ -n "$1" ]; then echo "Package $1 Helm chart." helm package "$1" else echo "Package all Helm charts." index-repo helm package clusterIssuer helm package postgres helm package vshnPostgres helm package odoo helm package hugo fi } function commit() { git config user.name 'Mint Bot' git config user.email 'bot@mint-system.ch' git remote set-url origin "https://x-access-token:${GITHUB_TOKEN}@github.com/Mint-System/Kubernetes-Build" git add *.tgz git commit -m "feat(helm): package revision update" git push || echo "No changes to commit" } function index-repo() { echo "Update index.yaml" helm repo index . } function publish-repo() { build-vitepress cp *.tgz .vitepress/dist cp index.yaml .vitepress/dist } function add-repos(){ echo "Add kubernetes-build." helm repo add kubernetes-build https://kubernetes.build echo "Add ingress-nginx." helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx echo "Add haproxy-ingress." helm repo add haproxy-ingress https://haproxy-ingress.github.io/charts echo "Add jetstack." helm repo add jetstack https://charts.jetstack.io echo "Add cnpg." helm repo add cnpg https://cloudnative-pg.github.io/charts echo "Add k8up." helm repo add k8up-io https://k8up-io.github.io/k8up } function remove-repo(){ echo "Remove the kubernetes-build repo." helm repo remove kubernetes-build } # Docs Commands function docs() { for REPO in $(list-charts | grep -v '^deploymentUpdater$'); do pnpm run generate-readme --values "$REPO/values.yaml" -r "$REPO/README.md" done } function lint() { for REPO in $(list-charts); do helm lint "$REPO" done } function dev-vitepress() { cp README.md index.md pnpm run docs:dev } function build-vitepress() { cp README.md index.md pnpm run docs:build } function preview-vitepress() { pnpm run docs:preview } if declare -f "$1" > /dev/null; then "$1" "${@:2}" else case "$1" in *) echo "Unknown command: $1" help exit 1 ;; esac fi