rollupdate - add support for translatenames

git-svn-id: https://svn.code.sf.net/p/xcat/code/xcat-core/trunk@10012 8638fb3e-16cb-4fca-ae20-7b5d299a9bcd
This commit is contained in:
mellor 2011-07-05 17:55:18 +00:00
parent 9bace51802
commit d29f467806
4 changed files with 254 additions and 20 deletions

View File

@ -20,6 +20,10 @@ require Data::Dumper;
require Getopt::Long;
require xCAT::MsgUtils;
require File::Path;
use Text::Balanced qw(extract_bracketed);
use Safe;
my $evalcpt = new Safe;
use strict;
use warnings;
@ -559,6 +563,7 @@ sub rollupdate {
return 1;
}
#
# Build and submit scheduler jobs
#
@ -643,6 +648,15 @@ sub ll_jobs {
return 1;
}
# Translate xCAT names to LL names
$::XLATED = {};
if (defined($::FILEATTRS{translatenames}[0])) {
foreach my $xlate_stanza( @{ $::FILEATTRS{'translatenames'} } ) {
translate_names($xlate_stanza);
}
}
# Create LL floating resources for mutual exclusion support
# and max_updates
if (&create_LL_mutex_resources($updategroup,$::updateall) > 0) {
@ -774,16 +788,22 @@ sub ll_jobs {
my ( $nodelist, $machinelist );
my $machinecount = 0;
foreach my $node ( @{ $updategroup->{$ugname} } ) {
if ( defined( $machines{$node} )
&& ( $machines{$node}{'mstatus'} eq "1" ) ) {
$machinelist .= " $machines{$node}{'mname'}";
my $xlated_node;
if ( defined ($::XLATED{$node}) ){
$xlated_node = $::XLATED{$node};
} else {
$xlated_node = $node;
}
if ( defined( $machines{$xlated_node} )
&& ( $machines{$xlated_node}{'mstatus'} eq "1" ) ) {
$machinelist .= " $machines{$xlated_node}{'mname'}";
$machinecount++;
$nodelist .= ",$node";
} elsif ( $run_if_down eq 'yes' ) {
if ( defined( $machines{$node} ) ) {
if ( defined( $machines{$xlated_node} ) ) {
# llmkres -D will allow reserving down nodes as long
# as they are present in the machine list
$machinelist .= " $machines{$node}{'mname'}";
$machinelist .= " $machines{$xlated_node}{'mname'}";
$machinecount++;
}
$nodelist .= ",$node";
@ -833,6 +853,11 @@ sub ll_jobs {
if (defined($::FILEATTRS{bringuptimeout}[0])){
push (@ugdflines, "bringuptimeout=$::FILEATTRS{bringuptimeout}[0]\n");
}
if (defined($::FILEATTRS{translatenames}[0])){
foreach my $xlate_stanza( @{ $::FILEATTRS{'translatenames'} } ) {
push (@ugdflines, "translatenames=$xlate_stanza\n");
}
}
if (defined($::FILEATTRS{skipshutdown}[0])){
push (@ugdflines, "skipshutdown=$::FILEATTRS{skipshutdown}[0]\n");
}
@ -884,7 +909,8 @@ sub ll_jobs {
}
# Build reservation callback script
my @rcblines;
my @rcblines;
my $rcbcmd = $::FILEATTRS{'reservationcallback'}[0];
if (!defined($rcbcmd)){ $rcbcmd = "$::XCATROOT/bin/runrollupdate"; }
push (@rcblines, "#!/bin/sh \n");
@ -953,6 +979,7 @@ sub ll_jobs {
if ( $jcline =~ /Feature/ ) {
$jcline =~ s/\"\s+/\"/g;
$jcline =~ s/\s+\"/\"/g;
$jcline =~ s/\=\"/\= \"/g;
}
if ($lastcount) {
$jcline2 = $jcline;
@ -1191,6 +1218,117 @@ sub check_policy {
#----------------------------------------------------------------------------
=head3 translate_names
Translate xCAT node names to scheduler names as requested by the user
Arguments: $instructions - translation instructions of the form:
<xcat_noderange>:/<pattern>/<replacement>/
OR
<xcat_noderange>:|<pattern>|<replacement>|
Returns:
Globals:
hash: $::XLATED{$node}=$xlated_name
AND $::XLATED{$xlated_name}=$node
to allow easy lookup in either direction
Error:
Example:
Comments:
=cut
#-----------------------------------------------------------------------------
# This is a utility function to create a number out of a string, useful for things like round robin algorithms on unnumbered nodes
sub mknum {
my $string = shift;
my $number=0;
foreach (unpack("C*",$string)) { #do big endian, then it would make 'fred' and 'free' be one number apart
$number += $_;
}
return $number;
}
$evalcpt->share('&mknum');
$evalcpt->permit('require');
sub translate_names{
my $instructions = shift;
my ($nr,$regexps) = split( /\:/, $instructions );
my @xCATnodes = xCAT::NodeRange::noderange($nr);
foreach my $xCATnode (@xCATnodes) {
my $xlated_node = $xCATnode;
my $datum = $regexps;
# The following is based on code copied from Table::getNodeAttribs
if ($datum =~ /^\/[^\/]*\/[^\/]*\/$/)
{
my $exp = substr($datum, 1);
chop $exp;
my @parts = split('/', $exp, 2);
$xlated_node =~ s/$parts[0]/$parts[1]/;
$datum = $xlated_node;
}
elsif ($datum =~ /^\|.*\|.*\|$/)
{
#Perform arithmetic and only arithmetic operations in bracketed issues on the right.
#Tricky part: don't allow potentially dangerous code, only eval if
#to-be-evaled expression is only made up of ()\d+-/%$
#Futher paranoia? use Safe module to make sure I'm good
my $exp = substr($datum, 1);
chop $exp;
my @parts = split('\|', $exp, 2);
my $curr;
my $next;
my $prev;
my $retval = $parts[1];
($curr, $next, $prev) =
extract_bracketed($retval, '()', qr/[^()]*/);
unless($curr) { #If there were no paramaters to save, treat this one like a plain regex
undef $@; #extract_bracketed would have set $@ if it didn't return, undef $@
$retval = $xlated_node;
$retval =~ s/$parts[0]/$parts[1]/;
$datum = $retval;
unless ($datum =~ /^$/) { # ignore blank translations
$xlated_node=$datum;
}
next; #skip the redundancy that follows otherwise
}
while ($curr)
{
#my $next = $comps[0];
my $value = $xlated_node;
$value =~ s/$parts[0]/$curr/;
# $value = $evalcpt->reval('use integer;'.$value);
$value = $evalcpt->reval($value);
$retval = $prev . $value . $next;
#use text::balanced extract_bracketed to parse each atom, make sure nothing but arith operators, parens, and numbers are in it to guard against code execution
($curr, $next, $prev) =
extract_bracketed($retval, '()', qr/[^()]*/);
}
undef $@;
#At this point, $retval is the expression after being arithmetically contemplated, a generated regex, and therefore
#must be applied in total
my $answval = $xlated_node;
$answval =~ s/$parts[0]/$retval/;
$datum = $answval; #$retval;
}
unless ($datum =~ /^$/) {
$::XLATED{$xCATnode}=$datum;
$::XLATED{$datum}=$xCATnode;
}
}
# print Dumper($::XLATED);
return ;
}
#----------------------------------------------------------------------------
=head3 set_LL_feature
@ -1788,9 +1926,15 @@ sub runrollupdate {
($::DATAATTRS{skipshutdown}[0] eq "1") ) ) {
$skipshutdown = 1;
}
$::XLATED = {};
if (defined($::DATAATTRS{translatenames}[0])) {
foreach my $xlate_stanza( @{ $::DATAATTRS{'translatenames'} } ) {
translate_names($xlate_stanza);
}
}
# make sure nodes are in correct state
my $hostlist = &get_hostlist;
my $hostlist = &get_hostlist();
if (! $hostlist ) {
if ($::VERBOSE) {
open (RULOG, ">>$::LOGDIR/$::LOGFILE");
@ -1804,7 +1948,7 @@ sub runrollupdate {
}
my $nltab = xCAT::Table->new('nodelist');
my @nodes = split( /\,/, $hostlist );
my @nodes = split( /\,/, $hostlist );
my $appstatus=xCAT::Utils->getAppStatus(\@nodes,"RollingUpdate");
foreach my $node (@nodes) {
unless ( defined($appstatus->{$node})
@ -2054,16 +2198,25 @@ sub runrollupdate {
my $totalwait = 0;
my %ll_res;
while ($not_done && $totalwait < ($statustimeout * 60)) {
my @query_bootnodes;
foreach my $bn (keys %ll_res) {
if ( ! ($ll_res{$bn}{removed}) ) {
push (@query_bootnodes,$bn);
}
}
if ( ! @query_bootnodes ) {
@query_bootnodes = @bootnodes;
}
if ($::VERBOSE) {
open (RULOG, ">>$::LOGDIR/$::LOGFILE");
print RULOG localtime()." $::ug_name: Checking ".join(",",@bootnodes)." xCAT database $statusattr for value $statusval \n";
print RULOG localtime()." $::ug_name: Checking ".join(",",@query_bootnodes)." xCAT database $statusattr for value $statusval \n";
close (RULOG);
}
my $nltab_stats =
$nltab->getNodesAttribs( \@bootnodes, [ 'node', $statusattr ] );
%ll_res = ();
$nltab->getNodesAttribs( \@query_bootnodes, [ 'node', $statusattr ] );
# %ll_res = ();
$not_done = 0;
foreach my $bn (@bootnodes) {
foreach my $bn (@query_bootnodes) {
if ( $nltab_stats->{$bn}->[0]->{$statusattr} !~ /$statusval/ ) {
$ll_res{$bn}{not_done}=1;
$not_done = 1;
@ -2075,9 +2228,14 @@ sub runrollupdate {
($::ll_reservation_id)){
my @remove_res;
foreach my $bn (keys %ll_res) {
if ($ll_res{$bn}{remove} && ! $ll_res{$bn}{removed} ){
push (@remove_res,$bn);
if (($ll_res{$bn}{remove}) && (! $ll_res{$bn}{removed}) ){
if ( defined($::XLATED{$bn}) ) {
push (@remove_res,$::XLATED{$bn});
} else {
push (@remove_res,$bn);
}
$ll_res{$bn}{removed} = 1;
$ll_res{$bn}{not_done} = 0;
}
}
if (@remove_res) {
@ -2086,8 +2244,12 @@ sub runrollupdate {
}
}
if ($not_done) {
sleep(20);
$totalwait += 20;
if ($::TEST) {
$not_done = 0;
} else {
sleep(20);
$totalwait += 20;
}
}
}
if ($not_done) {
@ -2109,10 +2271,19 @@ sub runrollupdate {
push (@error_nodes,$bn);
}
}
open (RULOG, ">>$::LOGDIR/$::LOGFILE");
print RULOG "\n";
print RULOG localtime()." ERROR: bringuptimeout exceeded for the following nodes: \n";
print RULOG join(",",@error_nodes);
print RULOG "\n";
xCAT::Utils->setAppStatus(\@error_nodes,"RollingUpdate","ERROR_bringuptimeout_exceeded");
if ( defined($remaining_nodes[0]) ) {
if ( @remaining_nodes ) {
print RULOG localtime()." ERROR: bringuptimeout exceeded for some nodes in a preceding bringuporder. The following nodes will not be powered on: \n";
print RULOG join(",",@remaining_nodes);
print RULOG "\n";
xCAT::Utils->setAppStatus(\@remaining_nodes,"RollingUpdate","ERROR_bringuptimeout_exceeded_for_previous_node");
}
close (RULOG);
}
last;
}
@ -2237,7 +2408,16 @@ sub get_hostlist {
print RULOG localtime()." Hostlist: $status_fields[22] \n";
close (RULOG);
}
return $status_fields[22];
my $return_list;
foreach my $machine (split( /\,/, $status_fields[22])) {
if ( defined($::XLATED{$machine}) ) {
$return_list = $return_list.','.$::XLATED{$machine};
} else {
$return_list = $return_list.','.$machine;
}
}
$return_list =~ s/^,//;
return $return_list;
}
@ -2609,8 +2789,10 @@ sub llreconfig {
my $runlocal=0;
foreach my $m (@llms) {
my ($sm,$rest) = split(/\./,$m);
my $xlated_sm = $sm;
if ( defined ($::XLATED{$sm}) ) { $xlated_sm = $::XLATED{$sm}; }
if (xCAT::Utils->thishostisnot($m)) {
push(@llnodes, $sm) unless $have{$sm}++;
push(@llnodes, $xlated_sm) unless $have{$sm}++;
} else {
$runlocal=1;
}
@ -2634,7 +2816,7 @@ sub llreconfig {
if ( scalar(@llnodes) > 0 ) {
if ($::VERBOSE) {
open (RULOG, ">>$::LOGDIR/$::LOGFILE");
print RULOG localtime()." Running command \'xdsh $llcms $llrms $cmd\'\n";
print RULOG localtime()." Running command \'xdsh ".join(',',@llnodes)." $cmd\'\n";
close (RULOG);
}
if ($::TEST) {

View File

@ -122,6 +122,23 @@ mutex_count=2
# nodegroup_mutex=block2IO
# nodegroup_mutex=block3IO
# translatenames:
# If your scheduler will be using names for nodes that are different from
# xCAT node names (e.g. the scheduler is using a different administrative
# network), you will need to tell xCAT how to translate from xCAT node names
# to the node names registered with your scheduler.
#
# Syntax:
# translatenames=<xCAT_noderange>:/<pattern>/<replacement>/
# where <pattern> and <replacement> are perl regular expressions to
# be performed on the node names in <xCAT_noderange>.
# See the xcatdb man page for more details on using regular expressions.
# Multiple translatenames statements are allowed. If an xCAT nodename
# exists in more than one xCAT_noderange, the last translated value
# will be used.
#translatenames=service:|bb(\d+)s(\d+)|bb($1)sn($2)|
#translatenames=compute:/\z/-hf2/

View File

@ -68,6 +68,24 @@ updateall_nodes=compute
updateall_nodecount=3
# translatenames:
# If your scheduler will be using names for nodes that are different from
# xCAT node names (e.g. the scheduler is using a different administrative
# network), you will need to tell xCAT how to translate from xCAT node names
# to the node names registered with your scheduler.
#
# Syntax:
# translatenames=<xCAT_noderange>:/<pattern>/<replacement>/
# where <pattern> and <replacement> are perl regular expressions to
# be performed on the node names in <xCAT_noderange>.
# See the xcatdb man page for more details on using regular expressions.
# Multiple translatenames statements are allowed. If an xCAT nodename
# exists in more than one xCAT_noderange, the last translated value
# will be used.
#translatenames=service:|bb(\d+)s(\d+)|bb($1)sn($2)|
#translatenames=compute:/\z/-hf2/
# Scheduler Feature values
# Node feature values that will be changed in the scheduler during the

View File

@ -91,6 +91,23 @@ updategroup=ns11(c4lpar211-c4lpar214)
#mutex=block2a,block2b,block2c
#mutex=block3a,block3b,block3c
# translatenames:
# If your scheduler will be using names for nodes that are different from
# xCAT node names (e.g. the scheduler is using a different administrative
# network), you will need to tell xCAT how to translate from xCAT node names
# to the node names registered with your scheduler.
#
# Syntax:
# translatenames=<xCAT_noderange>:/<pattern>/<replacement>/
# where <pattern> and <replacement> are perl regular expressions to
# be performed on the node names in <xCAT_noderange>.
# See the xcatdb man page for more details on using regular expressions.
# Multiple translatenames statements are allowed. If an xCAT nodename
# exists in more than one xCAT_noderange, the last translated value
# will be used.
#translatenames=service:|bb(\d+)s(\d+)|bb($1)sn($2)|
#translatenames=compute:/\z/-hf2/
# maxupdates: Maximum number of updategroups that can be updated at one time