xcat-core/xCAT-server/lib/xcat/plugins/xdsh.pm
2009-09-21 13:09:26 +00:00

380 lines
12 KiB
Perl

# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
#-------------------------------------------------------
=head1
xCAT plugin package to handle xdsh
Supported command:
xdsh-> dsh
xdcp-> dcp
=cut
#-------------------------------------------------------
package xCAT_plugin::xdsh;
use strict;
use Storable qw(dclone);
use File::Basename;
use File::Path;
require xCAT::Table;
require xCAT::Utils;
require xCAT::MsgUtils;
use Getopt::Long;
require xCAT::DSHCLI;
1;
#-------------------------------------------------------
=head3 handled_commands
Return list of commands handled by this plugin
=cut
#-------------------------------------------------------
sub handled_commands
{
return {
xdsh => "xdsh",
xdcp => "xdsh"
};
}
#-------------------------------------------------------
=head3 preprocess_request
Check and setup for hierarchy
=cut
#-------------------------------------------------------
sub preprocess_request
{
my $req = shift;
my $cb = shift;
my %sn;
my $sn;
my $command = $req->{command}->[0]; # xdsh vs xdcp
#if already preprocessed, go straight to request
if ($req->{_xcatpreprocessed}->[0] == 1) { return [$req]; }
my $nodes = $req->{node};
my $service = "xcat";
my @requests;
my $syncsn = 0;
my $syncsnfile;
# read the environment variables for rsync setup
foreach my $envar (@{$req->{env}})
{
my ($var, $value) = split(/=/, $envar, 2);
if ($var eq "RSYNCSNONLY")
{ # syncing SN, will change noderange to list of SN
# we are only syncing the service node ( -s flag)
$syncsn = 1;
}
if ($var eq "DSH_RSYNC_FILE") # from -F flag
{ # if hierarchy,need to copy file to the SN
$syncsnfile = $value; # in the new /tmp/xcatrf.tmp
}
}
# find service nodes for requested nodes
# build an individual request for each service node
# find out the names for the Management Node
my @MNnodeinfo = xCAT::Utils->determinehostname;
my $MNnodename = pop @MNnodeinfo; # hostname
my @MNnodeipaddr = @MNnodeinfo; # ipaddresses
my $mnname = $MNnodeipaddr[0];
my $tmpsyncsnfile = "/tmp/xcatrf.tmp";
my $SNpath;
my $synfiledir = "/var/xcat/syncfiles"; # default
if ($nodes)
{
$sn = xCAT::Utils->get_ServiceNode($nodes, $service, "MN");
my @snodes;
my @snoderange;
# check to see if service nodes and not just the MN
if ($sn)
{
foreach my $snkey (keys %$sn)
{
if (!grep(/$snkey/, @MNnodeipaddr))
{ # if not the MN
push @snodes, $snkey;
$snoderange[0] .= "$snkey,";
}
}
if (@snodes)
{
# get the directory on the servicenode to put the files in
my @syndir = xCAT::Utils->get_site_attribute("SNsyncfiledir");
if ($syndir[0])
{
$synfiledir = $syndir[0];
}
# if -F command and service nodes first need to rsync the SN
if ($syncsnfile)
{
#change noderange to the service nodes
my $addreq;
chop $snoderange[0];
$addreq->{'_xcatdest'} = $mnname;
$addreq->{node} = \@snodes;
$addreq->{noderange} = \@snoderange;
$addreq->{arg}->[0] = "-s";
$addreq->{arg}->[1] = "-F";
$addreq->{arg}->[2] = $syncsnfile;
$addreq->{command}->[0] = $req->{command}->[0];
$addreq->{cwd}->[0] = $req->{cwd}->[0];
push @requests, $addreq;
# need to add to the queue to copy rsync file( -F input)
# to the service node to the /tmp/xcatrf.tmp file
my $addreq;
$addreq->{'_xcatdest'} = $mnname;
$addreq->{node} = \@snodes;
$addreq->{noderange} = \@snoderange;
$addreq->{arg}->[0] = $syncsnfile;
$addreq->{arg}->[1] = $tmpsyncsnfile;
$addreq->{command}->[0] = $req->{command}->[0];
$addreq->{cwd}->[0] = $req->{cwd}->[0];
push @requests, $addreq;
}
else
{
# if other xdcp command
# mk the diretory on the SN to hold the files
# to be sent to the CN.
# build a command to update the service nodes
# change the destination to the tmp location on
# the service node.
if ($command eq "xdcp")
{
#make the needed directory on the service node
# create new directory for path on Service Node
my $frompath = $req->{arg}->[-2];
$SNpath = $synfiledir;
$SNpath .= $frompath;
my $SNdir;
$SNdir = dirname($SNpath); # get directory
my $addreq= dclone($req);
$addreq->{'_xcatdest'} = $mnname;
$addreq->{node} = \@snodes;
$addreq->{noderange} = \@snoderange;
$addreq->{arg}->[0] = "mkdir ";
$addreq->{arg}->[1] = "-p ";
$addreq->{arg}->[2] = $SNdir;
$addreq->{command}->[0] = "xdsh";
$addreq->{cwd}->[0] = $req->{cwd}->[0];
push @requests, $addreq;
# now sync file to the service node to the new
# tmp path
my $addreq = dclone($req);
$addreq->{'_xcatdest'} = $mnname;
chop $snoderange[0];
$addreq->{node} = \@snodes;
$addreq->{noderange} = \@snoderange;
$addreq->{arg}->[-1] = $SNdir;
push @requests, $addreq;
}
}
}
} # end if SN
# if not only syncing the service nodes ( -s flag)
# for each node build the
# the command, to sync from the service node
if ($syncsn == 0)
{ #syncing nodes ( no -s flag)
foreach my $snkey (keys %$sn)
{
if (!grep(/$snkey/, @MNnodeipaddr))
{ # entries run from the Service Node
# if the -F option to sync the nodes
# then for a Service Node
# change the command to use the -F /tmp/xcatrf.tmp
# because that is where the file was put on the SN
#
my $newSNreq = dclone($req);
if ($syncsnfile) # -F option
{
my $args = $newSNreq->{arg};
my $i = 0;
foreach my $argument (@$args)
{
# find the -F and change the name of the
# file in the next array entry to the tmp file
if ($argument eq "-F")
{
$i++;
$newSNreq->{arg}->[$i] = $tmpsyncsnfile;
last;
}
$i++;
}
}
else
{ # if other dcp command, change from directory
# to be the tmp directory on the service node
if ($command eq "xdcp")
{
$newSNreq->{arg}->[-2] = $SNpath;
}
}
$newSNreq->{node} = $sn->{$snkey};
$newSNreq->{'_xcatdest'} = $snkey;
$newSNreq->{_xcatpreprocessed}->[0] = 1;
push @requests, $newSNreq;
}
else
{ # just run normal dsh dcp
my $reqcopy = {%$req};
$reqcopy->{node} = $sn->{$snkey};
$reqcopy->{'_xcatdest'} = $snkey;
$reqcopy->{_xcatpreprocessed}->[0] = 1;
push @requests, $reqcopy;
}
} # end foreach
} # end syncing only service nodes
}
else
{ # running local on image
return [$req];
}
return \@requests;
}
#-------------------------------------------------------
=head3 process_request
Process the command
=cut
#-------------------------------------------------------
sub process_request
{
my $request = shift;
my $callback = shift;
my $nodes = $request->{node};
my $command = $request->{command}->[0];
my $args = $request->{arg};
my $envs = $request->{env};
my $rsp = {};
# get the Environment Variables and set them in the current environment
foreach my $envar (@{$request->{env}})
{
my ($var, $value) = split(/=/, $envar, 2);
$ENV{$var} = $value;
}
if ($command eq "xdsh")
{
xdsh($nodes, $args, $callback, $command, $request->{noderange}->[0]);
}
else
{
if ($command eq "xdcp")
{
xdcp($nodes, $args, $callback, $command,
$request->{noderange}->[0]);
}
else
{
my $rsp = {};
$rsp->{data}->[0] =
"Unknown command $command. Cannot process the command.";
xCAT::MsgUtils->message("E", $rsp, $callback, 1);
return;
}
}
}
#-------------------------------------------------------
=head3 xdsh
Parses Builds and runs the dsh
=cut
#-------------------------------------------------------
sub xdsh
{
my ($nodes, $args, $callback, $command, $noderange) = @_;
my $rsp = {};
# parse dsh input
my @local_results =
xCAT::DSHCLI->parse_and_run_dsh($nodes, $args, $callback,
$command, $noderange);
push @{$rsp->{data}}, @local_results;
xCAT::MsgUtils->message("D", $rsp, $callback);
return;
}
#-------------------------------------------------------
=head3 xdcp
Parses, Builds and runs the dcp command
=cut
#-------------------------------------------------------
sub xdcp
{
my ($nodes, $args, $callback, $command, $noderange) = @_;
#`touch /tmp/lissadebug`;
# parse dcp input
my @local_results =
xCAT::DSHCLI->parse_and_run_dcp($nodes, $args, $callback,
$command, $noderange);
my $rsp = {};
my $i = 0;
## process return data
foreach my $line (@local_results)
{
$rsp->{data}->[$i] = $line;
$i++;
}
xCAT::MsgUtils->message("D", $rsp, $callback);
if (-e "/tmp/xcatrf.tmp")
{ # used tmp file for -F option
#`rm /tmp/xcatrf.tmp`;
}
return;
}