view scripts/installer/install @ 14:be7787c36e58 default tip

new: nofity LGSercies for deleted files
author Zoe Hong <zhong@mpiwg-berlin.mpg.de>
date Mon, 02 Nov 2015 16:41:23 +0100
parents a50cf11e5178
children
line wrap: on
line source

#!/usr/bin/perl

use strict;
use warnings;
use Getopt::Long;
use Socket;
use File::Copy;

my $verbose;
my $pg_only;
my $hostname;
my $gfdir;
my $mailserver;
my $yes;
my $force;
my $nogfpasswd;
my ($rez) = GetOptions(
    #"length=i" => \$length,    # numeric
    #"file=s"   => \$data,      # string
    "verbose"      => \$verbose,
    "pg_only"      => \$pg_only,
    "hostname=s"   => \$hostname,
    "gfdir=s"      => \$gfdir,
    "mailserver=s" => \$mailserver,
    "y|yes"        => \$yes,
    "f|force"      => \$force,
    "nogfpasswd"   => \$nogfpasswd,
);

my $postgresonly = 0;

my @CONFIG_VARIABLES = (
    'HOST_DNS_ADDRESS',
    'GLASSFISH_DIRECTORY',
    'MAIL_SERVER',

    'POSTGRES_SERVER',
    'POSTGRES_PORT',
    'POSTGRES_DATABASE',
    'POSTGRES_USER',
    'POSTGRES_PASSWORD',

    'RSERVE_HOST',
    'RSERVE_PORT',
    'RSERVE_USER',
    'RSERVE_PASSWORD'

);

if ($pg_only) {
#    exit;
    @CONFIG_VARIABLES =
      ( 'POSTGRES_SERVER', 'POSTGRES_PORT', 'POSTGRES_DATABASE', 'POSTGRES_USER', 'POSTGRES_PASSWORD' );

    $postgresonly = 1;
}

# TODO:
# supply pre-set, default values in a text file;
# this way we can provide different sets of default
# values, for the installers intended for different
# groups of users - local developers vs. "real"
# dataverse users.

my %CONFIG_DEFAULTS = (
    'HOST_DNS_ADDRESS',    'localhost',
    'GLASSFISH_DIRECTORY', '/usr/local/glassfish4',
    'MAIL_SERVER',         'mail.hmdc.harvard.edu',

    'POSTGRES_SERVER',   'localhost',
    'POSTGRES_PORT',     5432,
    'POSTGRES_DATABASE', 'dvndb',
    'POSTGRES_USER',     'dvnapp',
    'POSTGRES_PASSWORD', 'secret',

    'RSERVE_HOST',     'localhost',
    'RSERVE_PORT',     6311,
    'RSERVE_USER',     'rserve',
    'RSERVE_PASSWORD', 'rserve'

);

my %CONFIG_PROMPTS = (
    'HOST_DNS_ADDRESS',    'Internet Address of your host',
    'GLASSFISH_DIRECTORY', 'Glassfish Directory',
    'MAIL_SERVER',         'SMTP (mail) server to relay notification messages',

    'POSTGRES_SERVER',   'Postgres Server',
    'POSTGRES_PORT',     'Postgres Server Port',
    'POSTGRES_DATABASE', 'Name of the Postgres Database',
    'POSTGRES_USER',     'Name of the Postgres User',
    'POSTGRES_PASSWORD', 'Postgres user password',

    'RSERVE_HOST',     'Rserve Server',
    'RSERVE_PORT',     'Rserve Server Port',
    'RSERVE_USER',     'Rserve User Name',
    'RSERVE_PASSWORD', 'Rserve User Password'

);

# Supported Posstgres JDBC drivers:
# (have to be configured explicitely, so that Perl "taint" (security) mode
# doesn't get paranoid)

my %POSTGRES_DRIVERS = (
    #    "8_4", "postgresql-8.3-603.jdbc4.jar",
    "8_4", "postgresql-8.4-703.jdbc4.jar",
    "9_0", "postgresql-9.0-802.jdbc4.jar",
    "9_1", "postgresql-9.1-902.jdbc4.jar",
    "9_2", "postgresql-9.1-902.jdbc4.jar",
    "9_3", "postgresql-9.1-902.jdbc4.jar"
);

# A few preliminary checks:

# user -- must be root:

my $user_real = `who am i`;
chop $user_real;
$user_real =~ s/ .*$//;

if ( $< != 0 ) {
    print STDERR "\nERROR: You must be logged in as root to run the installer.\n\n";
    exit 1;
}

# OS:

my $uname_out = `uname -a`;

# hostname:

my $hostname_from_cmdline = `hostname`;
chop $hostname_from_cmdline;

if ($hostname) {
    $CONFIG_DEFAULTS{'HOST_DNS_ADDRESS'} = $hostname;
}
else {
    $CONFIG_DEFAULTS{'HOST_DNS_ADDRESS'} = $hostname_from_cmdline;
}

if ($mailserver) {
    $CONFIG_DEFAULTS{'MAIL_SERVER'} = $mailserver;
}

if ($gfdir) {
    $CONFIG_DEFAULTS{'GLASSFISH_DIRECTORY'} = $gfdir;
}

print "\nWelcome to the Dataverse installer.\n";
unless ($postgresonly) {
    print "You will be guided through the process of setting up a NEW\n";
    print "instance of the dataverse application\n";
}
else {
    print "You will be guided through the process of configuring the\n";
    print "LOCAL instance of PostgreSQL database for use by the DVN\n";
    print "application.\n";
}

my @uname_tokens = split( " ", $uname_out );

my $WORKING_OS;
if ( $uname_tokens[0] eq "Darwin" ) {
    print "\nThis appears to be a MacOS X system; good.\n";
    # TODO: check the OS version

    $WORKING_OS = "MacOSX";
}
elsif ( $uname_tokens[0] eq "Linux" ) {
    if ( -f "/etc/redhat-release" ) {
        print "\nThis appears to be a RedHat system; good.\n";
        $WORKING_OS = "RedHat";
        # TODO: check the distro version
    }
    else {
        print "\nThis appears to be a non-RedHat Linux system;\n";
        print "this installation *may* succeed; but we're not making any promises!\n";
        $WORKING_OS = "Linux";
    }
}
else {
    print "\nWARNING: This appears to be neither a Linux or MacOS X system!\n";
    print "This installer script will most likely fail. Please refer to the\n";
    print "DVN Installers Guide for more information.\n\n";

    $WORKING_OS = "Unknown";

    print "Do you wish to continue?\n [y/n] ";

    my $yesnocont;

    if ($yes) {
        $yesnocont = "y";
    }
    else {
        print "here";
        exit;
        $yesnocont = <>;
        chop $yesnocont;
    }

    while ( $yesnocont ne "y" && $yesnocont ne "n" ) {
        print "Please enter 'y' or 'n'!\n";
        print "(or ctrl-C to exit the installer)\n";
        $yesnocont = <>;
        chop $yesnocont;
    }

    if ( $yesnocont eq "n" ) {
        exit 0;
    }

}

ENTERCONFIG:

print "\n";
print "Please enter the following configuration values:\n";
print "(hit [RETURN] to accept the default value)\n";
print "\n";

for my $ENTRY (@CONFIG_VARIABLES) {
    print $CONFIG_PROMPTS{$ENTRY} . ": ";
    print "[" . $CONFIG_DEFAULTS{$ENTRY} . "] ";

    my $user_entry;
    unless ($yes) {
        $user_entry = <>;
        chop $user_entry;
    }

    if ( $user_entry ne "" ) {
        $CONFIG_DEFAULTS{$ENTRY} = $user_entry;
    }

    print "\n";
}

# CONFIRM VALUES ENTERED:

print "\nOK, please confirm what you've entered:\n\n";

for my $ENTRY (@CONFIG_VARIABLES) {
    print $CONFIG_PROMPTS{$ENTRY} . ": " . $CONFIG_DEFAULTS{$ENTRY} . "\n";
}

my $yesno;
if ($yes) {
    $yesno = "y";
}
else {
    print "\nIs this correct? [y/n] ";
    $yesno = <>;
    chop $yesno;
}

while ( $yesno ne "y" && $yesno ne "n" ) {
    print "Please enter 'y' or 'n'!\n";
    print "(or ctrl-C to exit the installer)\n";
    $yesno = <>;
    chop $yesno;
}

if ( $yesno eq "n" ) {
    goto ENTERCONFIG;
}

# VALIDATION/VERIFICATION OF THE CONFIGURATION VALUES:
# 1. VERIFY MAIL SERVER THEY CONFIGURED:

unless ($postgresonly) {

    my ( $mail_server_iaddr, $mail_server__paddr, $mail_server_proto, $mail_server_status );

    $mail_server_status = 1;

    unless ( $mail_server_iaddr = inet_aton( $CONFIG_DEFAULTS{'MAIL_SERVER'} ) ) {
        print STDERR "Could not look up $CONFIG_DEFAULTS{'MAIL_SERVER'},\n";
        print STDERR "the host you specified as your mail server\n";
        $mail_server_status = 0;
    }

    if ($mail_server_status) {
        my $mail_server_paddr = sockaddr_in( 25, $mail_server_iaddr );
        $mail_server_proto = getprotobyname('tcp');

        unless ( socket( SOCK, PF_INET, SOCK_STREAM, $mail_server_proto )
            && connect( SOCK, $mail_server_paddr ) )
        {
            print STDERR "Could not establish connection to $CONFIG_DEFAULTS{'MAIL_SERVER'},\n";
            print STDERR "the address you provided for your Mail server.\n";
            print STDERR "Please select a valid mail server, and try again.\n\n";

            $mail_server_status = 0;
        }

    }

    close(SOCK);

    unless ($mail_server_status) {
        goto ENTERCONFIG;
    }
}

# 2. CHECK IF THE WAR FILE IS AVAILABLE:

my $WARFILE_LOCATION = "../../target/dataverse-4.0.war";

unless ( -f $WARFILE_LOCATION ) {
    $WARFILE_LOCATION = "dataverse-4.0.war";
}

unless ( -f $WARFILE_LOCATION ) {
    print "\nWARNING: Can't find the project .war file!\n";
    print "\tAre you running the installer in the right directory?\n";
    print "\tHave you built the war file?\n";
    print "\t(if not, build the project and run the installer again)\n";

    exit 0;
}

# check the working (installer) dir:
my $cwd;
chomp( $cwd = `pwd` );

# 2b. CHECK IF THE SQL TEMPLATE IS IN PLACE AND CREATE THE SQL FILE

my $SQL_REFERENCE_DATA     = "reference_data_filtered.sql";
my $SQL_REFERENCE_TEMPLATE = "../database/reference_data.sql";

unless ( -f $SQL_REFERENCE_TEMPLATE ) {
    $SQL_REFERENCE_TEMPLATE = "reference_data.sql";
}

unless ( -f $SQL_REFERENCE_TEMPLATE ) {
    print "\nWARNING: Can't find .sql data template!\n";
    print "(are you running the installer in the right directory?)\n";

    exit 0;
}

open DATATEMPLATEIN, $SQL_REFERENCE_TEMPLATE   || die $@;
open SQLDATAOUT,     '>' . $SQL_REFERENCE_DATA || die $@;

while (<DATATEMPLATEIN>) {
    s/dvnapp/$CONFIG_DEFAULTS{'POSTGRES_USER'}/g;
    print SQLDATAOUT $_;
}

close DATATEMPLATEIN;
close SQLDATAOUT;

# 3. CHECK POSTGRES AND JQ AVAILABILITY:

my $pg_local_connection = 0;
my $psql_exec;
my $jq_exec = "";
my $pg_major_version = 0;
my $pg_minor_version = 0;

my $POSTGRES_SYS_UID;
if ( $CONFIG_DEFAULTS{'POSTGRES_SERVER'} eq 'localhost' ) {
    $pg_local_connection = 1;

    # 3a. CHECK FOR USER postgres:

    print "\nChecking system user \"postgres\"... ";

    my $POSTGRES_SYS_NAME = "postgres";
    $POSTGRES_SYS_UID = ( getpwnam("postgres") )[2];

    unless ($POSTGRES_SYS_UID) {
        print STDERR "\nERROR: I haven't been able to find user \"postgres\" on the system! Is PostgreSQL installed?\n";
        print STDERR "(TODO: prompt the user instead to supply an alternative username, if\n";
        print STDERR "available)\n";

        exit 1;
    }

    print "OK.\n";

    # 3b. LOCATE THE EXECUTABLE:

    my $sys_path = $ENV{'PATH'};
    my @sys_path_dirs = split( ":", $sys_path );

    $psql_exec = "";

    for my $sys_path_dir (@sys_path_dirs) {
        if ( -x $sys_path_dir . "/psql" ) {
            $psql_exec = $sys_path_dir;
            last;
        }
    }

    for my $sys_path_dir (@sys_path_dirs) {
        if ( -x $sys_path_dir . "/jq" ) {
            $jq_exec = $sys_path_dir;
            last;
        }
    }
    if ( $jq_exec eq "" ) {
        print STDERR "\nERROR: I haven't been able to find the jq command in your PATH! Please install it from http://stedolan.github.io/jq/\n";
        exit 1;

    }

    my $psql_major_version = 0;
    my $psql_minor_version = 0;

    # 3c. IF PSQL WAS FOUND IN THE PATH, CHECK ITS VERSION:

    unless ( $psql_exec eq "" ) {
        open( PSQLOUT, $psql_exec . "/psql --version|" );

        my $psql_version_line = <PSQLOUT>;
        chop $psql_version_line;
        close PSQLOUT;

        my ( $postgresName, $postgresNameLong, $postgresVersion ) = split( " ", $psql_version_line );

        unless ( $postgresName eq "psql" && $postgresVersion =~ /^[0-9][0-9\.]*$/ ) {
            print STDERR "\nWARNING: Unexpected output from psql command!\n";
        }
        else {
            my (@psql_version_tokens) = split( '\.', $postgresVersion );

            print "\n\nFound Postgres psql command, version $postgresVersion.\n\n";

            $psql_major_version = $psql_version_tokens[0];
            $psql_minor_version = $psql_version_tokens[1];

            $pg_major_version = $psql_major_version;
            $pg_minor_version = $psql_minor_version;

        }
    }

    # a frequent problem with MacOSX is that the copy of psql found in the PATH
    # belongs to the older version of PostgresQL supplied with the OS, which happens
    # to be incompatible with the newer builds from the Postgres project; which are
    # recommended to be used with dataverse. So if this is a MacOSX box, we'll
    # check what other versions of PG are available, and select the highest version
    # we can find:

    if ( $WORKING_OS eq "MacOSX" ) {
        my $macos_pg_major_version = 0;
        my $macos_pg_minor_version = 0;

        for $macos_pg_minor_version ( "3", "2", "1", "0" ) {
            if ( -x "/Library/PostgreSQL/9." . $macos_pg_minor_version . "/bin/psql" ) {
                $macos_pg_major_version = 9;
                if (   ( $macos_pg_major_version > $psql_major_version )
                    || ( $macos_pg_minor_version >= $psql_minor_version ) )
                {
                    $psql_exec        = "/Library/PostgreSQL/9." . $macos_pg_minor_version . "/bin";
                    $pg_major_version = $macos_pg_major_version;
                    $pg_minor_version = $macos_pg_minor_version;
                }
                last;
            }
        }

        # And if we haven't found an 9.* version of postgresql installed, we'll also check
        # for version 8.* available:

        if ( $macos_pg_major_version < 9 ) {
            for $macos_pg_minor_version ( "4", "3" )
              # TODO:
              # Do we even want to support postgres 8.3?
            {
                if ( -x "/Library/PostgreSQL/8." . $macos_pg_minor_version . "/bin/psql" ) {
                    $macos_pg_major_version = 8;
                    if (   $macos_pg_major_version > $psql_major_version
                        || $macos_pg_minor_version > $psql_minor_version )
                    {
                        $psql_exec        = "/Library/PostgreSQL/8." . $macos_pg_minor_version . "/bin";
                        $pg_major_version = $macos_pg_major_version;
                        $pg_minor_version = $macos_pg_minor_version;
                    }
                    last;
                }
            }
        }
    }

    if ( $psql_exec eq "" ) {
        print STDERR "\nERROR: I haven't been able to find the psql command in your PATH!\n";
        print STDERR "Please make sure PostgresQL is properly installed; if necessary, add\n";
        print STDERR "the location of psql to the PATH, then try again.\n\n";

        exit 1;
    }

    if ( $pg_major_version == 0 ) {
    }

    # 4. CONFIGURE POSTGRES:

    print "\nConfiguring Postgres Database:\n";
    print "(Using psql version " . $pg_major_version . "." . $pg_minor_version . ")\n";

    $< = $POSTGRES_SYS_UID;
    $> = $POSTGRES_SYS_UID;

    # 4a. CHECK IF POSTGRES IS RUNNING:
    print "Checking if a local instance of Postgres is running and accessible...\n";

    # (change to /tmp before executing the command below -
    # we are trying to do it as user postgres, and it may not have
    # access to the current, installer directory; the command would still
    # work, but there would be an error message from the shell init on screen
    # - potentially confusing)

    chdir("/tmp");

    if ( !system( $psql_exec . "/psql -c 'SELECT * FROM pg_roles' > /dev/null 2>&1" ) ) {
        print "Yes, it is.\n";
    }
    else {
        print "Nope, I haven't been able to connect to the local instance of PostgresQL.\n";
        print "daemon. Is postgresql running? \n";
        print "On a RedHat-like system, you can check the status of the daemon with\n\n";
        print "   service postgresql status\n\n";
        print "and, if it's not running, start the daemon with\n\n";
        print "   service postgresql start\n\n";
        print "On MacOSX, use Applications -> PostgresQL -> Start Server.\n";
        print "(or, if there's no \"Start Server\" item in your PostgresQL folder, \n";
        print "simply restart your MacOSX system!)\n";
        print "Also, please make sure that the daemon is listening to network connections,\n";
        print "at least on the localhost interface. (See \"Installing Postgres\" section\n";
        print "of the installation manual).\n";
        print "Finally, please make sure that the postgres user can make localhost \n";
        print "connections without supplying a password. (That's controlled by the \n";
        print "\"localhost ... ident\" line in pg_hba.conf; again, please consult the \n";
        print "installation manual).\n";

        exit 1;
    }

    # 4c. CHECK IF THIS DB ALREADY EXISTS:

    my $psql_command_dbcheck =
      $psql_exec . "/psql -c \"\" -d " . $CONFIG_DEFAULTS{'POSTGRES_DATABASE'} . ">/dev/null 2>&1";
    if ($force) {
        print "WARNING! Database "
          . $CONFIG_DEFAULTS{'POSTGRES_DATABASE'}
          . " already exists but --force given... continuing.\n";
    }
    elsif ( ( my $exitcode = system($psql_command_dbcheck) ) == 0 ) {
        $> = 0;
        $< = 0;

        chdir($cwd);

        print "WARNING! Database " . $CONFIG_DEFAULTS{'POSTGRES_DATABASE'} . " already exists!\n";
        print "\nPlease note that you can only use this installer to create a blank, \n";
        print "new and shiny DVN database. I.e., you cannot install on top of an \n";
        print "existing database. Please enter a different name for the DVN database.\n";
        print "\nPress any key to continue, or ctrl-C to exit the installer...\n\n";

        system "stty cbreak </dev/tty >/dev/tty 2>&1";
        my $key = getc(STDIN);
        system "stty -cbreak </dev/tty >/dev/tty 2>&1";
        print "\n";

        goto ENTERCONFIG;

    }

    # 4d. CHECK IF THIS USER ALREADY EXISTS:

    my $psql_command_rolecheck =
      $psql_exec . "/psql -c \"\" -d postgres " . $CONFIG_DEFAULTS{'POSTGRES_USER'} . " >/dev/null 2>&1";
    if ( ( my $exitcode = system($psql_command_rolecheck) ) == 0 ) {
        print "User (role) " . $CONFIG_DEFAULTS{'POSTGRES_USER'} . " already exists;\n";
        print "Proceeding.";
    }
    else {
        # 4e. CREATE DVN DB USER:

        print "\nCreating Postgres user (role) for the DVN:\n";

        open TMPCMD, ">/tmp/pgcmd.$$.tmp";

        # with md5-encrypted password:
        my $pg_password_md5 =
          &create_pg_hash( $CONFIG_DEFAULTS{'POSTGRES_USER'}, $CONFIG_DEFAULTS{'POSTGRES_PASSWORD'} );
        my $sql_command =
            "CREATE ROLE \""
          . $CONFIG_DEFAULTS{'POSTGRES_USER'}
          . "\" PASSWORD 'md5"
          . $pg_password_md5
          . "' NOSUPERUSER CREATEDB CREATEROLE INHERIT LOGIN";

        print TMPCMD $sql_command;
        close TMPCMD;

        my $psql_commandline = $psql_exec . "/psql -f /tmp/pgcmd.$$.tmp >/dev/null 2>&1";

        my $out      = qx($psql_commandline 2>&1);
        my $exitcode = $?;
        unless ( $exitcode == 0 ) {
            print STDERR "Could not create the DVN Postgres user role!\n";
            print STDERR "(SQL: " . $sql_command . ")\n";
            print STDERR "(psql exit code: " . $exitcode . ")\n";
            print STDERR "(STDERR and STDOUT was: " . $out . ")\n";
            exit 1;
        }

        unlink "/tmp/pgcmd.$$.tmp";
        print "done.\n";
    }

    # 4f. CREATE DVN DB:

    print "\nCreating Postgres database:\n";

    my $psql_command =
        $psql_exec
      . "/createdb "
      . $CONFIG_DEFAULTS{'POSTGRES_DATABASE'}
      . " --owner="
      . $CONFIG_DEFAULTS{'POSTGRES_USER'};

    my $out      = qx($psql_command 2>&1);
    my $exitcode = $?;
    unless ( $exitcode == 0 ) {
        print STDERR "Could not create Postgres database for the DVN app!\n";
        print STDERR "(command: " . $psql_command . ")\n";
        print STDERR "(psql exit code: " . $exitcode . ")\n";
        print STDERR "(STDOUT and STDERR: " . $out . ")\n";
        if ($force) {
            print STDERR "\n--force called, continuing\n";
        }
        else {
            print STDERR "\naborting the installation (sorry!)\n\n";
            exit 1;
        }
    }

    # Changing back to root UID:

    $> = 0;
    $< = 0;

    chdir($cwd);

}
else {
    if (0) {    # THE LINES BELOW WERE PART OF THE 3.* "DEV." INSTALLER:
                # DO WE STILL WANT TO MAINTAIN THIS FUNCTIONALITY IN 4.0?
        print "\nIt is strongly recommended that you use a local PostgresQL server,\n";
        print "running on localhost, in your development environment!\n\n";

        print "Do you wish to continue?\n [y/n] ";

        my $yesnocont = <>;
        chop $yesnocont;

        while ( $yesnocont ne "y" && $yesnocont ne "n" ) {
            print "Please enter 'y' or 'n'!\n";
            print "(or ctrl-C to exit the installer)\n";
            $yesnocont = <>;
            chop $yesnocont;
        }

        if ( $yesnocont eq "n" ) {
            print "(aborting the installation)\n" . exit 0;
        }
    }

    if ($pg_only) {
        print "The script must be run in the --pg_only mode ONLY locally,\n";
        print "i.e., on the server where PostgresQL is running.\n";

        exit 1;
    }

    print "In order to use a PostgresQL database running on a remote server,\n";
    print "Please run this installer on that host with the \"--pg_only\" option:\n\n";
    print "./install --pg_only\n\n";

    print "Press any key to continue the installation process once that has been\n";
    print "done. Or press ctrl-C to exit the installer.\n\n";

    chdir("/tmp");
    system "stty cbreak </dev/tty >/dev/tty 2>&1";
    my $key = getc(STDIN);
    system "stty -cbreak </dev/tty >/dev/tty 2>&1";
    print "\n";
    chdir($cwd);

    # Check if the role and database have been created on the remote server:
    # -- TODO;

    # Find out what Postgres version is running remotely:

    $pg_major_version = 9;
    $pg_minor_version = 1;

    print "What version of PostgresQL is installed on the remote server?\n ["
      . $pg_major_version . "."
      . $pg_minor_version . "] ";

    my $postgresVersion = <>;
    chop $postgresVersion;

    while ( $postgresVersion ne "" && !( $postgresVersion =~ /^[0-9]+\.[0-9]+$/ ) ) {
        print "Please enter valid Postgres version!\n";
        print "(or ctrl-C to exit the installer)\n";
        $postgresVersion = <>;
        chop $postgresVersion;
    }

    unless ( $postgresVersion eq "" ) {
        my (@postgres_version_tokens) = split( '\.', $postgresVersion );

        unless ( ( $postgres_version_tokens[0] == 8 && $postgres_version_tokens[1] >= 4 )
            || ( $postgres_version_tokens[0] >= 9 ) )
        {
            print STDERR "\nERROR: PostgresQL version 8.4, or newer, is required!\n";
            print STDERR "Please make sure the right version of PostgresQL is properly installed\n";
            print STDERR "on the remote server, then try again.\n";

            exit 1;
        }

        $pg_major_version = $postgres_version_tokens[0];
        $pg_minor_version = $postgres_version_tokens[1];
    }

}

if ($postgresonly) {
    print "\nOK, done.\n";
    print "You can now resume the installation on the main DVN host.\n\n";

    exit 0;
}

# 5. CONFIGURE GLASSFISH

print "\nProceeding with the Glassfish setup.\n";
print "\nChecking your Glassfish installation...";

my $glassfish_dir = $CONFIG_DEFAULTS{'GLASSFISH_DIRECTORY'};

# 5a. CHECK IF GLASSFISH DIR LOOKS OK:

unless ( -d $glassfish_dir . "/glassfish/domains/domain1" ) {
    # TODO: need better check than this

    while ( !( -d $glassfish_dir . "/glassfish/domains/domain1" ) ) {
        print "\nInvalid Glassfish directory " . $glassfish_dir . "!\n";
        print "Enter the root directory of your Glassfish installation:\n";
        print "(Or ctrl-C to exit the installer): ";

        $glassfish_dir = <>;
        chop $glassfish_dir;
    }
}

print "OK!\n";

# 5b. DETERMINE HOW MUCH MEMORY TO GIVE TO GLASSFISH AS HEAP:

my $gf_heap_default = "2048m";
my $sys_mem_total   = 0;

if ( -e "/proc/meminfo" && open MEMINFO, "/proc/meminfo" ) {
    # Linux

    while ( my $mline = <MEMINFO> ) {
        if ( $mline =~ /MemTotal:[ \t]*([0-9]*) kB/ ) {
            $sys_mem_total = $1;
        }
    }

    close MEMINFO;

}
elsif ( -x "/usr/sbin/sysctl" ) {
    # MacOS X, probably...

    $sys_mem_total = `/usr/sbin/sysctl -n hw.memsize`;
    chop $sys_mem_total;
    if ( $sys_mem_total > 0 ) {
        $sys_mem_total = int( $sys_mem_total / 1024 );
        # size in kb
    }
}

if ( $sys_mem_total > 0 ) {
    # setting the default heap size limit to 3/8 of the available
    # amount of memory:
    $gf_heap_default = ( int( $sys_mem_total / ( 8 / 3 * 1024 ) ) );

    print "\nSetting the heap limit for Glassfish to " . $gf_heap_default . "MB. \n";
    print "You may need to adjust this setting to better suit \n";
    print "your system.\n\n";

    #$gf_heap_default .= "m";

}
else {
    print "\nCould not determine the amount of memory on your system.\n";
    print "Setting the heap limit for Glassfish to 2GB. You may need \n";
    print "to  adjust the value to better suit your system.\n\n";
}

push @CONFIG_VARIABLES, "DEF_MEM_SIZE";
$CONFIG_DEFAULTS{"DEF_MEM_SIZE"} = $gf_heap_default;

# TODO:
# if the system has more than 4GB of memory (I believe), glassfish must
# be run with the 64 bit flag set explicitly (at least that was the case
# with the MacOS glassfish build...). Verify, and if still the case,
# add a check.

print "\nInstalling the Glassfish PostgresQL driver... ";

my $install_driver_jar = "";

$install_driver_jar = $POSTGRES_DRIVERS{ $pg_major_version . "_" . $pg_minor_version };

unless ( $install_driver_jar && -e "pgdriver/" . $install_driver_jar ) {
    die "Installer could not find POSTGRES JDBC driver for your version of PostgresQL!\n("
      . $pg_major_version . "."
      . $pg_minor_version . ")";

}

system( "/bin/cp", "pgdriver/" . $install_driver_jar, $glassfish_dir . "/glassfish/lib" );
# more diagnostics needed?

print "done!\n";

print "\n*********************\n";
print "PLEASE NOTE, SOME OF THE ASADMIN COMMANDS ARE GOING TO FAIL,\n";
print "FOR EXAMPLE, IF A CONFIGURATION SETTING THAT WE ARE TRYING\n";
print "TO CREATE ALREADY EXISTS; OR IF A JVM OPTION THAT WE ARE\n";
print "DELETING DOESN'T. THESE \"FAILURES\" ARE NORMAL!\n";
print "*********************\n\n";
print "When/if asadmin asks you to \"Enter admin user name\",\n";
print "it should be safe to hit return and accept the default\n";
print "(which is \"admin\").\n";

print "\nPress any key to continue...\n\n";

system "stty cbreak </dev/tty >/dev/tty 2>&1";
unless ($yes) {
    my $key = getc(STDIN);
}
system "stty -cbreak </dev/tty >/dev/tty 2>&1";
print "\n";

# start domain, if not running:

my $javacheck = `java -version`;
my $exitcode  = $?;
unless ( $exitcode == 0 ) {
    print STDERR "$javacheck\n" if $javacheck;
    print STDERR "Do you have java installed?\n";
    exit 1;
}
my $DOMAIN = "domain1";
my $DOMAIN_DOWN =
  `$CONFIG_DEFAULTS{'GLASSFISH_DIRECTORY'}/bin/asadmin list-domains | grep "$DOMAIN " | grep "not running"`;
print STDERR $DOMAIN_DOWN . "\n";
if ($DOMAIN_DOWN) {
    print "Trying to start domain up...\n";
    system( $CONFIG_DEFAULTS{'GLASSFISH_DIRECTORY'} . "/bin/asadmin start-domain domain1" );
}
else {
    print "domain appears to be up...\n";
}

# create asadmin login, so that the user doesn't have to enter
# the username and password for every asadmin command, if
# access to :4848 is password-protected:

system( $glassfish_dir. "/bin/asadmin login" );

# NEW: configure glassfish using ASADMIN commands:

my $success = &setup_glassfish();

# CHECK EXIT STATUS, BARF IF SETUP SCRIPT FAILED:

unless ($success) {
    print "\nERROR! Failed to configure Glassfish domain!\n";
    print "(see the error messages above - if any)\n";
    print "Aborting...\n";

    exit 1;
}

# Additional config files:

my $JHOVE_CONFIG = "../../conf/jhove/jhove.conf";

unless ( -f $JHOVE_CONFIG ) {
    $JHOVE_CONFIG = "jhove.conf";
}

unless ( -f $JHOVE_CONFIG ) {
    print "\nERROR! Configuration files not found in config dir!\n";
    print "(are you running the installer in the right directory?\n";
    print "Aborting...\n";
    exit 1;
}

print "\nCopying additional configuration files... ";

system( "/bin/cp -Rf " . $JHOVE_CONFIG . " " . $glassfish_dir . "/glassfish/domains/domain1/config" );
#diagnostics needed!

# install the DVN guides (HTML) into the application docroot:
# (if the built docs exist?)
# TODO: add documentation build/installation to the installer.
#system ( "/bin/cp -Rf doc/guides/* ".$glassfish_dir."/glassfish/domains/domain1/docroot/guides");

print "done!\n";

# check if glassfish is running:
# TODO.

# 6. DEPLOY APPLICATION:

# 6b. TRY TO (AUTO-)DEPLOY:

unless (
    (
        my $exit_code =
        system( "cp -f " . $WARFILE_LOCATION . " " . $glassfish_dir . "/glassfish/domains/domain1/autodeploy" )
    ) == 0
  )
{
    print STDERR "Could copy the application into the auto-deploy directory!\n";
    print STDERR "(exit code: " . $exit_code . ")\n";
    exit 1;
}

print "Waiting for the dataverse application to start...\n";
sleep 60;

# 7. POPULATE DATABASE:

if ($pg_local_connection) {
    # 7a. POPULATE LOCALLY:
    print "\nPopulating the database (local PostgresQL instance):\n\n";

    # Copy the SQL file to /tmp, where user postgres will definitely
    # have read access to it:

    copy( $SQL_REFERENCE_DATA, "/tmp" ) or die "Could not copy $SQL_REFERENCE_DATA to /tmp: $!";
    unlink( $SQL_REFERENCE_DATA );

    chdir("/tmp");
    $< = $POSTGRES_SYS_UID;
    $> = $POSTGRES_SYS_UID;
    my $psql_command = $psql_exec . "/psql -d $CONFIG_DEFAULTS{'POSTGRES_DATABASE'} -f $SQL_REFERENCE_DATA";

    unless ( ( my $exitcode = system("$psql_command") ) == 0 ) {
        print STDERR "Could not populate Postgres database for the DVN app!\n";
        print STDERR "(command: " . $psql_command . ")\n";
        print STDERR "(psql exit code: " . $exitcode . ")\n";
        print STDERR "\nYou must populate the database before you can use your new\n";
        print STDERR "DVN instance. Please consult the installation manual and/or\n";
        print STDERR "seek support from the DVN team.\n\n";
        exit 1;

    }

}
else {
    # 7b. INSTRUCT THE USER TO POPULATE THE DB ON THE REMOTE SERVER:
    # NOT SUPPORTED YET -- TODO
    print "Please copy the file $SQL_REFERENCE_DATA (found in this directory)\n";
    print "onto the remote server and populate the database manually,\n";
    print "as user postgres, with the following command:\n\n";
    print "   psql -d $CONFIG_DEFAULTS{'POSTGRES_DATABASE'} -f $SQL_REFERENCE_DATA\n";
    print "then start glassfish again on this server with \n\n";
    print "   " . $glassfish_dir . "/bin/asadmin start-domain domain1\n\n";

#    exit 0;

}

# back to root:

$> = 0;
$< = 0;
chdir($cwd);
print "\nOK, done!\n";

# FIXME: don't just sleep... figure out if the app is up yet.
print "\n--Sleeping for 3 minutes--\n";
sleep 180;

# Populate the metadata block field values, create users
# and dataverses:

unless ( -d "data" && -f "setup-datasetfields.sh" && -f "setup-users.sh" && -f "setup-dvs.sh" && -f "setup-all.sh" ) {
    chdir("../api");
}

unless ( -d "data" && -f "setup-datasetfields.sh" && -f "setup-users.sh" && -f "setup-dvs.sh" && -f "setup-builtin-roles.sh" && -f "setup-all.sh" ) {
    print "\nERROR: Can't find the metadata and user/dataverse setup scripts!\n";
    print "\tAre you running the installer in the right directory?\n";
    exit 1;
}

for my $script ( "setup-all.sh" ) {
    print "Executing script " . $script . "...\n";

    my $my_hostname = $CONFIG_DEFAULTS{'HOST_DNS_ADDRESS'};

    my $run_script;
    #if ( $my_hostname ne "localhost" ) {
    #    system( "sed 's/localhost:8080/$my_hostname/g' < " . $script . " > tmpscript.sh; chmod +x tmpscript.sh" );
    #    $run_script = "tmpscript.sh";
    #}
    #else {
        $run_script = $script;
    #}

    unless ( my $exit_code = system( "./" . $run_script ) == 0 ) {
        print "\nERROR executing script " . $script . "!\n";
        exit 1;
    }
    print "ok!\n";
}

chdir($cwd);

print "\n\nYou should now have a running DVN instance at\n";
print "  http://" . $CONFIG_DEFAULTS{'HOST_DNS_ADDRESS'} . "[:YOURPORT]\n";

# (going to skip the Rserve check, for now)

exit 0;

# 9. FINALLY, CHECK IF RSERVE IS RUNNING:
print "\n\nFinally, checking if Rserve is running and accessible...\n";

unless ( $CONFIG_DEFAULTS{'RSERVE_PORT'} =~ /^[0-9][0-9]*$/ ) {
    print $CONFIG_DEFAULTS{'RSERVE_HOST'} . " does not look like a valid port number,\n";
    print "defaulting to 6311.\n\n";

    $CONFIG_DEFAULTS{'RSERVE_PORT'} = 6311;
}

my ( $rserve_iaddr, $rserve_paddr, $rserve_proto );

unless ( $rserve_iaddr = inet_aton( $CONFIG_DEFAULTS{'RSERVE_HOST'} ) ) {
    print STDERR "Could not look up $CONFIG_DEFAULTS{'RSERVE_HOST'},\n";
    print STDERR "the host you specified as your R server.\n";
    print STDERR "\nDVN can function without a working R server, but\n";
    print STDERR "much of the functionality concerning running statistics\n";
    print STDERR "and analysis on quantitative data will not be available.\n";
    print STDERR "Please consult the Installers guide for more info.\n";

    exit 0;
}

$rserve_paddr = sockaddr_in( $CONFIG_DEFAULTS{'RSERVE_PORT'}, $rserve_iaddr );
$rserve_proto = getprotobyname('tcp');

unless ( socket( SOCK, PF_INET, SOCK_STREAM, $rserve_proto )
    && connect( SOCK, $rserve_paddr ) )
{
    print STDERR "Could not establish connection to $CONFIG_DEFAULTS{'RSERVE_HOST'}\n";
    print STDERR "on port $CONFIG_DEFAULTS{'RSERVE_PORT'}, the address you provided\n";
    print STDERR "for your R server.\n";
    print STDERR "DVN can function without a working R server, but\n";
    print STDERR "much of the functionality concerning running statistics\n";
    print STDERR "and analysis on quantitative data will not be available.\n";
    print STDERR "Please consult the \"Installing R\" section in the Installers guide\n";
    print STDERR "for more info.\n";

    exit 0;

}

close(SOCK);
print "\nOK!\n";

sub setup_glassfish {
    my $success = 1;
    my $failure = 0;

    # We are going to run a standalone shell script with a bunch of asadmin
    # commands to set up all the glassfish components for the application.
    # All the parameters must be passed to that script as environmental
    # variables:

    $ENV{'GLASSFISH_ROOT'}   = $CONFIG_DEFAULTS{'GLASSFISH_DIRECTORY'};
    $ENV{'GLASSFISH_DOMAIN'} = "domain1";
    $ENV{'ASADMIN_OPTS'}     = "";
    $ENV{'MEM_HEAP_SIZE'}    = $CONFIG_DEFAULTS{'DEF_MEM_SIZE'};

    $ENV{'DB_PORT'} = $CONFIG_DEFAULTS{'POSTGRES_PORT'};
    $ENV{'DB_HOST'} = $CONFIG_DEFAULTS{'POSTGRES_SERVER'};
    $ENV{'DB_NAME'} = $CONFIG_DEFAULTS{'POSTGRES_DATABASE'};
    $ENV{'DB_USER'} = $CONFIG_DEFAULTS{'POSTGRES_USER'};
    $ENV{'DB_PASS'} = $CONFIG_DEFAULTS{'POSTGRES_PASSWORD'};

    $ENV{'RSERVE_HOST'} = $CONFIG_DEFAULTS{'RSERVE_HOST'};
    $ENV{'RSERVE_PORT'} = $CONFIG_DEFAULTS{'RSERVE_PORT'};
    $ENV{'RSERVE_USER'} = $CONFIG_DEFAULTS{'RSERVE_USER'};
    $ENV{'RSERVE_PASS'} = $CONFIG_DEFAULTS{'RSERVE_PASSWORD'};

    $ENV{'HOST_ADDRESS'} = $CONFIG_DEFAULTS{'HOST_DNS_ADDRESS'};
    $ENV{'SMTP_SERVER'}  = $CONFIG_DEFAULTS{'MAIL_SERVER'};
    $ENV{'FILES_DIR'} =
      $CONFIG_DEFAULTS{'GLASSFISH_DIRECTORY'} . "/glassfish/domains/" . $ENV{'GLASSFISH_DOMAIN'} . "/files";

    system("./glassfish-setup.sh");

    if ($?) {
        return $failure;
    }
    return $success;
}

sub create_pg_hash {
    my $pg_username = shift @_;
    my $pg_password = shift @_;

    my $encode_line = $pg_password . $pg_username;

    # for Redhat:

    ##print STDERR "executing /bin/echo -n $encode_line | md5sum\n";

    my $hash;
    if ( $WORKING_OS eq "MacOSX" ) {
        $hash = `/bin/echo -n $encode_line | md5`;
    }
    else {
        $hash = `/bin/echo -n $encode_line | md5sum`;
    }

    chop $hash;

    $hash =~ s/  \-$//;

    if ( ( length($hash) != 32 ) || ( $hash !~ /^[0-9a-f]*$/ ) ) {
        print STDERR "Failed to generate a MD5-encrypted password hash for the Postgres database.\n";
        exit 1;
    }

    return $hash;
}