Mercurial > hg > LGDataverses
diff scripts/installer/install @ 10:a50cf11e5178
Rewrite LGDataverse completely upgrading to dataverse4.0
author | Zoe Hong <zhong@mpiwg-berlin.mpg.de> |
---|---|
date | Tue, 08 Sep 2015 17:00:21 +0200 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/scripts/installer/install Tue Sep 08 17:00:21 2015 +0200 @@ -0,0 +1,1159 @@ +#!/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; +}