#!/bin/bash
# (Copyright) [2020 - 2020] Confluent, Inc.

#
# Use shellcheck to lint this file
#

set -e

# Status codes script exit
SUCCESS=false
ERROR_CODE=127
# Status code for CR POST requests
HTTP_SUCCESS_CODE="204"
FORMAT_CMD="jq '.'"

display_help() {
  echo "
This script can be used to import cluster information from a json file to MDS Cluster Registry.

Requirements:
Script requires following command line tools:
 1. curl
 2. jq

Usage:
User can specify the MDS credentials either in the properties file or  as command line argument.
For securing the password the command line argument only accepts the url and user will be prompted
for providing the user name and password
If both --url and --properties-file are provided then properties-file will take precedence and value in
-url will be ignored.

cluster-information-migration-script [-i import] [-e export] [-u url] [-p properties-file] -f clusters-file

Option                                  Description
------                                  -----------
import                                  Import the clusters from "clusters-file" to MDS Cluster Registry
export                                  Export clusters from MDS Cluster Registry to "clusters-file"
url                                     URL for MetadataServer(MDS)
properties-file                         Properties file for providing MDS url, username and password
clusters-file                           Json file for importing/exporting clusters information
[curl options]                          Curl command options. For example --cacert [file] to specify a CA certificate that can verify the remote server.

Example:
cluster-information-migration-script -i -p props.properties -f /apache/cluster.json
cluster-information-migration-script -e --url http://localhost:8090 -f /apache/cluster.json
cluster-information-migration-script -e --url http://localhost:8090 -f /apache/cluster.json -insecure

Sample Properties File:
username=mds
password=mds
url=http://localhost:8090

Sample Json File:
[
 {
   \"clusterName\": \"KafkaCluster\",
   \"scope\": {
     \"clusters\": {
       \"kafka-cluster\": \"kafka-GUID\",
     }
   },
   \"hosts\": [
     {
       \"host\": \"10.5.15.15\",
       \"port\": 9003
     }
   ],
  \"protocol\": \"SASL_PLAINTEXT\"
 }
]
"

  exit 0
}

usage() {
  echo "$(basename "$0")": ERROR: "$*" 1>&2
  echo usage: "$(basename "$0")" [-i import] [-e export] [-u url] [-p properties-file] -f clusters-file 1>&2
  exit 1
}

# Exit with an error message.
die() {
  echo "$@"
  exit "${ERROR_CODE}"
}

is_command() {
  command -v "$1" >/dev/null
}

invalid_requirement() {
  echo -n "Please install '${1}'"
  exit ${ERROR_CODE}
}

# The script requires curl and jq command for execution.
requirements() {
  is_command curl || invalid_requirement "curl"
  is_command jq || invalid_requirement "jq"
}

# Login user with MDS and obtain the jwt token
login_metadata_service() {
  local username="${1}"
  local password="${2}"
  local curl_options=${3}

  http_response=$(curl ${curl_options[@]} -sS -u "${username}":"${password}" "${url}"/security/1.0/authenticate)

  # check if login was successful
  http_status=$(echo "$http_response" | grep HTTP |  awk '{print $2}')
  if [[ "${http_status}"  == "ERROR" ]]; then
    die "Failed to login into Metadata Server."
  else
    # Note: you can perform jq operation only on valid response.
    token=$(echo "${http_response}" | jq -r '.auth_token')
  fi

  echo -e "Successfully logged into Metadata Server."
}

# Registers the clusters provided in Json file with Cluster Registry.
# Note: This operation is atomic i.e all clusters provided in the json file will be registered or none.
# If cluster name already exists in the Registry this operation will result in failure.
register_clusters() {
  validate_json_file "$clusters_file"
  echo "Registering the clusters with MDS Cluster Registry"
  local clusters_file="${1}"
  local curl_options=${2}

  resp_code=$(curl ${curl_options[@]} -sS -w "%{http_code}" -X POST "${url}"/security/1.0/registry/clusters -H "Authorization: Bearer ${token}" -H "accept: application/json" -H "Content-Type: application/json" -d @"${clusters_file}")

  # If cluster registration is successful 204 status code is returned
  if [[ "${resp_code}" = "${HTTP_SUCCESS_CODE}" ]]; then
    echo "Successfully registered the clusters with MDS Cluster Registry."
  else
    die "Failed to register the clusters with MDS Cluster Registry."
  fi
}

# Currently for testing only
# Lists the clusters in Cluster Registry and writes them to a Json file.
export_registered_clusters() {
  local clusters_file="${1}"
  local curl_options=${2}

  list=$(curl ${curl_options[@]} -sS -X GET "${url}"/security/1.0/registry/clusters -H "Authorization: Bearer ${token}" -H "accept: application/json" -H "Content-Type: application/json" | jq .)
  if [ -z "$list" ]
  then
    die "Failed to get the list of registered clusters from MDS Cluster Registry."
  fi
  echo "${list}" >> "${clusters_file}"
  echo "Successfully exported the registered clusters from MDS Cluster Registry to" "${clusters_file}"
}

# Validate if file exists and is a valid json file
validate_json_file() {
  local file_path="${1}"
  if [ -f "$file_path" ]; then
    if ! jq -e . >/dev/null 2>&1 <<< cat "${file_path}" ; then
     die "Invalid json file."
    fi
  else
     die "$file_path does not exist."
  fi
}

# Returns a <value> of (<key>=<value>) pair from properties file
function getProperty {
  prop_key=$2
  prop_file=$1
  prop_value=$(cat "$prop_file" | grep "$prop_key" | cut -d'=' -f2)
  echo "${prop_value}"
}

shutdown() {
  token=""
  if [[ "${SUCCESS}" == false ]]
  then
    echo "Unsuccessful execution. Failed to register the clusters with Cluster Registry."
  fi
}

main() {
  # Parse command-line arguments
  [[ $# -lt 1 ]] && usage "Required parameters missing."
  requirements

  while [[ "$#" -gt 0 ]]; do
    case $1 in
      -u|--url) url="$2"; shift ;;
      -f|--clusters-file) clusters_file="$2"; shift ;;
      -p|--properties-file) props_file="$2"; shift ;;
      -e|--export) operation="export";;
      -i|--import) operation="import";;
      -h|--help) show_help="true";;
        *) break ;;
    esac
    shift
    done

  if [[ "$show_help" == "true" ]]; then
    display_help
  fi

  if [ -z "$operation" ]; then
    usage "Either import or export flag must be specified."
  fi

   if [ -z "$clusters_file" ];then
    usage "Cluster information json file must be specified."
  fi

  # Check if properties file is provided
  if [ -z "$props_file" ];then
    if [ -z "$url" ]; then
      usage "Either MDS url or properties file must be specified."
    else # prompt the user for credentials
      echo "reading credentials::"
      read -p "Username: " user
      read -s -p "Password: " password
      echo -e # new line
    fi
   else # read the properties from properties file
    if [ ! -f "$props_file" ]; then
     die "$props_file does not exist."
    fi

    user=$(getProperty "$props_file" "username")
    if [ -z "$user" ]; then
      usage "'username' property missing in properties file"
    fi

    password=$(getProperty "$props_file" "password")
    if [ -z "$password" ]; then
      usage "'password' property missing in properties file"
    fi

    url=$(getProperty "$props_file" "url")
    if [ -z "$url" ]; then
      usage "'url' property missing in properties file"
    fi
  fi

  # login
  login_metadata_service "$user" "$password" "$@"
  if [[ "${operation}" == "import" ]]; then
     # register the clusters
    register_clusters "$clusters_file" "$@"
  else
    # export the clusters
    export_registered_clusters "$clusters_file" "$@"
  fi

  SUCCESS=true
  trap shutdown EXIT
}

main "$@"
