Node management sprint2 works, reviewed by xCAT beijing team
git-svn-id: https://svn.code.sf.net/p/xcat/code/xcat-core/trunk@13724 8638fb3e-16cb-4fca-ae20-7b5d299a9bcd
This commit is contained in:
		@@ -2080,4 +2080,179 @@ sub pingNodeStatus {
 | 
			
		||||
  return %status;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
=head3  isReservedIP
 | 
			
		||||
      Description : Validate whether specified string is a reseved IPv4 string.
 | 
			
		||||
      Arguments   : ipstr - the string to be validated. 
 | 
			
		||||
      Returns     : 1 - valid reserved String.
 | 
			
		||||
                    0 - invalid reserved String.
 | 
			
		||||
=cut
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------------------------------
 | 
			
		||||
sub isReservedIP
 | 
			
		||||
{
 | 
			
		||||
    my ($class, $ipstr) = @_;
 | 
			
		||||
    my @ipnums = split('\.', $ipstr);
 | 
			
		||||
    if ($ipnums[3] eq "0" || $ipnums[3] eq "255"){
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
=head3 isValidMAC
 | 
			
		||||
      Description : Validate whether specified string is a MAC string.
 | 
			
		||||
      Arguments   : macstr - the string to be validated. 
 | 
			
		||||
      Returns     : 1 - valid MAC String.
 | 
			
		||||
                    0 - invalid MAC String.
 | 
			
		||||
=cut
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------------------------------
 | 
			
		||||
sub isValidMAC
 | 
			
		||||
{
 | 
			
		||||
    my ($class, $macstr) = @_;
 | 
			
		||||
    if ($macstr =~ /^[0-9a-fA-F]{2}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}$/){
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
=head3 isValidHostname
 | 
			
		||||
      Description : Validate whether specified string is a valid hostname.
 | 
			
		||||
      Arguments   : hostname - the string to be validated. 
 | 
			
		||||
      Returns     : 1 - valid hostname String.
 | 
			
		||||
                    0 - invalid hostname String.
 | 
			
		||||
=cut
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------------------------------
 | 
			
		||||
sub isValidHostname
 | 
			
		||||
{
 | 
			
		||||
    my ($class, $hostname) = @_;
 | 
			
		||||
    if ($hostname =~ /^[\-a-zA-Z0-9]+$/){
 | 
			
		||||
        return 1;
 | 
			
		||||
    }
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
=head3 ip_to_int
 | 
			
		||||
      Description : convert an IPv4 string into int.
 | 
			
		||||
      Arguments   : ipstr - the IPv4 string.
 | 
			
		||||
      Returns     : ipint - int number
 | 
			
		||||
=cut
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------------------------------
 | 
			
		||||
sub ip_to_int
 | 
			
		||||
{
 | 
			
		||||
    my ($class, $ipstr) = @_;
 | 
			
		||||
    my $ipint = 0;
 | 
			
		||||
    my @ipnums = split('\.', $ipstr);
 | 
			
		||||
    $ipint += $ipnums[0] << 24;
 | 
			
		||||
    $ipint += $ipnums[1] << 16;
 | 
			
		||||
    $ipint += $ipnums[2] << 8;
 | 
			
		||||
    $ipint += $ipnums[3];
 | 
			
		||||
    return $ipint;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
=head3 int_to_ip
 | 
			
		||||
      Description : convert an int into IPv4 String.
 | 
			
		||||
      Arguments   : ipnit - the input int number.
 | 
			
		||||
      Returns     : ipstr - IPv4 String.
 | 
			
		||||
=cut
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------------------------------
 | 
			
		||||
sub int_to_ip
 | 
			
		||||
{
 | 
			
		||||
    my ($class, $ipint) = @_;
 | 
			
		||||
    return inet_ntoa(inet_aton($ipint));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
=head3 get_allips_in_range
 | 
			
		||||
      Description : Get all IPs in a IP range, return in a list. 
 | 
			
		||||
      Arguments   : $startip - start IP address
 | 
			
		||||
                    $endip - end IP address
 | 
			
		||||
                    $increment - increment factor
 | 
			
		||||
                    $reservflag - A flag for whether we exclude reserved ips or not
 | 
			
		||||
      Returns     : IP list in this range.
 | 
			
		||||
      Example     :
 | 
			
		||||
                    my $startip = "192.168.0.1";
 | 
			
		||||
                    my $endip = "192.168.0.100";
 | 
			
		||||
                    xCAT::NetworkUtils->get_allips_in_range($startip, $endip, 1, 1);
 | 
			
		||||
=cut
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------------------------------
 | 
			
		||||
sub get_allips_in_range
 | 
			
		||||
{
 | 
			
		||||
    my $class = shift;
 | 
			
		||||
    my $startip = shift;
 | 
			
		||||
    my $endip = shift;
 | 
			
		||||
    my $increment = shift;
 | 
			
		||||
    my $reservflag = shift;
 | 
			
		||||
    my @iplist;
 | 
			
		||||
 | 
			
		||||
    my $startipnum = xCAT::NetworkUtils->ip_to_int($startip);
 | 
			
		||||
    my $endipnum = xCAT::NetworkUtils->ip_to_int($endip);
 | 
			
		||||
    while ($startipnum <= $endipnum){
 | 
			
		||||
        my $ip = xCAT::NetworkUtils->int_to_ip($startipnum);
 | 
			
		||||
        $startipnum += $increment;
 | 
			
		||||
        # Not return reserved IPs
 | 
			
		||||
        if ($reservflag){
 | 
			
		||||
            if(xCAT::NetworkUtils->isReservedIP($ip)){
 | 
			
		||||
                next;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        push (@iplist, $ip);
 | 
			
		||||
    }
 | 
			
		||||
    return \@iplist;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
=head3 get_all_ips
 | 
			
		||||
      Description : Get all IP addresses from table nics, column nicips.
 | 
			
		||||
      Arguments   : hashref - if not set, will return a reference of list,
 | 
			
		||||
                              if set, will return a reference of hash.
 | 
			
		||||
      Returns     : All IPs reference.
 | 
			
		||||
=cut
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------------------------------
 | 
			
		||||
sub get_all_nicips{
 | 
			
		||||
    my ($class, $hashref) = @_;
 | 
			
		||||
    my %allipshash;
 | 
			
		||||
    my @allipslist;
 | 
			
		||||
 | 
			
		||||
    my $table = xCAT::Table->new('nics');
 | 
			
		||||
    my @entries = $table->getAllNodeAttribs(['nicips']);
 | 
			
		||||
    foreach (@entries){
 | 
			
		||||
        # $_->{nicips} looks like "eth0:ip1,eth1:ip2,bmc:ip3..."
 | 
			
		||||
        if($_->{nicips}){
 | 
			
		||||
            my @nicandiplist = split(',', $_->{nicips});
 | 
			
		||||
            # Each record in @nicandiplist looks like "eth0:ip1"
 | 
			
		||||
            foreach (@nicandiplist){
 | 
			
		||||
                my @nicandip = split(':', $_);
 | 
			
		||||
                if ($hashref){
 | 
			
		||||
                    $allipshash{$nicandip[1]} = 0;
 | 
			
		||||
                } else{
 | 
			
		||||
                    push (@allipslist, $nicandip[1]);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if ($hashref){
 | 
			
		||||
        return \%allipshash;
 | 
			
		||||
    } else{
 | 
			
		||||
        return \@allipslist;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
1;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										527
									
								
								perl-xCAT/xCAT/PCMNodeMgmtUtils.pm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										527
									
								
								perl-xCAT/xCAT/PCMNodeMgmtUtils.pm
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,527 @@
 | 
			
		||||
# IBM(c) 2012 EPL license http://www.eclipse.org/legal/epl-v10.html
 | 
			
		||||
package xCAT::PCMNodeMgmtUtils;
 | 
			
		||||
 | 
			
		||||
use strict;
 | 
			
		||||
use warnings;
 | 
			
		||||
use Socket;
 | 
			
		||||
use File::Path qw/mkpath/;
 | 
			
		||||
use File::Temp qw/tempfile/;
 | 
			
		||||
require xCAT::Table;
 | 
			
		||||
require xCAT::TableUtils;
 | 
			
		||||
require xCAT::NodeRange;
 | 
			
		||||
require xCAT::NetworkUtils;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#--------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
=head1    xCAT::PCMNodeMgmtkUtils
 | 
			
		||||
 | 
			
		||||
=head2    Package Description
 | 
			
		||||
 | 
			
		||||
This program module file, is a set of PCM node management utilities.
 | 
			
		||||
 | 
			
		||||
=cut
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
=head3 get_allocable_staticips_innet
 | 
			
		||||
      Description : Get allocable IPs from a network.
 | 
			
		||||
      Arguments   : $netname - network name
 | 
			
		||||
                    $exclude_ips_ref - excluded IPs list reference.
 | 
			
		||||
      Returns     : Reference of allocable IPs list
 | 
			
		||||
=cut
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------------------------------
 | 
			
		||||
sub get_allocable_staticips_innet
 | 
			
		||||
{
 | 
			
		||||
    my $class = shift;
 | 
			
		||||
    my $netname = shift;
 | 
			
		||||
    my $exclude_ips_ref = shift;
 | 
			
		||||
    my %iphash;
 | 
			
		||||
    my @allocableips;
 | 
			
		||||
 | 
			
		||||
    foreach (@$exclude_ips_ref){
 | 
			
		||||
        $iphash{$_} = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    my $networkstab = xCAT::Table->new('networks');
 | 
			
		||||
    my $netentry = ($networkstab->getAllAttribsWhere("netname = '$netname'", 'ALL'))[0];
 | 
			
		||||
    my ($startip, $endip) =  split('-', $netentry->{'staticrange'});
 | 
			
		||||
    my $incremental = $netentry->{'staticrangeincrement'};
 | 
			
		||||
    my $validipsref;
 | 
			
		||||
    if ($incremental and $startip and $endip){
 | 
			
		||||
        $validipsref = xCAT::NetworkUtils->get_allips_in_range($startip, $endip, $incremental);
 | 
			
		||||
    }
 | 
			
		||||
    foreach (@$validipsref){
 | 
			
		||||
        if (! exists($iphash{$_})){
 | 
			
		||||
            push @allocableips, $_;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return \@allocableips;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
=head3 genhosts_with_numric_tmpl
 | 
			
		||||
      Description : Generate numric hostnames using numric template name.
 | 
			
		||||
      Arguments   : $format - The hostname format string..
 | 
			
		||||
      Returns     : numric hostname list
 | 
			
		||||
      Example     : 
 | 
			
		||||
              calling  genhosts_with_numric_tmpl("compute#NNnode") will return a list like:
 | 
			
		||||
              ("compute00node", "compute01node", ..."compute98node", "compute99node")
 | 
			
		||||
=cut
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------------------------------
 | 
			
		||||
sub genhosts_with_numric_tmpl
 | 
			
		||||
{
 | 
			
		||||
    my ($class, $format) = @_;
 | 
			
		||||
 | 
			
		||||
    my ($prefix, $appendix, $len) = xCAT::PCMNodeMgmtUtils->split_hostname($format, 'N');
 | 
			
		||||
    return xCAT::PCMNodeMgmtUtils->gen_numric_hostnames($prefix, $appendix, $len);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
=head3 split_hostname
 | 
			
		||||
      Description : Split hostname format as prefix, appendix and number length.
 | 
			
		||||
      Arguments   : $format - hostname format
 | 
			
		||||
                    $patt_char - pattern char, we always use "N" to indicate numric pattern
 | 
			
		||||
      Returns     : ($prefix, $appendix, $numlen)
 | 
			
		||||
                    $prefix - the prefix string of hostname format.
 | 
			
		||||
                    $appendix - the appendix string of hostname format
 | 
			
		||||
                    $numlen - The number length in hostname format.
 | 
			
		||||
      Example     : 
 | 
			
		||||
              calling  split_hostname("compute#NNnode") will return a list like:
 | 
			
		||||
              ("compute", "node", 2)
 | 
			
		||||
=cut
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------------------------------
 | 
			
		||||
sub split_hostname
 | 
			
		||||
{
 | 
			
		||||
    my ($class, $format, $patt_char) = @_;
 | 
			
		||||
 | 
			
		||||
    my $idx = index $format, "#$patt_char";
 | 
			
		||||
    my @array_format = split(//, $format);
 | 
			
		||||
    my $pos = $idx+2;
 | 
			
		||||
    while ( $pos <= (scalar(@array_format) - 1)){
 | 
			
		||||
        if ($array_format[$pos] eq "$patt_char"){
 | 
			
		||||
            $pos++;
 | 
			
		||||
        }else{
 | 
			
		||||
            last;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    my $ridx = $pos - 1;
 | 
			
		||||
 | 
			
		||||
    my $prefix = "";
 | 
			
		||||
    $prefix = substr $format, 0, $idx;
 | 
			
		||||
    my $appendix = "";
 | 
			
		||||
    if (($ridx + 1) != scalar(@array_format)){
 | 
			
		||||
        $appendix = substr $format, $ridx + 1;
 | 
			
		||||
    }
 | 
			
		||||
    return $prefix, $appendix, ($ridx - $idx);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
=head3 gen_numric_hostnames
 | 
			
		||||
      Description : Generate numric hostnames.
 | 
			
		||||
      Arguments   : $prefix - The prefix string of the hostname.
 | 
			
		||||
                    $appendix - The appendix string of the hostname.
 | 
			
		||||
                    $len - the numric number length in hostname.
 | 
			
		||||
      Returns     : numric hostname list
 | 
			
		||||
      Example     : 
 | 
			
		||||
              calling  gen_numric_hostnames("compute", "node",2) will return a list like:
 | 
			
		||||
              ("compute00node", "compute01node", ..."compute98node", "compute99node")
 | 
			
		||||
=cut
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------------------------------
 | 
			
		||||
sub gen_numric_hostnames
 | 
			
		||||
{
 | 
			
		||||
    my ($class, $prefix, $appendix, $len) = @_;
 | 
			
		||||
    my @hostnames;
 | 
			
		||||
 | 
			
		||||
    my $cnt=0;
 | 
			
		||||
    my $maxnum = 10 ** $len;
 | 
			
		||||
    while($cnt < $maxnum)
 | 
			
		||||
    {
 | 
			
		||||
        my $fullnum = $maxnum + $cnt;
 | 
			
		||||
        my $hostname = $prefix.(substr $fullnum, 1).$appendix;
 | 
			
		||||
        push (@hostnames, $hostname);
 | 
			
		||||
        $cnt++;
 | 
			
		||||
    }
 | 
			
		||||
    return \@hostnames;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
=head3 get_hostname_format_type
 | 
			
		||||
      Description : Get hostname format type.
 | 
			
		||||
      Arguments   : $format - hostname format
 | 
			
		||||
      Returns     : hostname format type value:
 | 
			
		||||
                    "numric" - numric hostname format.
 | 
			
		||||
                    "rack" - rack info hostname format.
 | 
			
		||||
      Example     : 
 | 
			
		||||
              calling  get_hostname_format_type("compute#NNnode") will return "numric"
 | 
			
		||||
              calling  get_hostname_format_type("compute-#RR-#NN") will return "rack" 
 | 
			
		||||
=cut
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------------------------------
 | 
			
		||||
sub get_hostname_format_type{
 | 
			
		||||
    my ($class, $format) =  @_;
 | 
			
		||||
    my $type;
 | 
			
		||||
 | 
			
		||||
    my $ridx = index $format, "#R";
 | 
			
		||||
    my $nidx = index $format, "#N";
 | 
			
		||||
    if ($ridx >= 0){
 | 
			
		||||
        $type = "rack";
 | 
			
		||||
    } elsif ($nidx >= 0){
 | 
			
		||||
        $type = "numric";
 | 
			
		||||
    }
 | 
			
		||||
    return $type;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
=head3 rackformat_to_numricformat
 | 
			
		||||
      Description : convert rack hostname format into numric hostname format.
 | 
			
		||||
      Arguments   : $format - rack hostname format
 | 
			
		||||
                    $racknum - rack number.
 | 
			
		||||
      Returns     : numric hostname format.
 | 
			
		||||
      Example     : 
 | 
			
		||||
           calling  rackformat_to_numricformat("compute-#RR-#NN", 1) will return "compute-01-#NN" 
 | 
			
		||||
=cut
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------------------------------
 | 
			
		||||
sub rackformat_to_numricformat{
 | 
			
		||||
    my ($class, $format, $racknum) = @_;
 | 
			
		||||
    my ($prefix, $appendix, $len) = xCAT::PCMNodeMgmtUtils->split_hostname($format, 'R');
 | 
			
		||||
 | 
			
		||||
    my $maxnum = 10 ** $len;
 | 
			
		||||
    my $fullnum = $maxnum + $racknum;
 | 
			
		||||
    return $prefix.(substr $fullnum, 1).$appendix;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
=head3 get_netprofile_nic_attrs
 | 
			
		||||
      Description : Get networkprofile's NIC attributes and return a dict.
 | 
			
		||||
      Arguments   : $netprofilename - network profile name.
 | 
			
		||||
      Returns     : A hash %netprofileattrs for network profile attributes.
 | 
			
		||||
                    keys of %netprofileattrs are nics names, like: ib0, eth0, bmc...
 | 
			
		||||
                    values of %netprofileattrs are attributes of a specific nic, like:
 | 
			
		||||
                        type : nic type
 | 
			
		||||
                        hostnamesuffix: hostname suffix
 | 
			
		||||
                        customscript: custom script for this nic
 | 
			
		||||
                        network: network name for this nic
 | 
			
		||||
=cut
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------------------------------
 | 
			
		||||
sub get_netprofile_nic_attrs{
 | 
			
		||||
    my $class = shift;
 | 
			
		||||
    my $netprofilename = shift;
 | 
			
		||||
 | 
			
		||||
    my $nicstab = xCAT::Table->new( 'nics');
 | 
			
		||||
    my $entry = $nicstab->getNodeAttribs("$netprofilename", ['nictypes', 'nichostnamesuffixes', 'niccustomscripts', 'nicnetworks']);
 | 
			
		||||
 | 
			
		||||
    my %netprofileattrs;
 | 
			
		||||
    my @nicattrslist;
 | 
			
		||||
 | 
			
		||||
    if ($entry->{'nictypes'}){
 | 
			
		||||
        @nicattrslist = split(",", $entry->{'nictypes'});
 | 
			
		||||
        foreach (@nicattrslist){
 | 
			
		||||
            my @nicattrs = split(":", $_);
 | 
			
		||||
            $netprofileattrs{$nicattrs[0]}{'type'} = $nicattrs[1];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if($entry->{'nichostnamesuffixes'}){
 | 
			
		||||
        @nicattrslist = split(",", $entry->{'nichostnamesuffixes'});
 | 
			
		||||
        foreach (@nicattrslist){
 | 
			
		||||
            my @nicattrs = split(":", $_);
 | 
			
		||||
            $netprofileattrs{$nicattrs[0]}{'hostnamesuffix'} = $nicattrs[1];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if($entry->{'niccustomscripts'}){
 | 
			
		||||
        @nicattrslist = split(",", $entry->{'niccustomscripts'});
 | 
			
		||||
        foreach (@nicattrslist){
 | 
			
		||||
            my @nicattrs = split(":", $_);
 | 
			
		||||
            $netprofileattrs{$nicattrs[0]}{'customscript'} = $nicattrs[1];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if($entry->{'nicnetworks'}){
 | 
			
		||||
        @nicattrslist = split(",", $entry->{'nicnetworks'});
 | 
			
		||||
        foreach (@nicattrslist){
 | 
			
		||||
            my @nicattrs = split(":", $_);
 | 
			
		||||
            $netprofileattrs{$nicattrs[0]}{'network'} = $nicattrs[1];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return \%netprofileattrs;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
=head3 get_netprofile_bmcnet
 | 
			
		||||
      Description : Get bmc network name of a network profile.
 | 
			
		||||
      Arguments   : $nettmpl - network profile name 
 | 
			
		||||
      Returns     : bmc network name of this network profile.
 | 
			
		||||
=cut
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------------------------------
 | 
			
		||||
sub get_netprofile_bmcnet{
 | 
			
		||||
    my ($class, $netprofilename) = @_;
 | 
			
		||||
 | 
			
		||||
    my $netprofile_nicshash_ref = xCAT::PCMNodeMgmtUtils->get_netprofile_nic_attrs($netprofilename);
 | 
			
		||||
    my %netprofile_nicshash = %$netprofile_nicshash_ref;
 | 
			
		||||
    if (exists $netprofile_nicshash{'bmc'}{"network"}){
 | 
			
		||||
        return $netprofile_nicshash{'bmc'}{"network"}
 | 
			
		||||
    }else{
 | 
			
		||||
        return undef;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
=head3 get_netprofile_provisionnet
 | 
			
		||||
      Description : Get deployment network of a network profile.
 | 
			
		||||
      Arguments   : $nettmpl - network profile name 
 | 
			
		||||
      Returns     : deployment network name of this network profile.
 | 
			
		||||
=cut
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------------------------------
 | 
			
		||||
sub get_netprofile_provisionnet{
 | 
			
		||||
    my ($class, $netprofilename) = @_;
 | 
			
		||||
 | 
			
		||||
    my $netprofile_nicshash_ref = xCAT::PCMNodeMgmtUtils->get_netprofile_nic_attrs($netprofilename);
 | 
			
		||||
    my %netprofile_nicshash = %$netprofile_nicshash_ref;
 | 
			
		||||
    my $restab = xCAT::Table->new('noderes');
 | 
			
		||||
    my $installnicattr = $restab->getNodeAttribs($netprofilename, ['installnic']);
 | 
			
		||||
    my $installnic = $installnicattr->{'installnic'};
 | 
			
		||||
 | 
			
		||||
    if ($installnic){
 | 
			
		||||
        if (exists $netprofile_nicshash{$installnic}{"network"}){
 | 
			
		||||
            return $netprofile_nicshash{$installnic}{"network"}
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return undef;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
=head3 get_output_filename
 | 
			
		||||
      Description : Generate a temp file name for placing output details for PCM node management operations.
 | 
			
		||||
                    We make this file generated under /install/ so that clients can access it through http.
 | 
			
		||||
      Arguments   : N/A
 | 
			
		||||
      Returns     : A temp filename placed under /install/pcm/work/
 | 
			
		||||
=cut
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------------------------------
 | 
			
		||||
sub get_output_filename
 | 
			
		||||
{
 | 
			
		||||
    my $installdir = xCAT::TableUtils->getInstallDir();
 | 
			
		||||
    my $pcmworkdir = $installdir."/pcm/work/";
 | 
			
		||||
    if (! -d $pcmworkdir)
 | 
			
		||||
    {
 | 
			
		||||
        mkpath($pcmworkdir);
 | 
			
		||||
    }
 | 
			
		||||
    return tempfile("hostinfo_result_XXXXXXX", DIR=>$pcmworkdir);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
=head3 get_all_chassis
 | 
			
		||||
      Description : Get all chassis in system.
 | 
			
		||||
      Arguments   : hashref: if not set, return a array ref.
 | 
			
		||||
                             if set, return a hash ref.
 | 
			
		||||
      Returns     : ref for node list.
 | 
			
		||||
      Example     : 
 | 
			
		||||
                    my $arrayref = xCAT::PCMNodeMgmtUtils->get_all_chassis();
 | 
			
		||||
                    my $hashref = xCAT::PCMNodeMgmtUtils->get_all_chassis(1);
 | 
			
		||||
=cut
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------------------------------
 | 
			
		||||
sub get_all_chassis
 | 
			
		||||
{
 | 
			
		||||
    my $class = shift;
 | 
			
		||||
    my $hashref = shift;
 | 
			
		||||
    my %chassishash;
 | 
			
		||||
 | 
			
		||||
    my @chassis = xCAT::NodeRange::noderange('__Chassis');
 | 
			
		||||
    if ($hashref){
 | 
			
		||||
        foreach (@chassis){
 | 
			
		||||
            $chassishash{$_} = 1;
 | 
			
		||||
        }
 | 
			
		||||
        return \%chassishash;
 | 
			
		||||
    } else{
 | 
			
		||||
        return \@chassis;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
=head3 get_allnode_singleattrib_hash
 | 
			
		||||
      Description : Get all records of a column from a table, then return a hash.
 | 
			
		||||
                    The return hash's keys are the records of this attribute 
 | 
			
		||||
                    and values are all set as 1.
 | 
			
		||||
      Arguments   : $tabname - the table name.
 | 
			
		||||
                    $attr - the attribute name.
 | 
			
		||||
      Returns     : Reference of the records hash.
 | 
			
		||||
=cut
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------------------------------
 | 
			
		||||
sub get_allnode_singleattrib_hash
 | 
			
		||||
{
 | 
			
		||||
    my $class = shift;
 | 
			
		||||
    my $tabname = shift;
 | 
			
		||||
    my $attr = shift;
 | 
			
		||||
    my $table = xCAT::Table->new($tabname);
 | 
			
		||||
    my @entries = $table->getAllNodeAttribs([$attr]);
 | 
			
		||||
    my %allrecords;
 | 
			
		||||
    foreach (@entries) {
 | 
			
		||||
        if ($_->{$attr}){
 | 
			
		||||
            $allrecords{$_->{$attr}} = 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return \%allrecords;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
=head3 acquire_lock
 | 
			
		||||
      Description : Create lock file for node management plugin so that there is 
 | 
			
		||||
                    no multi node mamangement plugins running.
 | 
			
		||||
                    The file content will be the pid of the plugin running process.
 | 
			
		||||
                    Once the plugin process terminated abnormally and lock file not removed,
 | 
			
		||||
                    next time node management plugin runs, it will read the lock file 
 | 
			
		||||
                    and check whether this process is running or not. If not, 
 | 
			
		||||
                    just remove this lock file and create a new one.
 | 
			
		||||
      Arguments   : N/A
 | 
			
		||||
      Returns     : 1 - create lock success.
 | 
			
		||||
                    0 - failed, there may be a node management process running.
 | 
			
		||||
=cut
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------------------------------
 | 
			
		||||
sub acquire_lock
 | 
			
		||||
{
 | 
			
		||||
    my $lockfile = "/var/lock/pcm/nodemgmt";
 | 
			
		||||
    my $lockdir = "/var/lock/pcm";
 | 
			
		||||
    mkdir "$lockdir", 0755 unless -d "$lockdir";
 | 
			
		||||
 | 
			
		||||
    if (-e $lockfile) {
 | 
			
		||||
        open LOCKFILE, "<$lockfile";
 | 
			
		||||
        my @lines = <LOCKFILE>;
 | 
			
		||||
        my $pid = $lines[0];
 | 
			
		||||
        if (-d "/proc/$pid") {
 | 
			
		||||
            return 0;
 | 
			
		||||
        } else{
 | 
			
		||||
            # the process already not exists, remove lock file.
 | 
			
		||||
            File::Path->rmtree($lockfile);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    open LOCKFILE, ">$lockfile";
 | 
			
		||||
    print LOCKFILE $$;
 | 
			
		||||
    close LOCKFILE;
 | 
			
		||||
    return 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
=head3 release_lock
 | 
			
		||||
      Description : Release lock for node management process.
 | 
			
		||||
      Arguments   : N/A
 | 
			
		||||
      Returns     : N/A
 | 
			
		||||
=cut
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------------------------------
 | 
			
		||||
sub release_lock
 | 
			
		||||
{
 | 
			
		||||
    my $lockfile = "/var/lock/pcm/nodemgmt";
 | 
			
		||||
    if (-e $lockfile){
 | 
			
		||||
        open LOCKFILE, "<$lockfile";
 | 
			
		||||
        my @lines = <LOCKFILE>;
 | 
			
		||||
        my $pid = $lines[0];
 | 
			
		||||
        close LOCKFILE;
 | 
			
		||||
        if ($pid ne $$){
 | 
			
		||||
            File::Path->rmtree($lockfile);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
=head3 get_node_profiles
 | 
			
		||||
      Description : Get nodelist's profile and return a hash ref.
 | 
			
		||||
      Arguments   : node list.
 | 
			
		||||
      Returns     : nodelist's profile hash.
 | 
			
		||||
                    keys are node names.
 | 
			
		||||
                    values are hash ref. This hash ref is placing the node's profile information:
 | 
			
		||||
                        keys can be followings: "NetworkProfile", "ImageProfile", "HardwareProfile"
 | 
			
		||||
                        values are the profile names.
 | 
			
		||||
=cut
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
sub get_nodes_profiles
 | 
			
		||||
{
 | 
			
		||||
    my $class = shift;
 | 
			
		||||
    my $nodelistref = shift;
 | 
			
		||||
    my %profile_dict;
 | 
			
		||||
 | 
			
		||||
    my $nodelisttab = xCAT::Table->new('nodelist');
 | 
			
		||||
    my $groupshashref = $nodelisttab->getNodesAttribs($nodelistref, ['groups']);
 | 
			
		||||
    my %groupshash = %$groupshashref;
 | 
			
		||||
 | 
			
		||||
    foreach (keys %groupshash){
 | 
			
		||||
        my $value = $groupshash{$_};
 | 
			
		||||
        my $groups = $value->[0]->{'groups'};
 | 
			
		||||
        # groups looks like "__Managed,__NetworkProfile_default_cn,__ImageProfile_rhels6.3-x86_64-install-compute"
 | 
			
		||||
        my @grouplist = split(',', $groups);
 | 
			
		||||
        my @profilelist = ("NetworkProfile", "ImageProfile", "HardwareProfile");
 | 
			
		||||
        foreach my $group (@grouplist){
 | 
			
		||||
            foreach my $profile (@profilelist){
 | 
			
		||||
                my $idx = index ($group, $profile);
 | 
			
		||||
                # The Group starts with __, so index will be 2.
 | 
			
		||||
                if ( $idx == 2 ){
 | 
			
		||||
                    # The group string will like @NetworkProfile_<profile name>
 | 
			
		||||
                    # So, index should +3, 2 for '__', 1 for _.
 | 
			
		||||
                    my $append_index = length($profile) + 3;
 | 
			
		||||
                    $profile_dict{$_}{$profile} = substr $group, $append_index;
 | 
			
		||||
                    last;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return \%profile_dict;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
=head3 get_imageprofile_prov_method
 | 
			
		||||
      Description : Get A node's provisioning method from its imageprofile attribute.
 | 
			
		||||
      Arguments   : $imgprofilename - imageprofile name
 | 
			
		||||
      Returns     : node's provisioning method: install, netboot...etc
 | 
			
		||||
=cut
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------------------------------
 | 
			
		||||
sub get_imageprofile_prov_method
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    # For imageprofile, we can get node's provisioning method through:
 | 
			
		||||
    # nodetype table: node (imageprofile name), provmethod (osimage name)
 | 
			
		||||
    # osimage table: imagename (osimage name), provmethod (node deploy method: install, netboot...)
 | 
			
		||||
    my $class = shift;
 | 
			
		||||
    my $imgprofilename = shift;
 | 
			
		||||
 | 
			
		||||
    my $nodetypestab = xCAT::Table->new('nodetype');
 | 
			
		||||
    my $entry = ($nodetypestab->getAllAttribsWhere("node = '$imgprofilename'", 'ALL' ))[0];
 | 
			
		||||
    my $osimgname = $entry->{'provmethod'};
 | 
			
		||||
 | 
			
		||||
    my $osimgtab = xCAT::Table->new('osimage');
 | 
			
		||||
    my $osimgentry = ($osimgtab->getAllAttribsWhere("imagename = '$osimgname'", 'ALL' ))[0];
 | 
			
		||||
    return $osimgentry->{'provmethod'};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										117
									
								
								xCAT-server/lib/xcat/plugins/00pcmkitbase.pm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								xCAT-server/lib/xcat/plugins/00pcmkitbase.pm
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,117 @@
 | 
			
		||||
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
 | 
			
		||||
 | 
			
		||||
package xCAT_plugin::00pcmkitbase;
 | 
			
		||||
 | 
			
		||||
use strict;
 | 
			
		||||
use warnings;
 | 
			
		||||
require xCAT::Utils;
 | 
			
		||||
require xCAT::Table;
 | 
			
		||||
require xCAT::PCMNodeMgmtUtils;
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
=head1
 | 
			
		||||
 | 
			
		||||
    xCAT plugin, which is also the default PCM kit plugin.
 | 
			
		||||
    These commands are called by PCM node management commands, 
 | 
			
		||||
    should not be called directly by external.
 | 
			
		||||
    
 | 
			
		||||
=cut
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
=head3  handled_commands
 | 
			
		||||
 | 
			
		||||
    Return list of commands handled by this plugin
 | 
			
		||||
 | 
			
		||||
=cut
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------
 | 
			
		||||
sub handled_commands {
 | 
			
		||||
    return {
 | 
			
		||||
        kitcmd_nodemgmt_add => '00pcmkitbase',
 | 
			
		||||
        kitcmd_nodemgmt_remove => '00pcmkitbase',
 | 
			
		||||
        kitcmd_nodemgmt_update => '00pcmkitbase',
 | 
			
		||||
        kitcmd_nodemgmt_refresh => '00pcmkitbase',
 | 
			
		||||
        kitcmd_nodemgmt_finished => '00pcmkitbase',
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
=head3  process_request
 | 
			
		||||
 | 
			
		||||
    Process the command.  This is the main call.
 | 
			
		||||
 | 
			
		||||
=cut
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------
 | 
			
		||||
sub process_request {
 | 
			
		||||
    my $request = shift;
 | 
			
		||||
    my $callback = shift;
 | 
			
		||||
    my $request_command = shift;
 | 
			
		||||
    my $command = $request->{command}->[0];
 | 
			
		||||
    my $argsref = $request->{arg};
 | 
			
		||||
    
 | 
			
		||||
    my $nodelist = $request->{node};
 | 
			
		||||
 | 
			
		||||
    if($command eq 'kitcmd_nodemgmt_add')
 | 
			
		||||
    {
 | 
			
		||||
        $request_command->({command=>["makehosts"], node=>$nodelist});
 | 
			
		||||
        $request_command->({command=>["makedns"], node=>$nodelist}, arg=>['-n']);
 | 
			
		||||
        # Work around for makedns bug, it will set umask to 0007.
 | 
			
		||||
        umask(0022);
 | 
			
		||||
        $request_command->({command=>["makedhcp"], node=>$nodelist});
 | 
			
		||||
        $request_command->({command=>["makeknownhosts"], node=>$nodelist});
 | 
			
		||||
        my $firstnode = (@$nodelist)[0];
 | 
			
		||||
        my $profileref = xCAT::PCMNodeMgmtUtils->get_nodes_profiles([$firstnode]);
 | 
			
		||||
        my %profilehash = %$profileref;
 | 
			
		||||
        if (exists $profilehash{$firstnode}{"ImageProfile"}){
 | 
			
		||||
            $request_command->({command=>["nodeset"], node=>$nodelist, arg=>['osimage='.$profilehash{$firstnode}{"ImageProfile"}]});
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
    elsif ($command eq 'kitcmd_nodemgmt_remove'){
 | 
			
		||||
        $request_command->({command=>["nodeset"], node=>$nodelist, arg=>['offline']});
 | 
			
		||||
        $request_command->({command=>["makeknownhosts"], node=>$nodelist, arg=>['-r']});
 | 
			
		||||
        $request_command->({command=>["makedhcp"], node=>$nodelist, arg=>['-d']});
 | 
			
		||||
        $request_command->({command=>["makedns"], node=>$nodelist, arg=>['-d']});
 | 
			
		||||
        # Work around for makedns bug, it will set umask to 0007.
 | 
			
		||||
        umask(0022);
 | 
			
		||||
        $request_command->({command=>["makehosts"], node=>$nodelist, arg=>['-d']});
 | 
			
		||||
    }
 | 
			
		||||
    elsif ($command eq 'kitcmd_nodemgmt_update'){
 | 
			
		||||
        $request_command->({command=>["makehosts"], node=>$nodelist});
 | 
			
		||||
        $request_command->({command=>["makedns"], node=>$nodelist}, arg=>['-n']);
 | 
			
		||||
        # Work around for makedns bug, it will set umask to 0007.
 | 
			
		||||
        umask(0022);
 | 
			
		||||
        $request_command->({command=>["makedhcp"], node=>$nodelist});
 | 
			
		||||
        $request_command->({command=>["makeknownhosts"], node=>$nodelist});
 | 
			
		||||
        my $firstnode = (@$nodelist)[0];
 | 
			
		||||
        my $profileref = xCAT::PCMNodeMgmtUtils->get_nodes_profiles([$firstnode]);
 | 
			
		||||
        my %profilehash = %$profileref;
 | 
			
		||||
        if (exists $profilehash{$firstnode}{"ImageProfile"}){
 | 
			
		||||
            $request_command->({command=>["nodeset"], node=>$nodelist, arg=>['osimage='.$profilehash{$firstnode}{"ImageProfile"}]});
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    elsif ($command eq 'kitcmd_nodemgmt_refresh'){
 | 
			
		||||
        $request_command->({command=>["makehosts"], node=>$nodelist});
 | 
			
		||||
        $request_command->({command=>["makedns"], node=>$nodelist}, arg=>['-n']);
 | 
			
		||||
        # Work around for makedns bug, it will set umask to 0007.
 | 
			
		||||
        umask(0022);
 | 
			
		||||
        $request_command->({command=>["makedhcp"], node=>$nodelist});
 | 
			
		||||
        $request_command->({command=>["makeknownhosts"], node=>$nodelist});
 | 
			
		||||
    }
 | 
			
		||||
    elsif ($command eq 'kitcmd_nodemgmt_finished')
 | 
			
		||||
    {
 | 
			
		||||
        $request_command->({command=>["makeconservercf"]});
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
1;
 | 
			
		||||
							
								
								
									
										758
									
								
								xCAT-server/lib/xcat/plugins/pcmnodes.pm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										758
									
								
								xCAT-server/lib/xcat/plugins/pcmnodes.pm
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,758 @@
 | 
			
		||||
# IBM(c) 2012 EPL license http://www.eclipse.org/legal/epl-v10.html
 | 
			
		||||
#-------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
=head1
 | 
			
		||||
 | 
			
		||||
    xCAT plugin to support PCM node management
 | 
			
		||||
    These commands are designed to be called by PCM GUI.
 | 
			
		||||
    
 | 
			
		||||
=cut
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------
 | 
			
		||||
package xCAT_plugin::pcmnodes;
 | 
			
		||||
 | 
			
		||||
use strict;
 | 
			
		||||
use warnings;
 | 
			
		||||
require xCAT::Table;
 | 
			
		||||
require xCAT::DBobjUtils;
 | 
			
		||||
require xCAT::Utils;
 | 
			
		||||
require xCAT::TableUtils;
 | 
			
		||||
require xCAT::NetworkUtils;
 | 
			
		||||
require xCAT::MsgUtils;
 | 
			
		||||
require xCAT::PCMNodeMgmtUtils;
 | 
			
		||||
 | 
			
		||||
# Globals.
 | 
			
		||||
# These 2 global variables are for storing the parse result of hostinfo file.
 | 
			
		||||
# These 2 global varialbes are set in lib xCAT::DBobjUtils->readFileInput.
 | 
			
		||||
#%::FILEATTRS;     
 | 
			
		||||
#@::fileobjnames;
 | 
			
		||||
 | 
			
		||||
# All database records.
 | 
			
		||||
my %allhostnames;
 | 
			
		||||
my %allbmcips;
 | 
			
		||||
my %allmacs;
 | 
			
		||||
my %allips;
 | 
			
		||||
my %allinstallips;
 | 
			
		||||
my %allnicips;
 | 
			
		||||
my %allracks;
 | 
			
		||||
my %allchassis;
 | 
			
		||||
 | 
			
		||||
# Define parameters for xcat requests.
 | 
			
		||||
my $request;
 | 
			
		||||
my $callback;
 | 
			
		||||
my $request_command;
 | 
			
		||||
my $command;
 | 
			
		||||
my $args;
 | 
			
		||||
# Put arguments in a hash.
 | 
			
		||||
my %args_dict;
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
=head3  handled_commands
 | 
			
		||||
 | 
			
		||||
    Return list of commands handled by this plugin
 | 
			
		||||
 | 
			
		||||
=cut
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------
 | 
			
		||||
sub handled_commands {
 | 
			
		||||
    return {
 | 
			
		||||
        addhost_hostfile   => 'pcmnodes',
 | 
			
		||||
        addhost_discover     => 'pcmnodes',
 | 
			
		||||
        removehost     => 'pcmnodes',
 | 
			
		||||
        updatehost     => 'pcmnodes',
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
=head3  process_request
 | 
			
		||||
 | 
			
		||||
    Process the command.  This is the main call.
 | 
			
		||||
 | 
			
		||||
=cut
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------
 | 
			
		||||
sub process_request {
 | 
			
		||||
 | 
			
		||||
    my $lock = xCAT::PCMNodeMgmtUtils->acquire_lock();
 | 
			
		||||
    unless ($lock){
 | 
			
		||||
        setrsp_errormsg("Can not acquire lock, some process is operating node related actions.");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    $request = shift;
 | 
			
		||||
    $callback = shift;
 | 
			
		||||
    $request_command = shift;
 | 
			
		||||
    $command = $request->{command}->[0];
 | 
			
		||||
    $args = $request->{arg};
 | 
			
		||||
	
 | 
			
		||||
    if ($command eq "addhost_hostfile"){
 | 
			
		||||
        addhost_hostfile()
 | 
			
		||||
    } elsif ($command eq "removehost"){
 | 
			
		||||
    	removehost();
 | 
			
		||||
    } elsif ($command eq "updatehost"){
 | 
			
		||||
    	updatehost();
 | 
			
		||||
    }
 | 
			
		||||
    xCAT::PCMNodeMgmtUtils->release_lock($lock);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
=head3  parse_args
 | 
			
		||||
 | 
			
		||||
    Description : Parse arguments. We placed arguments into a directory %args_dict
 | 
			
		||||
    Arguments   : args - args of xCAT requests.
 | 
			
		||||
    Returns     : undef - parse succeed.
 | 
			
		||||
                  A string - parse arguments failed, the return value is error message.
 | 
			
		||||
=cut
 | 
			
		||||
 | 
			
		||||
#-----------------------------------------------------
 | 
			
		||||
 | 
			
		||||
sub parse_args{
 | 
			
		||||
    foreach my $arg (@$args){
 | 
			
		||||
        my @argarray = split(/=/,$arg);
 | 
			
		||||
        my $arglen = @argarray;
 | 
			
		||||
        if ($arglen > 2){
 | 
			
		||||
            return "Illegal arg $arg specified.";
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        # translate the profile names into real group names in db.
 | 
			
		||||
        if($argarray[0] eq "networkprofile"){
 | 
			
		||||
            $args_dict{$argarray[0]} = "__NetworkProfile_".$argarray[1];
 | 
			
		||||
        } elsif ($argarray[0] eq "imageprofile"){
 | 
			
		||||
            $args_dict{$argarray[0]} = "__ImageProfile_".$argarray[1];
 | 
			
		||||
        } elsif ($argarray[0] eq "hardwareprofile"){
 | 
			
		||||
            $args_dict{$argarray[0]} = "__HardwareProfile_".$argarray[1];
 | 
			
		||||
        } else{
 | 
			
		||||
            $args_dict{$argarray[0]} = $argarray[1];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return undef;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
=head3  addhost_hostfile
 | 
			
		||||
 | 
			
		||||
    Description : Create nodes by import hostinfo file.
 | 
			
		||||
    Arguments   : N/A
 | 
			
		||||
 | 
			
		||||
=cut
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------
 | 
			
		||||
sub addhost_hostfile {
 | 
			
		||||
 | 
			
		||||
    # Parse arges.
 | 
			
		||||
    xCAT::MsgUtils->message('S', "[PCM nodes mgmt]Import PCM nodes through hostinfo file.\n");
 | 
			
		||||
    my $retstr = parse_args();
 | 
			
		||||
    if ($retstr){
 | 
			
		||||
        setrsp_errormsg($retstr);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    # Make sure the specified parameters are valid ones.
 | 
			
		||||
    # TODO: support privisioning template.
 | 
			
		||||
    my @enabledparams = ('file', 'groups', 'networkprofile', 'hardwareprofile', 'imageprofile');
 | 
			
		||||
    foreach my $argname (keys %args_dict){
 | 
			
		||||
        if (! grep{ $_ eq $argname} @enabledparams){
 | 
			
		||||
            setrsp_errormsg("Illegal attribute $argname specified.");
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    # validate hostinfo file.
 | 
			
		||||
    if (! exists $args_dict{'file'}){
 | 
			
		||||
        setrsp_errormsg("No hostinfo file specified.");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    elsif(! (-e $args_dict{'file'})){
 | 
			
		||||
        setrsp_errormsg("The hostinfo file not exists.");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    # Get database records: all hostnames, all ips, all racks...
 | 
			
		||||
    xCAT::MsgUtils->message('S', "[PCM nodes mgmt]Getting database records.\n");
 | 
			
		||||
    my $recordsref = xCAT::PCMNodeMgmtUtils->get_allnode_singleattrib_hash('nodelist', 'node');
 | 
			
		||||
    %allhostnames = %$recordsref;
 | 
			
		||||
    $recordsref = xCAT::PCMNodeMgmtUtils->get_allnode_singleattrib_hash('ipmi', 'bmc');
 | 
			
		||||
    %allbmcips = %$recordsref;
 | 
			
		||||
    $recordsref = xCAT::PCMNodeMgmtUtils->get_allnode_singleattrib_hash('mac', 'mac');
 | 
			
		||||
    %allmacs = %$recordsref;
 | 
			
		||||
    $recordsref = xCAT::PCMNodeMgmtUtils->get_allnode_singleattrib_hash('hosts', 'ip');
 | 
			
		||||
    %allinstallips = %$recordsref;
 | 
			
		||||
    $recordsref = xCAT::NetworkUtils->get_all_nicips(1);
 | 
			
		||||
    %allips = %$recordsref;
 | 
			
		||||
 | 
			
		||||
    # Merge all BMC IPs and install IPs into allips.
 | 
			
		||||
    %allips = (%allips, %allbmcips, %allinstallips);
 | 
			
		||||
 | 
			
		||||
    #my $recordsref = xCAT::PCMNodeMgmtUtils->get_allnode_singleattrib_hash('rack', 'rackname');
 | 
			
		||||
    #%allracks = %$recordsref;
 | 
			
		||||
    #my $recordsref =  xCAT::PCMNodeMgmtUtils->get_allchassis(1);
 | 
			
		||||
    #%allchassis = %$recordsref;
 | 
			
		||||
 | 
			
		||||
    # Generate temporary hostnames for hosts entries in hostfile. 
 | 
			
		||||
    xCAT::MsgUtils->message('S', "[PCM nodes mgmt]Generate temporary hostnames.\n");
 | 
			
		||||
    my ($retcode_read, $retstr_read) = read_and_generate_hostnames($args_dict{'file'});
 | 
			
		||||
    if ($retcode_read != 0){
 | 
			
		||||
        setrsp_errormsg($retstr_read);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    # Parse and validate the hostinfo string. The real hostnames will be generated here.
 | 
			
		||||
    xCAT::MsgUtils->message('S', "[PCM nodes mgmt]Parsing hostinfo string and validate it.\n");
 | 
			
		||||
    my ($hostinfo_dict_ref, $invalid_records_ref) = parse_hosts_string($retstr_read);
 | 
			
		||||
    my %hostinfo_dict = %$hostinfo_dict_ref;
 | 
			
		||||
    my @invalid_records = @$invalid_records_ref;
 | 
			
		||||
    if (@invalid_records){
 | 
			
		||||
        setrsp_invalidrecords(\@invalid_records);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    unless (%hostinfo_dict){
 | 
			
		||||
        setrsp_errormsg("No valid host records found in hostinfo file.");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    # Create the real hostinfo string in stanza file format.
 | 
			
		||||
    xCAT::MsgUtils->message('S', "[PCM nodes mgmt]Generating new hostinfo string.\n");
 | 
			
		||||
    my ($retcode_gen, $retstr_gen) = gen_new_hostinfo_string(\%hostinfo_dict);
 | 
			
		||||
    unless ($retcode_gen){
 | 
			
		||||
        setrsp_errormsg($retstr_gen);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    # call mkdef to create hosts and then call nodemgmt for node management plugins.
 | 
			
		||||
    xCAT::MsgUtils->message('S', "[PCM nodes mgmt]call mkdef to create pcm nodes.\n");
 | 
			
		||||
    $request_command->({command=>["mkdef"], stdin=>[$retstr_gen], arg=>['-z']});
 | 
			
		||||
 | 
			
		||||
    my @nodelist = keys %hostinfo_dict;
 | 
			
		||||
    xCAT::MsgUtils->message('S', "[PCM nodes mgmt]call nodemgmt plugins.\n");
 | 
			
		||||
    $request_command->({command=>["kitcmd_nodemgmt_add"], node=>\@nodelist});
 | 
			
		||||
    $request_command->({command=>["kitcmd_nodemgmt_finished"], node=>\@nodelist});
 | 
			
		||||
    setrsp_success(\@nodelist);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
=head3  removehost
 | 
			
		||||
 | 
			
		||||
    Description : Remove nodes.
 | 
			
		||||
    Arguments   : N/A
 | 
			
		||||
 | 
			
		||||
=cut
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------
 | 
			
		||||
sub removehost{
 | 
			
		||||
    my $nodes   = $request->{node};
 | 
			
		||||
    xCAT::MsgUtils->message('S', "[PCM nodes mgmt]Remove PCM nodes.\n");
 | 
			
		||||
    # For remove nodes, we should call 'nodemgmt' in front of 'noderm'
 | 
			
		||||
    xCAT::MsgUtils->message('S', "[PCM nodes mgmt]call nodemgmt plugins.\n");
 | 
			
		||||
    $request_command->({command=>["kitcmd_nodemgmt_remove"], node=>$nodes});
 | 
			
		||||
    $request_command->({command=>["kitcmd_nodemgmt_finished"], node=>$nodes});
 | 
			
		||||
    xCAT::MsgUtils->message('S', "[PCM nodes mgmt]call noderm to remove nodes.\n");
 | 
			
		||||
    $request_command->({command=>["noderm"], node=>$nodes});
 | 
			
		||||
    setrsp_success($nodes);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
=head3  updatehost
 | 
			
		||||
 | 
			
		||||
    Description : Update host profiles.
 | 
			
		||||
    Arguments   : N/A
 | 
			
		||||
 | 
			
		||||
=cut
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------
 | 
			
		||||
sub updatehost{
 | 
			
		||||
    my $nodes   = $request->{node};
 | 
			
		||||
    my %updated_groups;
 | 
			
		||||
 | 
			
		||||
    xCAT::MsgUtils->message('S', "[PCM nodes mgmt]Update PCM nodes settings.\n");
 | 
			
		||||
    # Parse arges.
 | 
			
		||||
    my $retstr = parse_args();
 | 
			
		||||
    if ($retstr){
 | 
			
		||||
        setrsp_errormsg($retstr);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    # Make sure the specified parameters are valid ones.
 | 
			
		||||
    # TODO: support privisioning template.
 | 
			
		||||
    my @enabledparams = ('networkprofile', 'hardwareprofile', 'imageprofile');
 | 
			
		||||
    foreach my $argname (keys %args_dict){
 | 
			
		||||
        if (! grep{ $_ eq $argname} @enabledparams){
 | 
			
		||||
            setrsp_errormsg("Illegal attribute $argname specified.");
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    # Get current templates for all nodes.
 | 
			
		||||
    xCAT::MsgUtils->message('S', "[PCM nodes mgmt]Read database to get groups for all nodes.\n");
 | 
			
		||||
    my %groupdict;
 | 
			
		||||
    my $nodelstab = xCAT::Table->new('nodelist');
 | 
			
		||||
    my $nodeshashref = $nodelstab->getNodesAttribs($nodes, ['groups']);
 | 
			
		||||
    my %nodeshash = %$nodeshashref;
 | 
			
		||||
    my %updatenodeshash;
 | 
			
		||||
    foreach (keys %nodeshash){
 | 
			
		||||
        my @groups;
 | 
			
		||||
        my $attrshashref = $nodeshash{$_}[0];
 | 
			
		||||
        my %attrshash = %$attrshashref;
 | 
			
		||||
        if ($attrshash{'groups'}){
 | 
			
		||||
            @groups = split(/,/, $attrshash{'groups'});
 | 
			
		||||
 | 
			
		||||
            my $groupsref;
 | 
			
		||||
            # Replace the old template name with new specified ones in args_dict
 | 
			
		||||
            if(exists $args_dict{'networkprofile'}){
 | 
			
		||||
                $groupsref = replace_item_in_array(\@groups, "NetworkProfile", $args_dict{'networkprofile'});
 | 
			
		||||
            }
 | 
			
		||||
            if(exists $args_dict{'hardwareprofile'}){
 | 
			
		||||
                $groupsref = replace_item_in_array(\@groups, "HardwareProfile", $args_dict{'hardwareprofile'});
 | 
			
		||||
            }
 | 
			
		||||
            if(exists $args_dict{'imageprofile'}){
 | 
			
		||||
                $groupsref = replace_item_in_array(\@groups, "ImageProfile", $args_dict{'imageprofile'});
 | 
			
		||||
            }
 | 
			
		||||
            $updatenodeshash{$_}{'groups'} = join (',', @$groupsref);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    #update DataBase.
 | 
			
		||||
    xCAT::MsgUtils->message('S', "[PCM nodes mgmt]Update database records.\n");
 | 
			
		||||
    my $nodetab = xCAT::Table->new('nodelist',-create=>1);
 | 
			
		||||
    $nodetab->setNodesAttribs(\%updatenodeshash);
 | 
			
		||||
    $nodetab->close();
 | 
			
		||||
    
 | 
			
		||||
    # call plugins
 | 
			
		||||
    xCAT::MsgUtils->message('S', "[PCM nodes mgmt]call nodemgmt plugins.\n");
 | 
			
		||||
    $request_command->({command=>["kitcmd_nodemgmt_update"], node=>$nodes});
 | 
			
		||||
    $request_command->({command=>["kitcmd_nodemgmt_finished"], node=>$nodes});
 | 
			
		||||
    setrsp_success($nodes);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
=head3  replace_item_in_array
 | 
			
		||||
 | 
			
		||||
    Description : Replace an item in a list with new value. This item should match specified pattern.
 | 
			
		||||
    Arguments   : arrayref - the list.
 | 
			
		||||
                  pattern - the pattern which the old item must match.
 | 
			
		||||
                  newitem - the updated value.
 | 
			
		||||
=cut
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------
 | 
			
		||||
sub replace_item_in_array{
 | 
			
		||||
    my $arrayref = shift;
 | 
			
		||||
    my $pattern = shift;
 | 
			
		||||
    my $newitem = shift;
 | 
			
		||||
 | 
			
		||||
    my @newarray;
 | 
			
		||||
    foreach (@$arrayref){
 | 
			
		||||
        if ($_ =~ /__$pattern/){
 | 
			
		||||
            next;
 | 
			
		||||
        }
 | 
			
		||||
        push (@newarray, $_);
 | 
			
		||||
    }
 | 
			
		||||
    push(@newarray, $newitem);
 | 
			
		||||
    return \@newarray;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
=head3  gen_new_hostinfo_string
 | 
			
		||||
 | 
			
		||||
    Description : Generate a stanza file format string used for 'mkdef' to create nodes.
 | 
			
		||||
    Arguments   : hostinfo_dict_ref - The reference of hostinfo dict.
 | 
			
		||||
    Returns     : (returnvalue, returnmsg)
 | 
			
		||||
                  returnvalue - 0, stands for generate new hostinfo string failed.
 | 
			
		||||
                                1, stands for generate new hostinfo string OK.
 | 
			
		||||
                  returnnmsg -  error messages if generate failed.
 | 
			
		||||
                             - the new hostinfo string if generate OK.
 | 
			
		||||
=cut
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------
 | 
			
		||||
sub gen_new_hostinfo_string{
 | 
			
		||||
    my $hostinfo_dict_ref = shift;
 | 
			
		||||
    my %hostinfo_dict = %$hostinfo_dict_ref;
 | 
			
		||||
 | 
			
		||||
    # Get free ips list for all networks in network profile.
 | 
			
		||||
    my @allknownips = keys %allips;
 | 
			
		||||
    my $netprofileattrsref = xCAT::PCMNodeMgmtUtils->get_netprofile_nic_attrs($args_dict{'networkprofile'});
 | 
			
		||||
    my %netprofileattr = %$netprofileattrsref;
 | 
			
		||||
    my %freeipshash;
 | 
			
		||||
    foreach (keys %netprofileattr){
 | 
			
		||||
        my $netname = $netprofileattr{$_}{'network'};
 | 
			
		||||
        if($netname and (! exists $freeipshash{$netname})) {
 | 
			
		||||
            $freeipshash{$netname} = xCAT::PCMNodeMgmtUtils->get_allocable_staticips_innet($netname, \@allknownips);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    # Get networkprofile's installip
 | 
			
		||||
    my $noderestab = xCAT::Table->new('noderes');
 | 
			
		||||
    my $networkprofile = $args_dict{'networkprofile'};
 | 
			
		||||
    my $nodereshashref = $noderestab->getNodeAttribs($networkprofile, ['installnic']);
 | 
			
		||||
    my %nodereshash = %$nodereshashref;
 | 
			
		||||
    my $installnic = $nodereshash{'installnic'};
 | 
			
		||||
 | 
			
		||||
    # Get node's provisioning method
 | 
			
		||||
    my $provmethod = xCAT::PCMNodeMgmtUtils->get_imageprofile_prov_method($args_dict{'imageprofile'});
 | 
			
		||||
 | 
			
		||||
    # compose the stanza string for hostinfo file.
 | 
			
		||||
    my $hostsinfostr = "";
 | 
			
		||||
    foreach my $item (keys %hostinfo_dict){
 | 
			
		||||
        # Generate IPs for all interfaces.
 | 
			
		||||
        my %ipshash;
 | 
			
		||||
        foreach (keys %netprofileattr){
 | 
			
		||||
            my $netname = $netprofileattr{$_}{'network'};
 | 
			
		||||
            my $freeipsref;
 | 
			
		||||
            if ($netname){
 | 
			
		||||
                $freeipsref = $freeipshash{$netname};
 | 
			
		||||
            }
 | 
			
		||||
            my $nextip = shift @$freeipsref;
 | 
			
		||||
            if (!$nextip){
 | 
			
		||||
                return 0, "No sufficient IP address in network $netname for interface $_";
 | 
			
		||||
            }else{
 | 
			
		||||
                $ipshash{$_} = $nextip;
 | 
			
		||||
                $allips{$nextip} = 0;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        my $nicips = "";
 | 
			
		||||
        foreach(keys %ipshash){ 
 | 
			
		||||
            $nicips = "$_:$ipshash{$_},$nicips";
 | 
			
		||||
        }
 | 
			
		||||
        $hostinfo_dict{$item}{"nicips"} = $nicips;
 | 
			
		||||
 | 
			
		||||
        # Generate IP address if no IP specified.
 | 
			
		||||
        if (! exists $hostinfo_dict{$item}{"ip"}) {
 | 
			
		||||
            if (exists $ipshash{$installnic}){
 | 
			
		||||
                $hostinfo_dict{$item}{"ip"} = $ipshash{$installnic};
 | 
			
		||||
            }else{
 | 
			
		||||
                return 0, "No sufficient IP address for interface $installnic";
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        $hostinfo_dict{$item}{"objtype"} = "node";
 | 
			
		||||
        $hostinfo_dict{$item}{"groups"} = "__Managed";
 | 
			
		||||
        if (exists $args_dict{'networkprofile'}){$hostinfo_dict{$item}{"groups"} .= ",".$args_dict{'networkprofile'}}
 | 
			
		||||
        if (exists $args_dict{'imageprofile'}){$hostinfo_dict{$item}{"groups"} .= ",".$args_dict{'imageprofile'}}
 | 
			
		||||
        if (exists $args_dict{'hardwareprofile'}){$hostinfo_dict{$item}{"groups"} .= ",".$args_dict{'hardwareprofile'}}
 | 
			
		||||
        
 | 
			
		||||
        # Update BMC records.
 | 
			
		||||
        if (exists $netprofileattr{"bmc"}){
 | 
			
		||||
            $hostinfo_dict{$item}{"mgt"} = "ipmi";
 | 
			
		||||
            $hostinfo_dict{$item}{"chain"} = 'runcmd=bmcsetup,'.$provmethod;
 | 
			
		||||
 | 
			
		||||
            if (exists $ipshash{"bmc"}){
 | 
			
		||||
                $hostinfo_dict{$item}{"bmc"} = $ipshash{"bmc"};
 | 
			
		||||
            } else{
 | 
			
		||||
                return 0, "No sufficient IP addresses for BMC";
 | 
			
		||||
            }
 | 
			
		||||
        } else{
 | 
			
		||||
            $hostinfo_dict{$item}{"chain"} = $provmethod;
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
        # Generate the hostinfo string.
 | 
			
		||||
        $hostsinfostr = "$hostsinfostr$item:\n";
 | 
			
		||||
        my $itemdictref = $hostinfo_dict{$item};
 | 
			
		||||
        my %itemdict = %$itemdictref;
 | 
			
		||||
        foreach (keys %itemdict){
 | 
			
		||||
            $hostsinfostr = "$hostsinfostr  $_=\"$itemdict{$_}\"\n";
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return 1, $hostsinfostr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
=head3  read_and_generate_hostnames
 | 
			
		||||
 | 
			
		||||
    Description : Read hostinfo file and generate temporary hostnames for no-hostname specified ones.
 | 
			
		||||
    Arguments   : hostfile - the location of hostinfo file.
 | 
			
		||||
    Returns     : (returnvalue, returnmsg)
 | 
			
		||||
                  returnvalue - 0, stands for a failed return
 | 
			
		||||
                                1, stands for a success return
 | 
			
		||||
                  returnnmsg -  error messages for failed return.
 | 
			
		||||
                             -  the contents of the hostinfo string.
 | 
			
		||||
=cut
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------
 | 
			
		||||
sub read_and_generate_hostnames{
 | 
			
		||||
    my $hostfile = shift;
 | 
			
		||||
 | 
			
		||||
    # Get 10000 temprary hostnames.
 | 
			
		||||
    my $freehostnamesref = xCAT::PCMNodeMgmtUtils->gen_numric_hostnames("TMPHOSTS","", 4);
 | 
			
		||||
    # Auto generate hostnames for "__hostname__" entries.
 | 
			
		||||
    open(HOSTFILE, $hostfile);
 | 
			
		||||
    my $filecontent = join("", <HOSTFILE>); 
 | 
			
		||||
    while ((index $filecontent, "__hostname__:") >= 0){
 | 
			
		||||
    	my $nexthost = shift @$freehostnamesref;
 | 
			
		||||
    	# no more valid hostnames to assign.
 | 
			
		||||
    	if (! $nexthost){
 | 
			
		||||
            return 1, "Can not generate hostname automatically: No more valid hostnames available .";
 | 
			
		||||
    	}
 | 
			
		||||
    	# This hostname already specified in hostinfo file.
 | 
			
		||||
    	if ((index $filecontent, "$nexthost:") >= 0){
 | 
			
		||||
            next;
 | 
			
		||||
    	}
 | 
			
		||||
        # This hostname should not in database.
 | 
			
		||||
        if (exists $allhostnames{$nexthost}){
 | 
			
		||||
            next;
 | 
			
		||||
        }
 | 
			
		||||
    	$filecontent =~ s/__hostname__/$nexthost/;
 | 
			
		||||
    }
 | 
			
		||||
    close(HOSTFILE);
 | 
			
		||||
    return 0, $filecontent;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
=head3  parse_hosts_string
 | 
			
		||||
    
 | 
			
		||||
    Description : Parse the hostinfo string and validate it.
 | 
			
		||||
    Arguments   : filecontent - The content of hostinfo file.
 | 
			
		||||
    Returns     : (hostinfo_dict, invalid_records)
 | 
			
		||||
                  hostinfo_dict -  Reference of hostinfo dict. Key are hostnames and values is an attributes dict.
 | 
			
		||||
                  invalid_records - Reference of invalid records list.
 | 
			
		||||
=cut    
 | 
			
		||||
        
 | 
			
		||||
#-------------------------------------------------------
 | 
			
		||||
sub parse_hosts_string{
 | 
			
		||||
    my $filecontent = shift;
 | 
			
		||||
    my %hostinfo_dict;
 | 
			
		||||
    my @invalid_records;
 | 
			
		||||
 | 
			
		||||
    my $nicstab = xCAT::Table->new('nics');
 | 
			
		||||
    my $nodehashref = $nicstab->getNodeAttribs($args_dict{'networkprofile'}, ['hostnameformat']);
 | 
			
		||||
    my $nameformat = $nodehashref->{'hostnameformat'};
 | 
			
		||||
 | 
			
		||||
    my $nameformattype = xCAT::PCMNodeMgmtUtils->get_hostname_format_type($nameformat);
 | 
			
		||||
    my %freehostnames;
 | 
			
		||||
 | 
			
		||||
    # Parse hostinfo file string.
 | 
			
		||||
    xCAT::DBobjUtils->readFileInput($filecontent);
 | 
			
		||||
 | 
			
		||||
    # Record duplicated items.
 | 
			
		||||
    # We should go through list @::fileobjnames first as  %::FILEATTRS is just a hash, 
 | 
			
		||||
    # it not tells whether there are some duplicated hostnames in the hostinfo string.
 | 
			
		||||
    my %hostnamedict;
 | 
			
		||||
    foreach my $hostname (@::fileobjnames){
 | 
			
		||||
        if (exists $hostnamedict{$hostname}){
 | 
			
		||||
            push @invalid_records, [$hostname, "Duplicated hostname defined"];
 | 
			
		||||
        } else{
 | 
			
		||||
            $hostnamedict{$hostname} = 0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    # Verify each node entry.
 | 
			
		||||
    foreach (keys %::FILEATTRS){
 | 
			
		||||
        my $errmsg = validate_node_entry($_, $::FILEATTRS{$_});
 | 
			
		||||
        if ($errmsg) {
 | 
			
		||||
            if ($_=~ /^TMPHOSTS/){
 | 
			
		||||
                push @invalid_records, ["__hostname__", $errmsg];
 | 
			
		||||
            } else{
 | 
			
		||||
                push @invalid_records, [$_, $errmsg];
 | 
			
		||||
            }
 | 
			
		||||
            next;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        # We need generate hostnames for this entry.
 | 
			
		||||
        if ($_=~ /^TMPHOSTS/)
 | 
			
		||||
        {
 | 
			
		||||
            # rack + numric hostname format, we must specify rack in node's definition.
 | 
			
		||||
            my $numricformat;
 | 
			
		||||
            # Need convert hostname format into numric format first.
 | 
			
		||||
            if ($nameformattype eq "rack"){
 | 
			
		||||
                if (! exists $::FILEATTRS{$_}{"rack"}){
 | 
			
		||||
                    push @invalid_records, ["__hostname__", "No rack info specified. Do specify it because the nameformat contains rack info."];
 | 
			
		||||
                    next;
 | 
			
		||||
                }
 | 
			
		||||
                $numricformat = xCAT::PCMNodeMgmtUtils->rackformat_to_numricformat($nameformat, $::FILEATTRS{$_}{"rack"});
 | 
			
		||||
            } else{
 | 
			
		||||
                # pure numric hostname format
 | 
			
		||||
                $numricformat = $nameformat;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            # Generate hostnames based on numric hostname format.
 | 
			
		||||
            if (! exists $freehostnames{$numricformat}){
 | 
			
		||||
                $freehostnames{$numricformat} = xCAT::PCMNodeMgmtUtils->genhosts_with_numric_tmpl($numricformat);
 | 
			
		||||
            }
 | 
			
		||||
            my $hostnamelistref = $freehostnames{$numricformat};
 | 
			
		||||
            my $nexthostname = shift @$hostnamelistref;
 | 
			
		||||
            while (exists $allhostnames{$nexthostname}){
 | 
			
		||||
                $nexthostname = shift @$hostnamelistref;
 | 
			
		||||
            }
 | 
			
		||||
            $hostinfo_dict{$nexthostname} = $::FILEATTRS{$_};
 | 
			
		||||
        } else{
 | 
			
		||||
            $hostinfo_dict{$_} = $::FILEATTRS{$_};
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return (\%hostinfo_dict, \@invalid_records);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
=head3  validate_node_entry
 | 
			
		||||
    
 | 
			
		||||
    Description : Validate a node info hash.
 | 
			
		||||
    Arguments   : node_name - node hostname.
 | 
			
		||||
                  node_entry_ref - Reference of the node info hash.
 | 
			
		||||
    Returns     : errormsg
 | 
			
		||||
                      - undef: stands for no errror.
 | 
			
		||||
                      - valid string: stands for the error message of validation.    
 | 
			
		||||
=cut
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------
 | 
			
		||||
sub validate_node_entry{
 | 
			
		||||
    my $node_name = shift;
 | 
			
		||||
    my $node_entry_ref = shift;
 | 
			
		||||
    my %node_entry = %$node_entry_ref;
 | 
			
		||||
 | 
			
		||||
    # duplicate hostname found in hostinfo file.
 | 
			
		||||
    if (exists $allhostnames{$node_name}) {
 | 
			
		||||
        return "Specified hostname $node_name conflicts with database records.";
 | 
			
		||||
    }
 | 
			
		||||
    # Must specify either MAC or switch + port.
 | 
			
		||||
    if (exists $node_entry{"mac"} || 
 | 
			
		||||
        exists $node_entry{"switch"} && exists $node_entry{"port"}){
 | 
			
		||||
    } else{
 | 
			
		||||
        return "Neither MAC nor switch + port specified";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (! xCAT::NetworkUtils->isValidHostname($node_name)){
 | 
			
		||||
        return "Specified hostname: $node_name is invalid";
 | 
			
		||||
    }
 | 
			
		||||
    # validate each single value.
 | 
			
		||||
    foreach (keys %node_entry){
 | 
			
		||||
        if ($_ eq "mac"){
 | 
			
		||||
            if (exists $allmacs{$node_entry{$_}}){
 | 
			
		||||
                return "Specified MAC address $node_entry{$_} conflicts with MACs in database or hostinfo file";
 | 
			
		||||
            }elsif(! xCAT::NetworkUtils->isValidMAC($node_entry{$_})){
 | 
			
		||||
                return "Specified MAC address $node_entry{$_} is invalid";
 | 
			
		||||
            }else{
 | 
			
		||||
                $allmacs{$node_entry{$_}} = 0;
 | 
			
		||||
            }
 | 
			
		||||
        }elsif ($_ eq "ip"){
 | 
			
		||||
            if (exists $allips{$node_entry{$_}}){
 | 
			
		||||
                return "Specified IP address $node_entry{$_} conflicts with IPs in database or hostinfo file";
 | 
			
		||||
            }elsif((xCAT::NetworkUtils->validate_ip($node_entry{$_}))[0][0] ){
 | 
			
		||||
                return "Specified IP address $node_entry{$_} is invalid";
 | 
			
		||||
            }elsif(xCAT::NetworkUtils->isReservedIP($node_entry{$_})){
 | 
			
		||||
                return "Specified IP address $node_entry{$_} is invalid";
 | 
			
		||||
            }else {
 | 
			
		||||
                #push the IP into allips list.
 | 
			
		||||
                $allips{$node_entry{$_}} = 0;
 | 
			
		||||
            }
 | 
			
		||||
        }elsif ($_ eq "switch"){
 | 
			
		||||
            #TODO: xCAT switch discovery enhance: verify whether switch exists.
 | 
			
		||||
        }elsif ($_ eq "port"){
 | 
			
		||||
            #TODO: xCAT switch discovery enhance: verify whether port exists.
 | 
			
		||||
        }elsif ($_ eq "rack"){
 | 
			
		||||
            if (not exists $allracks{$node_entry{$_}}){
 | 
			
		||||
                return "Specified rack $node_entry{$_} not defined";
 | 
			
		||||
            }
 | 
			
		||||
        }elsif ($_ eq "chassis"){
 | 
			
		||||
            if (not exists $allchassis{$node_entry{$_}}){
 | 
			
		||||
                return "Specified chassis $node_entry{$_} not defined";
 | 
			
		||||
            }
 | 
			
		||||
        }elsif ($_ eq "unit"){
 | 
			
		||||
            # Not a valid number.
 | 
			
		||||
            if (!($node_entry{$_} =~ /^\d+$/)){
 | 
			
		||||
                return "Specified unit $node_entry{$_} is a invalid number";
 | 
			
		||||
            }
 | 
			
		||||
        }elsif ($_ eq "height"){
 | 
			
		||||
            # Not a valid number.
 | 
			
		||||
            if (!($node_entry{$_} =~ /^\d+$/)){
 | 
			
		||||
                return "Specified height $node_entry{$_} is a invalid number";
 | 
			
		||||
            }
 | 
			
		||||
        }else{
 | 
			
		||||
           return "Invalid attribute $_ specified";
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    # For blades, don't support specify unit and height.
 | 
			
		||||
    if(exists $node_entry{"chassis"} ){
 | 
			
		||||
        if(exists $node_entry{"unit"}){
 | 
			
		||||
            return "Can not specify 'unit' together with 'chassis'";
 | 
			
		||||
        }
 | 
			
		||||
        if(exists $node_entry{"height"}){
 | 
			
		||||
            return "can not specify 'height' together with 'chassis'";
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    # push hostinfo into global dicts.
 | 
			
		||||
    $allhostnames{$node_name} = 0;
 | 
			
		||||
    return undef;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
=head3  setrsp_invalidrecords
 | 
			
		||||
    
 | 
			
		||||
    Description : Set response for processing invalid host records.
 | 
			
		||||
    Arguments   : recordsref - Refrence of invalid nodes list.
 | 
			
		||||
 | 
			
		||||
=cut
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------
 | 
			
		||||
sub setrsp_invalidrecords
 | 
			
		||||
{
 | 
			
		||||
    my $recordsref =  shift;
 | 
			
		||||
    my $rsp;
 | 
			
		||||
    my $master=xCAT::TableUtils->get_site_Master();
 | 
			
		||||
    
 | 
			
		||||
    # The total number of invalid records.
 | 
			
		||||
    $rsp->{invalid_records_num} = scalar @$recordsref;
 | 
			
		||||
 | 
			
		||||
    # We write details of invalid records into a file.
 | 
			
		||||
    my ($fh, $filename) = xCAT::PCMNodeMgmtUtils->get_output_filename();
 | 
			
		||||
    foreach (@$recordsref){
 | 
			
		||||
    	my @erroritem = @$_;
 | 
			
		||||
        print $fh "nodename $erroritem[0], error: $erroritem[1]\n";
 | 
			
		||||
    }
 | 
			
		||||
    close $fh;
 | 
			
		||||
    # Tells the URL of the details file.
 | 
			
		||||
    xCAT::MsgUtils->message('S', "Detailed response info placed in file: http://$master/$filename\n");
 | 
			
		||||
    $rsp->{details} = "http://$master/$filename";
 | 
			
		||||
    $callback->($rsp);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
=head3  setrsp_errormsg
 | 
			
		||||
    
 | 
			
		||||
    Description : Set response for error messages.
 | 
			
		||||
    Arguments   : errormsg - Error messages.
 | 
			
		||||
 | 
			
		||||
=cut
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------
 | 
			
		||||
sub setrsp_errormsg
 | 
			
		||||
{
 | 
			
		||||
    my $errormsg = shift;
 | 
			
		||||
    my $rsp;
 | 
			
		||||
    xCAT::MsgUtils->message('S', "$errormsg\n");
 | 
			
		||||
    $rsp->{error}->[0] = $errormsg;
 | 
			
		||||
    $callback->($rsp);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------
 | 
			
		||||
 | 
			
		||||
=head3  setrsp_success
 | 
			
		||||
    
 | 
			
		||||
    Description : Set response for successfully processed nodes.
 | 
			
		||||
    Arguments   : recordsref - Refrence of nodes list.
 | 
			
		||||
 | 
			
		||||
=cut
 | 
			
		||||
 | 
			
		||||
#-------------------------------------------------------
 | 
			
		||||
sub setrsp_success
 | 
			
		||||
{
 | 
			
		||||
    my $recordsref = shift;
 | 
			
		||||
    my $rsp;
 | 
			
		||||
    my $master=xCAT::TableUtils->get_site_Master();
 | 
			
		||||
    
 | 
			
		||||
    # The total number of success nodes.
 | 
			
		||||
    $rsp->{success_nodes_num} = scalar @$recordsref;
 | 
			
		||||
    my ($fh, $filename) = xCAT::PCMNodeMgmtUtils->get_output_filename();
 | 
			
		||||
    foreach (@$recordsref){
 | 
			
		||||
        print $fh "success: $_\n";
 | 
			
		||||
    }
 | 
			
		||||
    close $fh;
 | 
			
		||||
    # Tells the URL of the details file.
 | 
			
		||||
    xCAT::MsgUtils->message('S', "Detailed response info placed in file: http://$master/$filename\n");
 | 
			
		||||
    $rsp->{details} = "http://$master/$filename";
 | 
			
		||||
    $callback->($rsp);
 | 
			
		||||
}
 | 
			
		||||
1;
 | 
			
		||||
		Reference in New Issue
	
	Block a user