#!/usr/bin/env perl -w # IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html ##################################################### # # xCAT post script for AIX nodes # # This script is used to update software on AIX # standalone systems. # - it is executed by the updatenode command # ##################################################### use File::Basename; use Getopt::Long; # MAIN # # Process the command line... # Getopt::Long::Configure("no_pass_through"); Getopt::Long::Configure("bundling"); $Getopt::Long::ignorecase = 0; if ( !GetOptions( 'f=s' => \$::FILENAME, # software list file name (full) 's=s' => \$::SERVER, 'i=s' => \$::INSTP_FLAGS, # installp flags 'r=s' => \$::RPM_FLAGS, # RPM flags 'e=s' => \$::EMGR_FLAGS, # emgr flags 'n|nfsv4' => \$::NFSV4, 'd|altsrc' => \$::ALTSRC, 'a|all' => \$::ALLSW ) ) { # Gather options exit 1; } # # set the name of this nodes server # my $servnode; if ($::SERVER) { $servnode = $::SERVER; } elsif (-f "/etc/xcatinfo") { my $cmd = "/bin/cat /etc/xcatinfo | /bin/grep 'XCATSERVER'"; &runcmd($cmd); my $SNline = $::outref; my $junk; ($junk, $servnode) = split(/=/, $SNline); chomp $servnode; $servnode =~ s/^\s*//; } elsif ($ENV{'MASTER'}) { $servnode = $ENV{'MASTER'}; } else { # error no server provided print "aixswupdate: Could not determine the xCAT server for this node.\n"; exit 1; } # pick a local mount point my $localsrc = "/xcatswmnt"; #ex. FILENAME -> /install/nim/lpp_source/71H_image_lpp_source/pkglist.$img # mntdir -> /install/nim/lpp_source/71H_image_lpp_source my $mntdir = dirname($::FILENAME); my $file = basename($::FILENAME); my $listfile = "$localsrc/$file"; # # mount the package source directory # my $mtcmd; if ($::NFSV4) { $mtcmd = qq~/bin/mkdir -m 644 -p $localsrc; /usr/sbin/mount -o vers=4 $servnode:$mntdir $localsrc~; } else { $mtcmd = qq~/bin/mkdir -m 644 -p $localsrc; /usr/sbin/mount $servnode:$mntdir $localsrc~; } $rc = &runcmd($mtcmd); if ($rc != 0) { print "aixswupdate: Could not mount $mntdir source directory from $servnode.\n"; exit 1; } # if the software list file exists then try to install the software if (-f $listfile) { # copy the file contents into a list unless (open(LISTFILE, "<$listfile")) { # error } my @pkglist = ; close(LISTFILE); if (scalar(@pkglist)) { # sort the list into diff packaging types my ($instpfile, $emgrfile, $rpmstring) = &processpkglist(\@pkglist); # installp if (-f $instpfile) { my $rc = &do_installp($instpfile, $::INSTP_FLAGS, $localsrc); if ($rc != 0) { print "One or more errors from the installp command.\n"; } } # updtvpkg my $upcmd = qq~/usr/sbin/updtvpkg~; my $rc = &runcmd($upcmd); if ($rc != 0) { print "Could not run updtvpkg.\n"; } # rpm if ($rpmstring) { my $rc = &do_rpms($rpmstring, $::RPM_FLAGS, $localsrc); if ($rc != 0) { print "One or more errors from the rpm command.\n"; } } # emgr if (-f $emgrfile) { my $rc = &do_emgr($emgrfile, $::EMGR_FLAGS, $localsrc); if ($rc != 0) { print "One or more errors from the emgr command.\n"; } } # clean up tmp files my $rmcmd = qq~/bin/rm -R $emgrfile $instpfile~; print "Running: \'$rmcmd\'\n"; $rc = &runcmd($rmcmd); if ($rc != 0) { # "Could not remove $emgrfile and $instpfile.\n"; } # unmount source dir my $umtcmd = qq~/usr/sbin/umount /xcatswmnt~; print "Running: \'$umtcmd\'\n"; $rc = &runcmd($umtcmd); if ($rc != 0) { # "Could not unmount source directory.\n"; } } } else { # return error print "aixswupdate: Cannot locate software list file: $::FILENAME\n"; exit 1; } #------------------------------------------------------------------------------- =head3 do_rpms This subroutine is used to install a list of rpm packages Arguments: Returns: 0 - ok 1 - error Example: my $rc = &do_rpm($rpmstring, $rpmflags, $localsrc); =cut #----------------------------------------------------------------------------- sub do_rpms { my $rpmstring = shift; my $rpmflag = shift; my $localsrc = shift; # set flags my $rflags; if ($rpmflag) { $rflags = $rpmflag; } else { # default $rflags = qq~ -Uvh --replacepkgs ~; } # if a specific dir was provided then use it # otherwise use the emgr dir in the lpp src my $dir; if ($::ALTSRC) { $dir = "$localsrc"; } else { $dir = "$localsrc/RPMS/ppc"; } my $pkg_string = ""; if ($::ALLSW) { $pkg_string = " *.rpm "; } else { $pkg_string = $rpmstring; } # - need to test rpms to make sure all will install # - add test to rpm cmd if not included in rpm_flags # my @doinstall = split /\s+/, $pkg_string; my @dontinstall = (); if ( ($rflags =~ /\-i/) || ($rflags =~ /install /) || ($rflags =~ /U/) || ($rflags =~ /update /)) { # if so then do test @doinstall = (); my $flags; # if the flags don't include test then add it if (!($rflags =~ /\-test/)) { $flags = " $rflags --test "; } $rpmcmd = qq~cd $dir; /usr/bin/rpm $flags $pkg_string ~; my $rc = &runcmd($rpmcmd); my @outpt = split /\n/, $::outref; my @badrpms; foreach my $line (@outpt) { chomp $line; $line =~ s/^\s+//; #remove leading spaces my ($first, $second, $rest) = split /\s+/, $line; chomp $first; if ($first eq 'package') { push @badrpms, $second; } } my @origrpms = split /\s+/, $pkg_string; foreach my $sr (@origrpms) { if ($sr) { my $r = $sr; $r =~ s/\*$//g; my $found = 0; foreach my $b (@badrpms) { if ($r =~ /$b/) { push @dontinstall, $r; $found++; last; } } if (!$found) { push @doinstall, $sr; } } } if (scalar(@doinstall)) { $pkg_string = join(' ', @doinstall); } else { $pkg_string = ""; } } if (scalar(@doinstall)) { if ($pkg_string) { $rpmcmd = qq~cd $dir; /usr/bin/rpm $rflags $pkg_string ~; } else { $rpmcmd = qq~/usr/bin/rpm $rflags ~; } print "Running: \'$rpmcmd\'\n"; my $rc = &runcmd($rpmcmd); print "$::outref\n"; if ($rc != 0) { # "error from rpm.\n"; return 1; } } if (scalar(@dontinstall)) { print "The following RPM packages were already installed and were not reinstalled:\n"; my @rpms; foreach my $rpm (@dontinstall) { print "$rpm\n"; } print "\n\n"; } return 0; } #------------------------------------------------------------------------------- =head3 do_emgr This subroutine is used to install a list of emgr packages Arguments: Returns: 0 - ok 1 - error Example: my $rc = &do_emgr($emgrfile, $emgrflags, $localsrc); =cut #----------------------------------------------------------------------------- sub do_emgr { my $emgrfile = shift; my $emgrflag = shift; my $localsrc = shift; # set flags my $eflags; if ($emgrflag) { $eflags = $emgrflag; } # if a specific dir was provided then use it # otherwise use the emgr dir in the lpp src my $dir; if ($::ALTSRC) { $dir = "$localsrc"; } else { $dir = "$localsrc/emgr/ppc"; } my $emgrcmd = qq~cd $dir; /usr/sbin/emgr~; if ($eflags) { $emgrcmd .= qq~ $eflags ~; } if ($emgrfile) { $emgrcmd .= qq~ -f $emgrfile ~; } print "Running: \'$emgrcmd\'\n"; my $rc = &runcmd($emgrcmd); print "$::outref\n"; if ($rc != 0) { # "error from emgr.\n"; return 1; } return 0; } #------------------------------------------------------------------------------- =head3 do_installp This subroutine is used to install a list of installp packages Arguments: Returns: 0 - ok 1 - error Example: my $rc = &do_installp($instpfile, $instpflags, $localsrc); =cut #----------------------------------------------------------------------------- sub do_installp { my $instpfile = shift; my $instpflag = shift; my $localsrc = shift; # set flags my $iflags; if ($instpflag) { $iflags = $instpflag; } else { # use default $iflags = " -abgQXY "; } # put together the installp command my $inpcmd = qq~/usr/sbin/installp ~; # these installp flags can be used with -d if ($iflags =~ /l|L|i|A|a/) { # if a specific dir was provided then use it # otherwise use the installp dir in the lpp src if ($::ALTSRC) { $inpcmd .= qq~ -d $localsrc ~; } else { $inpcmd .= qq~ -d $localsrc/installp/ppc ~; } } $inpcmd .= qq~$iflags ~; # don't provide a list of filesets with these flags if ($iflags !~ /C|L|l/) { if ($::ALLSW) { # we want all sw installed $inpcmd .= qq~ all ~; } else { # install what is in the tmp file $inpcmd .= qq~ -f $instpfile ~; } } print "Running: \'$inpcmd\'\n"; my $rc = &runcmd($inpcmd); print "$::outref\n"; if ($rc != 0) { # "error from installp.\n"; return 1; } return 0; } #------------------------------------------------------------------------------- =head3 processpkglist This subroutine is used to sort a list of software package names into separate lists for each software packaging tool. Arguments: Returns: - name of installp list file - name of emgr list file - ptr to list of rpms Example: my ($instpfile, $emgrfile, $rpmstring) = &processpkglist(\@pkglist); =cut #----------------------------------------------------------------------------- sub processpkglist { my $pkg = shift; my @pkglist = @$pkg; # process the package list # - split into rpm, emgr, and installp my @rpm_pkgs; my @emgr_pkgs; my @installp_pkgs; my $emgrfile; my $instpfile; my $rpmstring; # separate into lists for each type of software if (scalar(@pkglist)) { foreach my $p (@pkglist) { next if ($p =~ /^\s*$/ || $p =~ /^\s*#/); chomp $p; if (($p =~ /\.rpm/) || ($p =~ /^R:/)) { my ($junk, $pname); if ($p =~ /:/) { # remove leading prefix - if any ($junk, $pname) = split(/:/, $p); } else { $pname = $p; } push @rpm_pkgs, $pname; } elsif (($p =~ /epkg\.Z/) || ($p =~ /^E:/)) { my ($junk, $pname); if ($p =~ /:/) { ($junk, $pname) = split(/:/, $p); } else { $pname = $p; } push @emgr_pkgs, $pname; } else { my ($junk, $pname); if ($p =~ /:/) { ($junk, $pname) = split(/:/, $p); } else { $pname = $p; } push @installp_pkgs, $pname; } } } # end - separate into lists # # create tmp file for containing a list of software for # installp and emgr # # tmp file for installp # my $random_number = int(rand(1000000)); my $installp_file_name = "installp_file-" . $random_number; chomp $installp_file_name; if (scalar(@installp_pkgs)) { if (!open(INSTPFILE, ">/tmp/$installp_file_name")) { # error "Could not open $installp_file_name.\n"; $instpfile = ""; } else { foreach (@installp_pkgs) { print INSTPFILE $_ . "\n"; } close(INSTPFILE); $instpfile = qq~/tmp/$installp_file_name~; } } else { $instpfile = ""; } # # create tmp file for interim fix packages # my $emgr_file_name = "emgr_file-" . $random_number; chomp $emgr_file_name; if (scalar(@emgr_pkgs)) { if (!open(EMGRFILE, ">/tmp/$emgr_file_name")) { # error "Could not open $emgr_file_name.\n"; $emgrfile = ""; } else { foreach (@emgr_pkgs) { # print EMGRFILE "./$_" . "\n"; print EMGRFILE "$_" . "\n"; } close(EMGRFILE); $emgrfile = qq~/tmp/$emgr_file_name~; } } else { $emgrfile = ""; } # put rpm list in a string if (scalar(@rpm_pkgs)) { foreach my $pkg (@rpm_pkgs) { $rpmstring .= " $pkg"; } } else { $rpmstring = ""; } return ($instpfile, $emgrfile, $rpmstring); } # # run the command # sub runcmd { my ($cmd) = @_; my $rc = 0; $cmd .= ' 2>&1'; $::outref = `$cmd`; if ($?) { $rc = $? >> 8; if ($rc > 0) { return 1; } } return 0; }