#!/bin/bash

# This script performs managing of Muster environment.

CSDAC_VERSION='3.0.0'
S3BUCKET_HOST="https://csdac-cosign.s3.us-west-1.amazonaws.com"
PUBLIC_KEY_PATH="release"
COSIGN_IMAGE_PATH="public.ecr.aws/e6e4t5f5/csdac_cosign:windriver-latest"
NL=$'\n'
COLOR_GREEN=$'\u2714'
COLOR_RED=$'\u274c'
PROXY_CONFIG_FILE=/etc/sf/running_config_network_proxy.json
NO_PROXY_SCRIPT=change_docker_noproxy.sh
CDFMC_FILE=/etc/sf/CloudDeployment.enabled
# Allow all connectors by default (both on-prem and cdFMC)
# Include specified connectors for cdFMC
# Exclude specified connectors for on-prem FMC
CDFMC_INCLUDED_CONNECTORS=("pxgrid_cloud" "meta_azuread")
ONPREM_EXCLUDED_CONNECTORS=("pxgrid_cloud")

##### Start up file vars ####
CSDAC_TEMP_DIR="/tmp/csdac"
STARTUP_STATE_FILE="$CSDAC_TEMP_DIR/startup_state.json"
###########

##### Steps description vars ####
DOCKER_PREPARATION="Preparing Docker."
CORE_WARMUP="Bringing up Core services."
CORE_IMAGES_PULL="Downloading Core images."
IMAGES_VERIFICATION="Verifying images."
IMAGE_PULL="Downloading connector images."
USING_LOCAL_IMAGES="Using local images."
###########

##### Step statuses vars ####
WAITING="WAITING"
DONE="DONE"
FAILED="FAILED"
IN_PROGRESS="IN_PROGRESS"
WARNING="WARNING"
SKIPPED="SKIPPED"
###########

# Predefined steps.
STEPS=$(cat <<EOF
[{"description": "$DOCKER_PREPARATION", "state": "$WAITING", "log": ""}]
EOF
)

# Find Python 3. If no Python 3, skip steps which use it.
PYTHON=$(which python3)
if [ $? != 0 ]; then
    MUSTER_STARTUP_STATUS_TO_JSON=0
fi

# Get working dir of script
real_script_name="${0}"
while test -L "${real_script_name}"; do
        real_script_name="$(readlink "${real_script_name}")"
done
SCRIPT_DIR=$(dirname ${real_script_name})
cd "$SCRIPT_DIR"

# Import .env values
if [ -f .env ]
then
  export $(xargs < .env)
fi

help() {
    cat <<EOF
Control and monitor Muster services.
Usage:
  $(basename $0) [COMMAND]
Commands:
  help                                Get this help
  core-logs                           View output from core services
  debug-off                           Turn off debug
  debug-on                            Turn on debug
  container-debug-off <container_id>  Turn debug off for particular container
  container-debug-on <container_id>   Turn debug on for particular container
  trace-on <container_id>             Enable trace logs for the specified container
  trace-off <container_id>            Disable trace logs for the specified container
  log-status <container_id>           Get current log level of the the specified container
  dyn-logs                            View output from dynamically created services (connectors and adapters)
  start                               Start services
  status                              Services status
  stop                                Stop services
  down                                Stop and remove services
  versions                            Show app version for each container
  ts-gen                              Generate trouble-shoot bundle
  noproxy <noproxy_addresses>         Sets IP addresses or domains to bypass proxy, e.g. "localhost,10.10.10.10"
EOF
}

exclude_arg=
include_arg=
if [ -f "$CDFMC_FILE" ]; then
    for connector in "${CDFMC_INCLUDED_CONNECTORS[@]}"; do
        include_arg="$include_arg --include ${connector}.json"
    done
else
    include_arg="--include=*.json"
    for connector in "${ONPREM_EXCLUDED_CONNECTORS[@]}"; do
        exclude_arg="$exclude_arg --exclude ${connector}.json"
    done
fi

image_verification() {

echo "Image verification for signed images... STARTED..."

export DOCKER_CLI_EXPERIMENTAL=enabled
image_status=()
PUBLIC_KEY_FILE='PublicKey.pem'
# get all images from config
images=($(grep -r docker_image -h ./config $include_arg $exclude_arg | sed -rn 's/ *"docker_image" *: *"([^"]+)".*/\1/p'))
# get all images from docker-compose yaml
images+=($(grep -r image: docker-compose.yml | sed 's/^.* //'))
update_state "$IMAGES_VERIFICATION" "$IN_PROGRESS"
# download public key for verification
wget --tries=3 --timeout=30 -q -nv -O ${PUBLIC_KEY_FILE}  ${S3BUCKET_HOST}/${PUBLIC_KEY_PATH}/${PUBLIC_KEY_FILE}
   STATUS=$?
   if [ $STATUS -ne 0 ]; then
      ERROR_LOG="Failed to download verification public key with exit $STATUS. Please check the path and permission."
      echo $ERROR_LOG
      update_state "$IMAGES_VERIFICATION" "$WARNING" "$ERROR_LOG"
      return $STATUS
   fi

if [ -f .env ]; then
	PUBLICECRTOKEN=$(docker run --rm -i -e AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID} -e AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY} -e AWS_DEFAULT_REGION=${AWS_DEFAULT_REGION} amazon/aws-cli ecr-public get-login-password --region=us-east-1)
	echo $PUBLICECRTOKEN | docker login --username AWS --password-stdin public.ecr.aws
fi

# Verify cosign image itself
for i in {0..9}
do
  docker run --rm -v ${PWD}:/home -v ~/.docker:/root/.docker --entrypoint /bin/bash $COSIGN_IMAGE_PATH -c "cosign verify --key /home/$PUBLIC_KEY_FILE $COSIGN_IMAGE_PATH"
  STATUS=$?
  if [ $STATUS == 0 ]; then
    break
  else
    reply_timeout=$(((i+1)*4))
    echo "Previous attempt to verify sign cosign image was unsuccessful. Retry $((i+1))/10 in $reply_timeout sec"
    sleep $reply_timeout
  fi
done
if [ $STATUS == 0 ]; then
  image_status+=("$COSIGN_IMAGE_PATH     ${COLOR_GREEN} ${NL}")
else
  image_status+=("$COSIGN_IMAGE_PATH  ${COLOR_RED} ${NL}")
fi

# iterating images array for verification
for image in ${images[*]}
do
CONTAINER_FULL_TAG=$image
for i in {0..9}
do
  docker run --rm -v ${PWD}:/home -v ~/.docker:/root/.docker --entrypoint /bin/bash $COSIGN_IMAGE_PATH -c "cosign verify --key /home/$PUBLIC_KEY_FILE $CONTAINER_FULL_TAG"
  STATUS=$?
  if [ $STATUS == 0 ]; then
    break
  else
    reply_timeout=$(((i+1)*4))
    echo "Previous attempt to verify sign ${image} was unsuccessful. Retry $((i+1))/10 in $reply_timeout sec"
    sleep $reply_timeout
  fi
done
if [ $STATUS == 0 ]; then
  image_status+=("$CONTAINER_FULL_TAG  ${COLOR_GREEN} ${NL}")
else
  image_status+=("$CONTAINER_FULL_TAG  ${COLOR_RED} ${NL}")
fi
done

echo "------------------------------"
echo " Image Verification Status"
echo "------------------------------"

if [[ " ${image_status[*]} " =~ " ${COLOR_RED} " ]]; then
   ERROR_LOG="One or more image verification failed. Please contact Cisco Support.\n\n ${image_status[*]}"
   printf "$ERROR_LOG"
   update_state "$IMAGES_VERIFICATION" "$WARNING" "$ERROR_LOG"
   return 1
fi
update_state "$IMAGES_VERIFICATION" "$DONE"
echo "${image_status[*]}"
echo "------------------------------"

}

precheck() {
    # Public key bucket check
    {
        wget --spider -q ${S3BUCKET_HOST}/${PUBLIC_KEY_PATH}/${PUBLIC_KEY_FILE} &&
        echo "${COLOR_GREEN} Public key is reachable"
    } || {
        echo "${COLOR_RED} Make sure all of the following hosts are reachable from this host:"
        echo " - ${S3BUCKET_HOST}/"
        echo " - https://public.ecr.aws/"
        echo "If this host is behind a firewall, make sure there are rules that allow communication; if you have a proxy, make sure it is configured to allow access."
        exit 2
    }
    # public.ecr.aws check
    {
        docker pull ${COSIGN_IMAGE_PATH} 1>/dev/null &&
        echo "${COLOR_GREEN} Public.ecr.aws is reachable"
    } || {
        echo "${COLOR_RED} Make sure all of the following hosts are reachable from this host:"
        echo " - ${S3BUCKET_HOST}/"
        echo " - https://public.ecr.aws/"
        echo "If this host is behind a firewall, make sure there are rules that allow communication; if you have a proxy, make sure it is configured to allow access."
        exit 2
    }
}

prepull() {
    #Auth to ECR
    if [ -f .env ]; then
        ECRTOKEN=$(docker run --rm -i -e AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID} -e AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY} -e AWS_DEFAULT_REGION=${AWS_DEFAULT_REGION} amazon/aws-cli ecr get-login-password --region=${AWS_DEFAULT_REGION})
        echo $ECRTOKEN | docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com
	
	PUBLICECRTOKEN=$(docker run --rm -i -e AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID} -e AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY} -e AWS_DEFAULT_REGION=${AWS_DEFAULT_REGION} amazon/aws-cli ecr-public get-login-password --region=us-east-1)
        echo $PUBLICECRTOKEN | docker login --username AWS --password-stdin public.ecr.aws
    fi
    pull_status=()
    update_state "$IMAGE_PULL" "$IN_PROGRESS"
    # Get images for adapters
    adapter_dir="./config/adapters"
    if [ -d $adapter_dir ]; then
        echo "PRE-PULLING IMAGES FOR ADAPTERS" 
        adapter_images=($(grep -r docker_image -h ./config/adapters --include=\*.json | sed -rn 's/ *"docker_image" *: *"([^"]+)".*/\1/p'))
        for image in ${adapter_images[*]}
        do
            echo "Pulling $image ..."
            for i in {0..9}
            do
                docker pull "$image"
                STATUS=$?
                if [ $STATUS == 0 ]; then
                    break
                fi
                reply_timeout=$(((i+1)*4))
                echo "Previous attempt to pull ${image} was unsuccessful. Retry $((i+1))/10 in $reply_timeout sec"
                sleep $reply_timeout
            done
            if [ $STATUS == 0 ]; then
                pull_status+=("$image  ${COLOR_GREEN} ${NL}")
            else
                pull_status+=("$image  ${COLOR_RED} ${NL}")
            fi
        done    
    fi
    # Get images for connectors
    echo "PRE-PULLING IMAGES FOR CONNECTORS"
    connector_images=($(grep -r docker_image -h ./config/connectors $include_arg $exclude_arg | sed -rn 's/ *"docker_image" *: *"([^"]+)".*/\1/p'))
    for image in ${connector_images[*]}
    do
        echo "Pulling $image ..."
        for i in {0..9}
        do
            docker pull "$image"
            STATUS=$?
            if [ $STATUS == 0 ]; then
                break
            fi
            reply_timeout=$(((i+1)*4))
            echo "Previous attempt to pull ${image} was unsuccessful. Retry $((i+1))/10 in $reply_timeout sec"
            sleep $reply_timeout
        done
        if [ $STATUS == 0 ]; then
            pull_status+=("$image  ${COLOR_GREEN} ${NL}")
        else
            pull_status+=("$image  ${COLOR_RED} ${NL}")
        fi
    done
    if [[ " ${pull_status[*]} " =~ " ${COLOR_RED} " ]]; then
        ERROR_LOG="One or more image pull failed. Please contact Cisco Support.\n\n ${pull_status[*]}"
        printf "$ERROR_LOG"
        update_state "$IMAGE_PULL" "$WARNING" "$ERROR_LOG"
    else
        update_state "$IMAGE_PULL" "$DONE"
    fi
}

start() {
    [ "$MUSTER_STARTUP_STATUS_TO_JSON" == "1" ] && prepare_steps
    update_state "$DOCKER_PREPARATION" "$IN_PROGRESS"
    get_http_proxy
    export http_proxy=$http_proxy
    export https_proxy=$http_proxy

    docker volume create muster-status
    docker volume create muster-secret
    docker volume create muster-etcd-data
    docker volume create muster-rules

    docker network create -d bridge -o com.docker.network.bridge.enable_icc=true muster-net || true
    update_state "$DOCKER_PREPARATION" "$DONE"
    [ "$MUSTER_SKIP_VERIFICATION" == "1" ] || image_verification
    VERIFICATION_STATUS=$?
    if [ "$VERIFICATION_STATUS" != 0 ]; then
        update_state "$USING_LOCAL_IMAGES" "$IN_PROGRESS"
        printf "\nStarting CSDAC using local images...\n\n"
        check_local_images
    elif [ "$MUSTER_SKIP_PREPULL" != "1" ]; then
        prepull
        for i in {0..9}
        do
            cmd_wrapper "docker-compose pull" "$CORE_IMAGES_PULL" "$WARNING"
            if [ -z "$ERROR_LOG" ]; then
                break
            else
                reply_timeout=$(((i+1)*4))
                echo "Previous attempt to pull core images was unsuccessful. Retry $((i+1))/10 in $reply_timeout sec"
                sleep $reply_timeout
            fi
        done
        PULL_STATUS="$STATUS"
        [ "$PULL_STATUS" == "$DONE" ] && USING_LOCAL_IMAGES_STATUS="$SKIPPED" || USING_LOCAL_IMAGES_STATUS="$IN_PROGRESS"
        update_state "$USING_LOCAL_IMAGES" "$USING_LOCAL_IMAGES_STATUS"
    fi
    # Auth to ECR if needed
    if ([ -f .env ] && [ -z "$ECRTOKEN" ]); then
        ECRTOKEN=$(docker run --rm -i -e AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID} -e AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY} -e AWS_DEFAULT_REGION=${AWS_DEFAULT_REGION} amazon/aws-cli ecr get-login-password --region=${AWS_DEFAULT_REGION})
        echo $ECRTOKEN | docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com
    fi
    update_state "$CORE_WARMUP" "$IN_PROGRESS"

    export MUSTER_RUN_FILE=
    # Check if CSDAC-HA flag is present and set run files for ui-backend,
    # fmc and user-analysis adapters
    if [ -e /usr/local/sf/csdac/csdac-ha.flag ]; then
        export MUSTER_RUN_FILE=/app/sf/csdac.run
    fi

    docker-compose up -d
    [[ $? = 0 ]] && STATUS="$DONE" || STATUS="$FAILED"
    [ "$USING_LOCAL_IMAGES_STATUS" == "$SKIPPED" ] || update_state "$USING_LOCAL_IMAGES" "$STATUS"
    update_state "$CORE_WARMUP" "$STATUS"
}

stop() {
    # Stop dynamically created containers
    docker exec muster-ui-backend docker-compose -f /app/muster-gen/docker-compose.yml down

    docker-compose stop

    rm -f $STARTUP_STATE_FILE
}

down() {
    stop
    docker-compose down
}

status() {
    echo "=============================================== CORE SERVICES ==============================================="
    docker-compose ps
    echo "=========================== CONNECTORS AND ADAPTERS ==========================="
    docker exec -i muster-ui-backend docker-compose -f /app/muster-gen/docker-compose.yml ps
}

versions_core() {
    containers=''
    containers=$(docker-compose --log-level ERROR images | awk '{if (NR>1) {print $1}}')
    if [ "${containers}" != "" ]
    then
        printf "%-30s | %-20s | %-30s\n" "CONTAINER" "APP VERSION" "COMMIT"
        printf "=%.0s" {1..79}; printf "\n"
        for container in ${containers}; do
            version=$(docker inspect ${container} --format='{{index .Config.Labels "version"}}')
            commit=$(docker inspect ${container} --format='{{index .Config.Labels "commit"}}')
            if [ "${version}" = "" ]; then version='NOT SUPPORTED'; fi
            if [ "${commit}" = "" ]; then commit='NOT SUPPORTED'; fi
            printf "%-30s | %-20s | %-30s\n" "${container}" "${version}" "${commit}"
        done
    else
        echo "No created containers found. Please check that you executed 'muster-cli start' command"
        exit 1
    fi
}

versions_dyn() {
    containers=''
    containers=$(docker exec -i muster-ui-backend docker-compose --log-level ERROR -f /app/muster-gen/docker-compose.yml images | awk '{if (NR>1) {print $1}}')
    if [ "${containers}" != "" ]
    then
        for container in ${containers}; do
            version=$(docker inspect ${container} --format='{{index .Config.Labels "version"}}')
            commit=$(docker inspect ${container} --format='{{index .Config.Labels "commit"}}')
            if [ "${version}" = "" ]; then version='NOT SUPPORTED'; fi
            if [ "${commit}" = "" ]; then commit='NOT SUPPORTED'; fi
            printf "%-30s | %-20s | %-30s\n" "${container}" "${version}" "${commit}"
        done
    else
        echo "No created adapters or connectors found. Please check that you created any adapter or connector"
    fi
}

versions() {
    echo "CSDAC version: ${CSDAC_VERSION}"
    echo "CONTAINERS VERSIONS"
    versions_core
    versions_dyn
}

core_logs() {
    docker-compose logs -f
}

dyn_logs() {
    docker exec -it muster-ui-backend docker-compose -f /app/muster-gen/docker-compose.yml logs -f
}

debug() {
    local flag=$1
    if [ $flag == "on" ] ; then
        local from="INFO"
        local to="DEBUG"
    else
        local from="DEBUG"
        local to="INFO"
    fi

    if [ -f ./docker-compose.yml ] ; then
        # Set MUSTER_RUN_FILE once again, because docker-compose will be
        # restarted
        export MUSTER_RUN_FILE=
        # Check if CSDAC-HA flag is present and set run files for ui-backend,
        # fmc and user-analysis adapters
        if [ -e /usr/local/sf/csdac/csdac-ha.flag ]; then
            export MUSTER_RUN_FILE=/app/sf/csdac.run
        fi

        local current_time=$(date "+%Y.%m.%d-%H.%M.%S")
        cp -f docker-compose.yml docker-compose.yml.$current_time
        sed "s|MUSTER_LOG_LEVEL=${from}|MUSTER_LOG_LEVEL=${to}|" \
            docker-compose.yml.$current_time > docker-compose.yml
        docker-compose up -d
    else
        printf "Cannot find docker-compose.yml in current directory\n"
        exit 1
    fi
}

debug_on() {
    debug "on"
}

debug_off() {
    debug "off"
}

container_debug_on() {
    if [ "$1" == "" ] ; then
      # skip this until BEE start support SUGUSR signals
      # docker kill -s SIGUSR1 $(docker ps -q)
      printf "Please provide container id.\n"
    else
      docker kill -s SIGUSR1 "$1"
    fi
}

container_debug_off() {
    if [ "$1" == "" ] ; then
      # skip this until BEE start support SUGUSR signals
      # docker kill -s SIGUSR2 $(docker ps -q)
      printf "Please provide container id.\n"
    else
      docker kill -s SIGUSR2 "$1"
    fi
}

check_runfiles() {
    run_file=/etc/sf/csdac.run
    enable_file=/etc/sf/csdac.enabled
    printf "===== CSDAC FILES =====\n"
    if [ -f $run_file ]; then
        printf "$run_file file exists\n"
    else
        printf "$run_file file does NOT exist\n"
    fi
    if [ -f $enable_file ]; then
        printf "$enable_file file exists\n\n"
    else
        printf "$enable_file file does NOT exist\n\n"
    fi
}

gen_status() {
    # collect general status info
    local status_log=$1
    local ts_dir=$2
    printf "===== IMAGE VERSIONS =====\n" >> $status_log
    versions >> $status_log 2>&1
    printf "\n\n===== IMAGE STATUS =====\n" >> $status_log
    status >> $status_log 2>&1
    printf "\n\n===== IMAGE DETAILS =====\n" >> $status_log
    docker ps -a >> $status_log
    printf "\n\n===== IMAGE RESOURCES =====\n" >> $status_log
    docker stats --no-stream >> $status_log
    printf "\n\n===== IMAGE PROCESSES =====\n" >> $status_log
    docker-compose top >> $status_log
    printf "\n" >> $status_log
    docker exec -i muster-ui-backend \
            docker-compose --log-level ERROR \
            -f /app/muster-gen/docker-compose.yml top >> $status_log 2>&1
    gzip -9 $status_log

    # go through each images and collect any additional info
    echo "Collecting internal info..."
    mkdir -p $ts_dir/info
    local images=''
    local images=$(docker-compose --log-level ERROR images \
                        | awk '{if (NR>1) {print $1}}')
    images+=" "$((docker exec -i muster-ui-backend \
                        docker-compose --log-level ERROR \
                        -f /app/muster-gen/docker-compose.yml images \
                        | awk '{if (NR>1) {print $1}}') 2> /dev/null)
    for img in $images ; do
        if docker exec $img sh -c "[ -f /app/collect-info.sh ]" ; then
            docker exec -i $img sh /app/collect-info.sh \
                2>&1 | gzip -9 > $ts_dir/info/$img.log.gz
            if docker exec $img sh -c "[ -e /tmp/saved_db ]" ; then
                docker cp -L $img:/tmp/saved_db $ts_dir/info/$img-saved-db
            fi
	    if docker exec $img sh -c "[ -e /tmp/payload_logs ]" ; then
                docker cp -L $img:/tmp/payload_logs $ts_dir/info/$img-payload-logs
            fi
        fi
    done
    echo "Collecting logs..."
    # collect logs from each image
    mkdir -p $ts_dir/logs
    for img in $images ; do
        docker logs $img --since 24h 2>&1 | gzip -9 > $ts_dir/logs/$img-docker.log.gz
    done
    # collect journald logs
    local username=$(id -u -n)
    if groups $username | grep -q -e "\badm\b" -e "\bsystemd-journal\b" ; then
        journalctl --list-boots > $ts_dir/logs/journald-boots.log
        journalctl --since "24 hours ago" | gzip -9 > $ts_dir/logs/journald-day.log.gz
    else
        printf "WARNING: $username is not in group systemd-journal: journald logs skipped.\n"
        printf "    (Use 'sudo usermod -a -G systemd-journal $username' and logout/login to enable)\n"
    fi
}
ts_gen() {
    echo "Generating trouble-shoot bundle."
    echo
    echo "This may take a while.  Please be patient..."
    echo
    local current_time=$(date "+%Y.%m.%d-%H.%M.%S")
    echo "Start Time : $current_time"
    local ts_name="ts-bundle-$current_time"
    local ts_dir=$(mktemp -d "/tmp/$ts_name-XXX")
    # general status
    echo "Collecting general status..."
    local status_log="$ts_dir/status.log"
    printf "===== DOCKER STATUS =====\n" > $status_log
    if docker version > /dev/null 2>&1; then
        printf "Docker is running\n\n" >> $status_log
        check_runfiles >> $status_log
        containers=''
        if [ -f ./docker-compose.yml ] || [ -f ./docker-compose.yaml ]; then
            containers=$(docker-compose --log-level ERROR images | awk '{if (NR>1) {print $1}}')
        else
            printf "Cannot find docker-compose.yml in $(pwd)\n" >> $status_log
        fi
        if [ "${containers}" != "" ]; then
            gen_status $status_log $ts_dir
        else
            printf "No created containers found." >> $status_log
        fi
    else
        printf "Docker is NOT running\n\n" >> $status_log
    fi

    local file_name="$ts_name.tar"
    mv -f $ts_dir "/tmp/$ts_name"
    tar cf $file_name -C /tmp $ts_name
    echo "Trouble-shoot bundle $file_name generated."
    rm -rf "/tmp/$ts_name"
    echo "Finish Time : $(date "+%Y.%m.%d-%H.%M.%S")"
}
get_http_proxy() {
  http_proxy=""
    if [ -f $PROXY_CONFIG_FILE ]; then
      enable=$(get_value_from_proxy_config "enabled")
      if [ "$enable" == 1 ]; then
        proxy=$(get_value_from_proxy_config "proxy")
        port=$(get_value_from_proxy_config "port")
        http_proxy="http://${proxy}:${port}"
      fi
    fi
}

# Takes key as input and prints value
get_value_from_proxy_config()
{
    c=`cat <<EOF
import json
with open("$PROXY_CONFIG_FILE", 'r') as config_file:
    config = json.load(config_file)
    print(config.get("$1"))
EOF`
    python -c "$c"
}

# Prepare all start up steps. Creates/overwrites state file.
prepare_steps() {
    echo "Start up statuses JSON file can be found in $STARTUP_STATE_FILE."

    if [ "$MUSTER_SKIP_VERIFICATION" != "1" ]; then
        add_step "$IMAGES_VERIFICATION"
    fi
    if [ "$MUSTER_SKIP_PREPULL" != "1" ]; then
        add_step "$IMAGE_PULL"
        add_step "$CORE_IMAGES_PULL"
    fi
    add_step "$USING_LOCAL_IMAGES"
    add_step "$CORE_WARMUP"

    mkdir -p /tmp/csdac
    echo "$STEPS" > $STARTUP_STATE_FILE
}

# Add new step.
add_step() {
    c=$(cat <<EOF
import json
steps = json.loads("""$STEPS""".replace("\n", "\\\n"))
steps.append({"description": "$1", "state": "$WAITING", "log": ""})
print(json.dumps(steps))
EOF
    )
    STEPS=$($PYTHON -c "$c")
}

# Update exising state.
update_state() {
    if [ "$MUSTER_STARTUP_STATUS_TO_JSON" == "1" ]; then
        c=$(cat <<EOF
import json
steps = json.loads(r"""$STEPS""")
for step in steps:
    if step["description"] == "$1":
        step["state"] = "$2"
        step["log"] = """$3 """
print(json.dumps(steps))
EOF
        )
        STEPS=$($PYTHON -c "$c")
        echo "$STEPS" > $STARTUP_STATE_FILE
    fi
}

# Wraps command execution.
# Params:
#   $1 - command
#   $2 - stage description
#   $3 - status in case of failure
cmd_wrapper() {
    update_state "$2" "$IN_PROGRESS"
    ERROR_LOG=$(eval "$1" 2>&1 >/dev/null)
    [[ $? = 0 ]] && STATUS="$DONE" && ERROR_LOG="" || STATUS="$3"
    update_state "$2" "$STATUS" "$ERROR_LOG"
}

# Checks for required images locally.
check_local_images() {
    # get all images from docker-compose yaml
    core_images=($(grep -r image: docker-compose.yml | sed 's/^.* //'))
    # get all images from config
    config_images=($(grep -r docker_image -h ./config $include_arg $exclude_arg | sed -rn 's/ *"docker_image" *: *"([^"]+)".*/\1/p'))

    required_images=(${core_images[@]} ${config_images[@]})
    local_images=($(docker image ls --format '{{.Repository}}:{{.Tag}}'))

    # update 'Downloading connector images' and 'Downloading Core images.' steps' state
    if [ "$MUSTER_SKIP_PREPULL" != "1" ]; then
        update_state "$IMAGE_PULL" "$SKIPPED"
        update_state "$CORE_IMAGES_PULL" "$SKIPPED"
    fi

    for image in "${required_images[@]}"; do 
    if [[  ! "${local_images[@]}" =~ "${image}" ]]; then
        ERROR_LOG="\nExited. Required images do not exist locally.\n\n"
        printf "$ERROR_LOG"
        update_state "$USING_LOCAL_IMAGES" "$FAILED" "$ERROR_LOG"
        exit 1
    fi
    done
    update_state "$USING_LOCAL_IMAGES" "$DONE"
}

update_noproxy() {
    $NO_PROXY_SCRIPT noproxy $1
}

# Enable trace logs for the specified container.
trace_on() {
    local container_id=$1
    echo "Enabling tracing for $container_id..."
    if docker exec -i $container_id sh -c "command -v muster_logging_client" > /dev/null 2>&1 ; then
        docker exec -i $container_id sh -c "muster_logging_client set_log_level DEBUG && \
        muster_logging_client set_log_format --from_consume --from_produce -F HUMAN_READABLE" > /dev/null 2>&1
        [[ $? = 0 ]] && echo "Tracing for $container_id enabled."
    elif docker exec -i $container_id sh -c "[ -x ./bee ]" > /dev/null 2>&1 ; then
        docker exec -i $container_id sh -c "./bee set-log-level TRACE && \
        ./bee set-log-format true true HUMAN_READABLE" > /dev/null 2>&1
        [[ $? = 0 ]] && echo "Tracing for $container_id enabled."
    elif docker exec -i $container_id sh -c "[ -x ./connector ]" > /dev/null 2>&1 ; then
        docker exec -i $container_id sh -c "./connector -host=localhost -port=\$MUSTER_GRPC_PORT set_log_level -level=DEBUG; \
        ./connector -host=localhost -port=\$MUSTER_GRPC_PORT set_log_format -from_consume -from_produce -format=HUMAN_READABLE"  > /dev/null 2>&1
        [[ $? = 0 ]] && echo "Tracing for $container_id enabled."
    else
        echo "Enable tracing is not available for '$container_id'"
    fi
}

# Disable trace logs for the specified container.
trace_off() {
    local container_id=$1
    echo "Disabling tracing for $container_id..."
    if docker exec -i $container_id sh -c "command -v muster_logging_client" > /dev/null 2>&1 ; then
        docker exec -i $container_id sh -c "muster_logging_client set_log_level INFO && \
        muster_logging_client set_log_format" > /dev/null 2>&1
        [[ $? = 0 ]] && echo "Tracing for $container_id disabled."
    elif docker exec -i $container_id sh -c "[ -x ./bee ]" > /dev/null 2>&1 ; then
        docker exec -i $container_id sh -c "./bee set-log-level INFO && \
        ./bee set-log-format true true ONE_LINE" > /dev/null 2>&1
        [[ $? = 0 ]] && echo "Tracing for $container_id disabled."
    elif docker exec -i $container_id sh -c "[ -x ./connector ]" > /dev/null 2>&1 ; then
        docker exec -i $container_id sh -c "./connector -host=localhost -port=\$MUSTER_GRPC_PORT set_log_level -level=INFO; \
        ./connector -host=localhost -port=\$MUSTER_GRPC_PORT set_log_format" > /dev/null 2>&1
        [[ $? = 0 ]] && echo "Tracing for $container_id disabled."
    else
        echo "Tracing is not available for '$container_id'"
    fi
}

# Get log level for the specified container.
log_status() {
    local container_id=$1
    if docker exec -i $container_id sh -c "command -v muster_logging_client" > /dev/null 2>&1 ; then
        docker exec -i $container_id sh -c "muster_logging_client get_log_level"
    elif docker exec -i $container_id sh -c "[ -x ./bee ]" > /dev/null 2>&1 ; then
        docker exec -i $container_id sh -c "./bee get-log-level"
    elif docker exec -i $container_id sh -c "[ -x ./connector ]" > /dev/null 2>&1 ; then
        docker exec -i $container_id sh -c "./connector -host=localhost -port=\$MUSTER_GRPC_PORT get_log_level"
    else
        echo "Cannot get log level for '$container_id'"
    fi
}

##### main() #####
case $1 in
    help | "") help ;;
    core-logs) core_logs ;;
    debug-off) debug_off ;;
    debug-on) debug_on ;;
    container-debug-off) container_debug_off "$2" ;;
    container-debug-on) container_debug_on "$2" ;;
    trace-on) trace_on "$2" ;;
    trace-off) trace_off "$2" ;;
    log-status) log_status "$2" ;;
    dyn-logs) dyn_logs ;;
    start) start ;;
    status) status ;;
    stop) stop ;;
    down) down ;;
    versions) versions ;;
    ts-gen) ts_gen ;;
    verify) image_verification ;;
    noproxy) update_noproxy "$2" ;;
    *)
        echo "Unknown command: $1"
        echo
        help
        exit 1
        ;;
esac
exit 0
