#!/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%3N)
  local expire=$(($now + $timeout))
  while [ $now -lt $expire ]; do
    if $cmd ; then
      return 0
    fi  
    sleep $interval
    now=$(date +%s%3N)
  done
  return 1
}

try_until_text() {
  local cmd=$1
  local expected=$2
  local timeout=$3
  local interval=${4:-0.2}
  local now=$(date +%s%3N)
  local expire=$(($now + $timeout))
  while [ $now -lt $expire ]; do
    if [[ "$($cmd)" == "${expected}" ]] ; then
      echo "success, command: \"$cmd\" outputted: $expected"
      return 0
    fi  
      echo "waiting up to $timeout for command: \"$cmd\" to output: $expected"
    sleep $interval
    now=$(date +%s%3N)
  done
  log::error "try_until_text expired for '$cmd' == '$expected'"
  return 1
}

gather_logging_resources() {
  set +e
  local LOGGING_NS=$1
  local outdir=${2:-$ARTIFACT_DIR}
  local runtime=${3:-$(date +%s)}
  outdir=$outdir/$runtime
  mkdir $outdir ||:
  oc -n ${LOGGING_NS} get configmaps -o yaml > $outdir/configmaps.yaml 2>&1 || :
  oc -n ${LOGGING_NS} get secrets -o yaml > $outdir/secrets.yaml 2>&1 || :
  oc -n ${LOGGING_NS} get cronjobs -o yaml > $outdir/cronjobs.yaml 2>&1 || :
  
  oc -n ${LOGGING_NS} get deployments -o wide > $outdir/deployments.txt 2>&1 ||    :
  oc -n ${LOGGING_NS} get ds -o wide > $outdir/daemonsets.txt 2>&1 ||    :
  oc -n ${LOGGING_NS} get pods -o wide > $outdir/pods.txt 2>&1 || :
  oc -n ${LOGGING_NS} get clusterlogging instance -o yaml > $outdir/clusterlogging.instance.yaml  ||:
  oc -n ${LOGGING_NS} get logforwarding instance -o yaml > $outdir/logforwarding.instance.yaml  ||:

  oc -n ${LOGGING_NS} extract secret/elasticsearch --to=$outdir ||:
  oc -n ${LOGGING_NS} extract configmap/fluentd --to=$outdir ||:
  oc -n ${LOGGING_NS} extract configmap/secure-forward --to=$outdir ||:
  oc -n ${LOGGING_NS} extract secret/secure-forward --to=$outdir ||:

  oc -n ${LOGGING_NS} describe ds/fluentd > $outdir/fluentd.describe.txt  ||:
  

  oc -n openshift-logging exec -c elasticsearch \
    $(oc -n openshift-logging get pods -l component=elasticsearch -o jsonpath={.items[0].metadata.name}) \
    -- indices > $outdir/indices.txt||:
  for p in $(oc -n openshift-logging get pods -l component=fluentd -o jsonpath={.items[*].metadata.name}); do
    oc -n openshift-logging exec -- ls -l /var/lib/fluentd/clo_default_output_es > $outdir/$p.buffers.txt||:
    oc -n openshift-logging exec -- ls -l /var/lib/fluentd/retry_clo_default_output_es > $outdir/$p.buffers.retry.txt||:
  done

  oc -n openshift-operators-redhat get deployment elasticsearch-operator -o wide > $outdir/eo-deployment.txt 2>&1 || :
  oc -n openshift-operators-redhat describe deployment elasticsearch-operator > $outdir/eo-deployment.describe 2>&1 || :
  oc -n openshift-operators-redhat logs deployment/elasticsearch-operator > $outdir/elasticsearch-operator.logs 2>&1 || :

  get_all_logging_pod_logs $outdir
  get_all_olm_logs $outdir
  set -e
}

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 || :

    initContainers=$(oc -n ${LOGGING_NS} get po $p -o jsonpath='{.spec.initContainers[*].name}')
    for container in $initContainers ; do
        oc logs -n ${LOGGING_NS} -c $container $p > $outdir/$p.$container.init.log 2>&1
    done

    containers="$(oc -n ${LOGGING_NS} get po $p -o jsonpath='{.spec.containers[*].name}')"
    for container in $containers ; do
      oc logs -n ${LOGGING_NS} -c $container $p > $outdir/$p.$container.log 2>&1
      case "$container" in
        fluentd*) oc -n ${LOGGING_NS} exec $p -- logs > $outdir/$p.$container.exec.log 2>&1 ;;
        elasticsearch*) oc -n ${LOGGING_NS}  exec -c elasticsearch $p  -- logs > $outdir/$p.$container.exec.log 2>&1 ;;
        *) continue ;;
      esac
    done
  done
  set -e
}

get_all_olm_logs(){
    set +e
    local outdir=${1:-$ARTIFACT_DIR}
    local runtime=${2:-"120s"}
    oc  -n openshift-operator-lifecycle-manager logs --since=$runtime deployment/catalog-operator > $outdir/catalog-operator.logs 2>&1
    oc  -n openshift-operator-lifecycle-manager logs --since=$runtime deployment/olm-operator > $outdir/olm-operator.logs 2>&1
    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))
}