#! /bin/sh

# This script builds and installs Plasma via GODI, i.e. the latest
# version that is available in GODI. A few important remarks:
#
# - You can run the script in three modes:
#     -build: Builds the software (default)
#     -namenode: Prepares the namenode
#     -datanode: Prepares the datanode
#   The build is done on the build host (which can be a distinct
#   node but also one of the namenodes or datanodes).
# - If a node has several roles, you should run the script several
#   times, e.g. once with -namenode and once with -datanode.
# - Build mode:
#   The script creates a directory /opt/plasma and installs GODI
#   there. It is not possible to use an existing GODI. It is also
#   not possible to use another existing Ocaml installation (like
#   the one coming with the OS distribution). There is no need
#   to deinstall these - just put /opt/plasma/bin before them in
#   PATH.
# - All modes:
#   The script installs missing system packages. So far this works
#   only for a few Linux distributions. Users of other OS are on
#   their own here. (Tested distros: Debian, Ubuntu, Fedora, Opensuse.
#   Please avoid Fedora 13 for now.)
# - All modes:
#   The script needs to run a few commands as root. It knows several
#   methods of becoming root (su, sudo, ssh root@localhost). You can
#   select the right one on the command line. Do not start the script
#   as root. You should start it as the "file owner" of the installation.
#   In doubt, just create a new user "plasma" for it.
# - On namenodes the script also installs PostgreSQL, and configures
#   it. Again, this only works for the few known Linux distros.
# - Once you have built the software and prepared all namenodes and
#   datanodes, look into the manual ($root/doc/godi-plasma) for
#   how to go on. There is a chapter about deploying Plasma.
#
# DO NOT RUN THIS SCRIPT AS ROOT!

set -e

usage() {
  cat <<EOF
usage: $0 [options]...

List of options:
 -root <path>              Install into this path (default: /opt/plasma)
 -os (debian|redhat|suse)  Assume this OS (default: auto-detected)
 -su                       Use "su" to become root
 -sudo                     Use "sudo" to become root
 -ssh                      Use "ssh root@localhost" to become root
 -noroot                   Skip root stuff
 -namenode                 Only install packages for namenode
 -datanode                 Only install packages for datanode
 -build                    Build
EOF
}

uid=`id -u` 
if [ $uid = 0 ]; then
    echo "This script cannot be run as root."
fi

root=/opt/plasma
os=""
rootmeth=""
mode=build

while [ $# -gt 0 ]; do
  case "$1" in
      -root)
	  root="$2"; shift 2;;
      -os)
	  os="$2"; shift 2;;
      -su)
	  rootmeth="su"; shift ;;
      -sudo)
	  rootmeth="sudo"; shift ;;
      -ssh)
	  rootmeth="ssh"; shift ;;
      -noroot)
	  rootmeth="none"; shift ;;
      -namenode)
	  mode="namenode"; shift ;;
      -datanode)
	  mode="datanode"; shift ;;
      -build)
	  mode="build"; shift ;;
      *)
	  usage >&2; exit 2 ;;
  esac
done

######################################################################
# Auto-detect OS
######################################################################

if [ -f /etc/debian_version ]; then
    os="debian"
    if [ -f /etc/apt/sources.list ]; then
	if grep /ubuntu /etc/apt/sources.list >/dev/null; then
	    if [ -z "$rootmeth" ]; then
		rootmeth=sudo
	    fi
	fi
    fi
elif [ -f /etc/redhat-release ]; then
    os="redhat"
elif [ -f /etc/SuSE-release ]; then
    os="suse"
fi

if [ -z "$rootmeth" ]; then
    rootmeth=su
fi

######################################################################
# Packages to install
######################################################################

debian_build_pkgs="build-essential wget gzip bzip2 patch m4 libpq-dev \
                   libpcre3-dev zlib1g-dev"
debian_namenode_pkgs="libpq5 libpcre3 zlib1g postgresql"
debian_datanode_pkgs="libpq5 libpcre3 zlib1g"

redhat_build_pkgs="gcc wget gzip bzip2 patch m4 pcre make postgresql \
                   pcre-devel postgresql-devel zlib-devel"
redhat_namenode_pkgs="pcre zlib postgresql postgresql-server"
redhat_datanode_pkgs="pcre zlib postgresql"

suse_build_pkgs="gcc wget gzip bzip2 patch m4 pcre make postgresql \
                 pcre-devel postgresql-devel zlib-devel"
suse_namenode_pkgs="pcre zlib postgresql postgresql-server"
suse_datanode_pkgs="pcre zlib postgresql"

pkgs=""
case "$os,$mode" in
    debian,build)
	pkgs="$debian_build_pkgs" ;;
    debian,namenode)
	pkgs="$debian_namenode_pkgs" ;;
    debian,datanode)
	pkgs="$debian_datanode_pkgs" ;;
    redhat,build)
	pkgs="$redhat_build_pkgs" ;;
    redhat,namenode)
	pkgs="$redhat_namenode_pkgs" ;;
    redhat,datanode)
	pkgs="$redhat_datanode_pkgs" ;;
    suse,build)
	pkgs="$suse_build_pkgs" ;;
    suse,namenode)
	pkgs="$suse_namenode_pkgs" ;;
    suse,datanode)
	pkgs="$suse_datanode_pkgs" ;;
esac

pscript=""
pmsg=""
case "$os" in
    debian)
	pscript="apt-get install $pkgs"
	pmsg="installing packages" ;;
    redhat)
	pscript="yum install $pkgs"
	pmsg="installing packages" ;;
    suse)
	pscript="zypper install $pkgs"
	pmsg="installing packages" ;;
    *)
	echo "OS not recognized - not installing packages" ;;
esac

######################################################################
# Prepare root dir
######################################################################

thisuser=`id -u`
thisgroup=`id -g`
rscript=""
rmsg=""
if [ $mode = "build" ]; then
    rscript="mkdir -p '$root'; chown $thisuser:$thisgroup '$root'"
    rmsg="preparing $root"
fi

######################################################################
# Do stuff as root
######################################################################

if [ -n "$pscript" -o -n "$rscript" ]; then
    script="${pscript:-true}; ${rscript:-true}"

    if [ -n "$pmsg" -a -n "$rmsg" ]; then
	msg="$pmsg, $rmsg"
    else
	msg="$pmsg$rmsg"
    fi

    if [ "$rootmeth" != none ]; then
	echo "*******************************************************************"
	echo "* Doing as root: $msg"
	echo "*******************************************************************"
	echo "Method to become root: $rootmeth"
	echo "  (if this does not work for you, restart the script with the"
	echo "   right option: -su, -sudo, or -ssh)"
    fi

    case "$rootmeth" in
	su)
	    su -c "$script" ;;
	sudo)
	    sudo sh -c "$script" ;;
	ssh)
	    ssh root@localhost "$script" ;;
	none)
	    true ;;
    esac
fi

######################################################################
# Check PostgreSQL
######################################################################

pgscript=""
if [ $mode = namenode ]; then
    # Some OS initialize PG automatically at package install time,
    # some don't. Also, we have to set the max_prepared_transactions
    # parameter to at least 1 (we use 5 here to have some room).

    pgversion="$(psql --version | head -1 | sed -e 's/psql (PostgreSQL) //')"
    # something like 8.4.4. This is the version we are building for (some
    # OS allow it to have several PG versions in parallel).

    pgversion2="$(echo "$pgversion" | sed -e 's/^\([0-9]\+\.[0-9]\+\).*$/\1/')"
    # something like 8.4
    
    pgdir=""
    pgname="postgresql"
    pginit=""
    case "$os" in
	debian)
	    pgname="postgresql-$pgversion2"
	    pgdir="/etc/postgresql/$pgversion2/main"
	    pginit="pg_createcluster $pgversion2 main"
	    ;;
	redhat)
	    pgdir="/var/lib/pgsql/data" 
	    pginit="/sbin/service postgresql initdb"
	    ;;
	suse)
	    pgdir="/var/lib/pgsql/data"
	    pginit="/sbin/service postgresql start"
                # suse initializes on first start automatically
	    ;;
    esac

    # How to start/stop services:
    pgstart="/etc/init.d/$pgname start"
    pgstop="/etc/init.d/$pgname stop"
    if [ -x /sbin/service ]; then
	pgstart="/sbin/service $pgname start"
	pgstop="/sbin/service $pgname stop"
    fi

    user="$(id -un)"
    
    # The script to run as root:
    pgscript1="pgdir='$pgdir'; user='$user'"
    pgscript2="pgstart='$pgstart'; pgstop='$pgstop'; pginit='$pginit'"
    pgscript3=$(cat <<'EOF'
PATH=/sbin:/usr/sbin:$PATH
export PATH
if [ ! -f "$pgdir/postgresql.conf" ]; then
    echo "postgresql.conf not found. Need to initialize PostgreSQL first."
    $pginit
    if [ ! -f "$pgdir/postgresql.conf" ]; then
        echo "FAILURE"
        exit 1
    fi
fi
max_prepared_transactions=0
mptline="$(grep '^max_prepared_transactions' "$pgdir/postgresql.conf")"
if [ -n "$mptline" ]; then
    max_prepared_transactions="$(echo "$mptline" | sed -e 's/^max_prepared_transactions[ \t]*=[ \t]*\([0-9]\+\).*$/\1/')"
fi
if [ $max_prepared_transactions -lt 5 ]; then
    echo "PostgreSQL parameter max_prepared_transactions is too low."
    echo "Changing postgresql.conf"
    if [ -n "$mptline" ]; then
        f=/tmp/plasmainstall.$$
        sed -e 's/^max_prepared_transactions[ \t]*=[ \t]*[0-9]\+\(.*\)$/max_prepared_transactions = 5\1/' "$pgdir/postgresql.conf" >$f
        cp $f "$pgdir/postgresql.conf"
        rm -f $f
    else
        echo "max_prepared_transactions = 5" >>"$pgdir/postgresql.conf"
    fi
    $pgstop
fi
$pgstart
su postgres -c "createuser -S -d -R '$user'"
EOF
)
    pgscript="$pgscript1; $pgscript2; $pgscript3"
fi

######################################################################
# Do stuff as root
######################################################################

if [ -n "$pgscript" ]; then
    if [ "$rootmeth" != none ]; then
	echo "*******************************************************************"
	echo "* Doing as root: checking, reconfiguring, starting PostgreSQL"
	echo "*******************************************************************"
	echo "Method to become root: $rootmeth"
	echo "  (if this does not work for you, restart the script with the"
	echo "   right option: -su, -sudo, or -ssh)"
    fi

    case "$rootmeth" in
	su)
	    su -c "$pgscript" ;;
	sudo)
	    sudo sh -c "$pgscript" ;;
	ssh)
	    ssh root@localhost "$pgscript" ;;
	none)
	    true ;;
    esac
fi

######################################################################


if [ "$mode" != "build" ]; then
    echo "*******************************************************************"
    echo "* Done with system preparation."
    echo "*******************************************************************"
    exit 0
fi

######################################################################
# Install GODI
######################################################################

tmpdir="/tmp/plasmainstall.$$"

echo "*******************************************************************"
echo "* Using $tmpdir for bootstrapping GODI"
echo "*******************************************************************"

gv="godi-rocketboost-20091222"

mkdir $tmpdir
cd $tmpdir
wget http://download.camlcity.org/download/$gv.tar.gz
tar xzf $gv.tar.gz
cd ./$gv

echo | ./bootstrap --prefix "$root/." --section 3.12

PATH="$root/bin:$root/sbin:$PATH"
export PATH

./bootstrap_stage2

cd $HOME
rm -rf "$tmpdir"

######################################################################
# Install Plasma
######################################################################

echo "*******************************************************************"
echo "* Installing Plasma"
echo "*******************************************************************"

#echo "GODI_BUILD_SITES+=http://www.ocaml-programming.de/godi-build/ocamlnet3/" >>"$root/etc/godi.conf"
echo "GODI_OCAMLGRAPH_VIEWER=no" >>"$root/etc/godi.conf"

godi_console update
godi_console perform -build godi-ocamlnet
godi_console perform -build godi-plasma

echo "*******************************************************************"
echo "* Done with Plasma build"
echo "* Plasma root: $root"
echo "*******************************************************************"

