mirror of
				https://github.com/xcat2/xcat-core.git
				synced 2025-10-27 01:15:34 +00:00 
			
		
		
		
	enhance node info parsing mechanism: add more checks before import
git-svn-id: https://svn.code.sf.net/p/xcat/code/xcat-core/trunk@14792 8638fb3e-16cb-4fca-ae20-7b5d299a9bcd
This commit is contained in:
		| @@ -763,3 +763,78 @@ sub get_nodes_cmm | ||||
|      | ||||
|     return \%returncmm | ||||
| } | ||||
|  | ||||
| #------------------------------------------------------------------------------- | ||||
|  | ||||
| =head3 parse_nodeinfo_file | ||||
|     Description: Parse node info file content. And put node info into 2 global | ||||
|                  vals: @::profiledNodeObjNames and %::profiledNodeAttrs. | ||||
|                  @::profiledNodeObjNames: recording all nodes' names. | ||||
|                  %::profiledNodeAttrs: recording all nodes' attributes. | ||||
|     Arguments: $filedata: node info file content string. | ||||
|     Returns: ($retcode, $msgstr). | ||||
|               $retcode = 1. Parse success, the format of this file is OK. | ||||
|               $retcode = 0. Parse failed, there are some errors in this file. | ||||
|                             Detailed errors will be set in $msgstr. | ||||
| =cut | ||||
|  | ||||
| #------------------------------------------------------------------------------- | ||||
| sub parse_nodeinfo_file | ||||
| { | ||||
|     my($class, $filedata) = @_; | ||||
|     @::profiledNodeObjNames = (); | ||||
|     %::profiledNodeAttrs = (); | ||||
|  | ||||
|     my @lines = split /\n/, $filedata; | ||||
|     my $obj_found = 0; | ||||
|     my ($objname, $append); | ||||
|  | ||||
|     foreach my $line (@lines){ | ||||
|         # skip blank and comment lines | ||||
|         next if ($line =~ /^\s*$/ || $line =~ /^\s*#/); | ||||
|  | ||||
|         # The line ends with : | ||||
|         if (grep(/:\s*$/, $line)){ | ||||
|             ($objname, $append) = split(/:/, $line); | ||||
|             $objname =~ s/^\s*//;    # Remove any leading whitespace | ||||
|             $objname =~ s/\s*$//;    # Remove any trailing whitespace | ||||
|  | ||||
|             # OK we've found one object. | ||||
|             if ($objname){ | ||||
|                 $obj_found = 1; | ||||
|                 push(@::profiledNodeObjNames, $objname); | ||||
|             }else{ | ||||
|                 return 0, "No node name defined in line \'$line\'"; | ||||
|             } | ||||
|         } # The line has = | ||||
|         elsif (($line =~ /^\s*(.*?)\s*=\s*(.*)\s*/)){ | ||||
|             # No one object clarified yet. So this file format is illegal. | ||||
|             if (! $obj_found){ | ||||
|                 return 0, "No node defined before line \'$line\'"; | ||||
|             } | ||||
|  | ||||
|             my $attr = $1; | ||||
|             my $val  = $2; | ||||
|             $attr =~ s/^\s*//;    # Remove any leading whitespace | ||||
|             $attr =~ s/\s*$//;    # Remove any trailing whitespace | ||||
|             $val  =~ s/^\s*//; | ||||
|             $val  =~ s/\s*$//; | ||||
|  | ||||
|             # remove spaces and quotes | ||||
|             $val =~ s/^\s*"\s*//; | ||||
|             $val =~ s/\s*"\s*$//; | ||||
|  | ||||
|             if($attr && $val){ | ||||
|                 $::profiledNodeAttrs{$objname}{$attr} = $val; | ||||
|             }else{ | ||||
|                 return 0, "Line \'$line\' does not contain a valid key and value"; | ||||
|             } | ||||
|  | ||||
|         } #invalid line. | ||||
|         else{ | ||||
|             return 0, "Invalid Line \'$line\' found"; | ||||
|         } | ||||
|     } | ||||
|     return 1, ""; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -15,7 +15,6 @@ use warnings; | ||||
| use Getopt::Long qw(:config no_ignore_case); | ||||
| use Data::Dumper; | ||||
| require xCAT::Table; | ||||
| require xCAT::DBobjUtils; | ||||
| require xCAT::Utils; | ||||
| require xCAT::TableUtils; | ||||
| require xCAT::NetworkUtils; | ||||
| @@ -24,9 +23,9 @@ require xCAT::ProfiledNodeUtils; | ||||
|  | ||||
| # 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; | ||||
| # These 2 global varialbes are set in lib xCAT::ProfiledNodeUtils->parse_nodeinfo_file. | ||||
| #%::profiledNodeAttrs; | ||||
| #@::profiledNodeObjNames; | ||||
|  | ||||
| # All database records. | ||||
| my %allhostnames; | ||||
| @@ -347,10 +346,16 @@ Usage: | ||||
|         setrsp_errormsg($retstr_read); | ||||
|         return; | ||||
|     } | ||||
|     my ($parse_ret, $parse_str) = xCAT::ProfiledNodeUtils->parse_nodeinfo_file($retstr_read); | ||||
|     if (! $parse_ret){ | ||||
|         setrsp_progress("Failed to validate node information file."); | ||||
|         setrsp_errormsg($parse_str); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     # Parse and validate the hostinfo string. The real hostnames will be generated here. | ||||
|     xCAT::MsgUtils->message('S', "Parsing hostinfo string and validate it."); | ||||
|     my ($hostinfo_dict_ref, $invalid_records_ref) = parse_hosts_string($retstr_read); | ||||
|     my ($hostinfo_dict_ref, $invalid_records_ref) = validate_node_entries(); | ||||
|     my %hostinfo_dict = %$hostinfo_dict_ref; | ||||
|     my @invalid_records = @$invalid_records_ref; | ||||
|     if (@invalid_records){ | ||||
| @@ -1133,7 +1138,9 @@ sub findme{ | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     my ($hostinfo_dict_ref, $invalid_records_ref) = parse_hosts_string($raw_hostinfo_str); | ||||
|     xCAT::ProfiledNodeUtils->parse_nodeinfo_file($raw_hostinfo_str); | ||||
|  | ||||
|     my ($hostinfo_dict_ref, $invalid_records_ref) = validate_node_entries(); | ||||
|     my %hostinfo_dict = %$hostinfo_dict_ref; | ||||
|     # Create the real hostinfo string in stanza file format. | ||||
|     xCAT::MsgUtils->message('S', "Profiled nodes discover: Generating new hostinfo string.\n"); | ||||
| @@ -1374,18 +1381,17 @@ sub read_and_generate_hostnames{ | ||||
|  | ||||
| #------------------------------------------------------- | ||||
|  | ||||
| =head3  parse_hosts_string | ||||
| =head3  validate_node_entries | ||||
|      | ||||
|     Description : Parse the hostinfo string and validate it. | ||||
|     Arguments   : filecontent - The content of hostinfo file. | ||||
|     Description : Validate the node entrie and generate proper attributes. | ||||
|     Arguments   : N/A | ||||
|     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; | ||||
| sub validate_node_entries{ | ||||
|     my %hostinfo_dict; | ||||
|     my @invalid_records; | ||||
|  | ||||
| @@ -1394,14 +1400,11 @@ sub parse_hosts_string{ | ||||
|     my $nameformattype = xCAT::ProfiledNodeUtils->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,  | ||||
|     # We should go through list @::profiledNodeObjNames first as  %::profiledNodeAttrs is just a hash,  | ||||
|     # it not tells whether there are some duplicated hostnames in the hostinfo string. | ||||
|     my %hostnamedict; | ||||
|     foreach my $hostname (@::fileobjnames){ | ||||
|     foreach my $hostname (@::profiledNodeObjNames){ | ||||
|         if (exists $hostnamedict{$hostname}){ | ||||
|             push @invalid_records, [$hostname, "Duplicated hostname defined"]; | ||||
|         } else{ | ||||
| @@ -1422,18 +1425,18 @@ sub parse_hosts_string{ | ||||
|     my @chassislist = keys %allchassis; | ||||
|     my $chassisrackref = xCAT::ProfiledNodeUtils->get_racks_for_chassises(\@chassislist); | ||||
|  | ||||
|     foreach my $attr (keys %::FILEATTRS){ | ||||
|         my $errmsg = validate_node_entry($attr, $::FILEATTRS{$attr}); | ||||
|     foreach my $attr (keys %::profiledNodeAttrs){ | ||||
|         my $errmsg = validate_node_entry($attr, $::profiledNodeAttrs{$attr}); | ||||
|         # Check whether specified IP is in our prov network, static range. | ||||
|         if ($::FILEATTRS{$attr}->{'ip'}){ | ||||
|             unless (grep{ $_ eq $::FILEATTRS{$attr}->{'ip'}} @$freeprovipsref){ | ||||
|                 $errmsg .= "Specified IP address $::FILEATTRS{$attr}->{'ip'} not in static range of provision network $provnet"; | ||||
|         if ($::profiledNodeAttrs{$attr}->{'ip'}){ | ||||
|             unless (grep{ $_ eq $::profiledNodeAttrs{$attr}->{'ip'}} @$freeprovipsref){ | ||||
|                 $errmsg .= "Specified IP address $::profiledNodeAttrs{$attr}->{'ip'} not in static range of provision network $provnet"; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         # Set rack info for blades too. | ||||
|         if ($::FILEATTRS{$attr}->{'chassis'}){ | ||||
|             $::FILEATTRS{$attr}->{'rack'} = $chassisrackref->{$::FILEATTRS{$attr}->{'chassis'}}; | ||||
|         if ($::profiledNodeAttrs{$attr}->{'chassis'}){ | ||||
|             $::profiledNodeAttrs{$attr}->{'rack'} = $chassisrackref->{$::profiledNodeAttrs{$attr}->{'chassis'}}; | ||||
|         } | ||||
|         if ($errmsg) { | ||||
|             if ($attr =~ /^TMPHOSTS/){ | ||||
| @@ -1451,13 +1454,13 @@ sub parse_hosts_string{ | ||||
|             my $numricformat; | ||||
|             # Need convert hostname format into numric format first. | ||||
|             if ($nameformattype eq "rack"){ | ||||
|                 if (! exists $::FILEATTRS{$attr}{"rack"}){ | ||||
|                 if (! exists $::profiledNodeAttrs{$attr}{"rack"}){ | ||||
|                     push @invalid_records, ["__hostname__", "Rack information is not specified. You must enter the required rack information."]; | ||||
|                     next; | ||||
|                 } | ||||
|                 $numricformat = xCAT::ProfiledNodeUtils->rackformat_to_numricformat($nameformat, $::FILEATTRS{$attr}{"rack"}); | ||||
|                 $numricformat = xCAT::ProfiledNodeUtils->rackformat_to_numricformat($nameformat, $::profiledNodeAttrs{$attr}{"rack"}); | ||||
|                 if(! $numricformat){ | ||||
|                     push @invalid_records, ["__hostname__", "The rack number of rack $::FILEATTRS{$attr}{'rack'} does not match hostname format $nameformat"]; | ||||
|                     push @invalid_records, ["__hostname__", "The rack number of rack $::profiledNodeAttrs{$attr}{'rack'} does not match hostname format $nameformat"]; | ||||
|                 } | ||||
|             } else{ | ||||
|                 # pure numric hostname format | ||||
| @@ -1491,9 +1494,9 @@ sub parse_hosts_string{ | ||||
|  | ||||
|                 $nexthostname = shift @$hostnamelistref; | ||||
|             } | ||||
|             $hostinfo_dict{$nexthostname} = $::FILEATTRS{$attr}; | ||||
|             $hostinfo_dict{$nexthostname} = $::profiledNodeAttrs{$attr}; | ||||
|         } else{ | ||||
|             $hostinfo_dict{$attr} = $::FILEATTRS{$attr}; | ||||
|             $hostinfo_dict{$attr} = $::profiledNodeAttrs{$attr}; | ||||
|         } | ||||
|     } | ||||
|     return (\%hostinfo_dict, \@invalid_records); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user