#!/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.

# boskos-heartbeat refreshes the lease kubetest2-kops acquired; the owner
# string must match its acquire (JOB_NAME-kubetest2). No-op for non-GCE.
function boskos-heartbeat() {
    if [[ "${CLOUD_PROVIDER}" != "gce" || -z "${GCP_PROJECT:-}" ]]; then
        return 0
    fi
    local url
    url="http://${BOSKOS_HOST:-boskos.test-pods.svc.cluster.local}/update?name=${GCP_PROJECT}&state=busy&owner=${JOB_NAME:-kops-upgrade}-kubetest2"
    if curl -fsS -o /dev/null -X POST "${url}"; then
        echo "Boskos heartbeat sent for ${GCP_PROJECT}"
    else
        echo "Boskos heartbeat failed for ${GCP_PROJECT}"
    fi
}

# 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)
    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
    boskos-heartbeat
    "${KOPS_B}" reconcile cluster --allow-kops-downgrade --yes
    boskos-heartbeat

    # 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

    boskos-heartbeat
    # shellcheck disable=SC2086
    ${KUBETEST2} \
        --cloud-provider="${CLOUD_PROVIDER}" \
        --kops-binary-path="${KOPS}" \
        --test=kops \
        -- \
        $test_package_args \
        --parallel 25
}
