#!/bin/bash

yum_conf=/etc/yum.conf.ensim
email=""

version=4.0.1
release=9
yumv1=yum-1.0.3-1_73.noarch.rpm
yumv2=yum-2.0.6-1.noarch.rpm
install_log=/tmp/install.log.$$
ensim_install_log=/var/log/ensim/installer.log
# By default, we claim failure
gstatus=1
gabort=0
# One level of indirection so that we can still
# remember the default values, even if the user
# overrides them.
ensim_ftp_user=ensimwpl
ftp_user=$ensim_ftp_user
ensim_ftp_pass=ensim94089
ftp_pass=$ensim_ftp_pass
ensim_ftp_server=ftp2.ensim.com
ftp_server=$ensim_ftp_server

# Other user settings
ensim_source=
os_source=
updates_source=
other_source=
exclude_rpms=
install=1
cdrom=0
cdrom_default=${cdrom/0/no}
cdrom_default=${cdrom_default/1/yes}
assume_yes=0
skip_checker=0
# rpm -Uvh *.rpm installs/updates in correct
# dependacy order so use rpm.
use_rpm=1

usage()
{
    exit_code=$1
    rebuke=$2

    cat <<EOF
    $rebuke
    This is the Ensim Control Panel Installer. Available options are (default
    values, if available, appear in []s):

    -a <yum baseurl> | --additional-rpms=<yum baseurl>:
        A yum-style baseurl pointing to a yum repository for additional rpms
        that should be considered during the install/upgrade. To create a yum
        repository on the local filesystem, you can do the following:
        - copy the rpms you want considered into a directory (e.g. /tmp/rpms)
        - cd into that directory (e.g. /tmp/rpms) and run yum-arch .
        - use the argument -a file:////path/to/repository (e.g. -a file:////tmp/rpms)
    -c <y|yes|n|no> | --cdrom=<y|yes|n|no>: 
        If 'y' or 'yes', the Ensim Control Panel rpms will be searched for on 
	the cdrom. [$cdrom_default]
    -e <email> | --email=<email>: 
        Address to which any logs from the installation should be sent to.
    -E <yum baseurl> | --ensim-source=<yum baseurl>: 
        A yum-style baseurl pointing to a yum repository for the Ensim 
        Control Panel rpms. [ftp://${ftp_user}:${ftp_pass}@${ftp_server}/apt/ensim/LWP/$version/$release/RPMS.lwp]
    --exclude=<pkg1,pkg2,...>:
        A comma-separated list of packages that should be excluded from
	consideration when upgrading/installing. 
    -f <FTP server> | --ftp-server=<FTP server>: 
        The name of an FTP server that has the same directory structure as 
	the Ensim FTP server. Any base URLs not specified on the commandline
	will use this server. [$ftp_server]
    --ftp-pass=<password>:
        The password to use when accessing data from an FTP server. Any base
        URLs not specified on the commandline will use this password. [$ftp_pass]
    --ftp-user=<user>:
        The username to use when accessing data from an FTP server. Any base
        URLs not specified on the commandline will use this username. [$ftp_user]
    -i <yum|rpm> | --installer=<yum|rpm>:
        Specifed installer will be used to perform the operation. Yum is used
        to resolve dependencies in either case. [rpm]
    -o <yum baseurl> | --os-source=<yum baseurl>: 
        A yum-style baseurl pointing to a yum repository for the operating 
	system rpms. [=ftp://${ftp_user}:${ftp_pass}@${ftp_server}/apt/redhat/10/en/i386/RPMS.os]
    -s | --skip-checker:
        If specified, no prechecks are performed.
    -u <yum baseurl> | --updates-source=<yum baseurl>: 
        A yum-style baseurl pointing to a yum repository for any operating 
	system updates. [ftp://${ftp_user}:${ftp_pass}@${ftp_server}/apt/redhat/10/en/i386/RPMS.updates]

EOF

    exit $exit_code
}

installer_log()
{
    echo "`date +'%D %H:%M:%S'` : $1" | /usr/bin/tee -a $install_log
}

install_yum()
{
    if ! /bin/rpm -q yum >/dev/null 2>&1; then
	# Nuke atrpms and atrpms-package-config; since we'll only do
	# this if yum isn't installed, customers can reinstall later
	# if they want

        aptrpms=""
        if /bin/rpm -q apt >/dev/null 2>&1; then aptrpms="$aptrpms apt"; fi
        if /bin/rpm -q atrpms >/dev/null 2>&1; then aptrpms="$aptrpms atrpms"; fi
        if /bin/rpm -q atrpms-package-config >/dev/null 2>&1; then aptrpms="$aptrpms atrpms-package-config"; fi
        if /bin/rpm -q libapt-pkg >/dev/null 2>&1; then aptrpms="$aptrpms libapt-pkg"; fi
        if [ -n "$aptrpms" ]; then
            /bin/rpm -e --quiet $aptrpms
        fi

	# What are we running on? If 7.3, then we need yum version 1;
	# otherwise, we need yum version 2...
	name_ver=`/bin/rpm -q --qf "%{NAME} %{VERSION}" -f /etc/redhat-release`
	name=`echo $name_ver | cut -f1 -d' '`
	os_version=`echo $name_ver | cut -f2 -d' '`
	if [ $name == "fedora-release" ]; then
	    yum=$yumv2
	elif [ $name = "redhat-release" ]; then
	    if [ $os_version == "7.3" ]; then
		yum=$yumv1
	    else
		yum=$yumv2
	    fi
	fi
	
	if [ $cdrom -eq 1 ]; then
	    /bin/cp -f /mnt/cdrom/apt/ensim/LWP/$version/$release/RPMS.lwp/$yum /tmp
	elif [ -n "$ensim_source" ]; then
	    /usr/bin/wget -O /tmp/$yum -q ${ensim_source}/$yum
	else
	    /usr/bin/wget -O /tmp/$yum -q ftp://${ftp_user}:${ftp_pass}@${ftp_server}/apt/ensim/LWP/$version/$release/RPMS.lwp/$yum
	fi

	# We don't want to overwrite a customer's existing yum.conf (which may
	# have been installed by other rpms, such as atrpms)
        /bin/rm -f /tmp/yum.conf.bak.$$ 2>/dev/null
        if [ -f /etc/yum.conf ]; then
            /bin/mv -f /etc/yum.conf /tmp/yum.conf.bak.$$
        fi

	/bin/rpm -Uvh --force /tmp/$yum
        # PR 32239 No yum crons required on RHEL
        if [ ! $name == 'fedora-release' -a -f /etc/cron.daily/yum.cron -a ! -f /etc/yum.conf.rpmnew ]; then
           rm -f /etc/cron.daily/yum.cron
	fi

        if [ -f /tmp/yum.conf.bak.$$ ]; then
            /bin/mv -f /tmp/yum.conf.bak.$$ /etc/yum.conf
        fi
    fi
}

update_yum()
{
    # /etc/yum.conf is marked config(noreplace), so 
    # won't be overwritten if it changes.
    osname=`/bin/rpm -q --qf "%{NAME}" -f /etc/redhat-release`
    yumver=`/bin/rpm -q --qf="%{VERSION}-%{RELEASE}" yum`
    /usr/bin/yum -y -c $yum_conf update yum | /usr/bin/tee -a $install_log
    yumver2=`/bin/rpm -q --qf="%{VERSION}-%{RELEASE}" yum`
    
    # Remove yum.cron again if we are on RHES, we've updated yum, and there's
    # been no change in the default yum.conf file
    if [ "$yumver" != "$yumver2" -a ! $osname == 'fedora-release' -a -f /etc/cron.daily/yum.cron -a ! -f /etc/yum.conf.rpmnew ]; then
	rm -f /etc/cron.daily/yum.cron
    fi    
}

create_yum_conf()
{
    local ensim_base=""
    local os_base=""
    local updates_base=""
    local other_base=""

    # Get the first character of the version; I'll be specificically looking
    # for '3' below (RedHat Enterprise), in which case we won't be looking
    # for os or update rpms on the Ensim ftp server.
    rh_version=`/bin/rpm -qf --qf="%{VERSION}" /etc/redhat-release | /bin/cut -c1`

    if [ -n "$ensim_source" ]; then
	ensim_base=$ensim_source
    elif [ $cdrom -eq 1 ]; then
	ensim_base=file:///mnt/cdrom/apt/ensim/LWP/$version/$release/RPMS.lwp
    else
	ensim_base=ftp://${ftp_user}:${ftp_pass}@${ftp_server}/apt/ensim/LWP/$version/$release/RPMS.lwp
	if ! /usr/bin/wget -O - -q $ensim_base/headers/header.info > /dev/null; then
	    ensim_base=""
	fi
    fi

    if [ -n "$os_source" ]; then
	os_base=$os_source
    elif [ $cdrom -eq 1 -o $rh_version == "3" ]; then
	os_base=""
    else
	os_base=ftp://${ftp_user}:${ftp_pass}@${ftp_server}/apt/redhat/10/en/i386/RPMS.os
	if ! /usr/bin/wget -O - -q $os_base/headers/header.info > /dev/null; then
	    os_base=""
	fi
    fi

    if [ -n "$updates_source" ]; then
	updates_base=$updates_source
    elif [ $cdrom -eq 1  -o $rh_version == "3" ]; then
	updates_base=""
    else
	updates_base=ftp://${ftp_user}:${ftp_pass}@${ftp_server}/apt/redhat/10/en/i386/RPMS.updates
	if ! /usr/bin/wget -O - -q $updates_base/headers/header.info > /dev/null; then
	    updates_base=""
	fi
    fi

    if [ -n "$other_source" ]; then
	other_base=$other_source
    fi

    # If all <ensim/updates/os/others>_base are empty then either
    # FTP servers are not resolvable or yum repositories specified are not valid.
    if [ -z "$ensim_base" -a -z "$os_base" -a -z "$updates_base" -a -z "$other_base" ]; then
        installer_log "No yum repositories exist in the specified paths. Exiting."
        return 1
    fi

    # Check MySQL4 rpms are installed 
    mysql_rpms=""
    rpm -q MySQL-server &> /dev/null && mysql_rpms="mysql-*"

    mkdir -p /var/cache/yum.ensim
    cat > $yum_conf <<EOF
[main]
cachedir=/var/cache/yum.ensim
debuglevel=2
logfile=/var/log/yum.ensim.log
pkgpolicy=newest
tolerant=1
exactarch=1
exclude=kernel $exclude_rpms $mysql_rpms
EOF

    if [ -n "$os_base" ]; then
	cat >> $yum_conf <<EOF

[os]
name=OS - Base
baseurl=$os_base
EOF
    fi

    if [ -n "$updates_base" ]; then
	cat >> $yum_conf <<EOF

[updates]
name=OS - Updates
baseurl=$updates_base
EOF
    fi

    if [ -n "$ensim_base" ]; then
	cat >> $yum_conf <<EOF

[ensim]
name=Ensim Control Panel
baseurl=$ensim_base
EOF
    fi

    if [ -n "$other_base" ]; then
	cat >> $yum_conf <<EOF

[other]
name=Additional RPMs
baseurl=$other_base
EOF
    fi
    return 0
}

init_logs()
{
    mkdir -p -m 755 `dirname $install_log`
    mkdir -p -m 755 /var/log/ensim
    mkdir -p -m 755 /var/log/appliance
    /bin/touch $install_log
    /bin/touch $ensim_install_log
    installer_log "Ensim Installer"
    installer_log "Logging to file ${install_log}. Final logs will be appended to /var/log/ensim/installer.log"
    installer_log "Invoked with arguments: $1"
}

check_requirements()
{
    local result=0

    for pkg in libxml2 libxml2-python wget rpm-python; do
	if ! /bin/rpm -q --quiet $pkg; then
	    installer_log "$pkg is required. Please install the $pkg rpm and try again."
	    result=1
	fi
    done

    return $result
}

check_if_valid_cd()
{
    local result=0
    if [ ! -d /mnt/cdrom/apt/ensim/LWP/$version/$release/ ]; then
        installer_log "Please insert the Ensim Control Panel CDROM version $version-$release before proceeding."
        result=1
    fi
    return $result
}

backup_appldb()
{
    if [ -f /usr/lib/opcenter/VERSION ]; then
        BAK=/var/lib/pgsql/backups/appldb.`cat /usr/lib/opcenter/VERSION`.gz
	if [ ! -f $BAK ]; then
            installer_log "Backing up appliance database..."
            /usr/bin/pg_dump appldb 2>>$install_log | gzip -c --best > $BAK
        fi
    fi
}

abexit()
{
    # Setting global abort so that when exit gets called in the end
    # doexit handles it gracefully
    gabort=1
    installer_log "Upgrading/Installing Ensim Control Panel: ABORTED"

    # Strip the output of carriage returns, and append it to any existing logs
    /usr/bin/perl -pi -e 's/.*\r//g;' $install_log
    cat $install_log >> $ensim_install_log
  
    if [ -n "$email" ]; then
	hostname=`hostname --fqdn`
        subject="[$hostname] Upgrading/Installing Ensim Control Panel: ABORTED"

	cat $install_log | /bin/mail -s "$subject" $email
    fi

    exit 1
}

doexit()
{
    # Dont do any of the things that doexit does
    if [ $gabort != 0 ]; then
        exit $gstatus
    fi

    if [ $opt != "-h" ]; then
        if [ $gstatus -ne 0 ]; then
	    installer_log "Upgrading/Installing Ensim Control Panel: FAILED"
        else
            installer_log "Upgrading/Installing Ensim Control Panel: SUCCESSFUL"
        fi


        # Strip the output of carriage returns, and append it to any existing logs
        /usr/bin/perl -pi -e 's/.*\r//g;' $install_log
        cat $install_log >> $ensim_install_log
    fi

    if [ -n "$email" ]; then
	hostname=`hostname --fqdn`
	if [ $gstatus -ne 0 ]; then
	    subject="[$hostname] Upgrading/Installing Ensim Control Panel: FAILED"
	else
	    subject="[$hostname] Upgrading/Installing Ensim Control Panel: SUCCESSFUL"
	fi

	cat $install_log | /bin/mail -s "$subject" $email
    fi

    exit $gstatus
}

# enable job control
set -m

# catch exits
trap doexit EXIT
trap abexit INT QUIT TERM

saved_args="$*"

# Parse and reorder args
args=`/usr/bin/getopt -u -l email:,ensim-source:,os-source:,updates-source: \
                         -l ftp-server:,cdrom:,help,assume-yes,log: \
                         -l ftp-user:,ftp-pass:,skip-checker \
                         -l additional-rpms:,exclude:,installer: \
                         -o e:E:o:u:f:c:hyl:sa:i -- $*`
if [ $? -ne 0 ]; then
    exit 1
fi

set -- $args

init_logs "$saved_args"

for opt; do
    case $opt in 
	--email|-e) shift; email=$1; shift ;;
	--ensim-source|-E) shift; ensim_source=$1; shift ;;
	--os-source|-o) shift; os_source=$1; shift ;;
	--updates-source|-u) shift; updates_source=$1; shift ;;
        --ftp-server|-f) shift; ftp_server=$1; shift ;;
        --ftp-pass) shift; ftp_pass=$1; shift ;;
        --ftp-user) shift; ftp_user=$1; shift ;;
	--help|-h) shift; opt="-h"; email=""; gstatus=0; usage 0 "" ;;
	--cdrom|-c) shift 
	            opt_arg=`/bin/echo $1 | /usr/bin/tr '[:upper:]' '[:lower:]'`
		    shift
		    if [ $opt_arg == "y" -o $opt_arg == "yes" ]; then
			cdrom=1
		    else
			cdrom=0
		    fi ;;
	--exclude) shift; exclude_rpms="`echo "$1" | /usr/bin/tr ',' ' '`"; shift ;;
	--assume-yes|-y) shift; assume_yes=1 ;;
	--log|-l) shift; install_log=$1; shift ;;
	--skip-checker|-s) shift; skip_checker=1 ;;
        --additional-rpms|-a) shift; other_source=$1; shift ;;
	--installer|-i) shift; 
                        if [ $opt_arg == 'yum' ]; then
                            use_rpm=0
                        else
                            use_rpm=1 
                        fi ;;
    esac
done

# Validate arguments
if ! check_requirements; then
    exit 1
fi

# Mount the cdrom, if needed (not sure how this will happen,
# since the installer (that they are running now) is on the CD...)
if [ $cdrom -eq 1 -a ! -f /mnt/cdrom/ensim-installer.sh ]; then
    mount /mnt/cdrom
    if ! check_if_valid_cd; then
        exit 1
    fi
fi

# Install yum if needed, and create the conf file
install_yum
if ! create_yum_conf; then
    exit 1
fi
update_yum

# Install or upgrade?
if /bin/rpm -q --quiet webppliance-epilog; then
    install=0
fi

if [ $skip_checker -eq 0 ]; then
    # Install/update ensimchecker
    if /bin/rpm -q --quiet ensimchecker; then
	action=update
    else
	action=install
    fi

    /usr/bin/yum -y -c $yum_conf $action ensimchecker | /usr/bin/tee -a $install_log

    # Set up the email argument to ensimchecker
    email_str=""
    if [ -n "$email" ]; then
	email_str="--email=$email"
    fi

    # Run the checker
    installer_log "Running system check..." 
    if [ $install -eq 1 ]; then
	/usr/bin/ensimchecker --mode=install --version=${version}-${release} \
	    $email_str | /usr/bin/tee -a $install_log
    else
	/usr/bin/ensimchecker --mode=upgrade --version=${version}-${release} \
	    $email_str --old-version=`/bin/rpm -q --qf="%{VERSION}-%{RELEASE}" \
	    webppliance-version` | /usr/bin/tee -a $install_log
    fi

    gstatus=$?

    # Ask the user if he or she wishes to continue
    if [ $assume_yes -eq 0 ]; then
	if [ $gstatus -eq 0 ]; then
	    echo -n "\
The system check has completed. If you wish to browse the results, the
ouput has been stored in ${install_log}. Would you like to continue? [y/N]: "
	else
	    echo -n "\
The system check has completed, and encountered either warnings or errors.
If you wish to browse the results, the output has been stored in ${install_log}.
Would you like to continue? [y/N]: "
	fi

	read ans
	if [ -z "$ans" -o "$ans" != "y" -a "$ans" != "Y" ]; then
	    installer_log "Exiting on user request."
	    abexit
	fi
    fi
fi

# Just in case...
backup_appldb

# Hack this; If we weren't doing *.rpm down below, we wouldn't need this...
/bin/rm -f /var/cache/yum.ensim/*/packages/{yum,ensimchecker}-*.rpm

# Install/update Ensim. The /tmp/success hack is needed to get
# the ending status from yum/rpm, since you can't reliably get that
# from the kill that is used later on to terminate the hanging
# tee process.

if [ $use_rpm -eq 0 ]; then
    /bin/rm -f /tmp/success.$$
    /bin/rm -f /tmp/failure.$$
    if [ $install -eq 1 ]; then
	(/usr/bin/yum -y -c $yum_conf install \
	    webppliance-epilog webppliance-mysql-epilog \
	    webppliance-tomcat4-epilog webppliance-mivamerchant-epilog 2>&1 && \
	 /bin/touch /tmp/success.$$ || /bin/touch /tmp/failure.$$) | \
	 /usr/bin/tee -a $install_log &
    else
	(/usr/bin/yum -y -c $yum_conf upgrade 2>&1 && /bin/touch /tmp/success.$$ || \
	    /bin/touch /tmp/failure.$$) | /usr/bin/tee -a $install_log &
    fi
else
    rm -f /tmp/yum.out.$$
    if [ $install -eq 1 ]; then
	/usr/bin/yum -y -c $yum_conf --download-only install \
	   webppliance-epilog webppliance-mysql-epilog \
	   webppliance-tomcat4-epilog webppliance-mivamerchant-epilog 2>&1 | \
           /usr/bin/tee -a $install_log | /usr/bin/tee -a /tmp/yum.out.$$
    else
	/usr/bin/yum -y -c $yum_conf --download-only upgrade 2>&1 | \
           /usr/bin/tee -a $install_log | /usr/bin/tee -a /tmp/yum.out.$$
    fi

    gstatus=$?
    if [ $gstatus -ne 0 ]; then
	exit $1
    fi

    # Assemble the rpm names from yum's output
    rpms=`/bin/cat /tmp/yum.out.$$ | /bin/egrep '^\[(install|update|deps):' | \
              /bin/cut -f2,3 -d' ' | /usr/bin/tr -- ' ' '-' | \
              /usr/bin/tr -d ']' | /usr/bin/xargs -i \
              /bin/echo "/mnt/cdrom/apt/ensim/LWP/$version/$release/RPMS.lwp/{}.rpm"`

    if [ -z "$rpms" ]; then
        gstatus=0
        exit 0
    fi

    if [ $cdrom == 1 ]; then
        cp -f $rpms /var/cache/yum.ensim/ensim/packages/
    fi

    (/bin/rpm -Uvh /var/cache/yum.ensim/*/packages/*.rpm 2>&1 && \
	/bin/touch /tmp/success.$$ || /bin/touch /tmp/failure.$$) | \
    	/usr/bin/tee -a $install_log & 
fi

# Disown the process to protect it from dropped connections (we
# are disowning it entirely here, as it appears that some of the
# daemons started by rpm scriptlets end up being part of this
# job group).
disown %%

# some of the rpm scriptlets grab onto yum/rpm's stdout, which
# causes tee to sit there forever, reading on a pipe that no one is
# writing to or closing. So, busy wait for yum/rpm
busywait=1
while [ $busywait -eq 1 ]; do
    /usr/bin/test -f /tmp/success.$$ -o -f /tmp/failure.$$

    if [ $? -eq 1 ]; then
	/bin/sleep 3
    else
	busywait=0
	# Get the pid of tee
	tee_pid=`/usr/bin/pstree -p $$ | grep tee | \
	    /bin/sed 's/.*tee(\(.*\)).*/\1/'`
	# I don't want to kill the job as a whole, as that seems
	# to lead to several daemons launched during the install/
	# upgrade process being stopped.
	/bin/kill $tee_pid 1>/dev/null 2>&1
    fi
done

if [ -f /tmp/success.$$ ]; then
    gstatus=0
else
    gstatus=1
fi

# Clean out the yum-cached rpms; if we got this far, most should be installed
/usr/bin/yum -c $yum_conf clean packages

if [ $gstatus -ne 0 ]; then
    installer_log "Operation failed" 
else
    # Someone is killing postgres; it may be the kill above
    # (is postgres still in the installer's process group?)
    echo "Restarting postgres..."
    if [ -f /etc/rc.d/init.d/rhdb ]; then
        /sbin/service rhdb restart
    else
        /sbin/service postgresql restart
    fi

    echo "Restarting webppliance; this may take a while..." | \
	/usr/bin/tee -a $install_log
    
    /sbin/service webppliance restart | /usr/bin/tee -a $install_log &
    disown -h %%
    wait %%
    gstatus=$?
fi

exit $gstatus
