supporting Mellanox IB switch configurations in rspconfig command, more to come
git-svn-id: https://svn.code.sf.net/p/xcat/code/xcat-core/trunk@10761 8638fb3e-16cb-4fca-ae20-7b5d299a9bcd
This commit is contained in:
parent
3c52d63526
commit
efa5bf9b1b
624
xCAT-server/lib/perl/xCAT/MellanoxIB.pm
Normal file
624
xCAT-server/lib/perl/xCAT/MellanoxIB.pm
Normal file
@ -0,0 +1,624 @@
|
||||
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
|
||||
package xCAT::MellanoxIB;
|
||||
BEGIN
|
||||
{
|
||||
$::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat';
|
||||
}
|
||||
use lib "$::XCATROOT/lib/perl";
|
||||
|
||||
|
||||
use IO::Socket;
|
||||
use Data::Dumper;
|
||||
use xCAT::NodeRange;
|
||||
use xCAT::Utils;
|
||||
use Sys::Syslog;
|
||||
use Expect;
|
||||
use Storable;
|
||||
use strict;
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
=head1 xCAT::MellanoxIB
|
||||
=head2 Package Description
|
||||
It handles Mellanox IB switch related function. It used the CLI interface of
|
||||
Mellanox IB switch
|
||||
|
||||
=cut
|
||||
#--------------------------------------------------------------------------------
|
||||
|
||||
#--------------------------------------------------------------------------------
|
||||
=head3 getConfigure
|
||||
It queries the info from the given swithes.
|
||||
Arguments:
|
||||
noderange-- an array ref to switches.
|
||||
callback -- pointer for writes response back to the client.
|
||||
suncommand --- attribute to query about.
|
||||
Returns:
|
||||
0 --- sucessful
|
||||
none 0 --- unsuccessful.
|
||||
=cut
|
||||
#--------------------------------------------------------------------------------
|
||||
sub getConfig {
|
||||
my $noderange=shift;
|
||||
if ($noderange =~ /xCAT::MellanoxIB/) {
|
||||
$noderange=shift;
|
||||
}
|
||||
my $callback=shift;
|
||||
my $subreq=shift;
|
||||
my $subcommand=shift;
|
||||
|
||||
#handle sshcfg with expect script
|
||||
if ($subcommand eq "sshcfg") {
|
||||
return querySSHcfg($noderange,$callback);
|
||||
}
|
||||
|
||||
#get the username and the password
|
||||
my $swstab=xCAT::Table->new('switches',-create=>1);
|
||||
my $sws_hash = $swstab->getNodesAttribs($noderange,['sshusername']);
|
||||
|
||||
my $passtab = xCAT::Table->new('passwd');
|
||||
my $ent;
|
||||
($ent) = $passtab->getAttribs({key => "switch"}, qw(username));
|
||||
|
||||
foreach my $node (@$noderange) {
|
||||
my $cmd;
|
||||
my $username;
|
||||
if ($sws_hash->{$node}->[0]) {
|
||||
$username=$sws_hash->{$node}->[0]->{sshusername};
|
||||
}
|
||||
if (!$username) {
|
||||
if ($ent) {
|
||||
$username=$ent->{username};
|
||||
}
|
||||
}
|
||||
if (!$username) {
|
||||
$username="xcat";
|
||||
}
|
||||
|
||||
if (($subcommand eq "alert") || ($subcommand eq "snmpcfg") || ($subcommand eq "community") || ($subcommand eq "snmpdest")) {
|
||||
$cmd='show snmp';
|
||||
}
|
||||
else {
|
||||
my $rsp = {};
|
||||
$rsp->{error}->[0] = "Unsupported subcommand: $subcommand";
|
||||
$callback->($rsp);
|
||||
return;
|
||||
}
|
||||
|
||||
#now goto the switch and get the output
|
||||
my $output = xCAT::Utils->runxcmd({command => ["xdsh"], node =>[$node], arg => ["--devicetype", "IBSwitch::Mellanox", "$cmd"], env=>["DSH_TO_USERID=$username"]}, $subreq, -1, 1);
|
||||
if ($output) {
|
||||
my $result=parseOutput($node, $subcommand, $output);
|
||||
my $rsp = {};
|
||||
my $i=-1;
|
||||
foreach my $o (@$result) {
|
||||
$i++;
|
||||
$rsp->{data}->[$i] = $o;
|
||||
}
|
||||
$callback->($rsp);
|
||||
}
|
||||
|
||||
} #end foreach
|
||||
}
|
||||
|
||||
sub parseOutput {
|
||||
my $node=shift;
|
||||
my $subcommand=shift;
|
||||
my $input=shift; #an array pointer
|
||||
|
||||
my $output;
|
||||
if ($subcommand eq "alert") {
|
||||
foreach my $tmpstr (@$input) {
|
||||
if ($tmpstr =~ /Traps enabled:/) {
|
||||
if ($tmpstr =~ /yes/) {
|
||||
$output=["$node: Switch Alerting enabled"];
|
||||
} else {
|
||||
$output=["$node: Switch Alerting disabled"];
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($output) { return $output; }
|
||||
} elsif ($subcommand eq "snmpcfg") {
|
||||
foreach my $tmpstr (@$input) {
|
||||
if ($tmpstr =~ /SNMP enabled:/) {
|
||||
if ($tmpstr =~ /yes/) {
|
||||
$output=["$node: SNMP enabled"];
|
||||
} else {
|
||||
$output=["$node: SNMP disabled"];
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($output) { return $output; }
|
||||
} elsif ($subcommand eq "snmpdest") {
|
||||
my $found=0;
|
||||
my $j=0;
|
||||
foreach my $tmpstr (@$input) {
|
||||
if ((!$found) && ($tmpstr =~ /Trap sinks:/)) {
|
||||
$found=1;
|
||||
$output->[0]="$node: SNMP Destination:";
|
||||
}
|
||||
|
||||
if ($tmpstr =~ /Events for which/) {
|
||||
if (!$found) {
|
||||
next;
|
||||
} else {
|
||||
last;
|
||||
}
|
||||
}
|
||||
if ($found) {
|
||||
$tmpstr =~ s/$node: //g;
|
||||
$output->[++$j]=$tmpstr;
|
||||
}
|
||||
}
|
||||
if ($output) { return $output; }
|
||||
} elsif ($subcommand eq "community") {
|
||||
foreach my $tmpstr (@$input) {
|
||||
if ($tmpstr =~ /Read-only community:/) {
|
||||
my @a=split(':', $tmpstr);
|
||||
my $c_str;
|
||||
if (@a > 2) {
|
||||
$c_str=$a[2];
|
||||
}
|
||||
$output=["$node: SNMP Community: $c_str"];
|
||||
}
|
||||
}
|
||||
if ($output) { return $output; }
|
||||
}
|
||||
|
||||
return $input #an array pointer
|
||||
}
|
||||
|
||||
|
||||
#--------------------------------------------------------------------------------
|
||||
=head3 setConfigure
|
||||
It configures the the given swithes.
|
||||
Arguments:
|
||||
noderange-- an array ref to switches.
|
||||
callback -- pointer for writes response back to the client.
|
||||
suncommand --- attribute to set.
|
||||
Returns:
|
||||
0 --- sucessful
|
||||
none 0 --- unsuccessful.
|
||||
=cut
|
||||
#--------------------------------------------------------------------------------
|
||||
sub setConfig {
|
||||
my $noderange=shift;
|
||||
if ($noderange =~ /xCAT::MellanoxIB/) {
|
||||
$noderange=shift;
|
||||
}
|
||||
my $callback=shift;
|
||||
my $subreq=shift;
|
||||
my $subcommand=shift;
|
||||
my $argument=shift;
|
||||
|
||||
#handle sshcfg with expect script
|
||||
if ($subcommand eq "sshcfg") {
|
||||
if($argument eq "on" or $argument =~ /^en/ or $argument =~ /^enable/) {
|
||||
return setSSHcfg($noderange, $callback, 1);
|
||||
}
|
||||
elsif ($argument eq "off" or $argument =~ /^dis/ or $argument =~ /^disable/) {
|
||||
return setSSHcfg($noderange, $callback, 0);
|
||||
} else {
|
||||
my $rsp = {};
|
||||
$rsp->{error}->[0] = "Unsupported argument for sshcfg: $argument";
|
||||
$callback->($rsp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
#get the username and the password
|
||||
my $swstab=xCAT::Table->new('switches',-create=>1);
|
||||
my $sws_hash = $swstab->getNodesAttribs($noderange,['sshusername']);
|
||||
|
||||
my $passtab = xCAT::Table->new('passwd');
|
||||
my $ent;
|
||||
($ent) = $passtab->getAttribs({key => "switch"}, qw(username));
|
||||
|
||||
foreach my $node (@$noderange) {
|
||||
my @cfgcmds;
|
||||
my $username;
|
||||
if ($sws_hash->{$node}->[0]) {
|
||||
$username=$sws_hash->{$node}->[0]->{sshusername};
|
||||
}
|
||||
if (!$username) {
|
||||
if ($ent) {
|
||||
$username=$ent->{username};
|
||||
}
|
||||
}
|
||||
if (!$username) {
|
||||
$username="xcat"; #default ssh username
|
||||
}
|
||||
|
||||
if ($subcommand eq "alert") {
|
||||
if($argument eq "on" or $argument =~ /^en/ or $argument =~ /^enable/) {
|
||||
my $ip="9.114.154.69";
|
||||
$cfgcmds[0]="snmp-server enable traps";
|
||||
$cfgcmds[1]="snmp-server host$ip traps version 2c public";
|
||||
}
|
||||
elsif ($argument eq "off" or $argument =~ /^dis/ or $argument =~ /^disable/) {
|
||||
my $ip="9.114.154.69";
|
||||
$cfgcmds[0]="snmp-server host $ip disable";
|
||||
} else {
|
||||
my $rsp = {};
|
||||
$rsp->{error}->[0] = "Unsupported argument for $subcommand: $argument";
|
||||
$callback->($rsp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
elsif ($subcommand eq "snmpcfg") {
|
||||
if($argument eq "on" or $argument =~ /^en/ or $argument =~ /^enable/) {
|
||||
$cfgcmds[0]="snmp-server enable";
|
||||
}
|
||||
elsif ($argument eq "off" or $argument =~ /^dis/ or $argument =~ /^disable/) {
|
||||
$cfgcmds[0]="no snmp-server enable";
|
||||
} else {
|
||||
my $rsp = {};
|
||||
$rsp->{error}->[0] = "Unsupported argument for $subcommand: $argument";
|
||||
$callback->($rsp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
elsif ($subcommand eq "community") {
|
||||
$cfgcmds[0]="snmp-server community $argument";
|
||||
}
|
||||
elsif ($subcommand eq "snmpdest") {
|
||||
$cfgcmds[0]="snmp-server host $argument traps version 2c public";
|
||||
}
|
||||
else {
|
||||
my $rsp = {};
|
||||
$rsp->{error}->[0] = "Unsupported subcommand: $subcommand";
|
||||
$callback->($rsp);
|
||||
return;
|
||||
}
|
||||
|
||||
#now do the real bussiness
|
||||
my $cmd="enable;configure terminal";
|
||||
foreach (@cfgcmds) {
|
||||
$cmd .= ";$_";
|
||||
}
|
||||
my $output = xCAT::Utils->runxcmd({command => ["xdsh"], node =>[$node], arg => ["--devicetype", "IBSwitch::Mellanox", "$cmd"], env=>["DSH_TO_USERID=$username"]}, $subreq, -1, 1);
|
||||
|
||||
#only print out the error
|
||||
if ($::RUNCMD_RC != 0) {
|
||||
if ($output) {
|
||||
my $rsp = {};
|
||||
my $i=-1;
|
||||
foreach my $o (@$output) {
|
||||
$i++;
|
||||
$rsp->{data}->[$i] = $o;
|
||||
}
|
||||
$callback->($rsp);
|
||||
}
|
||||
}
|
||||
|
||||
#now qerry
|
||||
return getConfig($noderange, $callback, $subreq, $subcommand);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#--------------------------------------------------------------------------------
|
||||
=head3 querySSHcfg
|
||||
It checks if the current host can ssh to the given switches without password.
|
||||
Arguments:
|
||||
noderange-- an array ref to switches.
|
||||
callback -- pointer for writes response back to the client.
|
||||
Returns:
|
||||
0 --- sucessful
|
||||
none 0 --- unsuccessful.
|
||||
=cut
|
||||
#--------------------------------------------------------------------------------
|
||||
sub querySSHcfg {
|
||||
my $noderange=shift;
|
||||
if ($noderange =~ /xCAT::MellanoxIB/) {
|
||||
$noderange=shift;
|
||||
}
|
||||
my $callback=shift;
|
||||
|
||||
my $mysw;
|
||||
my $enable_cmd="enable\r";
|
||||
my $exit_cmd="exit\r";
|
||||
|
||||
my $pwd_prompt = "Password: ";
|
||||
my $sw_prompt = "^.*\] > ";
|
||||
my $enable_prompt="^.*\] \#";
|
||||
my $expstr="SSH authorized keys:";
|
||||
|
||||
|
||||
my $debug = 0;
|
||||
if ($::VERBOSE)
|
||||
{
|
||||
$debug = 1;
|
||||
}
|
||||
|
||||
|
||||
#get the username and the password
|
||||
my $swstab=xCAT::Table->new('switches',-create=>1);
|
||||
my $sws_hash = $swstab->getNodesAttribs($noderange,['sshusername','sshpassword']);
|
||||
my $passtab = xCAT::Table->new('passwd');
|
||||
my $ent;
|
||||
($ent) = $passtab->getAttribs({key => "switch"}, qw(username password));
|
||||
|
||||
|
||||
#get the ssh public key from this host
|
||||
my $fname = ((xCAT::Utils::isAIX()) ? "/.ssh/":"/root/.ssh/")."id_rsa.pub";
|
||||
unless ( open(FH,"<$fname") ) {
|
||||
$callback->({error=>["Error opening file $fname."],errorcode=>[1]});
|
||||
return 1;
|
||||
}
|
||||
my ($sshkey) = <FH>;
|
||||
close(FH);
|
||||
#remove the userid@host part
|
||||
my @tmpa=split(' ', $sshkey);
|
||||
if (@tmpa > 2) {
|
||||
$sshkey=$tmpa[0] . ' ' . $tmpa[1];
|
||||
}
|
||||
|
||||
|
||||
foreach my $node (@$noderange) {
|
||||
my $username;
|
||||
my $passwd;
|
||||
if ($sws_hash->{$node}->[0]) {
|
||||
#print "got to switches table\n";
|
||||
$username=$sws_hash->{$node}->[0]->{sshusername};
|
||||
$passwd=$sws_hash->{$node}->[0]->{sshpassword};
|
||||
}
|
||||
if (!$username) {
|
||||
#print "got to passwd table\n";
|
||||
if ($ent) {
|
||||
$username=$ent->{username};
|
||||
$passwd=$ent->{password};
|
||||
}
|
||||
}
|
||||
|
||||
unless ($username) {
|
||||
$callback->({error=>["Unable to get the username and the password for node $node. Please fill the switches table or the password table."],errorcode=>[1]});
|
||||
next;
|
||||
}
|
||||
|
||||
#print "username=$username, password=$passwd\n";
|
||||
|
||||
$mysw = new Expect;
|
||||
$mysw->exp_internal($debug);
|
||||
#
|
||||
# log_stdout(0) prevent the program's output from being shown.
|
||||
# turn on if debugging error
|
||||
$mysw->log_stdout($debug);
|
||||
|
||||
my @cfgcmds=();
|
||||
$cfgcmds[0]="show ssh client\r";
|
||||
my $login_cmd = "ssh -l $username $node\r";
|
||||
my $passwd_cmd="$passwd\r";
|
||||
unless ($mysw->spawn($login_cmd))
|
||||
{
|
||||
$mysw->soft_close();
|
||||
my $rsp;
|
||||
$rsp->{data}->[0]="Unable to run $login_cmd.";
|
||||
xCAT::MsgUtils->message("I", $rsp, $callback);
|
||||
next;
|
||||
}
|
||||
|
||||
my @result = $mysw->expect(
|
||||
5,
|
||||
[
|
||||
$pwd_prompt,
|
||||
sub {
|
||||
$mysw->clear_accum();
|
||||
$mysw->send($passwd_cmd);
|
||||
print "$node: password sent\n";
|
||||
$mysw->exp_continue();
|
||||
}
|
||||
],
|
||||
[
|
||||
"-re", $sw_prompt,
|
||||
sub {
|
||||
print "$node: sending command: $enable_cmd\n";
|
||||
$mysw->clear_accum();
|
||||
$mysw->send($enable_cmd);
|
||||
$mysw->exp_continue();
|
||||
}
|
||||
],
|
||||
[
|
||||
"-re", $enable_prompt,
|
||||
sub {
|
||||
print "$node: sending command: $cfgcmds[0]\n";
|
||||
$mysw->clear_accum();
|
||||
$mysw->send($cfgcmds[0]);
|
||||
$mysw->send(" ");
|
||||
sleep 1;
|
||||
$mysw->exp_continue();
|
||||
}
|
||||
],
|
||||
[
|
||||
$expstr,
|
||||
sub {
|
||||
print "got here\n";
|
||||
my $tmp=$mysw->after();
|
||||
my $tmp1=`echo "$tmp" \|col`;
|
||||
my @a=split('\n', $tmp1);
|
||||
my $line=0;
|
||||
foreach (@a) {
|
||||
$line++;
|
||||
print "$line ::: $_\n";
|
||||
}
|
||||
|
||||
#$rsp->{data}->[0]="$node: $outstr";
|
||||
#$callback->($rsp);
|
||||
$mysw->clear_accum();
|
||||
$mysw->send($exit_cmd);
|
||||
}
|
||||
]
|
||||
|
||||
);
|
||||
|
||||
if (defined($result[1]))
|
||||
{
|
||||
my $errmsg = $result[1];
|
||||
$mysw->soft_close();
|
||||
my $rsp;
|
||||
$rsp->{data}->[0]="$node: command error: $result[1]";
|
||||
xCAT::MsgUtils->message("I",$rsp, $callback);
|
||||
next;
|
||||
|
||||
}
|
||||
$mysw->soft_close();
|
||||
}
|
||||
}
|
||||
|
||||
#--------------------------------------------------------------------------------
|
||||
=head3 setSSHcfg
|
||||
It enables/diables the current host to ssh to the given switches without password.
|
||||
Arguments:
|
||||
noderange-- an array ref to switches.
|
||||
callback -- pointer for writes response back to the client.
|
||||
Returns:
|
||||
0 --- sucessful
|
||||
none 0 --- unsuccessful.
|
||||
=cut
|
||||
#--------------------------------------------------------------------------------
|
||||
sub setSSHcfg {
|
||||
my $noderange=shift;
|
||||
if ($noderange =~ /xCAT::MellanoxIB/) {
|
||||
$noderange=shift;
|
||||
}
|
||||
my $callback=shift;
|
||||
my $enable=shift;
|
||||
|
||||
my $mysw;
|
||||
my $enable_cmd="enable\r";
|
||||
my $config_cmd="configure terminal\r";
|
||||
my $exit_cmd="exit\r";
|
||||
|
||||
my $pwd_prompt = "Password: ";
|
||||
my $sw_prompt = "^.*\] > ";
|
||||
my $enable_prompt="^.*\] \#";
|
||||
my $config_prompt="^.*\\\(config\\\) \#";
|
||||
|
||||
|
||||
my $debug = 0;
|
||||
if ($::VERBOSE)
|
||||
{
|
||||
$debug = 1;
|
||||
}
|
||||
|
||||
#get the username and the password
|
||||
my $swstab=xCAT::Table->new('switches',-create=>1);
|
||||
my $sws_hash = $swstab->getNodesAttribs($noderange,['sshusername','sshpassword']);
|
||||
|
||||
my $passtab = xCAT::Table->new('passwd');
|
||||
my $ent;
|
||||
($ent) = $passtab->getAttribs({key => "switch"}, qw(username password));
|
||||
|
||||
#get the ssh public key from this host
|
||||
my $fname = ((xCAT::Utils::isAIX()) ? "/.ssh/":"/root/.ssh/")."id_rsa.pub";
|
||||
unless ( open(FH,"<$fname") ) {
|
||||
$callback->({error=>["Error opening file $fname."],errorcode=>[1]});
|
||||
return 1;
|
||||
}
|
||||
my ($sshkey) = <FH>;
|
||||
close(FH);
|
||||
#remove the userid@host part
|
||||
#my @tmpa=split(' ', $sshkey);
|
||||
#if (@tmpa > 2) {
|
||||
# $sshkey=$tmpa[0] . ' ' . $tmpa[1];
|
||||
#}
|
||||
|
||||
foreach my $node (@$noderange) {
|
||||
my $username;
|
||||
my $passwd;
|
||||
if ($sws_hash->{$node}->[0]) {
|
||||
#print "got to switches table\n";
|
||||
$username=$sws_hash->{$node}->[0]->{sshusername};
|
||||
$passwd=$sws_hash->{$node}->[0]->{sshpassword};
|
||||
}
|
||||
if (!$username) {
|
||||
#print "got to passwd table\n";
|
||||
if ($ent) {
|
||||
$username=$ent->{username};
|
||||
$passwd=$ent->{password};
|
||||
}
|
||||
}
|
||||
|
||||
unless ($username) {
|
||||
$callback->({error=>["Unable to get the username and the password for node $node. Please fill the switches table or the password table."],errorcode=>[1]});
|
||||
next;
|
||||
}
|
||||
|
||||
print "username=$username, password=$passwd\n";
|
||||
$mysw = new Expect;
|
||||
$mysw->exp_internal($debug);
|
||||
#
|
||||
# log_stdout(0) prevent the program's output from being shown.
|
||||
# turn on if debugging error
|
||||
$mysw->log_stdout($debug);
|
||||
|
||||
my @cfgcmds=();
|
||||
$cfgcmds[0]="ssh client user $username authorized-key sshv2 \"$sshkey\"\r";
|
||||
my $login_cmd = "ssh -l $username $node\r";
|
||||
my $passwd_cmd="$passwd\r";
|
||||
unless ($mysw->spawn($login_cmd))
|
||||
{
|
||||
$mysw->soft_close();
|
||||
my $rsp;
|
||||
$rsp->{data}->[0]="Unable to run $login_cmd.";
|
||||
xCAT::MsgUtils->message("I", $rsp, $callback);
|
||||
next;
|
||||
}
|
||||
|
||||
my @result = $mysw->expect(
|
||||
5,
|
||||
[
|
||||
$pwd_prompt,
|
||||
sub {
|
||||
$mysw->clear_accum();
|
||||
$mysw->send($passwd_cmd);
|
||||
print "$node: password sent\n";
|
||||
$mysw->exp_continue();
|
||||
}
|
||||
],
|
||||
[
|
||||
"-re", $sw_prompt,
|
||||
sub {
|
||||
print "$node: sending command: $enable_cmd\n";
|
||||
$mysw->clear_accum();
|
||||
$mysw->send($enable_cmd);
|
||||
$mysw->exp_continue();
|
||||
}
|
||||
],
|
||||
[
|
||||
"-re", $enable_prompt,
|
||||
sub {
|
||||
print "$node: sending command: $config_cmd\n";
|
||||
$mysw->clear_accum();
|
||||
$mysw->send($config_cmd);
|
||||
$mysw->exp_continue();
|
||||
}
|
||||
],
|
||||
[
|
||||
"-re", $config_prompt,
|
||||
sub {
|
||||
print "$node: sending command: $cfgcmds[0]\n";
|
||||
$mysw->clear_accum();
|
||||
$mysw->send($cfgcmds[0]);
|
||||
sleep 1;
|
||||
$mysw->send($exit_cmd);
|
||||
}
|
||||
],
|
||||
);
|
||||
|
||||
if (defined($result[1]))
|
||||
{
|
||||
my $errmsg = $result[1];
|
||||
$mysw->soft_close();
|
||||
my $rsp;
|
||||
$rsp->{data}->[0]="$node: command error: $result[1]";
|
||||
xCAT::MsgUtils->message("I",$rsp, $callback);
|
||||
next;
|
||||
|
||||
}
|
||||
$mysw->soft_close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
1;
|
@ -1,80 +1,249 @@
|
||||
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
|
||||
package xCAT_plugin::switch;
|
||||
BEGIN
|
||||
{
|
||||
$::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat';
|
||||
}
|
||||
use lib "$::XCATROOT/lib/perl";
|
||||
|
||||
|
||||
use IO::Socket;
|
||||
use Data::Dumper;
|
||||
use xCAT::MacMap;
|
||||
use xCAT::NodeRange;
|
||||
use Sys::Syslog;
|
||||
use Storable;
|
||||
use xCAT::MellanoxIB;
|
||||
|
||||
my $macmap;
|
||||
sub handled_commands {
|
||||
$macmap = xCAT::MacMap->new();
|
||||
return {
|
||||
findme => 'switch',
|
||||
findmac => 'switch',
|
||||
};
|
||||
$macmap = xCAT::MacMap->new();
|
||||
return {
|
||||
findme => 'switch',
|
||||
findmac => 'switch',
|
||||
rspconfig => 'nodehm:mgt',
|
||||
};
|
||||
}
|
||||
|
||||
sub preprocess_request {
|
||||
my $request = shift;
|
||||
if (defined $request->{_xcatpreprocessed}->[0] and $request->{_xcatpreprocessed}->[0] == 1) { return [$request]; }
|
||||
|
||||
my $callback=shift;
|
||||
my @requests;
|
||||
|
||||
my $noderange = $request->{node};
|
||||
my $command = $request->{command}->[0];
|
||||
my $extrargs = $request->{arg};
|
||||
my @exargs=($request->{arg});
|
||||
if (ref($extrargs)) {
|
||||
@exargs=@$extrargs;
|
||||
}
|
||||
|
||||
if ($command eq "rspconfig") {
|
||||
my $usage_string=xCAT::Usage->parseCommand($command, @exargs);
|
||||
if ($usage_string) {
|
||||
$callback->({data=>$usage_string});
|
||||
$request = {};
|
||||
return;
|
||||
}
|
||||
if (!$noderange) {
|
||||
$usage_string=xCAT::Usage->getUsage($command);
|
||||
$callback->({data=>$usage_string});
|
||||
$request = {};
|
||||
return;
|
||||
}
|
||||
|
||||
#make sure all the nodes are switches
|
||||
my $switchestab=xCAT::Table->new('switches',-create=>0);
|
||||
my @all_switches;
|
||||
my @tmp=$switchestab->getAllAttribs(('switch'));
|
||||
if (defined(@tmp) && (@tmp > 0)) {
|
||||
foreach(@tmp) {
|
||||
my @switches_tmp=noderange($_->{switch});
|
||||
if (@switches_tmp==0) { push @switches_tmp, $_->{switch}; }
|
||||
foreach my $switch (@switches_tmp) {
|
||||
push @all_switches, $switch;
|
||||
}
|
||||
}
|
||||
}
|
||||
#print "all switches=@all_switches\n";
|
||||
my @wrong_nodes;
|
||||
foreach my $node (@$noderange) {
|
||||
if (! grep /^$node$/, @all_switches) {
|
||||
push @wrong_nodes, $node;
|
||||
}
|
||||
}
|
||||
if (@wrong_nodes > 0) {
|
||||
my $rsp = {};
|
||||
$rsp->{error}->[0] = "The following nodes are not defined in the switches table:\n @wrong_nodes.";
|
||||
$callback->($rsp);
|
||||
return;
|
||||
}
|
||||
|
||||
# find service nodes for requested switch
|
||||
# build an individual request for each service node
|
||||
my $service = "xcat";
|
||||
my $sn = xCAT::Utils->get_ServiceNode($noderange, $service, "MN");
|
||||
|
||||
# build each request for each service node
|
||||
foreach my $snkey (keys %$sn)
|
||||
{
|
||||
#print "snkey=$snkey\n";
|
||||
my $reqcopy = {%$request};
|
||||
$reqcopy->{node} = $sn->{$snkey};
|
||||
$reqcopy->{'_xcatdest'} = $snkey;
|
||||
$reqcopy->{_xcatpreprocessed}->[0] = 1;
|
||||
push @requests, $reqcopy;
|
||||
}
|
||||
return \@requests;
|
||||
}
|
||||
return [$request];
|
||||
}
|
||||
|
||||
sub process_request {
|
||||
my $req = shift;
|
||||
my $cb = shift;
|
||||
my $doreq = shift;
|
||||
my $node;
|
||||
my $mac = '';
|
||||
if ($req->{command}->[0] eq 'findmac') {
|
||||
$mac = $req->{arg}->[0];
|
||||
$node = $macmap->find_mac($mac,0);
|
||||
$cb->({node=>[{name=>$node,data=>$mac}]});
|
||||
return;
|
||||
}
|
||||
my $ip = $req->{'_xcat_clientip'};
|
||||
if (defined $req->{nodetype} and $req->{nodetype}->[0] eq 'virtual') {
|
||||
#Don't attempt switch discovery of a VM Guest
|
||||
#TODO: in this case, we could/should find the host system
|
||||
#and then ask it what node is associated with the mac
|
||||
#Either way, it would be kinda weird since xCAT probably made up the mac addy
|
||||
#anyway, however, complex network topology function may be aided by
|
||||
#discovery working. Food for thought.
|
||||
return;
|
||||
}
|
||||
my $arptable = `/sbin/arp -n`;
|
||||
my @arpents = split /\n/,$arptable;
|
||||
foreach (@arpents) {
|
||||
if (m/^($ip)\s+\S+\s+(\S+)\s/) {
|
||||
$mac=$2;
|
||||
last;
|
||||
}
|
||||
}
|
||||
my $firstpass=1;
|
||||
if ($mac) {
|
||||
$node = $macmap->find_mac($mac,$req->{cacheonly}->[0]);
|
||||
$firstpass=0;
|
||||
}
|
||||
if (not $node) { # and $req->{checkallmacs}->[0]) {
|
||||
foreach (@{$req->{mac}}) {
|
||||
/.*\|.*\|([\dABCDEFabcdef:]+)(\||$)/;
|
||||
$node = $macmap->find_mac($1,$firstpass);
|
||||
$firstpass=0;
|
||||
if ($node) { last; }
|
||||
my $req = shift;
|
||||
my $cb = shift;
|
||||
my $doreq = shift;
|
||||
my $node;
|
||||
my $mac = '';
|
||||
if ($req->{command}->[0] eq 'findmac') {
|
||||
$mac = $req->{arg}->[0];
|
||||
$node = $macmap->find_mac($mac,0);
|
||||
$cb->({node=>[{name=>$node,data=>$mac}]});
|
||||
return;
|
||||
} elsif ($req->{command}->[0] eq 'rspconfig') {
|
||||
return process_switch_config($req, $cb, $doreq);
|
||||
} elsif ($req->{command}->[0] eq 'findme') {
|
||||
my $ip = $req->{'_xcat_clientip'};
|
||||
if (defined $req->{nodetype} and $req->{nodetype}->[0] eq 'virtual') {
|
||||
#Don't attempt switch discovery of a VM Guest
|
||||
#TODO: in this case, we could/should find the host system
|
||||
#and then ask it what node is associated with the mac
|
||||
#Either way, it would be kinda weird since xCAT probably made up the mac addy
|
||||
#anyway, however, complex network topology function may be aided by
|
||||
#discovery working. Food for thought.
|
||||
return;
|
||||
}
|
||||
my $arptable = `/sbin/arp -n`;
|
||||
my @arpents = split /\n/,$arptable;
|
||||
foreach (@arpents) {
|
||||
if (m/^($ip)\s+\S+\s+(\S+)\s/) {
|
||||
$mac=$2;
|
||||
last;
|
||||
}
|
||||
}
|
||||
my $firstpass=1;
|
||||
if ($mac) {
|
||||
$node = $macmap->find_mac($mac,$req->{cacheonly}->[0]);
|
||||
$firstpass=0;
|
||||
}
|
||||
if (not $node) { # and $req->{checkallmacs}->[0]) {
|
||||
foreach (@{$req->{mac}}) {
|
||||
/.*\|.*\|([\dABCDEFabcdef:]+)(\||$)/;
|
||||
$node = $macmap->find_mac($1,$firstpass);
|
||||
$firstpass=0;
|
||||
if ($node) { last; }
|
||||
}
|
||||
}
|
||||
|
||||
if ($node) {
|
||||
my $mactab = xCAT::Table->new('mac',-create=>1);
|
||||
$mactab->setNodeAttribs($node,{mac=>$mac});
|
||||
$mactab->close();
|
||||
#my %request = (
|
||||
# command => ['makedhcp'],
|
||||
# node => [$node]
|
||||
#);
|
||||
#$doreq->(\%request);
|
||||
$req->{command}=['discovered'];
|
||||
$req->{noderange} = [$node];
|
||||
$doreq->($req);
|
||||
%{$req}=();#Clear req structure, it's done..
|
||||
undef $mactab;
|
||||
} else {
|
||||
#Shouldn't complain, might be blade, but how to log total failures?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($node) {
|
||||
my $mactab = xCAT::Table->new('mac',-create=>1);
|
||||
$mactab->setNodeAttribs($node,{mac=>$mac});
|
||||
$mactab->close();
|
||||
#my %request = (
|
||||
# command => ['makedhcp'],
|
||||
# node => [$node]
|
||||
#);
|
||||
#$doreq->(\%request);
|
||||
$req->{command}=['discovered'];
|
||||
$req->{noderange} = [$node];
|
||||
$doreq->($req);
|
||||
%{$req}=();#Clear req structure, it's done..
|
||||
undef $mactab;
|
||||
} else {
|
||||
#Shouldn't complain, might be blade, but how to log total failures?
|
||||
}
|
||||
}
|
||||
|
||||
sub process_switch_config {
|
||||
my $request = shift;
|
||||
my $callback=shift;
|
||||
my $subreq=shift;
|
||||
my $noderange = $request->{node};
|
||||
my $command = $request->{command}->[0];
|
||||
my $extrargs = $request->{arg};
|
||||
my @exargs=($request->{arg});
|
||||
if (ref($extrargs)) {
|
||||
@exargs=@$extrargs;
|
||||
}
|
||||
|
||||
my $subcommand=join(' ', @exargs);
|
||||
my $argument;
|
||||
($subcommand,$argument) = split(/=/,$subcommand);
|
||||
if (!$subcommand) {
|
||||
my $rsp = {};
|
||||
$rsp->{error}->[0] = "No subcommand specified.";
|
||||
$callback->($rsp);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
#decide what kind of swith it is
|
||||
my $sw_types=getSwitchType($noderange); #hash {type=>[node1,node1...]}
|
||||
foreach my $t (keys(%$sw_types)) {
|
||||
my $nodes=$sw_types->{$t};
|
||||
if (@$nodes>0) {
|
||||
if ($t =~ /Mellanox/i) {
|
||||
if (!$argument) {
|
||||
xCAT::MellanoxIB::getConfig($nodes, $callback, $subreq, $subcommand);
|
||||
} else {
|
||||
xCAT::MellanoxIB::setConfig($nodes, $callback, $subreq, $subcommand, $argument);
|
||||
}
|
||||
} else {
|
||||
my $rsp = {};
|
||||
$rsp->{error}->[0] = "The following '$t' switches are unsuppored:\n@$nodes";
|
||||
$callback->($rsp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#--------------------------------------------------------------------------------
|
||||
=head3 getSwitchType
|
||||
It determins the swtich vendor and model for the given swith.
|
||||
Arguments:
|
||||
noderange-- an array ref to switches.
|
||||
Returns:
|
||||
a hash ref. the key is the switch type string and the value is an array ref to the swithces t
|
||||
=cut
|
||||
#--------------------------------------------------------------------------------
|
||||
sub getSwitchType {
|
||||
my $noderange=shift;
|
||||
if ($noderange =~ /xCAT_plugin::switch/) {
|
||||
$noderange=shift;
|
||||
}
|
||||
|
||||
my $ret={};
|
||||
my $switchestab = xCAT::Table->new('switches',-create=>1);
|
||||
my $switches_hash = $switchestab->getNodesAttribs($noderange,['switchtype']);
|
||||
foreach my $node (@$noderange) {
|
||||
my $type="EtherNet";
|
||||
if ($switches_hash) {
|
||||
if ($switches_hash->{$node}-[0]) {
|
||||
$type = $switches_hash->{$node}->[0]->{switchtype};
|
||||
}
|
||||
}
|
||||
if (exists($ret->{$type})) {
|
||||
$pa=$ret->{$type};
|
||||
push @$pa, $node;
|
||||
} else {
|
||||
$ret->{$type}=[$node];
|
||||
}
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
1;
|
||||
|
Loading…
Reference in New Issue
Block a user