Add genericrange option to noderange function so we can remove NameRange.pm

git-svn-id: https://svn.code.sf.net/p/xcat/code/xcat-core/branches/2.8@16364 8638fb3e-16cb-4fca-ae20-7b5d299a9bcd
This commit is contained in:
bp-sawyers 2013-05-20 13:14:26 +00:00
parent ee3e6061f0
commit 7731929803
3 changed files with 55 additions and 307 deletions

View File

@ -1,271 +0,0 @@
# IBM(c) 2007 EPL license http://www.eclipse.org/legal/epl-v10.html
package xCAT::NameRange;
require xCAT::Table;
require Exporter;
use strict;
#Perl implementation of namerange
# NOTE: This is identical to xCAT::NodeRange except that no
# database access occurs, no nodes are verified, and
# no nodegroups are expanded.
# Made a new utility since NodeRange is used EVERYWHERE in
# xCAT code and did not want to risk de-stabilizing existing code.
our @ISA = qw(Exporter);
our @EXPORT = qw(namerange);
my $recurselevel=0;
sub subnodes (\@@) {
#Subtract set of nodes from the first list
my $nodes = shift;
my $node;
foreach $node (@_) {
@$nodes = (grep(!/^$node$/,@$nodes));
}
}
sub expandatom {
my $atom = shift;
my @nodes= ();
if ($atom =~ /^\(.*\)$/) { # handle parentheses by recursively calling namerange()
$atom =~ s/^\((.*)\)$/$1/;
$recurselevel++;
return namerange($atom);
}
if ($atom =~ /@/) {
$recurselevel++;
return namerange($atom);
}
if ($atom =~ m/^\//) { # A regular expression - not supported in namerange
return ($atom);
}
if ($atom =~ m/(.*)\[(.*)\](.*)/) { # square bracket range
#for the time being, we are only going to consider one [] per atom
#xcat 1.2 does no better
my @subelems = split(/([\,\-\:])/,$2);
my $subrange="";
while (my $subelem = shift @subelems) {
my $subop=shift @subelems;
$subrange=$subrange."$1$subelem$3$subop";
}
foreach (split /,/,$subrange) {
my @newnodes=expandatom($_);
@nodes=(@nodes,@newnodes);
}
return @nodes;
}
if ($atom =~ m/\+/) { # process the + operator
$atom =~ m/^([^0-9]*)([0-9]+)([^\+]*)\+([0-9]+)/;
my $pref=$1;
my $startnum=$2;
my $suf=$3;
my $end=$4+$startnum;
my $endnum = sprintf("%d",$end);
if (length ($startnum) > length ($endnum)) {
$endnum = sprintf("%0".length($startnum)."d",$end);
}
foreach ("$startnum".."$endnum") {
my @addnodes=expandatom($pref.$_.$suf);
@nodes=(@nodes,@addnodes);
}
return (@nodes);
}
if ($atom =~ m/[-:]/) { # process the minus range operator
my $left;
my $right;
if ($atom =~ m/:/) {
($left,$right)=split /:/,$atom;
} else {
my $count= ($atom =~ tr/-//);
if (($count % 2)==0) { #can't understand even numbers of - in range context
# we might not really be in range context
return ($atom);
}
my $expr="([^-]+?".("-[^-]*"x($count/2)).")-(.*)";
$atom =~ m/$expr/;
$left=$1;
$right=$2;
}
if ($left eq $right) { #if they said node1-node1 for some strange reason
return expandatom($left);
}
my @leftarr=split(/(\d+)/,$left);
my @rightarr=split(/(\d+)/,$right);
if (scalar(@leftarr) != scalar(@rightarr)) { #Mismatch formatting..
# guess it's meant to be a nodename
return ($atom);
}
my $prefix = "";
my $suffix = "";
foreach (0..$#leftarr) {
my $idx = $_;
if ($leftarr[$idx] =~ /^\d+$/ and $rightarr[$idx] =~ /^\d+$/) { #pure numeric component
if ($leftarr[$idx] ne $rightarr[$idx]) { #We have found the iterator (only supporting one for now)
my $prefix = join('',@leftarr[0..($idx-1)]); #Make a prefix of the pre-validated parts
my $luffix; #However, the remainder must still be validated to be the same
my $ruffix;
if ($idx eq $#leftarr) {
$luffix="";
$ruffix="";
} else {
$ruffix = join('',@rightarr[($idx+1)..$#rightarr]);
$luffix = join('',@leftarr[($idx+1)..$#leftarr]);
}
if ($luffix ne $ruffix) { #the suffixes mismatched..
return ($atom);
}
foreach ($leftarr[$idx]..$rightarr[$idx]) {
my @addnodes=expandatom($prefix.$_.$luffix);
@nodes=(@nodes,@addnodes);
}
return (@nodes); #the return has been built, return, exiting loop and all
}
} elsif ($leftarr[$idx] ne $rightarr[$idx]) {
return ($atom);
}
$prefix .= $leftarr[$idx]; #If here, it means that the pieces were the same, but more to come
}
#I cannot conceive how the code could possibly be here, but whatever it is, it must be questionable
return ($atom);
}
return ($atom);
}
sub namerange {
#We for now just do left to right operations
my $range=shift;
my %nodes = ();
my %delnodes = ();
my $op = ",";
my @elems = split(/(,(?![^[]*?])(?![^\(]*?\)))/,$range); # commas outside of [] or ()
if (scalar(@elems)==1) {
@elems = split(/(@(?![^\(]*?\)))/,$range); # only split on @ when no , are present (inner recursion)
}
while (my $atom = shift @elems) {
if ($atom =~ /^-/) { # if this is an exclusion, strip off the minus, but remember it
$atom = substr($atom,1);
$op = $op."-";
}
if ($atom =~ /^\^(.*)$/) { # get a list of nodes from a file
open(NRF,$1);
while (<NRF>) {
my $line=$_;
unless ($line =~ m/^[\^#]/) {
$line =~ m/^([^: ]*)/;
my $newrange = $1;
chomp($newrange);
$recurselevel++;
my @filenodes = namerange($newrange);
foreach (@filenodes) {
$nodes{$_}=1;
}
}
}
close(NRF);
next;
}
my %newset = map { $_ =>1 } expandatom($atom); # expand the atom and make each entry in the resulting array a key in newset
if ($op =~ /@/) { # compute the intersection of the current atom and the node list we have received before this
foreach (keys %nodes) {
unless ($newset{$_}) {
delete $nodes{$_};
}
}
} elsif ($op =~ /,-/) { # add the nodes from this atom to the exclude list
foreach (keys %newset) {
$delnodes{$_}=1; #delay removal to end
}
} else { # add the nodes from this atom to the total node list
foreach (keys %newset) {
$nodes{$_}=1;
}
}
$op = shift @elems;
} # end of main while loop
# Now remove all the exclusion nodes
foreach (keys %nodes) {
if ($delnodes{$_}) {
delete $nodes{$_};
}
}
if ($recurselevel) {
$recurselevel--;
}
return sort (keys %nodes);
}
1;
=head1 NAME
xCAT::NameRange - Perl module for xCAT namerange expansion
=head1 SYNOPSIS
use xCAT::NameRange;
my @nodes=namerange("storage@rack1,node[1-200],^/tmp/nodelist,node300-node400,node401+10,500-550");
=head1 DESCRIPTION
namerange interprets xCAT noderange formatted strings and returns a list of
names. The following two operations are supported on elements, and interpreted
left to right:
, union next element with everything to the left.
@ take intersection of element to the right with everything on the left
(i.e. mask out anything to the left not belonging to what is described to
the right)
Each element can be a number of things:
A node name, i.e.:
=item * node1
A hyphenated node range (only one group of numbers may differ between the left and right hand side, and those numbers will increment in a base 10 fashion):
node1-node200 node1-compute-node200-compute
node1:node200 node1-compute:node200-compute
A namerange denoted by brackets:
node[1-200] node[001-200]
A regular expression describing the namerange:
/d(1.?.?|200)
A node plus offset (this increments the first number found in nodename):
node1+199
And most of the above substituting groupnames.
3C
3C
NameRange tries to be intelligent about detecting padding, so you can:
node001-node200
And it will increment according to the pattern.
=head1 COPYRIGHT
Copyright 2007 IBM Corp. All rights reserved.
=cut

View File

@ -180,7 +180,14 @@ sub nodesbycriteria {
return \%critnodes;
}
sub expandatom { #TODO: implement table selection as an atom (nodetype.os==rhels5.3)
# Expand one part of the noderange from the noderange() function. Initially, one part means the
# substring between commas in the noderange. But expandatom also calls itself recursively to
# further expand some parts.
# Input args:
# - atom to expand
# - verify: whether or not to require that the resulting nodenames exist in the nodelist table
# - options: genericrange - a purely syntactical expansion of the range, not using the db at all, e.g not expanding group names
sub expandatom {
my $atom = shift;
if ($recurselevel > 4096) { die "NodeRange seems to be hung on evaluating $atom, recursion limit hit"; }
unless (scalar(@allnodeset) and (($allnodesetstamp+5) > time())) { #Build a cache of all nodes, some corner cases will perform worse, but by and large it will do better. We could do tests to see where the breaking points are, and predict how many atoms we have to evaluate to mitigate, for now, implement the strategy that keeps performance from going completely off the rails
@ -190,26 +197,27 @@ sub expandatom { #TODO: implement table selection as an atom (nodetype.os==rhels
%allnodehash = map { $_->{node} => 1 } @allnodeset;
}
my $verify = (scalar(@_) >= 1 ? shift : 1);
my %args = @_;
my %options = @_; # additional options
my @nodes= ();
#TODO: these env vars need to get passed by the client to xcatd
my $nprefix=(defined ($ENV{'XCAT_NODE_PREFIX'}) ? $ENV{'XCAT_NODE_PREFIX'} : 'node');
my $nsuffix=(defined ($ENV{'XCAT_NODE_SUFFIX'}) ? $ENV{'XCAT_NODE_SUFFIX'} : '');
if (not $args{genericrange} and $allnodehash{$atom}) { #The atom is a plain old nodename
if (not $options{genericrange} and $allnodehash{$atom}) { #The atom is a plain old nodename
return ($atom);
}
if ($atom =~ /^\(.*\)$/) { # handle parentheses by recursively calling noderange()
$atom =~ s/^\((.*)\)$/$1/;
$recurselevel++;
return noderange($atom);
return noderange($atom,$verify,1,%options);
}
if ($atom =~ /@/) {
$recurselevel++;
return noderange($atom);
return noderange($atom,$verify,1,%options);
}
# Try to match groups?
unless ($args{genericrange}) {
unless ($options{genericrange}) {
unless ($grptab) {
$grptab = xCAT::Table->new('nodegroup');
}
@ -273,6 +281,7 @@ sub expandatom { #TODO: implement table selection as an atom (nodetype.os==rhels
}
}
# node selection based on db attribute values (nodetype.os==rhels5.3)
if ($atom =~ m/[=~]/) { #TODO: this is the clunky, slow code path to acheive the goal. It also is the easiest to write, strange coincidence. Aggregating multiples would be nice
my @nodes;
foreach (@allnodeset) {
@ -290,7 +299,7 @@ sub expandatom { #TODO: implement table selection as an atom (nodetype.os==rhels
}
if ($atom =~ m/^[0-9]+\z/) { # if only numbers, then add the prefix
my $nodename=$nprefix.$atom.$nsuffix;
return expandatom($nodename,$verify,%args);
return expandatom($nodename,$verify,%options);
}
my $nodelen=@nodes;
if ($nodelen > 0) {
@ -298,7 +307,7 @@ sub expandatom { #TODO: implement table selection as an atom (nodetype.os==rhels
}
if ($atom =~ m/^\//) { # A regular expression
unless ($verify) { # If not in verify mode, regex makes zero possible sense
if ($verify==0 or $options{genericrange}) { # If not in verify mode, regex makes zero possible sense
return ($atom);
}
#TODO: check against all groups
@ -312,25 +321,29 @@ sub expandatom { #TODO: implement table selection as an atom (nodetype.os==rhels
}
if ($atom =~ m/(.+?)\[(.+?)\](.*)/) { # square bracket range
# if there are more than 1 [], we picked off just the 1st. if there is another, we will process it later
my @subelems = split(/([\,\-\:])/,$2);
# if there is more than 1 set of [], we picked off just the 1st. If there more sets of [], we will expand
# the 1st set and create a new set of atom by concatenating each result in the 1st expandsion with the rest
# of the brackets. Then call expandatom() recursively on each new atom.
my @subelems = split(/([\,\-\:])/,$2); # $2 is the range inside the 1st set of brackets
my $subrange="";
my $subelem;
my $start = $1;
my $ending = $3;
my $morebrackets = $ending =~ /\[.+?\]/; # if there are more brackets, we have to expand just the 1st part, then add the 2nd part later
while (scalar @subelems) {
my $subelem = shift @subelems;
my $subelem;
my $start = $1; # the text before the 1st set of brackets
my $ending = $3; # the text after the 1st set of brackets (could contain more brackets)
my $morebrackets = $ending =~ /\[.+?\]/; # if there are more brackets, we have to expand just the 1st part, then add the 2nd part later
while (scalar @subelems) { # this while loop turns something like a[1-3] into a1-a3 because another section of expand atom knows how to expand that
my $subelem = shift @subelems;
my $subop=shift @subelems;
$subrange=$subrange."$start$subelem" . ($morebrackets?'':$ending) . "$subop";
}
foreach (split /,/,$subrange) {
my @newnodes=expandatom($_, ($morebrackets?0:$verify), genericrange=>$morebrackets);
foreach (split /,/,$subrange) { # this foreach is in case there were commas inside the brackets originally, e.g.: a[1,3,5]b[1-2]
# this expandatom just expands the part of the noderange that contains the 1st set of brackets
# e.g. if noderange is a[1-2]b[1-2] it will create newnodes of a1 and a2
my @newnodes=expandatom($_, ($morebrackets?0:$verify), genericrange=>($morebrackets||$options{genericrange}));
if (!$morebrackets) { push @nodes,@newnodes; }
else {
# for each of the new nodes, add the 2nd brackets and then expand
# for each of the new nodes (prefixes), add the rest of the brackets and then expand recursively
foreach my $n (@newnodes) {
push @nodes, expandatom("$n$ending", $verify, %args);
push @nodes, expandatom("$n$ending", $verify, %options);
}
}
}
@ -352,7 +365,7 @@ sub expandatom { #TODO: implement table selection as an atom (nodetype.os==rhels
$suf=$nsuffix;
}
foreach ("$startnum".."$endnum") {
my @addnodes=expandatom($pref.$_.$suf,$verify,%args);
my @addnodes=expandatom($pref.$_.$suf,$verify,%options);
@nodes=(@nodes,@addnodes);
}
return (@nodes);
@ -379,7 +392,7 @@ sub expandatom { #TODO: implement table selection as an atom (nodetype.os==rhels
$right=$2;
}
if ($left eq $right) { #if they said node1-node1 for some strange reason
return expandatom($left,$verify,%args);
return expandatom($left,$verify,%options);
}
my @leftarr=split(/(\d+)/,$left);
my @rightarr=split(/(\d+)/,$right);
@ -416,7 +429,7 @@ sub expandatom { #TODO: implement table selection as an atom (nodetype.os==rhels
}
}
foreach ($leftarr[$idx]..$rightarr[$idx]) {
my @addnodes=expandatom($prefix.$_.$luffix,$verify,%args);
my @addnodes=expandatom($prefix.$_.$luffix,$verify,%options);
push @nodes,@addnodes;
}
return (@nodes); #the return has been built, return, exiting loop and all
@ -464,7 +477,7 @@ sub retain_cache { #A semi private operation to be used *ONLY* in the interestin
%allgrphash=();
}
}
sub extnoderange { #An extended noderange function. Needed as the more straightforward function return format too simple for this.
sub extnoderange { #An extended noderange function. Needed by the GUI as the more straightforward function return format too simple for this.
my $range = shift;
my $namedopts = shift;
my $verify=1;
@ -490,7 +503,7 @@ sub extnoderange { #An extended noderange function. Needed as the more straight
return $return;
}
sub abbreviate_noderange {
#takes a list of nodes or a string and abbreviates
#takes a list of nodes or a string and reduces it by replacing a list of nodes that make up a group with the group name itself
my $nodes=shift;
my %grouphash;
my %sizedgroups;
@ -536,16 +549,20 @@ sub abbreviate_noderange {
return (join ',',keys %targetelems,keys %nodesleft);
}
# Expand the given noderange
# Input args:
# - noderange to expand
# - verify: whether or not to require that the resulting nodenames exist in the nodelist table
# - exsitenode: whether or not to honor site.excludenodes to automatically exclude those nodes from all noderanges
# - options: genericrange - a purely syntactical expansion of the range, not using the db at all, e.g not expanding group names
sub noderange {
$missingnodes=[];
#We for now just do left to right operations
my $range=shift;
$range =~ s/['"]//g;
my $verify = (scalar(@_) >= 1 ? shift : 1);
#excludenodes attribute in site table,
#these nodes should be excluded for any xCAT commands
my $exsitenode = (scalar(@_) >= 1 ? shift : 1);
my $exsitenode = (scalar(@_) >= 1 ? shift : 1); # if 1, honor site.excludenodes
my %options = @_; # additional options
unless ($nodelist) {
$nodelist =xCAT::Table->new('nodelist',-create =>1);
@ -580,7 +597,7 @@ sub noderange {
my $newrange = $1;
chomp($newrange);
$recurselevel++;
my @filenodes = noderange($newrange);
my @filenodes = noderange($newrange,$verify,$exsitenode,%options);
foreach (@filenodes) {
$nodes{$_}=1;
}
@ -590,7 +607,7 @@ sub noderange {
next;
}
my %newset = map { $_ =>1 } expandatom($atom,$verify); # expand the atom and make each entry in the resulting array a key in newset
my %newset = map { $_ =>1 } expandatom($atom,$verify,%options); # expand the atom and make each entry in the resulting array a key in newset
if ($op =~ /@/) { # compute the intersection of the current atom and the node list we have received before this
foreach (keys %nodes) {
@ -617,7 +634,7 @@ sub noderange {
my $badnoderange = 0;
my @badnodes = ();
if ($::XCATSITEVALS{excludenodes}) {
@badnodes = noderange($::XCATSITEVALS{excludenodes}, 1, 0);
@badnodes = noderange($::XCATSITEVALS{excludenodes}, 1, 0, %options);
foreach my $bnode (@badnodes) {
if (!$delnodes{$bnode}) {
$delnodes{$bnode} = 1;

View File

@ -14,7 +14,6 @@ BEGIN
}
require xCAT::NodeRange;
require xCAT::NameRange;
require xCAT::Table;
require xCAT::Utils;
require xCAT::TableUtils;
@ -583,7 +582,8 @@ sub rollupdate {
}
foreach my $mgline ( @{ $::FILEATTRS{'mapgroups'} } ) {
my @ugnamelist = xCAT::NameRange::namerange( $mgline, 0 );
#my @ugnamelist = xCAT::NameRange::namerange( $mgline, 0 );
my @ugnamelist = xCAT::NodeRange::noderange( $mgline, 0, 1, genericrange=>1 );
foreach my $ugname (@ugnamelist) {
@{ $updategroup{$ugname} } = xCAT::NodeRange::noderange($ugname);
if ( xCAT::NodeRange::nodesmissed() ) {
@ -1756,7 +1756,8 @@ sub create_LL_mutex_resources {
my @ugnames;
foreach my $mxpart ( @mxparts ) {
my $mxindex2 = $mxindex;
my @ugnamelist = xCAT::NameRange::namerange( $mxpart, 0 );
#my @ugnamelist = xCAT::NameRange::namerange( $mxpart, 0 );
my @ugnamelist = xCAT::NodeRange::noderange( $mxpart, 0, 1, genericrange=>1 );
foreach my $ugname (@ugnamelist) {
$::MUTEX[$mxindex2][$mxpi] = $ugname;
$mxindex2++;
@ -1780,7 +1781,8 @@ sub create_LL_mutex_resources {
foreach my $mxnodegrp_range ( @{ $::FILEATTRS{'nodegroup_mutex'} } ) {
my $mx_count = $::FILEATTRS{'nodegroup_mutex_count'}[$fileattrs_index];
foreach my $mxnodegroup ( xCAT::NameRange::namerange( $mxnodegrp_range, 0 ) ) {
#foreach my $mxnodegroup ( xCAT::NameRange::namerange( $mxnodegrp_range, 0 ) ) {
foreach my $mxnodegroup ( xCAT::NodeRange::noderange( $mxnodegrp_range, 0, 1, genericrange=>1 ) ) {
my $mxpi = 0;
mxnode_loop: foreach my $mxnode ( xCAT::NodeRange::noderange($mxnodegroup) ) {
foreach my $ugname ( keys %{$updategroup} ) {