git-svn-id: https://svn.code.sf.net/p/xcat/code/xcat-core/trunk@6017 8638fb3e-16cb-4fca-ae20-7b5d299a9bcd
		
			
				
	
	
		
			1977 lines
		
	
	
		
			67 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
			
		
		
	
	
			1977 lines
		
	
	
		
			67 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
| #!/usr/bin/env perl -w
 | |
| # IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
 | |
| 
 | |
| #####################################################
 | |
| #
 | |
| #   Utility subroutines that can be used to manage xCAT data object
 | |
| #			definitions.
 | |
| #
 | |
| #
 | |
| #####################################################
 | |
| package xCAT::DBobjUtils;
 | |
| 
 | |
| use xCAT::NodeRange;
 | |
| use xCAT::Schema;
 | |
| use xCAT::Table;
 | |
| use xCAT::Utils;
 | |
| use xCAT::MsgUtils;
 | |
| use xCAT::NetworkUtils;
 | |
| use strict;
 | |
| 
 | |
| #  IPv6 not yet implemented - need Socket6
 | |
| use Socket;
 | |
| 
 | |
| #----------------------------------------------------------------------------
 | |
| 
 | |
| =head3   getObjectsOfType
 | |
| 
 | |
|         Get a list of data objects of the given type.
 | |
| 
 | |
|         Arguments:
 | |
|         Returns:
 | |
|                 undef
 | |
|                 @objlist - list of objects of this type
 | |
|         Globals:
 | |
|         Error:
 | |
|         Example:
 | |
|         Comments:
 | |
| 
 | |
| 		@objlist = xCAT::DBobjUtils->getObjectsOfType($type);
 | |
| 
 | |
| =cut
 | |
| 
 | |
| #-----------------------------------------------------------------------------
 | |
| sub getObjectsOfType
 | |
| {
 | |
|     my ($class, $type) = @_;
 | |
| 
 | |
|     my @objlist;
 | |
| 
 | |
|     # special case for site table
 | |
|     if ($type eq 'site')
 | |
|     {
 | |
|         push(@objlist, 'clustersite');
 | |
|         return @objlist;
 | |
|     }
 | |
| 
 | |
|     if ($::saveObjList{$type})
 | |
|     {
 | |
|         @objlist = @{$::saveObjList{$type}};
 | |
|     }
 | |
|     else
 | |
|     {
 | |
| 
 | |
|         # get the key for this type object
 | |
|         # 	ex. for "network" type the key is "netname"
 | |
|         # get the data type spec from Schema.pm
 | |
|         my $datatype = $xCAT::Schema::defspec{$type};
 | |
| 
 | |
|         # get the key for this type object
 | |
|         #   ex. for "network" type the key is "netname"
 | |
|         my $objkey = $datatype->{'objkey'};
 | |
| 
 | |
|         my $table;
 | |
|         my $tabkey;
 | |
|         foreach my $this_attr (@{$datatype->{'attrs'}})
 | |
|         {
 | |
|             my $attr = $this_attr->{attr_name};
 | |
|             if ($attr eq $objkey)
 | |
|             {
 | |
|                 # get the table & key for to lookup
 | |
|                 # get the actual attr name to use in the table
 | |
|                 #   - may be different then the attr name used for the object.
 | |
|                 ($table, $tabkey) = split('\.', $this_attr->{tabentry});
 | |
|                 last;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         # get the whole table and add each entry in the objkey column
 | |
|         #   to the list of objects.
 | |
|         my @TableRowArray = xCAT::DBobjUtils->getDBtable($table);
 | |
| 
 | |
|         foreach (@TableRowArray)
 | |
|         {
 | |
|             push(@objlist, $_->{$tabkey});
 | |
| 
 | |
|         }
 | |
| 
 | |
|         # if this is type "group" we need to check the nodelist table
 | |
|         my @nodeGroupList=();
 | |
|         if ($type eq 'group')
 | |
|         {
 | |
|             my $table = "nodelist";
 | |
|             my @TableRowArray = xCAT::DBobjUtils->getDBtable($table);
 | |
|             foreach (@TableRowArray)
 | |
|             {
 | |
|                 my @tmplist = split(',', $_->{'groups'});
 | |
|                 push(@nodeGroupList, @tmplist);
 | |
|             }
 | |
|             foreach my $n (@nodeGroupList)
 | |
|             {
 | |
|                 if (!grep(/^$n$/, @objlist) ) {
 | |
|                     push(@objlist, $n);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
| 		
 | |
|         @{$::saveObjList{$type}} = @objlist;
 | |
|     }
 | |
| 
 | |
|     return @objlist;
 | |
| }
 | |
| 
 | |
| #----------------------------------------------------------------------------
 | |
| 
 | |
| =head3   getobjattrs
 | |
| 
 | |
|         Get data from tables 
 | |
| 
 | |
|                 $type_hash: objectname=>objtype hash
 | |
|                 $attrs_ref: only get the specific attributes,
 | |
|                             this can be useful especially for performance considerations
 | |
|         Arguments:
 | |
|         Returns:
 | |
|                 undef
 | |
|                 hash ref - (ex. $tabhash{$table}{$objname}{$attr} = $value)
 | |
|         Globals:
 | |
|         Error:
 | |
|         Example:
 | |
| 
 | |
|                 %tabhash = xCAT::DBobjUtils->getobjattrs(\%typehash);
 | |
| 
 | |
|         Comments:
 | |
| 			For now - only support tables that have 'node' as key !!!
 | |
| =cut
 | |
| 
 | |
| #-----------------------------------------------------------------------------
 | |
| sub getobjattrs
 | |
| {
 | |
|     my $class = shift;
 | |
|     my $ref_hash = shift;
 | |
|     my @attrs;
 | |
|     # The $attrs is an optional argument
 | |
|     if (ref $_[0]) {
 | |
|         @attrs = @{shift()};
 | |
|     }
 | |
|     my %typehash = %$ref_hash;
 | |
|     
 | |
|     my %tableattrs;
 | |
|     my %tabhash;
 | |
|     
 | |
|     # get a list of object names for each type
 | |
|     my %objtypelist;
 | |
|     foreach my $objname (sort (keys %typehash)) {
 | |
|         # get list of objects for each type
 | |
|         # $objtypelist{$typehash{$objname}}=$objname;
 | |
|         push @{$objtypelist{$typehash{$objname}}}, $objname;
 | |
|     }
 | |
|     
 | |
|     # go through each object type and look up all the info for each object
 | |
|     foreach my $objtype (keys %objtypelist) {
 | |
|     
 | |
|     	  # only do node type for now 
 | |
|          if ($objtype eq 'node') {
 | |
|             # find the list of tables and corresponding attrs 
 | |
|             #	- for this object type
 | |
|             # get the object type decription from Schema.pm
 | |
|             my $datatype = $xCAT::Schema::defspec{$objtype};
 | |
|             foreach my $this_attr (@{$datatype->{'attrs'}}) {
 | |
|                 my $attr = $this_attr->{attr_name};
 | |
|                 if (scalar(@attrs) > 0) { # Only query specific attributes
 | |
|                     if (!grep(/^$attr$/, @attrs)) {
 | |
|                         next; # This attribute is not needed
 | |
|                     }
 | |
|                 }
 | |
|                 
 | |
|                 # table_attr is the attr that actually appears in the
 | |
|                 #  table which could possibly be different then the attr
 | |
|                 #  used in the node def
 | |
|                 # ex. 'nodetype.arch'
 | |
|                 my ($lookup_table, $table_attr) = split('\.', $this_attr->{tabentry});
 | |
|                 if (!grep(/^$table_attr$/, @{$tableattrs{$lookup_table}})) {
 | |
|                     push @{$tableattrs{$lookup_table}}, $table_attr;
 | |
|                 }
 | |
|             }
 | |
|             
 | |
|             # foreach table look up the list of attrs for this 
 | |
|             # list of object names
 | |
|             foreach my $table (keys %tableattrs) {
 | |
|                 # open the table
 | |
|                 my $thistable = xCAT::Table->new($table, -create => 1, -autocommit => 0);
 | |
|                 if (!$thistable) {
 | |
|                     my $rsp;
 | |
|                     $rsp->{data}->[0] = "Could not get the \'$thistable\' table.";
 | |
|                     xCAT::MsgUtils->message("E", $rsp, $::callback);
 | |
|                 }
 | |
|             
 | |
|                 my @objlist = @{$objtypelist{$objtype}};
 | |
|                 
 | |
|                 my $rec = $thistable->getNodesAttribs(\@objlist, @{$tableattrs{$table}});
 | |
|                 
 | |
|                 # fill in %tabhash with any values that are set
 | |
|                 foreach my $n (@objlist) {
 | |
|                 	my $tmp1=$rec->{$n}->[0];
 | |
|                 	foreach $a (@{$tableattrs{$table}}) {
 | |
|                         if (defined($tmp1->{$a})) {
 | |
|                             $tabhash{$table}{$n}{$a} = $tmp1->{$a};
 | |
|                             #print "obj = $n, table = $table, attr =$a, val = $tabhash{$table}{$n}{$a}\n";
 | |
|                         } else {
 | |
|                             # Add a has been searched flag to improve the performance
 | |
|                             $tabhash{$table}{$n}{"$a"."_hassearched"} = 1;
 | |
|                         }
 | |
|                 	}
 | |
|                 }
 | |
|                 #$thistable->commit;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     return %tabhash;
 | |
| }
 | |
| 
 | |
| #----------------------------------------------------------------------------
 | |
| 
 | |
| =head3   getobjdefs
 | |
| 
 | |
|         Get object definitions from the DB.
 | |
| 
 | |
|                 $type_hash: objectname=>objtype hash
 | |
|                 $verbose: optional
 | |
|                 $attrs_ref: only get the specific attributes,
 | |
|                             this can be useful especially for performance considerations
 | |
|         Arguments:
 | |
|         Returns:
 | |
|                 undef - error
 | |
|                 hash ref - $objecthash{objectname}{attrname} = value
 | |
|         Globals:
 | |
|         Error:
 | |
|         Example:
 | |
| 
 | |
| 		To use create hash for objectname and object type
 | |
|             ex. $objhash{$obj} = $type;
 | |
| 
 | |
|         - then call as follows:
 | |
| 			%myhash = xCAT::DBobjUtils->getobjdefs(\%objhash);
 | |
| 
 | |
|         Comments:
 | |
| 
 | |
| =cut
 | |
| 
 | |
| #-----------------------------------------------------------------------------
 | |
| sub getobjdefs
 | |
| {
 | |
|     my ($class, $hash_ref, $verbose, $attrs_ref) = @_;
 | |
|     my %objhash;
 | |
|     my %typehash = %$hash_ref;
 | |
|     my %tabhash;
 | |
|     my @attrs;
 | |
|     if (ref($attrs_ref))
 | |
|     {
 | |
|         @attrs = @$attrs_ref;
 | |
|     }
 | |
| 
 | |
|     @::foundTableList = ();
 | |
|     
 | |
|     if ($::ATTRLIST eq "none") {
 | |
|         # just return the list of obj names
 | |
|         foreach my $objname (sort (keys %typehash))
 | |
|         {
 | |
|             my $type = $typehash{$objname};
 | |
|             $objhash{$objname}{'objtype'} = $type;
 | |
|         }
 | |
|         return %objhash;
 | |
|     }
 | |
| 
 | |
|     # see if we need to get any objects of type 'node' 
 | |
|     my $getnodes=0;
 | |
|     foreach my $objname (keys %typehash) {
 | |
|         if ($typehash{$objname} eq 'node') {
 | |
|             $getnodes=1;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     # if so then get node info from tables now
 | |
|     #   still may need to look up values in some tables using
 | |
|     #   other keys - also need to figure out what tables to take
 | |
|     #   values from when using 'only_if' - see below
 | |
|     # - but this saves lots of time
 | |
|     if ($getnodes) {
 | |
|         if (scalar(@attrs) > 0) # Only get specific attributes of the node
 | |
|         {
 | |
|             # find the onlyif key for the attributes
 | |
|             REDO: my $datatype = $xCAT::Schema::defspec{'node'};
 | |
|             foreach my $this_attr (@{$datatype->{'attrs'}}) {
 | |
|                 my $attr = $this_attr->{attr_name};
 | |
|                 if (exists($this_attr->{only_if})) {
 | |
|                     my ($onlyif_key, $onlyif_value) = split('\=', $this_attr->{only_if});
 | |
|                     if (!grep (/^$onlyif_key$/, @attrs)) {
 | |
|                         push @attrs, $onlyif_key;
 | |
|                         goto REDO;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|             %tabhash = xCAT::DBobjUtils->getobjattrs(\%typehash, \@attrs);
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             %tabhash = xCAT::DBobjUtils->getobjattrs(\%typehash);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     # Classify the nodes with type
 | |
|     my %type_obj = ();
 | |
|     foreach my $objname (keys %typehash) {
 | |
|         push @{$type_obj{$typehash{$objname}}}, $objname;
 | |
|     }
 | |
| 
 | |
|     foreach my $objtype (sort (keys %type_obj)) {
 | |
|         if ($objtype eq 'site') {
 | |
|             my @TableRowArray = xCAT::DBobjUtils->getDBtable('site');
 | |
|             foreach my $objname (sort @{$type_obj{$objtype}}) {
 | |
|                 if (@TableRowArray)
 | |
|                 {
 | |
|                     my $foundinfo = 0;
 | |
|                     foreach (@TableRowArray)
 | |
|                     {
 | |
|                         if ($_->{key})
 | |
|                         {
 | |
|                             if (defined($_->{value}) ) {
 | |
|                                 $foundinfo++;
 | |
|                                 if ($verbose == 1) {
 | |
|                                     $objhash{$objname}{$_->{key}} = "$_->{value}\t(Table:site - Key:$_->{key})";
 | |
|                                 } else {
 | |
|                                     $objhash{$objname}{$_->{key}} = $_->{value};
 | |
|                                 }
 | |
|                             }
 | |
|                         }
 | |
|                     }
 | |
|                     if ($foundinfo)
 | |
|                     {
 | |
|                         $objhash{$objname}{'objtype'} = 'site';
 | |
|                     }
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     my $rsp;
 | |
|                     $rsp->{data}->[0] ="Could not read the \'$objname\' object from the \'site\' table.";
 | |
|                     xCAT::MsgUtils->message("E", $rsp, $::callback);	
 | |
|                 }
 | |
|             }
 | |
|         } elsif ($objtype eq 'monitoring') {
 | |
|             # need a special case for the monitoring table
 | |
|             # 	- need to check the monsetting table for entries that contain
 | |
|             #	 the same name as the monitoring table entry.
 | |
|             my @TableRowArray = xCAT::DBobjUtils->getDBtable('monsetting');
 | |
|             foreach my $objname (sort @{$type_obj{$objtype}}) {
 | |
|                 if (@TableRowArray) {
 | |
|                     my $foundinfo = 0;
 | |
|                     foreach (@TableRowArray) {                     
 | |
|                         if ($_->{name} eq $objname ) {
 | |
|                             if ($_->{key})
 | |
|                             {
 | |
|                                 if (defined($_->{value}) ) {
 | |
|                                     $foundinfo++;
 | |
|                                     if ($verbose == 1) {
 | |
|                                         $objhash{$objname}{$_->{key}} = "$_->{value}\t(Table:monsetting)";
 | |
|                                     } else {
 | |
|                                         $objhash{$objname}{$_->{key}} = $_->{value};
 | |
|                                     }
 | |
|                                 }
 | |
|                             }
 | |
|                         }
 | |
|                     }
 | |
|                     if ($foundinfo)
 | |
|                     {
 | |
|                         $objhash{$objname}{'objtype'} = 'monitoring';
 | |
|                     }
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     my $rsp;
 | |
|                     $rsp->{data}->[0] ="Could not read the \'$objname\' object from the \'monsetting\' table.";
 | |
|                     xCAT::MsgUtils->message("E", $rsp, $::callback);	
 | |
|                 }
 | |
|             }
 | |
|         } else {
 | |
|             # get the object type decription from Schema.pm
 | |
|             my $datatype = $xCAT::Schema::defspec{$objtype};
 | |
|             # get the key to look for, for this object type
 | |
|             my $objkey = $datatype->{'objkey'};
 | |
| 
 | |
|            # go through the list of valid attrs
 | |
|            foreach my $this_attr (@{$datatype->{'attrs'}})
 | |
|            {
 | |
|                 my $ent;
 | |
|                 my $attr = $this_attr->{attr_name};
 | |
|     
 | |
|                 # skip the key attr  ???
 | |
|                 if ($attr eq $objkey)
 | |
|                 {
 | |
|                     next;
 | |
|                 }
 | |
|                 # skip the attributes that does not needed for node type
 | |
|                 if ($getnodes) {
 | |
|                     if (scalar(@attrs) > 0 && !grep(/^$attr$/, @attrs)) {
 | |
|                         next;
 | |
|                     } 
 | |
|                 }
 | |
|  
 | |
|                 #  OK - get the info needed to access the DB table
 | |
|                 #   - i.e. table name, key name, attr names
 | |
|     
 | |
|                 # need the actual table attr name corresponding
 | |
|                 #   to the object attr name
 | |
|                 #  ex. noderes.nfsdir
 | |
|                 my ($tab, $tabattr) = split('\.', $this_attr->{tabentry});
 | |
|     
 | |
|                 foreach my $objname (sort @{$type_obj{$objtype}}) {
 | |
|                     # get table lookup info from Schema.pm
 | |
|                     #  !!!! some tables depend on the value of certain attrs
 | |
|                     #   we need to look up attrs in the correct order or we will
 | |
|                     #   not be able to determine what tables to look
 | |
|                     #	in for some attrs.
 | |
|                     if (exists($this_attr->{only_if}))
 | |
|                     {
 | |
|                          my ($check_attr, $check_value) = split('\=', $this_attr->{only_if});
 | |
|                          # if the object value is not the value we need
 | |
|                          #   to match then try the next only_if value
 | |
|                          next if ( !($objhash{$objname}{$check_attr} =~ /\b$check_value\b/) );
 | |
|                     }
 | |
|                     
 | |
|                     
 | |
|                     $objhash{$objname}{'objtype'} = $objtype;
 | |
|                     my %tabentry = ();
 | |
|                     # def commands need to support multiple keys in one table
 | |
|                     # the subroutine parse_access_tabentry is used for supporting multiple keys
 | |
|                     my $rc = xCAT::DBobjUtils->parse_access_tabentry($objname, 
 | |
|                                                                      $this_attr->{access_tabentry}, \%tabentry);
 | |
|                     if ($rc != 0)
 | |
|                     {
 | |
|                          my $rsp;
 | |
|                          $rsp->{data}->[0] =
 | |
|                            "access_tabentry \'$this_attr->{access_tabentry}\' is not valid.";
 | |
|                           xCAT::MsgUtils->message("E", $rsp, $::callback);
 | |
|                          next;
 | |
|                     }
 | |
|                     #
 | |
|                     # Only allow one table in the access_tabentry
 | |
|                     # use multiple tables to look up tabentry does not make any sense
 | |
|                     my $lookup_table = $tabentry{'lookup_table'};
 | |
|                     my $intabhash = 0;
 | |
|                     my $notsearched = 0;
 | |
|                     foreach my $lookup_attr (keys %{$tabentry{'lookup_attrs'}})
 | |
|                     {
 | |
|                         # Check whether the attribute is already in %tabhash
 | |
|                         # The %tabhash is for performance considerations
 | |
|                         if ( ($lookup_attr eq 'node') && ($objtype eq 'node') ){ 
 | |
|                             if (defined($tabhash{$lookup_table}{$objname}{$tabattr})) {
 | |
|                                 if ($verbose == 1)
 | |
|                                 {
 | |
|                                     $objhash{$objname}{$attr} = "$tabhash{$lookup_table}{$objname}{$tabattr}\t(Table:$lookup_table - Key:$lookup_attr - Column:$tabattr)";
 | |
|                                 }
 | |
|                                 else
 | |
|                                 {
 | |
|                                     $objhash{$objname}{$attr} = $tabhash{$lookup_table}{$objname}{$tabattr};
 | |
|                                 }
 | |
|                                 $intabhash = 1;
 | |
|                                 last;
 | |
|                             } elsif (! defined($tabhash{$lookup_table}{$objname}{"$tabattr"."_hassearched"})) {
 | |
|                                 $notsearched = 1;
 | |
|                             } 
 | |
|                         } else {
 | |
|                             $notsearched = 1;
 | |
|                         }
 | |
|                     }
 | |
| 
 | |
|                     # Not in tabhash,
 | |
|                     # Need to lookup the table
 | |
|                     if ($intabhash == 0 && $notsearched == 1)
 | |
|                     {
 | |
|                         # look up attr values
 | |
|                         my @rows = xCAT::DBobjUtils->getDBtable($lookup_table);
 | |
|                         if (@rows)
 | |
|                         {
 | |
|                             foreach my $rowent (@rows)
 | |
|                             {
 | |
|                                 my $match = 1;
 | |
|                                 my $matchedattr;
 | |
|                                 # Again, multiple keys support needs the "foreach"
 | |
|                                 foreach my $lookup_attr (keys %{$tabentry{'lookup_attrs'}})
 | |
|                                 {
 | |
|                                     if ($rowent->{$lookup_attr} ne $tabentry{'lookup_attrs'}{$lookup_attr})
 | |
|                                     {
 | |
|                                         $match = 0;
 | |
|                                         last;
 | |
|                                     }
 | |
|                                 }
 | |
|                                 if ($match == 1)
 | |
|                                 {
 | |
|                                      if ($verbose == 1)
 | |
|                                      {
 | |
|                                          my @lookup_attrs = keys %{$tabentry{'lookup_attrs'}};
 | |
|                                          $objhash{$objname}{$attr} = "$rowent->{$tabattr}\t(Table:$lookup_table - Key: @lookup_attrs - Column:$tabattr)";
 | |
|                                      }
 | |
|                                      else 
 | |
|                                      {
 | |
|                                          $objhash{$objname}{$attr} = $rowent->{$tabattr};
 | |
|                                      }
 | |
|                                  } #end if ($match...
 | |
|                             } #end foreach
 | |
|                         } # end if (defined...
 | |
|                     } #end if ($intabhash...
 | |
|                 }
 | |
| 
 | |
|             }
 | |
|         }
 | |
|         
 | |
|     } #foreach my $objtype
 | |
| 
 | |
|     return %objhash;
 | |
| }
 | |
| 
 | |
| #----------------------------------------------------------------------------
 | |
| 
 | |
| =head3   getDBtable
 | |
| 
 | |
|         Get a DB table, cache it , & return list of rows from the table.
 | |
| 
 | |
|         Arguments:
 | |
|         Returns:
 | |
|                 undef - error
 | |
|                 @rows - of table
 | |
|         Globals:
 | |
|         Error:
 | |
|         Example:
 | |
| 
 | |
|         call as follows
 | |
|           my @TableRowArray= xCAT::DBobjUtils->getDBtable($tablename); 
 | |
| 
 | |
|         Comments:
 | |
| 
 | |
| =cut
 | |
| 
 | |
| #-----------------------------------------------------------------------------
 | |
| sub getDBtable
 | |
| {
 | |
|     my ($class, $table) = @_;
 | |
|     my @rows = [];
 | |
| 
 | |
| 	# save this table info - in case this subr gets called multiple times
 | |
|     if (grep(/^$table$/, @::foundTableList))
 | |
|     {
 | |
| 
 | |
|         # already have this
 | |
|         @rows = @{$::TableHash{$table}};
 | |
| 
 | |
|     }
 | |
|     else
 | |
|     {
 | |
| 
 | |
|     	# need to get info from DB
 | |
|     	my $thistable = xCAT::Table->new($table, -create => 1, -autocommit => 0);
 | |
|     	if (!$thistable)
 | |
|     	{
 | |
|         	return undef;
 | |
|     	}
 | |
| 
 | |
|     	#@rows = $thistable->getTable;
 | |
| 	@rows = @{$thistable->getAllEntries()};
 | |
| 
 | |
|     	#   !!!! this routine returns rows even if the table is empty!!!!!!
 | |
| 
 | |
| 		#  keep track of the fact that we checked this table
 | |
|         #   - even if it's empty!
 | |
|         push(@::foundTableList, $thistable->{tabname});
 | |
| 
 | |
|         @{$::TableHash{$table}} = @rows;
 | |
| 
 | |
|     	#$thistable->commit;
 | |
| 
 | |
| 	} # end if not cached
 | |
| 
 | |
|    	if (@rows)
 | |
|    	{
 | |
|        	return @rows;
 | |
|    	}
 | |
|    	else
 | |
|    	{
 | |
|        	return undef;
 | |
|     }
 | |
| }
 | |
| 
 | |
| #----------------------------------------------------------------------------
 | |
| 
 | |
| =head3   setobjdefs
 | |
| 
 | |
|         Set the object definitions in the DB.
 | |
|             - Handles the Schema lookup and updating the DB tables.
 | |
| 
 | |
|         Arguments:
 | |
|         Returns:
 | |
|                 1 - error
 | |
|                 0 - OK
 | |
|         Globals:
 | |
|         Error:
 | |
|         Example:
 | |
| 
 | |
|         To use:
 | |
| 		 	-create hash for objectname and object type
 | |
|             	ex. $objhash{$object}{$attribute} = value;
 | |
| 
 | |
| 			-then call as follows:
 | |
| 				if (xCAT::DBobjUtils->setobjdefs(\%objhash) != 0)
 | |
| 
 | |
|         Comments:
 | |
| 
 | |
| =cut
 | |
| 
 | |
| #-----------------------------------------------------------------------------
 | |
| sub setobjdefs
 | |
| {
 | |
|     my ($class, $hash_ref) = @_;
 | |
|     my %objhash = %$hash_ref;
 | |
|     my %settableref;
 | |
|     my $ret = 0;
 | |
|     my %allupdates;
 | |
|     my $setattrs=0;
 | |
| 
 | |
|     # get the attr=vals for these objects from the DB - if any
 | |
|     #       - so we can figure out where to put additional attrs
 | |
|     # The getobjdefs call was in the foreach loop,
 | |
|     # it caused mkdef/chdef performance issue,
 | |
|     # so it is moved out of the foreach loop
 | |
| 
 | |
|     my %DBhash;
 | |
|     my @attrs;
 | |
|     foreach my $objname (keys %objhash)
 | |
|     {
 | |
|         my $type = $objhash{$objname}{objtype};
 | |
|         $DBhash{$objname} = $type;
 | |
|         @attrs = keys %{$objhash{$objname}};
 | |
|     }
 | |
| 
 | |
|     my %DBattrvals;
 | |
|     %DBattrvals = xCAT::DBobjUtils->getobjdefs(\%DBhash, 0, \@attrs);
 | |
| 
 | |
|     # for each object figure out:
 | |
|     #	- what tables to update
 | |
|     #	- which table attrs correspond to which object attrs
 | |
|     #	- what the keys are for each table
 | |
|     # update the tables a row at a time
 | |
|     foreach my $objname (keys %objhash)
 | |
|     {
 | |
| 
 | |
|         # get attr=val that are set in the DB ??
 | |
|         my $type = $objhash{$objname}{objtype};
 | |
| 
 | |
| 		# handle the monitoring table as a special case !!!!!
 | |
|         if ($type eq 'monitoring')
 | |
|         {
 | |
| 
 | |
|             # Get the names of the attrs stored in monitoring table
 | |
|             # get the object type decription from Schema.pm
 | |
|             my $datatype = $xCAT::Schema::defspec{$type};
 | |
|             
 | |
|             #  get a list of valid attr names
 | |
|             #  for this type object
 | |
|             my @attrlist;
 | |
|             foreach my $entry (@{$datatype->{'attrs'}})
 | |
|             {
 | |
|             	   push(@attrlist, $entry->{'attr_name'});
 | |
|             }
 | |
| 
 | |
|             # open the tables (monitoring and monsetting)
 | |
|             my $montable = xCAT::Table->new('monitoring', -create => 1, -autocommit => 0);
 | |
|             if (!$montable)
 | |
|             {
 | |
|                 my $rsp;
 | |
|                 $rsp->{data}->[0] = "Could not set the \'$montable\' table.";
 | |
|                 xCAT::MsgUtils->message("E", $rsp, $::callback);
 | |
|                 return 1;
 | |
|             }
 | |
|             # open the table
 | |
|             my $monsettable = xCAT::Table->new('monsetting', -create => 1, -autocommit => 0);
 | |
|             if (!$monsettable)
 | |
|             {
 | |
|                 my $rsp;
 | |
|                 $rsp->{data}->[0] = "Could not set the \'$monsettable\' table.";
 | |
|                 xCAT::MsgUtils->message("E", $rsp, $::callback);
 | |
|                 return 1;
 | |
|             }
 | |
| 
 | |
|             my %keyhash; 
 | |
|             my %updates;
 | |
|             
 | |
|             foreach my $attr (keys %{$objhash{$objname}})
 | |
|             {
 | |
|                 my $val;
 | |
|                 if ($attr eq 'objtype')
 | |
|                 {
 | |
|                     next;
 | |
|                 }
 | |
| 
 | |
|                 # determine the value if we have plus or minus
 | |
|                 if ($::plus_option)
 | |
|                 {
 | |
|                     # add new to existing - at the end - comma separated
 | |
|                     if (defined($DBattrvals{$objname}{$attr}))
 | |
|                     {
 | |
|                         $val = "$DBattrvals{$objname}{$attr},$objhash{$objname}{$attr}";
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         $val = "$objhash{$objname}{$attr}";
 | |
|                     }
 | |
|                 }
 | |
|                 elsif ($::minus_option)
 | |
|                 {
 | |
|                     # remove the specified list of values from the current
 | |
|                     #   attr values.
 | |
|                     if ($DBattrvals{$objname}{$attr})
 | |
|                     {
 | |
|                         # get the list of attrs to remove
 | |
|                         my @currentList = split(/,/, $DBattrvals{$objname}{$attr});
 | |
|                         my @minusList   = split(/,/, $objhash{$objname}{$attr});
 | |
| 
 | |
|                         # make a new list without the one specified
 | |
|                         my $first = 1;
 | |
|                         my $newlist;
 | |
|                         foreach my $i (sort @currentList)
 | |
|                         {
 | |
|                             chomp $i;
 | |
|                             if (!grep(/^$i$/, @minusList))
 | |
|                             {
 | |
|                                 # set new groups list for node
 | |
|                                 if (!$first)
 | |
|                                 {
 | |
|                                     $newlist .= ",";
 | |
|                                 }
 | |
|                                 $newlist .= $i;
 | |
|                                 $first = 0;
 | |
|                             }
 | |
|                         }
 | |
|                         $val = $newlist;
 | |
|                     }
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     #just set the attr to what was provided! - replace
 | |
|                     $val = $objhash{$objname}{$attr};
 | |
|                 }
 | |
| 
 | |
|                 if (grep(/^$attr$/, @attrlist)) {
 | |
|                     # if the attr belong in the monitoring tabel
 | |
|                     %keyhash=(name=>$objname);
 | |
|                     %updates=($attr=>$val);
 | |
|                     $montable->setAttribs(\%keyhash, \%updates);
 | |
|                 } else {
 | |
|                     # else it belongs in the monsetting table
 | |
|                     $keyhash{name} = $objname;
 | |
|                     $keyhash{key} = $attr;
 | |
|                     $updates{value} = $val;
 | |
|                     $monsettable->setAttribs(\%keyhash, \%updates);
 | |
|                 }
 | |
|             }
 | |
|                 
 | |
|             $montable->commit;
 | |
|             $monsettable->commit;
 | |
|             next;
 | |
|         } #if ($type eq 'monitoring')
 | |
| 
 | |
|         # handle the site table as a special case !!!!!
 | |
|         if ($type eq 'site')
 | |
|         {
 | |
|             # open the table
 | |
|             my $thistable =
 | |
|             xCAT::Table->new('site', -create => 1, -autocommit => 0);
 | |
|             if (!$thistable)
 | |
|             {
 | |
|                 my $rsp;
 | |
|                 $rsp->{data}->[0] = "Could not set the \'$thistable\' table.";
 | |
|                 xCAT::MsgUtils->message("E", $rsp, $::callback);
 | |
|                 return 1;
 | |
|             }
 | |
| 
 | |
|             foreach my $attr (keys %{$objhash{$objname}})
 | |
|             {
 | |
|                 if ($attr eq 'objtype')
 | |
|                 {
 | |
|                     next;
 | |
|                 }
 | |
| 
 | |
|                 my %keyhash;
 | |
|                 $keyhash{key} = $attr;
 | |
| 
 | |
|                 my $val;
 | |
|                 if ($::plus_option)
 | |
|                 {
 | |
|                     # add new to existing - at the end - comma separated
 | |
|                     if (defined($DBattrvals{$objname}{$attr}))
 | |
|                     {
 | |
|                         $val =
 | |
|                           "$DBattrvals{$objname}{$attr},$objhash{$objname}{$attr}";
 | |
|                     }
 | |
|                     else
 | |
|                     {
 | |
|                         $val = "$objhash{$objname}{$attr}";
 | |
|                     }
 | |
|                 }
 | |
|                 elsif ($::minus_option)
 | |
|                 {
 | |
|                     # remove the specified list of values from the current
 | |
|                     #   attr values.
 | |
|                     if ($DBattrvals{$objname}{$attr})
 | |
|                     {
 | |
|                         # get the list of attrs to remove
 | |
|                         my @currentList = split(/,/, $DBattrvals{$objname}{$attr});
 | |
|                         my @minusList   = split(/,/, $objhash{$objname}{$attr});
 | |
| 
 | |
|                         # make a new list without the one specified
 | |
|                         my $first = 1;
 | |
|                         my $newlist;
 | |
|                         foreach my $i (sort @currentList)
 | |
|                         {
 | |
|                             chomp $i;
 | |
|                             if (!grep(/^$i$/, @minusList))
 | |
|                             {
 | |
|                                 # set new groups list for node
 | |
|                                 if (!$first)
 | |
|                                 {
 | |
|                                     $newlist .= ",";
 | |
|                                 }
 | |
|                                 $newlist .= $i;
 | |
|                                 $first = 0;
 | |
|                             }
 | |
|                         }
 | |
|                         $val = $newlist;
 | |
|                     }
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
| 
 | |
|                     #just set the attr to what was provided! - replace
 | |
|                     $val = $objhash{$objname}{$attr};
 | |
| 
 | |
|                 }
 | |
| 
 | |
|                 if ( $val eq "") { # delete the line
 | |
|                     $thistable->delEntries(\%keyhash);
 | |
|                 }  else { # change the attr
 | |
|                 
 | |
|                 my %updates;
 | |
|                 $updates{value} = $val;
 | |
|                 
 | |
|                 my ($rc, $str) = $thistable->setAttribs(\%keyhash, \%updates);
 | |
|                 if (!defined($rc))
 | |
|                 {
 | |
|                     if ($::verbose)
 | |
|                     {
 | |
|                         my $rsp;
 | |
|                         $rsp->{data}->[0] =
 | |
|                         	"Could not set the \'$attr\' attribute of the \'$objname\' object in the xCAT database.";
 | |
|                         $rsp->{data}->[1] =
 | |
|                         	"Error returned is \'$str->errstr\'.";
 | |
|                         xCAT::MsgUtils->message("I", $rsp, $::callback);
 | |
|                     }
 | |
|                         $ret = 1;
 | |
|                     }
 | |
|                 }
 | |
| 
 | |
|             }
 | |
| 
 | |
|             $thistable->commit;
 | |
| 
 | |
|             next;
 | |
|         } #if ($type eq 'site')
 | |
| 
 | |
| 
 | |
| 
 | |
|         #
 | |
|         #  handle the rest of the object types
 | |
|         #
 | |
| 
 | |
|         # get the object type decription from Schema.pm
 | |
|         my $datatype = $xCAT::Schema::defspec{$type};
 | |
| 
 | |
| 		# get the object key to look for, for this object type
 | |
|         my $objkey = $datatype->{'objkey'};
 | |
| 
 | |
|         #  get a list of valid attr names
 | |
|         #     for this type object
 | |
|         my %attrlist;
 | |
|         foreach my $entry (@{$datatype->{'attrs'}})
 | |
|         {
 | |
|             push(@{$attrlist{$type}}, $entry->{'attr_name'});
 | |
|         }
 | |
| 
 | |
|         my @attrprovided=();
 | |
| 
 | |
|         # check FINALATTRS to see if all the attrs are valid
 | |
|         foreach my $attr (keys %{$objhash{$objname}})
 | |
|         {
 | |
| 
 | |
|             if ($attr eq $objkey)
 | |
|             {
 | |
|                 next;
 | |
|             }
 | |
| 
 | |
|             if ($attr eq "objtype")
 | |
|             {
 | |
|                 # objtype not stored in object definition
 | |
|                 next;
 | |
|             }
 | |
| 
 | |
|             if (!(grep /^$attr$/, @{$attrlist{$type}}))
 | |
|             {
 | |
|                 if ($::verbose)
 | |
|                 {
 | |
|                     my $rsp;
 | |
|                     $rsp->{data}->[0] =
 | |
|                       "\'$attr\' is not a valid attribute for type \'$type\'.";
 | |
|                     $rsp->{data}->[1] = "Skipping to the next attribute.";
 | |
|                     xCAT::MsgUtils->message("I", $rsp, $::callback);
 | |
|                 }
 | |
|                 next;
 | |
|             }
 | |
|             push(@attrprovided, $attr); 
 | |
|         }
 | |
| 
 | |
|         #   we need to figure out what table to
 | |
|         #      store each attr
 | |
|         #   And we must do this in the order given in defspec!!
 | |
| 
 | |
|         my @setattrlist=();
 | |
|         my @checkedattrs;
 | |
|         my $invalidattr;
 | |
| 
 | |
|         foreach my $this_attr (@{$datatype->{'attrs'}})
 | |
|         {
 | |
|             my %keyhash;
 | |
|             my %updates;
 | |
|             my %tabentry;
 | |
|             my ($lookup_table, $lookup_attr, $lookup_data);
 | |
|             my $attr_name = $this_attr->{attr_name};
 | |
| 
 | |
|             if ($attr_name eq $objkey)
 | |
|             {
 | |
|                 next;
 | |
|             }
 | |
| 
 | |
|             # if we have a value for this attribute then process it
 | |
|             #   - otherwise go to the next attr
 | |
|             if (defined($objhash{$objname}{$attr_name}))
 | |
|             {
 | |
|                 # check the defspec to see where this attr goes
 | |
| 
 | |
|                 # the table for this attr might depend on the
 | |
|                 #       value of some other attr
 | |
|                 # need to check the only_if entries to find one where the
 | |
|                 #       other attr value matches what we have
 | |
|                 #       ex. like if I want to set hdwctrlpoint I will have
 | |
|                 #               to match the right value for mgtmethod
 | |
|                 if (exists($this_attr->{only_if}))
 | |
|                 {
 | |
|                     my ($check_attr, $check_value) =
 | |
|                       split('\=', $this_attr->{only_if});
 | |
| 
 | |
|                     # if my attr value for the attr to check doesn't
 | |
|                     #   match this then try the next one
 | |
|                     # ex. say I want to set hdwctrlpoint, the table
 | |
|                     #   will depend on the mgtmethod attr - so I need
 | |
|                     #   to find the 'only_if' that matches the value
 | |
|                     #   specified for that attr (ex. mgtmethod=hmc)
 | |
| 
 | |
|                     # need to check the attrs we are setting for the object
 | |
|                     #   as well as the attrs for this object that may be
 | |
|                    	#   already set in DB
 | |
| 
 | |
|                     if ( !($objhash{$objname}{$check_attr})  && !($DBattrvals{$objname}{$check_attr}) ) {
 | |
|                         # if I didn't already check for this attr
 | |
|                         my $rsp;
 | |
|                         if (!grep(/^$attr_name$/, @checkedattrs)) {
 | |
|                             push @{$rsp->{data}}, "Cannot set the \'$attr_name\' attribute unless a value is provided for \'$check_attr\'.";
 | |
| 
 | |
|                             foreach my $tmp_attr (@{$datatype->{'attrs'}}) {
 | |
|                                 my $attr = $tmp_attr->{attr_name};
 | |
|                                 if ($attr eq $check_attr) {
 | |
|                                     my ($tab, $at) = split(/\./, $tmp_attr->{tabentry});
 | |
|                                     my $schema = xCAT::Table->getTableSchema($tab);
 | |
|                                     my $desc = $schema->{descriptions}->{$at};
 | |
|                                     push @{$rsp->{data}}, "$check_attr => $desc";
 | |
|                                 }
 | |
|                             }
 | |
|                         }
 | |
|                         xCAT::MsgUtils->message("I", $rsp, $::callback);
 | |
|                         push(@checkedattrs, $attr_name);
 | |
|                         if ( $invalidattr->{$attr_name}->{valid} ne 1 ) {
 | |
|                             $invalidattr->{$attr_name}->{valid} = 0;
 | |
|                             $invalidattr->{$attr_name}->{condition} = "\'$check_attr=$check_value\'";
 | |
|                         }
 | |
| 
 | |
|                         next;
 | |
|                     }
 | |
| 
 | |
|                     if ( !($objhash{$objname}{$check_attr} =~ /\b$check_value\b/) && !($DBattrvals{$objname}{$check_attr}  =~ /\b$check_value\b/) )
 | |
|                     {
 | |
|                         if ( $invalidattr->{$attr_name}->{valid} ne 1 ) {
 | |
|                             $invalidattr->{$attr_name}->{valid} = 0;
 | |
|                             $invalidattr->{$attr_name}->{condition} = "\'$check_attr=$check_value\'";
 | |
| 
 | |
|                         }
 | |
| 
 | |
|                         next;
 | |
|                     }
 | |
|                 }
 | |
|                 $invalidattr->{$attr_name}->{valid} = 1;
 | |
| 
 | |
|                 #  get the info needed to write to the DB table
 | |
|                 #
 | |
|                 # get the actual attr name to use in the table
 | |
|                 #    - may be different then the attr name used for the object.
 | |
|                 ($::tab, $::tabattr) = split('\.', $this_attr->{tabentry});
 | |
| 
 | |
|                 my $rc = xCAT::DBobjUtils->parse_access_tabentry($objname, 
 | |
|                                                                 $this_attr->{access_tabentry}, \%tabentry);
 | |
|                 if ($rc != 0)
 | |
|                 {
 | |
|                     my $rsp;
 | |
|                     $rsp->{data}->[0] =
 | |
|                       "access_tabentry \'$this_attr->{access_tabentry}\' is not valid.";
 | |
|                      xCAT::MsgUtils->message("E", $rsp, $::callback);
 | |
|                      next;
 | |
|                 }
 | |
|                 $lookup_table = $tabentry{'lookup_table'};
 | |
|                 # Set the lookup criteria for this attribute into %allupdates
 | |
|                 # the key is 'lookup_attrs'
 | |
|                 foreach my $lookup_attr (keys %{$tabentry{'lookup_attrs'}})
 | |
|                 {
 | |
|                     $allupdates{$lookup_table}{$objname}{$attr_name}{'lookup_attrs'}{$lookup_attr} 
 | |
|                                              =$tabentry{'lookup_attrs'}{$lookup_attr};
 | |
|                 }
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 next;
 | |
|             }
 | |
| 
 | |
|             my $val;
 | |
|             my $delim = ',';
 | |
|             if(($type eq 'group') && ($DBattrvals{$objname}{'grouptype'} eq 'dynamic')) 
 | |
|             {
 | |
|                 # dynamic node group selection string use "::" as delimiter
 | |
|                 $delim = '::';
 | |
|             }
 | |
|             
 | |
|             if ($::plus_option)
 | |
|             {
 | |
| 
 | |
|                 # add new to existing - at the end - comma separated
 | |
|                 if (defined($DBattrvals{$objname}{$attr_name}))
 | |
|                 {
 | |
|                     # add the attr into the list if it's not already in the list!
 | |
|                     # and avoid the duplicate values
 | |
|                     my @DBattrarray = split(/$delim/, $DBattrvals{$objname}{$attr_name});
 | |
|                     my @objhasharray = split(/$delim/, $objhash{$objname}{$attr_name});
 | |
|                     foreach my $objattr (@objhasharray)
 | |
|                     {
 | |
|                         if (!grep(/^\Q$objattr\E$/, @DBattrarray))
 | |
|                         {
 | |
|                             push @DBattrarray, $objattr;
 | |
|                         }
 | |
|                      }
 | |
|                      $val = join($delim, @DBattrarray);
 | |
|                 }
 | |
|                 else
 | |
|                 {
 | |
|                     $val = "$objhash{$objname}{$attr_name}";
 | |
|                 }
 | |
| 
 | |
|             }
 | |
|             elsif ($::minus_option)
 | |
|             {
 | |
| 
 | |
|                 # remove the specified list of values from the current
 | |
|                 #	attr values.
 | |
|                 if ($DBattrvals{$objname}{$attr_name})
 | |
|                 {
 | |
| 
 | |
|                     # get the list of attrs to remove
 | |
|                     my @currentList =
 | |
|                       split(/$delim/, $DBattrvals{$objname}{$attr_name});
 | |
|                     my @minusList = split(/$delim/, $objhash{$objname}{$attr_name});
 | |
| 
 | |
|                     # make a new list without the one specified
 | |
|                     my $first = 1;
 | |
|                     my $newlist;
 | |
|                     foreach my $i (sort @currentList)
 | |
|                     {
 | |
|                         chomp $i;
 | |
|                         if (!grep(/^$i$/, @minusList))
 | |
|                         {
 | |
| 
 | |
|                             # set new list for node
 | |
|                             if (!$first)
 | |
|                             {
 | |
|                                 $newlist .= "$delim";
 | |
|                             }
 | |
|                             $newlist .= $i;
 | |
|                             $first = 0;
 | |
|                         }
 | |
|                     }
 | |
|                     $val = $newlist;
 | |
|                 }
 | |
| 
 | |
|             }
 | |
|             else
 | |
|             {
 | |
| 
 | |
|                 #just set the attr to what was provided! - replace
 | |
|                 $val = $objhash{$objname}{$attr_name};
 | |
| 
 | |
|             }
 | |
| 
 | |
|             # Set the values into %allupdates
 | |
|             # the key is 'tabattrs'
 | |
|             $allupdates{$lookup_table}{$objname}{$attr_name}{'tabattrs'}{$::tabattr} = $val;
 | |
|             $setattrs=1;
 | |
|             
 | |
|             push(@setattrlist, $attr_name);
 | |
| 
 | |
|         }    # end - foreach attribute
 | |
| 
 | |
|         my $rsp;
 | |
|         foreach my $att (keys %$invalidattr) {
 | |
|             if ( $invalidattr->{$att}->{valid} ne 1) {
 | |
| my $tt = $invalidattr->{$att}->{valid};
 | |
|                 push @{$rsp->{data}}, "Cannot set the attr=\'$att\' attribute unless $invalidattr->{$att}->{condition}.";
 | |
|                 xCAT::MsgUtils->message("E", $rsp, $::callback);
 | |
|             }
 | |
|         }
 | |
| 
 | |
| 
 | |
| # TODO - need to get back to this
 | |
| if (0) {
 | |
| 		#
 | |
| 		#  check to see if all the attrs got set
 | |
| 		#
 | |
| 
 | |
| 		my @errlist;
 | |
| 		foreach $a (@attrprovided)
 | |
|         {	
 | |
| 			#  is this attr was not set then add it to the error list
 | |
| 			if (!grep(/^$a$/, @setattrlist))
 | |
| 			{			
 | |
| 				push(@errlist, $a);
 | |
| 				$ret = 2;
 | |
| 			}
 | |
| 
 | |
| 		}
 | |
| 		if ($ret == 2) {
 | |
| 			my $rsp;
 | |
| 			$rsp->{data}->[0] = "Could not set the following attributes for the \'$objname\' definition in the xCAT database: \'@errlist\'";
 | |
| 			xCAT::MsgUtils->message("E", $rsp, $::callback);
 | |
| 		}
 | |
| 
 | |
| }
 | |
| 
 | |
|     }    # end - foreach object
 | |
| #==========================================================#
 | |
| #%allupdates structure:
 | |
| # for command: chdef -t node -o node1 groups=all 
 | |
| #              usercomment=ddee passwd.HMC=HMC 
 | |
| #              passwd.admin=cluster passwd.general=abc123
 | |
| # the %allupdates will be:
 | |
| #0  'ppcdirect'
 | |
| #1  HASH(0x12783d30)
 | |
| #   'node1' => HASH(0x12783cc4)
 | |
| #      'passwd.HMC' => HASH(0x12783ed4)
 | |
| #         'lookup_attrs' => HASH(0x12783f70)
 | |
| #            'hcp' => 'node1'
 | |
| #            'username' => 'HMC'
 | |
| #         'tabattrs' => HASH(0x12783e8c)
 | |
| #            'password' => 'HMC'
 | |
| #      'passwd.admin' => HASH(0x12783c64)
 | |
| #         'lookup_attrs' => HASH(0x12784000)
 | |
| #            'hcp' => 'node1'
 | |
| #            'username' => 'admin'
 | |
| #         'tabattrs' => HASH(0x12783f64)
 | |
| #            'password' => 'cluster'
 | |
| #      'passwd.general' => HASH(0x12783a6c)
 | |
| #         'lookup_attrs' => HASH(0x12784198)
 | |
| #            'hcp' => 'node1'
 | |
| #            'username' => 'general'
 | |
| #         'tabattrs' => HASH(0x12783aa8)
 | |
| #            'password' => 'abc123'
 | |
| #2  'nodelist'
 | |
| #3  HASH(0x127842b8)
 | |
| #   'node1' => HASH(0x12784378)
 | |
| #      'groups' => HASH(0x12784090)
 | |
| #         'lookup_attrs' => HASH(0x127844bc)
 | |
| #            'node' => 'node1'
 | |
| #         'tabattrs' => HASH(0x1277fd34)
 | |
| #            'groups' => 'all'
 | |
| #      'usercomment' => HASH(0x12784318)
 | |
| #         'lookup_attrs' => HASH(0x12780550)
 | |
| #            'node' => 'node1'
 | |
| #         'tabattrs' => HASH(0x127842f4)
 | |
| #            'comments' => 'ddee'
 | |
| #=================================================================#
 | |
| 	# now set the attribute values in the tables
 | |
| 	#   - handles all except site, monitoring & monsetting for now
 | |
| 	if ($setattrs) {
 | |
|             foreach my $table (keys %allupdates) {
 | |
|             
 | |
|             # get the keys for this table
 | |
|             my $schema = xCAT::Table->getTableSchema($table);
 | |
|             my $keys = $schema->{keys};
 | |
|             
 | |
|             # open the table
 | |
|             my $thistable = xCAT::Table->new($table, -create => 1, -autocommit => 0);
 | |
|             if (!$thistable) {
 | |
|             	my $rsp;
 | |
|             	$rsp->{data}->[0] = "Could not set the \'$thistable\' table.";
 | |
|             	xCAT::MsgUtils->message("E", $rsp, $::callback);
 | |
|             	return 1;
 | |
|             }
 | |
|             
 | |
|             # Special case for the postscripts table
 | |
|             # Does not set the postscripts to the postscripts table
 | |
|             # if the postscripts already in xcatdefaults
 | |
|             # for code logic, it will be clearer to put the special case into defch,
 | |
|             # but putting it into defch will introduce additional table access for postscripts table.
 | |
|             # accessing table is time consuming.
 | |
|             if ($table eq "postscripts") {
 | |
|                 my $xcatdefaultsps;
 | |
|                 my $xcatdefaultspbs;
 | |
|                 my @TableRowArray = xCAT::DBobjUtils->getDBtable('postscripts');
 | |
|                 if (@TableRowArray)
 | |
|                 {
 | |
|                     foreach my $tablerow (@TableRowArray)
 | |
|                     {
 | |
|                         if(($tablerow->{node} eq 'xcatdefaults') && !($tablerow->{disable}))
 | |
|                         {
 | |
|                             $xcatdefaultsps = $tablerow->{postscripts};
 | |
|                             $xcatdefaultspbs = $tablerow->{postbootscripts};
 | |
|                             last;
 | |
|                         }
 | |
|                     }
 | |
|                 }
 | |
|                 my @xcatdefps = split(/,/, $xcatdefaultsps);
 | |
|                 my @xcatdefpbs = split(/,/, $xcatdefaultspbs);
 | |
|                 foreach my $obj(keys %{$allupdates{$table}}) {
 | |
|                     if ($obj eq 'xcatdefaults') {
 | |
|                         #xcatdefaults can be treated as a node?
 | |
|                         next;
 | |
|                     }
 | |
|                     my @newps;
 | |
|                     if (defined($allupdates{$table}{$obj}{'postscripts'}) 
 | |
|                                    && defined($allupdates{$table}{$obj}{'postscripts'}{'tabattrs'}{'postscripts'})) {
 | |
|                         foreach my $tempps (split(/,/, $allupdates{$table}{$obj}{'postscripts'}{'tabattrs'}{'postscripts'})) {
 | |
|                             if (grep(/^$tempps$/, @xcatdefps)) {
 | |
|                                  my $rsp;
 | |
|                                  $rsp->{data}->[0] = "$obj: postscripts \'$tempps\' is already included in the \'xcatdefaults\'.";
 | |
|                                  xCAT::MsgUtils->message("E", $rsp, $::callback);
 | |
|                              } else {
 | |
|                                  push @newps, $tempps;
 | |
|                              }
 | |
|                         }
 | |
|                         $allupdates{$table}{$obj}{'postscripts'}{'tabattrs'}{'postscripts'} = join(',', @newps);
 | |
|                     }
 | |
|                     my @newpbs;
 | |
|                     if (defined($allupdates{$table}{$obj}{'postbootscripts'}) 
 | |
|                                      && defined($allupdates{$table}{$obj}{'postbootscripts'}{'tabattrs'}{'postbootscripts'})) {
 | |
|                         foreach my $temppbs (split(/,/, $allupdates{$table}{$obj}{'postbootscripts'}{'tabattrs'}{'postbootscripts'})) {
 | |
|                             if (grep(/^$temppbs$/, @xcatdefpbs)) {
 | |
|                                 my $rsp;
 | |
|                                 $rsp->{data}->[0] = "$obj: postbootscripts \'$temppbs\' is already included in the \'xcatdefaults\'.";
 | |
|                                 xCAT::MsgUtils->message("E", $rsp, $::callback);
 | |
|                             } else {
 | |
|                                 push @newpbs, $temppbs;
 | |
|                             }
 | |
|                         }
 | |
|                         $allupdates{$table}{$obj}{'postbootscripts'}{'tabattrs'}{'postbootscripts'} = join(',', @newpbs);
 | |
|                      }
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             my $commit_manually = 0;
 | |
|             my %node_updates;
 | |
|             OBJ: foreach my $obj (keys %{$allupdates{$table}}) {
 | |
|                 ROW: foreach my $row (keys %{$allupdates{$table}{$obj}}) {
 | |
|                     my %keyhash;
 | |
|                     my %updates;
 | |
|                     # make sure we have a value for each key
 | |
|                     foreach my $k (@$keys) {
 | |
|                         if (!$allupdates{$table}{$obj}{$row}{'lookup_attrs'}) {
 | |
|                             my $rsp;
 | |
|                             $rsp->{data}->[0] = "\nMissing required attribute values for the \'$obj\' object. The required attributes are: @$keys";
 | |
|                             xCAT::MsgUtils->message("E", $rsp, $::callback);
 | |
|                             $ret = 1;
 | |
|                             next ROW;
 | |
|                         }
 | |
|                     }
 | |
|                     
 | |
|                     # lookup keys in %hashkey
 | |
|                     # ex. $keyhash{'hcp'} = node1
 | |
|                     foreach my $key (keys %{$allupdates{$table}{$obj}{$row}{'lookup_attrs'}}) {
 | |
|                         $keyhash{$key} = $allupdates{$table}{$obj}{$row}{'lookup_attrs'}{$key};
 | |
|                     }
 | |
|                     
 | |
|                     # set values in %updates
 | |
|                     # ex. $updates{'groups'} = 'all,lpar'
 | |
|                     foreach my $attr (keys %{$allupdates{$table}{$obj}{$row}{'tabattrs'}}) {
 | |
|                         if (scalar(keys %keyhash) == 0 && $keyhash{'node'} && $keyhash{'node'} eq "node") {
 | |
|                             $node_updates{$obj}{$attr} = $allupdates{$table}{$obj}{$row}{'tabattrs'}{$attr};
 | |
|                         } else {
 | |
|                             $updates{$attr} = $allupdates{$table}{$obj}{$row}{'tabattrs'}{$attr};
 | |
|                         }
 | |
|                     }
 | |
| 
 | |
|                     # only uses the setAttribs to set attribute one by one when the obj type is NOT 'node'
 | |
|                     if (%updates) {
 | |
|                         $commit_manually = 1;
 | |
|                         my ($rc, $str) = $thistable->setAttribs(\%keyhash, \%updates);
 | |
|                     }
 | |
|                 } #end foreach my $row
 | |
|             } #end foreach my $obj
 | |
|             if ($commit_manually) {
 | |
|                 $thistable->commit;
 | |
|             }
 | |
|             if (%node_updates) {
 | |
|                 $thistable->setNodesAttribs(\%node_updates);
 | |
|             }
 | |
|         } #end forach my $table
 | |
|     }
 | |
|     return $ret;
 | |
| }
 | |
| 
 | |
| #----------------------------------------------------------------------------
 | |
| 
 | |
| =head3   rmobjdefs
 | |
| 
 | |
|         Remove object definitions from the DB.
 | |
| 
 | |
|         Arguments:
 | |
|         Returns:
 | |
|                 0 - OK
 | |
|                 1 - error
 | |
|         Globals:
 | |
|         Error:
 | |
|         Example:
 | |
| 
 | |
| 		To use create hash for object name and object type
 | |
|             ex. $objhash{$obj} = $type;
 | |
|         - then call as follows:
 | |
| 			xCAT::DBobjUtils->rmobjdefs(\%objhash);
 | |
| 
 | |
|         Comments:
 | |
| 
 | |
| =cut
 | |
| 
 | |
| #-----------------------------------------------------------------------------
 | |
| sub rmobjdefs
 | |
| {
 | |
|     my ($class, $hash_ref) = @_;
 | |
| 
 | |
|     my %tablehash;
 | |
| 
 | |
|     my %typehash = %$hash_ref;
 | |
| 
 | |
|     # get the attr=vals for these objects so we know how to
 | |
|     #   find what tables have to be modified
 | |
| 
 | |
|     foreach my $objname (sort (keys %typehash))
 | |
|     {
 | |
|         my $type = $typehash{$objname};
 | |
| 
 | |
|         # special handling for site table
 | |
|         if ($type eq 'site')
 | |
|         {
 | |
|             my %DBattrvals = xCAT::DBobjUtils->getobjdefs(\%typehash);
 | |
|             my $thistable =
 | |
|               xCAT::Table->new('site', -create => 1, -autocommit => 0);
 | |
|             my %keyhash;
 | |
|             foreach my $attr (keys %{$DBattrvals{$objname}})
 | |
|             {
 | |
| 
 | |
|                 # ex.  key = attr
 | |
|                 $keyhash{key} = $attr;
 | |
| 
 | |
|                 $thistable->delEntries(\%keyhash);
 | |
| 
 | |
|             }
 | |
|             $thistable->commit();
 | |
|             next;
 | |
|         }
 | |
| 
 | |
|         # get the object type decription from Schema.pm
 | |
|         my $datatype = $xCAT::Schema::defspec{$type};
 | |
| 
 | |
|         # go through the list of valid attrs
 | |
|         #  - need to delete the row with a $key value of $objname from $table
 | |
|         #  - make a hash containing $delhash{$table}{$key}= $objname
 | |
|         foreach my $this_attr (@{$datatype->{'attrs'}})
 | |
|         {
 | |
|             my $attr = $this_attr->{attr_name};
 | |
| 
 | |
|             # get table lookup info from Schema.pm
 | |
|             # def commands need to support multiple keys in one table
 | |
|             # the subroutine parse_access_tabentry is used for supporting multiple keys
 | |
|             my %tabentry = ();
 | |
|             my $rc = xCAT::DBobjUtils->parse_access_tabentry($objname, $this_attr->{access_tabentry}, \%tabentry);
 | |
|             if ($rc != 0)
 | |
|             {
 | |
|                 my $rsp;
 | |
|                 $rsp->{data}->[0] =
 | |
|                   "access_tabentry \'$this_attr->{access_tabentry}\' is not valid.";
 | |
|                  xCAT::MsgUtils->message("E", $rsp, $::callback);
 | |
|                  next;
 | |
|             }
 | |
| 
 | |
|             # Only allow one table in the access_tabentry
 | |
|             # use multiple tables to look up tabentry does not make any sense
 | |
|             my $lookup_table = $tabentry{'lookup_table'};
 | |
|             # The attr_name is the *def attribute name instead of db column
 | |
|             my $attr_name = $this_attr->{'attr_name'};
 | |
|             # we'll need table name, object name, attribute name and the lookup entries
 | |
|             # put this info in a hash - we'll process it later - below
 | |
|             foreach my $lookup_attr (keys %{$tabentry{'lookup_attrs'}})
 | |
|             {
 | |
|                 $tablehash{$lookup_table}{$objname}{$attr_name}{$lookup_attr} 
 | |
|                                     = $tabentry{'lookup_attrs'}{$lookup_attr};
 | |
|             }
 | |
| 
 | |
|         }
 | |
|     }
 | |
| #=============================================#
 | |
| # The tablehash looks like this
 | |
|  # DB<5> x %tablehash
 | |
|  # 'bootparams'
 | |
|  # HASH(0x1280828c)
 | |
|  #  'node1' => HASH(0x127bca50)
 | |
|  #     'addkcmdline' => HASH(0x127fb114)
 | |
|  #        'node' => 'node1'
 | |
|  #     'initrd' => HASH(0x127bcb40)
 | |
|  #        'node' => 'node1'
 | |
|  #     'kcmdline' => HASH(0x127fb24c)
 | |
|  #        'node' => 'node1'
 | |
|  #     'kernel' => HASH(0x127b2e80)
 | |
|  #        'node' => 'node1'
 | |
|  #  'testfsp' => HASH(0x1280e71c)
 | |
|  #     'addkcmdline' => HASH(0x1280e7a0)
 | |
|  #        'node' => 'testfsp'
 | |
|  #     'initrd' => HASH(0x1280e740)
 | |
|  #        'node' => 'testfsp'
 | |
|  #     'kcmdline' => HASH(0x1280e77c)
 | |
|  #        'node' => 'testfsp'
 | |
|  #     'kernel' => HASH(0x1280e758)
 | |
|  #        'node' => 'testfsp'
 | |
|  #...
 | |
|  # 'ppcdirect'
 | |
|  # HASH(0x1278fe1c)
 | |
|  #  'node1' => HASH(0x12808370)
 | |
|  #     'passwd.HMC' => HASH(0x128083e8)
 | |
|  #        'hcp' => 'node1'
 | |
|  #        'username' => 'HMC'
 | |
|  #     'passwd.admin' => HASH(0x128081c0)
 | |
|  #        'hcp' => 'node1'
 | |
|  #        'username' => 'admin'
 | |
|  #     'passwd.general' => HASH(0x128075d8)
 | |
|  #        'hcp' => 'node1'
 | |
|  #        'username' => 'general'
 | |
|  #  'testfsp' => HASH(0x12790620)
 | |
|  #     'passwd.HMC' => HASH(0x1280ee84)
 | |
|  #        'hcp' => 'testfsp'
 | |
|  #        'username' => 'HMC'
 | |
|  #     'passwd.admin' => HASH(0x128082f8)
 | |
|  #        'hcp' => 'testfsp'
 | |
|  #        'username' => 'admin'
 | |
|  #     'passwd.general' => HASH(0x1280843c)
 | |
|  #        'hcp' => 'testfsp'
 | |
|  #        'username' => 'general'
 | |
|  #...
 | |
| ##=========================================================#
 | |
|     # now for each table - clear the entry
 | |
|     foreach my $table (keys %tablehash)
 | |
|     {
 | |
|         my @all_keyhash;
 | |
| 
 | |
|         my $thistable =
 | |
|           xCAT::Table->new($table, -create => 1, -autocommit => 0);
 | |
| 
 | |
|         foreach my $obj (keys %{$tablehash{$table}}) {
 | |
|             my %keyhash;
 | |
|             foreach my $attr (keys %{$tablehash{$table}{$obj}})
 | |
|             {
 | |
|                 foreach my $key (keys %{$tablehash{$table}{$obj}{$attr}})
 | |
|                 {
 | |
| 
 | |
|                     # ex. $keyhash{node}=c68m3hvp01
 | |
|                     $keyhash{$key} = $tablehash{$table}{$obj}{$attr}{$key};
 | |
|                 }
 | |
|             }
 | |
|             push @all_keyhash, \%keyhash;
 | |
|         }
 | |
|         # ex. delete the c68m3hvp01 entry of the node column in the
 | |
|         #       nodelist table
 | |
|         $thistable->delEntries(\@all_keyhash);
 | |
| 
 | |
|         $thistable->commit();
 | |
|     }
 | |
| 
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| #----------------------------------------------------------------------------
 | |
| 
 | |
| =head3   readFileInput
 | |
| 
 | |
|         Process the command line input piped in from a file.
 | |
| 		 	(Support stanza or xml format.)
 | |
| 
 | |
|         Arguments:
 | |
|         Returns:
 | |
|                 0 - OK
 | |
|                 1 - error
 | |
|         Globals:
 | |
|         Error:
 | |
|         Example:
 | |
| 
 | |
|         Comments:
 | |
| 			Set @::fileobjtypes, @::fileobjnames, %::FILEATTRS
 | |
| 				(i.e.- $::FILEATTRS{objname}{attr}=val)
 | |
| 
 | |
| =cut
 | |
| 
 | |
| #-----------------------------------------------------------------------------
 | |
| sub readFileInput
 | |
| {
 | |
|     my ($class, $filedata) = @_;
 | |
| 	my ($objectname, $junk1, $junk2);
 | |
| 
 | |
|     @::fileobjnames = ();
 | |
| 
 | |
|     my @lines = split /\n/, $filedata;
 | |
| 
 | |
|     my $header = $lines[0];
 | |
| 
 | |
|     # to do
 | |
|     #if ($header =~/<xCAT data object stanza file>/) {
 | |
|     # do stanza file parsing
 | |
|     # } elsis ($header =~/<xCAT data object XML file>/) {
 | |
|     # do XML parsing
 | |
|     #}
 | |
| 
 | |
|     my $look_for_colon = 1;    # start with first line that has a colon
 | |
| 	my $objtype;
 | |
| 
 | |
|     foreach my $l (@lines)
 | |
|     {
 | |
| 
 | |
|         # skip blank and comment lines
 | |
|         next if ($l =~ /^\s*$/ || $l =~ /^\s*#/);
 | |
| 
 | |
|         # see if it's a stanza name
 | |
|         if (grep(/:\s*$/, $l))
 | |
|         {
 | |
| 
 | |
|             $look_for_colon = 0;    # ok - we have a colon
 | |
| 
 | |
|             ($objectname, $junk2) = split(/:/, $l);
 | |
| 
 | |
|             # if $junk2 is defined or there's an = 
 | |
|             if ($junk2 || grep(/=/, $objectname))
 | |
|             {
 | |
| 
 | |
|                 # error - invalid header $line in node definition file
 | |
|                 #         skipping to next node stanza
 | |
|                 # Skipping to the next valid header.
 | |
|                 $look_for_colon++;
 | |
|                 next;
 | |
|             }
 | |
| 
 | |
|             $objectname =~ s/^\s*//;    # Remove any leading whitespace
 | |
|             $objectname =~ s/\s*$//;    # Remove any trailing whitespace
 | |
| 
 | |
|             #  could have different default stanzas for different object types
 | |
| 
 | |
|             if ($objectname =~ /default/)
 | |
|             {
 | |
| 
 | |
|                 ($junk1, $objtype) = split(/-/, $objectname);
 | |
| 
 | |
|                 if ($objtype)
 | |
|                 {
 | |
|                     $objectname = 'default';
 | |
|                 }
 | |
| 
 | |
|                 next;
 | |
|             }
 | |
| 
 | |
|             push(@::fileobjnames, $objectname);
 | |
| 
 | |
|         }
 | |
|         elsif (($l =~ /^\s*(\w+)\s*=\s*(.*)\s*/) && (!$look_for_colon))
 | |
|         {
 | |
|             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 so createnode won't get upset
 | |
|             $val =~ s/^\s*"\s*//;
 | |
|             $val =~ s/\s*"\s*$//;
 | |
| 
 | |
|             if ($objectname eq "default")
 | |
|             {
 | |
| 
 | |
|                 # set the default for this attribute
 | |
|                 $::defAttrs{$objtype}{$attr} = $val;
 | |
| 
 | |
|             }
 | |
|             else
 | |
|             {
 | |
| 
 | |
|                 # set the value in the hash for this object
 | |
|                 $::FILEATTRS{$objectname}{$attr} = $val;
 | |
| 
 | |
|                 # if the attr being set is "objtype" then check
 | |
|                 # 	to see if we have any defaults set for this type
 | |
|                 # the objtype should be the first etntry in each stanza
 | |
|                 #	so after we set the defaults they will be overwritten
 | |
|                 #	by any values that appear in the rest of the stanza
 | |
|                 if ($attr eq 'objtype')
 | |
|                 {
 | |
|                     push(@::fileobjtypes, $val);
 | |
| 
 | |
|                     #  $val will be the object type ex. site, node etc.
 | |
|                     foreach my $a (keys %{$::defAttrs{$val}})
 | |
|                     {
 | |
| 
 | |
|                         # set the default values for this object hash
 | |
|                         $::FILEATTRS{$objectname}{$a} = $::defAttrs{$val}{$a};
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|         }
 | |
|         else
 | |
|         {
 | |
| 
 | |
|             # error - invalid line in node definition file
 | |
|             $look_for_colon++;
 | |
|         }
 | |
| 
 | |
|     }    # end while - go to next line
 | |
| 
 | |
|     return 0;
 | |
| 
 | |
| }
 | |
| 
 | |
| #----------------------------------------------------------------------------
 | |
| 
 | |
| =head3   getGroupMembers
 | |
| 
 | |
|         Get the list of members for the specified group.
 | |
| 
 | |
|         Arguments:
 | |
|         Returns:
 | |
|             undef - error
 | |
|             $members - comma-separated list of group members
 | |
|         Globals:
 | |
|         Error:
 | |
|         Example:
 | |
| 			To use:
 | |
|             - create hash for objectname and and attr values  (need group 
 | |
| 				name (object), and grouptype  & members attr values at a
 | |
| 				minimum.)
 | |
| 			
 | |
|                 ex. $objhash{$obj}{$attr} = value;
 | |
| 
 | |
|             - then call as follows:
 | |
|                 xCAT::DBobjUtils->getGroupMembers($objectname, \%objhash);
 | |
| 
 | |
|         Comments:
 | |
| 
 | |
| =cut
 | |
| 
 | |
| #-----------------------------------------------------------------------------
 | |
| sub getGroupMembers
 | |
| {
 | |
|     my ($class, $objectname, $hash_ref) = @_;
 | |
| 
 | |
|     my $members;
 | |
| 
 | |
|     my %objhash = %$hash_ref;
 | |
| 
 | |
|     # set 'static' as the dafault of nodetype
 | |
|     if (!defined($objhash{$objectname}{'grouptype'}) ||
 | |
|           $objhash{$objectname}{'grouptype'} eq "") {
 | |
|         $objhash{$objectname}{'grouptype'} = 'static';
 | |
|     }
 | |
| 
 | |
|     if ($objhash{$objectname}{'grouptype'} eq 'static')
 | |
|     {
 | |
| 
 | |
|         my $table = "nodelist";
 | |
| 
 | |
|         my @TableRowArray = xCAT::DBobjUtils->getDBtable($table);
 | |
| 
 | |
|         my $first = 1;
 | |
|         foreach (@TableRowArray)
 | |
|         {
 | |
| 
 | |
|             # if find the group name in the "groups" attr value then add the
 | |
|             #	 node name to the member list
 | |
|             #if ($_->{'groups'} =~ /$objectname/)
 | |
| 
 | |
|             my @nodeGroupList = split(',', $_->{'groups'});
 | |
|             if (grep(/^$objectname$/, @nodeGroupList))
 | |
| 
 | |
|             {
 | |
|                 chomp($_->{'node'});
 | |
|                 if (!$first)
 | |
|                 {
 | |
|                     $members .= ",";
 | |
|                 }
 | |
|                 $members .= $_->{'node'};
 | |
|                 $first = 0;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|     }
 | |
|     elsif ($objhash{$objectname}{'grouptype'} eq 'dynamic')
 | |
|     {
 | |
| 
 | |
|         # find all nodes that satisfy the criteria specified in "wherevals"
 | |
|         #	value
 | |
|         my %whereHash;
 | |
|         my %tabhash;
 | |
| 
 | |
|         # remove spaces and quotes so createnode won't get upset
 | |
|         #$val =~ s/^\s*"\s*//;
 | |
|         #$val =~ s/\s*"\s*$//;
 | |
| 
 | |
|         my @tmpWhereList = split('::', $objhash{$objectname}{'wherevals'});
 | |
|         my $rc = xCAT::Utils->parse_selection_string(\@tmpWhereList, \%whereHash);
 | |
|         if ($rc != 0)
 | |
|         {
 | |
|             my $rsp;
 | |
|             $rsp->{data}->[0] =
 | |
|               "The \'-w\' option has an incorrect attr*val pair.";
 | |
|             xCAT::MsgUtils->message("E", $rsp, $::callback);
 | |
|         }
 | |
| 
 | |
|         # see what nodes have these attr=values
 | |
|         # get a list of all nodes
 | |
|         my @tmplist = xCAT::DBobjUtils->getObjectsOfType('node');
 | |
| 
 | |
|         # create a hash of obj names and types
 | |
| 		my %tmphash;
 | |
|         foreach my $n (@tmplist)
 | |
|         {
 | |
|             $tmphash{$n} = 'node';
 | |
|         }
 | |
| 
 | |
|         # Only get the specific attributes of the node
 | |
|         my @whereattrs = keys %whereHash;
 | |
|         my %nodeattrhash = xCAT::DBobjUtils->getobjdefs(\%tmphash, 0, \@whereattrs);
 | |
| 
 | |
|         my $first = 1;
 | |
|         foreach my $objname (keys %nodeattrhash)
 | |
|         {
 | |
|             if (xCAT::Utils->selection_string_match(\%nodeattrhash, $objname, \%whereHash))
 | |
|             {
 | |
|                 chomp($objname);
 | |
|                 if (!$first)
 | |
|                 {
 | |
|                     $members .= ",";
 | |
|                 }
 | |
|                 $members .= $objname;
 | |
|                 $first = 0;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|     }
 | |
|     return $members;
 | |
| }
 | |
| 
 | |
| #----------------------------------------------------------------------------
 | |
| 
 | |
| =head3   getNetwkInfo
 | |
| 
 | |
|         Get the network info from the database for a list of nodes.
 | |
| 
 | |
|         Arguments:
 | |
|         Returns:
 | |
|                 undef
 | |
|                 hash ref - ex. $nethash{nodename}{networks attr name} = value
 | |
|         Globals:
 | |
|         Error:
 | |
|         Example:
 | |
| 
 | |
|                 %nethash = xCAT::DBobjUtils->getNetwkInfo(\@targetnodes);
 | |
| 
 | |
| 		Comments:
 | |
| 
 | |
| =cut
 | |
| 
 | |
| #-----------------------------------------------------------------------------
 | |
| sub getNetwkInfo
 | |
| {
 | |
| 	my ($class, $ref_nodes) = @_;
 | |
| 	my @nodelist    = @$ref_nodes;
 | |
| 
 | |
| 	my %nethash;
 | |
| 	my @attrnames;
 | |
| 
 | |
| 	# get the current list of network attrs (networks table columns)
 | |
|     my $datatype = $xCAT::Schema::defspec{'network'};
 | |
| 	foreach my $a (@{$datatype->{'attrs'}}) {
 | |
| 		my $attr = $a->{attr_name};
 | |
| 		push(@attrnames, $attr);
 | |
| 	}
 | |
| 
 | |
| 	# read the networks table
 | |
| 	my @TableRowArray = xCAT::DBobjUtils->getDBtable('networks');
 | |
| 	if (! @TableRowArray)
 | |
|     {
 | |
| 		return undef;
 | |
| 	}
 | |
| 
 | |
| 	# for each node - get the network info
 | |
| 	foreach my $node (@nodelist)
 | |
|     {
 | |
| 
 | |
| 		# get, check, split the node IP
 | |
| 		my $IP = xCAT::NetworkUtils->getipaddr($node);
 | |
| 		chomp $IP;
 | |
| 		unless (($IP =~ /\d+\.\d+\.\d+\.\d+/) || ($IP =~ /:/))
 | |
| 		{
 | |
|     		next;
 | |
| 		}
 | |
| 		my ($ia, $ib, $ic, $id) = split('\.', $IP);
 | |
| 
 | |
| 		# check the entries of the networks table
 | |
| 		# - if the bitwise AND of the IP and the netmask gives you 
 | |
| 		#	the "net" name then that is the entry you want.
 | |
| 		foreach (@TableRowArray) {
 | |
| 			my $NM = $_->{'mask'};
 | |
| 			my $net=$_->{'net'};
 | |
| 			chomp $NM;
 | |
| 			chomp $net;
 | |
| 
 | |
|                         if(xCAT::NetworkUtils->ishostinsubnet($IP, $NM, $net))
 | |
|                         {
 | |
| 				# fill in the hash - 
 | |
| 				foreach my $attr (@attrnames) {
 | |
| 					if ( defined($_->{$attr}) ) {
 | |
| 						$nethash{$node}{$attr} = $_->{$attr};
 | |
| 					}
 | |
|                                 }
 | |
|                                 next;
 | |
|                         }
 | |
|                             
 | |
| 		}
 | |
| 
 | |
| 	} #end - for each node
 | |
| 
 | |
| 	return %nethash;
 | |
| }
 | |
| #----------------------------------------------------------------------------
 | |
| 
 | |
| =head3   parse_access_tabentry
 | |
| 
 | |
|         Parse the access_tabentry field in Schema.pm.
 | |
|         We needs to support multiple keys in the table
 | |
|         Arguments:
 | |
|                 $objname: objectname=>objtype hash
 | |
|                 $access_tabentry: the access_tabentry defined in Schema.pm
 | |
|                 $tabentry_ref: return the parsed result through this hash ref 
 | |
|                                   The structure of the hash is:
 | |
|                                   {
 | |
|                                       'lookup_tables' => <table_name>
 | |
|                                       'lookup_attrs =>
 | |
|                                       {
 | |
|                                           'attr1' => 'val1'
 | |
|                                           'attr2' => 'val2'
 | |
|                                           ...
 | |
|                                        }
 | |
|                                   }
 | |
|         Returns:
 | |
|                 0 - success
 | |
|                 1 - failed
 | |
|         Globals:
 | |
|         Error:
 | |
|         Example:
 | |
| 
 | |
| 		To parse the access_tabentry field
 | |
| 
 | |
|                 my $rc = xCAT::DBobjUtils->parse_access_tabentry($objname, $this_attr->{access_tabentry}, \%tabentry);
 | |
| 
 | |
|         Comments:
 | |
| 
 | |
| =cut
 | |
| 
 | |
| #-----------------------------------------------------------------------------
 | |
| sub parse_access_tabentry()
 | |
| {
 | |
|     my ($class, $objname, $access_tabentry, $tabentry_ref) = @_;
 | |
| 
 | |
|     # ex. 'nodelist.node', 'attr:node'
 | |
|     foreach my $ent (split('::', $access_tabentry))
 | |
|     {
 | |
|         # ex. 'nodelist.node', 'attr:node'
 | |
|         my ($lookup_key, $lookup_value) = split('\=', $ent);
 | |
| 
 | |
|         # ex. 'nodelist', 'node'
 | |
|         my ($lookup_table, $lookup_attr) = split('\.', $lookup_key);
 | |
| 
 | |
|         # ex. 'attr', 'node'
 | |
|         my ($lookup_type, $lookup_data) = split('\:', $lookup_value);
 | |
| 
 | |
|         if (!defined($tabentry_ref->{'lookup_table'}))
 | |
|         {
 | |
|             $tabentry_ref->{'lookup_table'} = $lookup_table;
 | |
|         }
 | |
| 
 | |
|         # Only support one lookup table in the access_tabentry
 | |
|         # Do we need to support multiple tables in one access_tabentry ????
 | |
|         # has not seen any requirement...
 | |
|         if ($lookup_table ne $tabentry_ref->{'lookup_table'})
 | |
|         {
 | |
|             my $rsp;
 | |
|             $rsp->{data}->[0] =
 | |
|                   "The access_tabentry \"$access_tabentry\" is not valid, can not specify more than one tables to look up.";
 | |
|             xCAT::MsgUtils->message("E", $rsp, $::callback);
 | |
|             return 1;
 | |
|         }
 | |
| 
 | |
|        if ($lookup_type eq 'attr')
 | |
|        {
 | |
|            # TODO: may need to update in the future
 | |
|            # for now, the "val" in attr:val in 
 | |
|            # Schema.pm can only be the object name
 | |
|            # In the future, even if we need to change here,
 | |
|            # be caution about the performance
 | |
|            # looking up table is time consuming
 | |
|            $tabentry_ref->{'lookup_attrs'}->{$lookup_attr} = $objname;
 | |
|        }
 | |
|        elsif ($lookup_type eq 'str')
 | |
|        {
 | |
|            $tabentry_ref->{'lookup_attrs'}->{$lookup_attr} = $lookup_data;
 | |
|        } 
 | |
|        else
 | |
|        {
 | |
|            my $rsp;
 | |
|            $rsp->{data}->[0] =
 | |
|                  "The access_tabentry \"$access_tabentry\" is not valid, the lookup type can only be 'attr' or 'str'.";
 | |
|            xCAT::MsgUtils->message("E", $rsp, $::callback);
 | |
|            return 1;
 | |
|        }
 | |
|     }
 | |
|     return 0;
 | |
| }
 | |
| 1;
 |