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
This commit is contained in:
daniceexi 2013-04-01 10:32:07 +00:00
parent e927682f24
commit 2d9139705f
7 changed files with 1093 additions and 7 deletions

View File

@ -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;

View File

@ -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 <nic name!driver name>. e.g. eth0!be2net,eth1!be2net',
nicipv4 => 'The ipv4 address of the nic. The value should be comma separated <nic name!ipv4 address>. e.g. eth0!10.0.0.212/8',
nichwaddr => 'The hardware address of the nic. The should will be comma separated <nic name!hardware address>. 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 <nic name!pci device>. e.g. eth0!0000:0c:00.0,eth1!0000:0c:00.1',
nicloc => 'The location of the nic. The value should be comma separated <nic name!nic location>. e.g. eth0!Onboard Ethernet 1,eth1!Onboard Ethernet 2',
niconboard => 'The onboard info of the nic. The value should be comma separated <nic name!onboard info>. e.g. eth0!1,eth1!2',
nicfirm => 'The firmware description of the nic. The value should be comma separated <nic name!fimware description>. 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 <nic name!switch name>. e.g. eth0!c909f06sw01',
switchaddr => 'The address of the switch which the nic connected to. The value should be comma separated <nic name!switch address>. e.g. eth0!192.168.70.120',
switchdesc => 'The description of the switch which the nic connected to. The value should be comma separated <nic name!switch description>. 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 <nic name!switch port>. 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

View File

@ -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;

View File

@ -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");
}

View File

@ -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);

View File

@ -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=<noderange> hostiprange=<imageprofile> bmciprange=<bmciprange> [groups=<groups>] [rack=<rack>] [chassis=<chassis>] [height=<height>] [unit=<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;

View File

@ -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;