#!/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 DATABASELOC=site.databaseloc export INSTALLDIR=site.installdir 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 $::databaseloc = $ENV{'DATABASELOC'}; # directory for db instance my $installdir = $ENV{'INSTALLDIR'}; # installdir # check to see if the databaseloc attribute is in the installdir attribute # directory path. If it is error out and send something to syslog my @installlocdir = split '/', $installdir; # get base of installdir my @dblocdir = split '/',$::databaseloc; # get base of database if ($installlocdir[1] eq $dblocdir[1] ) { # if they match,error my $msg="db2install:The site databaseloc attribute is set to the directory or a sub-directory of the site table installloc or installdir attribute or the default of /install. This is not a supported configuration."; `logger -t xcat $msg`; exit(1); } 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))) { # not already installed $::db2installloc = $ENV{'DB2INSTALLLOC'}; if (!$::db2installloc) { $::db2installloc = "/mntdb2"; } chomp $::db2installloc; $::db2installloc =~ s/^(\'|\")(.*)(\"|\')$/$2/; # remove any surrounding quotes # startNFS $rc = &startNFS; # 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 = "db2install:Error installing DB2. Cannot continue. \n"; `logger -t xcat $msg`; &unmountdb2code; exit(1); } # unmount the db2 directory install directory &unmountdb2code; } else { $msg = "db2install:Cannot mount the site.db2installloc directory to get the db2 code to install. Setup cannot continue.\n"; `logger -t xcat $msg`; exit(1); } } else { $msg = "db2install:DB2 is already installed. Will skip installation. \n"; `logger -t xcat $msg`; } # get the cfgloc file,if linux should be in /etc/xcat/cfgloc.db2 from xcatserver # postscript $rc = &getcfgloc; if ($rc != 0) { # could not get the cfgloc file, cannot continue $msg = "db2install: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 = "db2install:$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 $cfgsave = "/etc/xcat/cfgloc.db2"; if (-e $cfgsave) { my $cmd = " cp $cfgsave $filename "; xCAT::Utils->runcmd($cmd, 0); if ($::RUNCMD_RC != 0) { $msg = "db2install: $cmd failed.\n"; `logger -t xcat $msg`; return 1; } } else { # file not there get it from the MN 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 = "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 = "db2install: cfgloc file not for DB2.\n"; `logger -t xcat $msg`; return 1; } } return 0; } ##################################################### # # startNFS # Makes sure NFS is running # ##################################################### sub startNFS { my $rc = 0; if (xCAT::Utils->isLinux()) { my $os = xCAT::Utils->osver(); if ($os =~ /sles.*/) { $rc = xCAT::Utils->startService("nfs"); $rc = xCAT::Utils->startService("nfsserver"); } else { $rc = xCAT::Utils->startService("nfs"); } } else { #AIX $rc = xCAT::Utils->startService("nfsd"); } if ($rc != 0) { return 1; } return $rc; } ##################################################### # # 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; my $installcode1 = "$::installloc/ese/db2_install"; my $installcode2 = "$::installloc/server/db2_install"; my $installcode3 = "$::installloc/wser/db2_install"; my $installcode4 = "$::installloc/wse/db2_install"; if ((!(-e $installcode1)) && (!(-e $installcode2)) && (!(-e $installcode3)) && (!(-e $installcode4))) { $msg = "db2install:Install code does not exist. Cannot install DB2 code.\n"; `logger -t xcat $msg`; exit 1; } # pick the correct install directory if (-e $installcode1 ) { $installcode=$installcode1; } else { if (-e $installcode2 ) { $installcode=$installcode2; } else { if (-e $installcode3 ) { $installcode=$installcode3; } else { $installcode=$installcode4; } } } my $expect_log = "/tmp/xcatexpect.log"; $msg = "db2install: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 = "db2install: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 = "db2install:Installing DB2 results = $errmsg.\n"; `logger -t xcat $msg`; } $db2sql->soft_close(); $msg = "db2install: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); if ($::databaseloc) { if (!(-e $::databaseloc)) { # if it does not exist, create it &runcmd("mkdir -p $::databaseloc"); } $cmd = "DATABASELOC=$::databaseloc XCATDB2SERVER=$::MN XCATDB2PW=$password $::XCATROOT/bin/db2sqlsetup -i -C"; } else { $cmd = "XCATDB2SERVER=$::MN XCATDB2PW=$password $::XCATROOT/bin/db2sqlsetup -i -C"; } $msg = "db2install:Running Client setup. \"$::XCATROOT/bin/db2sqlsetup -i -C\"\n"; `logger -t xcat $msg`; $rc = &runcmd($cmd); $msg = "db2install: 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; }