diff --git a/build-carvel-package.sh b/build-carvel-package.sh new file mode 100755 index 0000000000..6516893496 --- /dev/null +++ b/build-carvel-package.sh @@ -0,0 +1,61 @@ +#!/bin/bash + +function create_and_clear() { + rm -rf "$1" + mkdir -p "$1" +} + +SCDIR=$(realpath $(dirname "$(readlink -f "${BASH_SOURCE[0]}")")) +set -euxo pipefail +pushd $SCDIR > /dev/null +export DATAFLOW_VERSION=$(./mvnw help:evaluate -o -Dexpression=project.version -q -DforceStdout) +export SKIPPER_VERSION=$(./mvnw help:evaluate -o -Dexpression=spring-cloud-skipper.version -pl spring-cloud-dataflow-parent -q -DforceStdout) + +if [ "$PACKAGE_VERSION" = "" ]; then + export PACKAGE_VERSION=$DATAFLOW_VERSION +fi + +# you can launch a local docker registry using docker run -d -p 5000:5000 --name registry registry:2.7 +# export REPO_PREFIX=":5000/" +if [ "$REPO_PREFIX" = "" ]; then + REPO_PREFIX="docker.io/" +fi + +export PACKAGE_BUNDLE_REPOSITORY="${REPO_PREFIX}springcloud/scdf-oss-package" +export REPOSITORY_BUNDLE="${REPO_PREFIX}springcloud/scdf-oss-repo" + +export SKIPPER_REPOSITORY="springcloud/spring-cloud-skipper-server" +export SERVER_REPOSITORY="springcloud/spring-cloud-dataflow-server" +export CTR_VERSION=$DATAFLOW_VERSION +export PACKAGE_NAME="scdf" +export PACKAGE_BUNDLE_TEMPLATE="src/carvel/templates/bundle/package" +export IMGPKG_LOCK_TEMPLATE="src/carvel/templates/imgpkg" +export VENDIR_SRC_IN="src/carvel/config" +export SERVER_VERSION="$DATAFLOW_VERSION" + +export PACKAGE_BUNDLE_GENERATED=/tmp/generated/packagebundle +export IMGPKG_LOCK_GENERATED_IN=/tmp/generated/imgpkgin +export IMGPKG_LOCK_GENERATED_OUT=/tmp/generated/imgpkgout +create_and_clear $PACKAGE_BUNDLE_GENERATED +create_and_clear $IMGPKG_LOCK_GENERATED_IN +create_and_clear $IMGPKG_LOCK_GENERATED_OUT + +echo "bundle-path=$PACKAGE_BUNDLE_GENERATED" +export SCDF_DIR="$SCDIR" + +sh "$SCDIR/.github/actions/build-package-bundle/build-package-bundle.sh" + +imgpkg push --bundle "$PACKAGE_BUNDLE_REPOSITORY:$PACKAGE_VERSION" --file "$PACKAGE_BUNDLE_GENERATED" + +export REPO_BUNDLE_TEMPLATE="src/carvel/templates/bundle/repo" + +export REPO_BUNDLE_RENDERED=/tmp/generated/reporendered +export REPO_BUNDLE_GENERATED=/tmp/generated/repobundle +create_and_clear $REPO_BUNDLE_RENDERED +create_and_clear $REPO_BUNDLE_GENERATED + +sh "$SCDIR/.github/actions/build-repository-bundle/build-repository-bundle.sh" + +imgpkg push --bundle "$REPOSITORY_BUNDLE:$PACKAGE_VERSION" --file "$REPO_BUNDLE_GENERATED" + +popd diff --git a/build-containers.sh b/build-containers.sh new file mode 100755 index 0000000000..77b9a21662 --- /dev/null +++ b/build-containers.sh @@ -0,0 +1,3 @@ +#!/bin/bash +./mvnw install -s .settings.xml -DskipTests -T 1C -am -pl :spring-cloud-dataflow-server,:spring-cloud-skipper-server,:spring-cloud-dataflow-composed-task-runner +./mvnw spring-boot:build-image -s .settings.xml -DskipTests -T 1C -pl :spring-cloud-dataflow-server,:spring-cloud-skipper-server,:spring-cloud-dataflow-composed-task-runner \ No newline at end of file diff --git a/src/carvel/config/dataflow-svc.yml b/src/carvel/config/dataflow-svc.yml index ae728a8897..de0a15015e 100644 --- a/src/carvel/config/dataflow-svc.yml +++ b/src/carvel/config/dataflow-svc.yml @@ -1,6 +1,9 @@ #@ load("@ytt:data", "data") #@ load("dataflow.star", "service_spec_type") - +#@ load("dataflow.star", "service_spec_type_loadbalancer") +#@ load("dataflow.star", "service_spec_allocate_load_balancer_node_ports") +#@ load("dataflow.star", "has_service_spec_load_balancer_class") +#@ load("dataflow.star", "service_spec_load_balancer_class") kind: Service apiVersion: v1 metadata: @@ -18,5 +21,11 @@ spec: - port: 80 targetPort: 9393 name: scdf-server + #@ if service_spec_type_loadbalancer(): + allocateLoadBalancerNodePorts: #@ service_spec_allocate_load_balancer_node_ports() + #@ if has_service_spec_load_balancer_class(): + loadBalancerClass: #@ service_spec_load_balancer_class() + #@ end + #@ end selector: app: scdf-server diff --git a/src/carvel/config/dataflow.star b/src/carvel/config/dataflow.star index c724d794c1..33fe77218b 100644 --- a/src/carvel/config/dataflow.star +++ b/src/carvel/config/dataflow.star @@ -82,11 +82,30 @@ end def image_pull_secrets(): return [{"name": registry_secret_ref()}] end +def has_service_spec_type(): + return non_empty_string(data.values.scdf.server.service.type) +end + +def service_spec_type_loadbalancer(): + return non_empty_string(data.values.scdf.server.service.type) and data.values.scdf.server.service.type == 'LoadBalancer' +end def service_spec_type(): return data.values.scdf.server.service.type end +def service_spec_allocate_load_balancer_node_ports(): + return data.values.scdf.server.service.allocateLoadBalancerNodePorts +end + +def has_service_spec_load_balancer_class(): + return non_empty_string(data.values.scdf.server.service.loadBalancerClass) +end + +def service_spec_load_balancer_class(): + return data.values.scdf.server.service.loadBalancerClass +end + def context_path(): return data.values.scdf.server.contextPath end diff --git a/src/carvel/config/skipper-svc.yml b/src/carvel/config/skipper-svc.yml index 6049816e97..6219d77a90 100644 --- a/src/carvel/config/skipper-svc.yml +++ b/src/carvel/config/skipper-svc.yml @@ -1,5 +1,9 @@ #@ load("@ytt:data", "data") #@ load("skipper.star", "service_spec_type") +#@ load("skipper.star", "service_spec_type_loadbalancer") +#@ load("skipper.star", "service_spec_allocate_load_balancer_node_ports") +#@ load("skipper.star", "has_service_spec_load_balancer_class") +#@ load("skipper.star", "service_spec_load_balancer_class") apiVersion: v1 kind: Service @@ -16,5 +20,11 @@ spec: ports: - port: 80 targetPort: 7577 + #@ if service_spec_type_loadbalancer(): + allocateLoadBalancerNodePorts: #@ service_spec_allocate_load_balancer_node_ports() + #@ if has_service_spec_load_balancer_class(): + loadBalancerClass: #@ service_spec_load_balancer_class() + #@ end + #@ end selector: app: skipper diff --git a/src/carvel/config/skipper.star b/src/carvel/config/skipper.star index 48e3bd03a1..f2bb552f60 100644 --- a/src/carvel/config/skipper.star +++ b/src/carvel/config/skipper.star @@ -90,6 +90,23 @@ def service_spec_type(): return data.values.scdf.skipper.service.type end +def service_spec_type_loadbalancer(): + return non_empty_string(data.values.scdf.skipper.service.type) and data.values.scdf.skipper.service.type == 'LoadBalancer' +end + +def service_spec_allocate_load_balancer_node_ports(): + return data.values.scdf.skipper.service.allocateLoadBalancerNodePorts + end + +def has_service_spec_load_balancer_class(): + return non_empty_string(data.values.scdf.skipper.service.loadBalancerClass) + end + +def service_spec_load_balancer_class(): + return data.values.scdf.skipper.service.loadBalancerClass +end + def skipper_has_password(): return non_empty_string(data.values.scdf.skipper.database.password) -end \ No newline at end of file +end + diff --git a/src/carvel/config/values/values.yml b/src/carvel/config/values/values.yml index af1b65fad0..44de9d0736 100644 --- a/src/carvel/config/values/values.yml +++ b/src/carvel/config/values/values.yml @@ -15,6 +15,8 @@ scdf: digest: "" service: type: ClusterIP + allocateLoadBalancerNodePorts: true + loadBalancerClass: "" resources: limits: cpu: "" @@ -59,6 +61,8 @@ scdf: digest: "" service: type: ClusterIP + allocateLoadBalancerNodePorts: true + loadBalancerClass: "" resources: limits: cpu: "" diff --git a/src/carvel/templates/bundle/repo/values-schema.yml b/src/carvel/templates/bundle/repo/values-schema.yml index c1b77e957c..e760a6c057 100644 --- a/src/carvel/templates/bundle/repo/values-schema.yml +++ b/src/carvel/templates/bundle/repo/values-schema.yml @@ -79,6 +79,12 @@ components: - ClusterIP - ExternalName description: Service type + allocateLoadBalancerNodePorts: + type: boolean + description: Indicates if load balancer should create node ports. Default is true + loadBalancerClass: + type: string + description: Determines a specific configured type of load balancer. resources: type: object properties: @@ -185,6 +191,12 @@ components: - ClusterIP - ExternalName description: Service type + allocateLoadBalancerNodePorts: + type: boolean + description: Indicates if load balancer should create node ports. Default is true + loadBalancerClass: + type: string + description: Determines a specific configured type of load balancer. resources: type: object properties: diff --git a/src/carvel/test/ordering.test.ts b/src/carvel/test/ordering.test.ts index cda44e83d6..05c7b6a728 100644 --- a/src/carvel/test/ordering.test.ts +++ b/src/carvel/test/ordering.test.ts @@ -29,7 +29,6 @@ describe('ordering', () => { expect(findAnnotation(skipperDeployment, 'kapp.k14s.io/change-group')).toBe('scdf.tanzu.vmware.com/skipper'); expect(findAnnotation(dataflowService, 'kapp.k14s.io/change-group')).toBe('scdf.tanzu.vmware.com/server'); expect(findAnnotation(dataflowDeployment, 'kapp.k14s.io/change-group')).toBe('scdf.tanzu.vmware.com/server'); - expect(findAnnotations(dataflowService, 'kapp.k14s.io/change-rule')).toContainAnyValues([ 'upsert after upserting scdf.tanzu.vmware.com/skipper' ]); diff --git a/src/carvel/test/servers.test.ts b/src/carvel/test/servers.test.ts index 85cc7aee80..db78f1b43c 100644 --- a/src/carvel/test/servers.test.ts +++ b/src/carvel/test/servers.test.ts @@ -37,19 +37,25 @@ describe('servers', () => { dataValueYamls: [ ...DEFAULT_REQUIRED_DATA_VALUES, 'scdf.server.service.type=LoadBalancer', - 'scdf.skipper.service.type=LoadBalancer' + 'scdf.server.service.allocateLoadBalancerNodePorts=false', + 'scdf.skipper.service.type=ClusterIP', + 'scdf.skipper.service.allocateLoadBalancerNodePorts=true' ] }); expect(result.success, result.stderr).toBeTruthy(); const yaml = result.stdout; const dataflowService = findService(yaml, SCDF_SERVER_NAME); + console.log(dataflowService); expect(dataflowService).toBeTruthy(); expect(dataflowService?.spec?.type).toBe('LoadBalancer'); + expect(dataflowService?.spec?.allocateLoadBalancerNodePorts).toBe(false); + const skipperService = findService(yaml, SKIPPER_NAME); expect(skipperService).toBeTruthy(); - expect(skipperService?.spec?.type).toBe('LoadBalancer'); + expect(skipperService?.spec?.type).toBe('ClusterIP'); + expect(skipperService?.spec?.allocateLoadBalancerNodePorts).toBeFalsy(); }); it('should have tagged images', async () => { diff --git a/src/deploy/carvel/carvel-add-package.sh b/src/deploy/carvel/carvel-add-package.sh index 46199c095d..0161b3d855 100755 --- a/src/deploy/carvel/carvel-add-package.sh +++ b/src/deploy/carvel/carvel-add-package.sh @@ -15,6 +15,7 @@ fi check_env NS check_env PACKAGE check_env PACKAGE_NAME + echo "Adding $PACKAGE as $PACKAGE_NAME in $NS" if [ "$DEBUG" = "true" ]; then @@ -23,5 +24,27 @@ else ARGS="" fi echo "Creating $PACKAGE_NAME for $PACKAGE" -kctrl package repository add --namespace $NS --repository $PACKAGE_NAME --url $PACKAGE --yes --wait --wait-check-interval 10s $ARGS +if [ "$REPO_SECRET_REF" = "" ]; then + if [[ "$PACKAGE_NAME" == *"pro"* ]]; then + REPO_SECRET_REF=reg-creds-dev-registry + else + REPO_SECRET_REF=reg-creds-dockerhub + fi +fi + +echo "Using secretRef=$REPO_SECRET_REF in $PACKAGE_NAME for $PACKAGE" + +kubectl apply --namespace $NS -f - < " + exit 1 fi -if [ "$2" != "" ]; then - SA=$2 -else - SA=scdf-sa -fi -check_env NS +NS=$1 +SA=$2 + kubectl create namespace $NS -kubectl create namespace secrets-ns $SCDIR/add-roles.sh "system:aggregate-to-edit" "system:aggregate-to-admin" "system:aggregate-to-view" PRESENT=$(kubectl get serviceaccount --namespace $NS --output=json | count_kind serviceaccount "$SA") -if ((PRESENT > 0)); then - kubectl delete serviceaccount "$SA" --namespace $NS +if ((PRESENT==0)); then + kubectl create serviceaccount "$SA" --namespace $NS +fi +IMPORT=true +if [ "$IMPORT" == "true" ]; then + PRESENT=$(kubectl get namespace --output=json | count_kind namespace "secret-ns") + if ((PRESENT == 0)); then + kubectl create namespace secrets-ns + fi + $SCDIR/carvel-add-registry-secret.sh scdfmetadata index.docker.io "$DOCKER_HUB_USERNAME" "$DOCKER_HUB_PASSWORD" + $SCDIR/carvel-import-secret.sh scdfmetadata $NS + $SCDIR/carvel-add-registry-secret.sh reg-creds-dockerhub index.docker.io "$DOCKER_HUB_USERNAME" "$DOCKER_HUB_PASSWORD" + $SCDIR/carvel-import-secret.sh reg-creds-dockerhub $NS +else + create_secret scdfmetadata index.docker.io "$DOCKER_HUB_USERNAME" "$DOCKER_HUB_PASSWORD" "$NS" + create_secret reg-creds-dockerhub index.docker.io "$DOCKER_HUB_USERNAME" "$DOCKER_HUB_PASSWORD" "$NS" fi -kubectl create serviceaccount "$SA" --namespace $NS - -$SCDIR/carvel-add-registry-secret.sh scdfmetadata docker.io "$DOCKER_HUB_USERNAME" "$DOCKER_HUB_PASSWORD" -$SCDIR/carvel-add-registry-secret.sh reg-creds-dockerhub docker.io "$DOCKER_HUB_USERNAME" "$DOCKER_HUB_PASSWORD" -patch_serviceaccount '{"imagePullSecrets": [{"name": "reg-creds-dockerhub"},{"name":"scdfmetadata"}]}' +patch_serviceaccount '{"imagePullSecrets": [{"name": "reg-creds-dockerhub"},{"name":"scdfmetadata"}]}' $SA if [ "$SCDF_TYPE" = "pro" ]; then if [ "$TANZU_DOCKER_USERNAME" = "" ]; then echo "Cannot find TANZU_DOCKER_USERNAME" + exit 1 else check_env TANZU_DOCKER_PASSWORD - $SCDIR/carvel-add-registry-secret.sh reg-creds-dev-registry registry.packages.broadcom.com "$TANZU_DOCKER_USERNAME" "$TANZU_DOCKER_PASSWORD" + # for production + # $SCDIR/carvel-add-registry-secret.sh reg-creds-dev-registry registry.packages.broadcom.com "$TANZU_DOCKER_USERNAME" "$TANZU_DOCKER_PASSWORD" $SCDIR/carvel-add-registry-secret.sh reg-creds-dev-registry spring-scdf-docker-virtual.usw1.packages.broadcom.com "$TANZU_DOCKER_USERNAME" "$TANZU_DOCKER_PASSWORD" - patch_serviceaccount '{"imagePullSecrets": [{"name": "reg-creds-dev-registry"}]}' + $SCDIR/carvel-import-secret.sh reg-creds-dev-registry $NS + patch_serviceaccount '{"imagePullSecrets": [{"name": "reg-creds-dockerhub"},{"name":"scdfmetadata"},{"name": "reg-creds-dev-registry"}]}' $SA fi fi diff --git a/src/deploy/carvel/deploy-local-broker.sh b/src/deploy/carvel/deploy-local-broker.sh index b00b35c2a6..b675b4bc6c 100755 --- a/src/deploy/carvel/deploy-local-broker.sh +++ b/src/deploy/carvel/deploy-local-broker.sh @@ -32,7 +32,7 @@ K8S=$(realpath $SCDIR/../kubernetes) if [ ! -d "$K8S" ]; then K8S=$(realpath $SCDIR/../../kubernetes) fi -$SCDIR/prepare-local-namespace.sh "$BROKER-sa" $BROKER +$SCDIR/prepare-local-namespace.sh $BROKER "$BROKER-sa" kubectl create --namespace $BROKER -f $K8S/$BROKER/ if [ "$BROKER" = "rabbitmq" ]; then kubectl rollout status deployment --namespace "rabbitmq" rabbitmq diff --git a/src/deploy/carvel/deploy-local-database.sh b/src/deploy/carvel/deploy-local-database.sh index 1faeadf535..f92726f69c 100755 --- a/src/deploy/carvel/deploy-local-database.sh +++ b/src/deploy/carvel/deploy-local-database.sh @@ -39,7 +39,7 @@ if [ ! -d "$K8S" ]; then K8S=$(realpath $SCDIR/../../kubernetes) fi set +e -$SCDIR/prepare-local-namespace.sh "$DATABASE-sa" $DATABASE +$SCDIR/prepare-local-namespace.sh $DATABASE "$DATABASE-sa" kubectl create --namespace $DATABASE -f $K8S/$DATABASE/ set -e @@ -50,6 +50,7 @@ set +e "$SCDIR/configure-database.sh" skipper $DATABASE "$JDBC_URL" $DATABASE database-username database-password export DATABASE echo "Deployed $DATABASE. Host:$DATABASE.$DATABASE" + FILE="$(mktemp).yml" cat >$FILE < [namespace]" + echo "Usage: [service-account-name]" exit 1 fi +NS=$1 if [ "$2" != "" ]; then - NS=$2 + SA=$2 +fi +readonly DOCKER_HUB_USERNAME="${DOCKER_HUB_USERNAME:?must be set}" +readonly DOCKER_HUB_PASSWORD="${DOCKER_HUB_PASSWORD:?must be set}" +if [ "$SCDF_TYPE" = "pro" ]; then + readonly TANZU_DOCKER_USERNAME="${TANZU_DOCKER_USERNAME:?must be set}" + readonly TANZU_DOCKER_PASSWORD="${TANZU_DOCKER_PASSWORD:?must be set}" fi -check_env NS -SA=$1 -kubectl create namespace $NS +kubectl create namespace "$NS" $SCDIR/add-roles.sh "system:aggregate-to-edit" "system:aggregate-to-admin" "system:aggregate-to-view" +if [ "$SA" != "" ]; then + kubectl create serviceaccount "$SA" --namespace "$NS" +fi -kubectl create serviceaccount "$SA" --namespace $NS - -$SCDIR/add-local-registry-secret.sh scdfmetadata docker.io "$DOCKER_HUB_USERNAME" "$DOCKER_HUB_PASSWORD" -$SCDIR/add-local-registry-secret.sh reg-creds-dockerhub docker.io "$DOCKER_HUB_USERNAME" "$DOCKER_HUB_PASSWORD" -patch_serviceaccount '{"imagePullSecrets": [{"name": "reg-creds-dockerhub"},{"name":"scdfmetadata"}]}' +$SCDIR/add-local-registry-secret.sh scdfmetadata index.docker.io "$DOCKER_HUB_USERNAME" "$DOCKER_HUB_PASSWORD" +$SCDIR/add-local-registry-secret.sh reg-creds-dockerhub index.docker.io "$DOCKER_HUB_USERNAME" "$DOCKER_HUB_PASSWORD" +patch_serviceaccount '{"imagePullSecrets": [{"name": "reg-creds-dockerhub"},{"name":"scdfmetadata"}]}' "$SA" if [ "$SCDF_TYPE" = "pro" ]; then - if [ "$TANZU_DOCKER_USERNAME" = "" ]; then - echo "Cannot find TANZU_DOCKER_USERNAME" - else - check_env TANZU_DOCKER_PASSWORD - $SCDIR/carvel-add-registry-secret.sh reg-creds-dev-registry registry.packages.broadcom.com "$TANZU_DOCKER_USERNAME" "$TANZU_DOCKER_PASSWORD" - $SCDIR/carvel-add-registry-secret.sh reg-creds-dev-registry spring-scdf-docker-virtual.usw1.packages.broadcom.com "$TANZU_DOCKER_USERNAME" "$TANZU_DOCKER_PASSWORD" - patch_serviceaccount '{"imagePullSecrets": [{"name": "reg-creds-dev-registry"}]}' - fi + $SCDIR/carvel-add-registry-secret.sh reg-creds-dev-registry registry.packages.broadcom.com "$TANZU_DOCKER_USERNAME" "$TANZU_DOCKER_PASSWORD" + $SCDIR/carvel-add-registry-secret.sh reg-creds-dev-registry spring-scdf-docker-virtual.usw1.packages.broadcom.com "$TANZU_DOCKER_USERNAME" "$TANZU_DOCKER_PASSWORD" + patch_serviceaccount '{"imagePullSecrets": [{"name": "reg-creds-dev-registry"}]}' "$SA" fi diff --git a/src/deploy/carvel/setup-scdf-repo.sh b/src/deploy/carvel/setup-scdf-repo.sh index 578c098a36..92bcb49405 100755 --- a/src/deploy/carvel/setup-scdf-repo.sh +++ b/src/deploy/carvel/setup-scdf-repo.sh @@ -2,13 +2,6 @@ bold="\033[1m" dim="\033[2m" end="\033[0m" -function check_env() { - eval ev='$'$1 - if [ "$ev" == "" ]; then - echo "env var $1 not defined" - exit 1 - fi -} function count_kind() { jq --arg kind $1 --arg name $2 '.items | .[] | select(.kind == $kind) | .metadata | select(.name == $name) | .name' | grep -c -F "$2" @@ -20,13 +13,13 @@ fi SCDIR=$(dirname "$(readlink -f "${BASH_SOURCE[0]}")") start_time=$(date +%s) # the following names are your choice. -check_env NS -check_env SCDF_TYPE -check_env PACKAGE_VERSION -check_env DOCKER_HUB_USERNAME -check_env DOCKER_HUB_PASSWORD +readonly NS="${NS:?must be set}" +readonly SCDF_TYPE="${SCDF_TYPE:?must be set}" +readonly PACKAGE_VERSION="${PACKAGE_VERSION:?must be set}" +readonly DOCKER_HUB_USERNAME="${DOCKER_HUB_USERNAME:?must be set}" +readonly DOCKER_HUB_PASSWORD="${DOCKER_HUB_PASSWORD:?must be set}" -$SCDIR/carvel-prepare-namespaces.sh $NS +$SCDIR/carvel-prepare-namespaces.sh $NS scdf-sa # Credentials for docker.io case $SCDF_TYPE in @@ -42,7 +35,7 @@ case $SCDF_TYPE in "oss") PACKAGE_NAME=scdf.tanzu.vmware.com if [ "$PACKAGE_REPO" = "" ]; then - PACKAGE_REPO="index.docker.io/springcloud" + PACKAGE_REPO="docker.io/springcloud" fi if [ "$REPO_NAME" = "" ]; then REPO_NAME="scdf-oss-repo" diff --git a/src/deploy/k8s/configure-k8s.sh b/src/deploy/k8s/configure-k8s.sh index df144a5bd4..1642b4da6c 100755 --- a/src/deploy/k8s/configure-k8s.sh +++ b/src/deploy/k8s/configure-k8s.sh @@ -29,7 +29,9 @@ set +e case "$K8S_DRIVER" in "kind") echo "Creating kind cluster: $K8S_VERSION" + set -e kind create cluster --image "kindest/node:v$K8S_VERSION" + set +e "$SCDIR/setup-metallb.sh" ;; "gke")