#!/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="18.02.0.rc13"
DEFAULT_ONEPROVIDER_VERSION="onedata/oneprovider:18.02.0-rc13"

#######################################
# 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 an existing data space.

This script will perform following changes on this machine:
- install the latest versions of Docker and Docker Compose
- change machine 'ulimit' to the value found in /proc/sys/fs/file-max
- disable swappiness and Transparent Huge Pages feature
- open all ports required by Oneprovider

Oneprovider requirers valid SSL certificates
to register with Onezone, you can provide your own certificates
or Onedatify script will help you generate Let's Encrypt certificates.

In order to install Onedatify service prepare the following items:
- a fully qualified domain name (FQDN) of this machine
- an operating system that supports systemd
- the following ports need to be open:

    80/TCP      HTTP
    443/TCP     HTTPS
    6665/TCP    Onedata data transfer channel (RTransfer)
    9443/TCP    Onepanel web interface - needed only for system administrators

If you want to expose existing data via Onedata,
the storage with the data must be accessible for this machine
through a POSIX path (e.g. NFS mountpoint).

If you expect this provider to transfer data to other providers,
make sure that this VM has a direct connection (public IP or dedicated routing),
to other providers you want to transfer data to.

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."
        path_to_docker_compose=$(command -v docker-compose)
        if [ "$path_to_docker_compose" != "/usr/local/bin/docker-compose" ] ; then
            message "Linking existing docker compose at $path_to_docker_compose to /usr/local/bin/docker-compose"
            $sh_c "ln -s $path_to_docker_compose /usr/local/bin/docker-compose"
        fi
    fi

    message "Installing onedatify package:"
    # # Temorary hack
    if command_exists apt; then
        if dpkg-query -W "$package" 2>/dev/null 2>&1; then
            $sh_c "apt remove -y $package"
        fi
        deb_package_name="onedatify_${onedatify_package_version}.systemd_amd64.deb"
        deb_file_name=$(mktemp /tmp/${deb_package_name%.deb}.XXXXXXX.deb)
        $sh_c "curl --show-error https://packages.onedata.org/$deb_package_name > $deb_file_name"
        $sh_c "dpkg -i $deb_file_name"
        $sh_c "apt-mark hold $package"
    else
        if yum list installed "$package" 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"
        rpm_file_name=$(mktemp /tmp/${rpm_package_name%.rpm}.XXXXXXX.rpm)
        $sh_c "curl --show-error --silent https://packages.onedata.org/$rpm_package_name > $rpm_file_name"
        $sh_c "yum localinstall -y $rpm_file_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
            # Open ports on Centos and others
            $sh_c "firewall-cmd --zone=public --add-port=80/tcp --permanent"
            $sh_c "firewall-cmd --zone=public --add-port=443/tcp --permanent"
            $sh_c "firewall-cmd --zone=public --add-port=6665/tcp --permanent"
            $sh_c "firewall-cmd --zone=public --add-port=9443/tcp --permanent"

            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
}

positional_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_positional() {

    admin_password=""

    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"
    onedatify_interactive=0
    onedatify_install=0

    while [ $(( $# )) -ne 0 ] ; do
        case $1 in
            -h|-\?|--help)   # Call a "usage" function to display a synopsis, then exit.
                positional_usage
                exit 0
                ;;
            -e|--interactive)
                onedatify_interactive=1
                ;;
            -n|--install)
                onedatify_install=1
                ;;
            -t|--token)
                onedatify_token="$2"
                shift
                ;;
            -z|--onezone-url)
                onedatify_onezone_url=$2
                shift
                ;;
            -p|--oneprovider-version)
                onedatify_oneprovider_version="$2"
                shift
                ;;
            -i|--import)
                onedatify_import=1
                ;;
            -o|--onedatify-version)
                onedatify_package_version="$2"
                shift
                ;;
            -?*|*)
                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_positional "$@"

    # 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
        echo ""
        message "########################################"
        message "Package installation succesfull."
        message "$DEFAULT_ONEPROVIDER_VERSION"

        if [ "$onedatify_interactive" = 1 ]; then
            onedatify config set zone_fqdn="$onedatify_onezone_url"
            onedatify config set -t zone_fqdn="$onedatify_onezone_url"
            onedatify config set version="$onedatify_oneprovider_version"
            onedatify config set -t version="$onedatify_oneprovider_version"
            exit_code=$? ; [ $exit_code -ne 0 ] && exit $exit_code
            
            onedatify config interactive -e onezone_fqdn
            exit_code=$? ; [ $exit_code -ne 0 ] && echo "Configuration exited with code: $exit_code" && exit $exit_code
            
            if [ "$onedatify_install" = 1 ]; then
                onedatify install interactive -p orzechpass
                exit_code=$? ; [ $exit_code -ne 0 ] && echo "Installation exited with code: $exit_code" && exit $exit_code

                if [ "$onedatify_import" = 1 ]; then
                    onedatify storage interactive-import
                else
                    onedatify storage interactive
                fi
                exit_code=$? ; [ $exit_code -ne 0 ] && echo "Storage support exited with code: $exit_code" && exit $exit_code

                detected_storage_size=""
                # check if storage added was posix
                if onedatify storage get -s name=onedatify | grep --quiet '"type": "posix"' ; then
                    posix_storage_path=$(onedatify storage get -s name=onedatify | grep mountPoint | cut -d ':' -f '2' | sed 's/^ "\(.*\)",$/\1/')
                    posix_storage_size=$($sh_c "docker exec onedatify-oneprovider-1 df -k --output=size \"$posix_storage_path\" | tail -n+2 | tr -d ' '")
                    detected_storage_size="${posix_storage_size}KiB"
                fi
                
                if [ "$detected_storage_size" != "" ] ; then
                    storage_support_size=$detected_storage_size
                else
                    storage_support_size=1073741824 # 1GiB
                fi
                
                if [ "$onedatify_import" = 1 ]; then
                    onedatify support interactive --token "$onedatify_token" \
                                                  --size "$storage_support_size" \
                                                  --storage-id 1 \
                                                  --mount-in-root \
                                                  --import \
                                                  --update
                else
                    onedatify support interactive --token "$onedatify_token" \
                                                  --size "$storage_support_size" \
                                                  --storage-id 1
                fi
            else
              message ""
              message "Please use:"
              message "  onedatify install -p <your password>"
              message "to continue installing Oneprovider."
              message ""
              message "For more examples on setting up Oneprovider please see:"
              message "  onedatify --help"
            fi
            # onedatify support posix --path /tmp --import
        else
            message ""
            message "Use commands:"
            message "  onedatify config interactive"
            message "  onedatify install -p <your password>"
            message "to configure and install your Oneprovider service."
            message ""
            message "For more examples on setting up Oneprovider please see:"
            message "  onedatify --help"
        fi
    else
        echo ""
        message "'onedatify' is no avilable in your \$PATH installation must have failed."
    fi
}
# parse_command_line_options
# wrapped up in a function so that we have some protection against only getting
# half the file during "curl | sh"
main "$@"
