mirror of
				https://github.com/xcat2/xcat-core.git
				synced 2025-10-31 11:22:27 +00:00 
			
		
		
		
	implement discovery basic function
This commit is contained in:
		| @@ -5,7 +5,7 @@ package probe_utils; | ||||
| use strict; | ||||
| use File::Path; | ||||
| use File::Copy; | ||||
|  | ||||
| use Socket; | ||||
| #----------------------------------------- | ||||
|  | ||||
| =head3 | ||||
| @@ -341,4 +341,102 @@ sub is_dns_ready { | ||||
|     } | ||||
| } | ||||
|  | ||||
| #------------------------------------------ | ||||
|  | ||||
| =head3 | ||||
|     Description: | ||||
|         Convert host name to ip address  | ||||
|     Arguments: | ||||
|         hostname: The hostname need to convert  | ||||
|     Returns: | ||||
|         ip: The ip address  | ||||
| =cut | ||||
|  | ||||
| #------------------------------------------ | ||||
| sub get_ip_from_hostname{ | ||||
|     my $hostname = shift; | ||||
|     $hostname=shift if(($hostname) && ($hostname =~ /probe_utils/)); | ||||
|     my $ip = ""; | ||||
|  | ||||
|     my @output = `ping -c 1 $hostname 2>&1`; | ||||
|     if(!$?){ | ||||
|        if($output[0] =~ /^PING.+\s+\((\d+\.\d+\.\d+\.\d+)\).+/){ | ||||
|            $ip=$1; | ||||
|        } | ||||
|     } | ||||
|     return $ip; | ||||
| } | ||||
|  | ||||
| #------------------------------------------ | ||||
|  | ||||
| =head3 | ||||
|     Description: | ||||
|         Calculate network address from ip and netmask  | ||||
|     Arguments: | ||||
|         ip: ip address | ||||
|         mask: network mask | ||||
|     Returns: | ||||
|         network : The network address | ||||
| =cut | ||||
|  | ||||
| #------------------------------------------ | ||||
| sub get_network{ | ||||
|     my $ip = shift; | ||||
|     $ip=shift if(($ip) && ($ip =~ /probe_utils/)); | ||||
|     my $mask = shift; | ||||
|     my $net=""; | ||||
|  | ||||
|     return $net if (!is_ip_addr($ip)); | ||||
|     return $net if ($mask !~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/); | ||||
|  | ||||
|     my $bin_mask = 0; | ||||
|     $bin_mask = (($1 + 0) << 24) + (($2 + 0) << 16) + (($3 + 0) << 8) + ($4 + 0) if ($mask =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/); | ||||
|  | ||||
|     my $bin_ip = 0; | ||||
|     $bin_ip = (($1 + 0) << 24) + (($2 + 0) << 16) + (($3 + 0) << 8) + ($4 + 0) if ($ip =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/); | ||||
|  | ||||
|     my $net_int32 = $bin_mask & $bin_ip; | ||||
|     $net = ($net_int32 >> 24) . "." . (($net_int32 >> 16) & 0xff) . "." . (($net_int32 >> 8) & 0xff) . "." . ($net_int32 & 0xff); | ||||
|     return "$net/$mask"; | ||||
| } | ||||
|  | ||||
| #------------------------------------------ | ||||
|  | ||||
| =head3 | ||||
|     Description: | ||||
|         Convert ip to hostname  | ||||
|     Arguments: | ||||
|         ip: The ip need to convert | ||||
|     Returns: | ||||
|         hostname: hostname or ""  | ||||
| =cut | ||||
|  | ||||
| #------------------------------------------ | ||||
| sub get_hostname_from_ip{ | ||||
|     my  $ip = shift; | ||||
|     $ip=shift if(($ip) && ($ip =~ /probe_utils/)); | ||||
|     my $dns_server = shift; | ||||
|     my $hostname=""; | ||||
|     my $output=""; | ||||
|  | ||||
|     `which nslookup > /dev/null 2>&1`; | ||||
|     if(!$?){  | ||||
|         $output = `nslookup $ip  $dns_server 2>&1`; | ||||
|         if (!$?) { | ||||
|             chomp($output); | ||||
|             my $rc = $hostname = `echo "$output"|awk -F" " '/name =/ {print \$4}'|awk -F"." '{print \$1}'`; | ||||
|             chomp($hostname); | ||||
|             return $hostname if (!$rc); | ||||
|         }     | ||||
|     } | ||||
|     if(($hostname eq "") && (-e "/etc/hosts")){ | ||||
|         $output = `cat /etc/hosts 2>&1 |grep $ip`; | ||||
|         if(!$?){ | ||||
|             my @splitoutput = split(" ", $output); | ||||
|             $hostname = $splitoutput[1];  | ||||
|         } | ||||
|     } | ||||
|     return $hostname;  | ||||
| } | ||||
|  | ||||
| 1; | ||||
|   | ||||
| @@ -6,38 +6,71 @@ BEGIN { $::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : -d '/opt/xcat' ? '/o | ||||
| use lib "$::XCATROOT/probe/lib/perl"; | ||||
| use probe_utils; | ||||
| use File::Basename; | ||||
| use IO::Select; | ||||
| use Getopt::Long qw(:config no_ignore_case); | ||||
| use Data::Dumper; | ||||
|  | ||||
| my $program_name = basename("$0"); | ||||
| my $help; | ||||
| my $test; | ||||
| my $output  = "stdout"; | ||||
| my $verbose = 0; | ||||
| my $rst     = 0; | ||||
| my $output    = "stdout"; | ||||
| my $verbose   = 0; | ||||
| my $rst       = 0; | ||||
| my $pre_check = 0; | ||||
| my $monitor   = 0; | ||||
| my $discovery_type; | ||||
| my @valid_discovery_type = ("mtms", "switch"); | ||||
| my $valid_discovery_type_str = join(",", @valid_discovery_type); | ||||
| my $noderange; | ||||
| my $nics; | ||||
|  | ||||
| #used for discovery monitor | ||||
| my %rawdata; | ||||
| my %ipmacmap; | ||||
| my $terminal = 0; | ||||
| my %monitor_nodes; | ||||
|  | ||||
| $::USAGE = "Usage: | ||||
|     $program_name -h | ||||
|     $program_name -t | ||||
|     $program_name [-V] | ||||
|     $program_name -s | ||||
|     $program_name -p [-V] [-T <discovery_type>] [-n <node_range>]   | ||||
|     $program_name -m  | ||||
|     $program_name [-V] [-T <discovery_type>] [-n <node_range>] | ||||
|  | ||||
| Description: | ||||
|     Check discovery files or process.  | ||||
|     Do probe for discovery process, including pro-check for required configuration and realtime monitor of discovery process.  | ||||
|     If without any option, $program_name will do pro-check first, if all checking point pass, then goes to monitor directly. | ||||
|  | ||||
| Options: | ||||
|     -h : Get usage information of $program_name | ||||
|     -t : To verify if $program_name can work, reserve option for probe framework | ||||
|     -V : Output more information for debug | ||||
|     -s : Discovery static check, check whether genesis files are ready | ||||
|     -h : Get usage information of $program_name. | ||||
|     -t : To verify if $program_name can work, reserve option for probe framework. | ||||
|     -V : Output more information for debug. | ||||
|     -p : Do pre-check for disvoery, check whether required configuration have been done ahead. | ||||
|     -T : The type of discovery, the valid values are $valid_discovery_type_str. | ||||
|     -n : The range of predefined node, must used with option -m. | ||||
|     -m : Do realtime monitor for discovery process.  | ||||
| "; | ||||
|  | ||||
| #------------------------------------------ | ||||
|  | ||||
| =head3 | ||||
|     Description: | ||||
|         Check if all genesis files are available.  | ||||
|     Arguments: | ||||
|         arch: valid value are ppc64 and x86_64  | ||||
|     Returns: | ||||
|         0 : pass | ||||
|         1 : failed | ||||
| =cut | ||||
|  | ||||
| #------------------------------------------ | ||||
| sub check_genesis_file { | ||||
|     my $arch  = shift; | ||||
|     my $arch = shift; | ||||
|     if (($arch ne "ppc64") and ($arch ne "x86_64")) { | ||||
|         probe_utils->send_msg("$output", "f", "Please input correct arch type"); | ||||
|         probe_utils->send_msg("$output", "d", "Please input correct arch type") if ($verbose); | ||||
|         return 1; | ||||
|     } | ||||
|   | ||||
|  | ||||
|     my $rst_f = 0; | ||||
|     probe_utils->send_msg("$output", "d", "Start to check genesis files for $arch...") if ($verbose); | ||||
|  | ||||
| @@ -229,14 +262,669 @@ sub check_genesis_file { | ||||
|     return $rst_f; | ||||
| } | ||||
|  | ||||
| #------------------------------------------ | ||||
|  | ||||
| =head3 | ||||
|     Description: | ||||
|         1. check if there are dynamic range for specific networks defineded in dhcp conf file | ||||
|         2. check if these specific networks have corresponding genesis configuration  | ||||
|     Arguments: | ||||
|         networks: A Comma separated list of networks. Every network is combined by network address and mask(i.e. network/mask). | ||||
|         For example: 10.0.0.0/255.0.0.0,50.1.0.0/255.255.0.0 | ||||
|     Returns: | ||||
|         0 : pass | ||||
|         1 : failed | ||||
| =cut | ||||
|  | ||||
| #------------------------------------------ | ||||
| sub dhcp_dynamic_range_check { | ||||
|     my $nets = shift; | ||||
|     my $rst  = 0; | ||||
|  | ||||
|     return $rst; | ||||
| } | ||||
|  | ||||
| #------------------------------------------ | ||||
|  | ||||
| =head3 | ||||
|     Description: | ||||
|        Handle one line log come from tftp log file | ||||
|     Arguments: | ||||
|        msg: one line tftp log        | ||||
|     Returns: | ||||
|         0 : pass | ||||
|         1 : failed | ||||
| =cut | ||||
|  | ||||
| #------------------------------------------ | ||||
| sub handle_tftp_msg { | ||||
|     my $msg = shift; | ||||
|     if ($msg =~ /RRQ\s+from\s+(.+)\s+filename\s+(.+)/i) { | ||||
|         my $ip     = $1; | ||||
|         my $file   = $2; | ||||
|         my $record = "Via TFTP $ip download $file"; | ||||
|         probe_utils->send_msg("$output", "d", "$record"); | ||||
|         if (exists($rawdata{"$ipmacmap{$ip}"})) { | ||||
|  | ||||
|             #push(@{$rawdata{$ipmacmap{$ip}}{"history"}}, $record) unless (/^$record$/ ~~ @{$rawdata{$ipmacmap{$ip}}{"history"}}); | ||||
|             push(@{ $rawdata{ $ipmacmap{$ip} }{"history"} }, $record); | ||||
|         } | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| #------------------------------------------ | ||||
|  | ||||
| =head3 | ||||
|     Description: | ||||
|        Handle one line log come from http log file | ||||
|     Arguments: | ||||
|        msg: one line http log  | ||||
|     Returns: | ||||
|         0 : pass | ||||
|         1 : failed | ||||
| =cut | ||||
|  | ||||
| #------------------------------------------ | ||||
| sub handle_http_msg { | ||||
|     my $msg = shift; | ||||
|     if ($msg =~ /(\d+\.\d+.\d+.\d+)\s.+GET\s+(.+)\s+HTTP.+/) { | ||||
|         my $ip     = $1; | ||||
|         my $file   = $2; | ||||
|         my $record = "Via HTTP $ip download $file"; | ||||
|         probe_utils->send_msg("$output", "d", "$record"); | ||||
|         if (exists($rawdata{"$ipmacmap{$ip}"})) { | ||||
|             push(@{ $rawdata{ $ipmacmap{$ip} }{"history"} }, $record); | ||||
|         } | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| #------------------------------------------ | ||||
|  | ||||
| =head3 | ||||
|     Description: | ||||
|        Handle one line log come from dhcp log file | ||||
|     Arguments: | ||||
|        msg: one line http log | ||||
|        nics: target network interfaces | ||||
|     Returns: | ||||
|         0 : pass | ||||
|         1 : failed | ||||
| =cut | ||||
|  | ||||
| #------------------------------------------ | ||||
| sub handle_dhcp_msg { | ||||
|     my $msg      = shift; | ||||
|     my $nics     = shift; | ||||
|     my @nicarray = split(",", $nics); | ||||
|     if ($msg =~ /.+DHCPDISCOVER\s+from\s+(.+)\s+via\s+(.+)/i) { | ||||
|         my @tmpmsg = split(" ", $msg); | ||||
|         my $mac    = $tmpmsg[7]; | ||||
|         my $nic    = $tmpmsg[9]; | ||||
|         $nic =~ s/(.+):/$1/g if ($nic =~ /:$/); | ||||
|         return 0 unless (@nicarray ~~ /^$nic$/); | ||||
|         if ($msg =~ /no free leases/) { | ||||
|             probe_utils->send_msg("$output", "d", "Receive DHCPDISCOVER from $mac via $nic, no free leases"); | ||||
|             return 0; | ||||
|         } | ||||
|         my $record = "Receive DHCPDISCOVER from $mac via $nic"; | ||||
|         probe_utils->send_msg("$output", "d", "$record"); | ||||
|         if (!exists($rawdata{$mac})) { | ||||
|             my @history; | ||||
|             push(@history, $record); | ||||
|             $rawdata{$mac}{"history"} = \@history; | ||||
|         } else { | ||||
|             push(@{ $rawdata{$mac}{"history"} }, $record); | ||||
|         } | ||||
|     } elsif ($msg =~ /.+DHCPOFFER\s+on\s+(.+)\s+to\s+(.+)\s+via\s+(.+)/i) { | ||||
|         my $ip  = $1; | ||||
|         my $mac = $2; | ||||
|         my $nic = $3; | ||||
|         return 0 unless (@nicarray ~~ /^$nic$/); | ||||
|         my $record = "Send DHCPOFFER on $ip back to $mac via $nic"; | ||||
|         probe_utils->send_msg("$output", "d", "$record"); | ||||
|         if (exists($rawdata{$mac})) { | ||||
|             push(@{ $rawdata{$mac}{"history"} }, $record); | ||||
|         } | ||||
|     } elsif ($msg !~ /unknown lease/ && $msg !~ /ignored/ && $msg =~ /.+DHCPREQUEST\s+for\s+(.+)\s\((.+)\)\s+from\s+(.+)\s+via\s+(.+)/) { | ||||
|         my $ip     = $1; | ||||
|         my $server = $2; | ||||
|         my $mac    = $3; | ||||
|         my $nic    = $4; | ||||
|         return 0 unless (@nicarray ~~ /^$nic$/); | ||||
|         my $record = "Receive DHCPREQUEST from $mac for $ip via $nic"; | ||||
|         probe_utils->send_msg("$output", "d", "$record"); | ||||
|         if (exists($rawdata{$mac})) { | ||||
|             push(@{ $rawdata{$mac}{"history"} }, $record); | ||||
|         } | ||||
|     } elsif ($msg =~ /.+DHCPACK\s+on\s+(.+)\s+to\s+(.+)\s+via\s+(.+)/) { | ||||
|         my $ip  = $1; | ||||
|         my $mac = $2; | ||||
|         my $nic = $3; | ||||
|         return 0 unless (@nicarray ~~ /^$nic$/); | ||||
|         my $record = "Send DHCPACK on $ip back to $mac via $nic"; | ||||
|         probe_utils->send_msg("$output", "d", "$record"); | ||||
|         if (exists($rawdata{$mac})) { | ||||
|             $rawdata{$mac}{"ip"} = $ip; | ||||
|             push(@{ $rawdata{$mac}{"history"} }, $record); | ||||
|             $ipmacmap{$ip} = $mac; | ||||
|         } | ||||
|     } elsif ($msg =~ /.+BOOTREQUEST\s+from\s+(.+)\s+via\s+(.+)/) { | ||||
|         my @tmpmsg = split(" ", $msg); | ||||
|         my $mac    = $tmpmsg[7]; | ||||
|         my $nic    = $tmpmsg[9]; | ||||
|         $nic =~ s/(.+):/$1/g if ($nic =~ /:$/); | ||||
|         return 0 unless (@nicarray ~~ /^$nic$/); | ||||
|         if ($msg =~ /no dynamic leases/) { | ||||
|             probe_utils->send_msg("$output", "d", "Receive DHCPDISCOVER from $mac via $nic, no dynamic leases"); | ||||
|             return 0; | ||||
|         } | ||||
|         my $record = "Receive BOOTREQUEST from $mac via $nic"; | ||||
|         probe_utils->send_msg("$output", "d", "$record"); | ||||
|         if (!exists($rawdata{$mac})) { | ||||
|             my @history; | ||||
|             push(@history, $record); | ||||
|             $rawdata{$mac}{"history"} = \@history; | ||||
|         } else { | ||||
|             push(@{ $rawdata{$mac}{"history"} }, $record); | ||||
|         } | ||||
|     } elsif ($msg =~ /.+BOOTREPLY\s+for\s+(.+)\s+to\s+.+(\w\w:\w\w:\w\w:\w\w:\w\w:\w\w).+via\s+(.+)/) { | ||||
|         my $ip  = $1; | ||||
|         my $mac = $2; | ||||
|         my $nic = $3; | ||||
|         return 0 unless (@nicarray ~~ /^$nic$/); | ||||
|         my $record = "Send BOOTREPLY on $ip back to $mac via $nic"; | ||||
|         probe_utils->send_msg("$output", "d", "$record"); | ||||
|         if (exists($rawdata{$mac})) { | ||||
|             $rawdata{$mac}{"ip"} = $ip; | ||||
|             push(@{ $rawdata{$mac}{"history"} }, $record); | ||||
|             $ipmacmap{$ip} = $mac; | ||||
|         } | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| #------------------------------------------ | ||||
|  | ||||
| =head3 | ||||
|     Description: | ||||
|        Handle one line log come from computes.log  | ||||
|     Arguments: | ||||
|        msg: one line compute log | ||||
|     Returns: | ||||
|         0 : pass | ||||
|         1 : failed | ||||
| =cut | ||||
|  | ||||
| #------------------------------------------ | ||||
| sub handle_compute_msg { | ||||
|  | ||||
|     my $line   = shift; | ||||
|     my $sender = ""; | ||||
|     my $ip     = ""; | ||||
|     my $msg; | ||||
|  | ||||
|     my @splitline = split(" ", $line); | ||||
|     if (($splitline[4] =~ /^xcat/i) || ($splitline[5] =~ /^xcat/i)) { | ||||
|         $sender = $splitline[3]; | ||||
|         for (my $i = 0 ; $i < 5 ; $i++) { | ||||
|             shift(@splitline); | ||||
|         } | ||||
|         $msg = join(" ", @splitline); | ||||
|         if (!probe_utils->is_ip_addr("$sender")) { | ||||
|             $ip = probe_utils->get_ip_from_hostname("$sender"); | ||||
|         } else { | ||||
|             $ip = $sender; | ||||
|         } | ||||
|         if ($ip ne "" && exists($ipmacmap{$ip})) { | ||||
|             my $record = "Recv from $ipmacmap{$ip}($ip) : $msg"; | ||||
|             probe_utils->send_msg("$output", "d", "$record"); | ||||
|             push(@{ $rawdata{ $ipmacmap{$ip} }{"history"} }, $record); | ||||
|         } | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| #------------------------------------------ | ||||
|  | ||||
| =head3 | ||||
|     Description: | ||||
|        Handle one line log come from cluster.log  | ||||
|     Arguments: | ||||
|        msg: one line log | ||||
|     Returns: | ||||
|         0 : pass | ||||
|         1 : failed | ||||
| =cut | ||||
|  | ||||
| #------------------------------------------ | ||||
| sub handle_cluster_msg { | ||||
|     my $line   = shift; | ||||
|     my $sender = ""; | ||||
|     my $ip     = ""; | ||||
|     my $msg; | ||||
|  | ||||
|     if ($line =~ /.+\d+:\d+:\d+\s+(.+)\s+(xcat.+)/i) { | ||||
|         $sender = $1; | ||||
|         $msg    = $2; | ||||
|         if (!probe_utils->is_ip_addr("$sender")) { | ||||
|             $ip = probe_utils->get_ip_from_hostname("$sender"); | ||||
|         } else { | ||||
|             $ip = $sender; | ||||
|         } | ||||
|         if ($ip ne "" && exists($ipmacmap{$ip})) { | ||||
|             my $record = "Recv from $ipmacmap{$ip}($ip) : $msg"; | ||||
|             probe_utils->send_msg("$output", "d", "$record"); | ||||
|             push(@{ $rawdata{ $ipmacmap{$ip} }{"history"} }, $record); | ||||
|         } | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| #------------------------------------------ | ||||
|  | ||||
| =head3 | ||||
|     Description: | ||||
|        Dump monitor history,  categorised by mac address. | ||||
|     Arguments: | ||||
|        NULL | ||||
|     Returns: | ||||
| =cut | ||||
|  | ||||
| #------------------------------------------ | ||||
| sub dump_history { | ||||
|     probe_utils->send_msg("$output", "d", "======================================="); | ||||
|     probe_utils->send_msg("$output", "d", "=  The summary of discovery:"); | ||||
|     probe_utils->send_msg("$output", "d", "======================================="); | ||||
|  | ||||
|     my $masterip = `tabdump site 2>&1 | awk -F',' '/master/ { gsub(/"/, "", \$2) ; print \$2 }'`; | ||||
|     chomp($masterip); | ||||
|     foreach $mac (keys %rawdata) { | ||||
|         my $nodehostname = probe_utils->get_hostname_from_ip($rawdata{$mac}{"ip"}, $masterip); | ||||
|         if ($nodehostname ne "") { | ||||
|             probe_utils->send_msg("$output", "d", "[$mac ($nodehostname)]"); | ||||
|         } else { | ||||
|             probe_utils->send_msg("$output", "d", "[$mac]:"); | ||||
|         } | ||||
|         foreach my $line (@{ $rawdata{$mac}{"history"} }) { | ||||
|             probe_utils->send_msg("$output", "d", "|    $line"); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| #------------------------------------------ | ||||
|  | ||||
| =head3 | ||||
|     Description: | ||||
|        Check if all predefined node are valid | ||||
|     Arguments: | ||||
|        discovery_type: valid value are mtms and switch  | ||||
|        noderange: node range | ||||
|     Returns: | ||||
|        0: pass | ||||
|        1: failed | ||||
| =cut | ||||
|  | ||||
| #------------------------------------------ | ||||
| sub check_pre_defined_node { | ||||
|     my $discovery_type = shift; | ||||
|     my $noderange      = shift; | ||||
|  | ||||
|     my $rst = 0; | ||||
|     my @cmdoutput; | ||||
|     my %nodecheckrst; | ||||
|     my $currentnode = ""; | ||||
|  | ||||
|     @cmdoutput = `lsdef $noderange 2>&1`; | ||||
|     foreach (@cmdoutput) { | ||||
|         if ($_ =~ /^Error: Could not find an object named '(\w+)' .+/i) { | ||||
|             $currentnode = $1; | ||||
|             $nodecheckrst{$currentnode}{"error"} = "Could not find node definition"; | ||||
|             $rst = 1; | ||||
|         } elsif ($_ =~ /^\s*Object name: (\w+)/i) { | ||||
|             $currentnode = $1; | ||||
|         } elsif ($_ =~ /^\s+(\w+)\s*=\s*(\w+)/) { | ||||
|             $nodecheckrst{$currentnode}{$1} = $2; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     #print Dumper(%nodecheckrst); | ||||
|  | ||||
|     foreach my $node (keys %nodecheckrst) { | ||||
|         if (!exists($nodecheckrst{$node}{error})) { | ||||
|             if ($discovery_type eq "mtms") { | ||||
|                 if (exists($nodecheckrst{$node}{"mtm"}) && exists($nodecheckrst{$node}{"serial"})) { | ||||
|                     $nodecheckrst{$node}{"error"} = "node definition is good for '$discovery_type' type discovery"; | ||||
|                 } else { | ||||
|                     $nodecheckrst{$node}{"error"} = "node definition is wrong for '$discovery_type' type discovery"; | ||||
|                     $rst = 1; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             if ($discovery_type eq "switch") { | ||||
|                 if (exists($nodecheckrst{$node}{"switch"}) && exists($nodecheckrst{$node}{"switchport"})) { | ||||
|                     $nodecheckrst{$node}{"error"} = "node definition is good for '$discovery_type' type discovery"; | ||||
|                 } else { | ||||
|                     $nodecheckrst{$node}{"error"} = "node definition is wrong for '$discovery_type' type discovery"; | ||||
|                     $rst = 1; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     if ($verbose) { | ||||
|         foreach my $node (keys %nodecheckrst) { | ||||
|             probe_utils->send_msg("$output", "d", "$node : $nodecheckrst{$node}{error}"); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return $rst; | ||||
| } | ||||
|  | ||||
| #------------------------------------------ | ||||
|  | ||||
| =head3 | ||||
|     Description: | ||||
|        Get monitor nodes list  | ||||
|     Arguments: | ||||
|        One golble attribute %monitor_nodes; | ||||
|     Returns: | ||||
| =cut | ||||
|  | ||||
| #------------------------------------------ | ||||
| sub get_monitor_nodes_list { | ||||
|     my @cmdoutput = `lsdef $noderange 2>&1`; | ||||
|     foreach (@cmdoutput) { | ||||
|         if ($_ =~ /^Error: Could not find an object named '(\w+)' .+/i) { | ||||
|             $monitor_nodes{$1} = 0; | ||||
|         } elsif ($_ =~ /^\s*Object name: (\w+)/i) { | ||||
|             $monitor_nodes{$1} = 0; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| #------------------------------------------ | ||||
|  | ||||
| =head3 | ||||
|     Description: | ||||
|        Test if all nodes have finished job | ||||
|     Arguments: | ||||
|        One golble attribute %monitor_nodes; | ||||
|     Returns: | ||||
| =cut | ||||
|  | ||||
| #------------------------------------------ | ||||
| sub all_monitor_node_done { | ||||
|     my $done = 1; | ||||
|     foreach my $node (keys %monitor_nodes) { | ||||
|         $done = 0 if ($monitor_nodes{$node} == 0); | ||||
|     } | ||||
|     return $done; | ||||
| } | ||||
|  | ||||
| #------------------------------------------ | ||||
|  | ||||
| =head3 | ||||
|     Description: | ||||
|        Do pre_checking | ||||
|     Arguments: | ||||
|         nics: target network interface | ||||
|               if not specified, using the network which master belongs to | ||||
|     Returns: | ||||
|         0: pass | ||||
|         1: failed | ||||
| =cut | ||||
|  | ||||
| #------------------------------------------ | ||||
| sub do_pre_check { | ||||
|     my $nics = shift; | ||||
|     my @nets = (); | ||||
|     my $rst  = 0; | ||||
|     my $msg; | ||||
|  | ||||
|     if (defined($noderange) && defined($discovery_type)) { | ||||
|         $msg = "All pre_defined nodes are valid"; | ||||
|         my $rc = check_pre_defined_node($discovery_type, $noderange); | ||||
|         if ($rc) { | ||||
|             probe_utils->send_msg("$output", "f", $msg); | ||||
|             $rst = 1; | ||||
|         } else { | ||||
|             probe_utils->send_msg("$output", "o", $msg); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|  | ||||
|     if ($nics) { | ||||
|         if ($nics =~ /[^\w,]/) { | ||||
|             probe_utils->send_msg("$output", "f", "Invalid NIC list"); | ||||
|             probe_utils->send_msg("$output", "d", "$::USAGE"); | ||||
|             exit 1; | ||||
|         } | ||||
|  | ||||
|         $msg = "The input network interfaces $nics exist and are configured well on current server"; | ||||
|         my $miss = 0; | ||||
|         my @nic_array = split(",", $nics); | ||||
|         foreach my $nic (@nic_array) { | ||||
|             my $tmp_nic = `ip addr show $nic >/dev/null 2>&1`; | ||||
|             if ($?) { | ||||
|                 probe_utils->send_msg("$output", "d", "Network interface $nic doesn't exist on current server") if ($verbose); | ||||
|                 $miss = 1; | ||||
|             } else { | ||||
|                 my $tmp = `ifconfig $nic|awk -F" " '/inet / {print \$2,\$4}'`; | ||||
|                 chomp($tmp); | ||||
|                 if (!$tmp) { | ||||
|                     probe_utils->send_msg("$output", "d", "Network interface $nic isn't set IP address") if ($verbose); | ||||
|                     $miss = 1; | ||||
|                 } else { | ||||
|                     my ($ip, $mask) = split(" ", $tmp); | ||||
|                     push(@nets, probe_utils->get_network($ip, $mask)); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         if ($miss) { | ||||
|             probe_utils->send_msg("$output", "f", $msg); | ||||
|             $rst = 1; | ||||
|         } else { | ||||
|             probe_utils->send_msg("$output", "o", $msg); | ||||
|         } | ||||
|     } else { | ||||
|         $msg = "Attribute 'master' in 'site' table is configured well"; | ||||
|         my $masteripinsite = `tabdump site | awk -F',' '/master/ { gsub(/"/, "", \$2) ; print \$2 }'`; | ||||
|         chomp($masteripinsite); | ||||
|         if ($masteripinsite eq "") { | ||||
|             probe_utils->send_msg("$output", "d", "There isn't 'master' definition in 'site' talbe") if ($verbose); | ||||
|             probe_utils->send_msg("$output", "f", $msg); | ||||
|             exit 1; | ||||
|         } | ||||
|         if (!probe_utils->is_ip_addr("$masteripinsite")) { | ||||
|             probe_utils->send_msg("$output", "d", "The value of 'master' in 'site' table isn't a IP address") if ($verbose); | ||||
|             probe_utils->send_msg("$output", "f", $msg); | ||||
|             exit 1; | ||||
|         } | ||||
|         `ifconfig -a 2>&1 |grep  $masteripinsite`; | ||||
|         if ($?) { | ||||
|             probe_utils->send_msg("$output", "d", "The IP $masteripinsite of 'master' in 'site' table dosen't belong to any network on current server") if ($verbose); | ||||
|             probe_utils->send_msg("$output", "f", $msg); | ||||
|             exit 1; | ||||
|         } | ||||
|         probe_utils->send_msg("$output", "o", $msg); | ||||
|         my $tmp = `ifconfig -a|awk -F" " '/$masteripinsite/ {print \$2,\$4}'`; | ||||
|         chomp($tmp); | ||||
|         my ($ip, $mask) = split(" ", $tmp); | ||||
|         push(@nets, probe_utils->get_network($ip, $mask)); | ||||
|     } | ||||
|  | ||||
|     my $arch = `uname -i`; | ||||
|     chomp($arch); | ||||
|     $msg = "Genesis files for $arch are available"; | ||||
|     if ($arch =~ /ppc64/i) { | ||||
|         if (check_genesis_file("ppc64")) { | ||||
|             probe_utils->send_msg("$output", "f", $msg); | ||||
|             $rst = 1; | ||||
|         } else { | ||||
|             probe_utils->send_msg("$output", "o", $msg); | ||||
|             if (check_genesis_file("x86_64")) { | ||||
|                 probe_utils->send_msg("$output", "w", "Genesis files for x86 are not available"); | ||||
|                 probe_utils->send_msg("$output", "i", "If don't plan to manage a x86 server, please ignore above warning"); | ||||
|             } else { | ||||
|                 probe_utils->send_msg("$output", "o", "Genesis files for x86 are available"); | ||||
|             } | ||||
|         } | ||||
|     } elsif ($arch =~ /x86/i) { | ||||
|         if (check_genesis_file("x86_64")) { | ||||
|             probe_utils->send_msg("$output", "f", $msg); | ||||
|             $rst = 1; | ||||
|         } else { | ||||
|             probe_utils->send_msg("$output", "o", $msg); | ||||
|             if (check_genesis_file("ppc64")) { | ||||
|                 probe_utils->send_msg("$output", "w", "Genesis files for ppc64/ppc64le are not available"); | ||||
|                 probe_utils->send_msg("$output", "i", "If don't plan to manage a ppc64/ppc64le server, please ignore above warning"); | ||||
|             } else { | ||||
|                 probe_utils->send_msg("$output", "o", "Genesis files for ppc64/ppc64le are available"); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     $msg = "DHCP dynamic range is configured well"; | ||||
|     if (dhcp_dynamic_range_check(\@nets)) { | ||||
|         probe_utils->send_msg("$output", "f", $msg); | ||||
|         $rst = 1; | ||||
|     } else { | ||||
|         probe_utils->send_msg("$output", "o", $msg); | ||||
|     } | ||||
|  | ||||
|     return $rst; | ||||
| } | ||||
|  | ||||
| #------------------------------------------ | ||||
|  | ||||
| =head3 | ||||
|     Description: | ||||
|        Monitor the process of discovery  | ||||
|     Arguments: | ||||
|         nics: target network interface | ||||
|               if not specified, using the network which master belongs to | ||||
|     Returns: | ||||
|         0: pass | ||||
|         1: failed | ||||
| =cut | ||||
|  | ||||
| #------------------------------------------ | ||||
| sub do_monitor { | ||||
|     $SIG{TERM} = $SIG{INT} = sub { | ||||
|         $terminal = 1; | ||||
|     }; | ||||
|  | ||||
|     if ($monitor && !$pre_check && defined($noderange) && defined($discovery_type)) { | ||||
|         $msg = "All pre_defined nodes are valid"; | ||||
|         my $rc = check_pre_defined_node($discovery_type, $noderange); | ||||
|         if ($rc) { | ||||
|             probe_utils->send_msg("$output", "f", $msg); | ||||
|             exit 1; | ||||
|         } else { | ||||
|             probe_utils->send_msg("$output", "o", $msg); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     &get_monitor_nodes_list if (defined($noderange) && defined($discovery_type)); | ||||
|  | ||||
|     if (!$nics) { | ||||
|         my $masteripinsite = `tabdump site | awk -F',' '/master/ { gsub(/"/, "", \$2) ; print \$2 }'`; | ||||
|         chomp($masteripinsite); | ||||
|         $nics = `ip addr |grep -B2 $masteripinsite|awk -F" " '/mtu/{gsub(/:/,"",\$2); print \$2}'`; | ||||
|         chomp($nics); | ||||
|         if (!$nics) { | ||||
|             probe_utils->send_msg("$output", "f", "The value of master in site table is $masteripinsite, can't get corresponding network interface"); | ||||
|             exit 1; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     probe_utils->send_msg("$output", "d", "Start to capture every message during discovery process......"); | ||||
|  | ||||
|     my $varlogmsg  = "/var/log/messages"; | ||||
|     my $clusterlog = "/var/log/xcat/cluster.log"; | ||||
|     my $computelog = "/var/log/xcat/computes.log"; | ||||
|  | ||||
|     my $httplog; | ||||
|     my $os = probe_utils->get_os(); | ||||
|     if ($os eq "redhat") { | ||||
|         $httplog = "/var/log/httpd/access_log"; | ||||
|     } elsif ($os eq "sles") { | ||||
|         $httplog = "/var/log/apache2access_log"; | ||||
|     } elsif ($os eq "ubuntu") { | ||||
|         $httplog = "/var/log/apache2/access.log"; | ||||
|     } | ||||
|  | ||||
|     open(VARLOGMSGFILE,  "tail -f $varlogmsg 2>&1 |"); | ||||
|     open(CLUSTERLOGFILE, "tail -f $clusterlog 2>&1 |"); | ||||
|     open(HTTPLOGFILE,    "tail -f $httplog 2>&1 |"); | ||||
|     open(COMPUTERFILE,   "tail -f $computelog 2>&1 |"); | ||||
|  | ||||
|     my $select = new IO::Select; | ||||
|     $select->add(\*VARLOGMSGFILE); | ||||
|     $select->add(\*CLUSTERLOGFILE); | ||||
|     $select->add(\*HTTPLOGFILE); | ||||
|     $select->add(\*COMPUTERFILE); | ||||
|     $| = 1; | ||||
|  | ||||
|     my $line = ""; | ||||
|     my @hdls; | ||||
|     my $hdl; | ||||
|     for (; ;) { | ||||
|         if (@hdls = $select->can_read(0)) { | ||||
|             foreach $hdl (@hdls) { | ||||
|                 if ($hdl == \*VARLOGMSGFILE) { | ||||
|                     chomp($line = <VARLOGMSGFILE>); | ||||
|                     my @tmp = split(/ /, $line); | ||||
|                     if ($tmp[4] =~ /dhcpd:/i) { | ||||
|                         handle_dhcp_msg("$line", $nics); | ||||
|                     } elsif ($tmp[4] =~ /in.tftpd/i) { | ||||
|                         handle_tftp_msg("$line"); | ||||
|                     } | ||||
|                 } elsif ($hdl == \*CLUSTERLOGFILE) { | ||||
|                     chomp($line = <CLUSTERLOGFILE>); | ||||
|                     handle_cluster_msg("$line"); | ||||
|                 } elsif ($hdl == \*HTTPLOGFILE) { | ||||
|                     chomp($line = <HTTPLOGFILE>); | ||||
|                     handle_http_msg("$line"); | ||||
|                 } elsif ($hdl == \*COMPUTERFILE) { | ||||
|                     chomp($line = <COMPUTERFILE>); | ||||
|                     handle_compute_msg("$line"); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if ($terminal || (%monitor_nodes && all_monitor_node_done())) { | ||||
|             &dump_history; | ||||
|             close(VARLOGMSGFILE); | ||||
|             close(CLUSTERLOGFILE); | ||||
|             close(HTTPLOGFILE); | ||||
|             close(COMPUTERFILE); | ||||
|             exit 0; | ||||
|         } | ||||
|         sleep 0.01; | ||||
|     } | ||||
|  | ||||
|     close(VARLOGMSGFILE); | ||||
|     close(CLUSTERLOGFILE); | ||||
|     close(HTTPLOGFILE); | ||||
|     close(COMPUTERFILE); | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| #------------------------------------- | ||||
| # main process | ||||
| #------------------------------------- | ||||
| if ( | ||||
|     !GetOptions("--help|h|?" => \$help, | ||||
|         "t" => \$test, | ||||
|         "V" => \$verbose, | ||||
|         "s" => \$static)) | ||||
|         "t"   => \$test, | ||||
|         "V"   => \$verbose, | ||||
|         "m"   => \$monitor, | ||||
|         "p"   => \$pre_check, | ||||
|         "T=s" => \$discovery_type, | ||||
|         "n=s" => \$noderange, | ||||
|         "N=s" => \$nics)) | ||||
| { | ||||
|     probe_utils->send_msg("$output", "f", "Invalid parameter for $program_name"); | ||||
|     probe_utils->send_msg("$output", "d", "$::USAGE"); | ||||
| @@ -253,23 +941,37 @@ if ($help) { | ||||
| } | ||||
|  | ||||
| if ($test) { | ||||
|     probe_utils->send_msg("$output", "o", "Discovery Check."); | ||||
|     probe_utils->send_msg("$output", "o", "Do probe for discovery process, including pro-check for required configuration and realtime monitor of discovery process.Before using this command, please install nslookup command ahead."); | ||||
|     exit 0; | ||||
| } | ||||
|  | ||||
| if ($static) { | ||||
|     $rst = check_genesis_file("ppc64"); | ||||
|     if ($rst) { | ||||
|         probe_utils->send_msg("$output", "f", "Genesis files for ppc64/ppc64le failed."); | ||||
|     } else { | ||||
|         probe_utils->send_msg("$output", "o", "Genesis files for ppc64/ppc64le success."); | ||||
|     } | ||||
|     $rst = check_genesis_file("x86_64"); | ||||
|     if ($rst) { | ||||
|         probe_utils->send_msg("$output", "f", "Genesis files for x86_64 failed."); | ||||
|     } else { | ||||
|         probe_utils->send_msg("$output", "o", "Genesis files for x86_64 success."); | ||||
| if (defined($noderange) && !defined($discovery_type)) { | ||||
|     probe_utils->send_msg("$output", "f", "Option '-n' must used with '-m'"); | ||||
|     probe_utils->send_msg("$output", "d", "$::USAGE"); | ||||
|     exit 1; | ||||
| } | ||||
|  | ||||
| if (defined($discovery_type)) { | ||||
|     unless (@valid_discovery_type ~~ /^$discovery_type$/) { | ||||
|         probe_utils->send_msg("$output", "f", "Invalid discovery type. the vaild types are $valid_discovery_type_str"); | ||||
|         probe_utils->send_msg("$output", "d", "$::USAGE"); | ||||
|         exit 1; | ||||
|     } | ||||
| } | ||||
|  | ||||
| if ($pre_check) { | ||||
|     exit 1 if (do_pre_check($nics)); | ||||
| } | ||||
|  | ||||
| if ($monitor) { | ||||
|     $rst = do_monitor(); | ||||
| } | ||||
|  | ||||
| if (!$monitor && !$pre_check) { | ||||
|     $rst = do_pre_check(); | ||||
|     exit 1 if ($rst); | ||||
|  | ||||
|     $rst = do_monitor(); | ||||
| } | ||||
|  | ||||
| exit $rst; | ||||
|   | ||||
| @@ -84,34 +84,54 @@ sub loadsubcmds { | ||||
| sub format_cmd_output { | ||||
|     my $line    = shift; | ||||
|     my $nocolor = shift; | ||||
|  | ||||
|     if ($line =~ /\[(\w+)\]\s*:\s*(.+)/) { | ||||
|         my $flag = $1; | ||||
|         my $msg  = $2; | ||||
|         if ($flag =~ /failed/i) { | ||||
|             if ($nocolor) { | ||||
|                 print "[FAIL] "; | ||||
|             } else { | ||||
|                 print BOLD RED "[FAIL] "; | ||||
|         my $flag     = $1; | ||||
|         my $msg      = $2; | ||||
|         my @tmpmsg   = split(" ", $msg); | ||||
|         my $maxlen   = 80; | ||||
|         my @finalmsg = (); | ||||
|         my $str      = ""; | ||||
|         foreach my $word (@tmpmsg) { | ||||
|             $str .= $word . " "; | ||||
|             if (length($str) > $maxlen) { | ||||
|                 push @finalmsg, $str; | ||||
|                 $str = ""; | ||||
|             } | ||||
|         } | ||||
|         push @finalmsg, $str if ($str ne ""); | ||||
|  | ||||
|         for (my $i = 0 ; $i < $#finalmsg + 1 ; $i++) { | ||||
|             if ($i ne $#finalmsg) { | ||||
|                 print "$finalmsg[$i]\n"; | ||||
|                 next; | ||||
|             } | ||||
|             my $space = " " x ($maxlen - length($finalmsg[$i]) + 5); | ||||
|             print "$finalmsg[$i]$space"; | ||||
|  | ||||
|             if ($flag =~ /failed/i) { | ||||
|                 if ($nocolor) { | ||||
|                     print "[FAIL]\n"; | ||||
|                 } else { | ||||
|                     print BOLD RED "[FAIL]\n"; | ||||
|                 } | ||||
|             } elsif ($flag =~ /warning/i) { | ||||
|                 if ($nocolor) { | ||||
|                     print "[WARN]\n"; | ||||
|                 } else { | ||||
|                     print BOLD BLUE "[WARN]\n"; | ||||
|                 } | ||||
|             } elsif ($flag =~ /ok/i) { | ||||
|                 if ($nocolor) { | ||||
|                     print "[ OK ]\n"; | ||||
|                 } else { | ||||
|                     print BOLD GREEN "[ OK ]\n"; | ||||
|                 } | ||||
|             } elsif ($flag =~ /debug/i) { | ||||
|                 print "\n"; | ||||
|             } elsif ($flag =~ /info/i) { | ||||
|                 print "[INFO]\n"; | ||||
|             } | ||||
|         } elsif ($flag =~ /warning/i) { | ||||
|             if ($nocolor) { | ||||
|                 print "[WARN] "; | ||||
|             } else { | ||||
|                 print BOLD BLUE "[WARN] "; | ||||
|             } | ||||
|         } elsif ($flag =~ /ok/i) { | ||||
|             if ($nocolor) { | ||||
|                 print "[ OK ] "; | ||||
|             } else { | ||||
|                 print BOLD GREEN "[ OK ] "; | ||||
|             } | ||||
|         } elsif ($flag =~ /debug/i) { | ||||
|             print "       "; | ||||
|         } elsif ($flag =~ /info/i) { | ||||
|             print "[INFO] "; | ||||
|         } | ||||
|         print "$msg\n"; | ||||
|     } else { | ||||
|         print "$line\n"; | ||||
|     } | ||||
| @@ -210,10 +230,11 @@ if ($ARGV[0] eq "-l") { | ||||
| } | ||||
|  | ||||
| if (!defined($pluginname)) { | ||||
|     print "There isn't sub command input from command line\n"; | ||||
|     print "There isn't sub command input from command line, please use '-l' to list all valid subcommand\n"; | ||||
|     exit 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| for (my $i = 0 ; $i < $optnum + 1 ; $i++) { | ||||
|     shift @tmpargv; | ||||
| } | ||||
| @@ -223,9 +244,29 @@ my $subcmd = "$plugin_dir/$pluginname $pluginattrs"; | ||||
| print "\nsubcmd = $subcmd\n" if ($verbose); | ||||
|  | ||||
| open(PIPE, "$subcmd |"); | ||||
|  | ||||
| my $terminal  = 0; | ||||
| my $subcmdpid = 0; | ||||
| my @tmpoutput = `ps axjf |grep -v grep|grep -v ps|grep -v bash|grep $$`; | ||||
| foreach (@tmpoutput) { | ||||
|     @psline = split(" ", $_); $subcmdpid = $psline[1] if (($psline[0] eq $$) && ($psline[1] ne $$) && ($psline[2] eq $$)); | ||||
| } | ||||
| $SIG{TERM} = $SIG{INT} = sub { | ||||
|     $terminal = 1; | ||||
| }; | ||||
|  | ||||
| while (<PIPE>) { | ||||
|     chomp; | ||||
|     format_cmd_output($_, $nocolor); | ||||
|     if ($terminal && $subcmdpid) { | ||||
|         kill 'INT', $subcmdpid; | ||||
|         while (<PIPE>) { | ||||
|             chomp; | ||||
|             format_cmd_output($_, $nocolor); | ||||
|         } | ||||
|         close(PIPE); | ||||
|         exit $?; | ||||
|     } | ||||
| } | ||||
| close(PIPE);    # This will set the $? properly | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user