diff --git a/perl-xCAT/xCAT/DBobjUtils.pm b/perl-xCAT/xCAT/DBobjUtils.pm index 130be5c21..d83cefab6 100644 --- a/perl-xCAT/xCAT/DBobjUtils.pm +++ b/perl-xCAT/xCAT/DBobjUtils.pm @@ -1572,7 +1572,6 @@ sub getGroupMembers # find all nodes that satisfy the criteria specified in "wherevals" # value my %whereHash; - my @whereattrs; my %tabhash; my %nodeattrhash; @@ -1580,22 +1579,15 @@ sub getGroupMembers #$val =~ s/^\s*"\s*//; #$val =~ s/\s*"\s*$//; - my @tmpWhereList = split(',', $objhash{$objectname}{'wherevals'}); - foreach my $w (@tmpWhereList) + my @tmpWhereList = split('::', $objhash{$objectname}{'wherevals'}); + my $rc = xCAT::Utils->parse_selection_string(\@tmpWhereList, \%whereHash); + if ($rc != 0) { - my ($a, $v) = $w =~ /^\s*(\S+?)\s*=\s*(\S*.*)$/; - if (!defined($a) || !defined($v)) - { - my $rsp; - $rsp->{data}->[0] = - "The \'-w\' option has an incorrect attr=val pair - \'$w\'."; - xCAT::MsgUtils->message("I", $rsp, $::callback); - next; - } - - $whereHash{$a} = $v; - push @whereattrs, $a; - + my $rsp; + $rsp->{data}->[0] = + "The \'-w\' option has an incorrect attr=val pair."; + xCAT::MsgUtils->message("E", $rsp, $::callback); + next; } # see what nodes have these attr=values @@ -1610,41 +1602,13 @@ sub getGroupMembers } # Only get the specific attributes of the node + my @whereattrs = keys %whereHash; my %nodeattrhash = xCAT::DBobjUtils->getobjdefs(\%tmphash, 0, \@whereattrs); my $first = 1; foreach my $objname (keys %nodeattrhash) { - - # all the "where" attrs must match the object attrs - my $addlist = 1; - - foreach my $testattr (keys %whereHash) - { - if ($whereHash{$testattr} =~ /^\|/) - { # wherevals includes regular expression - my $tmpwherestring = $whereHash{$testattr}; - $tmpwherestring =~ /^\|(.*)\|$/g; - $tmpwherestring = $1; - if (!defined($nodeattrhash{$objname}{$testattr}) || ($nodeattrhash{$objname}{$testattr} !~ /$tmpwherestring/) ) - { - # don't disply - $addlist = 0; - next; - } - } - else #no regular expression in wherevals - { - if (!defined($nodeattrhash{$objname}{$testattr}) || ($nodeattrhash{$objname}{$testattr} ne $whereHash{$testattr})) - { - - # don't disply - $addlist = 0; - next; - } - } - } - if ($addlist) + if (xCAT::Utils->selection_string_match(\%nodeattrhash, $objname, \%whereHash)) { chomp($objname); if (!$first) diff --git a/perl-xCAT/xCAT/Utils.pm b/perl-xCAT/xCAT/Utils.pm index 08253b434..a8404ee01 100644 --- a/perl-xCAT/xCAT/Utils.pm +++ b/perl-xCAT/xCAT/Utils.pm @@ -4194,4 +4194,135 @@ sub getrootimage() } } +#---------------------------------------------------------------------------- + +=head3 parse_selection_string + Parse the selection string and + write the parsed result into %wherehash + + Arguments: + $ss_ref - selection string array from -w flag + \%wherehash - selection string hash %::WhereHash + Returns: + 0 - parse successfully + 1 - parse failed + Globals: + %wherehash + + Error: + + Example: + + Comments: +=cut + +#----------------------------------------------------------------------------- +sub parse_selection_string() +{ + my ($class, $ss_ref, $wherehash_ref) = @_; + + foreach my $m (@{$ss_ref}) + { + my $attr; + my $val; + my $matchtype; + if ($m =~ /^[^=]*\==/) { + ($attr, $val) = split /==/,$m,2; + $matchtype='match'; + } elsif ($m =~ /^[^=]*=~/) { + ($attr, $val) = split /=~/,$m,2; + $val =~ s/^\///; + $val =~ s/\/$//; + $matchtype='regex'; + } elsif ($m =~ /^[^=]*\!=/) { + ($attr,$val) = split /!=/,$m,2; + $matchtype='natch'; + } elsif ($m =~ /[^=]*!~/) { + ($attr,$val) = split /!~/,$m,2; + $val =~ s/^\///; + $val =~ s/\/$//; + $matchtype='negex'; + } elsif ($m =~ /^[^=]*=[^=]+$/) { # attr=val is the same as attr==val + ($attr, $val) = split /=/,$m,2; + $matchtype='match'; + } else { + return 1; + } + + if (!defined($attr) || !defined($val)) + { + return 1; + } + + $wherehash_ref->{$attr}->{'val'} = $val; + $wherehash_ref->{$attr}->{'matchtype'} = $matchtype; + } + return 0; +} + +#---------------------------------------------------------------------------- + +=head3 selection_string_match + Check whether a node matches the selection string + defined in hash %wherehash + + Arguments: + \%objhash - the hash contains the objects definition + $objname - the object name + $wherehash_ref - the selection string hash + Returns: + 0 - NOT match + 1 - match + Globals: + %wherehash + + Error: + + Example: + + Comments: +=cut + +#----------------------------------------------------------------------------- +sub selection_string_match() +{ + my ($class, $objhash_ref, $objname, $wherehash_ref) = @_; + + my %wherehash = %$wherehash_ref; + my $match = 1; + foreach my $testattr (keys %wherehash) { + # access non-exists hash entry will create an empty one + # we should not modify the $objhash_ref + if (exists($objhash_ref->{$objname}) && exists($objhash_ref->{$objname}->{$testattr})) { + if($wherehash{$testattr}{'matchtype'} eq 'match') { #attr==val or attr=val + if ($objhash_ref->{$objname}->{$testattr} ne $wherehash{$testattr}{'val'}) { + $match = 0; + last; + } + } + if(($wherehash{$testattr}{'matchtype'} eq 'natch')) { #attr!=val + if ($objhash_ref->{$objname}->{$testattr} eq $wherehash{$testattr}{'val'}) { + $match = 0; + last; + } + } + if($wherehash{$testattr}{'matchtype'} eq 'regex') { #attr=~val + if ($objhash_ref->{$objname}->{$testattr} !~ $wherehash{$testattr}{'val'}) { + $match = 0; + last; + } + } + if($wherehash{$testattr}{'matchtype'} eq 'negex') { #attr!~val + if ($objhash_ref->{$objname}->{$testattr} =~ $wherehash{$testattr}{'val'}) { + $match = 0; + last; + } + } + } else { #$objhash_ref->{$objname}->{$testattr} does not exist + $match = 0; + last; + } + } + return $match; +} 1; diff --git a/xCAT-client/pods/man1/chdef.1.pod b/xCAT-client/pods/man1/chdef.1.pod index a79cee8fa..e6d4308e8 100644 --- a/xCAT-client/pods/man1/chdef.1.pod +++ b/xCAT-client/pods/man1/chdef.1.pod @@ -8,7 +8,7 @@ B [B<-h>|B<--help>] [B<-t> I] B [B<-V>|B<--verbose>] [B<-t> I] [B<-o> I] [B<-d>|B<--dynamic>] [B<-p>|B<--plus>] [B<-m>|B<--minus>] [B<-z>|B<--stanza>] -[B<-w> I=I,[I=I]] [I] [I=I [I=I]] +[[B<-w> "I==I"] [B<-w> "I=~I"] ...] [I] [I=I [I=I]] =head1 DESCRIPTION @@ -54,9 +54,11 @@ A set of comma delimited object types. Use the help option to get a list of val Verbose mode. -=item B<-w> I +=item B<-w> I<"attr==val"> B<-w> I<"attr=~val"> ... -A comma-separated list of attributes and values that can be used to select objects. Use the help option to get a list of validattributes for each object type. +Use one or multiple -w flags to specify the selection string that can be used to select objects. The operators ==, !=, =~ and !~ are available. Use the help option to get a list of validattributes for each object type. + +Note: the operator !~ will be parsed by shell, if you want to use !~ in the selection string, use single quote instead. For example:-w 'mgt!~ipmi'. =item B<-z|--stanza> @@ -122,7 +124,7 @@ To update a set of definitions based on information contained in the stanza file To update a dynamic node group definition to add the cons=hmc wherevals pair. - chdef -t group -o dyngrp -d -p -w "cons=hmc" + chdef -t group -o dyngrp -d -p -w "cons==hmc" =back diff --git a/xCAT-client/pods/man1/lsdef.1.pod b/xCAT-client/pods/man1/lsdef.1.pod index fa4e3331a..79304c899 100644 --- a/xCAT-client/pods/man1/lsdef.1.pod +++ b/xCAT-client/pods/man1/lsdef.1.pod @@ -8,7 +8,7 @@ B [B<-h>|B<--help>] [B<-t> I] B [B<-V>|B<--verbose>] [B<-l>|B<--long>] [B<-a>|B<--all>] [B<-t> I] [B<-o> I] [B<-z>|B<--stanza>] [B<-i> I] -[B<-w> I=I,[I=I] [I] +[[B<-w> "I==I"] [B<-w> "I=~I"] ...] [I] =head1 DESCRIPTION @@ -54,9 +54,11 @@ A set of comma delimited object types. Use the help option to get a list of vali Verbose mode. -=item B<-w> I +=item B<-w> I<"attr==val"> B<-w> I<"attr=~val"> ... -A comma-separated list of attributes and values that can be used to select items to display. Use the help option to get a list of valid attributes. +Use one or multiple -w flags to specify the selection string that can be used to select objects. The operators ==, !=, =~ and !~ are available. Use the help option to get a list of validattributes for each object type. + +Note: the operator !~ will be parsed by shell, if you want to use !~ in the selection string, use single quote instead. For example:-w 'mgt!~ipmi'. =item B<-z|--stanza> @@ -123,7 +125,7 @@ To list an osimage definition named "aix53J". To list all node definitions that have a status value of "booting". - lsdef -t node -w status=booting + lsdef -t node -w "status==booting" =item 9. diff --git a/xCAT-client/pods/man1/mkdef.1.pod b/xCAT-client/pods/man1/mkdef.1.pod index 1587c4b86..c542cdf81 100644 --- a/xCAT-client/pods/man1/mkdef.1.pod +++ b/xCAT-client/pods/man1/mkdef.1.pod @@ -8,7 +8,7 @@ B [B<-h>|B<--help>] [B<-t> I] B [B<-V>|B<--verbose>] [B<-t> I] [B<-o> I] [B<-z>|B<--stanza>] [B<-d>|B<--dynamic>] [B<-f>|B<--force>] -[B<-w> I=I,[I=I]] [I] [I=I [I=I]] +[[B<-w> "I==I"] [B<-w> "I=~I"] ...] [I] [I=I [I=I]] =head1 DESCRIPTION @@ -52,9 +52,11 @@ A set of comma delimited object types. Use the help option to get a list of val Verbose mode. -=item B<-w> I +=item B<-w> I<"attr==val"> B<-w> I<"attr=~val"> ... -A comma-separated list of attributes and values that can be used to select objects. Use the help option to get a list of validattributes for each object type. +Use one or multiple -w flags to specify the selection string that can be used to select objects. The operators ==, !=, =~ and !~ are available. For mkdef commmand, the -w flag only makes sense for creating dynamic node group. Use the help option to get a list of validattributes for each object type. + +Note: the operator !~ will be parsed by shell, if you want to use !~ in the selection string, use single quote instead. For example:-w 'mgt!~ipmi'. =item B<-z|--stanza> @@ -122,13 +124,13 @@ To create node definitions for a set of node host names contained in the node ra To create a dynamic node group definition called HMCMgtNodes containing all the HMC managed nodes" - mkdef -t group -o HMCMgtNodes -d -w "mgt=hmc,cons=hmc" + mkdef -t group -o HMCMgtNodes -d -w "mgt==hmc" -w "cons==hmc" =item 9. To create a dynamic node group definition called SLESNodes containing all the SLES nodes - mkdef -t group -o SLESNodes -d -w "os=|^sles[0-9]+$|" + mkdef -t group -o SLESNodes -d -w "os=~^sles[0-9]+$" =back diff --git a/xCAT-server/lib/xcat/plugins/DBobjectdefs.pm b/xCAT-server/lib/xcat/plugins/DBobjectdefs.pm index 7ce32c42f..19b9bd1cf 100644 --- a/xCAT-server/lib/xcat/plugins/DBobjectdefs.pm +++ b/xCAT-server/lib/xcat/plugins/DBobjectdefs.pm @@ -15,6 +15,7 @@ use xCAT::DBobjUtils; use Data::Dumper; use Getopt::Long; use xCAT::MsgUtils; +use xCAT::Utils; use strict; # options can be bundled up like -vV @@ -221,7 +222,7 @@ sub processArgs 't=s' => \$::opt_t, 'verbose|V' => \$::opt_V, 'version|v' => \$::opt_v, - 'w=s' => \$::opt_w, + 'w=s@' => \$::opt_w, 'x|xml' => \$::opt_x, 'z|stanza' => \$::opt_z ) @@ -687,23 +688,13 @@ sub processArgs # check for the -w option if ($::opt_w) { - my @tmpWhereList = split(',', $::opt_w); - foreach my $w (@tmpWhereList) + my $rc = xCAT::Utils->parse_selection_string($::opt_w, \%::WhereHash); + if ($rc != 0) { - if ($w =~ /=/) - { - my ($a, $v) = $w =~ /^\s*(\S+?)\s*=\s*(\S*.*)$/; - if (!defined($a) || !defined($v)) - { - my $rsp; - $rsp->{data}->[0] = "Incorrect \'attr=val\' pair - $a\n"; - xCAT::MsgUtils->message("E", $rsp, $::callback); - return 3; - } - - $::WhereHash{$a} = $v; - - } + my $rsp; + $rsp->{data}->[0] = "Incorrect selection string specified with -w flag\n"; + xCAT::MsgUtils->message("E", $rsp, $::callback); + return 3; } } @@ -1009,7 +1000,8 @@ sub defmk { if ($::opt_w) { - $::FINALATTRS{$obj}{wherevals} = $::opt_w; + $::FINALATTRS{$obj}{wherevals} = join ('::', @{$::opt_w}); + #$::FINALATTRS{$obj}{wherevals} = $::opt_w; } else { @@ -1073,22 +1065,7 @@ sub defmk foreach my $objname (keys %myhash) { - # all the "where" attrs must match the object attrs - my $addlist = 1; - - foreach my $testattr (keys %::WhereHash) - { - if ( !($myhash{$objname}{$testattr} =~ /\b$::WhereHash{$testattr}\b/) ) - { - - # don't disply - $addlist = 0; - next; - } - } - - if ($addlist) - { + if (xCAT::Utils->selection_string_match(\%myhash, $objname, \%::WhereHash)) { push(@memberlist, $objname); } @@ -1550,7 +1527,8 @@ sub defch { if ($::opt_w) { - $::FINALATTRS{$obj}{wherevals} = $::opt_w; + $::FINALATTRS{$obj}{wherevals} = join ('::', @{$::opt_w}); + #$::FINALATTRS{$obj}{wherevals} = $::opt_w; } } @@ -1600,53 +1578,25 @@ sub defch # get all the attrs for these nodes my %myhash = xCAT::DBobjUtils->getobjdefs(\%objhash); - # get a list of attr=val pairs - my @tmpWhereList = - split(',', $::FINALATTRS{$obj}{wherevals}); - - # create an attr-val hash - foreach my $w (@tmpWhereList) + # get a list of attr=val pairs, is it really necessary?? + my @wherevals = split(/::/, $::FINALATTRS{$obj}{wherevals}); + my $rc = xCAT::Utils->parse_selection_string(\@wherevals, \%::WhereHash); + if ($rc != 0) { - if ($w =~ /=/) - { - my ($a, $v) = $w =~ /^\s*(\S+?)\s*=\s*(\S*.*)$/; - if (!defined($a) || !defined($v)) - { - my $rsp; - $rsp->{data}->[0] = - "Incorrect \'attr=val\' pair - $a\n"; - xCAT::MsgUtils->message("E", $rsp, $::callback); - return 3; - } - $::WhereHash{$a} = $v; - } + my $rsp; + $rsp->{data}->[0] = "Incorrect selection string specified with -m flag"; + xCAT::MsgUtils->message("E", $rsp, $::callback); + return 3; } # see which ones match the where values foreach my $objname (keys %myhash) { - # all the "where" attrs must match the object attrs - my $addlist = 1; - - foreach my $testattr (keys %::WhereHash) - { - - if ($myhash{$objname}{$testattr} ne - $::WhereHash{$testattr}) - { - - # don't disply - $addlist = 0; - next; - } - } - - if ($addlist) - { + if (xCAT::Utils->selection_string_match(\%myhash, $objname, \%::WhereHash)) { push(@memberlist, $objname); - } + } } @@ -2288,22 +2238,7 @@ sub defls { foreach my $obj (sort (keys %myhash)) { - - # all the "where" attrs must match the object attrs - my $dodisplay = 1; - - foreach my $testattr (keys %::WhereHash) - { - if ($myhash{$obj}{$testattr} ne $::WhereHash{$testattr}) - { - - # don't disply - $dodisplay = 0; - next; - } - } - if ($dodisplay) - { + if (xCAT::Utils->selection_string_match(\%myhash, $obj, \%::WhereHash)) { push(@displayObjList, $obj); } }