#!/bin/bash

millisecond=1
second=$(( 1000 * millisecond ))
minute=$(( 60 * second ))

LOGGING_NS="openshift-logging"

log::info(){
  echo " [INFO] $@"
}

log::error(){
  echo "[ERROR] $@"
}

indent() {
  INDENT="      "
  sed "s/^/$INDENT/" | sed "s/^${INDENT}\($1\)/${INDENT:0:-2}- \1/"
}

expect_success(){
  local cmd=$1
  echo "Running '$cmd'"
  if $cmd ; then
    return 0
  fi  
  return 1
}

try_until_failure() {
  local cmd=$1
  local timeout=$2
  local interval=${3:-0.2}
  local now=$(date +%s)
  local expire=$(($now + $timeout))
  while [ $now -lt $expire ]; do
    if ! $cmd ; then
      return 0
    fi  
    sleep $interval
    now=$(date +%s)
  done
  return 1
}
try_until_success() {
  local cmd=$1
  local timeout=$2
  local interval=${3:-0.2}
  local now=$(date +%s)
  local expire=$(($now + $timeout))
  while [ $now -lt $expire ]; do
    if $cmd ; then
      return 0
    fi  
    sleep $interval
    now=$(date +%s)
  done
  return 1
}

try_until_text() {
  local cmd=$1
  local expected=$2
  local timeout=$3
  local interval=${4:-0.2}
  local now=$(date +%s)
  local expire=$(($now + $timeout))
  while [ $now -lt $expire ]; do
    if [[ "$($cmd)" == "${expected}" ]] ; then
      return 0
    fi  
    sleep $interval
    now=$(date +%s)
  done
  log::error "try_until_text expired for '$cmd' == '$expected'"
  return 1
}
get_all_logging_pod_logs() {
  set +e
  local outdir=${1:-$ARTIFACT_DIR}
  local p
  local container
  for p in $(oc get pods -n ${LOGGING_NS} -o jsonpath='{.items[*].metadata.name}') ; do
    oc -n ${LOGGING_NS} describe pod $p > $outdir/$p.describe 2>&1 || :
    oc -n ${LOGGING_NS} get pod $p -o yaml > $outdir/$p.yaml 2>&1 || :
    for container in $(oc -n ${LOGGING_NS} get po $p -o jsonpath='{.spec.containers[*].name}') ; do
      oc logs -n ${LOGGING_NS} -c $container $p > $outdir/$p.$container.log 2>&1
      case "$container" in
        fluentd*) oc exec -n ${LOGGING_NS} $p -- logs > $outdir/$p.$container.exec.log 2>&1 ;;
        elasticsearch*) oc exec -n ${LOGGING_NS} -c elasticsearch $p  -- logs > $outdir/$p.$container.exec.log 2>&1 ;;
        *) continue ;;
      esac
    done
  done
  set -e
}

wait_for_deployment_to_be_ready(){
  local namespace=$1
  local name=$2
  local timeout=$3
  log::info "Waiting for $namespace/deployment/$name to be ready..."
  try_until_text "oc -n $namespace get deployment $name -o jsonpath={.status.availableReplicas} --ignore-not-found" "1" $timeout
}

deploy_marketplace_operator(){
  local ns=$1
  local name=$2
  local channel=$3
  local package=${4:-$name}
  local global=${5:-false}
  if [ "${global}" = "false" ] ; then 
    cat <<EOL | oc create -f -
apiVersion: v1
kind: List
items:
- apiVersion: v1
  kind: Namespace
  metadata:
    name: "$ns"
- apiVersion: operators.coreos.com/v1
  kind: OperatorGroup
  metadata:
    name: "$ns"
    namespace: "$ns"
  spec:
    targetNamespaces: 
    - "$ns"
    packages: "$name"    
- apiVersion: operators.coreos.com/v1alpha1
  kind: Subscription
  metadata:
    name: "$name"
    namespace: "$ns"
  spec:
    channel: "$channel"
    installPlanApproval: Automatic
    name: "$package"
    source: redhat-operators
    sourceNamespace: openshift-marketplace
EOL
  else
    cat <<EOL | oc create -f -
apiVersion: v1
kind: List
items:
- apiVersion: v1
  kind: Namespace
  metadata:
    name: "$ns"
- apiVersion: operators.coreos.com/v1
  kind: OperatorGroup
  metadata:
    name: "$ns"
    namespace: "$ns"
  spec:
    packages: "$name"    
- apiVersion: operators.coreos.com/v1alpha1
  kind: Subscription
  metadata:
    name: "$name"
    namespace: "$ns"
  spec:
    channel: "$channel"
    installPlanApproval: Automatic
    name: "$package"
    source: redhat-operators
    sourceNamespace: openshift-marketplace
EOL

fi
  wait_for_deployment_to_be_ready $ns $name $((2 * $minute))
}

deploy_config_map_catalog_source() {
  local namespace=$1
  local manifest_dir=$2
  local image=${3:-}

  local version=$(basename $(find $manifest_dir -type d | sort -r | head -n 1))

  local CRD=$(sed '/^#!.*$/d' $manifest_dir/$version/*crd.yaml | grep -v -- "---" | indent apiVersion)
  local PKG=$(sed '/^#!.*$/d' $manifest_dir/*package.yaml | indent packageName)
  local CSV=$(sed '/^#!.*$/d' $manifest_dir/$version/*version.yaml | sed -e "s,imagePullPolicy: IfNotPresent,imagePullPolicy: Always,"  | sed 's/namespace: placeholder/namespace: '$namespace'/' |grep -v -- "---" |  indent apiVersion)
  local PACKAGE_NAME=$(sed -nr 's,.*packageName: (.*),\1,p' $manifest_dir/*package.yaml)
  if [ -n "${image:-}" ] ; then
    CSV=$(echo "$CSV" | sed -e "s~containerImage:.*~containerImage: ${image}~" | indent apiVersion)
    CSV=$(echo "$CSV" | sed -e "s~image:.*~image: ${image}\n~" | indent ApiVersion)
  fi

  cat <<EOF | sed 's/^  *$//' | oc create -n $namespace -f -
kind: ConfigMap
apiVersion: v1
metadata:
  name: $PACKAGE_NAME
data:
  customResourceDefinitions: |-
$CRD
  clusterServiceVersions: |-
$CSV
  packages: |-
$PKG
EOF
  cat <<EOF | oc create -n $namespace -f -
apiVersion: operators.coreos.com/v1alpha1
kind: CatalogSource
metadata:
  name: $PACKAGE_NAME
spec:
  sourceType: internal
  configMap: $PACKAGE_NAME
  displayName: $PACKAGE_NAME
  publisher: Operator Framework
EOF

}

# deploy_clusterlogging_operator using a subscription and the image privided by IMAGE_CLUSTER_LOGGING_OPERATOR
function deploy_clusterlogging_operator() {
    local manifest=${repo_dir}/manifests
    local version=$(basename $(find $manifest -type d | sort -r | head -n 1))
    local csv=$manifest/$version/cluster-logging.*.clusterserviceversion.yaml
    local es_img k_img c_img f_img op_img
    if [ -n "${IMAGE_FORMAT:-}" ] ; then
        IMAGE_CLUSTER_LOGGING_OPERATOR=$(sed -e "s,\${component},cluster-logging-operator," <(echo $IMAGE_FORMAT))
        es_img=${IMAGE_FORMAT/'${component}'/logging-elasticsearch5}
        k_img=${IMAGE_FORMAT/'${component}'/logging-kibana5}
        c_img=${IMAGE_FORMAT/'${component}'/logging-curator5}
        f_img=${IMAGE_FORMAT/'${component}'/logging-fluentd}
        op_img=${IMAGE_FORMAT/'${component}'/oauth-proxy}
    else
        IMAGE_CLUSTER_LOGGING_OPERATOR=${IMAGE_CLUSTER_LOGGING_OPERATOR:-registry.svc.ci.openshift.org/ocp/$version:cluster-logging-operator}
        es_img=${IMAGE_ELASTICSEARCH_IMAGE:-registry.svc.ci.openshift.org/ocp/$version:logging-elasticsearch5}
        k_img=${IMAGE_KIBANA_IMAGE:-registry.svc.ci.openshift.org/ocp/$version:logging-kibana5}
        c_img=${IMAGE_CURATOR_IMAGE:-registry.svc.ci.openshift.org/ocp/$version:logging-curator5}
        f_img=${IMAGE_FLUENTD_IMAGE:-registry.svc.ci.openshift.org/ocp/$version:logging-fluentd}
        op_img=${IMAGE_OAUTH_PROXY_IMAGE:-registry.svc.ci.openshift.org/ocp/$version:oauth-proxy}
    fi
    sed -e "/name: ELASTICSEARCH_IMAGE/,/value:/s,value:.*\$,value: ${es_img}," \
        -e "/name: KIBANA_IMAGE/,/value:/s,value:.*\$,value: ${k_img}," \
        -e "/name: CURATOR_IMAGE/,/value:/s,value:.*\$,value: ${c_img}," \
        -e "/name: FLUENTD_IMAGE/,/value:/s,value:.*\$,value: ${f_img}," \
        -e "/name: OAUTH_PROXY_IMAGE/,/value:/s,value:.*\$,value: ${op_img}," \
        -i $csv
    deploy_operator "openshift-logging" "cluster-logging-operator" $manifest $IMAGE_CLUSTER_LOGGING_OPERATOR $((2 * $minute))
}

function deploy_elasticsearch_operator() {
    local manifest=${repo_dir}/vendor/github.com/openshift/elasticsearch-operator/manifests
    local version=$(basename $(find $manifest -type d | sort -r | head -n 1))
    if [ -n "${IMAGE_FORMAT:-}" ] ; then
        IMAGE_ELASTICSEARCH_OPERATOR=$(sed -e "s,\${component},elasticsearch-operator," <(echo $IMAGE_FORMAT))
    else
        IMAGE_ELASTICSEARCH_OPERATOR=${IMAGE_ELASTICSEARCH_OPERATOR:-registry.svc.ci.openshift.org/ocp/$version:elasticsearch-operator}
    fi
    GLOBAL=true deploy_operator "openshift-operators-redhat" "elasticsearch-operator" $manifest $IMAGE_ELASTICSEARCH_OPERATOR $((2 * $minute))
}

function deploy_operator() {
    local namespace=$1
    local operatorName=$2
    local manifest=$3
    local operatorImage=$4
    local timeout=$5

    local version=$(basename $(find $manifest -type d | sort -r | head -n 1))

    KUBECONFIG=${KUBECONFIG:-$HOME/.kube/config}

    log::info "Creating namespace: ${namespace}"
    oc create ns ${namespace} || :
    
    log::info "Deploying operator from ${manifest}"
    GLOBAL=${GLOBAL:-false} \
    VERSION=${version} \
    OPERATOR_IMAGE=${operatorImage} \
    MANIFEST_DIR=${manifest} \
    TEST_NAMESPACE=${namespace} \
    TARGET_NAMESPACE=${namespace} \
    ${repo_dir}/hack/vendor/olm-test-script/e2e-olm.sh

    if [ "$?" != "0" ] ; then
	    log::error "Error deploying operator via OLM using manifest: $manifest"
	    exit 1
    fi

    wait_for_deployment_to_be_ready $namespace $operatorName $timeout
}
