diff --git a/xCAT-server/lib/perl/xCAT/MellanoxIB.pm b/xCAT-server/lib/perl/xCAT/MellanoxIB.pm new file mode 100644 index 000000000..682dfcbef --- /dev/null +++ b/xCAT-server/lib/perl/xCAT/MellanoxIB.pm @@ -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) = ; + 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) = ; + 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; diff --git a/xCAT-server/lib/xcat/plugins/switch.pm b/xCAT-server/lib/xcat/plugins/switch.pm index 7cfdbffd8..386b458e8 100644 --- a/xCAT-server/lib/xcat/plugins/switch.pm +++ b/xCAT-server/lib/xcat/plugins/switch.pm @@ -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;