#!/bin/bash
# Copyright (c) 2020 Red Hat, Inc.

export WAIT_TIMEOUT=${WAIT_TIMEOUT:-10m}
export KUBECONFIG=$HOME/.kube/kind-config-hub
export SPOKE_KUBECONFIG=$HOME/.kube/kind-config-spoke
MONITORING_NS="open-cluster-management-observability"
DEFAULT_NS="open-cluster-management"
SPOKE_NS="open-cluster-management-addon-observability"
HUB_KUBECONFIG=$HOME/.kube/kind-config-hub
kubectl config set-context --current --namespace $MONITORING_NS

print_mco_operator_log() {
    kubectl --kubeconfig $HUB_KUBECONFIG -n $DEFAULT_NS get po \
        | grep multicluster-observability-operator | awk '{print $1}' \
        | xargs kubectl --kubeconfig $HUB_KUBECONFIG -n $DEFAULT_NS logs
}

wait_for_popup() {
    wait_for_event popup $@
}

wait_for_vanish() {
    wait_for_event vanish $@
}

wait_for_event() {
    CONFIG=""
    NAMESPACE=""
    if [ "$#" -eq 5 ]; then
        CONFIG="--kubeconfig $HOME/.kube/$4"
        NAMESPACE="-n $5"
    fi
    n=1
    while true
    do
        entity=$(kubectl get $2 $3 $CONFIG $NAMESPACE| grep -v NAME | awk '{ print $1 }') || true
        if [[ "$1" == "popup" ]]; then
            if [[ ! -z $entity ]]; then
                return
            fi
        elif [[ "$1" == "vanish" ]]; then
            if [[ -z $entity ]]; then
                return
            fi
        fi
        if [[ $n -ge 10 ]]; then
            exit 1
        fi
        n=$((n+1))
        echo "Retrying in 20s..."
        sleep 20
    done
}

run_test_readiness() {
    echo "Test to ensure all critical pods are running"

    MULTICLUSTER_MONITORING_CR_NAME="observability"

    MULTICLUSTER_MONITORING_DEPLOYMENTS="multicluster-observability-operator"
    GRAFANA_DEPLOYMENTS="grafana"
    MINIO_DEPLOYMENTS="minio"

    OBSERVATORIUM_DEPLOYMENTS="$MULTICLUSTER_MONITORING_CR_NAME-observatorium-observatorium-api $MULTICLUSTER_MONITORING_CR_NAME-observatorium-thanos-query $MULTICLUSTER_MONITORING_CR_NAME-observatorium-thanos-receive-controller"

    OBSERVATORIUM_STATEFULSET="$MULTICLUSTER_MONITORING_CR_NAME-observatorium-thanos-compact $MULTICLUSTER_MONITORING_CR_NAME-observatorium-thanos-receive-default $MULTICLUSTER_MONITORING_CR_NAME-observatorium-thanos-rule $MULTICLUSTER_MONITORING_CR_NAME-observatorium-thanos-store-memcached $MULTICLUSTER_MONITORING_CR_NAME-observatorium-thanos-store-shard-0"

    for depl in ${MULTICLUSTER_MONITORING_DEPLOYMENTS}; do
        if ! kubectl -n $DEFAULT_NS rollout status deployments $depl --timeout=$WAIT_TIMEOUT; then
            echo "$depl is not ready after $WAIT_TIMEOUT"
            exit 1
        fi
    done

    echo "wait for operator is ready for reconciling..."

    for depl in ${MINIO_DEPLOYMENTS}; do
        wait_for_popup "deployments" $depl
        if ! kubectl -n $MONITORING_NS rollout status deployments $depl --timeout=$WAIT_TIMEOUT; then
            echo "$depl is not ready after $WAIT_TIMEOUT"
            exit 1
        fi
    done


    for depl in ${OBSERVATORIUM_DEPLOYMENTS}; do
        wait_for_popup "deployments" $depl
        if ! kubectl -n $MONITORING_NS rollout status deployments $depl --timeout=$WAIT_TIMEOUT; then
            echo "$depl is not ready after $WAIT_TIMEOUT"
            exit 1
        fi
    done


    for depl in ${OBSERVATORIUM_STATEFULSET}; do
        wait_for_popup "statefulset" $depl
        if ! kubectl -n $MONITORING_NS rollout status statefulset $depl --timeout=$WAIT_TIMEOUT; then
            echo "$depl is not ready after $WAIT_TIMEOUT"
            exit 1
        fi
    done

    for depl in ${GRAFANA_DEPLOYMENTS}; do
        wait_for_popup "deployments" $depl
        if ! kubectl -n $MONITORING_NS rollout status deployments $depl --timeout=$WAIT_TIMEOUT; then
            echo "$depl is not ready after $WAIT_TIMEOUT"
            exit 1
        fi
    done
}

# test grafana replicas changes
run_test_scale_grafana() {
    kubectl patch MultiClusterObservability observability --patch '{"spec":{"grafana":{"replicas":2}}}' --type=merge

    n=1
    while true
    do
        # check there are 2 grafana pods here
        replicas=$(kubectl get deployment grafana | grep -v AVAILABLE | awk '{ print $4 }') || true
        if [[ $replicas -eq 2 ]]; then
            echo "grafana replicas is update to 2 successfully."
            break
        fi
        if [[ $n -ge 10 ]]; then
            echo "grafana replicas changes test is failed."
            exit 1
        fi
        n=$((n+1))
        echo "Retrying in 10s..."
        sleep 10
    done
}

run_test_teardown() {
    kubectl delete MultiClusterObservability observability
    kubectl delete -n $MONITORING_NS -f tests/e2e/minio
    kubectl delete -n $MONITORING_NS -f deploy/
    kubectl delete -n $MONITORING_NS -f tests/e2e/req_crds/hub_cr
    kubectl delete -n $MONITORING_NS  -f tests/e2e/grafana/grafana-route.yaml
    kubectl delete secret -n ${DEFAULT_NS} multiclusterhub-operator-pull-secret
    kubectl delete -n ${DEFAULT_NS} -f deploy/operator.yaml
    kubectl delete -f deploy/role.yaml
    kubectl delete -f deploy/role_binding.yaml
    kubectl delete -n ${DEFAULT_NS} -f deploy/service_account.yaml

    target_count="0"
    timeout=$true
    interval=0
    intervals=600
    while [ $interval -ne $intervals ]; do
      echo "Waiting for cleaning"
      count=$(kubectl -n $MONITORING_NS get all | wc -l)
      if [ "$count" -eq "$target_count" ]; then
        echo NS count is now: $count
	    timeout=$false
	    break
	  fi
	  sleep 5
	  interval=$((interval+5))
    done

    if [ $timeout ]; then
      echo "Timeout waiting for namespace to be empty"
      exit 1
    fi
}

run_test_reconciling() {
    kubectl patch MultiClusterObservability observability --patch '{"spec":{"retentionResolutionRaw":"14d"}}' --type=merge

    n=1
    while true
    do
        # check the changes were applied into observatorium
        retention=$(kubectl get observatorium observability-observatorium -ojsonpath='{.spec.compact.retentionResolutionRaw}') || true
        if [[ $retention == '14d' ]]; then
            echo "Change retentionResolutionRaw to 14d successfully."
            break
        fi

        if [[ $n -ge 5 ]]; then
            echo "Change retentionResolutionRaw is failed."
            print_mco_operator_log
            exit 1
        fi

        n=$((n+1))
        echo "Retrying in 2s..."
        sleep 2
    done
}

run_test_access_grafana() {
    n=1
    while true
    do
        RESULT=$(curl -s -o /dev/null -w "%{http_code}" -H "Host: grafana.local" -H "X-Forwarded-User: test" http://127.0.0.1/)
        if [ "$RESULT" -eq "200"  ]; then
            echo "grafana can be accessible."
            break
        fi
        if [ $n -ge 5 ]; then
            exit 1
        fi
        n=$((n+1))
        echo "Retrying in 10s..."
        sleep 10
    done

}

run_test_access_grafana_dashboard() {
    RESULT=$(curl -s -H "Host: grafana.local" -H "X-Forwarded-User: test"  http://127.0.0.1/api/search?folderIds=1 | jq '. | length')
    if [ "$RESULT" -eq 10  ]; then
        echo "There are 10 dashboards in default folder."
    else
        echo "The dashboard number is not equal to 10 in default folder."
        exit 1
    fi
}

run_test_endpoint_operator() {

    wait_for_popup oba observability-addon kind-config-hub cluster1
    if [ $? -ne 0 ]; then
        echo "The observabilityAddon observability-addon not created"
        exit 1
    else
        echo "The observabilityAddon observability-addon created"
    fi

    wait_for_popup manifestwork endpoint-observability-work kind-config-hub cluster1
    if [ $? -ne 0 ]; then
        echo "The manifestwork endpoint-observability-work not created"
        exit 1
    else
        echo "The manifestwork endpoint-observability-work created"
    fi

    wait_for_popup secret hub-kube-config kind-config-spoke $SPOKE_NS
    if [ $? -ne 0 ]; then
        echo "The secret hub-kube-config not created"
        exit 1
    else
        echo "The secret hub-kube-config created"
    fi

    wait_for_popup deployment endpoint-observability-operator kind-config-spoke $SPOKE_NS
    if [ $? -ne 0 ]; then
        echo "The deployment endpoint-observability-operator not created"
        exit 1
    else
        echo "The deployment endpoint-observability-operator created"
    fi

    wait_for_popup deployment metrics-collector-deployment kind-config-spoke $SPOKE_NS
    if [ $? -ne 0 ]; then
        echo "The deployment metrics-collector-deployment not created"
        exit 1
    else
        echo "The deployment metrics-collector-deployment created"
    fi
}

run_test_monitoring_disable() {
    # Workaround for placementrules operator
    echo "Patch open-cluster-management-observability placementrule"
    cat ~/.kube/kind-config-hub|grep certificate-authority-data|awk '{split($0, a, ": "); print a[2]}'|base64 -d  >> ca
    cat ~/.kube/kind-config-hub|grep client-certificate-data|awk '{split($0, a, ": "); print a[2]}'|base64 -d >> crt
    cat ~/.kube/kind-config-hub|grep client-key-data|awk '{split($0, a, ": "); print a[2]}'|base64 -d >> key
    SERVER=$(cat ~/.kube/kind-config-hub|grep server|awk '{split($0, a, ": "); print a[2]}')
    curl --cert ./crt --key ./key --cacert ./ca -X PATCH -H "Content-Type:application/merge-patch+json" \
        $SERVER/apis/apps.open-cluster-management.io/v1/namespaces/$MONITORING_NS/placementrules/observability/status \
        -d @./tests/e2e/templates/empty_status.json
    rm ca crt key

    wait_for_vanish oba observability-addon kind-config-hub cluster1
    if [ $? -ne 0 ]; then
        echo "The manifestwork endpoint-observability-work not removed"
        exit 1
    else
        echo "The manifestwork endpoint-observability-work removed"
    fi

    wait_for_vanish manifestwork endpoint-observability-work kind-config-hub cluster1
    if [ $? -ne 0 ]; then
        echo "The manifestwork endpoint-observability-work not removed"
        exit 1
    else
        echo "The manifestwork endpoint-observability-work removed"
    fi

    wait_for_vanish secret hub-kube-config kind-config-spoke $MONITORING_NS
    if [ $? -ne 0 ]; then
        echo "The secret hub-kube-config not removed"
        exit 1
    else
        echo "The secret hub-kube-config removed"
    fi

    wait_for_vanish deployment endpoint-observability-operator kind-config-spoke $MONITORING_NS
    if [ $? -ne 0 ]; then
        echo "The deployment endpoint-observability-operator not removed"
        exit 1
    else
        echo "The deployment endpoint-observability-operator removed"
    fi

    wait_for_vanish deployment metrics-collector-deployment kind-config-spoke $MONITORING_NS
    if [ $? -ne 0 ]; then
        echo "The deployment metrics-collector-deployment not removed"
        exit 1
    else
        echo "The deployment metrics-collector-deployment removed"
    fi
}

run_test_readiness
run_test_reconciling
# run_test_scale_grafana
# run_test_access_grafana
# run_test_access_grafana_dashboard
#run_test_endpoint_operator
run_test_monitoring_disable
run_test_teardown
