2007-10-26 22:44:33 +00:00
|
|
|
#!/usr/bin/env perl
|
|
|
|
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
|
|
|
|
package xCAT_plugin::nodediscover;
|
|
|
|
#use Net::SNMP qw(:snmp INTEGER);
|
|
|
|
use xCAT::Table;
|
|
|
|
use IO::Socket;
|
|
|
|
use SNMP;
|
|
|
|
use strict;
|
|
|
|
|
|
|
|
use XML::Simple;
|
2008-03-24 14:16:00 +00:00
|
|
|
$XML::Simple::PREFERRED_PARSER='XML::Parser';
|
2007-10-26 22:44:33 +00:00
|
|
|
use Data::Dumper;
|
|
|
|
use POSIX "WNOHANG";
|
|
|
|
use Storable qw(freeze thaw);
|
|
|
|
use IO::Select;
|
|
|
|
use IO::Handle;
|
2008-03-21 20:00:07 +00:00
|
|
|
use xCAT::Utils;
|
2007-10-26 22:44:33 +00:00
|
|
|
use Sys::Syslog;
|
|
|
|
|
|
|
|
|
2008-01-14 19:13:43 +00:00
|
|
|
sub gethosttag {
|
|
|
|
#This function tries to return a good hostname for a node based on the
|
|
|
|
#network to which it is connected (by $netn or maybe $ifname)
|
|
|
|
#heuristic:
|
|
|
|
#if the client had a valid IP address from a dhcp server, that is used as key
|
|
|
|
#once the matching network is found, and an explicit mapping defined, try that
|
|
|
|
#next, try to see if the ip for the case where hostname==nodename is on this net, if so, return that
|
|
|
|
#next, try to do nodename-ifname, return that if successful
|
|
|
|
#next, repeat process for all networks that have the common mgtifname field
|
|
|
|
#return undef for now if none of the above worked
|
|
|
|
my $node = shift;
|
|
|
|
my $netn = shift;
|
|
|
|
my $ifname = shift;
|
2008-03-21 20:00:07 +00:00
|
|
|
my $usednames = shift;
|
2008-03-24 19:32:02 +00:00
|
|
|
my %netmap = %{xCAT::Utils::my_if_netmap()};
|
2008-03-21 20:00:07 +00:00
|
|
|
my $mgtifname = $netmap{$netn};
|
2008-01-14 19:13:43 +00:00
|
|
|
my $secondpass = 0;
|
|
|
|
my $name = "";
|
|
|
|
my $defhost = inet_aton($node);
|
|
|
|
my $nettab = xCAT::Table->new('networks');
|
|
|
|
my $defn="";
|
|
|
|
my @netents = @{$nettab->getAllEntries()};
|
|
|
|
my $pass;
|
2008-01-26 19:06:21 +00:00
|
|
|
#TODO: mgtifname field will get trounced in hierarchical setup, use a live check to match accurately
|
2008-03-21 20:00:07 +00:00
|
|
|
foreach (@netents) {
|
|
|
|
if ($_->{net} eq $netn or ($mgtifname and $mgtifname eq $netmap{$_->{net}})) { #either is the network or shares physical interface
|
|
|
|
if ($_->{nodehostname}) { #Check for a nodehostname rule in the table
|
|
|
|
my $left;
|
|
|
|
my $right;
|
|
|
|
($left,$right) = split(/\//,$_->{nodehostname},2);
|
|
|
|
$name = $node;
|
|
|
|
$name =~ s/$left/$right/;
|
|
|
|
if ($name and inet_aton($name)) {
|
|
|
|
if ($netn eq $_->{net} and not $usednames->{$name}) { return $name; }
|
|
|
|
#At this point, it could still be valid if block was entered due to mgtifname
|
|
|
|
my $nnetn = inet_ntoa(pack("N",unpack("N",inet_aton($name)) & unpack("N",inet_aton($_->{mask}))));
|
|
|
|
if ($nnetn eq $_->{net} and not $usednames->{$name}) { return $name; }
|
|
|
|
}
|
|
|
|
$name=""; #Still here, this branch failed
|
|
|
|
}
|
|
|
|
$defn="";
|
|
|
|
if ($defhost) {
|
|
|
|
$defn = inet_ntoa(pack("N",unpack("N",$defhost) & unpack("N",inet_aton($_->{mask}))));
|
|
|
|
}
|
|
|
|
if ($defn eq $_->{net} and not $usednames->{$node}) { #the default nodename is on this network
|
|
|
|
return $node;
|
|
|
|
}
|
|
|
|
my $tentativehost = $node . "-".$ifname;
|
|
|
|
my $tnh = inet_aton($tentativehost);
|
|
|
|
if ($tnh) {
|
|
|
|
my $nnetn = inet_ntoa(pack("N",unpack("N",$tnh) & unpack("N",inet_aton($_->{mask}))));
|
|
|
|
if ($nnetn eq $_->{net} and not $usednames->{$tentativehost}) {
|
|
|
|
return $tentativehost;
|
|
|
|
}
|
|
|
|
}
|
2008-01-14 19:13:43 +00:00
|
|
|
}
|
2008-03-21 20:00:07 +00:00
|
|
|
}
|
2008-01-14 19:13:43 +00:00
|
|
|
}
|
|
|
|
|
2007-10-26 22:44:33 +00:00
|
|
|
sub handled_commands {
|
|
|
|
return {
|
2008-02-16 01:42:15 +00:00
|
|
|
#discovered => 'chain:ondiscover',
|
|
|
|
discovered => 'nodediscover',
|
2007-10-26 22:44:33 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
sub process_request {
|
|
|
|
my $request = shift;
|
|
|
|
my $callback = shift;
|
2008-01-14 22:19:17 +00:00
|
|
|
my $doreq = shift;
|
2007-10-26 22:44:33 +00:00
|
|
|
my $node = $request->{node}->[0];
|
2008-01-25 15:07:53 +00:00
|
|
|
my $ip = $request->{'_xcat_clientip'};
|
2007-10-26 22:44:33 +00:00
|
|
|
openlog("xCAT node discovery",'','local0');
|
|
|
|
#First, fill in tables with data fields..
|
|
|
|
if (defined($request->{mtm}) or defined($request->{serial})) {
|
|
|
|
my $vpdtab = xCAT::Table->new("vpd",-create=>1);
|
|
|
|
if ($request->{mtm}->[0]) {
|
|
|
|
$vpdtab->setNodeAttribs($node,{mtm=>$request->{mtm}->[0]});
|
|
|
|
}
|
|
|
|
if ($request->{serial}) {
|
|
|
|
$vpdtab->setNodeAttribs($node,{serial=>$request->{serial}->[0]});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (defined($request->{arch})) {
|
|
|
|
my $typetab=xCAT::Table->new("nodetype",-create=>1);
|
|
|
|
$typetab->setNodeAttribs($node,{arch=>$request->{arch}->[0]});
|
|
|
|
}
|
2008-01-14 19:13:43 +00:00
|
|
|
if (defined($request->{mac})) {
|
|
|
|
my $mactab = xCAT::Table->new("mac",-create=>1);
|
|
|
|
my @ifinfo;
|
|
|
|
my $macstring = "";
|
2008-03-21 20:00:07 +00:00
|
|
|
my %usednames;
|
2008-01-14 19:13:43 +00:00
|
|
|
foreach (@{$request->{mac}}) {
|
|
|
|
@ifinfo = split /\|/;
|
|
|
|
if ($ifinfo[3]) {
|
|
|
|
(my $ip,my $netbits) = split /\//,$ifinfo[3];
|
|
|
|
if ($ip =~ /\d+\.\d+\.\d+\.\d+/) {
|
|
|
|
my $ipn = unpack("N",inet_aton($ip));
|
|
|
|
my $mask = 2**$netbits-1<<(32-$netbits);
|
|
|
|
my $netn = inet_ntoa(pack("N",$ipn & $mask));
|
2008-03-21 20:00:07 +00:00
|
|
|
my $hosttag = gethosttag($node,$netn,@ifinfo[1],\%usednames);
|
2008-01-14 19:13:43 +00:00
|
|
|
if ($hosttag) {
|
2008-03-21 20:00:07 +00:00
|
|
|
$usednames{$hosttag}=1;
|
2008-01-14 19:13:43 +00:00
|
|
|
$macstring .= $ifinfo[2]."!".$hosttag."|";
|
2008-03-21 20:00:07 +00:00
|
|
|
} else {
|
|
|
|
$macstring .= $ifinfo[2]."!*NOIP*|";
|
|
|
|
}
|
2008-01-14 19:13:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
$mactab->setNodeAttribs($node,{mac=>$macstring});
|
2008-01-14 22:19:17 +00:00
|
|
|
my %request = (
|
|
|
|
command => ['makedhcp'],
|
|
|
|
node => [$node]
|
|
|
|
);
|
|
|
|
$doreq->(\%request);
|
2008-01-14 19:13:43 +00:00
|
|
|
}
|
2007-10-26 22:44:33 +00:00
|
|
|
#TODO: mac table? on the one hand, 'the' definitive interface was determined earlier...
|
|
|
|
#Delete the state it was in to make it traverse destiny once agoin
|
|
|
|
my $chaintab = xCAT::Table->new('chain');
|
|
|
|
if ($chaintab) {
|
|
|
|
$chaintab->setNodeAttribs($node,{currstate=>'',currchain=>''});
|
|
|
|
$chaintab->close();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#now, notify the node to continue life
|
|
|
|
my $sock = new IO::Socket::INET (
|
|
|
|
PeerAddr => $ip,
|
2008-01-11 20:55:28 +00:00
|
|
|
PeerPort => '3001',
|
|
|
|
Timeout => '1',
|
|
|
|
Proto => 'tcp'
|
|
|
|
);
|
2007-10-26 22:44:33 +00:00
|
|
|
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 "restart";
|
|
|
|
close($sock);
|
|
|
|
syslog("info","$node has been discovered");
|
|
|
|
}
|
|
|
|
|
|
|
|
1;
|