From 70419b1a065fc04b80f51e895482e249aab7da34 Mon Sep 17 00:00:00 2001 From: Kyle Squizzato Date: Thu, 7 Nov 2024 14:33:53 -0800 Subject: [PATCH] Add script and Makefile targets for bundling images for airgap (#475) --- .gitignore | 3 + Makefile | 25 +- docs/dev.md | 12 + scripts/airgap-push.sh | 196 ++++++++++++++ scripts/bundle-images.sh | 247 ++++++++++++++++++ scripts/package-k0s-extensions-helm.sh | 40 +++ .../templates/k0smotroncontrolplane.yaml | 2 +- .../templates/k0scontrolplane.yaml | 2 +- 8 files changed, 520 insertions(+), 7 deletions(-) create mode 100755 scripts/airgap-push.sh create mode 100755 scripts/bundle-images.sh create mode 100644 scripts/package-k0s-extensions-helm.sh diff --git a/.gitignore b/.gitignore index be8549cc..55aeadb6 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,6 @@ vendor # mkdocs folder mkdocs + +# airgap-push script directories +hmc-airgap diff --git a/Makefile b/Makefile index cfeaaeed..229a4caa 100644 --- a/Makefile +++ b/Makefile @@ -129,21 +129,35 @@ lint-fix: golangci-lint ## Run golangci-lint linter and perform fixes add-license: addlicense $(ADDLICENSE) -c "" -ignore ".github/**" -ignore "config/**" -ignore "templates/**" -ignore ".*" -y 2024 . -##@ Build +##@ Package TEMPLATES_DIR := templates PROVIDER_TEMPLATES_DIR := $(TEMPLATES_DIR)/provider CHARTS_PACKAGE_DIR ?= $(LOCALBIN)/charts +EXTENSION_CHARTS_PACKAGE_DIR ?= $(LOCALBIN)/charts/extensions +$(EXTENSION_CHARTS_PACKAGE_DIR): | $(LOCALBIN) + mkdir -p $(EXTENSION_CHARTS_PACKAGE_DIR) $(CHARTS_PACKAGE_DIR): | $(LOCALBIN) rm -rf $(CHARTS_PACKAGE_DIR) mkdir -p $(CHARTS_PACKAGE_DIR) +IMAGES_PACKAGE_DIR ?= $(LOCALBIN)/images +$(IMAGES_PACKAGE_DIR): | $(LOCALBIN) + rm -rf $(IMAGES_PACKAGE_DIR) + mkdir -p $(IMAGES_PACKAGE_DIR) TEMPLATE_FOLDERS = $(patsubst $(TEMPLATES_DIR)/%,%,$(wildcard $(TEMPLATES_DIR)/*)) .PHONY: helm-package -helm-package: $(CHARTS_PACKAGE_DIR) helm +helm-package: $(CHARTS_PACKAGE_DIR) $(EXTENSION_CHARTS_PACKAGE_DIR) helm @make $(patsubst %,package-%-tmpl,$(TEMPLATE_FOLDERS)) +bundle-images: dev-apply $(IMAGES_PACKAGE_DIR) ## Create a tarball with all images used by HMC. + @BUNDLE_TARBALL=$(IMAGES_PACKAGE_DIR)/hmc-images-$(VERSION).tgz EXTENSIONS_BUNDLE_TARBALL=$(IMAGES_PACKAGE_DIR)/hmc-extension-images-$(VERSION).tgz IMG=$(IMG) KUBECTL=$(KUBECTL) YQ=$(YQ) HELM=$(HELM) NAMESPACE=$(NAMESPACE) TEMPLATES_DIR=$(TEMPLATES_DIR) KIND_CLUSTER_NAME=$(KIND_CLUSTER_NAME) $(SHELL) "scripts/bundle-images.sh" + +airgap-package: bundle-images ## Create a tarball with all images and Helm charts used by HMC, useful for deploying in air-gapped environments. + @TEMPLATES_DIR=$(TEMPLATES_DIR) EXTENSION_CHARTS_PACKAGE_DIR=$(EXTENSION_CHARTS_PACKAGE_DIR) HELM=$(HELM) YQ=$(YQ) $(SHELL) "scripts/package-k0s-extensions-helm.sh" + cd $(LOCALBIN) && mkdir -p scripts && cp ../scripts/airgap-push.sh scripts/airgap-push.sh && tar -czf hmc-airgap-$(VERSION).tgz scripts/airgap-push.sh $(shell basename $(CHARTS_PACKAGE_DIR)) $(shell basename $(IMAGES_PACKAGE_DIR)) + package-%-tmpl: @make TEMPLATES_SUBDIR=$(TEMPLATES_DIR)/$* $(patsubst %,package-chart-%,$(shell ls $(TEMPLATES_DIR)/$*)) @@ -154,6 +168,8 @@ lint-chart-%: package-chart-%: lint-chart-% $(HELM) package --destination $(CHARTS_PACKAGE_DIR) $(TEMPLATES_SUBDIR)/$* +##@ Build + LD_FLAGS?= -s -w LD_FLAGS += -X github.com/Mirantis/hmc/internal/build.Version=$(VERSION) LD_FLAGS += -X github.com/Mirantis/hmc/internal/telemetry.segmentToken=$(SEGMENT_TOKEN) @@ -349,11 +365,11 @@ dev-creds-apply: dev-$(DEV_PROVIDER)-creds .PHONY: dev-aws-nuke dev-aws-nuke: envsubst awscli yq cloud-nuke ## Warning: Destructive! Nuke all AWS resources deployed by 'DEV_PROVIDER=aws dev-mcluster-apply' - @CLUSTER_NAME=$(CLUSTER_NAME) YQ=$(YQ) AWSCLI=$(AWSCLI) bash -c "./scripts/aws-nuke-ccm.sh elb" + @CLUSTER_NAME=$(CLUSTER_NAME) YQ=$(YQ) AWSCLI=$(AWSCLI) $(SHELL) "./scripts/aws-nuke-ccm.sh elb" @CLUSTER_NAME=$(CLUSTER_NAME) $(ENVSUBST) < config/dev/aws-cloud-nuke.yaml.tpl > config/dev/aws-cloud-nuke.yaml DISABLE_TELEMETRY=true $(CLOUDNUKE) aws --region $$AWS_REGION --force --config config/dev/aws-cloud-nuke.yaml --resource-type vpc,eip,nat-gateway,ec2,ec2-subnet,elb,elbv2,ebs,internet-gateway,network-interface,security-group @rm config/dev/aws-cloud-nuke.yaml - @CLUSTER_NAME=$(CLUSTER_NAME) YQ=$(YQ) AWSCLI=$(AWSCLI) bash -c "./scripts/aws-nuke-ccm.sh ebs" + @CLUSTER_NAME=$(CLUSTER_NAME) YQ=$(YQ) AWSCLI=$(AWSCLI) $(SHELL) "./scripts/aws-nuke-ccm.sh ebs" .PHONY: dev-azure-nuke dev-azure-nuke: envsubst azure-nuke ## Warning: Destructive! Nuke all Azure resources deployed by 'DEV_PROVIDER=azure dev-mcluster-apply' @@ -529,7 +545,6 @@ $(AWSCLI): | $(LOCALBIN) exit 1; \ fi; \ - # go-install-tool will 'go install' any package with custom target and name of binary, if it doesn't exist # $1 - target path with name of binary (ideally with version) # $2 - package url which can be installed diff --git a/docs/dev.md b/docs/dev.md index 7b16c91e..f3456de0 100644 --- a/docs/dev.md +++ b/docs/dev.md @@ -228,3 +228,15 @@ objects). For example: CSI expects single Secret with configuration in `ini` format ([documented here](https://docs.vmware.com/en/VMware-vSphere-Container-Storage-Plug-in/2.0/vmware-vsphere-csp-getting-started/GUID-BFF39F1D-F70A-4360-ABC9-85BDAFBE8864.html)). Options are similar to CCM and same defaults/considerations are applicable. + +## Generating the airgap bundle +Use the `make airgap-package` target to manually generate the airgap bundle, +to ensure the correctly tagged HMC controller image is present in the bundle +prefix the `IMG` env var with the desired image, for example: + +```bash +IMG="ghcr.io/mirantis/hmc:0.0.3" make airgap-package +``` + +Not setting an `IMG` var will use the default image name/tag generated by the +Makefile. diff --git a/scripts/airgap-push.sh b/scripts/airgap-push.sh new file mode 100755 index 00000000..0f894c36 --- /dev/null +++ b/scripts/airgap-push.sh @@ -0,0 +1,196 @@ +#!/bin/bash +# Copyright 2024 +# +# 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. +# +# This script can be used to help users re-tag and push images and Helm charts +# into a private registry for use when deploying HMC ManagedClusters into an +# air-gapped environment. This script is packaged as part of the airgap bundle +# for convenience. + +REPO="" +CHART_REPO="" +AIRGAP_BUNDLE="" +HELP="" +EXTENSION_TARBALL_PREFIX="hmc-extension-images" +WORK_DIR="$(pwd)/hmc-airgap" + +# Print the help message +function print_help() { + echo "Usage:" + echo " airgap-push.sh [OPTIONS]" + echo "Ensure repositories are logged into via 'helm' and 'docker' before running this script." + echo "Options:" + echo " -h, --help" + echo " Print this help message" + echo " -r, --image-repo (required)" + echo " The image repo to push the images to" + echo " -c, --chart-repo (required)" + echo " The repository to push the Helm charts to, for OCI prefix use oci://" + echo " -i, --insecure-registry" + echo " Use insecure registry for pushing Helm charts" + echo " -a, --airgap-bundle (required)" + echo " The path to the airgap bundle" +} + +function ctrl_c() { + echo "Caught CTRL-C, exiting..." + exit 1 +} + +trap ctrl_c INT + +# Parse the options +while [[ $# -gt 0 ]]; do + key="$1" + case $key in + -h|--help) + HELP="true" + shift + ;; + -r|--image-repo) + REPO="$2" + shift + shift + ;; + -c|--chart-repo) + CHART_REPO="$2" + shift + shift + ;; + -i|--insecure-registry) + INSECURE_REGISTRY="true" + shift + ;; + -a|--airgap-bundle) + AIRGAP_BUNDLE="$2" + shift + shift + ;; + *) + echo "Unknown option: $1" + print_help + exit 1 + ;; + esac +done + + +if [ ! -z "$HELP" ]; then + print_help + exit 0 +fi + +if [ -z "$REPO" ]; then + echo "The repository must be set" + print_help + exit 1 +fi + +if [ -z "$CHART_REPO" ]; then + echo "The chart repository must be set" + print_help + exit 1 +fi + +if [ -z "$AIRGAP_BUNDLE" ]; then + echo "The airgap bundle must be set" + exit 1 +else + # Validate the airgap bundle + if [ ! -f "$AIRGAP_BUNDLE" ]; then + echo "The provided airgap bundle: ${AIRGAP_BUNDLE} does not exist" + exit 1 + fi +fi + +if [ ! $(command -v jq) ]; then + echo "'jq' could not be found, install 'jq' to continue" + exit 1 +fi + +mkdir -p ${WORK_DIR} + +# Extract extension images from the airgap bundle. +echo "Extracting extension images from airgap bundle: ${AIRGAP_BUNDLE}..." +extension_tarball_name=$(tar tf ${AIRGAP_BUNDLE} | grep "${EXTENSION_TARBALL_PREFIX}") +tar -C ${WORK_DIR} -xf ${AIRGAP_BUNDLE} ${extension_tarball_name} +if [ $? -ne 0 ]; then + echo "Failed to extract extension images from the airgap bundle" + exit 1 +fi + +# Load the extension images into the Docker daemon for re-tagging and pushing. +echo "Loading extension images into Docker..." +docker load -i ${WORK_DIR}/${extension_tarball_name} +if [ $? -ne 0 ]; then + echo "Failed to load extension images into Docker" + exit 1 +fi + + +# Extract the repositories json file from the extensions bundle. +echo "Retagging and pushing extension images to ${REPO}..." +tar -C ${WORK_DIR} -xf ${WORK_DIR}/${extension_tarball_name} "repositories" +for image in $(cat ${WORK_DIR}/repositories | jq -r 'to_entries[] | .key'); do + image_name=$(echo ${image} | grep -o '[^/]*$') + + # docker images -a may return multiple images with the same name but + # different tags. We need to retag and push all of them. + for old_image in $(docker images -a | grep ${image} | awk '{print $1":"$2}'); do + tag=${old_image#*:} + new_image="${REPO}/${image_name}:${tag}" + + echo "Retagging image: ${old_image} with ${new_image}..." + + docker tag ${old_image} ${new_image} + if [ $? -ne 0 ]; then + echo "Failed to retag image: ${old_image} with ${new_image}" + exit 1 + fi + + echo "Pushing image: ${new_image}..." + + docker push ${new_image} + if [ $? -ne 0 ]; then + echo "Failed to push image: ${new_image}" + exit 1 + fi + done +done + +# Extract all of the Helm charts from the airgap bundle. +echo "Extracting Helm charts from airgap bundle: ${AIRGAP_BUNDLE}..." +tar -C ${WORK_DIR} -xf ${AIRGAP_BUNDLE} "charts" +if [ $? -ne 0 ]; then + echo "Failed to extract Helm charts from the airgap bundle" + exit 1 +fi + +# Next, use Helm to push the charts to the given chart repository. +echo "Pushing Helm charts to ${CHART_REPO}..." +if [ ! -z "$INSECURE_REGISTRY" ]; then + insecure_registry_flag="--insecure-skip-tls-verify" +fi + +for chart in $(find ${WORK_DIR}/charts -name "*.tgz"); do + helm push ${insecure_registry_flag} ${chart} ${CHART_REPO} + if [ $? -ne 0 ]; then + echo "Failed to push Helm chart: ${chart}" + exit 1 + fi +done + +# Clean up any extracted files. +echo "Cleaning up..." +rm -rf ${WORK_DIR} diff --git a/scripts/bundle-images.sh b/scripts/bundle-images.sh new file mode 100755 index 00000000..d56ff951 --- /dev/null +++ b/scripts/bundle-images.sh @@ -0,0 +1,247 @@ +#!/bin/bash +# Copyright 2024 +# +# 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. +# +# bundle-images.sh bundles all of the images used across HMC into a single +# tarball. This is useful for deploying HMC into air-gapped environments. +# It is recommended to use this script in conjunction with the Makefile target +# `make bundle-images` which will perform some additional steps outside of +# this scripts functionality. +# Usage: make bundle-images +# This script should not be run directly. Use 'make bundle-images' instead. +LABEL_KEY="cluster.x-k8s.io/provider" +IMAGES_BUNDLED="$IMG" +EXTENSION_IMAGES_BUNDLED="" + +echo -e "Bundling images for HMC, this may take awhile...\n" + +trap ctrl_c INT + +function wait_for_deploy_exist() { + local deployment_label=$1 + local max_wait_secs=300 + local interval_secs=5 + local start_time + + start_time=$(date +%s) + + echo "Waiting up to ${max_wait_secs}s for provider Deployment with label: \"${deployment_label}\" to exist in namespace: \"${NAMESPACE}\"..." + + while true; do + current_time=$(date +%s) + if (( (current_time - start_time) > max_wait_secs )); then + echo "Error: Waited for Deployment with label: \"${deployment_label}\" in namespace: \"${NAMESPACE}\" to exist for ${max_wait_secs} seconds and it still does not exist." + return 1 + fi + + output=$(${KUBECTL} -n "${NAMESPACE}" get deploy -l ${deployment_label}) + + if [[ $output != "" ]]; then + echo "Deployment in namespace: \"${NAMESPACE}\" with label: \"${deployment_label}\" exists." + break + else + echo "Deployment with label: \"${deployment_label}\" in namespace: \"${NAMESPACE}\" does not exist yet. Waiting ${interval_secs} seconds..." + sleep $interval_secs + fi + done +} + +function bundle_images() { + local images=$1 + local tarball=$2 + + echo "Bundling images into ${tarball}..." + docker save -o ${tarball} ${images} + if [[ $? -ne 0 ]]; then + echo "Error: Failed to bundle images into ${tarball}" + exit 1 + fi +} + + +function ctrl_c() { + echo "Caught CTRL-C, exiting..." + exit 1 +} + +echo -e "\nVerifying provider Deployments are ready...\n" + +# Verify each provider we support has deployed so we can get the images used +# across the deployments. +for template in $(find ${TEMPLATES_DIR} -name 'provider.yaml'); +do + result=$(grep 'kind: .*Provider' ${template}) + provider_yaml=$(grep "${result}" -A2 ${template}) + provider_kind=$(echo -e "${provider_yaml}" | $YQ e '.kind' -) + provider_name=$(echo -e "${provider_yaml}" | $YQ e '.metadata.name' -) + provider_kind_tolower=$(echo ${provider_kind} | tr '[:upper:]' '[:lower:]') + + if [[ $provider_name == "" ]]; then + echo "Error: Cannot determine provider Name from ${template}" + exit 1 + fi + + if [[ $provider_kind_tolower == "" ]]; then + echo "Error: Cannot determine provider Kind from ${template}" + exit 1 + fi + + # controlplane is a special case which needs a hyphen. + if [[ $provider_kind_tolower == "controlplane" ]]; then + provider_kind_tolower="control-plane" + fi + + # coreprovider does not have a provider prefix. + if [[ $provider_kind_tolower == "coreprovider" ]]; then + label_value=$(echo ${provider_name}) + else + label_value=$(echo $(echo ${provider_kind_tolower} | sed -e 's/provider//g')-${provider_name}) + fi + + wait_for_deploy_exist "$LABEL_KEY=$label_value" + + echo "Verifying Deployment(s) with ${LABEL_KEY}=${label_value} label is condition=available..." + + ${KUBECTL} wait --for condition=available --timeout=10m deploy -l ${LABEL_KEY}=${label_value} -n ${NAMESPACE} + if [[ $? -ne 0 ]]; then + echo "Error: Timed out waiting for available Deployment with ${LABEL_KEY}=${label_value} label" + exit 1 + fi +done + + +# Now that we know everything is deployed and ready, we can get all of images by +# execing into the KIND cluster. +control_plane=$(${KUBECTL} get nodes --no-headers -o custom-columns=":metadata.name") +if [[ $? -ne 0 ]] || [[ $control_plane == "" ]]; then + echo "Error: Cannot get control plane node" + exit 1 +fi + +echo -e "\nPulling images for HMC components...\n" + +for image in $(docker exec -it ${control_plane} crictl images | sed 1,1d | awk '{print $1":"$2}' | grep -v 'kindest'); +do + if [[ $image == "" ]]; then + echo "Error: Failed to get image from KIND cluster, image string should not be empty" + exit 1 + fi + + if [[ $image == *"hmc"* ]]; then + # Don't try to pull the controller image. + continue + fi + + tag=${image#*:} + if [[ $tag == "" ]]; then + echo "Will not pull image: ${image} with tag , continuing..." + continue + fi + + docker pull $image + if [[ $? -ne 0 ]]; then + echo "Error: Failed to pull ${image}" + exit 1 + fi + + IMAGES_BUNDLED="$IMAGES_BUNDLED $image" +done + +echo -e "\nPulling images for HMC extensions...\n" + +# Next, we need to build a list of images used by k0s extensions. Walk the +# templates directory and extract the images used by the extensions. +for template in $(find ${templates_dir} -name 'k0s*.yaml'); +do + if [[ $template == *"k0smotron"* ]]; then + extensions_path=".spec.k0sConfig.spec.extensions.helm" + else + extensions_path=".spec.k0sConfigSpec.k0s.spec.extensions.helm" + fi + + repos=$(grep -vw "{{" ${template} | $YQ e "${extensions_path}.repositories[] | [.url, .name] | join(\";\")") + for repo in $repos + do + url=${repo%;*} + chartname=${repo#*;} + version=$(grep -vw "{{" ${template} | + $YQ e "${extensions_path}.charts[] | select(.chartname == \"*${chartname}*\") | .version") + name=$(grep -vw "{{" ${template} | + $YQ e "${extensions_path}.charts[] | select(.chartname == \"*${chartname}*\") | .name") + grep -vw "{{" $template | $YQ e "${extensions_path}.charts[] | select(.chartname == \"*$chartname*\") | .values" > ${name}-values.yaml + + if [[ $url == "" ]] || [[ $name == "" ]] || [[ $version == "" ]]; then + echo "Error: Failed to get URL, name, or version from ${template}" + exit 1 + fi + + # Use 'helm template' to get the images used by the extension. + if [[ $name == "kube-vip" ]]; then + # FIXME: This is a temporary workaround for kube-vip, if we use + # a custom image tag in the future we'll need to update this. + # kube-vip is a special case where our yaml values result in invalid + # Helm template output, for now render the YAML without values. + template_output=$(${HELM} template --repo ${url} --version ${version} ${name}) + else + template_output=$(${HELM} template --repo ${url} --version ${version} ${name} --values ${name}-values.yaml) + if [[ $? -ne 0 ]]; then + echo "Error: Failed to get images from Helm template for ${name}, trying to output values with debug..." + + template_output=$(${HELM} template --repo ${url} --version ${version} ${name} --values ${name}-values.yaml --debug) + if [[ $? -ne 0 ]]; then + echo "Error: Failed to get images from Helm template for ${name} with debug output" + exit 1 + fi + fi + fi + + for image in $(${HELM} template --repo ${url} --version ${version} ${name} --values ${name}-values.yaml | $YQ -N e .spec.template.spec.containers[].image); + do + docker pull ${image} + if [[ $? -ne 0 ]]; then + echo "Error: Failed to pull ${image}" + exit 1 + fi + + EXTENSION_IMAGES_BUNDLED="$EXTENSION_IMAGES_BUNDLED $image" + done + + rm $name-values.yaml + done +done + +echo -e "\nSaving images...\n" +images_bundled_uniq=$(echo "${IMAGES_BUNDLED}" | tr ' ' '\n' | sort -u) +bundle_images "$images_bundled_uniq" $BUNDLE_TARBALL + +if [[ $EXTENSION_IMAGES_BUNDLED != "" ]]; then + extension_images_bundled_uniq=$(echo "${EXTENSION_IMAGES_BUNDLED}" | tr ' ' '\n' | sort -u) + bundle_images "$extension_images_bundled_uniq" $EXTENSIONS_BUNDLE_TARBALL +fi + +echo -e "\nCleaning up all pulled images...\n" +# Cleanup the images bundled by removing them from the local image cache. +all_images="$images_bundled_uniq $extension_images_bundled_uniq" +for image in $all_images; +do + echo "Removing ${image} from local image cache..." + docker rmi ${image} + if [ $? -ne 0 ]; then + # Note that we failed here but continue trying to remove the other + # images. + echo "Error: Failed to remove ${image} from local image cache" + fi +done + +echo "Done! Images bundled into ${BUNDLE_TARBALL} and ${EXTENSIONS_BUNDLE_TARBALL}" diff --git a/scripts/package-k0s-extensions-helm.sh b/scripts/package-k0s-extensions-helm.sh new file mode 100644 index 00000000..9a6149db --- /dev/null +++ b/scripts/package-k0s-extensions-helm.sh @@ -0,0 +1,40 @@ +#!/bin/bash +# Copyright 2024 +# +# 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. +# This script packages Helm charts affiliated with k0s extensions for airgap +# installations. +# This script should not be run directly. Use 'make airgap-package' instead. +for template in $(find ${TEMPLATES_DIR} -name 'k0s*.yaml'); do + if [[ $template == *"k0smotron"* ]]; then + extensions_path=".spec.k0sConfig.spec.extensions.helm" + else + extensions_path=".spec.k0sConfigSpec.k0s.spec.extensions.helm" + fi + + repos=$(grep -vw "{{" ${template} | ${YQ} e "${extensions_path}.repositories[] | [.url, .name] | join(\";\")") + for repo in $repos; do + url=${repo%;*} + chartname=${repo#*;} + version=$(grep -vw "{{" ${template} | $YQ e "${extensions_path}.charts[] | select(.chartname == \"*${chartname}*\") | .version") + name=$(grep -vw "{{" ${template} | $YQ e "${extensions_path}.charts[] | select(.chartname == \"*${chartname}*\") | .name") + if [[ $url == "" ]] || [[ $name == "" ]] || [[ $version == "" ]]; then + echo "Error: Cannot construct Helm pull command from url: $url, name: $name, version: $version: one or more vars is not populated" + exit 1 + fi + if [[ ! $(find ${EXTENSION_CHARTS_PACKAGE_DIR} -name ${name}-${version}*.tgz) ]]; then + echo "Pulling Helm chart ${name} from ${url} with version ${version}" + ${HELM} pull --repo ${url} --version ${version} ${name} -d ${EXTENSION_CHARTS_PACKAGE_DIR} + fi + done +done diff --git a/templates/cluster/vsphere-hosted-cp/templates/k0smotroncontrolplane.yaml b/templates/cluster/vsphere-hosted-cp/templates/k0smotroncontrolplane.yaml index 375afe4b..cd27b2ff 100644 --- a/templates/cluster/vsphere-hosted-cp/templates/k0smotroncontrolplane.yaml +++ b/templates/cluster/vsphere-hosted-cp/templates/k0smotroncontrolplane.yaml @@ -56,7 +56,7 @@ spec: - key: CriticalAddonsOnly effect: NoExecute operator: Exists - - name: vsphere-csi + - name: vsphere-csi-driver chartname: mirantis/vsphere-csi-driver version: 0.0.2 order: 2 diff --git a/templates/cluster/vsphere-standalone-cp/templates/k0scontrolplane.yaml b/templates/cluster/vsphere-standalone-cp/templates/k0scontrolplane.yaml index 0b18d181..bf6d178e 100644 --- a/templates/cluster/vsphere-standalone-cp/templates/k0scontrolplane.yaml +++ b/templates/cluster/vsphere-standalone-cp/templates/k0scontrolplane.yaml @@ -90,7 +90,7 @@ spec: - key: CriticalAddonsOnly effect: NoExecute operator: Exists - - name: vsphere-csi + - name: vsphere-csi-driver chartname: mirantis/vsphere-csi-driver version: 0.0.2 order: 3