#!/usr/bin/env sh
#set -e
#
# This script is meant for quick & easy install via:
#   'curl -sSL http://packages.onedata.org/onedatify.sh | sh -s <zone_name> <space_support_token>'
# or:
#   'wget -qO- http://packages.onedata.org/onedatify.sh | sh -s <zone_name> <space_support_token>'
#

# By default this script installs onedatify package version
DEFAULT_ONEDATIFY_PACKAGE_VERSION="17.06.0"
DEFAULT_ONEPROVIDER_VERSION="onedata/oneprovider:17.06.1"

#######################################
# Utility logging and colour functions
#######################################
colors() {
  if [ -t 1 ] ; then
    def_color=$(tput sgr0 || tput me )
    red=$(tput setaf 1; tput bold || tput md)
    green=$(tput setaf 2;tput bold || tput md)
    yellow=$(tput setaf 3; tput bold || tput md)
    blue=$(tput setaf 4; tput bold || tput md)
    magneta=$(tput setaf 5; tput bold || tput md)
    cyan=$(tput setaf 6; tput bold || tput md)
    grey=$(tput setaf 7;)
    grey_bold=$(tput setaf 7 ; tput bold || tput md )
  else
    def_color=''
    red=''
    green=''
    yellow=''
    blue=''
    magneta=''
    cyan=''
    grey=''
    grey_bold=''
  fi
}
colors

log() {
  printf '%s%s%s%s\n' "$1" "$2" "$3" "$def_color" >&2
}
_log() {
  printf '%s%s%s%s' "$1" "$2" "$3" "$def_color" >&2
}

message() {
  log "$grey_bold" "" "$@"
}
message_imp() {
  log "$red" "" "$@"
}

_message_imp() {
  _log "$red" "" "$@"
}
_message() {
  _log "$grey_bold" "" "$@"
}

command_exists() {
  command -v "$@" > /dev/null 2>&1
}

# shellcheck disable=SC1117
preflight_checks() {

cat <<EOF

  ______                             __              __      __   ______           
 /      \                           /  |            /  |    /  | /      \          
/\$\$\$\$\$\$  | _______    ______    ____\$\$ |  ______   _\$\$ |_   \$\$/ /\$\$\$\$\$\$  |__    __ 
\$\$ |  \$\$ |/       \  /      \  /    \$\$ | /      \ / \$\$   |  /  |\$\$ |_ \$\$//  |  /  |
\$\$ |  \$\$ |\$\$\$\$\$\$\$  |/\$\$\$\$\$\$  |/\$\$\$\$\$\$\$ | \$\$\$\$\$\$  |\$\$\$\$\$\$/   \$\$ |\$\$   |   \$\$ |  \$\$ |
\$\$ |  \$\$ |\$\$ |  \$\$ |\$\$    \$\$ |\$\$ |  \$\$ | /    \$\$ |  \$\$ | __ \$\$ |\$\$\$\$/    \$\$ |  \$\$ |
\$\$ \__\$\$ |\$\$ |  \$\$ |\$\$\$\$\$\$\$\$/ \$\$ \__\$\$ |/\$\$\$\$\$\$\$ |  \$\$ |/  |\$\$ |\$\$ |     \$\$ \__\$\$ |
\$\$    \$\$/ \$\$ |  \$\$ |\$\$       |\$\$    \$\$ |\$\$    \$\$ |  \$\$  \$\$/ \$\$ |\$\$ |     \$\$    \$\$ |
 \$\$\$\$\$\$/  \$\$/   \$\$/  \$\$\$\$\$\$\$/  \$\$\$\$\$\$\$/  \$\$\$\$\$\$\$/    \$\$\$\$/  \$\$/ \$\$/       \$\$\$\$\$\$\$ |
                                                                         /  \__\$\$ |
                                                                         \$\$    \$\$/ 
                                                                          \$\$\$\$\$\$/  
 

The onedatify script allows you to easily install Oneprovider service
and connect to existing data space.

The script will now install the latest versions of docker and docker compose 
on this machine.

In order to install onedatify service prepare the following items:
- a fully qualified domain name (FQDN) of this machine
- valid SSL certificates issued for your FQDN
- data you would like to expose must be accessible for this machine through a POSIX path
- the command 'hostname -f' on your machine must properly return your FQDN
- operating system that supports systemd
- the following ports need to be open:

    53/TCP      DNS (Optional - used for load-balancing)
    53/UDP      DNS (Optional - used for load-balancing)
    80/TCP      HTTP
    443/TCP     HTTPS
    5555/TCP    Communication between Oneclient command line tool and Oneprovider service (TCP)
    5556/TCP    Communication between Oneprovider services among different sites
    6665/TCP    Onedata data transfer channel (RTransfer)
    6666/TCP    Onedata data transfer channel (RTransfer)
    7443/TCP    Communication between Oneprovider instances and Onezone used to exchange metadata
    8443/TCP    REST and CDMI API's (HTTP)
    8876/TCP    RTransfer protocol gateway
    8877/TCP    RTransfer protocol gateway
    9443/TCP    Onepanel web interface

EOF

    proceed_with_the_installation=""
    while [ "$proceed_with_the_installation" != "n" ] && [ "$proceed_with_the_installation" != "y" ] ; do
        _message "Are you ready to proceed with the installation (y|n)?: "
        read proceed_with_the_installation </dev/tty
    done
    if [ "$proceed_with_the_installation" = "n" ] ; then
        message "Please prepare all the requirements and rerun the script." 
        exit 1
    fi

    if ! command_exists systemctl ; then
        message_imp "Your system does not support systemd, the installation cannot continue."
        exit 1
    fi
}

install_docker() {
    message "Installing docker"
    #echo "$sh_c $curl"
    $sh_c "$curl https://get.docker.com/ | sh"
}

do_install() {
    package="$1"
    url="$2"
    onedatify_package_version="$3"

   if [ "$onedatify_package_version" != "" ]; then
     apt_package_package="=$onedatify_package_version"
     yum_package_version="-$onedatify_package_version"
   fi

    apt_url="${url}/apt"
    yum_url="${url}/yum"

    user="$(id -un 2>/dev/null || true)"

    sh_c='sh -c'
    if [ "$user" != 'root' ]; then
        if command_exists sudo; then
            sh_c='sudo -E sh -c'
        elif command_exists su; then
            sh_c='su -c'
        else
cat >&2 <<EOF
Error: this installer needs the ability to run commands as root.
We are unable to find either "sudo" or "su" available to make this happen.
EOF
        exit 1
        fi
    fi

    curl=''
    if command_exists curl; then
        curl='curl -sSL'
    elif command_exists wget; then
        curl='wget -qO-'
    fi

    message ""
    message "########### Installing Onedatify Pacage ###########"
    message "Onedatify installation process started..."
    message ""

    if ! command_exists docker ; then
        install_docker=""
        while [ "$install_docker" != "n" ] && [ "$install_docker" != "y" ] ; do
            _message "We detected you don't have docker installed. Would you like to install it now (y|n)?: "
            read install_docker </dev/tty
        done
        if [ "$install_docker" = "y" ] ; then
            install_docker
            if ! command_exists docker ; then
                message "Docker installation must have failed." 
                exit 1
            fi
        fi
        if [ "$install_docker" = "n" ] ; then
            message "This script cannot continue without docker."
            exit 1
        fi
    else 
        message "Docker installation found."
    fi

    if ! command_exists docker-compose ; then
        install_compose=""
        while [ "$install_compose" != "n" ] && [ "$install_compose" != "y" ] ; do
            _message "We detected you don't have docker-compose installed. Would you like to install it now (y|n)?: "
            read install_compose </dev/tty
        done
        if [ "$install_compose" = "y" ] ; then
            message "Docker-compose installation started..."
            $sh_c "$curl -L https://github.com/docker/compose/releases/download/1.19.0/docker-compose-$(uname -s)-$(uname -m) > /usr/local/bin/docker-compose"
            $sh_c "chmod +x /usr/local/bin/docker-compose"
            message "Docker-compose installed under /usr/local/bin/docker-compose"
            if ! command_exists docker-compose  ; then
                message "Docker-compose installation must have failed." 
                exit 1
            fi
        fi
        if [ "$install_compose" = "n" ] ; then
            message "This script cannot continue without docker-compose."
            exit 1
        fi
    else 
        message "Docker-compose binary was detected on the machine."
    fi

    message "Installing onedatify package:"
    # # Temorary hack
    if command_exists apt; then
        if dpkg-query -W onedatify 2>/dev/null 2>&1; then
            $sh_c "apt remove -y $package"
        fi
        deb_package_name="onedatify_${onedatify_package_version}.systemd_amd64.deb"
        $sh_c "curl --show-error https://packages.onedata.org/$deb_package_name> /tmp/$deb_package_name"
        $sh_c "dpkg -i /tmp/$deb_package_name"
        $sh_c "apt-mark hold $package"
    else 
        if yum list installed onedatify 2>/dev/null 2>&1; then
            $sh_c "yum remove -y $package"
        fi
        rpm_package_name="onedatify_${onedatify_package_version}.systemd-1.x86_64.rpm"
        $sh_c "curl --show-error --silent https://packages.onedata.org/$rpm_package_name > /tmp/$rpm_package_name"
        $sh_c "/tmp/$rpm_package_name"
    fi
    return 0

    # perform some very rudimentary platform detection
    lsb_dist=''
    dist_version=''
    if command_exists lsb_release; then
        lsb_dist="$(lsb_release -si)"
    fi
    if [ -z "$lsb_dist" ] && [ -r /etc/lsb-release ]; then
        lsb_dist="$(. /etc/lsb-release && echo "$DISTRIB_ID")"
    fi
    if [ -z "$lsb_dist" ] && [ -r /etc/debian_version ]; then
        lsb_dist='debian'
    fi
    if [ -z "$lsb_dist" ] && [ -r /etc/fedora-release ]; then
        lsb_dist='fedora'
    fi
    if [ -z "$lsb_dist" ] && [ -r /etc/oracle-release ]; then
        lsb_dist='oracleserver'
    fi
    if [ -z "$lsb_dist" ] && [ -r /etc/centos-release ]; then
        lsb_dist='centos'
    fi
    if [ -z "$lsb_dist" ] && [ -r /etc/redhat-release ]; then
        lsb_dist='redhat'
    fi
    if [ -z "$lsb_dist" ] && [ -r /etc/photon-release ]; then
        lsb_dist='photon'
    fi
    if [ -z "$lsb_dist" ] && [ -r /etc/os-release ]; then
        lsb_dist="$(. /etc/os-release && echo "$ID")"
    fi

    lsb_dist="$(echo "$lsb_dist" | tr '[:upper:]' '[:lower:]')"

    # Special case redhatenterpriseserver
    if [ "${lsb_dist}" = "redhatenterpriseserver" ]; then
            # Set it to redhat, it will be changed to centos below anyways
            lsb_dist='redhat'
    fi

    case "$lsb_dist" in
        ubuntu)
            if command_exists lsb_release; then
                dist_version="$(lsb_release --codename | cut -f2)"
            fi
            if [ -z "$dist_version" ] && [ -r /etc/lsb-release ]; then
                dist_version="$(. /etc/lsb-release && echo "$DISTRIB_CODENAME")"
            fi
        ;;
        debian|raspbian)
            dist_version="$(cat /etc/debian_version | sed 's/\/.*//' | sed 's/\..*//')"
            case "$dist_version" in
                9)
                    dist_version="stretch"
                ;;
                8)
                    dist_version="jessie"
                ;;
                7)
                    dist_version="wheezy"
                ;;
            esac
        ;;
        oracleserver)
            # need to switch lsb_dist to match yum repo URL
            lsb_dist="oraclelinux"
            dist_version="$(rpm -q --whatprovides redhat-release --queryformat "%{VERSION}\n" | sed 's/\/.*//' | sed 's/\..*//' | sed 's/Server*//')"
        ;;

        fedora|centos|redhat)
            dist_version="$(rpm -q --whatprovides ${lsb_dist}-release --queryformat "%{VERSION}\n" | sed 's/\/.*//' | sed 's/\..*//' | sed 's/Server*//' | sort | tail -1)"
        ;;

        "vmware photon")
            lsb_dist="photon"
            # shellcheck disable=SC1091
            dist_version="$(. /etc/os-release && echo "$VERSION_ID")"
        ;;

        *)
            if command_exists lsb_release; then
                dist_version="$(lsb_release --codename | cut -f2)"
            fi
            if [ -z "$dist_version" ] && [ -r /etc/os-release ]; then
            # shellcheck disable=SC1091
                dist_version="$(. /etc/os-release && echo "$VERSION_ID")"
            fi
        ;;
    esac

    # Run setup for each distro accordingly
    case "$lsb_dist" in
        ubuntu|debian|raspbian)
            export DEBIAN_FRONTEND=noninteractive
            (
            set -x
            $sh_c "$curl ${apt_url}/onedata.gpg.key | apt-key add -"
            $sh_c "mkdir -p /etc/apt/sources.list.d"
            $sh_c "echo deb \[arch=$(dpkg --print-architecture)\] ${apt_url}/${lsb_dist}/${dist_version} ${dist_version} ${repo} > /etc/apt/sources.list.d/onedata.list"
            $sh_c "echo deb-src \[arch=$(dpkg --print-architecture)\] ${apt_url}/${lsb_dist}/${dist_version} ${dist_version} ${repo} >> /etc/apt/sources.list.d/onedata.list"
            $sh_c "sleep 3 ; apt-get update ; apt-get remove -y -q ${package}"
            $sh_c "sleep 3 ; apt-get update ; apt-get install --allow-unauthenticated -y -q ${package}=${apt_package_package}"
            $sh_c "sleep 3 ; apt-mark hold ${package}"
            )
            return 0
            ;;

        fedora|centos|redhat|oraclelinux|photon)
            if [ "${lsb_dist}" = "redhat" ]; then
                # we use the centos repository for both redhat and centos releases
                lsb_dist='centos'
            fi
            if [ "${lsb_dist}" = "centos" ]; then
                # we use the centos repository for both redhat and centos releases
                dist_version=${dist_version}x
            fi
            if [ "${lsb_dist}" = "scientific" ]; then
                # we use the centos repository for both redhat and centos releases
                dist_version=${dist_version}x
            fi
            reponame="onedata-${repo}"
$sh_c "cat >/etc/yum.repos.d/onedata-${repo}.repo" <<EOF
[$reponame]
name=Onedata ${repo} Repository
baseurl=${yum_url}/${lsb_dist}/${dist_version}
enabled=0
gpgcheck=0
gpgkey=${yum_url}/gpg
EOF
            if [ "$lsb_dist" = "fedora" ] && [ "$dist_version" -ge "22" ]; then
                (
                    set -x
                    $sh_c "sleep 3; dnf -y -q install ${package}${yum_package_version}"
                )
            elif [ "$lsb_dist" = "photon" ]; then
                (
                    set -x
                    $sh_c "sleep 3; tdnf -y install ${package}${yum_package_version}"
                )
            else
                (
                    set -x
                    $sh_c "sleep 3; systemctl disable  onedatify.service"
                    $sh_c "sleep 3; yum remove -y -q ${package}"
                    $sh_c "sleep 3; yum -y -q  --disablerepo=* --enablerepo=$reponame install ${package}${yum_package_version}"
                )
            fi

            return 0
            ;;
    esac

    # intentionally mixed spaces and tabs here -- tabs are stripped by "<<-'EOF'", spaces are kept in the output
    cat >&2 <<EOF
Either your platform is not easily detectable, is not supported by this
installer script, or does not yet have a package for ${package}.
Currently supported distributions are: ubuntu wily, ubuntu xenial and fedora 23

For detailed instructions go to https://onedata.org/
EOF
    exit 1
}

usage() {
s=${0##*/}
margin=$(printf "%-${#s}s" " ")
#a=./abc.sh ; a="${a##*/}" ; echo "length=${#a}"
cat <<EOF
This script provides guided assitance to easely deploy the Oneprovider service.: 

${0##*/} -z <onezone url> -t <space support token> [ --interactive [ --install ] [--import ]]
${margin} [ --oneprovider-version <version> ] [ --oneprovider-version <version> ] [ --help ]

Options:
  -t, --interactive            enter interactive installation mod, where user is assked a series
                               of questions to properly configure the Oneprovider service
  -h, --help                   display this help and exit
  -t, --token                  space support token
  -z, --onezone-url            Onezone url
  -p, --oneprovider-version    Oneprovider docker image tag to be deployed on your system
  -i, --import                 when used with -e, includes option to import existing data into the space
  -o, --onedatify-version      Onedatify package version to be installed on your system
  -n, --install                autoamaticaly install Oneprovider using configuration present on the host
  
Examples:
TODO

EOF
exit 1
}

parse_arguments() {
    if [ $(( $# )) -eq 0 ]; then
        positional_usage
        exit 0
    fi

    onedatify_onezone_url=""
    onedatify_token=""
    onedatify_import=0
    onedatify_package_version="$DEFAULT_ONEDATIFY_PACKAGE_VERSION"
    onedatify_oneprovider_version="$DEFAULT_ONEPROVIDER_VERSION"

    while [ $(( $# )) -ne 0 ] ; do
        case $1 in
            -h|-\?|--help)   # Call a "usage" function to display a synopsis, then exit.
                positional_usage
                exit 0
                ;;
            -z|--onezone-url)
                onedatify_onezone_url="$2"
                shift
                ;;
            -t|--token)
                onedatify_token="$2"
                shift
                ;;
            -i|--import)
                onedatify_import=1
                ;;
            -o|--onedatify-version)
                onedatify_package_version="$2"
                shift
                ;;
            -p|--oneprovider-version)
                onedatify_oneprovider_version="$2"
                shift
                ;;
            # Bellow options are for forward compatibilith
            # with never Onedatify version
            -e|--interactive)
                ;;
            -n|--install)
                ;;
            -?*|*)
                printf 'WARN: Unknown option (ignored): %s\n' "$1" >&2
                exit 1
                ;;
        esac
        shift
    done

    if [ "$onedatify_onezone_url" = "" ]; then
        echo "Error: missing onezone url. Please see -h."
        exit 1
    else
        onedatify_onezone_url="${onedatify_onezone_url#*//}"
    fi
    if [ "$onedatify_token" = "" ] ; then
        echo "Error: missing space support token. Please see -h." 
        exit 1
    fi
}

main() {
    preflight_checks
    parse_arguments "$@"

    # check to see which repo they are trying to install from
    if [ -z "$repo" ]; then
        repo='main'
        repo_url="https://packages.onedata.org"
    elif [ "$repo" = "dev" ]; then
        repo_url="http://onedata-dev-packages.cloud.plgrid.pl"
        echo "Using $url"
    else
        echo "Repo \"$repo\" does not exist. Please use main or dev."
        exit 1
    fi

    do_install "onedatify" "$repo_url" "$onedatify_package_version"

    if command_exists onedatify ; then
        message "Package installation succesfull, you will now be asked to provide configuration parameters."
        message ""
        set -o xtrace
        $sh_c "onedatify '$onedatify_onezone_url' '$onedatify_token' '$onedatify_oneprovider_version' '$onedatify_import'"
    else
        message "'onedatify' is no avilable in your \$PATH installation must have failed."
    fi
}

# wrapped up in a function so that we have some protection against only getting
# half the file during "curl | sh"
main "$@"