mirror of
https://github.com/xcat2/xcat-core.git
synced 2025-05-31 10:06:39 +00:00
2721 lines
98 KiB
Perl
Executable File
2721 lines
98 KiB
Perl
Executable File
#!/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;
|
|
|
|
require xCAT::NodeRange;
|
|
require xCAT::Schema;
|
|
require xCAT::Table;
|
|
require xCAT::Utils;
|
|
require xCAT::MsgUtils;
|
|
require xCAT::NetworkUtils;
|
|
require xCAT::ServiceNodeUtils;
|
|
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;
|
|
}
|
|
|
|
# The database may be changed between getObjectsOfType calls
|
|
# do not use cache %::saveObjList if --nocache is specified
|
|
if ($::saveObjList{$type} && !$::opt_nc) {
|
|
@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
|
|
# with autocommit => 0, it does not work on Ubuntu running mysql
|
|
my $thistable = xCAT::Table->new($table, -create => 1, -autocommit => 1);
|
|
if (!$thistable) {
|
|
my $rsp;
|
|
$rsp->{data}->[0] = "Could not open the \'$table\' table.";
|
|
xCAT::MsgUtils->message("E", $rsp, $::callback);
|
|
next;
|
|
}
|
|
|
|
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
|
|
$chname_ref: used to get the table entries for changing the object name
|
|
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, $chname_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);
|
|
}
|
|
}
|
|
} elsif (($objtype eq 'auditlog') || ($objtype eq 'eventlog')) {
|
|
|
|
# Special case for auditlog/eventlog
|
|
# All the auditlog/eventlog attributes are in auditlog/eventlog table,
|
|
# Do not need to read the table multiple times for each attribute.
|
|
# The auditlog/eventlog is likely be very big over time,
|
|
# performance is a big concern with the general logic
|
|
my @TableRowArray = xCAT::DBobjUtils->getDBtable($objtype);
|
|
foreach my $objname (sort @{ $type_obj{$objtype} }) {
|
|
if (@TableRowArray) {
|
|
my $foundinfo = 0;
|
|
foreach my $entry (@TableRowArray) {
|
|
if ($entry->{recid} eq $objname) {
|
|
foreach my $k (keys %{$entry}) {
|
|
|
|
# recid is the object name, do not need to be in the attributes list
|
|
if ($k eq 'recid') { next; }
|
|
if (defined($entry->{$k})) {
|
|
$foundinfo++;
|
|
if ($verbose == 1) {
|
|
$objhash{$objname}{$k} = "$entry->{$k}\t(Table:$objtype - Key:$k)";
|
|
} else {
|
|
$objhash{$objname}{$k} = $entry->{$k};
|
|
}
|
|
}
|
|
}
|
|
if ($foundinfo) {
|
|
$objhash{$objname}{'objtype'} = $objtype;
|
|
}
|
|
|
|
# There should not be multiple entries with the same recid
|
|
last;
|
|
} # end if($entry->
|
|
} # end foreach my $entry
|
|
} # end if(@TableTowArray
|
|
} # end foreach my $objname
|
|
} 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
|
|
my $tabspec = $xCAT::Schema::tabspec{$lookup_table};
|
|
my $nodecol = $tabspec->{'nodecol'} if defined($tabspec->{'nodecol'});
|
|
if (($lookup_attr eq 'node' && $objtype eq 'node') || (defined($nodecol) && $objtype eq 'node' && $lookup_table ne 'ppcdirect')) {
|
|
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};
|
|
}
|
|
if (defined $chname_ref) {
|
|
push @{ $chname_ref->{$lookup_table} }, ($tabentry{'lookup_attrs'}, $lookup_attr);
|
|
}
|
|
$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};
|
|
}
|
|
if (defined $chname_ref) {
|
|
push @{ $chname_ref->{$lookup_table} }, ($tabentry{'lookup_attrs'}, (keys %{ $tabentry{'lookup_attrs'} })[0]);
|
|
}
|
|
} #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
|
|
# --nocache flag specifies not to use cahe
|
|
if (grep(/^$table$/, @::foundTableList) && !$::opt_nc) {
|
|
|
|
# already have this
|
|
@rows = @{ $::TableHash{$table} };
|
|
|
|
} else {
|
|
|
|
# need to get info from DB
|
|
my $thistable = xCAT::Table->new($table, -create => 1);
|
|
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) {
|
|
|
|
my $obj_need_update = 0;
|
|
# 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 (@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;
|
|
$objhash{$objname}{updated} = 1;
|
|
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 (@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;
|
|
}
|
|
}
|
|
|
|
}
|
|
unless ($ret) {
|
|
$objhash{$objname}{updated} = 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'});
|
|
$attrlist{$type}{ $entry->{'attr_name'} } = 1;
|
|
}
|
|
|
|
my @attrprovided = ();
|
|
#get group objects data
|
|
my %DBgroupsattr;
|
|
my %tmpghash;
|
|
my @tmplgrplist;
|
|
my %grpvalidattr;
|
|
if (defined($objhash{$objname}{'groups'})){
|
|
|
|
@tmplgrplist = split(",", $objhash{$objname}{'groups'});
|
|
foreach my $tmpgrp (@tmplgrplist) {
|
|
$tmpghash{$tmpgrp} = "group";
|
|
}
|
|
%DBgroupsattr=xCAT::DBobjUtils->getobjdefs(\%tmpghash);
|
|
}
|
|
|
|
# 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 (!defined($attrlist{$type}{$attr})) {
|
|
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 (!defined($checkedattrs{$attr_name})) {
|
|
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";
|
|
}
|
|
}
|
|
}
|
|
$checkedattrs{$attr_name} = 1;
|
|
if ($invalidattr->{$attr_name}->{valid} != 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} != 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.
|
|
my $ntab;
|
|
($ntab, $::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);
|
|
$objhash{$objname}{error} = 1;
|
|
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});
|
|
|
|
my $operation_failed = 0;
|
|
foreach my $em (@minusList) {
|
|
if (!(grep { $_ eq $em } @currentList)) {
|
|
if (($::opt_t eq 'group') && ($DBattrvals{$objname}{'grouptype'} ne 'dynamic')) {
|
|
my $rsp;
|
|
$rsp->{data}->[0] = "$objname is not a member of \'$em\'.";
|
|
xCAT::MsgUtils->message("E", $rsp, $::callback);
|
|
$operation_failed = 1;
|
|
} else {
|
|
my $rsp;
|
|
$rsp->{data}->[0] = "$em is not in the attribute of \'$attr_name\' for the \'$objname\' definition.";
|
|
xCAT::MsgUtils->message("E", $rsp, $::callback);
|
|
$operation_failed = 1;
|
|
}
|
|
}
|
|
}
|
|
if ($operation_failed) {
|
|
$objhash{$objname}{error} = 1;
|
|
next;
|
|
}
|
|
|
|
# make a new list without the one specified
|
|
my $first = 1;
|
|
my $newlist;
|
|
foreach my $i (@currentList) {
|
|
chomp $i;
|
|
if (!grep(/^\Q$i\E$/, @minusList)) {
|
|
|
|
# set new list for node
|
|
if (!$first) {
|
|
$newlist .= "$delim";
|
|
}
|
|
$newlist .= $i;
|
|
$first = 0;
|
|
}
|
|
}
|
|
$val = $newlist;
|
|
}
|
|
else {
|
|
my $rsp;
|
|
$rsp->{data}->[0] = "No value got for attribute \'$attr_name\' for the \'$objname\' definition.";
|
|
xCAT::MsgUtils->message("E", $rsp, $::callback);
|
|
next;
|
|
}
|
|
|
|
} 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;
|
|
$obj_need_update = 1;
|
|
push(@setattrlist, $attr_name);
|
|
|
|
} # end - foreach attribute
|
|
if ($obj_need_update) {
|
|
$objhash{$objname}{updated} = 1;
|
|
}
|
|
|
|
my $rsp;
|
|
foreach my $att (keys %$invalidattr) {
|
|
my $pickvalidattr=0;
|
|
if ($invalidattr->{$att}->{valid} != 1) {
|
|
my $tt = $invalidattr->{$att}->{valid};
|
|
#if attribute is set invalid, check if its pre-check attribute exists in group objects, pick the attribute into valid.
|
|
# ex. if I want to set hdwctrlpoint I will have
|
|
# to match the right value for mgtmethod, but mgtmethod does exist in node object in chdef command
|
|
# if mgtmethod exists in group objects, set hdwctrlpoint valid
|
|
my $conditionkv=$invalidattr->{$att}->{condition};
|
|
$conditionkv=~s/(^'|'$)//g;
|
|
my ($attk, $attv)=split("=", $conditionkv);
|
|
foreach my $tmpgrp (@tmplgrplist) {
|
|
if ($DBgroupsattr{$tmpgrp}{$attk} eq $attv) {
|
|
$pickvalidattr=1;
|
|
last;
|
|
}
|
|
}
|
|
if ($pickvalidattr != 1) {
|
|
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} }) {
|
|
my %keyhash;
|
|
my %updates;
|
|
my $firsttime = 1;
|
|
ROW: foreach my $row (keys %{ $allupdates{$table}{$obj} }) {
|
|
|
|
# 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;
|
|
}
|
|
}
|
|
|
|
if ($firsttime) {
|
|
|
|
# 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};
|
|
}
|
|
$firsttime = 0;
|
|
} else {
|
|
|
|
# check if the look_attrs is the same as the %keyhash
|
|
foreach my $key (keys %{ $allupdates{$table}{$obj}{$row}{'lookup_attrs'} }) {
|
|
|
|
# The lookup_attrs can be different for tables with more than one keys such as ppcdirect
|
|
if ((scalar(keys %keyhash) != scalar(keys %{ $allupdates{$table}{$obj}{$row}{'lookup_attrs'} }))
|
|
|| !defined($keyhash{$key})
|
|
|| ($keyhash{$key} ne $allupdates{$table}{$obj}{$row}{'lookup_attrs'}{$key})) {
|
|
|
|
# different keys, set the existing attributes into database
|
|
# update the %keyhash and clean up the %updates hash
|
|
if (%updates) {
|
|
$commit_manually = 1;
|
|
my ($rc, $str) = $thistable->setAttribs(\%keyhash, \%updates);
|
|
}
|
|
foreach my $key (keys %{ $allupdates{$table}{$obj}{$row}{'lookup_attrs'} }) {
|
|
$keyhash{$key} = $allupdates{$table}{$obj}{$row}{'lookup_attrs'}{$key};
|
|
}
|
|
%updates = ();
|
|
}
|
|
}
|
|
}
|
|
|
|
# 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};
|
|
}
|
|
}
|
|
|
|
} #end foreach my $row
|
|
# 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 $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} }) {
|
|
|
|
#multiple keys support
|
|
if (defined($keyhash{$key}) && ($keyhash{$key} ne $tablehash{$table}{$obj}{$attr}{$key})) {
|
|
my %tmpkeyhash;
|
|
|
|
# copy hash
|
|
foreach my $hashkey (keys %keyhash) {
|
|
$tmpkeyhash{$hashkey} = $keyhash{$hashkey};
|
|
}
|
|
push @all_keyhash, \%tmpkeyhash;
|
|
|
|
#$thistable->delEntries(\@all_keyhash);
|
|
}
|
|
|
|
# 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
|
|
|
|
# Remove any trailing whitespace
|
|
$l =~ s/\s*$//;
|
|
|
|
# IPv6 network names could be something like fd59::/64
|
|
# Use all the characters before the last ":" as the object name
|
|
# .* means greedy regular expression
|
|
$l =~ /^(.*):(.*?)$/;
|
|
($objectname, $junk2) = ($1, $2);
|
|
|
|
# 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*(.*?)\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);
|
|
|
|
# The attribute 'node' can be used as a key of selection string,
|
|
# however, the 'node' attribute is not included in the getobjdefs hash
|
|
foreach my $objname (keys %nodeattrhash) {
|
|
$nodeattrhash{$objname}{'node'} = $objname;
|
|
}
|
|
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};
|
|
}
|
|
}
|
|
if ($nethash{$node}{'gateway'} eq '<xcatmaster>') {
|
|
if (xCAT::NetworkUtils->ip_forwarding_enabled()) {
|
|
$nethash{$node}{'gateway'} = xCAT::NetworkUtils->my_ip_in_subnet($net, $NM);
|
|
} else {
|
|
$nethash{$node}{'gateway'} = '';
|
|
}
|
|
$nethash{$node}{'myselfgw'} = 1;
|
|
|
|
# For hwctrl commands, it is possible that this subroutine is called
|
|
# on MN instead of SN, if the hcp SN is not set
|
|
if (xCAT::Utils->isMN() && !$nethash{$node}{'gateway'}) {
|
|
|
|
# does not have ip address in this subnet,
|
|
# use the node attribute 'xcatmaster' or site.master
|
|
my @nodes = ("$node");
|
|
my $sn = xCAT::ServiceNodeUtils->get_ServiceNode(\@nodes, "xcat", "Node");
|
|
my $snkey = (keys %{$sn})[0];
|
|
my $gw = xCAT::NetworkUtils->getipaddr($snkey);
|
|
|
|
# two possible cases when this code is run:
|
|
# 1. flat cluster: ip forwarding is not enabled on MN
|
|
# 2. hw ctrl in hierarchy cluster, in which HCP SN is not set
|
|
# in either case, MN itself should not be the gateway
|
|
if (xCAT::NetworkUtils->thishostisnot($gw)) {
|
|
$nethash{$node}{'gateway'} = $gw;
|
|
}
|
|
}
|
|
|
|
}
|
|
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;
|
|
}
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
=head3 getchildren
|
|
Arguments:
|
|
single hostname
|
|
optional port number
|
|
Returns:
|
|
array of fsp/bpa hostnames (IPs)
|
|
if specified port, it will just return nodes within the port.
|
|
Globals:
|
|
%PPCHASH - HASH of nodename -> array of ip addresses
|
|
where the nodetype is fsp or bpa
|
|
Error:
|
|
$::RUNCMD_RC = 1;
|
|
Writes error to syslog
|
|
Example:
|
|
$c1 = getchildren($nodetocheck);
|
|
$c1 = getchildren($nodetocheck,$port);
|
|
Comments:
|
|
none
|
|
=cut
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
my %PPCHASH;
|
|
|
|
sub getchildren
|
|
{
|
|
my $parent = shift;
|
|
if (($parent) && ($parent =~ /xCAT::/)) {
|
|
$parent = shift;
|
|
}
|
|
$::RUNCMD_RC = 0;
|
|
my $port = shift;
|
|
my @tabletype = qw(ppc zvm);
|
|
my @children = ();
|
|
my @children_port = ();
|
|
if (!%PPCHASH) {
|
|
my $ppctab = xCAT::Table->new('ppc');
|
|
unless ($ppctab) { # cannot open the table return with error
|
|
xCAT::MsgUtils->message('S', "getchildren:Unable to open ppc table.\n");
|
|
$::RUNCMD_RC = 1;
|
|
return undef;
|
|
}
|
|
my @ps = $ppctab->getAllNodeAttribs([ 'node', 'parent', 'nodetype', 'hcp' ]);
|
|
foreach my $entry (@ps) {
|
|
my $p = $entry->{parent};
|
|
my $c = $entry->{node};
|
|
my $t = $entry->{nodetype};
|
|
if ($p and $c) {
|
|
if ($t) { # the nodetype exists in the ppc table, use it
|
|
if ($t eq 'fsp' or $t eq 'bpa') {
|
|
|
|
# build hash of ppc.parent -> ppc.node
|
|
push @{ $PPCHASH{$p} }, $c;
|
|
} elsif ($t eq 'blade') {
|
|
push @{ $PPCHASH{$c} }, $entry->{hcp};
|
|
}
|
|
} else { # go look in the nodetype table to find nodetype
|
|
my $type = getnodetype($c, "ppc");
|
|
if ($type eq 'fsp' or $type eq 'bpa') {
|
|
|
|
# build hash of ppc.parent -> ppc.node
|
|
push @{ $PPCHASH{$p} }, $c;
|
|
} elsif ($type eq "blade") {
|
|
push @{ $PPCHASH{$c} }, $entry->{hcp};
|
|
}
|
|
}
|
|
} # not $p and $c
|
|
}
|
|
|
|
# Find parent in the hash and build return values
|
|
foreach (@{ $PPCHASH{$parent} }) {
|
|
push @children, $_;
|
|
}
|
|
} else {
|
|
if (exists($PPCHASH{$parent})) {
|
|
foreach (@{ $PPCHASH{$parent} }) {
|
|
push @children, $_;
|
|
}
|
|
}
|
|
}
|
|
|
|
# if port not input
|
|
if (!defined($port)) {
|
|
return \@children;
|
|
} else {
|
|
if (@children) {
|
|
my $vpdtab = xCAT::Table->new('vpd');
|
|
unless ($vpdtab) { # cannot open the table return with error
|
|
xCAT::MsgUtils->message('S', "getchildren:Unable to open vpd table.\n");
|
|
$::RUNCMD_RC = 1;
|
|
return undef;
|
|
}
|
|
my $sides = $vpdtab->getNodesAttribs(\@children, ['side']);
|
|
if (!$sides) {
|
|
return undef;
|
|
}
|
|
foreach my $n (@children) {
|
|
my $nside = $sides->{$n}->[0];
|
|
if ($nside->{side} =~ /$port/) {
|
|
push @children_port, $n;
|
|
}
|
|
}
|
|
return \@children_port;
|
|
} else { # no children
|
|
return undef;
|
|
}
|
|
}
|
|
}
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
=head3 getnodetype
|
|
Query ppc table, if no type found query nodetype table
|
|
Arguments:
|
|
An array of nodenames or 1 nodename
|
|
Returns:
|
|
If the input is an array, it returns a hash,
|
|
for the nodes that can't get node type, it will be 'node' => undef;
|
|
If the input is not an array, it returns the value of type,
|
|
for the node that can't get node type, it will be undef;
|
|
Globals:
|
|
%NODETYPEHASH
|
|
Error:
|
|
$::RUNCMD_RC = 1;
|
|
Errors written to syslog
|
|
Example:
|
|
$type = xCAT::DBobjUtils->getnodetype($node, "ppc");
|
|
$type = xCAT::DBobjUtils->getnodetype($node);
|
|
$typerefer = xCAT::DBobjUtils->getnodetype(\@nodes, "PPC");
|
|
$typerefer = xCAT::DBobjUtils->getnodetype(\@nodes);
|
|
Comments:
|
|
none
|
|
=cut
|
|
|
|
#-------------------------------------------------------------------------------
|
|
my %NODETYPEHASH;
|
|
|
|
sub getnodetype
|
|
{
|
|
my $nodes = shift;
|
|
if (($nodes) && ($nodes =~ /xCAT::/)) {
|
|
$nodes = shift;
|
|
}
|
|
my $table = shift;
|
|
my $rsp;
|
|
my @tabletype = qw(ppc zvm);
|
|
my %typehash;
|
|
my %tablehash;
|
|
$::RUNCMD_RC = 0;
|
|
|
|
my @failnodes;
|
|
my @failnodes1;
|
|
######################################################################
|
|
# if the table arg is set, go to the specified table first
|
|
# if can't get anything from the specified table, go to nodetype table
|
|
######################################################################
|
|
if ($table) {
|
|
my $nodetypetab = xCAT::Table->new($table);
|
|
unless ($nodetypetab) {
|
|
xCAT::MsgUtils->message('S', "getnodetype:Unable to open $table table.\n");
|
|
$::RUNCMD_RC = 1;
|
|
if ($nodes =~ /^ARRAY/) {
|
|
foreach my $tn (@$nodes) {
|
|
$typehash{$tn} = undef;
|
|
}
|
|
} else {
|
|
$typehash{$nodes} = undef;
|
|
}
|
|
return \%typehash;
|
|
}
|
|
############################################
|
|
# if the input node arg is an array,
|
|
# query table and don't use the global hash
|
|
############################################
|
|
if ($nodes =~ /^ARRAY/) {
|
|
my $nodetypes = $nodetypetab->getNodesAttribs($nodes, ['nodetype']);
|
|
foreach my $tn (@$nodes) {
|
|
my $gottype = $nodetypes->{$tn}->[0]->{'nodetype'};
|
|
if ($gottype) {
|
|
$NODETYPEHASH{$tn} = $gottype;
|
|
$typehash{$tn} = $gottype;
|
|
} else {
|
|
push @failnodes, $tn;
|
|
}
|
|
}
|
|
################################################
|
|
# for the failed nodes, go to nodetype table
|
|
################################################
|
|
if (@failnodes) {
|
|
my $typetable = xCAT::Table->new('nodetype');
|
|
unless ($typetable) { # cannot open the table return with error
|
|
xCAT::MsgUtils->message('S', "getnodetype:Unable to open nodetype table.\n");
|
|
$::RUNCMD_RC = 1;
|
|
foreach my $tn (@failnodes) {
|
|
$typehash{$tn} = undef;
|
|
}
|
|
} else {
|
|
my $nodetypes = $nodetypetab->getNodesAttribs(\@failnodes, ['nodetype']);
|
|
foreach my $tn (@failnodes) {
|
|
if ($nodetypes->{$tn}->[0]) {
|
|
$NODETYPEHASH{$tn} = $nodetypes->{$tn}->[0]->{'nodetype'};
|
|
$typehash{$tn} = $nodetypes->{$tn}->[0]->{'nodetype'};
|
|
} else {
|
|
push @failnodes1, $tn;
|
|
$typehash{$tn} = undef;
|
|
}
|
|
##################################################
|
|
# give error msg for the nodes can't get nodetype
|
|
##################################################
|
|
}
|
|
if (@failnodes1) {
|
|
my $nodelist = join(",", @failnodes1);
|
|
xCAT::MsgUtils->message('S', "getnodetype:Can't find these nodes' type: $nodelist.\n");
|
|
}
|
|
}
|
|
}
|
|
#####################
|
|
# return the result
|
|
#####################
|
|
return \%typehash;
|
|
|
|
} else {
|
|
############################################
|
|
# if the input node arg is not an array,
|
|
# query table and use the global hash first
|
|
############################################
|
|
if ($NODETYPEHASH{$nodes}) {
|
|
return $NODETYPEHASH{$nodes};
|
|
} else {
|
|
my $typep = $nodetypetab->getNodeAttribs($nodes, ['nodetype']);
|
|
if ($typep->{nodetype}) {
|
|
$NODETYPEHASH{$nodes} = $typep->{nodetype};
|
|
return $typep->{nodetype};
|
|
} else { #if not find in the specified table, go to nodetype table
|
|
my $typetable = xCAT::Table->new('nodetype');
|
|
unless ($typetable) { # cannot open the table return with error
|
|
xCAT::MsgUtils->message('S', "getnodetype:Unable to open nodetype table.\n");
|
|
$::RUNCMD_RC = 1;
|
|
return undef;
|
|
}
|
|
my $typep = $typetable->getNodeAttribs($nodes, ['nodetype']);
|
|
if ($typep->{nodetype}) {
|
|
$NODETYPEHASH{$nodes} = $typep->{nodetype};
|
|
return $typep->{nodetype};
|
|
} else {
|
|
return undef;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
######################################################################
|
|
# if the table arg is not set, go to the nodetype table first
|
|
# if can't get anything from the specified table, go to nodetype table
|
|
######################################################################
|
|
my $nodetypetab = xCAT::Table->new('nodetype');
|
|
unless ($nodetypetab) {
|
|
xCAT::MsgUtils->message('S', "getnodetype:Unable to open $table table.\n");
|
|
$::RUNCMD_RC = 1;
|
|
if ($nodes =~ /^ARRAY/) {
|
|
foreach my $tn (@$nodes) {
|
|
$typehash{$tn} = undef;
|
|
}
|
|
} else {
|
|
$typehash{$nodes} = undef;
|
|
}
|
|
return \%typehash;
|
|
}
|
|
############################################
|
|
# if the input node arg is an array,
|
|
# query table and don't use the global hash
|
|
############################################
|
|
if ($nodes =~ /^ARRAY/) {
|
|
my $nodetypes = $nodetypetab->getNodesAttribs($nodes, ['nodetype']);
|
|
foreach my $tn (@$nodes) {
|
|
my $gottype = $nodetypes->{$tn}->[0]->{'nodetype'};
|
|
if ($gottype) {
|
|
if ($gottype =~ /,/) { #if find ppc,osi
|
|
my @tbty = split /,/, $gottype;
|
|
foreach my $ttable (@tbty) {
|
|
if (grep(/$ttable/, @tabletype)) {
|
|
$tablehash{$tn} = $ttable;
|
|
last;
|
|
}
|
|
}
|
|
} elsif (grep(/$gottype/, @tabletype)) { #if find ppc or zvm
|
|
$tablehash{$tn} = $gottype;
|
|
} else {
|
|
$NODETYPEHASH{$tn} = $gottype;
|
|
$typehash{$tn} = $gottype;
|
|
}
|
|
} else {
|
|
$typehash{$tn} = undef;
|
|
}
|
|
}
|
|
################################################
|
|
# for the failed nodes, go to related tables
|
|
################################################
|
|
if (%tablehash) {
|
|
foreach my $ttable (@tabletype) {
|
|
my @nodegroup;
|
|
foreach my $fnode (keys %tablehash) {
|
|
if ($tablehash{$fnode} eq $ttable) {
|
|
push @nodegroup, $fnode;
|
|
}
|
|
}
|
|
next unless (@nodegroup);
|
|
my $typetable = xCAT::Table->new($ttable);
|
|
unless ($typetable) {
|
|
my $failnodes = join(",", @nodegroup);
|
|
xCAT::MsgUtils->message('S', "getnodetype:Unable to open $ttable table, can't find $failnodes type.\n");
|
|
$::RUNCMD_RC = 1;
|
|
foreach (@nodegroup) {
|
|
$typehash{$_} = undef;
|
|
}
|
|
} else {
|
|
my $typep = $typetable->getNodesAttribs(\@nodegroup, ['nodetype']);
|
|
foreach my $fn (@nodegroup) {
|
|
if ($typep->{$fn}->[0]->{'nodetype'}) {
|
|
$typehash{$fn} = $typep->{$fn}->[0]->{'nodetype'};
|
|
$NODETYPEHASH{$fn} = $typep->{$fn}->[0]->{'nodetype'};
|
|
} else {
|
|
$typehash{$fn} = undef;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return \%typehash;
|
|
} else { # if not an array
|
|
if ($NODETYPEHASH{$nodes}) {
|
|
return $NODETYPEHASH{$nodes};
|
|
} else {
|
|
my $typep = $nodetypetab->getNodeAttribs($nodes, ["nodetype"]);
|
|
if ($typep->{nodetype} and !(grep(/$typep->{nodetype}/, @tabletype))) {
|
|
$NODETYPEHASH{$nodes} = $typep->{nodetype};
|
|
return $typep->{nodetype};
|
|
} elsif (grep(/$typep->{nodetype}/, @tabletype)) {
|
|
my $typetable = xCAT::Table->new($typep->{nodetype});
|
|
unless ($typetable) {
|
|
xCAT::MsgUtils->message('S', "getnodetype:Unable to open nodetype table.\n");
|
|
$::RUNCMD_RC = 1;
|
|
return undef;
|
|
}
|
|
my $typep = $typetable->getNodeAttribs($nodes, ["nodetype"]);
|
|
if ($typep->{nodetype}) {
|
|
$NODETYPEHASH{$nodes} = $typep->{nodetype};
|
|
return $typep->{nodetype};
|
|
} else {
|
|
return undef;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
=head3 getcecchildren
|
|
returns cec of the specified frame,
|
|
Arguments:
|
|
frame name
|
|
Returns:
|
|
Array of cec hostnames
|
|
Globals:
|
|
%PARENT_CHILDREN_CEC
|
|
Error:
|
|
none
|
|
Example:
|
|
@frame_members = getcecchildren($frame);
|
|
Comments:
|
|
none
|
|
=cut
|
|
|
|
#-------------------------------------------------------------------------------
|
|
my %PARENT_CHILDREN_CEC;
|
|
|
|
sub getcecchildren
|
|
{
|
|
my $parent = shift;
|
|
if (($parent) && ($parent =~ /xCAT::/)) {
|
|
$parent = shift;
|
|
}
|
|
my @children = ();
|
|
if (!%PARENT_CHILDREN_CEC) {
|
|
my $ppctab = xCAT::Table->new('ppc');
|
|
unless ($ppctab) { # cannot open the table return with error
|
|
xCAT::MsgUtils->message('S', "getcecchildren:Unable to open ppc table.\n");
|
|
$::RUNCMD_RC = 1;
|
|
return undef;
|
|
}
|
|
if ($ppctab) {
|
|
my @ps = $ppctab->getAllNodeAttribs([ 'node', 'parent', 'nodetype' ]);
|
|
foreach my $entry (@ps) {
|
|
my $p = $entry->{parent};
|
|
my $c = $entry->{node};
|
|
my $t = $entry->{nodetype};
|
|
if ($p and $c) {
|
|
if ($t) { # the nodetype exists in the ppc table, use it
|
|
if ($t eq 'cec') {
|
|
|
|
# build hash of ppc.parent -> ppc.node
|
|
push @{ $PARENT_CHILDREN_CEC{$p} }, $c;
|
|
}
|
|
} else { # go look in the nodetype table to find nodetype
|
|
my $type = getnodetype($c);
|
|
if ($type eq 'cec') {
|
|
push @{ $PARENT_CHILDREN_CEC{$p} }, $c;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# find a match for the parent and build the return array
|
|
foreach (@{ $PARENT_CHILDREN_CEC{$parent} }) {
|
|
push @children, $_;
|
|
}
|
|
return \@children;
|
|
}
|
|
} else { # already built the HASH
|
|
if (exists($PARENT_CHILDREN_CEC{$parent})) {
|
|
foreach (@{ $PARENT_CHILDREN_CEC{$parent} }) {
|
|
push @children, $_;
|
|
}
|
|
return \@children;
|
|
}
|
|
}
|
|
return undef;
|
|
}
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
=head3 judge_node
|
|
judge the node is a real FSP/BPA,
|
|
use to distinguish if the data is defined in xCAT 2.5 or later
|
|
Arguments:
|
|
node name
|
|
Returns:
|
|
0 is a fake FSP/BPA,defined in xCAT 2.5
|
|
1 is a real FSP/BPA,defined in xCAT 2.6 or later
|
|
Error:
|
|
none
|
|
Example:
|
|
$result = judge_node($nodetocheck);
|
|
Comments:
|
|
none
|
|
=cut
|
|
|
|
#-------------------------------------------------------------------------------
|
|
sub judge_node
|
|
{
|
|
my $node = shift;
|
|
if (($node) && ($node =~ /xCAT::/)) {
|
|
$node = shift;
|
|
}
|
|
my $type = shift;
|
|
my $flag = 0;
|
|
my $parenttype;
|
|
my $nodeparent;
|
|
my $ppctab = xCAT::Table->new('ppc');
|
|
if ($ppctab) {
|
|
$nodeparent = $ppctab->getNodeAttribs($node, ["parent"]);
|
|
if ($nodeparent and $nodeparent->{parent}) {
|
|
$parenttype = getnodetype($nodeparent->{parent});
|
|
}
|
|
}
|
|
|
|
if ($type =~ /^fsp$/) {
|
|
if ($parenttype =~ /^cec$/) {
|
|
$flag = 1;
|
|
} else {
|
|
$flag = 0;
|
|
}
|
|
}
|
|
|
|
if ($type =~ /^bpa$/) {
|
|
if ($parenttype =~ /^frame$/) {
|
|
$flag = 1;
|
|
} else {
|
|
$flag = 0;
|
|
}
|
|
}
|
|
|
|
return $flag;
|
|
}
|
|
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
=head3 expandnicsattr
|
|
Expand the nics related attributes into the readable format,
|
|
for example, the nicsips=eth0!1.1.1.1|2.1.1.1,eth1!3.1.1.1|4.1.1.1
|
|
expanded format:
|
|
nicsips.eth0=1.1.1.1|2.1.1.1
|
|
nicsips.eth1=3.1.1.1|4.1.1.1
|
|
|
|
Arguments:
|
|
nicsattr value, like niccsips=eth0!1.1.1.1|2.1.1.1,eth1!3.1.1.1|4.1.1.1
|
|
node name, like frame10node10
|
|
nicnames: only return the value for specific nics, like "eth0,eth1"
|
|
is_group: bool value indicates whether the type of object is group
|
|
Returns:
|
|
expanded format, like:
|
|
nicsips.eth0=1.1.1.1|2.1.1.1
|
|
nicsips.eth1=3.1.1.1|4.1.1.1
|
|
Error:
|
|
none
|
|
|
|
Example:
|
|
my $nicsstr = xCAT::DBobjUtils->expandnicsattr($attrval);
|
|
|
|
Comments:
|
|
none
|
|
=cut
|
|
|
|
#-------------------------------------------------------------------------------
|
|
sub expandnicsattr()
|
|
{
|
|
my $nicstr = shift;
|
|
if (($nicstr) && ($nicstr =~ /xCAT::/)) {
|
|
$nicstr = shift;
|
|
}
|
|
my ($node, $nicnames, $is_group) = @_;
|
|
my $ret;
|
|
|
|
$nicstr =~ /^(.*?)=(.*?)$/;
|
|
|
|
#Attribute: nicips, nichostnamesuffix, etc.
|
|
my $nicattr = $1;
|
|
|
|
# Value: eth0!1.1.1.1|2.1.1.1,eth1!3.1.1.1|4.1.1.1
|
|
my $nicval = $2;
|
|
|
|
#if there is regrex in nicips
|
|
if (($nicval) && ($nicval =~ /^\|(.*?)\|$/)) {
|
|
|
|
#$nicval Value: |node(d+)|eth0!192.1.1.($1+10)| or
|
|
# |eth0!192.1.1.($1+10),bond0!10.28.41.($1+10)|
|
|
#In the lsdef, remove the ^| and |$ before displaying
|
|
$nicval =~ s/(^\||\|$)//g;
|
|
|
|
#$nicval Value: node(d+)|eth0!192.1.1.($1+10)
|
|
if (($nicval) && ($nicval =~ /\|/)) {
|
|
my ($str1, $str2) = split('\|', $nicval);
|
|
#$nivval Value: eth0!192.1.1.($1+10)
|
|
$nicval = $str2;
|
|
}
|
|
}
|
|
|
|
# $nicarr[0]: eth0!1.1.1.1|2.1.1.1
|
|
# $nicarr[1]: eth1!3.1.1.1|4.1.1.1
|
|
my @nicarr = split(/,/, $nicval);
|
|
|
|
foreach my $nicentry (@nicarr) {
|
|
|
|
#nicentry: eth0!1.1.1.1|2.1.1.1
|
|
# $nicv[0]: eth0
|
|
# $nicv[1]: 1.1.1.1|2.1.1.1
|
|
my @nicv = split(/!/, $nicentry);
|
|
|
|
# only return nic* attr for these specific nics
|
|
if ($nicnames) {
|
|
my @nics = split(/,/, $nicnames);
|
|
if ($nicv[0]) {
|
|
|
|
# Do not need to return the nic attr for this nic
|
|
if (!grep(/^$nicv[0]$/, @nics)) {
|
|
next;
|
|
}
|
|
}
|
|
}
|
|
# print group attributes in original format
|
|
if (!$is_group) {
|
|
$nicv[1]= xCAT::Table::transRegexAttrs($node, $nicv[1]);
|
|
}
|
|
# ignore the line that does not have nicname or value
|
|
if ($nicv[0] && $nicv[1]) {
|
|
$ret .= " $nicattr.$nicv[0]=$nicv[1]\n";
|
|
}
|
|
}
|
|
|
|
chomp($ret);
|
|
return $ret;
|
|
|
|
}
|
|
|
|
|
|
#-------------------------------------------------------------------------------
|
|
|
|
=head3 collapsenicsattr
|
|
Collapse the nics related attributes into the database format,
|
|
for example,
|
|
nicsips.eth0=1.1.1.1|2.1.1.1
|
|
nicsips.eth1=3.1.1.1|4.1.1.1
|
|
|
|
the collapsed format:
|
|
nicsips=eth0!1.1.1.1|2.1.1.1,eth1!3.1.1.1|4.1.1.1
|
|
|
|
The collapse will be done against the hash %::FILEATTRS or %::CLIATTRS,
|
|
remove the nicips.thx attributes from %::FILEATTRS or %::CLIATTRS,
|
|
add the collapsed info nicips into %::FILEATTRS or %::CLIATTRS.
|
|
|
|
Arguments:
|
|
$::FILEATTRS{$objname} or $::CLIATTRS{$objname}
|
|
$objname
|
|
|
|
Returns:
|
|
None, update %::FILEATTRS or %::CLIATTRS directly
|
|
|
|
Error:
|
|
none
|
|
|
|
Example:
|
|
xCAT::DBobjUtils->collapsenicsattr($nodeattrhash);
|
|
|
|
Comments:
|
|
none
|
|
=cut
|
|
|
|
#-------------------------------------------------------------------------------
|
|
sub collapsenicsattr()
|
|
{
|
|
my $nodeattrhash = shift;
|
|
if (($nodeattrhash) && ($nodeattrhash =~ /xCAT::/)) {
|
|
$nodeattrhash = shift;
|
|
}
|
|
my $objname = shift;
|
|
my %nicattrs = ();
|
|
foreach my $nodeattr (keys %{$nodeattrhash}) {
|
|
|
|
# e.g nicips.eth0
|
|
# do not need to handle nic attributes without the postfix .ethx,
|
|
# it will be overwritten by the attributes with the postfix .ethx,
|
|
if ($nodeattr =~ /^(nic\w+)\.(.*)$/) {
|
|
if ($1 && $2) {
|
|
|
|
# chdef <noderange> nicips.eth2= to remove the definition for eth2
|
|
# in this case, the $nodeattrhash->{'nicips.eth0'} is blank
|
|
# $nicattrs{nicips}{eth0} = "1.1.1.1|1.2.1.1"
|
|
$nicattrs{$1}{$2} = $nodeattrhash->{$nodeattr};
|
|
|
|
# remove nicips.eth0 from the %::FILEATTRS
|
|
delete $nodeattrhash->{$nodeattr};
|
|
}
|
|
}
|
|
}
|
|
|
|
# $nicattrs{'nicips'}{'eth0'} = "1.1.1.1|1.2.1.1"
|
|
# $nicattrs{'nicips'}{'eth1'} = "2.1.1.1|2.2.1.1"
|
|
foreach my $nicattr (keys %nicattrs) {
|
|
my @tmparray = ();
|
|
foreach my $nicname (keys %{ $nicattrs{$nicattr} }) {
|
|
|
|
# eth0!1.1.1.1|1.2.1.1
|
|
if ($nicattrs{$nicattr}{$nicname}) {
|
|
push @tmparray, "$nicname!$nicattrs{$nicattr}{$nicname}";
|
|
}
|
|
}
|
|
|
|
# eth0!1.1.1.1|1.2.1.1,eth1!2.1.1.1|2.2.1.1
|
|
$nodeattrhash->{$nicattr} = join(',', @tmparray);
|
|
}
|
|
}
|
|
|
|
1;
|