2008-09-08 18:54:30 +00:00
|
|
|
#!/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 strict;
|
|
|
|
use warnings;
|
|
|
|
use xCAT::Table;
|
|
|
|
use xCAT::Schema;
|
|
|
|
use Data::Dumper;
|
|
|
|
use xCAT::Utils;
|
|
|
|
use Getopt::Long;
|
|
|
|
use xCAT::GlobalDef;
|
|
|
|
use Sys::Hostname;
|
2008-09-25 03:04:56 +00:00
|
|
|
use xCAT::GlobalDef;
|
|
|
|
use xCAT_monitoring::monitorctrl;
|
2008-09-08 18:54:30 +00:00
|
|
|
|
|
|
|
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 {
|
2008-09-25 03:04:56 +00:00
|
|
|
updatenode => "updatenode",
|
|
|
|
updatenodestat => "updatenode"};
|
2008-09-08 18:54:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#-------------------------------------------------------
|
|
|
|
=head3 preprocess_request
|
|
|
|
Check and setup for hierarchy
|
|
|
|
=cut
|
|
|
|
#-------------------------------------------------------
|
|
|
|
sub preprocess_request
|
|
|
|
{
|
|
|
|
my $request = shift;
|
|
|
|
my $callback = shift;
|
2009-06-04 15:33:44 +00:00
|
|
|
my $subreq = shift;
|
2008-09-08 18:54:30 +00:00
|
|
|
my $command = $request->{command}->[0];
|
|
|
|
if ($request->{_xcatdest}) { return [$request]; } #exit if preprocessed
|
|
|
|
my @requests=();
|
|
|
|
|
|
|
|
if ($command eq "updatenode")
|
|
|
|
{
|
2009-06-04 15:33:44 +00:00
|
|
|
return preprocess_updatenode($request, $callback, $subreq);
|
2008-09-25 03:04:56 +00:00
|
|
|
} elsif ($command eq "updatenodestat") {
|
|
|
|
return [$request];
|
|
|
|
}
|
2008-09-08 18:54:30 +00:00
|
|
|
else {
|
|
|
|
my $rsp={};
|
|
|
|
$rsp->{data}->[0]= "unsupported command: $command.";
|
|
|
|
$callback->($rsp);
|
|
|
|
return \@requests;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#--------------------------------------------------------------------------------
|
|
|
|
=head3 process_request
|
|
|
|
It processes the monitoring control commands.
|
|
|
|
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 unsuccess. The error messages are returns through the callback pointer.
|
|
|
|
=cut
|
|
|
|
#--------------------------------------------------------------------------------
|
|
|
|
sub process_request
|
|
|
|
{
|
|
|
|
my $request = shift;
|
|
|
|
my $callback = shift;
|
2009-06-04 15:33:44 +00:00
|
|
|
my $subreq = shift;
|
2008-09-08 18:54:30 +00:00
|
|
|
my $command = $request->{command}->[0];
|
|
|
|
my $localhostname=hostname();
|
|
|
|
|
2008-09-25 03:04:56 +00:00
|
|
|
if ($command eq "updatenode") {
|
2009-06-04 15:33:44 +00:00
|
|
|
return updatenode($request, $callback, $subreq);
|
2008-09-25 03:04:56 +00:00
|
|
|
} elsif ($command eq "updatenodestat") {
|
|
|
|
return updatenodestat($request, $callback);
|
|
|
|
} else {
|
2008-09-08 18:54:30 +00:00
|
|
|
my $rsp={};
|
|
|
|
$rsp->{data}->[0]= "$localhostname: unsupported command: $command.";
|
|
|
|
$callback->($rsp);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#--------------------------------------------------------------------------------
|
|
|
|
=head3 preprocess_updatenode
|
|
|
|
This function checks for the syntax of the updatenode command
|
|
|
|
and distribute the command to the right server.
|
|
|
|
Arguments:
|
|
|
|
request - the request. The request->{arg} is of the format:
|
|
|
|
[-h|--help|-v|--version] or
|
2009-06-04 15:33:44 +00:00
|
|
|
[noderange [-s | -S] [postscripts]]
|
2008-09-08 18:54:30 +00:00
|
|
|
callback - the pointer to the callback function.
|
|
|
|
Returns:
|
|
|
|
A pointer to an array of requests.
|
|
|
|
=cut
|
|
|
|
#--------------------------------------------------------------------------------
|
|
|
|
sub preprocess_updatenode {
|
|
|
|
my $request = shift;
|
|
|
|
my $callback = shift;
|
2009-06-04 15:33:44 +00:00
|
|
|
my $subreq = shift;
|
2008-09-08 18:54:30 +00:00
|
|
|
my $args=$request->{arg};
|
|
|
|
my @requests=();
|
|
|
|
|
|
|
|
# subroutine to display the usage
|
|
|
|
sub updatenode_usage
|
|
|
|
{
|
|
|
|
my $cb=shift;
|
|
|
|
my $rsp={};
|
|
|
|
$rsp->{data}->[0]= "Usage:";
|
2009-06-04 15:33:44 +00:00
|
|
|
$rsp->{data}->[1]= " updatenode <noderange> [-s | -S] [posts]";
|
2008-09-11 04:43:33 +00:00
|
|
|
$rsp->{data}->[2]= " updatenode [-h|--help|-v|--version]";
|
2008-09-08 20:59:07 +00:00
|
|
|
$rsp->{data}->[3]= " noderange is a list of nodes or groups.";
|
|
|
|
$rsp->{data}->[4]= " posts is a comma separated list of postscript names.";
|
2008-09-08 18:54:30 +00:00
|
|
|
$rsp->{data}->[5]= " if omitted, all the postscripts will be run.";
|
|
|
|
$cb->($rsp);
|
|
|
|
}
|
|
|
|
|
|
|
|
@ARGV=();
|
|
|
|
if ($args) {
|
|
|
|
@ARGV=@{$args};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# parse the options
|
|
|
|
Getopt::Long::Configure("bundling");
|
|
|
|
Getopt::Long::Configure("no_pass_through");
|
|
|
|
if(!GetOptions(
|
|
|
|
'h|help' => \$::HELP,
|
2009-06-04 15:33:44 +00:00
|
|
|
'v|version' => \$::VERSION,
|
|
|
|
's' => \$::SYNCSN,
|
|
|
|
'S' => \$::SKIPSYNCFILE ))
|
2008-09-08 18:54:30 +00:00
|
|
|
{
|
|
|
|
&updatenode_usage($callback);
|
|
|
|
return \@requests;;
|
|
|
|
}
|
|
|
|
|
|
|
|
# display the usage if -h or --help is specified
|
|
|
|
if ($::HELP) {
|
|
|
|
&updatenode_usage($callback);
|
|
|
|
return \@requests;;
|
|
|
|
}
|
|
|
|
|
|
|
|
# display the version statement if -v or --verison is specified
|
|
|
|
if ($::VERSION)
|
|
|
|
{
|
|
|
|
my $rsp={};
|
|
|
|
$rsp->{data}->[0]= xCAT::Utils->Version();
|
|
|
|
$callback->($rsp);
|
|
|
|
return \@requests;
|
|
|
|
}
|
|
|
|
|
2008-09-08 20:59:07 +00:00
|
|
|
my $nodes = $request->{node};
|
|
|
|
if (!$nodes) {
|
|
|
|
&updatenode_usage($callback);
|
|
|
|
return \@requests;;
|
2008-09-08 18:54:30 +00:00
|
|
|
}
|
|
|
|
|
2008-09-08 20:59:07 +00:00
|
|
|
my @nodes=@$nodes;
|
|
|
|
my $postscripts;
|
2008-09-08 18:54:30 +00:00
|
|
|
|
|
|
|
if (@nodes == 0) { return \@requests; }
|
|
|
|
|
2008-09-08 20:59:07 +00:00
|
|
|
if (@ARGV > 0) {
|
|
|
|
$postscripts=$ARGV[0];
|
2008-09-08 18:54:30 +00:00
|
|
|
my @posts=split(',',$postscripts);
|
|
|
|
foreach (@posts) {
|
|
|
|
if ( ! -e "/install/postscripts/$_") {
|
|
|
|
my $rsp={};
|
|
|
|
$rsp->{data}->[0]= "The postcript /install/postscripts/$_ does not exist.";
|
|
|
|
$callback->($rsp);
|
|
|
|
return \@requests;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-06-09 02:59:16 +00:00
|
|
|
# If -s argument specified, sync files to the service nodes firstly
|
2009-06-04 15:33:44 +00:00
|
|
|
if ($::SYNCSN) {
|
2009-06-09 02:59:16 +00:00
|
|
|
my %syncfile_node = ();
|
2009-06-04 15:33:44 +00:00
|
|
|
my $node_syncfile = xCAT::Utils->getsynclistfile($nodes);
|
2009-06-09 02:59:16 +00:00
|
|
|
foreach my $node (@$nodes) {
|
|
|
|
my $synclist = $$node_syncfile{$node};
|
2009-06-04 15:33:44 +00:00
|
|
|
|
2009-06-09 02:59:16 +00:00
|
|
|
if ($synclist) {
|
|
|
|
push @{$syncfile_node{$synclist}}, $node;
|
|
|
|
next;
|
2009-06-04 15:33:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-06-09 02:59:16 +00:00
|
|
|
foreach my $syncfile (keys %syncfile_node) {
|
2009-06-04 15:33:44 +00:00
|
|
|
my $arg = ["-s", "-F", "$syncfile"];
|
|
|
|
my $env = ["RSYNCSN=yes", "DSH_RSYNC_FILE=$syncfile"];
|
2009-06-09 02:59:16 +00:00
|
|
|
$subreq->({command=>['xdcp'], node=>$syncfile_node{$syncfile}, arg=>$arg, env=>$env}, $callback);
|
2009-06-04 15:33:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-06-09 02:59:16 +00:00
|
|
|
# find service nodes for requested nodes
|
|
|
|
# build an individual request for each service node
|
|
|
|
my $sn = xCAT::Utils->get_ServiceNode(\@nodes, "xcat", "MN");
|
|
|
|
|
2008-09-08 20:59:07 +00:00
|
|
|
# build each request for each service node
|
|
|
|
foreach my $snkey (keys %$sn)
|
|
|
|
{
|
|
|
|
my $reqcopy = {%$request};
|
|
|
|
$reqcopy->{node} = $sn->{$snkey};
|
|
|
|
$reqcopy->{'_xcatdest'} = $snkey;
|
|
|
|
$reqcopy->{postscripts} = [$postscripts];
|
|
|
|
push @requests, $reqcopy;
|
2008-09-08 18:54:30 +00:00
|
|
|
}
|
|
|
|
return \@requests;
|
2008-09-08 20:59:07 +00:00
|
|
|
|
2008-09-08 18:54:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#--------------------------------------------------------------------------------
|
|
|
|
=head3 updatenode
|
|
|
|
This function implements the updatenode command.
|
|
|
|
Arguments:
|
|
|
|
request - the request.
|
|
|
|
callback - the pointer to the callback function.
|
|
|
|
Returns:
|
|
|
|
0 for success. The output is returned through the callback pointer.
|
|
|
|
1. for unsuccess. The error messages are returns through the callback pointer.
|
|
|
|
=cut
|
|
|
|
#--------------------------------------------------------------------------------
|
|
|
|
sub updatenode {
|
|
|
|
my $request = shift;
|
|
|
|
my $callback = shift;
|
2009-06-04 15:33:44 +00:00
|
|
|
my $subreq = shift;
|
2008-09-08 18:54:30 +00:00
|
|
|
my $postscripts="";
|
|
|
|
if (($request->{postscripts}) && ($request->{postscripts}->[0])) { $postscripts=$request->{postscripts}->[0];}
|
2008-09-08 20:59:07 +00:00
|
|
|
my $nodes =$request->{node};
|
2008-09-08 18:54:30 +00:00
|
|
|
my $localhostname=hostname();
|
|
|
|
|
2009-06-04 15:33:44 +00:00
|
|
|
# if not specifying -S, do the sync file operation
|
|
|
|
unless ($::SKIPSYNCFILE) {
|
|
|
|
my %syncfile_node = ();
|
2009-06-19 08:32:47 +00:00
|
|
|
my %syncfile_rootimage = ();
|
2009-06-04 15:33:44 +00:00
|
|
|
my $node_syncfile = xCAT::Utils->getsynclistfile($nodes);
|
|
|
|
foreach my $node (@$nodes) {
|
|
|
|
my $synclist = $$node_syncfile{$node};
|
|
|
|
|
|
|
|
if ($synclist) {
|
|
|
|
push @{$syncfile_node{$synclist}}, $node;
|
2009-06-19 08:32:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
# Figure out the directory of the root image
|
|
|
|
# one $synclist will only map to one root image, so
|
|
|
|
# just find the root image one time
|
|
|
|
# only for netboot node (diskless)
|
|
|
|
if ($synclist && $synclist =~ /\/netboot\//) {
|
|
|
|
if (! defined($syncfile_rootimage{$synclist})) {
|
|
|
|
my $root_dir = xCAT::Utils->getrootimage($node);
|
|
|
|
if (-d $root_dir) {
|
|
|
|
$syncfile_rootimage{$synclist} = $root_dir;
|
|
|
|
} else {
|
|
|
|
$syncfile_rootimage{$synclist} = "no_root_image";
|
|
|
|
}
|
|
|
|
}
|
2009-06-04 15:33:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-06-19 08:32:47 +00:00
|
|
|
# Sync files to the target nodes
|
2009-06-04 15:33:44 +00:00
|
|
|
foreach my $synclist (keys %syncfile_node) {
|
|
|
|
my $args = ["-F", "$synclist"];
|
|
|
|
my $env = ["DSH_RSYNC_FILE=$synclist"];
|
|
|
|
$subreq->({command=>['xdcp'], node=>$syncfile_node{$synclist}, arg=>$args, env=>$env}, $callback);
|
|
|
|
}
|
2009-06-19 08:32:47 +00:00
|
|
|
|
|
|
|
# Sync files to the root image for the diskless nodes
|
|
|
|
foreach my $synclist (keys %syncfile_rootimage) {
|
|
|
|
if ($syncfile_rootimage{$synclist} eq "no_root_image") {
|
|
|
|
next;
|
|
|
|
}
|
|
|
|
my $args = ["-i", $syncfile_rootimage{$synclist}, "-F", $synclist];
|
|
|
|
my $env = ["DSH_RSYNC_FILE=$synclist"];
|
|
|
|
$subreq->({command=>['xdcp'], arg=>$args, env=>$env}, $callback);
|
|
|
|
}
|
2009-06-04 15:33:44 +00:00
|
|
|
}
|
|
|
|
|
2008-09-08 18:54:30 +00:00
|
|
|
my $nodestring=join(',', @$nodes);
|
2008-09-26 23:07:45 +00:00
|
|
|
#print "postscripts=$postscripts, nodestring=$nodestring\n";
|
2008-09-08 18:54:30 +00:00
|
|
|
|
|
|
|
if ($nodestring) {
|
2008-11-09 03:20:21 +00:00
|
|
|
my $cmd;
|
2008-09-11 04:43:33 +00:00
|
|
|
if (xCAT::Utils->isLinux()) {
|
2008-11-09 03:20:21 +00:00
|
|
|
$cmd="XCATBYPASS=Y $::XCATROOT/bin/xdsh $nodestring -s -e /install/postscripts/xcatdsklspost 1 $postscripts 2>&1";
|
2008-09-11 04:43:33 +00:00
|
|
|
}
|
|
|
|
else {
|
2009-03-31 17:41:15 +00:00
|
|
|
$cmd="XCATBYPASS=Y $::XCATROOT/bin/xdsh $nodestring -s -e /install/postscripts/xcataixpost -c 1 $postscripts 2>&1";
|
2008-11-09 03:20:21 +00:00
|
|
|
}
|
|
|
|
if (! open (CMD, "$cmd |")) {
|
|
|
|
my $rsp={};
|
|
|
|
$rsp->{data}->[0]= "Cannot run command $cmd";
|
|
|
|
$callback->($rsp);
|
|
|
|
} else {
|
|
|
|
while (<CMD>) {
|
|
|
|
my $rsp={};
|
|
|
|
$rsp->{data}->[0]= "$_";
|
|
|
|
$callback->($rsp);
|
|
|
|
}
|
|
|
|
close(CMD);
|
2008-09-11 04:43:33 +00:00
|
|
|
}
|
2008-09-08 18:54:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-09-25 03:04:56 +00:00
|
|
|
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}); }
|
|
|
|
}
|
|
|
|
if (ref($request->{arg})) {
|
|
|
|
@args=@{$request->{arg}};
|
|
|
|
} else {
|
|
|
|
@args=($request->{arg});
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((@nodes>0) && (@args>0)) {
|
|
|
|
my %node_status=();
|
|
|
|
my $stat=$args[0];
|
|
|
|
$node_status{$stat}=[];
|
|
|
|
foreach my $node (@nodes) {
|
|
|
|
my $pa=$node_status{$stat};
|
|
|
|
push(@$pa, $node);
|
|
|
|
}
|
2008-11-09 04:01:11 +00:00
|
|
|
xCAT_monitoring::monitorctrl::setNodeStatusAttributes(\%node_status, 1);
|
2008-09-25 03:04:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-09-08 18:54:30 +00:00
|
|
|
|
|
|
|
|
|
|
|
|