#!/bin/sh

# This program is Copyright (c) 2013-2015 VividCortex, Inc. All rights reserved.

# This is a placeholder that is populated with the version of agents
# that the script is deployed with. It is here for information purposes only - DO NOT USE
VERSION=1.6.397

# Placeholder that is populated with the base URI for the download server - DO NOT USE
baseuri=https://download.vividcortex.com

# Override the baseuri when $VC_CUSTOM_URI var is set
if [ ! -z "$VC_CUSTOM_URI" ]; then baseuri=$VC_CUSTOM_URI; fi

globalconf=/etc/vividcortex/global.conf
confdir="$(dirname "$globalconf")"
logdir=/var/log/vividcortex
tempdir=""
socks5=""


msg()
{
	if [ $# -gt 0 ]; then
		echo "$1" >&2
	else
		echo >&2
	fi
}

abort()
{
	if [ $# -gt 0 ]; then
		msg
		msg "$1"
		msg
	fi
	[ -n "$tempdir" ] && rm -Rf "$tempdir" >/dev/null 2>&1
	exit 1
}

createdir()
{
	mkdir -p "$1" || abort "Unable to create directory $1"
}

getfile()
{
	failed=0
	if command -v curl >/dev/null 2>&1 ; then
		if [ -z "${socks5}" ]; then
			curl -f -s "$1" > "$2" && return 0
		else
			curl -f -s --socks5-hostname "${socks5}" "$1" > "$2" && return 0
			curl -f -s --socks5 "${socks5}" "$1" > "$2" && return 0
			curl -f -s -x "socks5://${socks5}" "$1" > "$2" && return 0
		fi
		failed=1
	fi
	if command -v wget >/dev/null 2>&1 ; then
		# depending on version, uses env vars
		wget -q -O - "$1" > "$2" && return 0
		failed=1
	fi
	if command -v fetch >/dev/null 2>&1 ; then
		# fetch uses env vars and does not support socks5
		fetch -q -o - "$1" > "$2" && return 0
		failed=1
	fi

	if [ $failed -eq 0 ]; then
		abort "No suitable tool for file download found"
	fi

	case "$initver" in
		FreeBSD)
			abort "Unable to retrieve $1
Please verify proxy/firewall and install or update CA Root Certificates - e.g. pkg install security/ca_root_nss"
			;;
		Redhat)
			abort "Unable to retrieve $1
Please verify proxy/firewall and install or update CA Root Certificates - e.g. yum update ca-certificates"
			;;
		Debian|OpenRC|systemd)
			if [ "${distro}" = "SuSE" ]; then
				abort "Unable to retrieve $1
Please verify proxy/firewall and install or update CA Root Certificates - e.g. zypper install ca-certificates ; update-ca-certificates"
			else
				abort "Unable to retrieve $1
Please verify proxy/firewall and install or update CA Root Certificates - e.g. update-ca-certificates"
			fi
			;;
		*)
			abort "Unable to retrieve $1
Please verify proxy/firewall and install or update CA Root Certificates."
			;;
	esac
}

usage()
{
	abort "Usage: install [-h|--help] [--autostart|--no-autostart] [-s|--start-now] [-t|--token API-token]
               [--no-proxy] [-p|--proxy HTTP-or-SOCKS5-proxy] [-v|--version version-number]"
}

set -u
POSIXLY_CORRECT=1
export POSIXLY_CORRECT

if [ $(id -u) -ne 0 ]; then
	abort "This script must be run as root"
fi

if [ "$(hostname)" = "" ]; then
	abort "VividCortex requires hostname to be set"
fi

test -d /usr || abort "/usr not mounted"

# Note that I am using the external getopt(1) here rather than the bash-
# internal getopts() because /bin/sh on some operating systems (e.g. FreeBSD)
# is not bash.
(getopt -T) >/dev/null 2>&1
exitcode=$?
if [ $exitcode -eq 4 ]; then
	# GNU version, supports long options
	GETARGS=$(getopt -o "hsp:t:v:" -l "help,autostart,no-autostart,start-now,no-proxy,proxy:,token:,version:" -n "$0" -- "$@")
	test $? -eq 0 || usage
	eval set -- "$GETARGS"
else
	# BSD, cannot validate
	eval set -- "$*"
fi

AUTOSTART=""
NOPROXY=""
PROXY=""
STARTNOW=""
VCTOKEN=""
INSTALL_VERSION=current

while [ $# -ne 0 ] ; do
	case "$1" in
		--autostart)
			shift
			AUTOSTART=1
			;;
		--no-autostart)
			shift
			AUTOSTART=0
			;;
		-s|--start-now)
			shift
			STARTNOW=1
			;;
		--no-proxy)
			shift
			NOPROXY=1
			PROXY=""
			;;
		-p|--proxy)
			shift
			if [ -n "$1" ]; then
				PROXY="$1"
				NOPROXY=""
				shift
			fi
			# Undocumented, but worth honoring anyway just to be neighborly.
			if [ "$PROXY" = "no" -o "$PROXY" = "none" -o "$PROXY" = "false" -o "$PROXY" = "off" ]; then
				PROXY=""
				NOPROXY=1
			fi
			;;
		-t|--token)
			shift
			if [ -n "$1" ]; then
				VCTOKEN="$1"
				shift
			fi
			;;
		-v|--version)
			shift
			if [ -n "$1" ]; then
				INSTALL_VERSION="$1"
				shift
			fi
			;;
		-h|--help)
			shift
			echo
			echo "Usage: install [-h|--help] [--autostart|--no-autostart] [-s|--start-now] [-t|--token API-token]"
			echo "               [--no-proxy] [-p|--proxy HTTP-or-SOCKS5-proxy] [-v|--version version-number]"
			echo
			echo "Where:"
			echo
			echo "--help [-h]                Display this help information"
			echo "--autostart                Configure system to start VividCortex at boot"
			echo "--no-autostart             Do not configure system to start VividCortex at boot"
			echo "--start-now [-s]           Start VividCortex services after installation"
			echo "--token [-t] 'API-token'   Configure VividCortex token to 'API-token'"
			echo "--no-proxy                 Do not configure an HTTP proxy"
			echo "--proxy [-p] 'proxy-URI'   Configure http/https or socks5 proxy to 'proxy-URI'"
			echo "--version [-t] 'Version'   Install the specified version of VividCortex (installs latest if not specified)"
			echo
			echo "For some configuration parameters, if no option is specified, 'install' will"
			echo "fall back to interactive querying to obtain the parameters."
			echo
			exit 0
			;;
		--)
			shift
			break
			;;
		*)
			shift
			usage
			;;
	esac
done

platform=$(uname -s | tr A-Z a-z)
distro=""
arch=""
initver=""
initdir=""
initname="vividcortex"
initperm=755
startcmd=""
stopcmd=""
installcmd=""
uninstallcmd="true"

longbit=$(getconf LONG_BIT 2>/dev/null)
if [ -z "$longbit" ]; then
	if /usr/bin/file /bin/cat | grep 64.bit >/dev/null 2>&1 ; then
		longbit=64
	fi
fi

case "$longbit" in
	64)
		arch="amd64"
		;;
	*)
		arch="386"
		abort "VividCortex isn't supported on 32-bit systems"
		;;
esac

# aborts or sets (distro) or (distro,initdir,initver)
case "${platform}" in
	linux)
		initdir="/etc/init.d"

		if grep -i ubuntu /etc/*-release >/dev/null 2>&1 ; then
			distro="Ubuntu"
			initver="Debian"
		elif grep -i debian /etc/*-release >/dev/null 2>&1 ; then
			distro="Debian"
			initver="Debian"
		elif grep -i amazon /etc/*-release >/dev/null 2>&1 ; then
			distro="Amazon"
			initver="Redhat"
		elif grep -i centos /etc/*-release >/dev/null 2>&1 ; then
			distro="CentOS"
			initver="Redhat"
		elif grep -i red.hat.enterprise /etc/*-release >/dev/null 2>&1 ; then
			distro="RHEL"
			initver="Redhat"
		elif grep -i fedora /etc/*-release >/dev/null 2>&1 ; then
			distro="Fedora"
			initver="Redhat"
		elif [ -e /etc/redhat-release ]; then
			distro="Redhat"
			initver="Redhat"
		elif [ -e /etc/debian_version ]; then
			distro="Debian"
			initver="Debian"
		elif [ -e /etc/gentoo-release ]; then
			distro="Gentoo"
			initver="OpenRC"
		elif [ -e /etc/SuSE-release ]; then
			distro="SuSE"
			initver="Debian"
		else
			abort "Could not determine Linux distribution.
Please contact VividCortex for installation support."
		fi
		;;
	freebsd)
		initdir="/etc/rc.d"
		distro="FreeBSD"
		initver="FreeBSD"
		;;
	darwin)
		distro="Darwin"
		initver="launchd"
		initdir="/Library/LaunchDaemons"
		initname="com.vividcortex.supervisor.plist"
		;;
	*)
		abort "Sorry, this install script doesn't support the '${platform}' platform.
Please contact VividCortex for installation support."
		;;
esac

# verify initver dependencies and set startcmd/stopcmd/installcmd
case "${initver}" in
	Redhat)
		startcmd="${initdir}/vividcortex start"
		stopcmd="${initdir}/vividcortex stop"
		installcmd="/sbin/chkconfig --add vividcortex"
		uninstallcmd="/sbin/chkconfig --del vividcortex"
		command -v /sbin/chkconfig >/dev/null 2>&1 || initver=""
		;;
	Debian)
		if systemctl >/dev/null 2>&1; then
			startcmd="systemctl start vividcortex.service"
			stopcmd="systemctl stop vividcortex.service"
			installcmd="systemd_install"
			initdir="/etc/systemd/system"
			initname="vividcortex.service"
			initperm=644
			initver="systemd"
		elif command -v update-rc.d >/dev/null 2>&1; then
			startcmd="${initdir}/vividcortex start"
			stopcmd="${initdir}/vividcortex stop"
			installcmd="update-rc.d vividcortex defaults"
		elif command -v /sbin/chkconfig >/dev/null 2>&1; then
			startcmd="${initdir}/vividcortex start"
			stopcmd="${initdir}/vividcortex stop"
			installcmd="/sbin/chkconfig --add vividcortex"
			uninstallcmd="/sbin/chkconfig --del vividcortex"
		else
			initver=""
		fi
		;;
	OpenRC)
		startcmd="rc-service vividcortex start"
		stopcmd="rc-service vividcortex stop"
		installcmd="rc-update add vividcortex"
		command -v rc-update >/dev/null 2>&1 || initver=""
		command -v rc-service >/dev/null 2>&1 || initver=""
		;;
	systemd)
		startcmd="systemctl start vividcortex.service"
		stopcmd="systemctl stop vividcortex.service"
		installcmd="systemd_install"
		initperm=644
		command -v systemctl >/dev/null 2>&1 || initver=""
		;;
	launchd)
		startcmd="launchctl start com.vividcortex.supervisor"
		stopcmd="launchctl stop com.vividcortex.supervisor"
		installcmd="launchctl load -w ${initdir}/${initname}"
		uninstallcmd="launchctl unload -w ${initdir}/${initname}"
		command -v launchctl >/dev/null 2>&1 || initver=""
		# to-do
		if [ "${AUTOSTART}" = "0" ]; then
			abort "Not-autostarting unsupported"
		fi
		AUTOSTART="1"
		;;
	FreeBSD)
		startcmd="${initdir}/vividcortex start"
		stopcmd="${initdir}/vividcortex stop"
		installcmd="true"
		if [ "${AUTOSTART}" = "0" ]; then
			abort "Not-autostarting unsupported"
		fi
		AUTOSTART="1"
		;;
	*)
		initver=""
		;;
esac

systemd_install () {
	systemctl daemon-reload
	systemctl enable vividcortex.service
}


if [ "${initver}" = "" -o "${initdir}" = "" -o ! -d "${initdir}" ]; then
	abort "Sorry, this install script does not yet support your version or flavor of ${distro}.

Additional information: `uname -a`

Please contact VividCortex for installation support."
fi


if [ -e "$globalconf" ]; then
	abort "$globalconf exists; stopping.
Remove and re-run if you want to replace an existing install."
fi

# agents are installed in /usr/local/bin; make sure it exists
if [ ! -d /usr/local/bin ]; then
	if [ ! -d /usr/local ]; then
		mkdir /usr/local >/dev/null 2>&1
		chmod 755 /usr/local >/dev/null 2>&1
	fi
	mkdir /usr/local/bin >/dev/null 2>&1
	chmod 755 /usr/local/bin >/dev/null 2>&1
	test -d /usr/local/bin || abort "Cannot create /usr/local/bin"
fi

# customer consented a reinstall by removing globalconf; make sure service isn't running
if [ -e "${initdir}/${initname}" ]; then
	${stopcmd} >/dev/null 2>&1
	${uninstallcmd} >/dev/null 2>&1
fi

# remove service file
rm -f "${initdir}/${initname}"

if [ -z "${VCTOKEN}" ]; then
	echo
	echo -n "Please enter your VividCortex API token: "

	if ! read VCTOKEN; then
		abort "Unable to read API token."
	fi

	if [ -z "$VCTOKEN" ]; then
		abort "A token has to be provided."
	fi
fi

echo
echo "Installing the VividCortex vc-agent-007 agent for ${platform} ${distro} ${arch}."

if [ -n "${NOPROXY}" ]; then
	proxy=""
elif [ -n "${PROXY}" ]; then
	proxy="${PROXY}"
else
	proxy=""
	resp=""
	echo
	echo -n "Do you need to set up a proxy? [y/N] "
	if read resp && [ "$resp" = 'Y' -o "$resp" = 'y' ]; then
		# try to get a default from env, just for display purposes
		proxy=${https_proxy:-''}
		test ! -z "${proxy}" && echo "${proxy}" | grep -v '://' >/dev/null 2>&1 && proxy="https://${proxy}"
		echo "${proxy}" | grep '^http' >/dev/null 2>&1 || proxy=${http_proxy:-''}
		test ! -z "${proxy}" && echo "${proxy}" | grep -v '://' >/dev/null 2>&1 && proxy="http://${proxy}"
		echo "${proxy}" | grep '^http' >/dev/null 2>&1 || proxy=${HTTP_PROXY:-''}
		test ! -z "${proxy}" && echo "${proxy}" | grep -v '://' >/dev/null 2>&1 && proxy="http://${proxy}"
		echo "${proxy}" | grep '^http' >/dev/null 2>&1 || proxy=""
		if [ -z "${proxy}" ]; then
			proxy=${SOCKS_SERVER:-''}
			test ! -z "${proxy}" && echo "${proxy}" | grep -v '://' >/dev/null 2>&1 && proxy="socks5://${proxy}"
			echo "${proxy}" | grep '^socks' >/dev/null 2>&1 || proxy=""
		fi
		if [ ! -z "${proxy}" ]; then
			echo
			echo "Environment vars suggest this may be a valid proxy: ${proxy}"
			proxy=""
		fi

		echo
		echo -n "Please input your proxy URI: "
		read proxy
		test -z "${proxy}" && proxy="x" # fail
	fi
fi

if [ -n "${proxy}" ]; then
	if ! echo $proxy | grep "^\(socks5\|https\|http\)://" >/dev/null 2>&1 ; then
		abort "proxy URI must begin with 'https://', 'http://' or 'socks5://'.  E.g.: socks5://user:pass@127.0.0.1:1080"
	fi
fi

export http_proxy=""
export HTTP_PROXY=""
export https_proxy=""
export SOCKS_SERVER=""
export SOCKS_VERSION=""
if [ -n "${proxy}" ]; then
	if echo $proxy | grep "^socks5://" >/dev/null 2>&1 ; then
		# socks5 proxy
		socks5=`echo ${proxy} | sed 's/socks5:\/\///'`
		export SOCKS_SERVER="${socks5}"
		export SOCKS_VERSION=5
	else
		# http/https proxy
		export http_proxy=$proxy
		export HTTP_PROXY=$proxy
		export https_proxy=$proxy
	fi
	echo
	echo "Using proxy: ${proxy}"
fi

# Download to temp folder in case we need to abort
tempdir=$(mktemp -d /tmp/vividcortex.XXXX)

if [ $? -ne 0 ]; then
	abort "Unable to create temp folder under /tmp"
fi

if [ $INSTALL_VERSION != "current" ]; then
	echo
	echo "Installing VividCortex version: $INSTALL_VERSION"
fi

getfile "$baseuri/$platform/$arch/$INSTALL_VERSION/vc-agent-007" "$tempdir/vc-agent-007"
getfile "$baseuri/$platform/init-scripts/$initver/$INSTALL_VERSION/vividcortex" "$tempdir/vividcortex"

mv -f $tempdir/vc-agent-007 /usr/local/bin/ || abort "Unable to install vc-agent-007"
chmod 700 /usr/local/bin/vc-agent-007 || abort "Unable to set /usr/local/bin/vc-agent-007 permissions"

# Verify that env looks good to 007

{ /usr/local/bin/vc-agent-007 -self-test -proxy-uri="${proxy}" -config-file="" -api-token="${VCTOKEN}"; } >/dev/null 2>&1
exitcode=$?
# 0 exitSuccess, 2 exitBadOptions (pre-1.6.143 vc-agent-007 doesn't support -self-test)
if [ $exitcode -ne 0 -a $exitcode -ne 2 ]; then
	rm -f /usr/local/bin/vc-agent-007
	if   [ $exitcode -eq 3 ]; then  # exitNoToken
		abort "The API token you used, ${VCTOKEN}, is not valid, please verify and retry installation"
	elif [ $exitcode -eq 4 ]; then  # exitBadProxy
		abort "Cannot use proxy [ ${proxy} ], please verify and retry installation"
	elif [ $exitcode -eq 7 ]; then  # exitCantReachAPI
		if [ "${platform}" = "freebsd" -a ! -f /usr/local/share/certs/ca-root-nss.crt ]; then
			abort "Cannot reach VividCortex, please verify that proxy/firewall allows outgoing https (port 443) to app.vividcortex.com, CA root certificates present (pkg install security/ca_root_nss), and retry installation"
		elif [ "${distro}" = "SuSE" ]; then
			abort "Cannot reach VividCortex, please verify that proxy/firewall allows outgoing https (port 443) to app.vividcortex.com, and retry installation.
You may need to install or update CA Root Certificates - e.g. zypper install ca-certificates ; update-ca-certificates"
		else
			abort "Cannot reach VividCortex, please verify that proxy/firewall allows outgoing https (port 443) to app.vividcortex.com, and retry installation"
		fi
	elif [ $exitcode -eq 8 -o $exitcode -ge 128 ]; then # exitUnsupported or segfault
		abort "OS version probably unsupported, please contact VividCortex.
Additional information: ${distro}/${arch} (exitcode=${exitcode}) `uname -a`"
	else
		abort "Installation failed. Please retry and, if the problem persists, contact VividCortex.
Additional information: ${distro}/${arch} (exitcode=${exitcode}) `uname -a`"
	fi
fi

mv -f "${tempdir}/vividcortex" "${initdir}/${initname}" || abort "Unable to install vividcortex init script"
chmod ${initperm} "${initdir}/${initname}" || abort "Unable to set ${initdir}/${initname} permissions"

rm -Rf $tempdir >/dev/null 2>&1
tempdir=""

createdir "$confdir"
createdir "$logdir"

cat - > "$globalconf" <<EOF
{

    "api-token": "$VCTOKEN",
    "proxy-uri": "$proxy"
}
EOF

chmod 600 "$globalconf"

[ $? -eq 0 ] || abort "Unable to create $globalconf"

echo
echo "VividCortex agents successfully installed"
echo

resp=""
if [ -z "$AUTOSTART" ]; then
	echo -n "Would you like to schedule automatic service startup? [Y/n] "
	read resp
	echo
fi

if [ "$resp" = 'Y' -o "$resp" = 'y' -o "$AUTOSTART" = "1" ]; then
	if [ "${installcmd}" = "" ]; then
		msg "Sorry, don't know how to enable init scripts for '${initver}'."
		msg "Please enable the 'vividcortex' init script manually."
		msg "Please also tell VividCortex how to improve this script to do that."
		abort ""
	else
		${installcmd} >/dev/null 2>&1 || abort "Unable to install init script using '${installcmd}'"
	fi
	echo "VividCortex init script scheduled for automatic start/stop"
else
	echo "VividCortex init script *NOT* scheduled for automatic start/stop"
fi

echo

if [ "$STARTNOW" = 1 ]; then
	echo "Starting VividCortex service"
	${startcmd} >/dev/null 2>&1

	if [ $? -ne 0 ]; then
		msg
		msg "VividCortex service startup may have failed."
		msg "Please inspect '$logdir/vc-agent-007.log' for details."
		msg
		msg "VividCortex service can be started by running:"
		msg
		msg "    ${startcmd}"
	fi
else
	echo "VividCortex service can be started by running:"
	echo
	echo "    ${startcmd}"
fi

echo
echo "Installation is done; please check the VividCortex app to see the new host"
echo
exit 0
