3318 lines
		
	
	
		
			98 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
			
		
		
	
	
			3318 lines
		
	
	
		
			98 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
#!/usr/bin/env perl
 | 
						|
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
 | 
						|
 | 
						|
package xCAT_plugin::updatenode;
 | 
						|
 | 
						|
BEGIN
 | 
						|
{
 | 
						|
    $::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat';
 | 
						|
}
 | 
						|
use lib "$::XCATROOT/lib/perl";
 | 
						|
 | 
						|
use xCAT::Table;
 | 
						|
use xCAT::Schema;
 | 
						|
use Data::Dumper;
 | 
						|
use xCAT::Utils;
 | 
						|
use xCAT::SvrUtils;
 | 
						|
use xCAT::Scope;
 | 
						|
use xCAT::Usage;
 | 
						|
use Storable qw(dclone);
 | 
						|
use xCAT::TableUtils;
 | 
						|
use xCAT::ServiceNodeUtils;
 | 
						|
use xCAT::NetworkUtils;
 | 
						|
use xCAT::InstUtils;
 | 
						|
use xCAT::CFMUtils;
 | 
						|
use xCAT::Postage;
 | 
						|
use Getopt::Long;
 | 
						|
use xCAT::GlobalDef;
 | 
						|
use Sys::Hostname;
 | 
						|
use File::Basename;
 | 
						|
use xCAT::GlobalDef;
 | 
						|
use xCAT_monitoring::monitorctrl;
 | 
						|
use Socket;
 | 
						|
 | 
						|
use strict;
 | 
						|
my $CALLBACK;
 | 
						|
my $RERUNPS4SECURITY;
 | 
						|
1;
 | 
						|
 | 
						|
#-------------------------------------------------------------------------------
 | 
						|
 | 
						|
=head1  xCAT_plugin:updatenode
 | 
						|
=head2    Package Description
 | 
						|
  xCAT plug-in module. It handles the updatenode command.
 | 
						|
=cut
 | 
						|
 | 
						|
#------------------------------------------------------------------------------
 | 
						|
 | 
						|
#--------------------------------------------------------------------------------
 | 
						|
 | 
						|
=head3   handled_commands
 | 
						|
      It returns a list of commands handled by this plugin.
 | 
						|
    Arguments:
 | 
						|
        none
 | 
						|
    Returns:
 | 
						|
        a list of commands.
 | 
						|
=cut
 | 
						|
 | 
						|
#------------------------------------------------------------------------------
 | 
						|
sub handled_commands
 | 
						|
{
 | 
						|
    return {
 | 
						|
            updatenode           => "updatenode",
 | 
						|
            updatenodestat       => "updatenode",
 | 
						|
            updatemynodestat     => "updatenode",
 | 
						|
            updatenodeappstat    => "updatenode",
 | 
						|
            };
 | 
						|
}
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3  preprocess_request
 | 
						|
  Check and setup for hierarchy 
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub preprocess_request
 | 
						|
{
 | 
						|
    my $request  = shift;
 | 
						|
    my $callback = shift;
 | 
						|
    $::subreq = shift;
 | 
						|
 | 
						|
    # needed for runcmd output
 | 
						|
    $::CALLBACK = $callback;
 | 
						|
 | 
						|
    my $command = $request->{command}->[0];
 | 
						|
    if ($request->{_xcatpreprocessed}->[0] == 1) { return [$request]; }
 | 
						|
 | 
						|
    my @requests = ();
 | 
						|
 | 
						|
    if ($command eq "updatenode")
 | 
						|
    {
 | 
						|
        return &preprocess_updatenode($request, $callback, $::subreq);
 | 
						|
    }
 | 
						|
    elsif ($command eq "updatenodestat")
 | 
						|
    {
 | 
						|
        return [$request];
 | 
						|
    }
 | 
						|
    elsif ($command eq "updatemynodestat")
 | 
						|
    {
 | 
						|
        return [$request];
 | 
						|
    }
 | 
						|
    elsif ($command eq "updatenodeappstat")
 | 
						|
    {
 | 
						|
        return [$request];
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        my $rsp = {};
 | 
						|
        $rsp->{data}->[0] = "Unsupported command: $command.";
 | 
						|
        $callback->($rsp);
 | 
						|
        return;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
#-----------------------------------------------------------------------------
 | 
						|
 | 
						|
=head3   process_request
 | 
						|
      It processes the updatenode command.
 | 
						|
    Arguments:
 | 
						|
      request -- a hash table which contains the command name and the arguments.
 | 
						|
      callback -- a callback pointer to return the response to.
 | 
						|
    Returns:
 | 
						|
        0 - for success. The output is returned through the callback pointer.
 | 
						|
        1 -  for error. The error messages are returns through the 
 | 
						|
							callback pointer.
 | 
						|
=cut
 | 
						|
 | 
						|
#------------------------------------------------------------------------------
 | 
						|
sub process_request
 | 
						|
{
 | 
						|
    my $request  = shift;
 | 
						|
    my $callback = shift;
 | 
						|
    $::subreq = shift;
 | 
						|
 | 
						|
    # needed for runcmd output
 | 
						|
    $::CALLBACK = $callback;
 | 
						|
 | 
						|
    my $command       = $request->{command}->[0];
 | 
						|
    my $localhostname = hostname();
 | 
						|
 | 
						|
    if ($command eq "updatenode")
 | 
						|
    {
 | 
						|
        return updatenode($request, $callback, $::subreq);
 | 
						|
    }
 | 
						|
    elsif ($command eq "updatenodestat")
 | 
						|
    {
 | 
						|
        return updatenodestat($request, $callback);
 | 
						|
    }
 | 
						|
    elsif ($command eq "updatemynodestat")
 | 
						|
    {
 | 
						|
        delete $request
 | 
						|
          ->{node}; #the restricted form of this command must be forbidden from specifying other nodes, only can set it's own value
 | 
						|
        return updatenodestat($request, $callback);
 | 
						|
    }
 | 
						|
    elsif ($command eq "updatenodeappstat")
 | 
						|
    {
 | 
						|
        return updatenodeappstat($request, $callback);
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        my $rsp = {};
 | 
						|
        $rsp->{data}->[0] = "$localhostname: Unsupported command: $command.";
 | 
						|
        $callback->($rsp);
 | 
						|
        return 1;
 | 
						|
    }
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
#-----------------------------------------------------------------------------
 | 
						|
 | 
						|
=head3   preprocess_updatenode
 | 
						|
        This function checks for the syntax of the updatenode command
 | 
						|
     		and distributes the command to the right server. 
 | 
						|
    Arguments:
 | 
						|
      request - the request. 
 | 
						|
      callback - the pointer to the callback function.
 | 
						|
	  subreq - the sub request
 | 
						|
    Returns:
 | 
						|
      A pointer to an array of requests.
 | 
						|
=cut
 | 
						|
 | 
						|
#------------------------------------------------------------------------------
 | 
						|
sub preprocess_updatenode
 | 
						|
{
 | 
						|
    my $request  = shift;
 | 
						|
    my $callback = shift;
 | 
						|
    my $subreq   = shift;
 | 
						|
    my $args     = $request->{arg};
 | 
						|
    my @requests = ();
 | 
						|
 | 
						|
    my $installdir = xCAT::TableUtils->getInstallDir();
 | 
						|
    my $localhost = hostname();
 | 
						|
 | 
						|
    # subroutine to display the usage
 | 
						|
    sub updatenode_usage
 | 
						|
    {
 | 
						|
        my $cb           = shift;
 | 
						|
        my $rsp          = {};
 | 
						|
        my $usage_string = xCAT::Usage->getUsage("updatenode");
 | 
						|
        push @{$rsp->{data}}, $usage_string;
 | 
						|
 | 
						|
        $cb->($rsp);
 | 
						|
    }
 | 
						|
 | 
						|
    @ARGV = ();
 | 
						|
    if ($args)
 | 
						|
    {
 | 
						|
        @ARGV = @{$args};
 | 
						|
    }
 | 
						|
 | 
						|
    # parse the options
 | 
						|
    my ($ALLSW,$CMDLINE,$ALTSRC,$HELP,$VERSION,$VERBOSE,$FILESYNC,$GENMYPOST,$USER,$SNFILESYNC,$SWMAINTENANCE,$SETSERVER,$RERUNPS,$SECURITY,$OS,$fanout,$timeout); 
 | 
						|
    Getopt::Long::Configure("bundling");
 | 
						|
    Getopt::Long::Configure("no_pass_through");
 | 
						|
    if (
 | 
						|
        !GetOptions(
 | 
						|
                    'A|updateallsw' => \$ALLSW,
 | 
						|
                    'c|cmdlineonly' => \$CMDLINE,
 | 
						|
                    'd=s'           => \$ALTSRC,
 | 
						|
                    'h|help'        => \$HELP,
 | 
						|
                    'v|version'     => \$VERSION,
 | 
						|
                    'V|verbose'     => \$VERBOSE,
 | 
						|
                    'F|sync'        => \$FILESYNC,
 | 
						|
                    'g|genmypost'   => \$GENMYPOST,
 | 
						|
                    'l|user:s'      => \$USER,
 | 
						|
                    'f|snsync'      => \$SNFILESYNC,
 | 
						|
                    'S|sw'          => \$SWMAINTENANCE,
 | 
						|
                    's|sn'          => \$SETSERVER,
 | 
						|
                    'P|scripts:s'   => \$RERUNPS,
 | 
						|
                    'k|security'    => \$SECURITY,
 | 
						|
                    'o|os:s'        => \$OS,
 | 
						|
                    'fanout=i'      => \$fanout,
 | 
						|
                    't|timetout=i'  => \$timeout,
 | 
						|
 | 
						|
        )
 | 
						|
      )
 | 
						|
    {
 | 
						|
        &updatenode_usage($callback);
 | 
						|
        return;
 | 
						|
    }
 | 
						|
    # These globals are used in the updatenode subroutines,
 | 
						|
    #  need to undefine them if not defined in GetOpts
 | 
						|
    # to make updatenode be able to be called multiple times in one process.
 | 
						|
    # $RERUNPS can be set later in the logic based on other input 
 | 
						|
    if (defined($VERBOSE)) {
 | 
						|
       $::VERBOSE=$VERBOSE;
 | 
						|
    } else {
 | 
						|
       undef $::VERBOSE;
 | 
						|
    }
 | 
						|
    if (defined($timeout)) {
 | 
						|
       $::timeout=$timeout;
 | 
						|
    } else {
 | 
						|
       undef $::timeout;
 | 
						|
    }
 | 
						|
    if (defined($fanout)) {
 | 
						|
       $::fanout=$fanout;
 | 
						|
    } else {
 | 
						|
       undef $::fanout;
 | 
						|
    }
 | 
						|
    if (defined($USER)) {
 | 
						|
       $::USER=$USER;
 | 
						|
    } else {
 | 
						|
       undef $::USER;
 | 
						|
    }
 | 
						|
    if (defined($ALTSRC)) {
 | 
						|
       $::ALTSRC=$ALTSRC;
 | 
						|
    } else {
 | 
						|
       undef $::ALTSRC;
 | 
						|
    }
 | 
						|
    if (defined($ALLSW)) {
 | 
						|
       $::ALLSW=$ALLSW;
 | 
						|
    } else {
 | 
						|
       undef $::ALLSW;
 | 
						|
    }
 | 
						|
    if (defined($SETSERVER)) {
 | 
						|
       $::SETSERVER=$SETSERVER;
 | 
						|
    } else {
 | 
						|
       undef $::SETSERVER;
 | 
						|
    }
 | 
						|
 | 
						|
    # display the usage if -h or --help is specified
 | 
						|
    if ($HELP)
 | 
						|
    {
 | 
						|
        &updatenode_usage($callback);
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    # display the version statement if -v or --verison is specified
 | 
						|
    if ($VERSION)
 | 
						|
    {
 | 
						|
        my $rsp = {};
 | 
						|
        $rsp->{data}->[0] = xCAT::Utils->Version();
 | 
						|
        $callback->($rsp);
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    # preprocess generate mypostscripts files (-g) for hierarchy
 | 
						|
    # if no sharedtftp then we need to broadcast this updatenode -g to all service nodes inorder
 | 
						|
    # to be able to support service node pools
 | 
						|
    #
 | 
						|
    if ($GENMYPOST)
 | 
						|
    {
 | 
						|
        # precreatemypostscript has to be yes/1 or do nothing
 | 
						|
        my @entries =  xCAT::TableUtils->get_site_attribute("precreatemypostscripts");
 | 
						|
        if ($entries[0] ) {
 | 
						|
          $entries[0] =~ tr/a-z/A-Z/;
 | 
						|
          if ($entries[0] =~ /^(1|YES)$/ ) {
 | 
						|
            # now check if sharedtftp = 0, if it is we need to broadcast to all the servicenode
 | 
						|
            # if there are service nodes
 | 
						|
            my @entries =  xCAT::TableUtils->get_site_attribute("sharedtftp");
 | 
						|
            my $t_entry = $entries[0];
 | 
						|
            if ( defined($t_entry)  and ($t_entry eq "0" or $t_entry eq "no" or $t_entry eq "NO")) {
 | 
						|
              # see if there are any servicenodes.  If so then run updatenode -g on all of them
 | 
						|
               my @SN;
 | 
						|
               my @CN;
 | 
						|
               my $nodes = $request->{node};
 | 
						|
               xCAT::ServiceNodeUtils->getSNandCPnodes(\@$nodes, \@SN, \@CN);
 | 
						|
               if (@CN >0 ) { # if compute nodes broadcast to all servicenodes
 | 
						|
                    return xCAT::Scope->get_broadcast_scope($request,@_);
 | 
						|
               }
 | 
						|
            } else {  # sharedtftp=yes, just run on MN
 | 
						|
              my $notmpfiles=1;
 | 
						|
              my $nofiles=0;
 | 
						|
              xCAT::Postage::create_mypostscript_or_not($request, $callback, $subreq,$notmpfiles,$nofiles);
 | 
						|
              my $rsp = {};
 | 
						|
              $rsp->{data}->[0] = "Generated new mypostscript files on $localhost";
 | 
						|
              $callback->($rsp);
 | 
						|
              return 0;
 | 
						|
            }
 | 
						|
          } else {  # not valid unless precreatemypostscripts enabled
 | 
						|
            my $rsp = {};
 | 
						|
            $rsp->{error}->[0] =
 | 
						|
              "This option is only valid if site table precreatemypostscripts attribute is 1 or YES";
 | 
						|
            $rsp->{errorcode}->[0] =1;
 | 
						|
            $callback->($rsp);
 | 
						|
            return ;
 | 
						|
          }
 | 
						|
        } else { # precreatemypostscripts not in the site table
 | 
						|
            my $rsp = {};
 | 
						|
            $rsp->{error}->[0] =
 | 
						|
             "This option is only valid if site table precreatemypostscripts attribute is 1 or YES";
 | 
						|
            $rsp->{errorcode}->[0] =1;
 | 
						|
            $callback->($rsp);
 | 
						|
            return ;
 | 
						|
        }
 | 
						|
    }  # end GENMYPOST
 | 
						|
 | 
						|
 | 
						|
 | 
						|
    # -c must work with -S for AIX node
 | 
						|
    if ($CMDLINE && !$SWMAINTENANCE)
 | 
						|
    {
 | 
						|
        my $rsp = {};
 | 
						|
        $rsp->{data}->[0] =
 | 
						|
          "If you specify the -c flag you must specify the -S flag";
 | 
						|
        $callback->($rsp);
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    # -s must not be with any other flag, this updates xcatinfo and run setuppostbootscripts 
 | 
						|
    if ($SETSERVER && ($SWMAINTENANCE || $RERUNPS || $SECURITY))
 | 
						|
    {
 | 
						|
        my $rsp = {};
 | 
						|
        $rsp->{data}->[0] =
 | 
						|
          "If you specify the -s flag you must not specify either the -S or -k or -P
 | 
						|
 flags";
 | 
						|
        $callback->($rsp);
 | 
						|
        return;
 | 
						|
    } 
 | 
						|
    # For -s flag just run this one script
 | 
						|
    if ($SETSERVER) {
 | 
						|
       $RERUNPS            = "setuppostbootscripts";
 | 
						|
    }
 | 
						|
    # -f or -F not both
 | 
						|
    if (($FILESYNC) && ($SNFILESYNC))
 | 
						|
    {
 | 
						|
        my $rsp = {};
 | 
						|
        $rsp->{data}->[0] = "You can not specify both the -f and -F flags.";
 | 
						|
        $callback->($rsp);
 | 
						|
        return;
 | 
						|
    }
 | 
						|
    # -f must not be with any other flag, this updates service nodes syncfiles 
 | 
						|
    if ($SNFILESYNC && ($SWMAINTENANCE || $RERUNPS || defined($RERUNPS) || $SECURITY || $FILESYNC))
 | 
						|
    {
 | 
						|
        my $rsp = {};
 | 
						|
        $rsp->{data}->[0] =
 | 
						|
          "If you specify the -f flag you must not specify either the -S or -k or -P or -F
 | 
						|
 flags";
 | 
						|
        $callback->($rsp);
 | 
						|
        return;
 | 
						|
    } 
 | 
						|
 | 
						|
    # --security cannot work with -S -P -F -f
 | 
						|
    if ($SECURITY
 | 
						|
        && ($SWMAINTENANCE || $RERUNPS || defined($RERUNPS) || $FILESYNC || $SNFILESYNC))
 | 
						|
    {
 | 
						|
        my $rsp = {};
 | 
						|
        $rsp->{data}->[0] =
 | 
						|
          "If you use the -k flag, you cannot specify the -S,-P,-f  or -F flags.";
 | 
						|
        $callback->($rsp);
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    # the -P flag is omitted when only postscripts are specified,
 | 
						|
    # so if there are parameters without any flags, it may mean
 | 
						|
    # to re-run the postscripts. Except for the -k flag
 | 
						|
    if (@ARGV)
 | 
						|
    {
 | 
						|
 | 
						|
        # we have one or more operands on the cmd line
 | 
						|
        if (
 | 
						|
            $#ARGV == 0
 | 
						|
            && !(
 | 
						|
                    $FILESYNC
 | 
						|
                 || $SNFILESYNC
 | 
						|
                 || $SWMAINTENANCE
 | 
						|
                 || defined($RERUNPS)
 | 
						|
                 || $SECURITY
 | 
						|
            )
 | 
						|
          )
 | 
						|
        {
 | 
						|
 | 
						|
            # there is only one operand
 | 
						|
            # if it doesn't contain an = sign then it must be postscripts
 | 
						|
            if (!($ARGV[0] =~ /=/))
 | 
						|
            {
 | 
						|
                $RERUNPS = $ARGV[0];
 | 
						|
                $ARGV[0] = "";
 | 
						|
            }
 | 
						|
 | 
						|
        }
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
 | 
						|
        # if not syncing Service Node
 | 
						|
        if (!($SNFILESYNC))
 | 
						|
        {
 | 
						|
 | 
						|
            # no flags and no operands, set defaults
 | 
						|
            if (
 | 
						|
                !(
 | 
						|
                      $FILESYNC
 | 
						|
                   || $SWMAINTENANCE
 | 
						|
                   || defined($RERUNPS)
 | 
						|
                   || $SECURITY
 | 
						|
                )
 | 
						|
              )
 | 
						|
            {
 | 
						|
                $FILESYNC      = 1;   # these are the defaults when no flags input to updatenode 
 | 
						|
                $SWMAINTENANCE = 1;
 | 
						|
                $RERUNPS       = "";
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    my $nodes = $request->{node};
 | 
						|
 | 
						|
    if (!$nodes)
 | 
						|
    {
 | 
						|
        my $rsp = {};
 | 
						|
        $rsp->{data}->[0] =
 | 
						|
          "A noderange is required for the updatenode command.";
 | 
						|
        $callback->($rsp);
 | 
						|
        return;
 | 
						|
    }
 | 
						|
    if ($SECURITY)
 | 
						|
    {
 | 
						|
 | 
						|
        # check to see if the Management Node is in the noderange and
 | 
						|
        # if it is abort
 | 
						|
        my @mname = xCAT::Utils->noderangecontainsMn(@$nodes);
 | 
						|
        if (@mname)
 | 
						|
        {    # MN in the nodelist
 | 
						|
            my $nodes=join(',', @mname);
 | 
						|
            my $rsp = {};
 | 
						|
            $rsp->{error}->[0] =
 | 
						|
              "You must not run -k option against a management node: $nodes.";
 | 
						|
            xCAT::MsgUtils->message("E", $rsp, $callback, 1);
 | 
						|
            return;
 | 
						|
        }
 | 
						|
 | 
						|
        # now build a list of all service nodes that are either in the
 | 
						|
        # noderange or a service node of a node in the noderange
 | 
						|
        # and update there ssh keys and credentials
 | 
						|
        # get computenodes and servicenodes from the noderange
 | 
						|
        my @SN;
 | 
						|
        my @CN;
 | 
						|
        xCAT::ServiceNodeUtils->getSNandCPnodes(\@$nodes, \@SN, \@CN);
 | 
						|
        $::NODEOUT = ();
 | 
						|
        &update_SN_security($request, $callback, $subreq, \@SN);
 | 
						|
 | 
						|
        # are there compute nodes, then we want to change the request to
 | 
						|
        # just update the compute nodes
 | 
						|
        if (scalar(@CN))
 | 
						|
        {
 | 
						|
            $request->{node}      = \@CN;
 | 
						|
            $request->{noderange} = \@CN;
 | 
						|
            $RERUNPS            = "remoteshell";
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {    # no more nodes
 | 
						|
            return;
 | 
						|
        }
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
    #
 | 
						|
    # process @ARGV
 | 
						|
    #
 | 
						|
 | 
						|
    # the first arg should be a noderange - the other should be attr=val
 | 
						|
    #  - put attr=val operands in %attrvals hash
 | 
						|
 | 
						|
    my %attrvals;
 | 
						|
    if ($SWMAINTENANCE)
 | 
						|
    {
 | 
						|
        while (my $a = shift(@ARGV))
 | 
						|
        {
 | 
						|
            if ($a =~ /=/)
 | 
						|
            {
 | 
						|
 | 
						|
                # if it has an "=" sign its an attr=val - we hope
 | 
						|
                my ($attr, $value) = $a =~ /^\s*(\S+?)\s*=\s*(\S*.*)$/;
 | 
						|
 | 
						|
                if (!defined($attr) || !defined($value))
 | 
						|
                {
 | 
						|
                    my $rsp;
 | 
						|
                    $rsp->{data}->[0] = "Incorrect \'attr=val\' pair - $a\n";
 | 
						|
                    xCAT::MsgUtils->message("E", $rsp, $::callback);
 | 
						|
                    return 3;
 | 
						|
                }
 | 
						|
 | 
						|
                # put attr=val in hash
 | 
						|
                $attrvals{$attr} = $value;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    my @nodes = @$nodes;
 | 
						|
    my $postscripts;
 | 
						|
 | 
						|
    # Handle updating operating system
 | 
						|
    if (defined($OS))
 | 
						|
    {
 | 
						|
        my $reqcopy = {%$request};
 | 
						|
        $reqcopy->{os}->[0] = "yes";
 | 
						|
        push @requests, $reqcopy;
 | 
						|
 | 
						|
        return \@requests;
 | 
						|
    }
 | 
						|
 | 
						|
    # handle the validity of postscripts
 | 
						|
    # check to see if they exist except for the internal xCAT
 | 
						|
    # postscripts-start-here,postbootscripts-start-here,
 | 
						|
    # defaults-postbootscripts-start-here, osimage-postbootscripts-start-here,
 | 
						|
    # etc
 | 
						|
    if (defined($RERUNPS))
 | 
						|
    {
 | 
						|
        if ($RERUNPS eq "")
 | 
						|
        {
 | 
						|
            $postscripts = "";
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            $postscripts = $RERUNPS;
 | 
						|
            my @posts = split(',', $postscripts);
 | 
						|
            if (!grep(/start-here/, @posts))
 | 
						|
            {
 | 
						|
                foreach (@posts)
 | 
						|
                {
 | 
						|
                    my @aa = split(' ', $_);
 | 
						|
                    if (!-e "$installdir/postscripts/$aa[0]")
 | 
						|
                    {
 | 
						|
                        my $rsp = {};
 | 
						|
                        $rsp->{data}->[0] =
 | 
						|
                          "The postscript $installdir/postscripts/$aa[0] does not exist.";
 | 
						|
                        $callback->($rsp);
 | 
						|
                        return;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
 | 
						|
                # can only input one internal postscript  on call
 | 
						|
                # updatenode -P defaults-postscripts-start-here
 | 
						|
                my $arraySize = @posts;
 | 
						|
                if ($arraySize > 1)
 | 
						|
                {    # invalid
 | 
						|
                    my $rsp = {};
 | 
						|
                    $rsp->{data}->[0] =
 | 
						|
                      "Only one internal postscript can be used with -P. Postscripts input were as follows:$postscripts";
 | 
						|
                    $callback->($rsp);
 | 
						|
                    return;
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    # If -F or -f  option specified, sync files to the noderange and their
 | 
						|
    # service nodes.
 | 
						|
    if ($FILESYNC)
 | 
						|
    {
 | 
						|
        $request->{FileSyncing}->[0] = "yes";
 | 
						|
    }
 | 
						|
    if ($SNFILESYNC)    # either sync service node
 | 
						|
    {
 | 
						|
        $request->{SNFileSyncing}->[0] = "yes";
 | 
						|
    }
 | 
						|
 | 
						|
    # If -F  or -f then,  call CFMUtils  to check if any PCM CFM data is to be
 | 
						|
    # built for the node.   This will also create the synclists attribute in
 | 
						|
    # the osimage for each node in the noderange
 | 
						|
    if (($FILESYNC) || ($SNFILESYNC))
 | 
						|
    {
 | 
						|
 | 
						|
        # determine the list of osimages names in the noderange to pass into
 | 
						|
        # the CFMUtils
 | 
						|
        my @imagenames = xCAT::TableUtils->getimagenames(\@nodes);
 | 
						|
 | 
						|
        # Now here we will call CFMUtils
 | 
						|
        $::CALLBACK = $callback;
 | 
						|
        my $rc = 0;
 | 
						|
        $rc = xCAT::CFMUtils->updateCFMSynclistFile(\@imagenames);
 | 
						|
        if ($rc != 0)
 | 
						|
        {
 | 
						|
            my $rsp = {};
 | 
						|
            $rsp->{data}->[0] =
 | 
						|
              "The call to CFMUtils to build synclist returned an errorcode=$rc.";
 | 
						|
            $callback->($rsp);
 | 
						|
            return;
 | 
						|
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    #  - need to consider the mixed cluster case
 | 
						|
    #		- can't depend on the os of the MN - need to split out the AIX nodes
 | 
						|
    my ($rc, $AIXnodes, $Linuxnodes) = xCAT::InstUtils->getOSnodes($nodes);
 | 
						|
    my @aixnodes = @$AIXnodes;
 | 
						|
 | 
						|
    # for AIX nodes we need to copy software to SNs first - if needed
 | 
						|
    my ($imagedef, $updateinfo);
 | 
						|
    if (defined($SWMAINTENANCE) && scalar(@aixnodes))
 | 
						|
    {
 | 
						|
        ($rc, $imagedef, $updateinfo) =
 | 
						|
          &doAIXcopy($callback, \%attrvals, $AIXnodes, $subreq);
 | 
						|
        if ($rc != 0)
 | 
						|
        {
 | 
						|
 | 
						|
            # Do nothing when doAIXcopy failed
 | 
						|
            return undef;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    
 | 
						|
    #  Determine if we are dealing with hierarchy
 | 
						|
    my $sn = xCAT::ServiceNodeUtils->get_ServiceNode(\@nodes, "xcat", "MN");
 | 
						|
    if ($::ERROR_RC)
 | 
						|
    {
 | 
						|
        my $rsp;
 | 
						|
        $rsp->{data}->[0] =
 | 
						|
         "Could not get list of xCAT service nodes";
 | 
						|
        xCAT::MsgUtils->message("E", $rsp, $callback);
 | 
						|
        return;
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
    # Get the MN names
 | 
						|
    my @MNip = xCAT::NetworkUtils->determinehostname;
 | 
						|
    my @MNnodeinfo   = xCAT::NetworkUtils->determinehostname;
 | 
						|
    my $MNnodename   = pop @MNnodeinfo;                  # hostname
 | 
						|
    my @MNnodeipaddr = @MNnodeinfo;                      # ipaddresses
 | 
						|
 | 
						|
    # if no service nodes, or I am on a Service Node, then no hierarchy to deal with
 | 
						|
 | 
						|
    my @sns  = ();
 | 
						|
    if (! (xCAT::Utils->isServiceNode())) {  # not on a servicenode
 | 
						|
       if ($sn)
 | 
						|
       {
 | 
						|
         foreach my $snkey (keys %$sn)
 | 
						|
         {
 | 
						|
           if (!grep(/$snkey/, @MNnodeipaddr))  # don't put the MN in the array
 | 
						|
           {     # if not the MN
 | 
						|
                    push @sns, $snkey;
 | 
						|
 | 
						|
           }
 | 
						|
         }
 | 
						|
       }
 | 
						|
    }
 | 
						|
    # check if no servicenodes for noderange and using the -f flag
 | 
						|
    if ($SNFILESYNC) {
 | 
						|
      if (!(scalar(@sns))) {
 | 
						|
        my $rsp;
 | 
						|
        $rsp->{data}->[0] =
 | 
						|
         "There are no servicenodes to process for the noderange in the updatenode -f command.";
 | 
						|
        xCAT::MsgUtils->message("E", $rsp, $callback);
 | 
						|
        return;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    # process the -F or -f flags 
 | 
						|
    if (($FILESYNC) || ($SNFILESYNC))
 | 
						|
    {
 | 
						|
       # If it is only -F or -f  in the command, which are always run on the MN, 
 | 
						|
       # then run it now and you are
 | 
						|
       # finished.
 | 
						|
       if ((!defined($SWMAINTENANCE))  && (!defined($RERUNPS))) {
 | 
						|
        $request->{_xcatpreprocessed}->[0] = 1;
 | 
						|
        &updatenode($request, $callback, $subreq);
 | 
						|
        return;
 | 
						|
       } else {  
 | 
						|
         if (@sns)  {  # if servicenodes
 | 
						|
           # We have a command with -F and -S and/or -P 
 | 
						|
           # if hierarchical we need to run -f now from the managment node 
 | 
						|
           # to sync the service nodes
 | 
						|
           my $reqcopy ;
 | 
						|
           $reqcopy->{arg}->[0] = "-f";
 | 
						|
           $reqcopy->{_xcatpreprocessed}->[0] = 1;
 | 
						|
           $reqcopy->{SNFileSyncing}->[0] = "yes";
 | 
						|
           $reqcopy->{command}->[0] = $request->{command}->[0];
 | 
						|
           $reqcopy->{environment} = $request->{environment};
 | 
						|
           $reqcopy->{node} = $request->{node};
 | 
						|
           $reqcopy->{noderange} = $request->{noderange};
 | 
						|
           $reqcopy->{username} = $request->{username};
 | 
						|
           $reqcopy->{clienttype} = $request->{clientype};
 | 
						|
           $reqcopy->{cwd} = $request->{cwd};
 | 
						|
           &updatenodesyncfiles($reqcopy, $subreq, $callback);
 | 
						|
         }
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    
 | 
						|
    if (defined($SWMAINTENANCE))
 | 
						|
    {
 | 
						|
            $request->{swmaintenance}->[0] = "yes";
 | 
						|
 | 
						|
            # send along the update info and osimage defs
 | 
						|
            if ($imagedef)
 | 
						|
            {
 | 
						|
                xCAT::InstUtils->taghash($imagedef);
 | 
						|
                $request->{imagedef} = [$imagedef];
 | 
						|
            }
 | 
						|
            if ($updateinfo)
 | 
						|
            {
 | 
						|
                xCAT::InstUtils->taghash($updateinfo);
 | 
						|
                $request->{updateinfo} = [$updateinfo];
 | 
						|
            }
 | 
						|
     }
 | 
						|
     if (defined($RERUNPS))
 | 
						|
     {
 | 
						|
            $request->{rerunps}->[0] = "yes";
 | 
						|
            $request->{postscripts} = [$postscripts];
 | 
						|
            if (defined($::SECURITY))
 | 
						|
            {
 | 
						|
                $request->{rerunps4security}->[0] = "yes";
 | 
						|
            }
 | 
						|
     }
 | 
						|
 | 
						|
     if (defined($SECURITY))
 | 
						|
     {
 | 
						|
            $request->{security}->[0] = "yes";
 | 
						|
     }
 | 
						|
 | 
						|
     #
 | 
						|
     # Handle updating OS
 | 
						|
     #
 | 
						|
     if (defined($OS))
 | 
						|
     {
 | 
						|
            $request->{os}->[0] = "yes";
 | 
						|
     }
 | 
						|
 | 
						|
 | 
						|
    #
 | 
						|
    # if hierarchy,  then build the request for the service nodes
 | 
						|
    #
 | 
						|
    if (@sns)  {  # if servicenodes
 | 
						|
      # build each request for each servicenode 
 | 
						|
      foreach my $snkey (keys %$sn)
 | 
						|
      {
 | 
						|
 | 
						|
 | 
						|
        # build request
 | 
						|
 | 
						|
        my $reqcopy = {%$request};
 | 
						|
        $reqcopy->{node}                   = $sn->{$snkey};
 | 
						|
        $reqcopy->{'_xcatdest'}            = $snkey;
 | 
						|
        $reqcopy->{_xcatpreprocessed}->[0] = 1;
 | 
						|
 | 
						|
        push @requests, $reqcopy;
 | 
						|
 | 
						|
      }
 | 
						|
    } else { # no hierarchy, process it right now , here on the MN
 | 
						|
        $request->{_xcatpreprocessed}->[0] = 1;
 | 
						|
        &updatenode($request, $callback, $subreq);
 | 
						|
        return;
 | 
						|
 | 
						|
    }
 | 
						|
    return \@requests;
 | 
						|
}
 | 
						|
 | 
						|
#-------------------------------------------------------------------------------
 | 
						|
 | 
						|
=head3  update_SN_security 
 | 
						|
 | 
						|
    process updatenode -k command 
 | 
						|
    determine all the service nodes that must be processed from the
 | 
						|
    input noderange and then update the ssh keys and credentials 
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-----------------------------------------------------------------------------
 | 
						|
sub update_SN_security
 | 
						|
 | 
						|
{
 | 
						|
    my $request      = shift;
 | 
						|
    my $callback     = shift;
 | 
						|
    my $subreq       = shift;
 | 
						|
    my $servicenodes = shift;
 | 
						|
    my @SN           = @$servicenodes;
 | 
						|
    my $nodes        = $request->{node};
 | 
						|
    my @nodes        = @$nodes;
 | 
						|
    my $sn = xCAT::ServiceNodeUtils->get_ServiceNode(\@nodes, "xcat", "MN");
 | 
						|
 | 
						|
    if ($::ERROR_RC)
 | 
						|
    {
 | 
						|
        my $rsp;
 | 
						|
        push @{$rsp->{data}}, "Could not get list of xCAT service nodes.";
 | 
						|
        xCAT::MsgUtils->message("E", $rsp, $callback);
 | 
						|
        return;
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
    # take out the Management Node
 | 
						|
    my @MNip = xCAT::NetworkUtils->determinehostname;
 | 
						|
    my @sns  = ();
 | 
						|
    foreach my $s (keys %$sn)
 | 
						|
    {
 | 
						|
        my @tmp_a = split(',', $s);
 | 
						|
        foreach my $s1 (@tmp_a)
 | 
						|
        {
 | 
						|
            if (!grep (/^$s1$/, @MNip))
 | 
						|
            {
 | 
						|
                push @sns, $s1;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    # now add any service nodes in the input noderange, we missed
 | 
						|
    foreach my $sn (@SN)
 | 
						|
    {
 | 
						|
        if (!grep (/^$sn$/, @sns))
 | 
						|
        {
 | 
						|
            push @sns, $sn;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    # if we  have any service nodes to process
 | 
						|
    if (scalar(@sns))
 | 
						|
    {
 | 
						|
 | 
						|
        # setup the ssh keys on the service nodes
 | 
						|
        # run the postscripts: remoteshell, servicenode
 | 
						|
        # These are all servicenodes
 | 
						|
        my $RERUNPS = "remoteshell,servicenode";
 | 
						|
 | 
						|
        my $req_rs = {%$request};
 | 
						|
        my $ps;
 | 
						|
        $ps                              = $RERUNPS;
 | 
						|
        $req_rs->{rerunps}->[0]          = "yes";
 | 
						|
        $req_rs->{security}->[0]         = "yes";
 | 
						|
        $req_rs->{rerunps4security}->[0] = "yes";
 | 
						|
        $req_rs->{node}                  = \@sns;
 | 
						|
        $req_rs->{noderange}             = \@sns;
 | 
						|
        $req_rs->{postscripts}           = [$ps];
 | 
						|
        updatenode($req_rs, $callback, $subreq);
 | 
						|
 | 
						|
        # parse the output of update security for sns
 | 
						|
        foreach my $sn (keys %{$::NODEOUT})
 | 
						|
        {
 | 
						|
            if (!grep /^$sn$/, @sns)
 | 
						|
            {
 | 
						|
                next;
 | 
						|
            }
 | 
						|
            if (   (grep /ps ok/, @{$::NODEOUT->{$sn}})
 | 
						|
                && (grep /ssh ok/, @{$::NODEOUT->{$sn}}))
 | 
						|
            {
 | 
						|
                push @::good_sns, $sn;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        if ($::VERBOSE)
 | 
						|
        {
 | 
						|
            my $rsp;
 | 
						|
            push @{$rsp->{data}},
 | 
						|
              "Update security for following service nodes: @sns.";
 | 
						|
            push @{$rsp->{data}},
 | 
						|
              "  Following service nodes have been updated successfully: @::good_sns";
 | 
						|
            xCAT::MsgUtils->message("I", $rsp, $callback);
 | 
						|
        }
 | 
						|
 | 
						|
    }
 | 
						|
    return;
 | 
						|
}
 | 
						|
 | 
						|
#-------------------------------------------------------------------------------
 | 
						|
 | 
						|
=head3  security_update_sshkeys 
 | 
						|
 | 
						|
    process updatenode -k command 
 | 
						|
    the ssh keys on  the service nodes  and nodes
 | 
						|
    by calling xdsh -K
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-----------------------------------------------------------------------------
 | 
						|
sub security_update_sshkeys
 | 
						|
 | 
						|
{
 | 
						|
    my $request       = shift;
 | 
						|
    my $callback      = shift;
 | 
						|
    my $subreq        = shift;
 | 
						|
    my $nodes         = shift;
 | 
						|
    my @nodes         = @$nodes;
 | 
						|
    my $localhostname = hostname();
 | 
						|
 | 
						|
    # remove the host key from known_hosts
 | 
						|
    xCAT::Utils->runxcmd(
 | 
						|
                         {
 | 
						|
                          command => ['makeknownhosts'],
 | 
						|
                          node    => \@$nodes,
 | 
						|
                          arg     => ['-r'],
 | 
						|
                         },
 | 
						|
                         $subreq, 0, 1
 | 
						|
                         );
 | 
						|
 | 
						|
    if ($::VERBOSE)
 | 
						|
    {
 | 
						|
        my $rsp = {};
 | 
						|
        $rsp->{data}->[0] =
 | 
						|
          "  $localhostname: run makeknownhosts to clean known_hosts file for nodes: @$nodes";
 | 
						|
        $callback->($rsp);
 | 
						|
    }
 | 
						|
 | 
						|
    # call the xdsh -K to set up the ssh keys
 | 
						|
    my @envs = @{$request->{environment}};
 | 
						|
    my $args;
 | 
						|
    push @$args,"-K"; 
 | 
						|
    if (defined($::timeout))  {  # timeout 
 | 
						|
       push @$args,"-t" ;
 | 
						|
       push @$args,$::timeout;
 | 
						|
    }
 | 
						|
    my $res  =
 | 
						|
      xCAT::Utils->runxcmd(
 | 
						|
                           {
 | 
						|
                            command => ['xdsh'],
 | 
						|
                            node    => \@$nodes,
 | 
						|
                            arg     => $args,
 | 
						|
                            env     => \@envs,
 | 
						|
                           },
 | 
						|
                           $subreq, 0, 1
 | 
						|
                           );
 | 
						|
 | 
						|
    if ($::VERBOSE)
 | 
						|
    {
 | 
						|
        my $rsp = {};
 | 
						|
        # not display password in verbose mode.
 | 
						|
        $rsp->{data}->[0] =
 | 
						|
          "  $localhostname: Internal call command: xdsh  @$nodes " . join(' ', @$args);
 | 
						|
        $rsp->{data}->[1] =
 | 
						|
          "  $localhostname: return messages of last command: @$res";
 | 
						|
        $callback->($rsp);
 | 
						|
    }
 | 
						|
 | 
						|
    # parse the output of xdsh -K
 | 
						|
    my @failednodes = @$nodes;
 | 
						|
    foreach my $line (@$res)
 | 
						|
    {
 | 
						|
        chomp($line);
 | 
						|
        if ($line =~ /SSH setup failed for the following nodes: (.*)\./)
 | 
						|
        {
 | 
						|
            @failednodes = split(/,/, $1);
 | 
						|
        }
 | 
						|
        elsif ($line =~ /setup is complete/)
 | 
						|
        {
 | 
						|
            @failednodes = ();
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    my $rsp = {};
 | 
						|
    foreach my $node (@$nodes)
 | 
						|
    {
 | 
						|
        if (grep /^$node$/, @failednodes)
 | 
						|
        {
 | 
						|
            push @{$rsp->{data}}, "$node: Setup ssh keys failed.";
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            push @{$rsp->{data}}, "$node: Setup ssh keys has completed.";
 | 
						|
        }
 | 
						|
    }
 | 
						|
    $callback->($rsp);
 | 
						|
    return;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#--------------------------------------------------------------------------------
 | 
						|
 | 
						|
=head3   updatenode
 | 
						|
        This function implements the updatenode command. 
 | 
						|
    Arguments:
 | 
						|
      request - the request.        
 | 
						|
      callback - the pointer to the callback function.
 | 
						|
	  subreq - the sub request
 | 
						|
    Returns:
 | 
						|
        0 - for success. The output is returned through the callback pointer.
 | 
						|
        1 - for error. The error messages are returned through the 
 | 
						|
				callback pointer.
 | 
						|
=cut
 | 
						|
 | 
						|
#-----------------------------------------------------------------------------
 | 
						|
sub updatenode
 | 
						|
{
 | 
						|
    my $request  = shift;
 | 
						|
    my $callback = shift;
 | 
						|
    my $subreq   = shift;
 | 
						|
    @::SUCCESSFULLNODES=();
 | 
						|
    @::FAILEDNODES=();
 | 
						|
    #print Dumper($request);
 | 
						|
    my $nodes         = $request->{node};
 | 
						|
    #$request->{status}= "yes";  # for testing
 | 
						|
    my $localhostname = hostname();
 | 
						|
    $::CALLERCALLBACK=$callback;
 | 
						|
    # if status return requested
 | 
						|
    my $numberofnodes;
 | 
						|
    # This is an internal call from another plugin requesting status
 | 
						|
    # currently this is not displayed is only returned and not displayed
 | 
						|
    # by updatenode. 
 | 
						|
    if ((defined($request->{status})) && ($request->{status} eq "yes")) {  
 | 
						|
      $numberofnodes = @$nodes;
 | 
						|
      my $rsp = {};
 | 
						|
      $rsp->{status}->[0] = "TOTAL NODES: $numberofnodes";
 | 
						|
      $callback->($rsp); 
 | 
						|
    }
 | 
						|
    # in a mixed cluster we could potentially have both AIX and Linux
 | 
						|
    #	nodes provided on the command line ????
 | 
						|
    my ($rc, $AIXnodes, $Linuxnodes) = xCAT::InstUtils->getOSnodes($nodes);
 | 
						|
 | 
						|
    my $args = $request->{arg};
 | 
						|
    @ARGV = ();
 | 
						|
    if ($args)
 | 
						|
    {
 | 
						|
        @ARGV = @{$args};
 | 
						|
    }
 | 
						|
 | 
						|
    # Lookup Install dir location at this Mangment Node.
 | 
						|
    # XXX: Suppose that compute nodes has the same Install dir location.
 | 
						|
    my $installdir = xCAT::TableUtils->getInstallDir();
 | 
						|
 | 
						|
    #if the postscripts directory exists then make sure it is
 | 
						|
    # world readable  by root
 | 
						|
    my $postscripts = "$installdir/postscripts";
 | 
						|
    if (-e $postscripts)
 | 
						|
    {
 | 
						|
        my $cmd = "chmod -R a+r $postscripts";
 | 
						|
        xCAT::Utils->runcmd($cmd, 0);
 | 
						|
        my $rsp = {};
 | 
						|
        if ($::RUNCMD_RC != 0)
 | 
						|
        {
 | 
						|
            $rsp->{data}->[0] = "$cmd failed.\n";
 | 
						|
            xCAT::MsgUtils->message("E", $rsp, $callback);
 | 
						|
 | 
						|
        }
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
    # get the NIM primary server name
 | 
						|
    my $nimprime = xCAT::InstUtils->getnimprime();
 | 
						|
    chomp $nimprime;
 | 
						|
 | 
						|
    # parse the options
 | 
						|
    my ($ALLSW,$CMDLINE,$ALTSRC,$HELP,$VERSION,$VERBOSE,$FILESYNC,$GENMYPOST,$USER,$SNFILESYNC,$SWMAINTENANCE,$SETSERVER,$RERUNPS,$SECURITY,$OS,$fanout,$timeout); 
 | 
						|
    Getopt::Long::Configure("bundling");
 | 
						|
    Getopt::Long::Configure("no_pass_through");
 | 
						|
    if (
 | 
						|
        !GetOptions(
 | 
						|
                    'A|updateallsw' => \$ALLSW,
 | 
						|
                    'c|cmdlineonly' => \$CMDLINE,
 | 
						|
                    'd=s'           => \$ALTSRC,
 | 
						|
                    'g|genmypost'   => \$GENMYPOST,
 | 
						|
                    'h|help'        => \$HELP,
 | 
						|
                    'v|version'     => \$VERSION,
 | 
						|
                    'V|verbose'     => \$VERBOSE,
 | 
						|
                    'F|sync'        => \$FILESYNC,
 | 
						|
                    'l|user:s'      => \$USER,
 | 
						|
                    'f|snsync'      => \$SNFILESYNC,
 | 
						|
                    'S|sw'          => \$SWMAINTENANCE,
 | 
						|
                    's|sn'          => \$SETSERVER,
 | 
						|
                    'P|scripts:s'   => \$RERUNPS,
 | 
						|
                    'k|security'    => \$SECURITY,
 | 
						|
                    'o|os:s'        => \$OS,
 | 
						|
                    'fanout=i'      => \$fanout,
 | 
						|
                    't|timetout=i'  => \$timeout,
 | 
						|
        )
 | 
						|
      )
 | 
						|
    {
 | 
						|
    }
 | 
						|
    # These globals are used in the updatenode subroutines,
 | 
						|
    #  need to undefine them if not defined in GetOpts
 | 
						|
    # to make updatenode be able to be called multiple times in one process.
 | 
						|
    if (defined($VERBOSE)) {
 | 
						|
       $::VERBOSE=$VERBOSE;
 | 
						|
    } else {
 | 
						|
       undef $::VERBOSE;
 | 
						|
    }
 | 
						|
    if (defined($timeout)) {
 | 
						|
       $::timeout=$timeout;
 | 
						|
    } else {
 | 
						|
       undef $::timeout;
 | 
						|
    }
 | 
						|
    if (defined($fanout)) {
 | 
						|
       $::fanout=$fanout;
 | 
						|
    } else {
 | 
						|
       undef $::fanout;
 | 
						|
    }
 | 
						|
    if (defined($USER)) {
 | 
						|
       $::USER=$USER;
 | 
						|
    } else {
 | 
						|
       undef $::USER;
 | 
						|
    }
 | 
						|
    if (defined($ALTSRC)) {
 | 
						|
       $::ALTSRC=$ALTSRC;
 | 
						|
    } else {
 | 
						|
       undef $::ALTSRC;
 | 
						|
    }
 | 
						|
    if (defined($ALLSW)) {
 | 
						|
       $::ALLSW=$ALLSW;
 | 
						|
    } else {
 | 
						|
       undef $::ALLSW;
 | 
						|
    }
 | 
						|
    if (defined($SETSERVER)) {
 | 
						|
       $::SETSERVER=$SETSERVER;
 | 
						|
    } else {
 | 
						|
       undef $::SETSERVER;
 | 
						|
    }
 | 
						|
 | 
						|
    #
 | 
						|
    # process @ARGV
 | 
						|
    #
 | 
						|
    #  - put attr=val operands in %::attrres hash
 | 
						|
    while (my $a = shift(@ARGV))
 | 
						|
    {
 | 
						|
        if ($a =~ /=/)
 | 
						|
        {
 | 
						|
 | 
						|
            # if it has an "=" sign its an attr=val - we hope
 | 
						|
            my ($attr, $value) = $a =~ /^\s*(\S+?)\s*=\s*(\S*.*)$/;
 | 
						|
 | 
						|
            if (!defined($attr) || !defined($value))
 | 
						|
            {
 | 
						|
                my $rsp;
 | 
						|
                $rsp->{data}->[0] = "Incorrect \'attr=val\' pair - $a\n";
 | 
						|
                xCAT::MsgUtils->message("E", $rsp, $::callback);
 | 
						|
                return 3;
 | 
						|
            }
 | 
						|
 | 
						|
            # put attr=val in hash
 | 
						|
            $::attrres{$attr} = $value;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    # Just generate mypostscripts file and get out 
 | 
						|
    if ($GENMYPOST)
 | 
						|
    {
 | 
						|
        my @entries =  xCAT::TableUtils->get_site_attribute("precreatemypostscripts");
 | 
						|
        if ($entries[0] ) {
 | 
						|
          $entries[0] =~ tr/a-z/A-Z/;
 | 
						|
          if ($entries[0] =~ /^(1|YES)$/ ) {
 | 
						|
 | 
						|
            my $notmpfiles=1;
 | 
						|
            my $nofiles=0;
 | 
						|
            xCAT::Postage::create_mypostscript_or_not($request, $callback, $subreq,$notmpfiles,$nofiles);
 | 
						|
            my $rsp = {};
 | 
						|
            $rsp->{data}->[0] = "Generated new mypostscript files on $localhostname";
 | 
						|
            $callback->($rsp);
 | 
						|
          } else {  # not valid unless precreatemypostscripts enabled
 | 
						|
            my $rsp = {};
 | 
						|
            $rsp->{error}->[0] =
 | 
						|
              "This option is only valid if site table precreatemypostscripts attribute is 1 or YES";
 | 
						|
            $rsp->{errorcode}->[0] =1;
 | 
						|
            $callback->($rsp);
 | 
						|
            return ;
 | 
						|
          }
 | 
						|
        } else { # not in the site table
 | 
						|
            my $rsp = {};
 | 
						|
            $rsp->{error}->[0] =
 | 
						|
             "This option is only valid if site table precreatemypostscripts attribute is 1 or YES";
 | 
						|
            $rsp->{errorcode}->[0] =1;
 | 
						|
            $callback->($rsp);
 | 
						|
            return ;
 | 
						|
        }
 | 
						|
        return 0;
 | 
						|
    }
 | 
						|
 | 
						|
    #create each /tftpboot/mypostscript/mypostscript.<nodename> for each node
 | 
						|
    # This first removes the old one if precreatemypostscripts =0 or undefined
 | 
						|
    # call create files but no tmp files
 | 
						|
    my $notmpfiles=1;
 | 
						|
    my $nofiles=0;
 | 
						|
    #my $nofiles=1;
 | 
						|
    xCAT::Postage::create_mypostscript_or_not($request, $callback, $subreq,$notmpfiles,$nofiles);
 | 
						|
 | 
						|
    # convert the hashes back to the way they were passed in
 | 
						|
    my $flatreq = xCAT::InstUtils->restore_request($request, $callback);
 | 
						|
    my $imgdefs;
 | 
						|
    my $updates;
 | 
						|
    if ($flatreq->{imagedef})
 | 
						|
    {
 | 
						|
        $imgdefs = $flatreq->{imagedef};
 | 
						|
    }
 | 
						|
    if ($flatreq->{updateinfo})
 | 
						|
    {
 | 
						|
        $updates = $flatreq->{updateinfo};
 | 
						|
    }
 | 
						|
 | 
						|
    # if not just using the -k flag, then set all nodes to syncing in 
 | 
						|
    # nodelist updatestatus  for the other updatenode options
 | 
						|
    if (!($::SECURITY)) {
 | 
						|
     my $stat="syncing";
 | 
						|
     xCAT::TableUtils->setUpdateStatus(\@$nodes, $stat);
 | 
						|
    }
 | 
						|
 | 
						|
    
 | 
						|
       
 | 
						|
    #
 | 
						|
    #  handle file synchronization
 | 
						|
    #
 | 
						|
    if (($request->{FileSyncing} && $request->{FileSyncing}->[0] eq "yes")
 | 
						|
        || (
 | 
						|
            (   $request->{SNFileSyncing}
 | 
						|
             && $request->{SNFileSyncing}->[0] eq "yes")))
 | 
						|
    {
 | 
						|
        &updatenodesyncfiles($request, $subreq, $callback);
 | 
						|
    }
 | 
						|
 | 
						|
    if (scalar(@$AIXnodes))
 | 
						|
    {
 | 
						|
        if (xCAT::Utils->isLinux())
 | 
						|
        {
 | 
						|
 | 
						|
            # mixed cluster enviornment, Linux MN=>AIX node
 | 
						|
            # linux nfs client can not mount AIX nfs directory with default settings.
 | 
						|
            # settting nfs_use_reserved_ports=1 could solve the problem
 | 
						|
            my $cmd    = qq~nfso -o nfs_use_reserved_ports=1~;
 | 
						|
            my $output =
 | 
						|
              xCAT::InstUtils->xcmd($callback, $subreq, "xdsh", $AIXnodes, $cmd,
 | 
						|
                                    0);
 | 
						|
            if ($::RUNCMD_RC != 0)
 | 
						|
            {
 | 
						|
                my $rsp;
 | 
						|
                push @{$rsp->{data}},
 | 
						|
                  "Could not set nfs_use_reserved_ports=1 on nodes. Error message is:\n";
 | 
						|
                push @{$rsp->{data}}, "$output\n";
 | 
						|
                xCAT::MsgUtils->message("E", $rsp, $callback);
 | 
						|
                return 1;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    #
 | 
						|
    #  handle software updates
 | 
						|
    #
 | 
						|
    if ($request->{swmaintenance} && $request->{swmaintenance}->[0] eq "yes")
 | 
						|
    {
 | 
						|
        &updatenodesoftware($request, $subreq, $callback, $imgdefs, $updates);
 | 
						|
    }
 | 
						|
 | 
						|
    #
 | 
						|
    # handle of setting up ssh keys
 | 
						|
    #
 | 
						|
 | 
						|
    if ($request->{security} && $request->{security}->[0] eq "yes")
 | 
						|
    {
 | 
						|
 | 
						|
        # check to see if the Management Node is in the noderange and
 | 
						|
        # if it is abort
 | 
						|
        my @mname = xCAT::Utils->noderangecontainsMn(@$nodes);
 | 
						|
        if (@mname)
 | 
						|
        {    # MN in the nodelist
 | 
						|
            my $nodes=join(',', @mname);
 | 
						|
            my $rsp = {};
 | 
						|
            $rsp->{error}->[0] =
 | 
						|
              "You must not run -k option against a management node: $nodes.";
 | 
						|
            xCAT::MsgUtils->message("E", $rsp, $callback, 1);
 | 
						|
            return;
 | 
						|
        }
 | 
						|
        # setup the root ssh keys ( runs xdsh -k)
 | 
						|
 | 
						|
        &security_update_sshkeys($request, $callback, $subreq, \@$nodes);
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
    #
 | 
						|
    # handle the running of cust scripts
 | 
						|
    #
 | 
						|
 | 
						|
    if ($request->{rerunps} && $request->{rerunps}->[0] eq "yes")
 | 
						|
    {
 | 
						|
        &updatenoderunps($request, $subreq, $callback);
 | 
						|
    }
 | 
						|
 | 
						|
    #
 | 
						|
    # Handle updating OS
 | 
						|
    #
 | 
						|
    if ($request->{os} && $request->{os}->[0] eq "yes")
 | 
						|
    {
 | 
						|
        my $os = $::OS;
 | 
						|
 | 
						|
        # Process ID for xfork()
 | 
						|
        my $pid;
 | 
						|
 | 
						|
        # Child process IDs
 | 
						|
        my @children;
 | 
						|
 | 
						|
        # Go through each node
 | 
						|
        foreach my $node (@$nodes)
 | 
						|
        {
 | 
						|
            $pid = xCAT::Utils->xfork();
 | 
						|
 | 
						|
            # Parent process
 | 
						|
            if ($pid)
 | 
						|
            {
 | 
						|
                push(@children, $pid);
 | 
						|
            }
 | 
						|
 | 
						|
            # Child process
 | 
						|
            elsif ($pid == 0)
 | 
						|
            {
 | 
						|
 | 
						|
                # Update OS
 | 
						|
                updateOS($callback, $node, $os);
 | 
						|
 | 
						|
                # Exit process
 | 
						|
                exit(0);
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
 | 
						|
                # Ran out of resources
 | 
						|
                die "Error: Could not fork\n";
 | 
						|
            }
 | 
						|
        }    # End of foreach
 | 
						|
 | 
						|
        # Wait for all processes to end
 | 
						|
        foreach (@children)
 | 
						|
        {
 | 
						|
            waitpid($_, 0);
 | 
						|
        }
 | 
						|
    }
 | 
						|
    # if immediate return of status not requested (PCM), then update the DB here
 | 
						|
    # in one transaction, otherwise it is updated in getdata callback and buildnodestatus
 | 
						|
    if (!(defined($request->{status})) || ($request->{status} ne "yes")) {
 | 
						|
      # update the node status, this is done when -F -S -P are run
 | 
						|
      # make sure the nodes only appear in one array good or bad 
 | 
						|
      &cleanstatusarrays;  
 | 
						|
	   if(@::SUCCESSFULLNODES)
 | 
						|
	   {
 | 
						|
	     
 | 
						|
            my $stat="synced";
 | 
						|
            xCAT::TableUtils->setUpdateStatus(\@::SUCCESSFULLNODES, $stat);
 | 
						|
                      
 | 
						|
	   }
 | 
						|
	   if(@::FAILEDNODES)
 | 
						|
	   {
 | 
						|
	     
 | 
						|
            my $stat="failed";
 | 
						|
            xCAT::TableUtils->setUpdateStatus(\@::FAILEDNODES, $stat);
 | 
						|
                      
 | 
						|
	   }
 | 
						|
	 }
 | 
						|
    #  if site.precreatemypostscripts = not 1 or yes or undefined,
 | 
						|
    # remove all the
 | 
						|
    # node files in the noderange in  /tftpboot/mypostscripts
 | 
						|
     my $removeentries=0;
 | 
						|
     my @entries = 
 | 
						|
         xCAT::TableUtils->get_site_attribute("precreatemypostscripts");
 | 
						|
     if ($entries[0] ) {  # not 1 or yes and defined
 | 
						|
       $entries[0] =~ tr/a-z/A-Z/;
 | 
						|
       if ($entries[0] !~ /^(1|YES)$/ ) {
 | 
						|
         $removeentries=1; 
 | 
						|
       }
 | 
						|
     } else {  # or not defined
 | 
						|
         $removeentries=1; 
 | 
						|
     }
 | 
						|
 
 | 
						|
     if ($removeentries ==1) { 
 | 
						|
         my $tftpdir = xCAT::TableUtils::getTftpDir();
 | 
						|
         foreach my $n (@$nodes ) {
 | 
						|
               unlink("$tftpdir/mypostscripts/mypostscript.$n");
 | 
						|
         }
 | 
						|
     }
 | 
						|
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
#-------------------------------------------------------------------------------
 | 
						|
 | 
						|
=head3  updatenoderunps  - run postscripts or the updatenode -P option 
 | 
						|
 | 
						|
    Arguments: request
 | 
						|
    Returns:
 | 
						|
        0 - for success.
 | 
						|
        1 - for error.
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-----------------------------------------------------------------------------
 | 
						|
sub updatenoderunps
 | 
						|
 | 
						|
{
 | 
						|
    my $request       = shift;
 | 
						|
    my $subreq        = shift;
 | 
						|
    my $callback      = shift;
 | 
						|
    my $nodes         = $request->{node};
 | 
						|
    my $localhostname = hostname();
 | 
						|
    my $installdir    = xCAT::TableUtils->getInstallDir();
 | 
						|
    my $tftpdir       = xCAT::TableUtils->getTftpDir();
 | 
						|
    my $postscripts      = "";
 | 
						|
    my $orig_postscripts = "";
 | 
						|
    # For AIX nodes check NFS
 | 
						|
    my $nfsv4;
 | 
						|
    my @nfsv4 =
 | 
						|
      xCAT::TableUtils->get_site_attribute("useNFSv4onAIX");
 | 
						|
      if ($nfsv4[0] && ($nfsv4[0] =~ /1|Yes|yes|YES|Y|y/)) {
 | 
						|
         $nfsv4 = "yes";
 | 
						|
      } else {
 | 
						|
         $nfsv4 = "no";
 | 
						|
      }
 | 
						|
      my $flowcontrol = 0;
 | 
						|
      my @fc =
 | 
						|
      xCAT::TableUtils->get_site_attribute("useflowcontrol");
 | 
						|
      if ($fc[0] && ($fc[0] =~ /1|Yes|yes|YES|Y|y/)) {
 | 
						|
         $flowcontrol = 1;
 | 
						|
      }
 | 
						|
      # if running postscript report status here, if requested.     
 | 
						|
      if ((defined($request->{status})) && ($request->{status} eq "yes")) {  
 | 
						|
        $::REPORTSTATUS="Y";
 | 
						|
      }
 | 
						|
 | 
						|
      # this drives getdata to report status complete for postscripts
 | 
						|
      $::TYPECALL ="P";
 | 
						|
      if (($request->{postscripts}) && ($request->{postscripts}->[0]))
 | 
						|
      {
 | 
						|
        $orig_postscripts = $request->{postscripts}->[0];
 | 
						|
      }
 | 
						|
        $postscripts = $orig_postscripts;
 | 
						|
 | 
						|
        my $cmd;
 | 
						|
 | 
						|
        # get server names as known by the nodes
 | 
						|
        my %servernodes =
 | 
						|
          %{xCAT::InstUtils->get_server_nodes($callback, \@$nodes)};
 | 
						|
 | 
						|
        # it's possible that the nodes could have diff server names
 | 
						|
        # do all the nodes for a particular server at once
 | 
						|
 | 
						|
        foreach my $snkey (keys %servernodes)
 | 
						|
        {
 | 
						|
            if ((!defined($snkey)) or ($snkey eq "")) {  # if we could not find the xcatmaster 
 | 
						|
                
 | 
						|
                my $rsp = {};
 | 
						|
                $rsp->{error}->[0] = "Could not find xcatmaster for @{$servernodes{$snkey}}. Will skip this node. ";
 | 
						|
                $callback->($rsp);
 | 
						|
                next;
 | 
						|
            }
 | 
						|
            my $nodestring = join(',', @{$servernodes{$snkey}});
 | 
						|
            my $args;
 | 
						|
            my $mode;
 | 
						|
 | 
						|
            #now build the actual updatenode command
 | 
						|
           
 | 
						|
            if (   $request->{rerunps4security}
 | 
						|
                && $request->{rerunps4security}->[0] eq "yes")
 | 
						|
            {
 | 
						|
 | 
						|
                # for updatenode --security
 | 
						|
                $mode = "5";
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
 | 
						|
                # for updatenode -P
 | 
						|
                $mode = "1";
 | 
						|
            }
 | 
						|
            my $args1;
 | 
						|
            # Note order of parameters to xcatdsklspost 
 | 
						|
            #is important and cannot be changed  and calls in this routine and updatenodesoftware
 | 
						|
            # should be kept the same.
 | 
						|
            my $runpscmd;
 | 
						|
            
 | 
						|
            if ($::SETSERVER){  # update the xcatinfo file on the node and run setuppostbootscripts
 | 
						|
               $runpscmd  =
 | 
						|
                    "$installdir/postscripts/xcatdsklspost $mode -M $snkey '$postscripts' --tftp $tftpdir --installdir $installdir --nfsv4 $nfsv4 -c";
 | 
						|
            } else {
 | 
						|
               $runpscmd  =
 | 
						|
                    "$installdir/postscripts/xcatdsklspost $mode -m $snkey '$postscripts' --tftp $tftpdir --installdir $installdir --nfsv4 $nfsv4 -c"
 | 
						|
            }
 | 
						|
            # add flowcontrol flag
 | 
						|
            if ($flowcontrol == 1){
 | 
						|
               $runpscmd .= " -F";
 | 
						|
            }
 | 
						|
 | 
						|
            # add verbose flag
 | 
						|
            if ($::VERBOSE){
 | 
						|
               $runpscmd .= " -V";
 | 
						|
            }
 | 
						|
 | 
						|
            push @$args1,"--nodestatus"; # return nodestatus
 | 
						|
            if (defined($::fanout))  {  # fanout
 | 
						|
             push @$args1,"-f" ;
 | 
						|
             push @$args1,$::fanout;
 | 
						|
            }
 | 
						|
            if (defined($::timeout))  {  # timeout 
 | 
						|
             push @$args1,"-t" ;
 | 
						|
             push @$args1,$::timeout;
 | 
						|
            }
 | 
						|
            if (defined($::USER))  {  # -l contains sudo user
 | 
						|
             push @$args1,"--sudo" ;
 | 
						|
             push @$args1,"-l" ;
 | 
						|
             push @$args1,"$::USER" ;
 | 
						|
            }
 | 
						|
            push @$args1,"-s";  # streaming
 | 
						|
            push @$args1,"-v";  # streaming
 | 
						|
            push @$args1,"-e";  # execute 
 | 
						|
            push @$args1,"$runpscmd"; # the command 
 | 
						|
 | 
						|
 | 
						|
            if ($::VERBOSE)
 | 
						|
            {
 | 
						|
                my $rsp = {};
 | 
						|
                $rsp->{data}->[0] =
 | 
						|
                  "  $localhostname: Internal call command: xdsh $nodestring "
 | 
						|
                  . join(' ', @$args1);
 | 
						|
                $callback->($rsp);
 | 
						|
            }
 | 
						|
 | 
						|
            $CALLBACK = $callback;
 | 
						|
            if ($request->{rerunps4security})
 | 
						|
            {
 | 
						|
                $RERUNPS4SECURITY = $request->{rerunps4security}->[0];
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                $RERUNPS4SECURITY = "";
 | 
						|
            }
 | 
						|
            $subreq->(
 | 
						|
                      {
 | 
						|
                       command           => ["xdsh"],
 | 
						|
                       node              => $servernodes{$snkey},
 | 
						|
                       arg               => $args1,
 | 
						|
                       _xcatpreprocessed => [1]
 | 
						|
                      },
 | 
						|
                      \&getdata
 | 
						|
                      );
 | 
						|
        }
 | 
						|
 | 
						|
 | 
						|
    if (   $request->{rerunps4security}
 | 
						|
        && $request->{rerunps4security}->[0] eq "yes")
 | 
						|
    {
 | 
						|
 | 
						|
        # clean the know_hosts
 | 
						|
        xCAT::Utils->runxcmd(
 | 
						|
                             {
 | 
						|
                              command => ['makeknownhosts'],
 | 
						|
                              node    => \@$nodes,
 | 
						|
                              arg     => ['-r'],
 | 
						|
                             },
 | 
						|
                             $subreq, 0, 1
 | 
						|
                             );
 | 
						|
    }
 | 
						|
    # report final status PCM
 | 
						|
    if ((defined($request->{status})) && ($request->{status} eq "yes")) {
 | 
						|
       my $rsp = {};
 | 
						|
       $rsp->{status}->[0] = "Running of postscripts has completed.";
 | 
						|
       $callback->($rsp);
 | 
						|
    }
 | 
						|
    return;
 | 
						|
}
 | 
						|
 | 
						|
#-------------------------------------------------------------------------------
 | 
						|
 | 
						|
=head3  updatenodesyncfiles  - performs node rsync  updatenode -F  or -f
 | 
						|
 | 
						|
    Arguments: request
 | 
						|
    Returns:
 | 
						|
        0 - for success.
 | 
						|
        1 - for error.
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-----------------------------------------------------------------------------
 | 
						|
sub updatenodesyncfiles
 | 
						|
{
 | 
						|
    my $request            = shift;
 | 
						|
    my $subreq             = shift;
 | 
						|
    my $callback           = shift;
 | 
						|
    my $nodes              = $request->{node};
 | 
						|
    my $localhostname      = hostname();
 | 
						|
    my %syncfile_node      = ();
 | 
						|
    my %syncfile_rootimage = ();
 | 
						|
    # if running -P or -S do not report  or no status requested
 | 
						|
    if ((defined($request->{status})) && ($request->{status} eq "yes")) { # status requested 
 | 
						|
      if (($request->{rerunps} && $request->{rerunps}->[0] eq "yes") ||  
 | 
						|
        ($request->{swmaintenance} && $request->{swmaintenance}->[0] eq "yes")){
 | 
						|
          $::REPORTSTATUS="N";
 | 
						|
      } else {   # report at sync time (-F)
 | 
						|
          $::REPORTSTATUS="Y";
 | 
						|
      }   
 | 
						|
    }   
 | 
						|
        
 | 
						|
    my $node_syncfile      = xCAT::SvrUtils->getsynclistfile($nodes);
 | 
						|
    foreach my $node (@$nodes)
 | 
						|
    {
 | 
						|
        my $synclist = $$node_syncfile{$node};
 | 
						|
 | 
						|
        if ($synclist)
 | 
						|
        {
 | 
						|
        
 | 
						|
            # this can be a comma separated list of multiple
 | 
						|
            # syncfiles
 | 
						|
            my @sl = split(',', $synclist);
 | 
						|
            foreach my $s (@sl)
 | 
						|
            {
 | 
						|
                push @{$syncfile_node{$s}}, $node;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    my $numberofsynclists=0; 
 | 
						|
    if (%syncfile_node)
 | 
						|
    {    # there are files to sync defined
 | 
						|
        # Check the existence of the synclist file , if running from the Management Node
 | 
						|
        # other wise rely on xdcp
 | 
						|
        if (xCAT::Utils->isMN()) {
 | 
						|
          foreach my $synclist (keys %syncfile_node)
 | 
						|
          {
 | 
						|
            if (!(-r $synclist))
 | 
						|
            {
 | 
						|
                my $rsp = {};
 | 
						|
                $rsp->{data}->[0] =
 | 
						|
                  "The file $synclist which is specified to be sync'd to the node does NOT exist.";
 | 
						|
                xCAT::MsgUtils->message("E", $rsp, $callback);
 | 
						|
                return 1;
 | 
						|
            }
 | 
						|
          }
 | 
						|
        }
 | 
						|
 | 
						|
        # Sync files to the target nodes
 | 
						|
        my $output; 
 | 
						|
        foreach my $synclist (keys %syncfile_node)
 | 
						|
        {
 | 
						|
            $numberofsynclists++; 
 | 
						|
            my $args;
 | 
						|
            my $env;
 | 
						|
            if ($request->{SNFileSyncing}->[0] eq "yes") { 
 | 
						|
              push @$args,"-s" ;   # add xdcp -s flag to only sync SN  ( updatenode -f option)
 | 
						|
              $env = ["DSH_RSYNC_FILE=$synclist", "RSYNCSNONLY=1"];
 | 
						|
            } else {   # else this is updatenode -F
 | 
						|
              $env = ["DSH_RSYNC_FILE=$synclist"];
 | 
						|
            }
 | 
						|
            push @$args,"--nodestatus" ;
 | 
						|
            if (defined($::fanout))  {  # fanout
 | 
						|
             push @$args,"-f" ;
 | 
						|
             push @$args,$::fanout;
 | 
						|
            }
 | 
						|
            if (defined($::timeout))  {  # timeout 
 | 
						|
             push @$args,"-t" ;
 | 
						|
             push @$args,$::timeout;
 | 
						|
            }
 | 
						|
            if (defined($::USER))  {  # -l must sudo
 | 
						|
             push @$args,"--sudo" ;
 | 
						|
             push @$args,"-l" ;
 | 
						|
             push @$args,"$::USER" ;
 | 
						|
            }
 | 
						|
            push @$args,"-F" ;
 | 
						|
            push @$args,"$synclist" ;
 | 
						|
            my $nodestring = join(',', @{$syncfile_node{$synclist}});
 | 
						|
 | 
						|
            if ($::VERBOSE)
 | 
						|
            {
 | 
						|
                my $rsp = {};
 | 
						|
                $rsp->{data}->[0] =
 | 
						|
                  "  $localhostname: Internal call command: xdcp $nodestring " . join(' ', @$args);
 | 
						|
                $callback->($rsp);
 | 
						|
            }
 | 
						|
 | 
						|
            $CALLBACK = $callback;
 | 
						|
 | 
						|
 | 
						|
           $output =
 | 
						|
             xCAT::Utils->runxcmd(
 | 
						|
                   {
 | 
						|
                     command => ["xdcp"],
 | 
						|
                     node    => $syncfile_node{$synclist},
 | 
						|
                     arg     => $args,
 | 
						|
                     env     => $env
 | 
						|
                   },
 | 
						|
                   $subreq, -1,1);
 | 
						|
 | 
						|
           # build the list of good and bad nodes
 | 
						|
           &buildnodestatus(\@$output,$callback);
 | 
						|
	     }
 | 
						|
   	
 | 
						|
       if ($request->{SNFileSyncing}->[0] eq "yes") { 
 | 
						|
          my $rsp = {};
 | 
						|
          $rsp->{data}->[0] = "File synchronization has completed for service nodes.";
 | 
						|
          $callback->($rsp);
 | 
						|
       }
 | 
						|
       if ($request->{FileSyncing}->[0] eq "yes") { 
 | 
						|
          my $rsp = {};
 | 
						|
          $rsp->{data}->[0] = "File synchronization has completed for nodes.";
 | 
						|
          $callback->($rsp);
 | 
						|
       }
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {    # no syncfiles defined
 | 
						|
        my $rsp = {};
 | 
						|
        $rsp->{data}->[0] =
 | 
						|
          "There were no syncfiles defined to process. File synchronization has completed.";
 | 
						|
        $callback->($rsp);
 | 
						|
        my $stat="synced";
 | 
						|
        xCAT::TableUtils->setUpdateStatus(\@$nodes, $stat);
 | 
						|
 | 
						|
    }
 | 
						|
    # report final status PCM
 | 
						|
    if ((defined($request->{status})) && ($request->{status} eq "yes")) {
 | 
						|
       my $rsp = {};
 | 
						|
       $rsp->{status}->[0] = "File synchronization has completed.";
 | 
						|
       $callback->($rsp);
 | 
						|
    }
 | 
						|
 | 
						|
    return;
 | 
						|
}
 | 
						|
#-------------------------------------------------------------------------------
 | 
						|
=head3  buildnodestatus - Takes the output of the updatenode run
 | 
						|
        and builds a global array of successfull nodes  and one of failed nodes
 | 
						|
        and then outputs the remaining user info
 | 
						|
 | 
						|
    Arguments: output,callback
 | 
						|
    Globals @::SUCCESSFULLNODES,  @::FAILEDNODE  
 | 
						|
    $::REPORTSTATUS  if "Y" then imediately return status in $::CALLERCALLBACK (PCM)
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
 | 
						|
#-----------------------------------------------------------------------------
 | 
						|
sub buildnodestatus
 | 
						|
{
 | 
						|
    my $output       = shift;
 | 
						|
    my $callback      = shift;
 | 
						|
    my @userinfo=();
 | 
						|
    # determine if the sync was successful or not
 | 
						|
	 foreach my $line (@$output) {
 | 
						|
	   if($line =~ /^\s*(\S+)\s*:\s*Remote_command_successful/)
 | 
						|
	   {
 | 
						|
         my ($node,$info) = split (/:/, $line);
 | 
						|
         if ($::REPORTSTATUS eq "Y" ) { # return status NOW
 | 
						|
           if (grep(/^$node$/, @::FAILEDNODES)) {  # already on the fail buffer
 | 
						|
              my $rsp2 = {};  # report failed
 | 
						|
              $rsp2->{status}->[0] = "$node: FAILED";
 | 
						|
              $::CALLERCALLBACK->($rsp2); 
 | 
						|
              # update the nodelist table updatestatus flag for the node
 | 
						|
              my $stat="failed";
 | 
						|
              my @nodearray=();
 | 
						|
              push @nodearray,$node;
 | 
						|
              xCAT::TableUtils->setUpdateStatus(\@nodearray, $stat);
 | 
						|
           } else {  # completely successful
 | 
						|
              my $rsp2 = {};
 | 
						|
              $rsp2->{status}->[0] = "$node: SUCCEEDED";
 | 
						|
              $::CALLERCALLBACK->($rsp2); 
 | 
						|
              # update the nodelist table updatestatus flag for the node
 | 
						|
              my $stat="synced";
 | 
						|
              my @nodearray=();
 | 
						|
              push @nodearray,$node;
 | 
						|
              xCAT::TableUtils->setUpdateStatus(\@nodearray, $stat);
 | 
						|
           }
 | 
						|
         }
 | 
						|
         if (grep(/^$node$/, @::SUCCESSFULLNODES)) {  # already on the buffer
 | 
						|
		     next; 
 | 
						|
         } else {
 | 
						|
		     push(@::SUCCESSFULLNODES,$node); 
 | 
						|
         }
 | 
						|
	   }
 | 
						|
      elsif($line =~ /^\s*(\S+)\s*:\s*Remote_command_failed/)
 | 
						|
	   {
 | 
						|
         my ($node,$info)= split (/:/, $line);
 | 
						|
         if ($::REPORTSTATUS eq "Y" ) { # return status NOW 
 | 
						|
              my $rsp2 = {};
 | 
						|
              $rsp2->{status}->[0] = "$node: FAILED";
 | 
						|
              $::CALLERCALLBACK->($rsp2); 
 | 
						|
              # update the nodelist table updatestatus flag for the node
 | 
						|
              my $stat="failed";
 | 
						|
              my @nodearray=();
 | 
						|
              push @nodearray,$node;
 | 
						|
              xCAT::TableUtils->setUpdateStatus(\@nodearray, $stat);
 | 
						|
         }
 | 
						|
         if (grep(/^$node$/, @::FAILEDNODES)) {  # already on the buffer
 | 
						|
		     next; 
 | 
						|
         } else {
 | 
						|
	         push(@::FAILEDNODES,$node);
 | 
						|
	      }	
 | 
						|
	   }	
 | 
						|
      else  
 | 
						|
	   {
 | 
						|
	      push(@userinfo,$line);   # user data
 | 
						|
	   }	
 | 
						|
	 }
 | 
						|
    # output user data 
 | 
						|
    if (@userinfo) {
 | 
						|
        foreach my $line (@userinfo) {
 | 
						|
           my $rsp = {};
 | 
						|
           $rsp->{data}->[0] = $line;
 | 
						|
           $callback->($rsp);
 | 
						|
	     }
 | 
						|
	 }
 | 
						|
 | 
						|
  return;
 | 
						|
}
 | 
						|
#-------------------------------------------------------------------------------
 | 
						|
=head3  cleanstatusarrays
 | 
						|
    Makes sure no Failed nodes are in the successfull nodes list
 | 
						|
    Removes dups
 | 
						|
    Globals @::SUCCESSFULLNODES,  @::FAILEDNODES
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
 | 
						|
#-----------------------------------------------------------------------------
 | 
						|
sub cleanstatusarrays 
 | 
						|
{
 | 
						|
    my %m=();
 | 
						|
    my %n=();
 | 
						|
 | 
						|
    for(@::FAILEDNODES)
 | 
						|
    {
 | 
						|
       $m{$_}++;
 | 
						|
    }
 | 
						|
    for(@::SUCCESSFULLNODES)
 | 
						|
    {
 | 
						|
        $m{$_}++ || $n{$_}++;
 | 
						|
    }
 | 
						|
    @::SUCCESSFULLNODES=keys %n;
 | 
						|
  return;
 | 
						|
}
 | 
						|
#-------------------------------------------------------------------------------
 | 
						|
 | 
						|
=head3  updatenodesoftware  - software updates  updatenode -S
 | 
						|
 | 
						|
    Arguments: request, subreq,callback,imgdefs,updates
 | 
						|
    Returns:
 | 
						|
        0 - for success.
 | 
						|
        1 - for error.
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-----------------------------------------------------------------------------
 | 
						|
sub updatenodesoftware
 | 
						|
{
 | 
						|
    my $request       = shift;
 | 
						|
    my $subreq        = shift;
 | 
						|
    my $callback      = shift;
 | 
						|
    my $imgdefs       = shift;
 | 
						|
    my $updates       = shift;
 | 
						|
    my $nodes         = $request->{node};
 | 
						|
    my $installdir    = xCAT::TableUtils->getInstallDir();
 | 
						|
    my $tftpdir       = xCAT::TableUtils->getTftpDir();
 | 
						|
    my $localhostname = hostname();
 | 
						|
    my $rsp;
 | 
						|
    my $nfsv4 = "no";  # AIX only but set to keep the xcatdsklspost call the same for -F and -S
 | 
						|
    # Determine when to report status, do not report it here if -P is to run
 | 
						|
    if ((defined($request->{status})) && ($request->{status} eq "yes")) { # if status requested 
 | 
						|
      if ($request->{rerunps} && $request->{rerunps}->[0] eq "yes") {  # (-P) running postscripts
 | 
						|
        $::REPORTSTATUS="N";
 | 
						|
      } else {
 | 
						|
        $::REPORTSTATUS="Y";
 | 
						|
      }   
 | 
						|
    }   
 | 
						|
    my $flowcontrol = 0;
 | 
						|
    my @fc =
 | 
						|
    xCAT::TableUtils->get_site_attribute("useflowcontrol");
 | 
						|
    if ($fc[0] && ($fc[0] =~ /1|Yes|yes|YES|Y|y/)) {
 | 
						|
        $flowcontrol = 1;
 | 
						|
    }
 | 
						|
 | 
						|
    # this drives getdata to report status complete for software updatees 
 | 
						|
    $::TYPECALL ="S";
 | 
						|
 | 
						|
    $CALLBACK = $callback;
 | 
						|
    push @{$rsp->{data}},
 | 
						|
      "Performing software maintenance operations. This could take a while, if there are packages to install.\n";
 | 
						|
    xCAT::MsgUtils->message("I", $rsp, $callback);
 | 
						|
 | 
						|
    my ($rc, $AIXnodes_nd, $Linuxnodes_nd) =
 | 
						|
      xCAT::InstUtils->getOSnodes($nodes);
 | 
						|
 | 
						|
    #
 | 
						|
    #   do linux nodes
 | 
						|
    #
 | 
						|
    if (scalar(@$Linuxnodes_nd))
 | 
						|
    {    # we have a list of linux nodes
 | 
						|
        my $cmd;
 | 
						|
 | 
						|
        # get server names as known by the nodes
 | 
						|
        my %servernodes =
 | 
						|
          %{xCAT::InstUtils->get_server_nodes($callback, \@$Linuxnodes_nd)};
 | 
						|
 | 
						|
        # it's possible that the nodes could have diff server names
 | 
						|
        # do all the nodes for a particular server at once
 | 
						|
        # Note order of parameters to xcatdsklspost 
 | 
						|
        #is important and cannot be changed  and calls in this routine and updatenoderunps
 | 
						|
        # should be kept the same.
 | 
						|
        foreach my $snkey (keys %servernodes)
 | 
						|
        {
 | 
						|
            my $nodestring = join(',', @{$servernodes{$snkey}});
 | 
						|
            my $cmd;
 | 
						|
            my $args1;
 | 
						|
            $cmd =
 | 
						|
                  "$installdir/postscripts/xcatdsklspost 2 -m $snkey 'ospkgs,otherpkgs,syscloneimgupdate' --tftp $tftpdir --installdir $installdir --nfsv4 $nfsv4 -c";
 | 
						|
            # add flowcontrol flag
 | 
						|
            if ($flowcontrol == 1){
 | 
						|
               $cmd .= " -F";
 | 
						|
            }
 | 
						|
            # add verbose flag
 | 
						|
            if ($::VERBOSE){
 | 
						|
               $cmd .= " -V";
 | 
						|
            }
 | 
						|
    
 | 
						|
            # build xdsh command
 | 
						|
            push @$args1,"--nodestatus"; # return nodestatus
 | 
						|
            if (defined($::fanout))  {  # fanout
 | 
						|
             push @$args1,"-f" ;
 | 
						|
             push @$args1,$::fanout;
 | 
						|
            }
 | 
						|
            if (defined($::timeout))  {  # timeout 
 | 
						|
             push @$args1,"-t" ;
 | 
						|
             push @$args1,$::timeout;
 | 
						|
            }
 | 
						|
            if (defined($::USER))  {  # -l contains sudo user
 | 
						|
             push @$args1,"--sudo" ;
 | 
						|
             push @$args1,"-l" ;
 | 
						|
             push @$args1,"$::USER" ;
 | 
						|
            }
 | 
						|
            push @$args1,"-s";  # streaming
 | 
						|
            push @$args1,"-v";  # streaming
 | 
						|
            push @$args1,"-e";  # execute 
 | 
						|
            push @$args1,"$cmd"; # the command 
 | 
						|
 | 
						|
 | 
						|
 | 
						|
            if ($::VERBOSE)
 | 
						|
            {
 | 
						|
                my $rsp = {};
 | 
						|
                $rsp->{data}->[0] =
 | 
						|
                  "  $localhostname: Internal call command: xdsh $nodestring "
 | 
						|
                  . join(' ', @$args1);
 | 
						|
                $callback->($rsp);
 | 
						|
            }
 | 
						|
            $subreq->(
 | 
						|
                      {
 | 
						|
                       command           => ["xdsh"],
 | 
						|
                       node              => $servernodes{$snkey},
 | 
						|
                       arg               => $args1,
 | 
						|
                       _xcatpreprocessed => [1]
 | 
						|
                      },
 | 
						|
                      \&getdata
 | 
						|
                      );
 | 
						|
 | 
						|
 | 
						|
        }
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
    #
 | 
						|
    #   do AIX nodes
 | 
						|
    #
 | 
						|
 | 
						|
    if (scalar(@$AIXnodes_nd))
 | 
						|
    {
 | 
						|
 | 
						|
        # update the software on an AIX node
 | 
						|
        if (
 | 
						|
            &updateAIXsoftware(
 | 
						|
                               $callback, \%::attrres,  $imgdefs,
 | 
						|
                               $updates,  $AIXnodes_nd, $subreq
 | 
						|
            ) != 0
 | 
						|
          )
 | 
						|
        {
 | 
						|
 | 
						|
            #		my $rsp;
 | 
						|
            #		push @{$rsp->{data}},  "Could not update software for AIX nodes \'@$AIXnodes\'.";
 | 
						|
            #		xCAT::MsgUtils->message("E", $rsp, $callback);;
 | 
						|
            return 1;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    # report final status PCM
 | 
						|
    if ((defined($request->{status})) && ($request->{status} eq "yes")) {
 | 
						|
       my $rsp = {};
 | 
						|
       $rsp->{status}->[0] = "Running of Software maintenance has completed.";
 | 
						|
       $callback->($rsp);
 | 
						|
    }
 | 
						|
 | 
						|
    return;
 | 
						|
}
 | 
						|
#-------------------------------------------------------------------------------
 | 
						|
 | 
						|
=head3  getdata  - This is the local callback that handles the response from
 | 
						|
        the xdsh streaming calls when running postscripts(-P) and software updates (-S)
 | 
						|
        $::TYPECALL = P  from postscripts runs or S from Software updates
 | 
						|
        $::CALLERCALLBACK  = saved callback from calling routine  
 | 
						|
        $::REPORTSTATUS, if Y,  return the good/bad status right away from this
 | 
						|
                         routine  to the $::CALLERCALLBACK ( PCM)
 | 
						|
 | 
						|
=cut
 | 
						|
#-------------------------------------------------------------------------------
 | 
						|
sub getdata
 | 
						|
{
 | 
						|
    no strict;
 | 
						|
    my $response = shift;
 | 
						|
    my $rsp;
 | 
						|
    foreach my $type (keys %$response)
 | 
						|
    {
 | 
						|
        my $alreadyinstalled=0;
 | 
						|
        foreach my $output (@{$response->{$type}})
 | 
						|
        {
 | 
						|
            chomp($output);
 | 
						|
            $output =~ s/\\cM//;
 | 
						|
            if($output =~ /^\s*(\S+)\s*:\s*Remote_command_successful/)
 | 
						|
            {
 | 
						|
              my ($node,$info) = split (/:/, $output);
 | 
						|
              if ($::REPORTSTATUS eq "Y" ) { # return status NOW 
 | 
						|
               if (grep(/^$node$/, @::FAILEDNODES)) {  # already on the fail buffer
 | 
						|
                  my $rsp2 = {};  # report failed
 | 
						|
                  $rsp2->{status}->[0] = "$node: FAILED";
 | 
						|
                  $::CALLERCALLBACK->($rsp2); 
 | 
						|
                  # update the nodelist table updatestatus flag for the node
 | 
						|
                  my $stat="failed";
 | 
						|
                  my @nodearray=();
 | 
						|
                  push @nodearray,$node;
 | 
						|
                  xCAT::TableUtils->setUpdateStatus(\@nodearray, $stat);
 | 
						|
               } else {  # completely successful
 | 
						|
                   my $rsp2 = {};
 | 
						|
                   $rsp2->{status}->[0] = "$node: SUCCEEDED";
 | 
						|
                   $::CALLERCALLBACK->($rsp2); 
 | 
						|
                   # update the nodelist table updatestatus flag for the node
 | 
						|
                   my $stat="synced";
 | 
						|
                   my @nodearray=();
 | 
						|
                   push @nodearray,$node;
 | 
						|
                   xCAT::TableUtils->setUpdateStatus(\@nodearray, $stat);
 | 
						|
               }
 | 
						|
              }
 | 
						|
              if (grep(/^$node$/, @::SUCCESSFULLNODES)) {  # already on the buffer
 | 
						|
		            next; 
 | 
						|
              } else {
 | 
						|
		           push(@::SUCCESSFULLNODES,$node); 
 | 
						|
              }
 | 
						|
            }
 | 
						|
            # check for already installed on software updates, this is not an error
 | 
						|
            if($output =~ /^\s*(\S+)\s*:\s*already installed/)
 | 
						|
            {
 | 
						|
              $alreadyinstalled = 1;
 | 
						|
            }
 | 
						|
 | 
						|
            if($output =~ /^\s*(\S+)\s*:\s*Remote_command_failed/)
 | 
						|
            {
 | 
						|
              my ($node,$info) = split (/:/, $output);
 | 
						|
              if ($alreadyinstalled == 0) { # not an already install error, then real error 
 | 
						|
                if ($::REPORTSTATUS eq "Y" ) { # return status NOW 
 | 
						|
                    my $rsp2 = {};
 | 
						|
                    $rsp2->{status}->[0] = "$node: FAILED";
 | 
						|
                    $::CALLERCALLBACK->($rsp2); 
 | 
						|
                    # update the nodelist table updatestatus flag for the node
 | 
						|
                    my $stat="failed";
 | 
						|
                    my @nodearray=();
 | 
						|
                    push @nodearray,$node;
 | 
						|
                    xCAT::TableUtils->setUpdateStatus(\@nodearray, $stat);
 | 
						|
                }
 | 
						|
                if (grep(/^$node$/, @::FAILEDNODES)) {  # already on the buffer
 | 
						|
		            next; 
 | 
						|
                } else {
 | 
						|
                  push(@::FAILEDNODES,$node);
 | 
						|
                }
 | 
						|
              } else {   # already installed is ok
 | 
						|
                  if ($::REPORTSTATUS eq "Y" ) { # return status NOW 
 | 
						|
                    if (grep(/^$node$/, @::FAILEDNODES)) {  # already on the fail buffer
 | 
						|
                      my $rsp2 = {};  # report failed
 | 
						|
                      $rsp2->{status}->[0] = "$node: FAILED";
 | 
						|
                      $::CALLERCALLBACK->($rsp2); 
 | 
						|
                      # update the nodelist table updatestatus flag for the node
 | 
						|
                      my $stat="failed";
 | 
						|
                      my @nodearray=();
 | 
						|
                      push @nodearray,$node;
 | 
						|
                      xCAT::TableUtils->setUpdateStatus(\@nodearray, $stat);
 | 
						|
                   } else {  # completely successful
 | 
						|
                      my $rsp2 = {};
 | 
						|
                      $rsp2->{status}->[0] = "$node: SUCCEEDED";
 | 
						|
                      $::CALLERCALLBACK->($rsp2); 
 | 
						|
                      # update the nodelist table updatestatus flag for the node
 | 
						|
                      my $stat="synced";
 | 
						|
                      my @nodearray=();
 | 
						|
                      push @nodearray,$node;
 | 
						|
                      xCAT::TableUtils->setUpdateStatus(\@nodearray, $stat);
 | 
						|
                   }
 | 
						|
                  }
 | 
						|
                  if (grep(/^$node$/, @::SUCCESSFULLNODES)) {  # already on the buffer
 | 
						|
	                   next; 
 | 
						|
                  } else {
 | 
						|
		               push(@::SUCCESSFULLNODES,$node); 
 | 
						|
                 }
 | 
						|
              }
 | 
						|
            }
 | 
						|
 | 
						|
 | 
						|
            if ($output =~ /returned from postscript/)
 | 
						|
            {
 | 
						|
              if ($::TYPECALL eq "P") {  # -P flag
 | 
						|
                $output =~
 | 
						|
                  s/returned from postscript/Running of postscripts has completed./;
 | 
						|
              } else {  # should be -S flag 
 | 
						|
                $output =~
 | 
						|
                   s/returned from postscript/Running of Software Maintenance has completed./;
 | 
						|
              }
 | 
						|
            }
 | 
						|
            if ($RERUNPS4SECURITY && $RERUNPS4SECURITY eq "yes")
 | 
						|
            {
 | 
						|
                if ($output =~ /Running of postscripts has completed/)
 | 
						|
                {
 | 
						|
                    $output =~
 | 
						|
                      s/Running of postscripts has completed/Redeliver security files has completed/;
 | 
						|
                    push @{$rsp->{$type}}, $output;
 | 
						|
                } else {
 | 
						|
                   if (($output !~ (/Running postscript/)) && ($output !~ (/Error loading module/)) && ($output !~ /^\s*(\S+)\s*:\s*Remote_command_successful/) && ($output !~ /^\s*(\S+)\s*:\s*Remote_command_failed/))
 | 
						|
                   {
 | 
						|
                    push @{$rsp->{$type}}, "$output";
 | 
						|
                   }
 | 
						|
                }
 | 
						|
            } else{  # for non -k option then get the rest of the output
 | 
						|
              if (($output !~ (/Error loading module/)) && ($output !~ /^\s*(\S+)\s*:\s*Remote_command_successful/) && ($output !~ /^\s*(\S+)\s*:\s*Remote_command_failed/))
 | 
						|
              {
 | 
						|
                push @{$rsp->{$type}}, "$output";
 | 
						|
              }
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
    $CALLBACK->($rsp);
 | 
						|
}
 | 
						|
 | 
						|
#-------------------------------------------------------------------------------
 | 
						|
 | 
						|
=head3   updatenodestat
 | 
						|
 | 
						|
    Arguments:
 | 
						|
    Returns:
 | 
						|
        0 - for success.
 | 
						|
        1 - for error.
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-----------------------------------------------------------------------------
 | 
						|
sub updatenodestat
 | 
						|
{
 | 
						|
    my $request  = shift;
 | 
						|
    my $callback = shift;
 | 
						|
    my @nodes    = ();
 | 
						|
    my @args     = ();
 | 
						|
    if (ref($request->{node}))
 | 
						|
    {
 | 
						|
        @nodes = @{$request->{node}};
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        if ($request->{node}) { @nodes = ($request->{node}); }
 | 
						|
        else
 | 
						|
        {    #client asking to update its own status...
 | 
						|
            unless (ref $request->{username})
 | 
						|
            {
 | 
						|
                return;
 | 
						|
            }    #TODO: log an attempt without credentials?
 | 
						|
            @nodes = @{$request->{username}};
 | 
						|
        }
 | 
						|
    }
 | 
						|
    if (ref($request->{arg}))
 | 
						|
    {
 | 
						|
        @args = @{$request->{arg}};
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        @args = ($request->{arg});
 | 
						|
    }
 | 
						|
 | 
						|
    if ((@nodes > 0) && (@args > 0))
 | 
						|
    {
 | 
						|
        my %node_status = ();
 | 
						|
        my $stat        = $args[0];
 | 
						|
        unless ($::VALID_STATUS_VALUES{$stat})
 | 
						|
        {
 | 
						|
            return;
 | 
						|
        }    #don't accept just any string, see GlobalDef for updates
 | 
						|
        $node_status{$stat} = [];
 | 
						|
        foreach my $node (@nodes)
 | 
						|
        {
 | 
						|
 | 
						|
            my $pa = $node_status{$stat};
 | 
						|
            push(@$pa, $node);
 | 
						|
        }
 | 
						|
        xCAT_monitoring::monitorctrl::setNodeStatusAttributes(\%node_status, 1);
 | 
						|
    }
 | 
						|
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
#-------------------------------------------------------------------------------
 | 
						|
 | 
						|
=head3   doAIXcopy
 | 
						|
 | 
						|
    Copy software update files to SNs - if needed.
 | 
						|
 | 
						|
    Arguments:
 | 
						|
 | 
						|
    Returns:
 | 
						|
		errors:
 | 
						|
      		0 - OK
 | 
						|
      		1 - error
 | 
						|
		hash refs:
 | 
						|
			- osimage definitions
 | 
						|
			- node update information
 | 
						|
 | 
						|
    Example
 | 
						|
	 my ($rc, $imagedef, $updateinfo) = &doAIXcopy($callback, \%attrvals, 
 | 
						|
			$nodes, $subreq);
 | 
						|
 | 
						|
    Comments:
 | 
						|
        - running on MN
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#------------------------------------------------------------------------------
 | 
						|
sub doAIXcopy
 | 
						|
{
 | 
						|
    my $callback = shift;
 | 
						|
    my $av       = shift;
 | 
						|
    my $nodes    = shift;
 | 
						|
    my $subreq   = shift;
 | 
						|
 | 
						|
    my @nodelist;    # node list
 | 
						|
    my %attrvals;    # cmd line attr=val pairs
 | 
						|
 | 
						|
    if ($nodes)
 | 
						|
    {
 | 
						|
        @nodelist = @$nodes;
 | 
						|
    }
 | 
						|
 | 
						|
    if ($av)
 | 
						|
    {
 | 
						|
        %attrvals = %{$av};
 | 
						|
    }
 | 
						|
    if (defined($::USER)){ # not supported on AIX
 | 
						|
     		my $rsp;
 | 
						|
         $rsp->{error}->[0] = " The -l option is not supported on AIX";
 | 
						|
     		xCAT::MsgUtils->message("E", $rsp, $callback);;
 | 
						|
         return 1;
 | 
						|
    } 
 | 
						|
 | 
						|
    # get the NIM primary server name
 | 
						|
    my $nimprime = xCAT::InstUtils->getnimprime();
 | 
						|
    chomp $nimprime;
 | 
						|
 | 
						|
    my %nodeupdateinfo;
 | 
						|
 | 
						|
    #
 | 
						|
    # do we have to copy files to any SNs????
 | 
						|
    #
 | 
						|
 | 
						|
    # get a list of service nodes for this node list
 | 
						|
    my $sn = xCAT::ServiceNodeUtils->get_ServiceNode(\@nodelist, "xcat", "MN");
 | 
						|
    if ($::ERROR_RC)
 | 
						|
    {
 | 
						|
        my $rsp;
 | 
						|
        push @{$rsp->{data}}, "Could not get list of xCAT service nodes.";
 | 
						|
        xCAT::MsgUtils->message("E", $rsp, $callback);
 | 
						|
        return 1;
 | 
						|
    }
 | 
						|
 | 
						|
    # want list of remote service nodes - to copy files to
 | 
						|
 | 
						|
    # get the ip of the NIM primary (normally the management node)
 | 
						|
    my $ip = xCAT::NetworkUtils->getipaddr($nimprime);
 | 
						|
    chomp $ip;
 | 
						|
    my ($p1, $p2, $p3, $p4) = split /\./, $ip;
 | 
						|
 | 
						|
    my @SNlist;
 | 
						|
    foreach my $snkey (keys %$sn)
 | 
						|
    {
 | 
						|
 | 
						|
        my $sip = xCAT::NetworkUtils->getipaddr($snkey);
 | 
						|
        chomp $sip;
 | 
						|
        if ($ip eq $sip)
 | 
						|
        {
 | 
						|
            next;
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            if (!grep(/^$snkey$/, @SNlist))
 | 
						|
            {
 | 
						|
                push(@SNlist, $snkey);
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    # get a list of osimage names needed for the nodes
 | 
						|
    my $nodetab = xCAT::Table->new('nodetype');
 | 
						|
    my $images  =
 | 
						|
      $nodetab->getNodesAttribs(\@nodelist, ['node', 'provmethod', 'profile']);
 | 
						|
    my @imagenames;
 | 
						|
    my @noimage;
 | 
						|
    foreach my $node (@nodelist)
 | 
						|
    {
 | 
						|
        my $imgname;
 | 
						|
        if ($images->{$node}->[0]->{provmethod})
 | 
						|
        {
 | 
						|
            $imgname = $images->{$node}->[0]->{provmethod};
 | 
						|
        }
 | 
						|
        elsif ($images->{$node}->[0]->{profile})
 | 
						|
        {
 | 
						|
            $imgname = $images->{$node}->[0]->{profile};
 | 
						|
        }
 | 
						|
 | 
						|
        if (!$imgname)
 | 
						|
        {
 | 
						|
            push @noimage, $node;
 | 
						|
        }
 | 
						|
        elsif (!grep(/^$imgname$/, @imagenames))
 | 
						|
        {
 | 
						|
            push @imagenames, $imgname;
 | 
						|
        }
 | 
						|
        $nodeupdateinfo{$node}{imagename} = $imgname;
 | 
						|
    }
 | 
						|
    $nodetab->close;
 | 
						|
 | 
						|
    if (@noimage)
 | 
						|
    {
 | 
						|
        my $rsp;
 | 
						|
        my $allnodes = join(',', @noimage);
 | 
						|
        push @{$rsp->{data}},
 | 
						|
          "No osimage specified for the following nodes: $allnodes. You can try to run the nimnodeset command or set the profile|provmethod attributes manually.";
 | 
						|
        xCAT::MsgUtils->message("E", $rsp, $callback);
 | 
						|
        return 1;
 | 
						|
    }
 | 
						|
 | 
						|
    my $osimageonly = 0;
 | 
						|
    if ((!$attrvals{installp_bundle} && !$attrvals{otherpkgs}) && !$::CMDLINE)
 | 
						|
    {
 | 
						|
 | 
						|
        # if nothing is provided on the cmd line and we don't set CMDLINE
 | 
						|
        #	then we just use the osimage def - used for permanent updates
 | 
						|
        $osimageonly = 1;
 | 
						|
    }
 | 
						|
 | 
						|
    #
 | 
						|
    #  get the osimage defs
 | 
						|
    #
 | 
						|
    my %imagedef;
 | 
						|
    my @pkglist;    # list of all software to go to SNs
 | 
						|
    my %bndloc;
 | 
						|
 | 
						|
    foreach my $img (@imagenames)
 | 
						|
    {
 | 
						|
        my %objtype;
 | 
						|
        $objtype{$img} = 'osimage';
 | 
						|
        %imagedef = xCAT::DBobjUtils->getobjdefs(\%objtype, $callback);
 | 
						|
        if (!(%imagedef))
 | 
						|
        {
 | 
						|
            my $rsp;
 | 
						|
            push @{$rsp->{data}},
 | 
						|
              "Could not get the xCAT osimage definition for \'$img\'.\n";
 | 
						|
            xCAT::MsgUtils->message("E", $rsp, $callback);
 | 
						|
            return 1;
 | 
						|
        }
 | 
						|
 | 
						|
        #
 | 
						|
        #  if this is not a "standalone" type image then this is an error
 | 
						|
        #
 | 
						|
        if ($imagedef{$img}{nimtype} ne "standalone")
 | 
						|
        {
 | 
						|
            my $rsp;
 | 
						|
            push @{$rsp->{data}},
 | 
						|
              "The osimage \'$img\' is not a standalone type.  \nThe software maintenance function of updatenode command can only be used for standalone (diskfull) type nodes. \nUse the mknimimage comamand to update diskless osimages.";
 | 
						|
            xCAT::MsgUtils->message("E", $rsp, $callback);
 | 
						|
            return 1;
 | 
						|
        }
 | 
						|
 | 
						|
        # if we're not using the os image
 | 
						|
        if ($osimageonly != 1)
 | 
						|
        {
 | 
						|
 | 
						|
            # set the imagedef to the cmd line values
 | 
						|
            if ($attrvals{installp_bundle})
 | 
						|
            {
 | 
						|
                $imagedef{$img}{installp_bundle} = $attrvals{installp_bundle};
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                $imagedef{$img}{installp_bundle} = "";
 | 
						|
            }
 | 
						|
            if ($attrvals{otherpkgs})
 | 
						|
            {
 | 
						|
                $imagedef{$img}{otherpkgs} = $attrvals{otherpkgs};
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                $imagedef{$img}{otherpkgs} = "";
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        if ($attrvals{installp_flags})
 | 
						|
        {
 | 
						|
            $imagedef{$img}{installp_flags} = $attrvals{installp_flags};
 | 
						|
        }
 | 
						|
 | 
						|
        if ($attrvals{rpm_flags})
 | 
						|
        {
 | 
						|
            $imagedef{$img}{rpm_flags} = $attrvals{rpm_flags};
 | 
						|
        }
 | 
						|
 | 
						|
        if ($attrvals{emgr_flags})
 | 
						|
        {
 | 
						|
            $imagedef{$img}{emgr_flags} = $attrvals{emgr_flags};
 | 
						|
        }
 | 
						|
 | 
						|
        # get loc of software for node
 | 
						|
        if ($::ALTSRC)
 | 
						|
        {
 | 
						|
            $imagedef{$img}{alt_loc} = $::ALTSRC;
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
            if ($imagedef{$img}{lpp_source})
 | 
						|
            {
 | 
						|
                $imagedef{$img}{lpp_loc} =
 | 
						|
                  xCAT::InstUtils->get_nim_attr_val($imagedef{$img}{lpp_source},
 | 
						|
                                     'location', $callback, $nimprime, $subreq);
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                $imagedef{$img}{lpp_loc} = "";
 | 
						|
                next;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        if ($::ALLSW)
 | 
						|
        {
 | 
						|
 | 
						|
            # get a list of all the files in the location
 | 
						|
            # if its an alternate loc than just check that dir
 | 
						|
            # if it's an lpp_source than check both RPM and installp
 | 
						|
            my $rpmloc;
 | 
						|
            my $instploc;
 | 
						|
            my $emgrloc;
 | 
						|
            if ($::ALTSRC)
 | 
						|
            {
 | 
						|
 | 
						|
                # use same loc for everything
 | 
						|
                $rpmloc = $instploc = $imagedef{$img}{alt_loc};
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
 | 
						|
                # use specific lpp_source loc
 | 
						|
                $rpmloc   = "$imagedef{$img}{lpp_loc}/RPMS/ppc";
 | 
						|
                $instploc = "$imagedef{$img}{lpp_loc}/installp/ppc";
 | 
						|
                $emgrloc  = "$imagedef{$img}{lpp_loc}/emgr/ppc";
 | 
						|
            }
 | 
						|
 | 
						|
            # get installp filesets in this dir
 | 
						|
            my $icmd =
 | 
						|
              qq~installp -L -d $instploc | /usr/bin/cut -f1 -d':' 2>/dev/null~;
 | 
						|
            my @ilist = xCAT::Utils->runcmd("$icmd", -1);
 | 
						|
            foreach my $f (@ilist)
 | 
						|
            {
 | 
						|
                if (!grep(/^$f$/, @pkglist))
 | 
						|
                {
 | 
						|
                    push(@pkglist, $f);
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            # get epkg files
 | 
						|
            my $ecmd = qq~/usr/bin/ls $emgrloc 2>/dev/null~;
 | 
						|
            my @elist = xCAT::Utils->runcmd("$ecmd", -1);
 | 
						|
            foreach my $f (@elist)
 | 
						|
            {
 | 
						|
                if (($f =~ /epkg\.Z/))
 | 
						|
                {
 | 
						|
                    push(@pkglist, $f);
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            # get rpm packages
 | 
						|
            my $rcmd = qq~/usr/bin/ls $rpmloc 2>/dev/null~;
 | 
						|
            my @rlist = xCAT::Utils->runcmd("$rcmd", -1);
 | 
						|
            foreach my $f (@rlist)
 | 
						|
            {
 | 
						|
                if ($f =~ /\.rpm/)
 | 
						|
                {
 | 
						|
                    push(@pkglist, $f);
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
 | 
						|
            # use otherpkgs and or installp_bundle
 | 
						|
 | 
						|
            # keep a list of packages from otherpkgs and bndls
 | 
						|
            if ($imagedef{$img}{otherpkgs})
 | 
						|
            {
 | 
						|
                foreach my $pkg (split(/,/, $imagedef{$img}{otherpkgs}))
 | 
						|
                {
 | 
						|
                    my ($junk, $pname);
 | 
						|
                    $pname = $pkg;
 | 
						|
                    if (!grep(/^$pname$/, @pkglist))
 | 
						|
                    {
 | 
						|
                        push(@pkglist, $pname);
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
            if ($imagedef{$img}{installp_bundle})
 | 
						|
            {
 | 
						|
                my @bndlist = split(/,/, $imagedef{$img}{installp_bundle});
 | 
						|
                foreach my $bnd (@bndlist)
 | 
						|
                {
 | 
						|
                    my ($rc, $list, $loc) =
 | 
						|
                      xCAT::InstUtils->readBNDfile($callback, $bnd, $nimprime,
 | 
						|
                                                   $subreq);
 | 
						|
                    foreach my $pkg (@$list)
 | 
						|
                    {
 | 
						|
                        chomp $pkg;
 | 
						|
                        if (!grep(/^$pkg$/, @pkglist))
 | 
						|
                        {
 | 
						|
                            push(@pkglist, $pkg);
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                    $bndloc{$bnd} = $loc;
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        # put array in string to pass along to SN
 | 
						|
        $imagedef{$img}{pkglist} = join(',', @pkglist);
 | 
						|
    }
 | 
						|
 | 
						|
    # if there are no SNs to update then return
 | 
						|
    if (scalar(@SNlist) == 0)
 | 
						|
    {
 | 
						|
        return (0, \%imagedef, \%nodeupdateinfo);
 | 
						|
    }
 | 
						|
 | 
						|
    # copy pkgs from location on nim prime to same loc on SN
 | 
						|
    foreach my $snkey (@SNlist)
 | 
						|
    {
 | 
						|
 | 
						|
        # copy files to SN from nimprime!!
 | 
						|
        # for now - assume nimprime is management node
 | 
						|
 | 
						|
        foreach my $img (@imagenames)
 | 
						|
        {
 | 
						|
            if (!$::ALTSRC)
 | 
						|
            {
 | 
						|
 | 
						|
                # if lpp_source is not defined on SN then next
 | 
						|
                my $scmd =
 | 
						|
                  qq~/usr/sbin/lsnim -l $imagedef{$img}{lpp_source} 2>/dev/null~;
 | 
						|
                my $out =
 | 
						|
                  xCAT::InstUtils->xcmd($callback, $subreq, "xdsh", $snkey,
 | 
						|
                                        $scmd, 0);
 | 
						|
 | 
						|
                if ($::RUNCMD_RC != 0)
 | 
						|
                {
 | 
						|
                    my $rsp;
 | 
						|
                    push @{$rsp->{data}},
 | 
						|
                      "The NIM lpp_source resource named $imagedef{$img}{lpp_source} is not defined on $snkey. Cannot copy software to $snkey.\n";
 | 
						|
                    xCAT::MsgUtils->message("E", $rsp, $callback);
 | 
						|
                    next;
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            # get the dir names to copy to
 | 
						|
            my $srcdir;
 | 
						|
            if ($::ALTSRC)
 | 
						|
            {
 | 
						|
                $srcdir = "$imagedef{$img}{alt_loc}";
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                $srcdir = "$imagedef{$img}{lpp_loc}";
 | 
						|
            }
 | 
						|
            my $dir = dirname($srcdir);
 | 
						|
 | 
						|
            if ($::VERBOSE)
 | 
						|
            {
 | 
						|
                my $rsp;
 | 
						|
                push @{$rsp->{data}},
 | 
						|
                  "Copying $srcdir to $dir on service node $snkey.\n";
 | 
						|
                xCAT::MsgUtils->message("I", $rsp, $callback);
 | 
						|
            }
 | 
						|
 | 
						|
            # make sure the dir exists on the service node
 | 
						|
            #  also make sure it's writeable by all
 | 
						|
            my $mkcmd  = qq~/usr/bin/mkdir -p $dir~;
 | 
						|
            my $output =
 | 
						|
              xCAT::InstUtils->xcmd($callback, $subreq, "xdsh", $snkey, $mkcmd,
 | 
						|
                                    0);
 | 
						|
            if ($::RUNCMD_RC != 0)
 | 
						|
            {
 | 
						|
                my $rsp;
 | 
						|
                push @{$rsp->{data}},
 | 
						|
                  "Could not create directories on $snkey.\n";
 | 
						|
                if ($::VERBOSE)
 | 
						|
                {
 | 
						|
                    push @{$rsp->{data}}, "$output\n";
 | 
						|
                }
 | 
						|
                xCAT::MsgUtils->message("E", $rsp, $callback);
 | 
						|
                next;
 | 
						|
            }
 | 
						|
 | 
						|
            # sync source files to SN
 | 
						|
            my $cpcmd =
 | 
						|
              qq~$::XCATROOT/bin/prsync -o "rlHpEAogDz" $srcdir $snkey:$dir 2>/dev/null~;
 | 
						|
            $output =
 | 
						|
              xCAT::InstUtils->xcmd($callback, $subreq, "xdsh", $nimprime,
 | 
						|
                                    $cpcmd, 0);
 | 
						|
            if ($::RUNCMD_RC != 0)
 | 
						|
            {
 | 
						|
                my $rsp;
 | 
						|
                push @{$rsp->{data}},
 | 
						|
                  "Could not copy $srcdir to $dir for service node $snkey.\n";
 | 
						|
                push @{$rsp->{data}}, "Output from command: \n\n$output\n\n";
 | 
						|
                xCAT::MsgUtils->message("E", $rsp, $callback);
 | 
						|
                return (1);
 | 
						|
            }
 | 
						|
 | 
						|
            # run inutoc in remote installp dir
 | 
						|
            my $installpsrcdir;
 | 
						|
            if ($::ALTSRC)
 | 
						|
            {
 | 
						|
                $installpsrcdir = $srcdir;
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                $installpsrcdir = "$srcdir/installp/ppc";
 | 
						|
            }
 | 
						|
            my $icmd   = qq~cd $installpsrcdir; /usr/sbin/inutoc .~;
 | 
						|
            my $output =
 | 
						|
              xCAT::InstUtils->xcmd($callback, $subreq, "xdsh", $snkey, $icmd,
 | 
						|
                                    0);
 | 
						|
            if ($::RUNCMD_RC != 0)
 | 
						|
            {
 | 
						|
                my $rsp;
 | 
						|
                push @{$rsp->{data}},
 | 
						|
                  "Could not run inutoc for $installpsrcdir on $snkey\n";
 | 
						|
                xCAT::MsgUtils->message("E", $rsp, $callback);
 | 
						|
            }
 | 
						|
        }    # end for each osimage
 | 
						|
    }    # end - for each service node
 | 
						|
    return (0, \%imagedef, \%nodeupdateinfo);
 | 
						|
}
 | 
						|
 | 
						|
#-------------------------------------------------------------------------------
 | 
						|
 | 
						|
=head3   updateAIXsoftware
 | 
						|
 | 
						|
    Update the software on an xCAT AIX cluster node. 
 | 
						|
 | 
						|
    Arguments:
 | 
						|
 | 
						|
    Returns:
 | 
						|
      0 - OK
 | 
						|
      1 - error
 | 
						|
 | 
						|
	Example
 | 
						|
		if (&updateAIXsoftware($callback, \%attrres, $imgdefs, $updates, $nodes, $subreq)!= 0) 
 | 
						|
 | 
						|
    Comments:
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------------------------------
 | 
						|
 | 
						|
sub updateAIXsoftware
 | 
						|
{
 | 
						|
    my $callback = shift;
 | 
						|
    my $attrs    = shift;
 | 
						|
    my $imgdefs  = shift;
 | 
						|
    my $updates  = shift;
 | 
						|
    my $nodes    = shift;
 | 
						|
    my $subreq   = shift;
 | 
						|
 | 
						|
    my @noderange = @$nodes;
 | 
						|
    my %attrvals;    # cmd line attr=val pairs
 | 
						|
    my %imagedefs;
 | 
						|
    my %nodeupdateinfo;
 | 
						|
    my @pkglist;     # list of ALL software to install
 | 
						|
 | 
						|
    # att=val - bndls, otherpakgs, flags
 | 
						|
    if ($attrs)
 | 
						|
    {
 | 
						|
        %attrvals = %{$attrs};
 | 
						|
    }
 | 
						|
    if ($imgdefs)
 | 
						|
    {
 | 
						|
        %imagedefs = %{$imgdefs};
 | 
						|
    }
 | 
						|
    if ($updates)
 | 
						|
    {
 | 
						|
        %nodeupdateinfo = %{$updates};
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    # this drives getdata to report status complete for software updatees 
 | 
						|
    $::TYPECALL ="S";
 | 
						|
 | 
						|
    my %bndloc;
 | 
						|
 | 
						|
    # get the server name for each node - as known by the node
 | 
						|
    my $noderestab  = xCAT::Table->new('noderes');
 | 
						|
    my $xcatmasters =
 | 
						|
      $noderestab->getNodesAttribs(\@noderange, ['node', 'xcatmaster']);
 | 
						|
 | 
						|
    # get the NIM primary server name
 | 
						|
    my $nimprime = xCAT::InstUtils->getnimprime();
 | 
						|
    chomp $nimprime;
 | 
						|
 | 
						|
	#
 | 
						|
	# get a list of servers and a hash of the servers name for each node
 | 
						|
	#
 | 
						|
    my %server;
 | 
						|
    my @servers;
 | 
						|
    foreach my $node (@noderange)
 | 
						|
    {
 | 
						|
        if ($xcatmasters->{$node}->[0]->{xcatmaster})
 | 
						|
        {
 | 
						|
            $server{$node} = $xcatmasters->{$node}->[0]->{xcatmaster};
 | 
						|
        }
 | 
						|
        else
 | 
						|
        {
 | 
						|
			# if it's not the xcatmaster then default to the NIM primary
 | 
						|
            $server{$node} = $nimprime;
 | 
						|
        }
 | 
						|
 | 
						|
        if (!grep($server{$node}, @servers))
 | 
						|
        {
 | 
						|
            push(@servers, $server{$node});
 | 
						|
        }
 | 
						|
    }
 | 
						|
    $noderestab->close;
 | 
						|
 | 
						|
	#  need to sort nodes by osimage AND server 
 | 
						|
	#	- each aixswupdate call should go to all nodes with the same server
 | 
						|
	#		and osimage
 | 
						|
 | 
						|
	my %nodeoslist;
 | 
						|
	foreach my $node (@noderange) {
 | 
						|
		my $server = $server{$node};
 | 
						|
		my $osimage = $nodeupdateinfo{$node}{imagename};
 | 
						|
		push(@{$nodeoslist{$server}{$osimage}}, $node);
 | 
						|
	}
 | 
						|
 | 
						|
    my $error = 0;
 | 
						|
 | 
						|
	# process nodes - all that have same serv and osimage go at once
 | 
						|
	foreach my $serv (keys %nodeoslist) {   # for each server
 | 
						|
 | 
						|
		foreach my $img (keys %{$nodeoslist{$serv}} ) { # for each osimage
 | 
						|
 | 
						|
			my @nodes = @{$nodeoslist{$serv}{$img}};
 | 
						|
			if ( !scalar(@nodes)){
 | 
						|
                next;
 | 
						|
            }
 | 
						|
 | 
						|
        	# set the location of the software
 | 
						|
        	my $pkgdir = "";
 | 
						|
        	if ($::ALTSRC)
 | 
						|
        	{
 | 
						|
            	$pkgdir = $::ALTSRC;
 | 
						|
        	}
 | 
						|
        	else
 | 
						|
        	{
 | 
						|
            	$pkgdir = $imagedefs{$img}{lpp_loc};
 | 
						|
        	}
 | 
						|
 | 
						|
			# check for pkg dir
 | 
						|
			if ( ! -d $pkgdir ) {
 | 
						|
				my $rsp;
 | 
						|
				push @{$rsp->{data}}, "The source directory $pkgdir does not exist.\n";
 | 
						|
				xCAT::MsgUtils->message("E", $rsp, $callback);
 | 
						|
				$error++;
 | 
						|
				next;
 | 
						|
			}
 | 
						|
 | 
						|
			# create a file in the pkgdir and add the pkg list to it
 | 
						|
			#  the pkgdir is mounted and the pkglist file will be available 
 | 
						|
			#	on the node.
 | 
						|
			#
 | 
						|
			# create a unique name
 | 
						|
			my $thisdate = `date +%s`;
 | 
						|
			my $pkglist_file_name = qq~pkglist_file.$thisdate~;			
 | 
						|
           	chomp $pkglist_file_name;
 | 
						|
 | 
						|
			@pkglist = split(/,/, $imagedefs{$img}{pkglist});
 | 
						|
 | 
						|
           	if (!scalar(@pkglist))
 | 
						|
           	{
 | 
						|
				my $rsp;
 | 
						|
				push @{$rsp->{data}}, "There is no list of packages for nodes: @nodes.\n";		
 | 
						|
				xCAT::MsgUtils->message("E", $rsp, $callback);
 | 
						|
				$error++;
 | 
						|
				next;
 | 
						|
			}
 | 
						|
			
 | 
						|
            #  make sure the permissions are correct on pkgdir
 | 
						|
            # - we are running on MN
 | 
						|
            my $chmcmd = qq~/bin/chmod -R +r $pkgdir~;
 | 
						|
            my @result = xCAT::Utils->runcmd("$chmcmd", -1);
 | 
						|
            if ($::RUNCMD_RC != 0)
 | 
						|
            {
 | 
						|
                my $rsp;
 | 
						|
                push @{$rsp->{data}},
 | 
						|
                    "Could not set permissions for $pkgdir.\n";
 | 
						|
                xCAT::MsgUtils->message("E", $rsp, $callback);
 | 
						|
				$error++;
 | 
						|
				next;
 | 
						|
            }
 | 
						|
 | 
						|
			# create a pkglist file in the pkgdir on MN
 | 
						|
			my $pkglist_file= qq~$pkgdir/$pkglist_file_name~;
 | 
						|
 | 
						|
           	if (!open(PKGLISTFILE, ">$pkglist_file"))
 | 
						|
           	{
 | 
						|
               	my $rsp;
 | 
						|
               	push @{$rsp->{data}}, "Could not open $pkglist_file_name.\n";
 | 
						|
               	xCAT::MsgUtils->message("E", $rsp, $callback);
 | 
						|
				$error++;
 | 
						|
				next;
 | 
						|
			}
 | 
						|
			else
 | 
						|
           	{
 | 
						|
               	foreach (@pkglist)
 | 
						|
               	{
 | 
						|
                   	print PKGLISTFILE $_ . "\n";
 | 
						|
               	}
 | 
						|
               	close(PKGLISTFILE);
 | 
						|
			}
 | 
						|
 | 
						|
# ndebug
 | 
						|
# ??? has the whole pkgdir been copied to the SN yet???
 | 
						|
 | 
						|
			if (!xCAT::InstUtils->is_me($serv)) {
 | 
						|
				# cp file to SN 
 | 
						|
				# has pkgdir already been copied.             
 | 
						|
				my $rcpcmd = "$::XCATROOT/bin/xdcp $serv $pkglist_file $pkgdir ";
 | 
						|
				my $output = xCAT::Utils->runcmd("$rcpcmd", -1);
 | 
						|
				if ($::RUNCMD_RC != 0)
 | 
						|
				{
 | 
						|
					my $rsp;
 | 
						|
					push @{$rsp->{data}}, "Could not copy $pkglist_file to $serv.\n";
 | 
						|
					xCAT::MsgUtils->message("E", $rsp, $callback);
 | 
						|
					$error++;
 | 
						|
					next;
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			# export the pkgdir on the server
 | 
						|
			my $ecmd;
 | 
						|
			my @nfsv4 = xCAT::TableUtils->get_site_attribute("useNFSv4onAIX");
 | 
						|
			if ($nfsv4[0] && ($nfsv4[0] =~ /1|Yes|yes|YES|Y|y/))
 | 
						|
			{
 | 
						|
				$ecmd = qq~exportfs -i -o vers=4 $pkgdir~;
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				$ecmd = qq~exportfs -i $pkgdir~;
 | 
						|
			}
 | 
						|
 | 
						|
			if (!xCAT::InstUtils->is_me($serv)) {
 | 
						|
				my $output = xCAT::Utils->runxcmd(
 | 
						|
					{
 | 
						|
						command => ["xdsh"],
 | 
						|
						node    => [$serv],	
 | 
						|
						arg     => [$ecmd]
 | 
						|
					},
 | 
						|
					$subreq, -1, 1
 | 
						|
					);
 | 
						|
				if ($::RUNCMD_RC != 0)
 | 
						|
				{
 | 
						|
					my $rsp;
 | 
						|
					push @{$rsp->{data}}, "Could not export $pkgdir on $serv.\n";
 | 
						|
					xCAT::MsgUtils->message("E", $rsp, $callback);
 | 
						|
					$error++;
 | 
						|
                    next;
 | 
						|
				}
 | 
						|
			} else {
 | 
						|
				my $output = xCAT::Utils->runcmd("$ecmd", -1);
 | 
						|
				if ($::RUNCMD_RC != 0)
 | 
						|
				{
 | 
						|
					my $rsp;
 | 
						|
					push @{$rsp->{data}}, "Could not export $pkgdir on $serv.\n";
 | 
						|
					push @{$rsp->{data}}, "$output\n";
 | 
						|
					xCAT::MsgUtils->message("E", $rsp, $callback);
 | 
						|
					$error++;
 | 
						|
					next;
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			#
 | 
						|
           	# call aixswupdate to install sw on the nodes
 | 
						|
           	#
 | 
						|
 | 
						|
			# put together the cmd string
 | 
						|
           	my $installcmd = qq~/install/postscripts/aixswupdate -f $pkglist_file ~;
 | 
						|
 | 
						|
			# $serv is the name of the nodes server as known by the node
 | 
						|
			$installcmd .= qq~ -s $serv ~;
 | 
						|
		
 | 
						|
			if ($::ALLSW) {
 | 
						|
				$installcmd .= qq~ -a ~;
 | 
						|
			}
 | 
						|
 | 
						|
			if ($::ALTSRC) {
 | 
						|
				$installcmd .= qq~ -d ~;
 | 
						|
			}
 | 
						|
 | 
						|
			if ($::NFSV4) {
 | 
						|
				$installcmd .= qq~ -n ~;
 | 
						|
			}
 | 
						|
 | 
						|
			# add installp flags
 | 
						|
			if ( $imagedefs{$img}{installp_flags} ) {
 | 
						|
				$installcmd .= qq~ -i $imagedefs{$img}{installp_flags} ~;
 | 
						|
			}
 | 
						|
			# add rpm flags
 | 
						|
			if ( $imagedefs{$img}{rpm_flags} ) {
 | 
						|
               	$installcmd .= qq~ -r $imagedefs{$img}{rpm_flags} ~;
 | 
						|
           	}
 | 
						|
			# add emgr flags
 | 
						|
           	if ( $imagedefs{$img}{emgr_flags} ) {
 | 
						|
               	$installcmd .= qq~ -e $imagedefs{$img}{emgr_flags} ~;
 | 
						|
           	}
 | 
						|
 | 
						|
			my $args1;
 | 
						|
			push @$args1,"--nodestatus";
 | 
						|
			push @$args1,"-s";
 | 
						|
			push @$args1,"-v";
 | 
						|
			push @$args1,"-e";
 | 
						|
			if (defined($::fanout))  {  # fanout input
 | 
						|
				push @$args1,"-f" ;
 | 
						|
				push @$args1,$::fanout;
 | 
						|
			}
 | 
						|
         if (defined($::timeout))  {  # timeout 
 | 
						|
            push @$args1,"-t" ;
 | 
						|
            push @$args1,$::timeout;
 | 
						|
         }
 | 
						|
			push @$args1,"$installcmd";
 | 
						|
 | 
						|
			$subreq->(
 | 
						|
				{
 | 
						|
					command           => ["xdsh"],
 | 
						|
					node              => \@nodes,
 | 
						|
					arg               => $args1,
 | 
						|
					_xcatpreprocessed => [1]
 | 
						|
				},
 | 
						|
				\&getdata
 | 
						|
				);
 | 
						|
 | 
						|
			# remove pkglist_file from MN - local
 | 
						|
			my $rcmd = qq~/bin/rm -f $pkglist_file~;
 | 
						|
            my $output = xCAT::Utils->runcmd("$rcmd", -1);
 | 
						|
            if ($::RUNCMD_RC != 0)
 | 
						|
            {
 | 
						|
                my $rsp;
 | 
						|
                push @{$rsp->{data}}, "Could not remove $pkglist_file.\n";
 | 
						|
                xCAT::MsgUtils->message("E", $rsp, $callback);
 | 
						|
            }
 | 
						|
 | 
						|
 | 
						|
			# if not $serv then remove pkglist_file from $serv
 | 
						|
			if (!xCAT::InstUtils->is_me($serv)) {
 | 
						|
				my $output = xCAT::Utils->runxcmd(
 | 
						|
                      	{
 | 
						|
                       		command => ["xdsh"],
 | 
						|
                       		node    => [$serv],
 | 
						|
                          	arg     => [$rcmd]
 | 
						|
                       	},
 | 
						|
                       	$subreq, -1, 1
 | 
						|
                        );
 | 
						|
				if ($::RUNCMD_RC != 0)
 | 
						|
				{
 | 
						|
					my $rsp;
 | 
						|
					push @{$rsp->{data}}, "Could not remove $pkglist_file on $serv.\n";
 | 
						|
					xCAT::MsgUtils->message("E", $rsp, $callback);
 | 
						|
					$error++;
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			# unexport pkgdir
 | 
						|
			my $ucmd = qq~exportfs -u -F $pkgdir~;
 | 
						|
			if (xCAT::InstUtils->is_me($serv)) {
 | 
						|
                my $ucmd = qq~exportfs -u -F $pkgdir~;
 | 
						|
                my $output = xCAT::Utils->runcmd("$ucmd", -1);
 | 
						|
                if ($::RUNCMD_RC != 0)
 | 
						|
                {
 | 
						|
                    my $rsp;
 | 
						|
                    push @{$rsp->{data}}, "Could not unexport $pkgdir.\n";
 | 
						|
                    if ($::VERBOSE)
 | 
						|
                    {
 | 
						|
                        push @{$rsp->{data}}, "$output\n";
 | 
						|
                	}
 | 
						|
                	xCAT::MsgUtils->message("E", $rsp, $callback);
 | 
						|
					$error++;
 | 
						|
				}
 | 
						|
			} else {
 | 
						|
				# unexport dirs on SNs
 | 
						|
				my $output = xCAT::Utils->runxcmd(
 | 
						|
                        {
 | 
						|
                            command => ["xdsh"],
 | 
						|
                            node    => [$serv],
 | 
						|
                            arg     => [$ucmd]
 | 
						|
                        },
 | 
						|
                        $subreq, -1, 1
 | 
						|
                        );
 | 
						|
                if ($::RUNCMD_RC != 0)
 | 
						|
                {
 | 
						|
                    my $rsp;
 | 
						|
                    push @{$rsp->{data}}, "Could not unexport $pkgdir on $serv.\n";
 | 
						|
                    xCAT::MsgUtils->message("E", $rsp, $callback);
 | 
						|
					$error++;
 | 
						|
                }
 | 
						|
			}
 | 
						|
		} # for each osimage
 | 
						|
	} # for each server 
 | 
						|
 | 
						|
    if ($error)
 | 
						|
    {
 | 
						|
        my $rsp;
 | 
						|
        push @{$rsp->{data}},
 | 
						|
          "One or more errors occured while updating node software.\n";
 | 
						|
        xCAT::MsgUtils->message("E", $rsp, $callback);
 | 
						|
        return 1;
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        my $rsp;
 | 
						|
        push @{$rsp->{data}},
 | 
						|
          "Cluster node software update commands have completed.\n";
 | 
						|
        xCAT::MsgUtils->message("I", $rsp, $callback);
 | 
						|
    }
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
 | 
						|
=head3   updateOS
 | 
						|
 | 
						|
	Description	: Update the node operating system
 | 
						|
    Arguments	: 
 | 
						|
    Returns		: Nothing
 | 
						|
    Example		: updateOS($callback, $nodes, $os);
 | 
						|
    
 | 
						|
=cut
 | 
						|
 | 
						|
#-------------------------------------------------------
 | 
						|
sub updateOS
 | 
						|
{
 | 
						|
 | 
						|
    # Get inputs
 | 
						|
    my ($callback, $node, $os) = @_;
 | 
						|
    my $rsp;
 | 
						|
 | 
						|
    # Get install directory
 | 
						|
    my $installDIR = xCAT::TableUtils->getInstallDir();
 | 
						|
 | 
						|
    # Get HTTP server
 | 
						|
    my $http = xCAT::NetworkUtils->my_ip_facing($node);
 | 
						|
    if (!$http)
 | 
						|
    {
 | 
						|
        push @{$rsp->{data}}, "$node: (Error) Missing HTTP server";
 | 
						|
        xCAT::MsgUtils->message("I", $rsp, $callback);
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    # Get OS to update to
 | 
						|
    my $update2os = $os;
 | 
						|
 | 
						|
    push @{$rsp->{data}}, "$node: Upgrading $node to $os";
 | 
						|
    xCAT::MsgUtils->message("I", $rsp, $callback);
 | 
						|
 | 
						|
    # Get the OS that is installed on the node
 | 
						|
    my $arch = `ssh -o ConnectTimeout=5 $node "uname -m"`;
 | 
						|
    chomp($arch);
 | 
						|
    my $installOS;
 | 
						|
    my $version;
 | 
						|
 | 
						|
    # Red Hat Linux
 | 
						|
    if (
 | 
						|
        `ssh -o ConnectTimeout=5 $node "test -f /etc/redhat-release && echo 'redhat'"`
 | 
						|
      )
 | 
						|
    {
 | 
						|
        $installOS = "rh";
 | 
						|
        chomp($version =
 | 
						|
              `ssh $node "tr -d '.' < /etc/redhat-release" | head -n 1`);
 | 
						|
        $version =~ s/[^0-9]*([0-9]+).*/$1/;
 | 
						|
    }
 | 
						|
 | 
						|
    # SUSE Linux
 | 
						|
    elsif (
 | 
						|
        `ssh -o ConnectTimeout=5 $node "test -f /etc/SuSE-release && echo 'SuSE'"`
 | 
						|
      )
 | 
						|
    {
 | 
						|
        $installOS = "sles";
 | 
						|
        chomp($version =
 | 
						|
              `ssh $node "tr -d '.' < /etc/SuSE-release" | head -n 1`);
 | 
						|
        $version =~ s/[^0-9]*([0-9]+).*/$1/;
 | 
						|
    }
 | 
						|
 | 
						|
    # Everything else
 | 
						|
    else
 | 
						|
    {
 | 
						|
        $installOS = "Unknown";
 | 
						|
 | 
						|
        push @{$rsp->{data}}, "$node: (Error) Linux distribution not supported";
 | 
						|
        xCAT::MsgUtils->message("I", $rsp, $callback);
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    # Is the installed OS and the update to OS of the same distributor
 | 
						|
    if (!($update2os =~ m/$installOS/i))
 | 
						|
    {
 | 
						|
        push @{$rsp->{data}},
 | 
						|
          "$node: (Error) Cannot not update $installOS$version to $os.  Linux distribution does not match";
 | 
						|
        xCAT::MsgUtils->message("I", $rsp, $callback);
 | 
						|
        return;
 | 
						|
    }
 | 
						|
 | 
						|
    # Setup the repository for the node
 | 
						|
    my $path;
 | 
						|
    my $out;
 | 
						|
    if ("$installOS$version" =~ m/sles10/i)
 | 
						|
    {
 | 
						|
 | 
						|
        # SUSE repository path - http://10.1.100.1/install/sles10.3/s390x/1/
 | 
						|
        $path = "http://$http$installDIR/$os/$arch/1/";
 | 
						|
        if (!(-e "$installDIR/$os/$arch/1/"))
 | 
						|
        {
 | 
						|
            push @{$rsp->{data}},
 | 
						|
              "$node: (Error) Missing install directory $installDIR/$os/$arch/1/";
 | 
						|
            xCAT::MsgUtils->message("I", $rsp, $callback);
 | 
						|
            return;
 | 
						|
        }
 | 
						|
 | 
						|
        # Add installation source using rug
 | 
						|
        $out = `ssh $node "rug sa -t zypp $path $os"`;
 | 
						|
        push @{$rsp->{data}}, "$node: $out";
 | 
						|
        xCAT::MsgUtils->message("I", $rsp, $callback);
 | 
						|
 | 
						|
        # Subscribe to catalog
 | 
						|
        $out = `ssh $node "rug sub $os"`;
 | 
						|
        push @{$rsp->{data}}, "$node: $out";
 | 
						|
        xCAT::MsgUtils->message("I", $rsp, $callback);
 | 
						|
 | 
						|
        # Refresh services
 | 
						|
        $out = `ssh $node "rug ref"`;
 | 
						|
        push @{$rsp->{data}}, "$node: $out";
 | 
						|
        xCAT::MsgUtils->message("I", $rsp, $callback);
 | 
						|
 | 
						|
        # Update
 | 
						|
        $out = `ssh $node "rug up -y"`;
 | 
						|
        push @{$rsp->{data}}, "$node: $out";
 | 
						|
        xCAT::MsgUtils->message("I", $rsp, $callback);
 | 
						|
    }
 | 
						|
 | 
						|
    elsif ("$installOS$version" =~ m/sles/i)
 | 
						|
    {
 | 
						|
 | 
						|
        # SUSE repository path - http://10.1.100.1/install/sles10.3/s390x/1/
 | 
						|
        $path = "http://$http$installDIR/$os/$arch/1/";
 | 
						|
        if (!(-e "$installDIR/$os/$arch/1/"))
 | 
						|
        {
 | 
						|
            push @{$rsp->{data}},
 | 
						|
              "$node: (Error) Missing install directory $installDIR/$os/$arch/1/";
 | 
						|
            xCAT::MsgUtils->message("I", $rsp, $callback);
 | 
						|
            return;
 | 
						|
        }
 | 
						|
 | 
						|
        # Add installation source using zypper
 | 
						|
        $out = `ssh $node "zypper ar $path $installOS$version"`;
 | 
						|
        push @{$rsp->{data}}, "$node: $out";
 | 
						|
        xCAT::MsgUtils->message("I", $rsp, $callback);
 | 
						|
 | 
						|
        # Refresh services
 | 
						|
        $out = `ssh $node "zypper ref"`;
 | 
						|
        push @{$rsp->{data}}, "$node: $out";
 | 
						|
        xCAT::MsgUtils->message("I", $rsp, $callback);
 | 
						|
 | 
						|
        # Update
 | 
						|
        $out =
 | 
						|
          `ssh $node "zypper --non-interactive update --auto-agree-with-licenses"`;
 | 
						|
        push @{$rsp->{data}}, "$node: $out";
 | 
						|
        xCAT::MsgUtils->message("I", $rsp, $callback);
 | 
						|
    }
 | 
						|
 | 
						|
    elsif ("$installOS$version" =~ m/rh/i)
 | 
						|
    {
 | 
						|
 | 
						|
        # Red Hat repository path - http://10.0.0.1/install/rhel5.4/s390x/Server/
 | 
						|
        $path = "http://$http$installDIR/$os/$arch/Server/";
 | 
						|
        if (!(-e "$installDIR/$os/$arch/Server/"))
 | 
						|
        {
 | 
						|
            push @{$rsp->{data}},
 | 
						|
              "$node: (Error) Missing install directory $installDIR/$os/$arch/Server/";
 | 
						|
            xCAT::MsgUtils->message("I", $rsp, $callback);
 | 
						|
            return;
 | 
						|
        }
 | 
						|
 | 
						|
        # Create a yum repository file
 | 
						|
        my $exist =
 | 
						|
          `ssh $node "test -e /etc/yum.repos.d/$os.repo && echo 'File exists'"`;
 | 
						|
        if (!$exist)
 | 
						|
        {
 | 
						|
            $out = `ssh $node "echo [$os] >> /etc/yum.repos.d/$os.repo"`;
 | 
						|
            $out =
 | 
						|
              `ssh $node "echo baseurl=$path >> /etc/yum.repos.d/$os.repo"`;
 | 
						|
            $out = `ssh $node "echo enabled=1 >> /etc/yum.repos.d/$os.repo"`;
 | 
						|
        }
 | 
						|
 | 
						|
        # Send over release key
 | 
						|
        my $key = "$installDIR/$os/$arch/RPM-GPG-KEY-redhat-release";
 | 
						|
        my $tmp = "/tmp/RPM-GPG-KEY-redhat-release";
 | 
						|
        my $tgt = "root@" . $node;
 | 
						|
        $out = `scp $key $tgt:$tmp`;
 | 
						|
 | 
						|
        # Import key
 | 
						|
        $out = `ssh $node "rpm --import $tmp"`;
 | 
						|
 | 
						|
        # Upgrade
 | 
						|
        $out = `ssh $node "yum -y upgrade"`;
 | 
						|
        push @{$rsp->{data}}, "$node: $out";
 | 
						|
        xCAT::MsgUtils->message("I", $rsp, $callback);
 | 
						|
    }
 | 
						|
 | 
						|
    else
 | 
						|
    {
 | 
						|
        push @{$rsp->{data}},
 | 
						|
          "$node: (Error) Could not update operating system";
 | 
						|
        xCAT::MsgUtils->message("I", $rsp, $callback);
 | 
						|
    }
 | 
						|
 | 
						|
    return;
 | 
						|
}
 | 
						|
 | 
						|
#-------------------------------------------------------------------------------
 | 
						|
 | 
						|
=head3   updatenodeappstat
 | 
						|
    This subroutine is used to handle the messages reported by 
 | 
						|
    HPCbootstatus postscript. Update appstatus node attribute.
 | 
						|
 | 
						|
    Arguments:
 | 
						|
    Returns:
 | 
						|
        0 - for success.
 | 
						|
        1 - for error.
 | 
						|
 | 
						|
=cut
 | 
						|
 | 
						|
#-----------------------------------------------------------------------------
 | 
						|
sub updatenodeappstat
 | 
						|
{
 | 
						|
    my $request  = shift;
 | 
						|
    my $callback = shift;
 | 
						|
    my @nodes    = ();
 | 
						|
    my @args     = ();
 | 
						|
    if (ref($request->{node}))
 | 
						|
    {
 | 
						|
        @nodes = @{$request->{node}};
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        if ($request->{node}) { @nodes = ($request->{node}); }
 | 
						|
    }
 | 
						|
    if (ref($request->{arg}))
 | 
						|
    {
 | 
						|
        @args = @{$request->{arg}};
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        @args = ($request->{arg});
 | 
						|
    }
 | 
						|
 | 
						|
    if ((@nodes > 0) && (@args > 0))
 | 
						|
    {
 | 
						|
 | 
						|
        # format: apps=status
 | 
						|
        my $appstat = $args[0];
 | 
						|
        my ($apps, $newstatus) = split(/=/, $appstat);
 | 
						|
 | 
						|
        xCAT::TableUtils->setAppStatus(\@nodes, $apps, $newstatus);
 | 
						|
 | 
						|
    }
 | 
						|
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 |