From 2d9139705f70faa1739b32702b5fb13998015290 Mon Sep 17 00:00:00 2001 From: daniceexi Date: Mon, 1 Apr 2013 10:32:07 +0000 Subject: [PATCH] Code drop for sequential discovery support git-svn-id: https://svn.code.sf.net/p/xcat/code/xcat-core/trunk@15758 8638fb3e-16cb-4fca-ae20-7b5d299a9bcd --- perl-xCAT/xCAT/DiscoveryUtils.pm | 96 ++ perl-xCAT/xCAT/Schema.pm | 36 + xCAT-server/lib/xcat/plugins/blade.pm | 1 + xCAT-server/lib/xcat/plugins/nodediscover.pm | 64 +- xCAT-server/lib/xcat/plugins/profilednodes.pm | 35 +- xCAT-server/lib/xcat/plugins/seqdiscovery.pm | 867 ++++++++++++++++++ xCAT-server/lib/xcat/plugins/switch.pm | 1 + 7 files changed, 1093 insertions(+), 7 deletions(-) create mode 100644 perl-xCAT/xCAT/DiscoveryUtils.pm create mode 100644 xCAT-server/lib/xcat/plugins/seqdiscovery.pm diff --git a/perl-xCAT/xCAT/DiscoveryUtils.pm b/perl-xCAT/xCAT/DiscoveryUtils.pm new file mode 100644 index 000000000..82e79e439 --- /dev/null +++ b/perl-xCAT/xCAT/DiscoveryUtils.pm @@ -0,0 +1,96 @@ +#!/usr/bin/env perl +# IBM(c) 2013 EPL license http://www.eclipse.org/legal/epl-v10.html + +package xCAT::DiscoveryUtils; + +use strict; +use XML::Simple; +$XML::Simple::PREFERRED_PARSER='XML::Parser'; + +use xCAT::MsgUtils; + +=head3 update_discovery_data + Update the discovery data from the xcat request to discoverydata table to indicate the discovery events + arg1 - the request + +=cut + +sub update_discovery_data { + my $class = shift; + my $request = shift; + + my %disdata; + my %otherdata; + + unless ($request->{'uuid'}->[0]) { + xCAT::MsgUtils->message("S", "Discovery Error: Found a node without uuid"); + } + + if ($request->{'discoverymethod'}->[0]) { + $disdata{'method'} = $request->{'discoverymethod'}->[0]; + } else { + $disdata{'method'} = "undef"; + } + + #discoverytime + my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time); + my $currtime = sprintf("%02d-%02d-%04d %02d:%02d:%02d", + $mon + 1, $mday, $year + 1900, $hour, $min, $sec); + $disdata{'discoverytime'} = $currtime; + + foreach my $attr (keys %$request) { + if ($attr =~ /^(command|discoverymethod|_xcat|cacheonly|noderange|environment)/) { + next; + } elsif ($attr =~ /^(node|uuid|arch|cpucount|cputype|memory|mtm|serial)$/) { + $disdata{$attr} = $request->{$attr}->[0]; + } elsif ($attr eq 'nic') { + # Set the nics attributes + foreach my $nic (@{$request->{nic}}) { + my $nicname = $nic->{'devname'}->[0]; + foreach my $nicattr (keys %$nic) { + my $tbattr; + if ($nicattr eq 'driver') { + $tbattr = "nicdriver"; + } elsif ($nicattr eq 'ip4address') { + $tbattr = "nicipv4"; + } elsif ($nicattr eq 'hwaddr') { + $tbattr = "nichwaddr"; + } elsif ($nicattr eq 'pcidev') { + $tbattr = "nicpci"; + } elsif ($nicattr eq 'location') { + $tbattr = "nicloc"; + } elsif ($nicattr eq 'onboardeth') { + $tbattr = "niconboard"; + } elsif ($nicattr eq 'firmdesc') { + $tbattr = "nicfirm"; + } elsif ($nicattr =~ /^(switchname|switchaddr|switchdesc|switchport)$/) { + $tbattr = $nicattr; + } + + if ($tbattr) { + if ($disdata{$tbattr}) { + $disdata{$tbattr} .= ','.$nicname.'!'.$nic->{$nicattr}->[0]; + } else { + $disdata{$tbattr} = $nicname.'!'.$nic->{$nicattr}->[0]; + } + } + } + } + } else { + # store to otherdata for the not parsed attributes + $otherdata{$attr} = $request->{$attr}; + } + } + + if (keys %otherdata) { + $disdata{'otherdata'} = XMLout(\%otherdata,RootName=>'discoveryotherdata' ,NoAttr=>1); + } + + my $distab = xCAT::Table->new('discoverydata'); + if ($distab) { + $distab->setAttribs({uuid=>$request->{'uuid'}->[0]},\%disdata); + $distab->close(); + } +} + +1; diff --git a/perl-xCAT/xCAT/Schema.pm b/perl-xCAT/xCAT/Schema.pm index 87fb9ad03..c1b765f3c 100644 --- a/perl-xCAT/xCAT/Schema.pm +++ b/perl-xCAT/xCAT/Schema.pm @@ -1398,6 +1398,42 @@ kitcomponent => { disable => "Set to 'yes' or '1' to comment out this row.", }, }, +discoverydata => { + cols => [qw(uuid node method discoverytime arch cpucount cputype memory mtm serial nicdriver nicipv4 nichwaddr nicpci nicloc niconboard nicfirm switchname switchaddr switchdesc switchport otherdata comments disable)], + keys => [qw(uuid)], + tablespace =>'XCATTBS32K', + table_desc => 'Discovery data which sent from genesis.', + types => { + otherdata => 'VARCHAR(2048)', + }, + descriptions => { + uuid => 'The uuid of the node which send out the discovery request.', + node => 'The node name which assigned to the discovered node.', + method => 'The method which handled the discovery request. The method could be one of: switch, blade, profile, sequential.', + discoverytime => 'The last time that xCAT received the discovery message.', + arch => 'The architecture of the discovered node. e.g. x86_64.', + cpucount => 'The cpu number of the discovered node. e.g. 32.', + cputype => 'The cpu type of the discovered node. e.g. Intel(R) Xeon(R) CPU E5-2690 0 @ 2.90GHz', + memory => 'The memory size of the discovered node. e.g. 198460852', + mtm => 'The machine type model of the discovered node. e.g. 786310X', + serial => 'The serial number of the discovered node. e.g. 1052EFB', + nicdriver => 'The driver of the nic. The value should be comma separated . e.g. eth0!be2net,eth1!be2net', + nicipv4 => 'The ipv4 address of the nic. The value should be comma separated . e.g. eth0!10.0.0.212/8', + nichwaddr => 'The hardware address of the nic. The should will be comma separated . e.g. eth0!34:40:B5:BE:DB:B0,eth1!34:40:B5:BE:DB:B4', + nicpci => 'The pic device of the nic. The value should be comma separated . e.g. eth0!0000:0c:00.0,eth1!0000:0c:00.1', + nicloc => 'The location of the nic. The value should be comma separated . e.g. eth0!Onboard Ethernet 1,eth1!Onboard Ethernet 2', + niconboard => 'The onboard info of the nic. The value should be comma separated . e.g. eth0!1,eth1!2', + nicfirm => 'The firmware description of the nic. The value should be comma separated . e.g. eth0!ServerEngines BE3 Controller,eth1!ServerEngines BE3 Controller', + switchname => 'The switch name which the nic connected to. The value should be comma separated . e.g. eth0!c909f06sw01', + switchaddr => 'The address of the switch which the nic connected to. The value should be comma separated . e.g. eth0!192.168.70.120', + switchdesc => 'The description of the switch which the nic connected to. The value should be comma separated . e.g. eth0!IBM Flex System Fabric EN4093 10Gb Scalable Switch, flash image: version 7.2.6, boot image: version 7.2.6', + switchport => 'The port of the switch that the nic connected to. The value should be comma separated . e.g. eth0!INTA2', + otherdata => 'The left data which is not parsed to specific attributes (The complete message comes from genesis)', + comments => 'Any user-written notes.', + disable => "Set to 'yes' or '1' to comment out this row.", + }, +}, + ); # end of tabspec definition diff --git a/xCAT-server/lib/xcat/plugins/blade.pm b/xCAT-server/lib/xcat/plugins/blade.pm index dd3b170c8..0a7e7ba4f 100644 --- a/xCAT-server/lib/xcat/plugins/blade.pm +++ b/xCAT-server/lib/xcat/plugins/blade.pm @@ -4220,6 +4220,7 @@ sub process_request { #$doreq->(\%request); $request->{command}=['discovered']; $request->{noderange} = [$node]; + $request->{discoverymethod} = ['blade']; $doreq->($request); %{$request}=(); #Clear request. it is done return 0; diff --git a/xCAT-server/lib/xcat/plugins/nodediscover.pm b/xCAT-server/lib/xcat/plugins/nodediscover.pm index b56172ecb..b38287b20 100644 --- a/xCAT-server/lib/xcat/plugins/nodediscover.pm +++ b/xCAT-server/lib/xcat/plugins/nodediscover.pm @@ -16,6 +16,8 @@ use xCAT::Utils; use Sys::Syslog; use Text::Balanced qw(extract_bracketed); +use xCAT::DiscoveryUtils; + sub gethosttag { #This function tries to return a good hostname for a node based on the @@ -192,10 +194,11 @@ sub process_request { $nrtab->setNodeAttribs($node,{netboot=>'yaboot'}); } } + + my $macstring = ""; if (defined($request->{mac})) { my $mactab = xCAT::Table->new("mac",-create=>1); my @ifinfo; - my $macstring = ""; my %usednames; my %bydriverindex; my $forcenic=0; #-1 is force skip, 0 is use default behavior, 1 is force to be declared even if hosttag is skipped to do so @@ -283,6 +286,65 @@ sub process_request { unless ($sock) { syslog("err","Failed to notify $ip that it's actually $node."); return; } #Give up if the node won't hear of it. print $sock $restartstring; close($sock); + + # Update the switch port information if the 'updateswitch' flag is added in the request. + # 'updateswitch' is default added for sequential discovery + if ($request->{'updateswitch'} && $macstring) { + my $firstmac; + + # Get the mac which defined as the management nic + my @macents = split (/\|/, $macstring); + foreach my $macent (@macents) { + my ($mac, $host) = split (/!/, $macent); + unless ($firstmac) { + $firstmac = $mac; + } + if ($host eq $node) { + $firstmac = $mac; + last; + } + } + + # search the management nic and record the switch informaiton + foreach my $nic (@{$request->{nic}}) { + if (defined ($nic->{'hwaddr'}) && $nic->{'hwaddr'}->[0] =~ /$firstmac/i ) { + if (defined ($nic->{'switchname'}) && defined ($nic->{'switchaddr'})) { + # update the switch to switches table + my $switchestab = xCAT::Table->new('switches'); + if ($switchestab) { + $switchestab->setAttribs({switch=>$nic->{'switchname'}->[0]}, {comments=>$nic->{'switchdesc'}->[0]}); + $switchestab->close(); + } + # update the ip of switch to hosts table + my $hosttab = xCAT::Table->new('hosts'); + if ($hosttab) { + $hosttab->setNodeAttribs($nic->{'switchname'}->[0], {ip => $nic->{'switchaddr'}->[0]}); + $hosttab->commit(); + } + + # add the switch as a node to xcat db + my $nltab = xCAT::Table->new('nodelist'); + if ($nltab) { + $nltab->setNodeAttribs($nic->{'switchname'}->[0], {groups=>"all,switch"}); + $nltab->commit(); + } + + if (defined ($nic->{'switchport'})) { + # update the switch table + my $switchtab = xCAT::Table->new('switch'); + if ($switchtab) { + $switchtab->setNodeAttribs($node, {switch=>$nic->{'switchname'}->[0], port=>$nic->{'switchport'}->[0]}); + $switchtab->close(); + } + } + } + } + } + } + + #Update the discoverydata table to indicate the successful discovery + xCAT::DiscoveryUtils->update_discovery_data($request); + syslog("info","$node has been discovered"); } diff --git a/xCAT-server/lib/xcat/plugins/profilednodes.pm b/xCAT-server/lib/xcat/plugins/profilednodes.pm index 8a7b62d95..1c1ac4d56 100644 --- a/xCAT-server/lib/xcat/plugins/profilednodes.pm +++ b/xCAT-server/lib/xcat/plugins/profilednodes.pm @@ -196,6 +196,8 @@ sub validate_args{ my $help; my $ver; + my ($type, $uuid, $long); + @ARGV = (); if($args) { @ARGV = @$args; @@ -204,6 +206,9 @@ sub validate_args{ 'h|help' => \$help, 'V|verbose' => \$::VERBOSE, 'v|version' => \$ver, + 't=s' => \$type, + 'u=s' => \$uuid, + 'l' => \$long, ); if($help){ @@ -217,6 +222,11 @@ sub validate_args{ setrsp_infostr($versionmsg); return 0; } + + if ($type || $uuid || $long) { + # these args for general discovery, return directly + return; + } my $parseret = parse_args(); if ($parseret){ @@ -229,10 +239,17 @@ sub validate_args{ if($enabledparamsref){ @enabledparams = @$enabledparamsref; } + foreach my $argname (keys %args_dict){ if (! grep{ $_ eq $argname} @enabledparams){ + if (defined $args_dict{'noderange'}) { + # This is a sequential discovery request, just return to make sequential to handle it + return 0; + } else { setrsp_errormsg("Illegal attribute $argname specified."); + setrsp_infostr($helpmsg); return 0; + } } } @@ -243,7 +260,8 @@ sub validate_args{ } foreach (@mandatoryparams){ if(! exists($args_dict{$_})){ - setrsp_errormsg("You must specify the $_ option."); + setrsp_errormsg("For profile discovery, the $_ option must be specified."); + setrsp_infostr($helpmsg); return 0; } } @@ -1166,7 +1184,8 @@ Usage: xCAT::MsgUtils->message("Stopping profiled node's discover."); my $discover_running = xCAT::ProfiledNodeUtils->is_discover_started(); if (! $discover_running){ - setrsp_errormsg("Node discovery for all nodes using profiles is not started."); + # do nothing that make sequential discovery to handle the message + # setrsp_errormsg("Node discovery for all nodes using profiles is not started."); return; } @@ -1215,7 +1234,8 @@ Usage: if($discover_running){ setrsp_progress("Node discovery for all nodes using profiles is running"); }else{ - setrsp_progress("Node discovery for all nodes using profiles is not started"); + # do nothing that make sequential discovery to handle the message + # setrsp_progress("Node discovery for all nodes using profiles is not started"); } } @@ -1244,7 +1264,8 @@ Usage: # Read DB to confirm the discover is started. my $discover_running = xCAT::ProfiledNodeUtils->is_discover_started(); if (! $discover_running){ - setrsp_errormsg("Node discovery process is not running."); + # do nothing that make sequential discovery to handle the message + # setrsp_errormsg("Node discovery process is not running."); return; } @@ -1297,7 +1318,6 @@ Usage: #------------------------------------------------------- sub findme{ - xCAT::MsgUtils->message('S', "Profield nodes discover: Start.\n"); # re-initalize the global variable %args_dict = (); # Read DB to confirm the discover is started. @@ -1308,9 +1328,11 @@ sub findme{ $sitevaluesstr = $stabent->{'value'}; } unless ($sitevaluesstr){ - setrsp_errormsg("Profiled nodes discovery not started yet."); + #setrsp_errormsg("Profiled nodes discovery not started yet."); return; } + + xCAT::MsgUtils->message('S', "Profile Discovery: Start.\n"); # We store node profiles in site table, key is "__PCMDiscover" my @profilerecords = split(',', $sitevaluesstr); @@ -1434,6 +1456,7 @@ sub findme{ xCAT::MsgUtils->message('S', "Call discovered request.\n"); $request->{"command"} = ["discovered"]; $request->{"node"} = \@nodelist; + $request->{discoverymethod} = ['profile']; $retref = xCAT::Utils->runxcmd($request, $request_command, 0, 2); $retstrref = parse_runxcmd_ret($retref); diff --git a/xCAT-server/lib/xcat/plugins/seqdiscovery.pm b/xCAT-server/lib/xcat/plugins/seqdiscovery.pm new file mode 100644 index 000000000..495e4a8f4 --- /dev/null +++ b/xCAT-server/lib/xcat/plugins/seqdiscovery.pm @@ -0,0 +1,867 @@ +#!/usr/bin/env perl +## IBM(c) 20013 EPL license http://www.eclipse.org/legal/epl-v10.html +# +# This plugin is used to handle the sequencial discovery. During the discovery, +# the nodes should be powered on one by one, sequencial discovery plugin will +# discover the nodes one by one and define them to xCAT DB. + +# For the new discovered node but NOT handled by xCAT plugin, +# it will be recorded to discoverydata table. +# + +package xCAT_plugin::seqdiscovery; +BEGIN +{ + $::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat'; +} + +use strict; +use Getopt::Long; + +use lib "$::XCATROOT/lib/perl"; +use xCAT::NodeRange; +use xCAT::Table; +use xCAT::NetworkUtils; +use xCAT::MsgUtils; +use xCAT::DiscoveryUtils; + +use Time::HiRes qw(gettimeofday sleep); + +sub handled_commands { + return { + findme => 'seqdiscovery', + nodediscoverstart => 'seqdiscovery', + nodediscoverstop => 'seqdiscovery', + nodediscoverls => 'seqdiscovery', + nodediscoverstatus => 'seqdiscovery', + } +} + +sub findme { + my $request = shift; + my $callback = shift; + my $subreq = shift; + + my @SEQdiscover = xCAT::TableUtils->get_site_attribute("__SEQDiscover"); + my @PCMdiscover = xCAT::TableUtils->get_site_attribute("__PCMDiscover"); + unless ($SEQdiscover[0]) { + if ($PCMdiscover[0]) { + #profile disocvery is running, then just return to make profile discovery to handle it + return; + } + # update the discoverydata table to have an undefined node + $request->{method}->[0] = 'undef'; + xCAT::DiscoveryUtils->update_discovery_data($request); + return; + } + + # do the sequential discovery + xCAT::MsgUtils->message("S", "Sequential Discovery: Processing"); + + # Get the parameters for the sequential discovery + my %param; + my @params = split (',', $SEQdiscover[0]); + foreach (@params) { + my ($name, $value) = split ('=', $_); + $param{$name} = $value; + } + + my $mac; + my $ip = $request->{'_xcat_clientip'}; + if (defined $request->{nodetype} and $request->{nodetype}->[0] eq 'virtual') { + return; + } + my $arptable = `/sbin/arp -n`; + my @arpents = split /\n/,$arptable; + foreach (@arpents) { + if (m/^($ip)\s+\S+\s+(\S+)\s/) { + $mac=$2; + last; + } + } + + unless ($mac) { + xCAT::MsgUtils->message("S", "Discovery Error: Could not find the mac of the $ip."); + return; + } + + # check whether the mac could map to a node + my $mactab = xCAT::Table->new('mac'); + unless ($mactab) { + xCAT::MsgUtils->message("S", "Discovery Error: Could not open table: mac."); + } + + my $node; + my @macs = $mactab->getAllAttribs('node', 'mac'); + # for each entry: 34:40:b5:be:db:b0!*NOIP*|34:40:b5:be:db:b0!*NOIP* + foreach my $macnode (@macs) { + my @macents = split ('\|', $macnode->{'mac'}); + foreach my $macent (@macents) { + my ($usedmac) = split ('!', $macent); + if ($usedmac =~ /$mac/i) { + $node = $macnode->{'node'}; + last; + } + } + } + + unless ($node) { + # get a free node + $node = getfreenodes($param{'noderange'}); + } + + if ($node) { + my $skiphostip; + my $skipbmcip; + my @newhosts = ($node); + # check the host ip and bmc + my $hosttab = xCAT::Table->new('hosts'); + unless ($hosttab) { + xCAT::MsgUtils->message("S", "Discovery Error: Could not open table: hosts."); + } + my $hostip = $hosttab->getNodeAttribs($node, ['ip']); + if ($hostip->{'ip'}) { + $skiphostip = 1; + } + + my $ipmitab = xCAT::Table->new('ipmi'); + unless ($ipmitab) { + xCAT::MsgUtils->message("S", "Discovery Error: Could not open table: ipmi."); + } + my $ipmibmc = $ipmitab->getNodeAttribs($node, ['bmc']); + if ($ipmibmc->{'bmc'}) { + $skipbmcip = 1; + unless ($ipmibmc->{'bmc'} =~ /\d+\.\d+\.\d+\.\d+/) { + push @newhosts, $ipmibmc->{'bmc'}; + } + } + + # set the host ip and bmc if needed + unless ($skiphostip) { + my $hostip = getfreeips($param{'hostiprange'}); + unless ($hostip) { + xCAT::MsgUtils->message("S", "Discovery Error: No free host ip."); + nodediscoverstop($callback, undef, 1); + return; + } + $hosttab->setNodeAttribs($node, {ip => $hostip}); + $hosttab->commit(); + } + + my $bmcname; + unless ($skipbmcip) { + my $bmcip = getfreeips($param{'bmciprange'}); + unless ($bmcip) { + xCAT::MsgUtils->message("S", "Discovery Error: No free bmc ip."); + nodediscoverstop($callback, undef, 1); + return; + } + $bmcname = $node."-bmc"; + $hosttab->setNodeAttribs($bmcname, {ip => $bmcip}); + $hosttab->commit(); + + # set the bmc to the ipmi table + $ipmitab->setNodeAttribs($node, {bmc => $bmcname}); + + push @newhosts, $bmcname; + } + + # update the host ip pair to /etc/hosts, it's necessary for discovered and makedhcp commands + if (@newhosts) { + my $req; + $req->{command}=['makehosts']; + $req->{node} = \@newhosts; + $subreq->($req); + } + + # set the specific attributes from parameters + my $updateparams; + my %setpos; + if (defined ($param{'rack'})) { + $setpos{'rack'} = $param{'rack'}; + } + if (defined ($param{'chassis'})) { + $setpos{'chassis'} = $param{'chassis'}; + } + if (defined ($param{'height'})) { + $setpos{'height'} = $param{'height'}; + } + if (defined ($param{'unit'})) { + $setpos{'u'} = $param{'unit'}; + + if (defined ($param{'height'})) { + $param{'unit'} += $param{'height'}; + } else { + $param{'unit'} += 1; + } + + $updateparams = 1; + } + if (keys %setpos) { + my $postab = xCAT::Table->new('nodepos'); + unless ($postab) { + xCAT::MsgUtils->message("S", "Discovery Error: Could not open table: nodepos."); + } + $postab->setNodeAttribs($node, \%setpos); + $postab->close(); + } + + + if ($updateparams) { + my $textparam; + foreach my $name (keys %param) { + $textparam .= "$name=$param{$name},"; + } + $textparam =~ s/,\z//; + + # Update the discovery parameters to the site.__SEQDiscover which will be used by nodediscoverls/status/stop and findme, + my $sitetab = xCAT::Table->new("site"); + $sitetab->setAttribs({"key" => "__SEQDiscover"}, {"value" => "$textparam"}); + $sitetab->close(); + } + + #set the groups for the node + my $nltab = xCAT::Table->new('nodelist'); + unless ($nltab) { + xCAT::MsgUtils->message("S", "Discovery Error: Could not open table: nodelist."); + } + if (defined ($param{'groups'})) { + $nltab->setNodeAttribs($node, {groups=>$param{'groups'}}); + if ($bmcname) { + $nltab->setNodeAttribs($bmcname, {groups=>$param{'groups'}.",bmc"}); + } + } else { + $nltab->setNodeAttribs($node, {groups=>"all"}); + if ($bmcname) { + $nltab->setNodeAttribs($bmcname, {groups=>"all,bmc"}); + } + } + + $request->{command}=['discovered']; + $request->{noderange} = [$node]; + $request->{discoverymethod} = ['sequential']; + $request->{updateswitch} = ['yes']; + $subreq->($request); + %{$request}=();#Clear req structure, it's done.. + undef $mactab; + } else { + # + xCAT::MsgUtils->message("S", "Discovery Error: No free node name."); + nodediscoverstop($callback, undef, 1); + return; + } + + xCAT::MsgUtils->message("S", "Sequential Discovery: Done"); +} + +=head3 nodediscoverstart + Initiate the sequencial discovery process +=cut +sub nodediscoverstart { + my $callback = shift; + my $args = shift; + + my $usage = sub { + my $cb = shift; + my $msg = shift; + + my $rsp; + if ($msg) { + push @{$rsp->{data}}, $msg; + xCAT::MsgUtils->message("E", $rsp, $cb, 1); + } + + my $usageinfo = "nodediscoverstart: Start sequential nodes discovery. +Usage: +\tnodediscoverstart noderange= hostiprange= bmciprange= [groups=] [rack=] [chassis=] [height=] [unit=] +\tnodediscoverstart [-h|--help] +\tnodediscoverstart {-v|--version} + "; + $rsp = (); + push @{$rsp->{data}}, $usageinfo; + xCAT::MsgUtils->message("I", $rsp, $cb); + }; + + # valid attributes for deqdiscovery + my %validargs = ( + 'noderange' => 1, + 'hostiprange' => 1, + 'bmciprange' => 1, + 'groups' => 1, + 'rack' => 1, + 'chassis' => 1, + 'height' => 1, + 'unit' => 1, + ); + + if ($args) { + @ARGV = @$args; + } + my ($help, $ver); + if (!GetOptions( + 'h|help' => \$help, + 'V|verbose' => \$::VERBOSE, + 'v|version' => \$ver)) { + $usage->($callback); + return; + } + + if ($help) { + $usage->($callback); + return; + } + + if ($ver) { + # just return to make profile discovery to handle it + return; + } + + my %orgargs; + foreach (@ARGV) { + my ($name, $value) = split ('=', $_); + $orgargs{$name} = $value; + } + + # Todo: Check the noderage=has been specified which is the flag that this is for sequential discovery + + # Otherwise try to check the whether the networkprofile || hardwareprofile || imageprofile + # has been passed, if yes, return to profile discovery + unless (defined ($orgargs{noderange}) ) { + if (defined ($orgargs{networkprofile}) || defined($orgargs{hardwareprofile}) || defined($orgargs{imageprofile})) { + # just return that make profile-based discovery to handle it + return; + } else { + $usage->($callback, "For sequential discovery, the \'noderange\' option must be specified."); + return; + } + } + + xCAT::MsgUtils->message("S", "Sequential Discovery: Start"); + + my %param; # The valid parameters + my $textparam; # The valid parameters in 'name=value,name=value...' format + + # Check the validate of parameters + foreach my $name (keys %orgargs) { + unless (defined ($validargs{$name})) { + $usage->($callback, "Invalid arguement \"$name\"."); + return; + } + unless (defined ($orgargs{$name})) { + $usage->($callback, "The parameter \"$name\" need a value."); + return; + } + + # keep the valid parameters + $param{$name} = $orgargs{$name}; + $textparam .= $name.'='.$param{$name}.','; + } + + $textparam =~ s/,\z//; + + # Check the running of profile-based discovery + my @PCMdiscover = xCAT::TableUtils->get_site_attribute("__PCMDiscover"); + if ($PCMdiscover[0]) { + my $rsp; + push @{$rsp->{data}}, "Sequentail Discovery cannot run together with Profile-based discovery"; + xCAT::MsgUtils->message("E", $rsp, $callback, 1); + return; + } + + # Check the running of sequential discovery + my @SEQdiscover = xCAT::TableUtils->get_site_attribute("__SEQDiscover"); + if ($SEQdiscover[0]) { + my $rsp; + push @{$rsp->{data}}, "Sequentail Discovery is running. If you want to rerun the discovery, stop the running discovery first."; + xCAT::MsgUtils->message("E", $rsp, $callback, 1); + return; + } + + # Check that the dynamic range in the dhcpd.conf has been set correctly + # search all the network in the networks table that make sure the dynamic range for the deployment network has been set + + # Set the discovery parameters to the site.__SEQDiscover which will be used by nodediscoverls/status/stop and findme, + my $sitetab = xCAT::Table->new("site"); + $sitetab->setAttribs({"key" => "__SEQDiscover"}, {"value" => "$textparam"}); + $sitetab->close(); + + # Clean the entries which discovery method is 'sequential' from the discoverdata table + my $distab = xCAT::Table->new("discoverydata"); + $distab->delEntries({method => 'sequential'}); + $distab->commit(); + + # Calculate the available node name and IPs + my @freenodes = getfreenodes($param{'noderange'}, "all"); + my @freehostips = getfreeips($param{'hostiprange'}, "all"); + my @freebmcips = getfreeips($param{'bmciprange'}, "all"); + + my $rsp; + push @{$rsp->{data}}, "Sequential node discovery started:"; + push @{$rsp->{data}}, " Number of free node names: ".($#freenodes+1); + if ($param{'hostiprange'}) { + if (@freehostips) { + push @{$rsp->{data}}, " Number of free host ips: ".($#freehostips+1); + } else { + push @{$rsp->{data}}, " No free host ips."; + } + } + if ($param{'bmciprange'}) { + if (@freebmcips) { + push @{$rsp->{data}}, " Number of free bmc ips: ".($#freebmcips+1); + } else { + push @{$rsp->{data}}, " No free bmc ips."; + } + } + xCAT::MsgUtils->message("I", $rsp, $callback); +} + + +=head3 nodediscoverstop + Stop the sequencial discovery process +=cut +sub nodediscoverstop { + my $callback = shift; + my $args = shift; + my $auto = shift; + + my $usage = sub { + my $cb = shift; + my $msg = shift; + + my $rsp; + if ($msg) { + push @{$rsp->{data}}, $msg; + xCAT::MsgUtils->message("E", $rsp, $cb, 1); + } + + my $usageinfo = "nodediscoverstop: Stop the sequential discovery. +Usage: +\tnodediscoverstop [-h|--help] [-v | --version] + "; + $rsp = (); + push @{$rsp->{data}}, $usageinfo; + xCAT::MsgUtils->message("I", $rsp, $cb); + }; + + if ($args) { + @ARGV = @$args; + } + my ($help, $ver); + if (!GetOptions( + 'h|help' => \$help, + 'V|verbose' => \$::VERBOSE, + 'v|version' => \$ver)) { + $usage->($callback); + return; + } + + if ($help) { + #$usage->($callback); + # just return to make profile discovery to handle it + return; + } + if ($ver) { + # just return to make profile discovery to handle it + return; + } + + # Check the running of sequential discovery + my @SEQDiscover = xCAT::TableUtils->get_site_attribute("__SEQDiscover"); + my @PCMDiscover = xCAT::TableUtils->get_site_attribute("__PCMDiscover"); + if ($PCMDiscover[0]) { + # return directly that profile discover will cover it + } elsif (!$SEQDiscover[0]) { + # Neither of profile nor sequential was running + my $rsp; + push @{$rsp->{data}}, "Sequential Discovery is stopped."; + push @{$rsp->{data}}, "Profile Discovery is stopped."; + xCAT::MsgUtils->message("E", $rsp, $callback, 1); + return; + } + + + # Go thought discoverydata table and display the sequential disocvery entries + my $distab = xCAT::Table->new('discoverydata'); + unless ($distab) { + my $rsp; + push @{$rsp->{data}}, "Discovery Error: Could not open table: discoverydata."; + xCAT::MsgUtils->message("E", $rsp, $callback); + return; + } + my @disdata = $distab->getAllAttribsWhere("method='sequential'", 'node', 'mtm', 'serial'); + my @discoverednodes; + + foreach (@disdata) { + push @discoverednodes, sprintf(" %-20s%-10s%-10s", $_->{'node'}, $_->{'mtm'}, substr($_->{'serial'},0,8), ); + } + + my $rsp; + push @{$rsp->{data}}, "Discovered ".($#discoverednodes+1)." nodes."; + if (@discoverednodes) { + push @{$rsp->{data}}, sprintf(" %-20s%-10s%-10s", 'NODE', 'MTM', 'SERIAL'); + foreach (@discoverednodes) { + push @{$rsp->{data}}, "$_"; + } + } + xCAT::MsgUtils->message("I", $rsp, $callback); + + if ($auto) { + xCAT::MsgUtils->message("S", "Sequential Discovery: Auto Stopped. Run \'nodediscoverls -t seq\' to display the discovery result."); + } else { + xCAT::MsgUtils->message("S", "Sequential Discovery: Stop"); + } + + # Clean the entries which discovery method is 'sequential' from the discoverdata table + unless ($auto) { + my $distab = xCAT::Table->new("discoverydata"); + $distab->delEntries({method => 'sequential'}); + $distab->commit(); + } + + # Remove the site.__SEQDiscover + my $sitetab = xCAT::Table->new("site"); + $sitetab->delEntries({key => '__SEQDiscover'}); + $sitetab->commit(); +} + +=head3 nodediscoverls + Display the discovered nodes +=cut +sub nodediscoverls { + my $callback = shift; + my $args = shift; + + my $usage = sub { + my $cb = shift; + my $msg = shift; + + my $rsp; + if ($msg) { + push @{$rsp->{data}}, $msg; + xCAT::MsgUtils->message("E", $rsp, $cb, 1); + } + + my $usageinfo = "nodediscoverls: list the discovered nodes. +Usage: +\tnodediscoverls +\tnodediscoverls [-h|--help] +\tnodediscoverls [-v | --version] +\tnodediscoverls [-t seq|profile|switch|blade|undef|all] [-l] +\tnodediscoverls [-u uuid] [-l] + "; + $rsp = (); + push @{$rsp->{data}}, $usageinfo; + xCAT::MsgUtils->message("I", $rsp, $cb); + }; + + if ($args) { + @ARGV = @$args; + } + my ($type, $uuid, $long, $help, $ver); + if (!GetOptions( + 't=s' => \$type, + 'u=s' => \$uuid, + 'l' => \$long, + 'h|help' => \$help, + 'V|verbose' => \$::VERBOSE, + 'v|version' => \$ver)) { + $usage->($callback); + return; + } + + if ($help) { + $usage->($callback); + return; + } + if ($ver) { + # just return to make profile discovery to handle it + return; + } + + # If the type is specified, display the corresponding type of nodes + if ($type) { + if ($type !~ /^(seq|profile|switch|blade|undef|all)$/) { + $usage->($callback, "The discovery type \'$type\' is not supported."); + return; + } + } elsif ($uuid) { + } else { + # Check the running of sequential discovery + my @SEQDiscover = xCAT::TableUtils->get_site_attribute("__SEQDiscover"); + if ($SEQDiscover[0]) { + $type = "seq"; + } else { + my @PCMDiscover = xCAT::TableUtils->get_site_attribute("__PCMDiscover"); + if ($PCMDiscover[0]) { + #return directly if my type of discover is not running. + return; + } else { + # no type, no seq and no profile, then just diaplay all + $type = "all"; + } + } + } + + # Go thought discoverydata table and display the disocvery entries + my $distab = xCAT::Table->new('discoverydata'); + unless ($distab) { + my $rsp; + push @{$rsp->{data}}, "Discovery Error: Could not open table: discoverydata."; + xCAT::MsgUtils->message("E", $rsp, $callback); + return; + } + my @disdata; + my @disattrs; + if ($long) { + @disattrs = ('uuid', 'node', 'method', 'discoverytime', 'arch', 'cpucount', 'cputype', 'memory', 'mtm', 'serial', 'nicdriver', 'nicipv4', 'nichwaddr', 'nicpci', 'nicloc', 'niconboard', 'nicfirm', 'switchname', 'switchaddr', 'switchdesc', 'switchport'); + } else { + @disattrs = ('uuid', 'node', 'method', 'mtm', 'serial'); + } + if ($type) { + if ($type eq "all") { + @disdata = $distab->getAllAttribs(@disattrs); + } else { + $type = "sequential" if ($type =~ /^seq/); + @disdata = $distab->getAllAttribsWhere("method='$type'", @disattrs); + } + } elsif ($uuid) { + @disdata = $distab->getAllAttribsWhere("uuid='$uuid'", @disattrs); + } + my $discoverednum = $#disdata + 1; + + my @discoverednodes; + foreach my $ent (@disdata) { + if ($long) { + foreach my $attr (@disattrs) { + if ($attr eq "uuid") { + push @discoverednodes, "Object uuid: $ent->{$attr}"; + } elsif (defined ($ent->{$attr})) { + push @discoverednodes, " $attr=$ent->{$attr}"; + } + } + } else { + $ent->{'node'} = 'undef' unless ($ent->{'node'}); + $ent->{'method'} = 'undef' unless ($ent->{'method'}); + push @discoverednodes, sprintf(" %-40s%-20s%-15s%-10s%-10s", $ent->{'uuid'}, $ent->{'node'}, $ent->{'method'}, $ent->{'mtm'}, substr($ent->{'serial'},0,8)); + } + } + + my $rsp; + if ($type eq "sequential") { + push @{$rsp->{data}}, "Discovered $discoverednum node."; + } + if (@discoverednodes) { + unless ($long) { + push @{$rsp->{data}}, sprintf(" %-40s%-20s%-15s%-10s%-10s", 'UUID', 'NODE', ,'METHOD', 'MTM', 'SERIAL'); + } + foreach (@discoverednodes) { + push @{$rsp->{data}}, "$_"; + } + } + + xCAT::MsgUtils->message("I", $rsp, $callback); +} + + +=head3 nodediscoverstatus + Display the discovery status +=cut +sub nodediscoverstatus { + my $callback = shift; + my $args = shift; + + my $usage = sub { + my $cb = shift; + my $msg = shift; + + my $rsp; + if ($msg) { + push @{$rsp->{data}}, $msg; + xCAT::MsgUtils->message("E", $rsp, $cb, 1); + } + + my $usageinfo = "nodediscoverstatus: Display the discovered status. +Usage: +\tnodediscoverstatus [-h|--help] [-v | --version] + "; + $rsp = (); + push @{$rsp->{data}}, $usageinfo; + xCAT::MsgUtils->message("I", $rsp, $cb); + }; + + if ($args) { + @ARGV = @$args; + } + my ($type, $uuid, $long, $help, $ver); + if (!GetOptions( + 'h|help' => \$help, + 'V|verbose' => \$::VERBOSE, + 'v|version' => \$ver)) { + $usage->($callback); + return; + } + + if ($help) { + #$usage->($callback); + # just return to make profile discovery to handle it + return; + } + if ($ver) { + # just return to make profile discovery to handle it + return; + } + + # Check the running of sequential discovery + my @SEQDiscover = xCAT::TableUtils->get_site_attribute("__SEQDiscover"); + my @PCMDiscover = xCAT::TableUtils->get_site_attribute("__PCMDiscover"); + if ($SEQDiscover[0]) { + my $rsp; + push @{$rsp->{data}}, "Sequential discovery is running."; + push @{$rsp->{data}}, " The parameters used for discovery: ".$SEQDiscover[0]; + xCAT::MsgUtils->message("I", $rsp, $callback); + } elsif ($PCMDiscover[0]) { + # return directly that Profile discover to cover the output + return; + } else { + my $rsp; + push @{$rsp->{data}}, "Sequential Discovery is stopped."; + push @{$rsp->{data}}, "Profile Discovery is stopped."; + xCAT::MsgUtils->message("I", $rsp, $callback); + } + +} + + +sub process_request { + my $request = shift; + my $callback = shift; + my $subreq = shift; + + my $command = $request->{command}->[0]; + my $args = $request->{arg}; + + if ($command eq "findme"){ + findme($request, $callback, $subreq); + } elsif ($command eq "nodediscoverstart") { + nodediscoverstart($callback, $args); + } elsif ($command eq "nodediscoverstop") { + nodediscoverstop($callback, $args); + } elsif ($command eq "nodediscoverls") { + nodediscoverls($callback, $args); + } elsif ($command eq "nodediscoverstatus") { + nodediscoverstatus($callback, $args); + } +} + +=head3 getfreenodes + Get the free nodes base on the user specified noderange and defined nodes + arg1 - the noderange + arg2 - "all': return all the free nodes; otherwise just return one. +=cut +sub getfreenodes () { + my $noderange = shift; + my $all = shift; + + my @freenodes; + + # get all the nodes from noderange + my @nodes = noderange($noderange, 0); + + # get all nodes from nodelist and mac table + my $nltb = xCAT::Table->new('nodelist'); + unless ($nltb) { + xCAT::MsgUtils->message("S", "Discovery Error: Could not open table: nodelist."); + return; + } + + my $mactb = xCAT::Table->new('mac'); + unless ($mactb) { + xCAT::MsgUtils->message("S", "Discovery Error: Could not open table: mac."); + return; + } + + my $nlent = $nltb->getNodesAttribs(\@nodes,['groups']); + my $macent = $mactb->getNodesAttribs(\@nodes,['mac']); + foreach my $node (@nodes) { + if ($nlent->{$node}->[0]) { + unless ($macent->{$node}->[0] && $macent->{$node}->[0]->{'mac'}) { + push @freenodes, $node; + unless ($all) { last;} + } + } else { + push @freenodes, $node; + unless ($all) { last;} + } + } + + unless (@freenodes) { + return; + } + + if ($all ) { + return @freenodes; + } else { + return $freenodes[0]; + } +} + + +=head3 getfreeips + Get the free ips base on the user specified ip range + arg1 - the ip range. Two format are suported: 192.168.1.1-192.168.2.50; 192.168.[1-2].[10-100] + arg2 - "all': return all the free nodes; otherwise just return one. +=cut +sub getfreeips () { + my $iprange = shift; + my $all = shift; + + my @freeips; + + # get all used ip from hosts table + my $hoststb = xCAT::Table->new('hosts'); + unless ($hoststb) { + xCAT::MsgUtils->message("S", "Discovery Error: Could not open table: hosts."); + } + + my @hostsent = $hoststb->getAllAttribs('ip'); + my %usedips = (); + foreach my $host (@hostsent) { + $usedips{$host->{'ip'}} = 1; + } + + if ($iprange =~ /(\d+\.\d+\.\d+\.\d+)-(\d+\.\d+\.\d+\.\d+)/) { + my ($startip, $endip) = ($1, $2); + my $startnum = xCAT::NetworkUtils->ip_to_int($startip); + my $endnum = xCAT::NetworkUtils->ip_to_int($endip); + + while ($startnum <= $endnum) { + my $ip = xCAT::NetworkUtils->int_to_ip($startnum); + unless ($usedips{$ip}) { + push @freeips, $ip; + unless ($all) {last;} + } + $startnum++; + } + } else { + # use the noderange to expand the range + my @ips = noderange($iprange, 0); + foreach my $ip (@ips) { + unless ($usedips{$ip}) { + push @freeips, $ip; + unless ($all) {last;} + } + } + } + + unless (@freeips) { + return; + } + + if ($all) { + return @freeips; + } else { + return $freeips[0]; + } +} + +1; diff --git a/xCAT-server/lib/xcat/plugins/switch.pm b/xCAT-server/lib/xcat/plugins/switch.pm index 1bac5deb8..3ae9ef45d 100644 --- a/xCAT-server/lib/xcat/plugins/switch.pm +++ b/xCAT-server/lib/xcat/plugins/switch.pm @@ -163,6 +163,7 @@ sub process_request { #$doreq->(\%request); $req->{command}=['discovered']; $req->{noderange} = [$node]; + $req->{discoverymethod} = ['switch']; $doreq->($req); %{$req}=();#Clear req structure, it's done.. undef $mactab;