#!/bin/bash
#
# Script to install/unistall OperatorLifecycleManager(OLM)
# into the cluster. OLM is used to deploy operator using the
# olm-bundle generated by `operator-generate-bundle` make target.

set -o errexit
set -o pipefail

TEST_DIRECTORY=${TEST_DIRECTORY:-$(dirname "$(readlink -f "$0")")}
source "${TEST_CONFIG:-${TEST_DIRECTORY}/test-config.sh}"

REPO_DIR="${REPO_DIRECTORY:-$(dirname "${TEST_DIRECTORY}")}"
BIN_DIR="${REPO_DIR}/_work/bin"
CLUSTER=${CLUSTER:-pmem-govm}
CLUSTER_DIR="${CLUSTER_DIRECTORY:-${REPO_DIR}/_work/${CLUSTER}}"
SSH="${CLUSTER_DIR}/ssh.0"
KUBECTL="${SSH} kubectl" # Always use the kubectl installed in the cluster.

# https://github.com/operator-framework/operator-lifecycle-manager/releases
OLM_VERSION=v0.20.0

function usage() {
    echo "Usage:"
    echo "  $0 <start|stop>"
}

if [ $# -ne 1 ]; then
    usage
    exit 1
fi

cmd=""
case $1 in
    start)
        cmd="install";;
    stop)
        cmd="uninstall";;
    *)
        usage
        exit 1
esac

# Nothing to do for install or uninstall if the cluster has its own OLM.
if ${TEST_HAVE_OLM}; then
    exit 0
fi

# It's expected that `olm status` returns non-zero if no OLM running
set +e
echo "Checking if OLM is already running..."
${BIN_DIR}/operator-sdk olm status 2>&1
status=$?
set -e
set -x
if [ $cmd == install ]; then
    if [ $status -eq 0 ] ; then
        echo "Reusing already running OLM"
        exit 0
    fi
    # Sometimes operator-sdk fails with timeouts even it successfully
    # installs the OLM
    # https://github.com/operator-framework/operator-sdk/pull/3786
    # So, we depend on `olm status` instead to check if the installation
    # was successfull
    set +e
    echo "Installing OLM..."
    attempt=0
    while true; do
        if ${BIN_DIR}/operator-sdk olm install --version=${OLM_VERSION} --verbose --timeout=5m 2>&1 &&
               ${BIN_DIR}/operator-sdk olm status 2>&1 ; then
            break
        else
            echo "OLM installation failed, attempt #$attempt!!!"
            if [ "$attempt" -ge 5 ]; then
                echo "Giving up. Current status is:"
                ${KUBECTL} get all -n olm
                exit 1
            fi
            echo "OLM installation will be retried after removing the incomplete installation."
            attempt=$((attempt + 1))

            # We try to uninstall "the official way" first, but that sometimes
            # that doesn't work because "uninstall" seems to expect a complete
            # installation. As fallback we delete all objects listed in the
            # YAML file for the release, which seems to be what "install"
            # checks for.
            ${BIN_DIR}/operator-sdk olm uninstall
            ${KUBECTL} delete -f https://github.com/operator-framework/operator-lifecycle-manager/releases/download/${OLM_VERSION}/olm.yaml
            ${KUBECTL} delete -f https://github.com/operator-framework/operator-lifecycle-manager/releases/download/${OLM_VERSION}/crds.yaml
            ${KUBECTL} delete ns olm
        fi
    done
    set -e
    echo "OLM installation sucessful after $attempt retries!!!"
    ## Show olm-operator pod status
    ${KUBECTL} get po -n olm -l app=olm-operator

    # Wait for it to be running.
    ${KUBECTL} wait --for=condition=Ready -n olm pod -l app=olm-operator
elif [ $status -ne 0 ]; then
    echo "No running OLM found."
else
    attempt=0
    while ! ${BIN_DIR}/operator-sdk olm uninstall;  do
        if [ "$attempt" -ge 5 ]; then
            echo "Giving up. Current status is:"
            ${KUBECTL} get all -n olm
            exit 1
        fi
        attempt=$((attempt + 1))
    done
fi
