Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions tests/e2e/kubetest2-kops/deployer/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,7 @@ func (d *deployer) defaultClusterName() (string, error) {
return "", errors.New("PULL_NUMBER must be set when JOB_TYPE=presubmit and --cluster-name is not set")
}

// TODO(hakman): revisit how dnsDomain is used, ignoring it is unexpected.
var suffix string
switch d.CloudProvider {
case "aws":
Expand All @@ -389,8 +390,13 @@ func (d *deployer) defaultClusterName() (string, error) {
suffix = dnsDomain
}
case "azure":
// Azure uses --dns=none and the domain is not needed
suffix = ""
if dnsDomain == "k8s.local" || strings.HasSuffix(dnsDomain, ".k8s.local") {
// Opt into gossip via a k8s.local KOPS_DNS_DOMAIN.
suffix = dnsDomain
} else {
// With --dns=none and the domain is not needed.
suffix = ""
}
default:
suffix = "k8s.local"
}
Expand Down
164 changes: 164 additions & 0 deletions tests/e2e/scenarios/lib/upgrade.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
#!/usr/bin/env bash

# Copyright 2026 The Kubernetes Authors.
#
# 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.

# kops-upgrade runs an A->B kops upgrade test. Source after lib/common.sh.
# Caller passes the create-args string; sets KOPS_VERSION_{A,B} and K8S_VERSION_{A,B}.
function kops-upgrade() {
local create_args="$1"

if [ -z "${KOPS_VERSION_A-}" ] || [ -z "${K8S_VERSION_A-}" ] || [ -z "${KOPS_VERSION_B-}" ] || [ -z "${K8S_VERSION_B-}" ]; then
>&2 echo "must set all of KOPS_VERSION_A, K8S_VERSION_A, KOPS_VERSION_B, K8S_VERSION_B env vars"
exit 1
fi

TEST_PACKAGE_VERSION="${K8S_VERSION_B}"

if [[ "$K8S_VERSION_A" == "latest" ]]; then
K8S_VERSION_A=$(curl -L https://dl.k8s.io/release/latest.txt)
fi
if [[ "$K8S_VERSION_B" == "latest" ]]; then
K8S_VERSION_B=$(curl -L https://dl.k8s.io/release/latest.txt)
TEST_PACKAGE_MARKER="latest.txt"
fi
if [[ "$K8S_VERSION_A" == "stable" ]]; then
K8S_VERSION_A=$(curl -L https://dl.k8s.io/release/stable.txt)
fi
if [[ "$K8S_VERSION_B" == "stable" ]]; then
K8S_VERSION_B=$(curl -L https://dl.k8s.io/release/stable.txt)
TEST_PACKAGE_MARKER="stable.txt"
fi
if [[ "$K8S_VERSION_A" == "ci" ]]; then
K8S_VERSION_A=https://storage.googleapis.com/k8s-release-dev/ci/$(curl https://storage.googleapis.com/k8s-release-dev/ci/latest.txt)
fi
if [[ "$K8S_VERSION_B" == "ci" ]]; then
K8S_VERSION_B=https://storage.googleapis.com/k8s-release-dev/ci/$(curl https://storage.googleapis.com/k8s-release-dev/ci/latest.txt)
TEST_PACKAGE_MARKER="latest.txt"
TEST_PACKAGE_DIR="ci"
TEST_PACKAGE_URL="https://storage.googleapis.com/k8s-release-dev"
fi

export KOPS_BASE_URL

echo "Cleaning up any leaked resources from previous cluster"
# For KOPS_VERSION_B, the value "latest" means build of the tree
if [[ "${KOPS_VERSION_B}" == "latest" ]]; then
kops-acquire-latest
KOPS_BASE_URL_B="${KOPS_BASE_URL}"
KOPS_B="${KOPS}"
else
KOPS_BASE_URL=$(kops-base-from-marker "${KOPS_VERSION_B}")
KOPS_BASE_URL_B="${KOPS_BASE_URL}"
KOPS_B=$(kops-download-from-base)
CHANNELS=$(kops-channels-download-from-base)
export CHANNELS
fi

${KUBETEST2} \
--down \
--kops-binary-path="${KOPS_B}" || echo "kubetest2 down failed"

# First kOps version may be a released version. If so, it is prefixed with v
if [[ "${KOPS_VERSION_A:0:1}" == "v" ]]; then
KOPS_BASE_URL=""
KOPS_A=$(kops-download-release "$KOPS_VERSION_A")
KOPS="${KOPS_A}"
else
KOPS_BASE_URL=$(kops-base-from-marker "${KOPS_VERSION_A}")
KOPS_A=$(kops-download-from-base)
KOPS="${KOPS_A}"
fi

# TODO: Switch scripts to use KOPS_CONTROL_PLANE_COUNT
if [[ -n "${KOPS_CONTROL_PLANE_SIZE:-}" ]]; then
echo "Recognized (deprecated) KOPS_CONTROL_PLANE_SIZE=${KOPS_CONTROL_PLANE_SIZE}, please set KOPS_CONTROL_PLANE_COUNT instead"
KOPS_CONTROL_PLANE_COUNT=${KOPS_CONTROL_PLANE_SIZE}
fi

# Note that we use --control-plane-size, even though it is deprecated, because we have to support old versions
# in the upgrade test.
${KUBETEST2} \
--up \
--env-file="${WORKSPACE}/env" \
--kops-binary-path="${KOPS_A}" \
--kubernetes-version="${K8S_VERSION_A}" \
--control-plane-size="${KOPS_CONTROL_PLANE_COUNT:-1}" \
--template-path="${KOPS_TEMPLATE:-}" \
--create-args="${create_args}"

# Source the env file to get exported variables, in particular CLUSTER_NAME and KOPS_STATE_STORE
# shellcheck disable=SC1091
. "${WORKSPACE}/env"
export CLUSTER_NAME KOPS_STATE_STORE

# Export kubeconfig-a
KUBECONFIG_A=$(mktemp -t kops.XXXXXXXXX)
"${KOPS_A}" export kubecfg --name "${CLUSTER_NAME}" --admin --kubeconfig "${KUBECONFIG_A}"

# Verify kubeconfig-a
kubectl get nodes -owide --kubeconfig="${KUBECONFIG_A}"

KOPS_BASE_URL="${KOPS_BASE_URL_B}"

KOPS="${KOPS_B}"

"${KOPS_B}" edit cluster "${CLUSTER_NAME}" "--set=cluster.spec.kubernetesVersion=${K8S_VERSION_B}"

# Preview changes
"${KOPS_B}" reconcile cluster --allow-kops-downgrade

# Apply changes
"${KOPS_B}" reconcile cluster --allow-kops-downgrade --yes

# Verify no additional changes
"${KOPS_B}" update cluster

"${KOPS_B}" validate cluster

# Verify kubeconfig-a still works
kubectl get nodes -owide --kubeconfig="${KUBECONFIG_A}"

cp "${KOPS_B}" "${WORKSPACE}/kops"
export PATH="${WORKSPACE}:${PATH}"

"${KOPS_B}" export kubecfg --name "${CLUSTER_NAME}" --admin

if [[ -n ${KOPS_SKIP_E2E:-} ]]; then
return 0
fi

local test_package_args="--parallel 25"

if [[ -n ${TEST_PACKAGE_MARKER-} ]]; then
test_package_args+=" --test-package-marker=${TEST_PACKAGE_MARKER}"
if [[ -n ${TEST_PACKAGE_DIR-} ]]; then
test_package_args+=" --test-package-dir=${TEST_PACKAGE_DIR-}"
fi
if [[ -n ${TEST_PACKAGE_BUCKET-} ]]; then
test_package_args+=" --test-package-url=${TEST_PACKAGE_URL-}"
fi
else
test_package_args+=" --test-package-version=${TEST_PACKAGE_VERSION}"
fi

# shellcheck disable=SC2086
${KUBETEST2} \
--cloud-provider="${CLOUD_PROVIDER}" \
--kops-binary-path="${KOPS}" \
--test=kops \
-- \
$test_package_args \
--parallel 25
}
52 changes: 52 additions & 0 deletions tests/e2e/scenarios/upgrade-ab-gossip/run-test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#!/usr/bin/env bash

# Copyright 2026 The Kubernetes Authors.
#
# 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.

# Like upgrade-ab, but on a gossip cluster — exercises hybrid worker bootstrap (#18245).

REPO_ROOT=$(git rev-parse --show-toplevel);

# k8s.local suffix triggers gossip mode across all clouds.
export KOPS_DNS_DOMAIN="${KOPS_DNS_DOMAIN:-k8s.local}"
if [[ "${KOPS_DNS_DOMAIN}" != "k8s.local" && "${KOPS_DNS_DOMAIN}" != *.k8s.local ]]; then
>&2 echo "KOPS_DNS_DOMAIN must be (or end in) k8s.local for gossip; got ${KOPS_DNS_DOMAIN}"
exit 1
fi

source "${REPO_ROOT}"/tests/e2e/scenarios/lib/common.sh
source "${REPO_ROOT}"/tests/e2e/scenarios/lib/upgrade.sh

# Plain clusters only; the many-addons template is AWS-specific.
unset KOPS_TEMPLATE

# Gossip needs an NLB on AWS, any LB elsewhere.
case "${CLOUD_PROVIDER}" in
aws)
cloud_args="--api-loadbalancer-type=public --api-loadbalancer-class=network"
;;
gce)
cloud_args="--api-loadbalancer-type=public --gce-service-account=default"
;;
*)
cloud_args="--api-loadbalancer-type=public"
;;
esac

# Drop dns-controller's priorityClassName so kops `validate cluster` ignores the pod.
# The new image side-loads only on newly bootstrapped nodes, so until the rolling
# update replaces the old ones the pod stays Pending, and would fail validation.
override="--override=spec.externalDns.priorityClassName="

kops-upgrade "--networking cilium --dns=private ${cloud_args} ${override} ${KOPS_EXTRA_FLAGS:-}"
144 changes: 2 additions & 142 deletions tests/e2e/scenarios/upgrade-ab/run-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,146 +16,6 @@

REPO_ROOT=$(git rev-parse --show-toplevel);
source "${REPO_ROOT}"/tests/e2e/scenarios/lib/common.sh
source "${REPO_ROOT}"/tests/e2e/scenarios/lib/upgrade.sh

if [ -z "${KOPS_VERSION_A-}" ] || [ -z "${K8S_VERSION_A-}" ] || [ -z "${KOPS_VERSION_B-}" ] || [ -z "${K8S_VERSION_B-}" ]; then
>&2 echo "must set all of KOPS_VERSION_A, K8S_VERSION_A, KOPS_VERSION_B, K8S_VERSION_B env vars"
exit 1
fi

TEST_PACKAGE_VERSION="${K8S_VERSION_B}"

if [[ "$K8S_VERSION_A" == "latest" ]]; then
K8S_VERSION_A=$(curl -L https://dl.k8s.io/release/latest.txt)
fi
if [[ "$K8S_VERSION_B" == "latest" ]]; then
K8S_VERSION_B=$(curl -L https://dl.k8s.io/release/latest.txt)
TEST_PACKAGE_MARKER="latest.txt"
fi
if [[ "$K8S_VERSION_A" == "stable" ]]; then
K8S_VERSION_A=$(curl -L https://dl.k8s.io/release/stable.txt)
fi
if [[ "$K8S_VERSION_B" == "stable" ]]; then
K8S_VERSION_B=$(curl -L https://dl.k8s.io/release/stable.txt)
TEST_PACKAGE_MARKER="stable.txt"
fi
if [[ "$K8S_VERSION_A" == "ci" ]]; then
K8S_VERSION_A=https://storage.googleapis.com/k8s-release-dev/ci/$(curl https://storage.googleapis.com/k8s-release-dev/ci/latest.txt)
fi
if [[ "$K8S_VERSION_B" == "ci" ]]; then
K8S_VERSION_B=https://storage.googleapis.com/k8s-release-dev/ci/$(curl https://storage.googleapis.com/k8s-release-dev/ci/latest.txt)
TEST_PACKAGE_MARKER="latest.txt"
TEST_PACKAGE_DIR="ci"
TEST_PACKAGE_URL="https://storage.googleapis.com/k8s-release-dev"
fi

export KOPS_BASE_URL

echo "Cleaning up any leaked resources from previous cluster"
# For KOPS_VERSION_B, the value "latest" means build of the tree
if [[ "${KOPS_VERSION_B}" == "latest" ]]; then
kops-acquire-latest
KOPS_BASE_URL_B="${KOPS_BASE_URL}"
KOPS_B="${KOPS}"
else
KOPS_BASE_URL=$(kops-base-from-marker "${KOPS_VERSION_B}")
KOPS_BASE_URL_B="${KOPS_BASE_URL}"
KOPS_B=$(kops-download-from-base)
CHANNELS=$(kops-channels-download-from-base)
fi

${KUBETEST2} \
--down \
--kops-binary-path="${KOPS_B}" || echo "kubetest2 down failed"

# First kOps version may be a released version. If so, it is prefixed with v
if [[ "${KOPS_VERSION_A:0:1}" == "v" ]]; then
KOPS_BASE_URL=""
KOPS_A=$(kops-download-release "$KOPS_VERSION_A")
KOPS="${KOPS_A}"
else
KOPS_BASE_URL=$(kops-base-from-marker "${KOPS_VERSION_A}")
KOPS_A=$(kops-download-from-base)
KOPS="${KOPS_A}"
fi

# TODO: Switch scripts to use KOPS_CONTROL_PLANE_COUNT
if [[ -n "${KOPS_CONTROL_PLANE_SIZE:-}" ]]; then
echo "Recognized (deprecated) KOPS_CONTROL_PLANE_SIZE=${KOPS_CONTROL_PLANE_SIZE}, please set KOPS_CONTROL_PLANE_COUNT instead"
KOPS_CONTROL_PLANE_COUNT=${KOPS_CONTROL_PLANE_SIZE}
fi

# Note that we use --control-plane-size, even though it is deprecated, because we have to support old versions
# in the upgrade test.
${KUBETEST2} \
--up \
--env-file="${WORKSPACE}/env" \
--kops-binary-path="${KOPS_A}" \
--kubernetes-version="${K8S_VERSION_A}" \
--control-plane-size="${KOPS_CONTROL_PLANE_COUNT:-1}" \
--template-path="${KOPS_TEMPLATE:-}" \
--create-args="--networking calico ${KOPS_EXTRA_FLAGS:-}"

# Source the env file to get exported variables, in particular CLUSTER_NAME and KOPS_STATE_STORE
# shellcheck disable=SC1091
. "${WORKSPACE}/env"
export CLUSTER_NAME KOPS_STATE_STORE

# Export kubeconfig-a
KUBECONFIG_A=$(mktemp -t kops.XXXXXXXXX)
"${KOPS_A}" export kubecfg --name "${CLUSTER_NAME}" --admin --kubeconfig "${KUBECONFIG_A}"

# Verify kubeconfig-a
kubectl get nodes -owide --kubeconfig="${KUBECONFIG_A}"

KOPS_BASE_URL="${KOPS_BASE_URL_B}"

KOPS="${KOPS_B}"

"${KOPS_B}" edit cluster "${CLUSTER_NAME}" "--set=cluster.spec.kubernetesVersion=${K8S_VERSION_B}"

# Preview changes
"${KOPS_B}" reconcile cluster --allow-kops-downgrade

# Apply changes
"${KOPS_B}" reconcile cluster --allow-kops-downgrade --yes

# Verify no additional changes
"${KOPS_B}" update cluster

"${KOPS_B}" validate cluster

# Verify kubeconfig-a still works
kubectl get nodes -owide --kubeconfig="${KUBECONFIG_A}"

cp "${KOPS_B}" "${WORKSPACE}/kops"
export PATH="${WORKSPACE}:${PATH}"

"${KOPS_B}" export kubecfg --name "${CLUSTER_NAME}" --admin

if [[ -n ${KOPS_SKIP_E2E:-} ]]; then
exit
fi


test_package_args="--parallel 25"

if [[ -n ${TEST_PACKAGE_MARKER-} ]]; then
test_package_args+=" --test-package-marker=${TEST_PACKAGE_MARKER}"
if [[ -n ${TEST_PACKAGE_DIR-} ]]; then
test_package_args+=" --test-package-dir=${TEST_PACKAGE_DIR-}"
fi
if [[ -n ${TEST_PACKAGE_BUCKET-} ]]; then
test_package_args+=" --test-package-url=${TEST_PACKAGE_URL-}"
fi
else
test_package_args+=" --test-package-version=${TEST_PACKAGE_VERSION}"
fi

# shellcheck disable=SC2086
${KUBETEST2} \
--cloud-provider="${CLOUD_PROVIDER}" \
--kops-binary-path="${KOPS}" \
--test=kops \
-- \
$test_package_args \
--parallel 25
kops-upgrade "--networking calico ${KOPS_EXTRA_FLAGS:-}"
Loading