diff --git a/xCAT/postscripts/db2install b/xCAT/postscripts/db2install new file mode 100755 index 000000000..0f0bad58f --- /dev/null +++ b/xCAT/postscripts/db2install @@ -0,0 +1,645 @@ +#!/usr/bin/perl +# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html +#(C)IBM Corp + +# + +#----------------------------------------------------------------------------- + +=head1 db2install + + This postscript installs and sets up db2 on a client machine, usually a Service Node + or a login node. This script can only be used to automatically install an + AIX 6.1 or 7.1, or a Linux Redhat5 or Redhat6 Client. + Note: the db2 code must be in a mountable directory defined by the + db2installloc attribute in the site table. + The perl-DBD-DB2 code should have been installed during the xCAT install from + the AIX or Linux xCAT deps package for AIX6.1 or 7.1 or Redhat5 or Redhat 6. + More information can be obtained from the xCAT http://xcat.svn.sourceforge.net/viewvc/xcat/xcat-core/trunk/xCAT-client/share/doc/xCAT2SetupDB2.pdf. + Needs export MASTER=site.master + export DB2INSTALLLOC=site.db2installlloc + export XCATDPORT=site.xcatdport + export NODE= + +=cut + +#----------------------------------------------------------------------------- + +BEGIN +{ + $::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat'; +} + +# if AIX - make sure we include perl 5.8.2 in INC path. +# Needed to find perl dependencies shipped in deps tarball. +if ($^O =~ /^aix/i) +{ + use lib "/usr/opt/perl5/lib/5.8.2/aix-thread-multi"; + use lib "/usr/opt/perl5/lib/5.8.2"; + use lib "/usr/opt/perl5/lib/site_perl/5.8.2/aix-thread-multi"; + use lib "/usr/opt/perl5/lib/site_perl/5.8.2"; +} + +use lib "$::XCATROOT/lib/perl"; +use strict; +use IO::Socket; +use File::Path; +use Expect; +use xCAT::Utils; +use xCAT::NetworkUtils; +use xCAT::MsgUtils; + +my $useSocketSSL = eval { require IO::Socket::SSL; }; +if ($useSocketSSL) +{ + require IO::Socket::SSL; +} + +# MAIN + +my $rc = 0; +my $msg = ""; +my $cmd; + +# setup some important variable +$::osname = `uname`; +chomp $::osname; + +$::sdate = `/bin/date`; +chomp $::sdate; + +$::hname = `hostname`; +chomp $::hname; + +$::MN = $ENV{'MASTER'}; # as known by the node +if ($::osname eq 'AIX') +{ + $::installdb2dir = "/opt/IBM/db2/V9.7"; # default +} +else +{ # linux + $::installdb2dir = "/opt/ibm/db2/V9.7"; # default +} +my $msg; + +# check to see if db2 already installed and configured, if so +# skip the install +my $db2install = $::installdb2dir; +$db2install .= "\/instance"; +if (!(-e ($db2install))) +{ # already installed + $::db2installloc = $ENV{'DB2INSTALLLOC'}; + if (!$::db2installloc) + { + $::db2installloc = "/mntdb2"; + } + chomp $::db2installloc; + $::db2installloc =~ + s/^(\'|\")(.*)(\"|\')$/$2/; # remove any surrounding quotes + + # mount the db2 directory to get to the db2 code to install + $rc = &mountdb2code; + + # install db2 + if ($rc == 0) + { + $rc = &installdb2code; + if ($rc != 0) + { + $msg = "Error installing DB2. \n"; + `logger -t xcat $msg`; + + } + + # unmount the db2 directory install directory + &unmountdb2code; + } + else + { + $msg = + "Cannot mount the site.db2installloc directory to get to the\n db2 code to install. Setup cannot continue.\n"; + `logger -t xcat $msg`; + exit(1); + } +} +else +{ + $msg = "DB2 is already installed. Will skip installation. \n"; + `logger -t xcat $msg`; +} +my $getcfgloc = 1; # get the cfgloc file from the MN +if (-e ("/etc/xcat/cfgloc")) # check to see if xcat is using DB2 already +{ # cfgloc exists + $cmd = "fgrep DB2 /etc/xcat/cfgloc"; + xCAT::Utils->runcmd($cmd, -1); + if ($::RUNCMD_RC == 0) + { + my $msg = + "The /etc/xcat/cfgloc file is already configured for DB2. xCAT appears to be already running on DB2. xcat database configuration will not take place."; + `logger -t xcat $msg`; + $getcfgloc = 0; # do not get the cfgloc file + + } +} +if ($getcfgloc == 1) +{ + + # get the cfgloc file from the Management Node + $rc = &getcfgloc; + if ($rc != 0) + { # could not get the cfgloc file, cannot continue + $msg = + "Cannot get the cfgloc file from the MN. Client setup cannot continue. \n"; + `logger -t xcat $msg`; + exit 1; + } + +} +# setup the db2 Client for xCAT and start xCAT on the DB2 database + +&rundb2sqlsetup; + +exit 0; + +# +# Subroutines +# + +# run the command +sub runcmd +{ + my ($cmd) = @_; + my $rc = 0; + + $cmd .= ' 2>&1'; + + # my $outref = []; + # @$outref = `$cmd`; + + $::outref = []; + $::outref = `$cmd`; + if ($?) + { + $rc = $? >> 8; + if ($rc > 0) + { + my $msg = "$cmd returned rc=$rc $::outref\n"; + `logger -t xcat $msg`; + return 1; + } + } + return 0; +} + +##################################################### +# +# getcfgloc +# Get DB cfgloc file +# +##################################################### +sub getcfgloc +{ + my $msg; + my $filename = "/etc/xcat/cfgloc"; + my $response = &getresponse("xcat_cfgloc"); + if (defined($response)) + { + my $fd; + &runcmd("mkdir -p /etc/xcat"); + open($fd, '>', $filename); + print $fd $response; + close($fd); + + # set the permissions + my $cmd = "chmod 600 $filename > /dev/null 2>&1"; + &runcmd($cmd); + } + else + { + $msg = "$::sdate db2install: Could not get cfgloc file.\n"; + `logger -t xcat $msg`; + return 1; + } + + # get the info + my $xcatcfg; + my $cfgl; + open($cfgl,"<",$filename); + $xcatcfg = <$cfgl>; + close($cfgl); + chomp $xcatcfg; + my ($hdr, $instance, $password) = split('\|', $xcatcfg); + if ($hdr =~ /^DB2:/) + { + return 0; + } + else + { + $msg = "$::sdate db2install: cfgloc file not for DB2.\n"; + `logger -t xcat $msg`; + return 1; + } + return 0; + +} +##################################################### +# +# mountdb2code +# mount the directory from the db2server that contains +# the db2 code +# +##################################################### +sub mountdb2code +{ + my $msg; + my $rc; + my $server; + my $db2installloc = $ENV{'DB2INSTALLLOC'}; + if (!($db2installloc)) + { + $db2installloc = "/mntdb2"; # set default + } + + # determine server and mount location + if (grep /:/, $db2installloc) + { + my ($hostname, $newinstallloc) = split ":", $db2installloc; + if ($hostname) + { # hostname set in /installloc attribute + $server = $hostname; # set server for mount + $::installloc = $newinstallloc; #set path for mount point + } + } + else + { + $server = $::MN; + $::installloc = $db2installloc; + } + + # mount the install directory from the installloc location + # make the directory to mount on-- same name + if (!(-e $::installloc)) + { + mkpath($::installloc); + } + + # check to see if already mounted + + my $mounted = xCAT::Utils->isMounted($::installloc); + if ($mounted == 0) + { # not mounted + + # need to mount the directory + my $cmd = "mount $server:$::installloc $::installloc"; + $rc = &runcmd($cmd); + } + + return $rc; + +} +##################################################### +# +# installdb2code +# installs the db2 code from the mounted server +# +##################################################### +sub installdb2code +{ + my $msg; + my $rc = 0; + my $installcode = "$::installloc/ese/db2_install"; + + if (!(-e $installcode)) + { + $msg = "$installcode does not exist. Cannot install DB2 code.\n"; + `logger -t xcat $msg`; + exit 1; + } + + my $expect_log = "/tmp/xcatexpect.log"; + $msg = + "$::sdate Starting DB2 install. Monitor progress in $expect_log on the node. \n"; + `logger -t xcat $msg`; + my $db2sql; + my $timeout = 1000; #sets Expect default timeout, 0 accepts immediately + my $timeout; # null says wait forever + my $pwd_sent = 0; + my $dir_prompt = 'Do you want'; + my $product_prompt = " to exit"; + my $debug = 0; + if ($::VERBOSE) + { + $debug = 1; + } + $db2sql = new Expect; + + # + # -re $dir_prompt + # Installation of products - /opt/ibm/db2/V9.7 + # + # Do you want to choose a different directory to install [yes/no] ? + # + # -re $product_prompt + # Specify one of the following keywords to install DB2 products. + # ESE + # CLIENT + # RTCL + # + # + + # disable command echoing + #$db2sql->slave->stty(qw(sane -echo)); + # restart timeout + $db2sql->restart_timeout_upon_receive(1); + + # + # exp_internal(1) sets exp_internal debugging + # to STDERR. + # + #$db2sql->exp_internal(1); + $db2sql->exp_internal($debug); + + # + # log_stdout(0) prevent the program's output from being shown. + # + #$db2sql->log_stdout(1); + $db2sql->log_stdout($debug); + + # + # log session + # + #$db2sql->log_file($expect_log); + $db2sql->log_file($expect_log); + + my $spawncmd; + $spawncmd = "$installcode"; + unless ($db2sql->spawn($spawncmd)) + { + $msg = "Unable to run $spawncmd to create database.\n"; + `logger -t xcat $msg`; + exit 1; + + } + + # + # setup input to db2_install + # + + my @result = $db2sql->expect( + $timeout, + [ + $dir_prompt, + sub { + $db2sql->send("no\r"); + $db2sql->clear_accum(); + $db2sql->exp_continue(); + } + ], + [ + $product_prompt, + sub { + + $db2sql->send("CLIENT\r"); + $db2sql->exp_continue(); + + } + ] + ); + ########################################## + # Expect error - report and quit + ########################################## + if (defined($result[1])) + { + my $errmsg = $result[1]; + $db2sql->soft_close(); + $msg = "Installing DB2 results = $errmsg.\n"; + `logger -t xcat $msg`; + + } + $db2sql->soft_close(); + $msg = "$::sdate Ending DB2 install.\n"; + `logger -t xcat $msg`; + return $rc; + +} + +##################################################### +# +# unmountdb2code +# unmounts the directory from the db2server that contains +# the db2 code +# +##################################################### +sub unmountdb2code +{ + my $msg; + my $rc = 0; + my $cmd; + + # need to un mount the directory + if ($::osname eq 'AIX') + { + $cmd = "unmount $::installloc"; + } + else + { + $cmd = "umount $::installloc"; + } + $rc = &runcmd($cmd); + + return $rc; + +} +##################################################### +# +# rundb2sqlsetup +# runs the db2sqlsetup script and sets up xCAT/DB2 Client +# +##################################################### +sub rundb2sqlsetup +{ + my $msg; + my $rc = 0; + my $cmd; + my $filename = "/etc/xcat/cfgloc"; + # get the info + my $xcatcfg; + my $cfgl; + open($cfgl,"<",$filename); + $xcatcfg = <$cfgl>; + close($cfgl); + chomp $xcatcfg; + my ($database, $instance, $password) = split('\|', $xcatcfg); + $cmd = + "XCATDB2SERVER=$::MN XCATDB2PW=$password $::XCATROOT/bin/db2sqlsetup -i -C"; + $msg = "$::sdate Running Client setup. $::XCATROOT/bin/db2sqlsetup -i -C\n"; + `logger -t xcat $msg`; + + $rc = &runcmd($cmd); + + $msg = "$::sdate Client setup finished.\n"; + `logger -t xcat $msg`; + + return $rc; + +} +##################################################### +# +# getresponse +# Request info from xcatd on the management node +# +# - uses SSL socket on port 3001 to connect to MN xcatd +# to make the request for info +# +##################################################### +sub getresponse +{ + my ($req) = @_; + my $msg; + my $port = $ENV{'XCATDPORT'}; + my $node = $ENV{'NODE'}; + + # open listener connection to wait for check from management node + my $lpid = &openlistener(); + + # open a socket to request data + my $sock = + IO::Socket::SSL->new( + PeerAddr => $::MN, + PeerPort => $port, + Proto => 'tcp', + ); + + # try a few more times + my $times = 1; + while (!$sock) + { + sleep(2); + $times++; + $sock = + IO::Socket::SSL->new( + PeerAddr => $::MN, + PeerPort => $port, + Proto => 'tcp', + ); + if ($times == 5) + { + last; + } + } + + unless ($sock) + { + $msg = "db2install: Cannot connect to host \'$::MN\'\n"; + `logger -t xcat $msg`; + print $msg; + return undef; + } + + # request must be in XML format + print $sock "\n"; + print $sock " getcredentials\n"; + print $sock " $req\n"; + print $sock " 300\n"; + print $sock "\n"; + + #TODO - do we have to try again after waiting for a bit???? + my $response = ''; + my $line; + while (defined($line = <$sock>)) + { + + # skip xml tags + next if ($line =~ /^\s*/) + { + last: + } + $response .= $line; + } + + close($sock); + + #print "resp = \'$response\'\n"; + + kill 2, $lpid; + if ($response) + { + return $response; + } + return undef; +} + +##################################################### +# +# openlistener +# - fork a child process to respond to a check from the MN +# +##################################################### +sub openlistener +{ + my $node = $ENV{'NODE'}; + + + # fork a child process to open a socket to listen for communication + # from the server + my $pid = xCAT::Utils->xfork; + unless (defined $pid) + { + + # fork failed + $msg = "db2install: Could not fork process.\n"; + `logger -t xcat $msg`; + + #print $msg; + return undef; + } + + if ($pid != 0) + { + + # This is the parent process, just return + return $pid; + } + + my $listener = + IO::Socket::INET->new( + LocalPort => '300', + Proto => 'tcp', + Listen => '64', + Reuse => 1 + ); + + unless ($listener) + { + my $msg = "db2install: Cannot open socket on \'$node\'\n"; + `logger -t xcat $msg`; + print $msg; + exit 1; + } + + # xcatd sends a quick req to see if we are really asking + # for info - this listener checks for the req and says ok + my $client; + while ($client = $listener->accept()) + { + + # $client is the new connection + my $text = <$client>; + + # see if we got "CREDOKBYYOU?" + if ($text =~ /CREDOKBYYOU?/) + { + print $client "CREDOKBYME"; + close($client); + close($listener); + exit 0; + } + close($client); + } + close($client); + close($listener); + exit 0; +}