xcat-core/xCAT-client-2.0/bin/xdsh

519 lines
14 KiB
Perl

#!/usr/bin/env perl
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
BEGIN
{
$::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : -d '/opt/xcat' ? '/opt/xcat' : '/usr';
}
use lib "$::XCATROOT/lib/perl";
use IO::Socket::SSL;
use IO::Socket::INET;
use File::Basename;
use Data::Dumper;
use Getopt::Long;
use xCAT::MsgUtils;
use xCAT::DSHCLI;
use xCAT::Client submit_request;
my $bname = basename($0);
#-----------------------------------------------------------------------------
=head1 xdsh/xdcp
This program is the client interface for xdsh/xdcp.
xdsh/xdcp command
This is the interface to for xdsh/xdsp
The command can run in client/server mode (default) or in bypass mode
where it does not use the xcat daemon xcatd.
Bypass mode is useful, when executing the command on the Management Server
and in particular if you want to run as a non-root id.
Call parse_args to verify mode (client/server or bypass)
and whether to use Env Variables
Build hash and submit request
See man page for options
=cut
#-----------------------------------------------------------------------------
# Main
my $rc = 0;
# report unsupported dsh exports
&check_invalid_exports;
my $cmdref;
my $arg;
my @SaveARGV = @ARGV;
$cmdref->{command}->[0] = $bname; # save my command name
my $arg = shift(@SaveARGV);
if ($arg =~ /^-/) # no noderange
{
push @{$cmdref->{arg}}, $arg;
foreach (@SAVEARGV)
{
push(@{$cmdref->{arg}}, $_);
}
@ARGV = @{$cmdref->{arg}}; # save just the argument to parse
}
else
{
$cmdref->{noderange}->[0] = $arg; # save noderange
@ARGV = @SaveARGV; # noderange removed for parsing
}
# check for help, bypass, other client flags
if ($bname eq "xdsh")
{
&parse_args_xdsh;
}
else
{ # xdcp
&parse_args_xdcp;
}
foreach (@SaveARGV)
{
push(@{$cmdref->{arg}}, $_);
}
# add environment variables, if they have not already been assigned with
# command line flags
if (!($::NODE_RSH))
{
if ($ENV{'DSH_NODE_RSH'})
{
push(@{$cmdref->{env}}, "DSH_NODE_RSH=$ENV{'DSH_NODE_RSH'}");
}
}
if (!($cmdref->{noderange}->[0])) # if no node range defined
{
if ($ENV{'DSH_LIST'}) # if file of nodes input
{
push(@{$cmdref->{env}}, "DSH_LIST=$ENV{'DSH_LIST'}");
}
}
if (!($::NODE_OPTS))
{
if ($ENV{'DSH_NODE_OPTS'})
{
push(@{$cmdref->{env}}, "DSH_NODE_OPTS=$ENV{'DSH_NODE_OPTS'}");
}
}
if (!($::FANOUT))
{
if ($ENV{'DSH_FANOUT'})
{
push(@{$cmdref->{env}}, "DSH_FANOUT=$ENV{'DSH_FANOUT'}");
}
}
if (!($::TIMEOUT))
{
if ($ENV{'DSH_TIMEOUT'})
{
push(@{$cmdref->{env}}, "DSH_TIMEOUT=$ENV{'DSH_TIMEOUT'}");
}
}
if (!($::CONTEXT_SET))
{
if ($ENV{'DSH_CONTEXT'})
{
push(@{$cmdref->{env}}, "DSH_CONTEXT=$ENV{'DSH_CONTEXT'}");
}
}
xCAT::Client::submit_request($cmdref, \&handle_response);
exit $rc;
#-----------------------------------------------------------------------------
=head3 parse_args_xdsh
Parses for dsh input
Check if the command ask for help and display usage
Need to check only for the -X flag
Need to check -B flag to determine mode
=cut
#-----------------------------------------------------------------------------
sub parse_args_xdsh
{
Getopt::Long::Configure("posix_default");
Getopt::Long::Configure("no_gnu_compat");
Getopt::Long::Configure("bundling");
my %options = ();
if (
!GetOptions(
'e|execute' => \$options{'execute'},
'f|fanout=i' => \$options{'fanout'},
'h|help' => \$options{'help'},
'l|user=s' => \$options{'user'},
'm|monitor' => \$options{'monitor'},
'o|node-options=s' => \$options{'node-options'},
'q|show-config' => \$options{'show-config'},
'r|node-rsh=s' => \$options{'node-rsh'},
's|stream' => \$options{'streaming'},
't|timeout=i' => \$options{'timeout'},
'v|verify' => \$options{'verify'},
'z|exit-status' => \$options{'exit-status'},
'B|bypass' => \$options{'bypass'},
'C|context=s' => \$options{'context'},
'E|environment=s' => \$options{'environment'},
'I|ignore-sig|ignoresig=s' => \$options{'ignore-signal'},
'K|keysetup' => \$options{'ssh-setup'},
'L|no-locale' => \$options{'no-locale'},
'Q|silent' => \$options{'silent'},
'S|syntax=s' => \$options{'syntax'},
'T|trace' => \$options{'trace'},
'V|version' => \$options{'version'},
'command-name|commandName=s' => \$options{'command-name'},
'command-description|commandDescription=s' =>
\$options{'command-description'},
'X:s' => \$options{'ignore_env'}
)
)
{
xCAT::DSHCLI->usage_dsh;
exit 1;
}
if ($options{'help'})
{
xCAT::DSHCLI->usage_dsh;
exit 0;
}
if ($options{'bypass'})
{
$ENV{XCATBYPASS} = "yes"; # bypass xcatd
}
if ($options{'version'})
{
xCAT::MsgUtils->message("I", "Version 2.0\n");
exit 0;
}
if ($options{'node-rsh'}) # if set on command line, use it
{
$::NODE_RSH = 1;
}
if ($options{'node-opts'}) # if set on command line, use it
{
$::NODE_OPTS = 1;
}
if ($options{'fanout'}) # if set on command line, use it
{
$::FANOUT = 1;
}
if ($options{'timeout'}) # if set on command line, use it
{
$::TIMEOUT = 1;
}
if ($options{'context'}) # if a context is specified, use it
{
$::CONTEXT_SET = 1;
}
if (defined $options{'ignore_env'})
{
xCAT::DSHCLI->ignoreEnv($options{'ignore_env'});
}
}
#-----------------------------------------------------------------------------
=head3 parse_args_xdcp
Parses for dcp input
Check if the command ask for help and display usage
Need to check -X flag to determine how to set Environment Variables
Need to check -B flag to determine mode
=cut
#-----------------------------------------------------------------------------
sub parse_args_xdcp
{
my %options = ();
Getopt::Long::Configure("posix_default");
Getopt::Long::Configure("no_gnu_compat");
Getopt::Long::Configure("bundling");
if (
!GetOptions(
'f|fanout=i' => \$options{'fanout'},
'h|help' => \$options{'help'},
'l|user=s' => \$options{'user'},
'n|nodes=s' => \$options{'nodes'},
'o|node-options=s' => \$options{'node-options'},
'q|show-config' => \$options{'show-config'},
'p|preserve' => \$options{'preserve'},
'r|c|node-rcp=s' => \$options{'node-rcp'},
's' => \$options{'rsync'},
't|timeout=i' => \$options{'timeout'},
'v|verify' => \$options{'verify'},
'B|bypass' => \$options{'bypass'},
'C|context=s' => \$options{'context'},
'Q|silent' => \$options{'silent'},
'P|pull' => \$options{'pull'},
'R|recursive' => \$options{'recursive'},
'T|trace' => \$options{'trace'},
'V|version' => \$options{'version'},
'X:s' => \$options{'ignore_env'}
)
)
{
xCAT::DSHCLI->usage_dcp;
exit 1;
}
if ($options{'help'})
{
xCAT::DSHCLI->usage_dcp;
exit 0;
}
if ($options{'version'})
{
xCAT::MsgUtils->message("I", "Version 2.0");
exit 0;
}
if ($::BYPASS)
{
$ENV{XCATBYPASS} = "yes"; # bypass xcatd
}
}
#-----------------------------------------------------------------------------
=head3 check_invalid_exports
Check for unsupported dsh exports and warns
=cut
#-----------------------------------------------------------------------------
sub check_invalid_exports
{
##
# Check for unsupported Environment Variables
# DSH_DEVICE_LIST, DSH_DEVICE_OPTS, DSH_DEVICE_RCP,DSH_DEVICE_RSH,
# DSH_NODEGROUP_PATH
# For support Env Variables tell them to use the command line flag
##
if ($ENV{'DSH_NODE_LIST'})
{
xCAT::MsgUtils->message(
"I",
"DSH_NODE_LIST is set but is not supported. It will be ignored.\n"
);
}
if ($ENV{'WCOLL'})
{
xCAT::MsgUtils->message("I",
"WCOLL is set but is not supported. It will be ignored.\n");
}
if ($ENV{'DSH_DEVICE_LIST'})
{
xCAT::MsgUtils->message(
"I",
"DSH_DEVICE_LIST is set but is not supported. It will be ignored.\n"
);
}
if ($ENV{'DSH_DEVICE_OPTS'})
{
xCAT::MsgUtils->message(
"I",
"DSH_DEVICE_OPTS is set but is not supported. It will be ignored.\n"
);
}
if ($ENV{'DSH_DEVICE_RCP'})
{
xCAT::MsgUtils->message(
"I",
"DSH_DEVICE_RCP is set but is not supported. It will be ignored.\n"
);
}
if ($ENV{'DSH_DEVICE_RSH'})
{
xCAT::MsgUtils->message(
"I",
"DSH_DEVICE_RSH is set but is not supported. It will be ignored.\n"
);
}
if ($ENV{'DSH_NODEGROUP_PATH'})
{
xCAT::MsgUtils->message(
"I",
"DSH_NODEGROUP_PATH is set but is not supported. It will be ignored.\n"
);
}
if ($ENV{'RSYNC_RSH'})
{
xCAT::MsgUtils->message("I",
" RSYNC_RSH is set but is not supported. It will be ignored.\n");
}
if ($ENV{'DSH_REPORT'})
{
xCAT::MsgUtils->message("I",
" DSH_REPORT is set but is not supported. It will be ignored.\n");
}
}
#-----------------------------------------------------------------------------
=head3 handle_response
handle_response is the callback that is
invoked to print out the data returned by
the plugin.
Format of the response hash:
{data => [ 'data str1', 'data str2', '...' ] }
Results are printed as:
data str1
data str2
or:
{data => [ {desc => [ 'desc1' ],
contents => [ 'contents1' ] },
{desc => [ 'desc2 ],
contents => [ 'contents2' ] }
:
] }
NOTE: In this format, only the data array can have more than one
element. All other arrays are assumed to be a single element.
Results are printed as:
desc1: contents1
desc2: contents2
or:
{node => [ {name => ['node1'],
data => [ {desc => [ 'node1 desc' ],
contents => [ 'node1 contents' ] } ] },
{name => ['node2'],
data => [ {desc => [ 'node2 desc' ],
contents => [ 'node2 contents' ] } ] },
:
] }
NOTE: Only the node array can have more than one element.
All other arrays are assumed to be a single element.
This was generated from the corresponding HTML:
<xcatrequest>
<node>
<name>node1</name>
<data>
<desc>node1 desc</desc>
<contents>node1 contents</contents>
</data>
</node>
<node>
<name>node2</name>
<data>
<desc>node2 desc</desc>
<contents>node2 contents</contents>
</data>
</node>
</xcatrequest>
Results are printed as:
node_name: desc: contents
=cut
#-----------------------------------------------------------------------------
sub handle_response
{
my $rsp = shift;
# Handle {node} structure
if ($rsp->{errorcode})
{
foreach my $ecode (@{$rsp->{errorcode}})
{
$exitcode |= $ecode;
}
}
# Handle {node} structure
if ($rsp->{node})
{
my $nodes = ($rsp->{node});
my $node;
foreach $node (@$nodes)
{
my $desc = $node->{name}->[0];
if ($node->{data})
{
if (ref(\($node->{data}->[0])) eq 'SCALAR')
{
$desc = $desc . ": " . $node->{data}->[0];
}
else
{
if ($node->{data}->[0]->{desc})
{
$desc = $desc . ": " . $node->{data}->[0]->{desc}->[0];
}
if ($node->{data}->[0]->{contents})
{
$desc = "$desc: " . $node->{data}->[0]->{contents}->[0];
}
}
}
if ($desc)
{
print "$desc\n";
}
}
}
# Handle {data} structure with no nodes
if ($rsp->{data})
{
my $data = ($rsp->{data});
my $data_entry;
foreach $data_entry (@$data)
{
my $desc;
if (ref(\($data_entry)) eq 'SCALAR')
{
$desc = $data_entry;
}
else
{
if ($data_entry->{desc})
{
$desc = $data_entry->{desc}->[0];
}
if ($data_entry->{contents})
{
if ($desc)
{
$desc = "$desc: " . $data_entry->{contents}->[0];
}
else
{
$desc = $data_entry->{contents}->[0];
}
}
}
if ($desc)
{
print "$desc\n";
}
}
}
}