mirror of
				https://github.com/xcat2/xcat-core.git
				synced 2025-11-04 05:12:30 +00:00 
			
		
		
		
	git-svn-id: https://svn.code.sf.net/p/xcat/code/xcat-core/trunk@2899 8638fb3e-16cb-4fca-ae20-7b5d299a9bcd
		
			
				
	
	
		
			188 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
			
		
		
	
	
			188 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
#!/usr/bin/env perl
 | 
						|
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
 | 
						|
package xCAT_plugin::nodediscover;
 | 
						|
use xCAT::Table;
 | 
						|
use IO::Socket;
 | 
						|
use strict;
 | 
						|
 | 
						|
use XML::Simple;
 | 
						|
if ($^O =~ /^linux/i) {
 | 
						|
	$XML::Simple::PREFERRED_PARSER='XML::Parser';
 | 
						|
}
 | 
						|
use Data::Dumper;
 | 
						|
use POSIX "WNOHANG";
 | 
						|
use Storable qw(freeze thaw);
 | 
						|
use IO::Select;
 | 
						|
use IO::Handle;
 | 
						|
use xCAT::Utils;
 | 
						|
use Sys::Syslog;
 | 
						|
 | 
						|
 | 
						|
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;
 | 
						|
   my $usednames = shift;
 | 
						|
   my %netmap = %{xCAT::Utils::my_if_netmap()};
 | 
						|
   my $mgtifname = $netmap{$netn};
 | 
						|
   my $secondpass = 0;
 | 
						|
   my $name = "";
 | 
						|
   my $defhost = inet_aton($node);
 | 
						|
   my $nettab = xCAT::Table->new('networks');
 | 
						|
   my $defn="";
 | 
						|
   my @netents = @{$nettab->getAllEntries()};
 | 
						|
   my $pass;
 | 
						|
   #TODO: mgtifname field will get trounced in hierarchical setup, use a live check to match accurately
 | 
						|
   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;
 | 
						|
            }
 | 
						|
         }
 | 
						|
      }
 | 
						|
   }
 | 
						|
}
 | 
						|
 | 
						|
sub handled_commands {
 | 
						|
  return {
 | 
						|
    #discovered => 'chain:ondiscover',
 | 
						|
    discovered => 'nodediscover',
 | 
						|
  };
 | 
						|
}
 | 
						|
sub process_request {
 | 
						|
  my $request = shift;
 | 
						|
  my $callback = shift;
 | 
						|
  my $doreq = shift;
 | 
						|
  my $node = $request->{node}->[0];
 | 
						|
  my $ip = $request->{'_xcat_clientip'};
 | 
						|
  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]});
 | 
						|
    }
 | 
						|
  }
 | 
						|
  my $nrtab;
 | 
						|
  if (defined($request->{arch})) {
 | 
						|
    #Set the architecture in nodetype.  If 32-bit only x86 or ppc detected, overwrite.  If x86_64, only set if either not set or not an x86 family
 | 
						|
    my $typetab=xCAT::Table->new("nodetype",-create=>1);
 | 
						|
    if ($request->{arch}->[0] =~ /x86_64/) {
 | 
						|
      (my $nent) = $typetab->getNodeAttribs($node,['arch']);
 | 
						|
      unless ($nent and ($nent->{arch} =~ /x86/)) { #If already an x86 variant, do not change
 | 
						|
         $typetab->setNodeAttribs($node,{arch=>$request->{arch}->[0]});
 | 
						|
         #this check is so that if an admin explicitly declares a node 'x86', the 64 bit capability is ignored
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
      $typetab->setNodeAttribs($node,{arch=>$request->{arch}->[0]});
 | 
						|
    }
 | 
						|
    my $currboot='';
 | 
						|
    $nrtab = xCAT::Table->new('noderes'); #Attempt to check and set if wrong the netboot method on discovery, if admin omitted
 | 
						|
    (my $rent) = $nrtab->getNodeAttribs($node,['netboot']);
 | 
						|
    if ($rent and $rent->{'netboot'}) {
 | 
						|
       $currboot=$rent->{'netboot'};
 | 
						|
    }
 | 
						|
    if ($request->{arch}->[0] =~ /x86/ and $currboot !~ /pxe/) {
 | 
						|
       $nrtab->setNodeAttribs($node,{netboot=>'pxe'});
 | 
						|
    } elsif ($request->{arch}->[0] =~ /ppc/ and $currboot  !~ /yaboot/) {
 | 
						|
       $nrtab->setNodeAttribs($node,{netboot=>'yaboot'});
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if (defined($request->{mac})) {
 | 
						|
    my $mactab = xCAT::Table->new("mac",-create=>1);
 | 
						|
    my @ifinfo;
 | 
						|
    my $macstring = "";
 | 
						|
    my %usednames;
 | 
						|
    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));
 | 
						|
		my $hosttag = gethosttag($node,$netn,@ifinfo[1],\%usednames);
 | 
						|
		if ($hosttag) {
 | 
						|
         (my $rent) = $nrtab->getNodeAttribs($node,['primarynic','nfsserver']);
 | 
						|
         unless ($rent and $rent->{primarynic}) { #if primarynic not set, set it to this nic
 | 
						|
            $nrtab->setNodeAttribs($node,{primarynic=>@ifinfo[1]});
 | 
						|
         }
 | 
						|
         unless ($rent and $rent->{primarynic}) {
 | 
						|
            $nrtab->setNodeAttribs($node,{nfsserver=>xCAT::Utils->my_ip_facing($hosttag)});
 | 
						|
         }
 | 
						|
         $usednames{$hosttag}=1;
 | 
						|
		   $macstring .= $ifinfo[2]."!".$hosttag."|";
 | 
						|
		} else {
 | 
						|
         $macstring .= $ifinfo[2]."!*NOIP*|";
 | 
						|
      }
 | 
						|
	  }
 | 
						|
       }
 | 
						|
    }
 | 
						|
    $mactab->setNodeAttribs($node,{mac=>$macstring});
 | 
						|
    my %request = (
 | 
						|
       command => ['makedhcp'],
 | 
						|
       node => [$node]
 | 
						|
    );
 | 
						|
    $doreq->(\%request);
 | 
						|
  }
 | 
						|
  #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,
 | 
						|
          PeerPort => '3001',
 | 
						|
          Timeout => '1',
 | 
						|
          Proto => 'tcp'
 | 
						|
    );
 | 
						|
    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;
 |