From e5d88570541b308671cbbd2cc081610deb13113a Mon Sep 17 00:00:00 2001 From: Bin Xu Date: Tue, 19 Sep 2017 07:46:02 +0800 Subject: [PATCH] Not return directly for nodeset when hit one node failure --- xCAT-server/lib/xcat/plugins/anaconda.pm | 149 +++++----- xCAT-server/lib/xcat/plugins/destiny.pm | 327 +++++++++++++--------- xCAT-server/lib/xcat/plugins/petitboot.pm | 35 ++- 3 files changed, 303 insertions(+), 208 deletions(-) diff --git a/xCAT-server/lib/xcat/plugins/anaconda.pm b/xCAT-server/lib/xcat/plugins/anaconda.pm index 1507b768f..d04d768fb 100644 --- a/xCAT-server/lib/xcat/plugins/anaconda.pm +++ b/xCAT-server/lib/xcat/plugins/anaconda.pm @@ -355,9 +355,11 @@ sub mknetboot $img_hash{$imagename}->{'partfile'} = $ref1->{'partitionfile'}; } } else { - $callback->( - { error => ["The os image $imagename does not exists on the osimage table for $node"], - errorcode => [1] }); + my $rsp; + $rsp->{node}->[0]->{name}->[0] = $node; + $rsp->{node}->[0]->{errorcode}->[0] = 1; + $rsp->{node}->[0]->{error}->[0] = "The OS image '$imagename' for node does not exist"; + $callback->($rsp); next; } } @@ -379,6 +381,7 @@ sub mknetboot $cfgpart = $ph->{'cfgpart'}; } else { + # This is deprecated mode to define node's provmethod, not supported now. $osver = $ent->{os}; $arch = $ent->{arch}; $profile = $ent->{profile}; @@ -402,10 +405,12 @@ sub mknetboot $rootfstype = $ref1->{'rootfstype'}; } } else { - $callback->( - { error => [qq{Cannot find the linux image called "$osver-$arch-$imgname-$profile", maybe you need to use the "nodeset osimage=" command to set the boot state}], - errorcode => [1] } - ); + my $rsp; + $rsp->{node}->[0]->{name}->[0] = $node; + $rsp->{node}->[0]->{errorcode}->[0] = 1; + $rsp->{node}->[0]->{error}->[0] = "The OS image $osver-$arch-$imgname-$profile for node does not exist"; + $callback->($rsp); + next; } if (!$linuximagetab) { @@ -441,22 +446,23 @@ sub mknetboot } } } else { - $callback->( - { error => [qq{ Cannot find the linux image called "$osver-$arch-$imgname-$profile", maybe you need to use the "nodeset osimage=" command to set the boot state}], - errorcode => [1] } - ); + my $rsp; + $rsp->{node}->[0]->{name}->[0] = $node; + $rsp->{node}->[0]->{errorcode}->[0] = 1; + $rsp->{node}->[0]->{error}->[0] = "The OS image $osver-$arch-$imgname-$profile for node does not exist"; + $callback->($rsp); + next; } } #print"osvr=$osver, arch=$arch, profile=$profile, imgdir=$rootimgdir\n"; unless ($osver and $arch and $profile) { - $callback->( - { - error => ["Insufficient nodetype entry or osimage entry for $node"], - errorcode => [1] - } - ); + my $rsp; + $rsp->{node}->[0]->{name}->[0] = $node; + $rsp->{node}->[0]->{errorcode}->[0] = 1; + $rsp->{node}->[0]->{error}->[0] = "Insufficient nodetype entry or osimage entry for $node"; + $callback->($rsp); next; } @@ -467,18 +473,20 @@ sub mknetboot # statelite images are not packed. if ($statelite) { unless (-r "$rootimgdir/kernel") { - $callback->({ - error => [qq{Did you run "genimage" before running "liteimg"? kernel cannot be found at $rootimgdir/kernel on $myname}], - errorcode => [1] - }); + my $rsp; + $rsp->{node}->[0]->{name}->[0] = $node; + $rsp->{node}->[0]->{errorcode}->[0] = 1; + $rsp->{node}->[0]->{error}->[0] = qq{Did you run "genimage" before running "liteimg"? kernel cannot be found at $rootimgdir/kernel on $myname}; + $callback->($rsp); next; } if (!-r "$rootimgdir/initrd-statelite.gz") { if (!-r "$rootimgdir/initrd.gz") { - $callback->({ - error => [qq{Did you run "genimage" before running "liteimg"? initrd.gz or initrd-statelite.gz cannot be found at $rootimgdir/initrd.gz on $myname}], - errorcode => [1] - }); + my $rsp; + $rsp->{node}->[0]->{name}->[0] = $node; + $rsp->{node}->[0]->{errorcode}->[0] = 1; + $rsp->{node}->[0]->{error}->[0] = qq{Did you run "genimage" before running "liteimg"? initrd.gz or initrd-statelite.gz cannot be found at $rootimgdir/initrd.gz on $myname}; + $callback->($rsp); next; } else { @@ -486,35 +494,40 @@ sub mknetboot } } if ($rootfstype eq "ramdisk" and !-r "$rootimgdir/rootimg-statelite.gz") { - $callback->({ - error => [qq{No packed image for platform $osver, architecture $arch and profile $profile, please run "liteimg" to create it.}], - errorcode => [1] - }); + my $rsp; + $rsp->{node}->[0]->{name}->[0] = $node; + $rsp->{node}->[0]->{errorcode}->[0] = 1; + $rsp->{node}->[0]->{error}->[0] = qq{No packed image for platform $osver, architecture $arch and profile $profile, please run "liteimg" to create it.}; + $callback->($rsp); next; } } else { unless (-r "$rootimgdir/kernel") { - $callback->({ - error => [qq{Did you run "genimage" before running "packimage"? kernel cannot be found at $rootimgdir/kernel on $myname}], - errorcode => [1] - }); + my $rsp; + $rsp->{node}->[0]->{name}->[0] = $node; + $rsp->{node}->[0]->{errorcode}->[0] = 1; + $rsp->{node}->[0]->{error}->[0] = qq{Did you run "genimage" before running "packimage"? kernel cannot be found at $rootimgdir/kernel on $myname}; + $callback->($rsp); next; } if (!-r "$rootimgdir/initrd-stateless.gz") { if (!-r "$rootimgdir/initrd.gz") { - $callback->({ - error => [qq{Did you run "genimage" before running "packimage"? initrd.gz or initrd-stateless.gz cannot be found at $rootimgdir/initrd.gz on $myname}], - errorcode => [1] - }); + my $rsp; + $rsp->{node}->[0]->{name}->[0] = $node; + $rsp->{node}->[0]->{errorcode}->[0] = 1; + $rsp->{node}->[0]->{error}->[0] = qq{Did you run "genimage" before running "packimage"? initrd.gz or initrd-stateless.gz cannot be found at $rootimgdir/initrd.gz on $myname}; + $callback->($rsp); next; } else { copy("$rootimgdir/initrd.gz", "$rootimgdir/initrd-stateless.gz"); } } unless ( -f -r "$rootimgdir/$compressedrootimg") { - $callback->({ - error => ["No packed image for platform $osver, architecture $arch, and profile $profile found at $rootimgdir/rootimg.gz or $rootimgdir/rootimg.sfs on $myname, please run packimage (e.g. packimage -o $osver -p $profile -a $arch"], - errorcode => [1] }); + my $rsp; + $rsp->{node}->[0]->{name}->[0] = $node; + $rsp->{node}->[0]->{errorcode}->[0] = 1; + $rsp->{node}->[0]->{error}->[0] = "No packed image for platform $osver, architecture $arch, and profile $profile found at $rootimgdir/rootimg.gz or $rootimgdir/rootimg.sfs on $myname, please run packimage (e.g. packimage -o $osver -p $profile -a $arch"; + $callback->($rsp); next; } } @@ -567,21 +580,21 @@ sub mknetboot } else { $initrdloc .= "/initrd-statelite.gz"; } - unless (-r "$tftppath/kernel" - and -r $initrdloc) { - $callback->({ - error => [qq{copying to $tftppath failed}], - errorcode => [1] - }); + unless (-r "$tftppath/kernel" and -r $initrdloc) { + my $rsp; + $rsp->{node}->[0]->{name}->[0] = $node; + $rsp->{node}->[0]->{errorcode}->[0] = 1; + $rsp->{node}->[0]->{error}->[0] = qq{Copying to $tftppath failed.}; + $callback->($rsp); next; } } else { - unless (-r "$tftppath/kernel" - and -r "$tftppath/initrd-stateless.gz") { - $callback->({ - error => [qq{copying to $tftppath failed}], - errorcode => [1] - }); + unless (-r "$tftppath/kernel" and -r "$tftppath/initrd-stateless.gz") { + my $rsp; + $rsp->{node}->[0]->{name}->[0] = $node; + $rsp->{node}->[0]->{errorcode}->[0] = 1; + $rsp->{node}->[0]->{error}->[0] = qq{Copying to $tftppath failed.}; + $callback->($rsp); next; } } @@ -635,14 +648,11 @@ sub mknetboot } unless ($imgsrv) { - $callback->( - { - error => [ -"Unable to determine or reasonably guess the image server for $node" - ], - errorcode => [1] - } - ); + my $rsp; + $rsp->{node}->[0]->{name}->[0] = $node; + $rsp->{node}->[0]->{errorcode}->[0] = 1; + $rsp->{node}->[0]->{error}->[0] = "Unable to determine or reasonably guess the image server for $node"; + $callback->($rsp); next; } my $kcmdline; @@ -753,11 +763,9 @@ sub mknetboot } else { if (-r "$rootimgdir/$compressedrootimg.metainfo") { - $kcmdline = -"imgurl=$httpmethod://$imgsrv:$httpport/$rootimgdir/$compressedrootimg.metainfo "; + $kcmdline = "imgurl=$httpmethod://$imgsrv:$httpport/$rootimgdir/$compressedrootimg.metainfo "; } else { - $kcmdline = -"imgurl=$httpmethod://$imgsrv:$httpport/$rootimgdir/$compressedrootimg "; + $kcmdline = "imgurl=$httpmethod://$imgsrv:$httpport/$rootimgdir/$compressedrootimg "; } $kcmdline .= "XCAT=$xcatmaster:$xcatdport "; $kcmdline .= "NODE=$node "; @@ -832,14 +840,11 @@ sub mknetboot #my $sent = $hmtab->getNodeAttribs($node,['serialspeed','serialflow']); unless ($sent->{serialspeed}) { - $callback->( - { - error => [ -"serialport defined, but no serialspeed for $node in nodehm table" - ], - errorcode => [1] - } - ); + my $rsp; + $rsp->{node}->[0]->{name}->[0] = $node; + $rsp->{node}->[0]->{errorcode}->[0] = 1; + $rsp->{node}->[0]->{error}->[0] = "serialport defined, but no serialspeed for $node in nodehm table"; + $callback->($rsp); next; } if ($arch =~ /ppc64/i) { diff --git a/xCAT-server/lib/xcat/plugins/destiny.pm b/xCAT-server/lib/xcat/plugins/destiny.pm index ae72167d6..5bbb39ea4 100755 --- a/xCAT-server/lib/xcat/plugins/destiny.pm +++ b/xCAT-server/lib/xcat/plugins/destiny.pm @@ -35,6 +35,7 @@ my $tftpdir = "/tftpboot"; my $nonodestatus = 0; +my %failurenodes = (); #my $sitetab = xCAT::Table->new('site'); #if ($sitetab) { @@ -64,36 +65,41 @@ sub process_request { my $result = xCAT::TableUtils->checkCredFiles($callback); } if ($request->{command}->[0] eq 'getdestiny') { + xCAT::MsgUtils->trace(0, "d", "destiny->process_request: starting getdestiny..."); getdestiny(0); - } - if ($request->{command}->[0] eq 'nextdestiny') { + } elsif ($request->{command}->[0] eq 'nextdestiny') { + xCAT::MsgUtils->trace(0, "d", "destiny->process_request: starting nextdestiny..."); nextdestiny(0, 1); #it is called within dodestiny - } - if ($request->{command}->[0] eq 'setdestiny') { + } elsif ($request->{command}->[0] eq 'setdestiny') { + xCAT::MsgUtils->trace(0, "d", "destiny->process_request: starting setdestiny..."); setdestiny($request, 0); } + xCAT::MsgUtils->trace(0, "d", "destiny->process_request: processing is finished for " . $request->{command}->[0]); } sub relay_response { my $resp = shift; - my $failure = 0; + return unless ($resp); + $callback->($resp); if ($resp and ($resp->{errorcode} and $resp->{errorcode}->[0]) or ($resp->{error} and $resp->{error}->[0])) { - $failure = 1; + $errored = 2; + return; } - # quick return when detect failure. - unless ( $failure ) { - foreach (@{ $resp->{node} }) { - if ($_->{error} or $_->{errorcode}) { - $failure = 1; - last; + + my $failure = 0; + # Partial error on nodes, it allows to continue the rest of business on the sucessful nodes. + foreach (@{ $resp->{node} }) { + if ($_->{error} or $_->{errorcode}) { + $failure = 1; + if ($_->{name}) { + $failurenodes{$_->{name}->[0]} = 2; } } } if ( $failure ) { $errored = $failure; } - } sub setdestiny { @@ -101,7 +107,6 @@ sub setdestiny { my $flag = shift; my $noupdate = shift; $chaintab = xCAT::Table->new('chain', -create => 1); - my @nodes = @{ $req->{node} }; my $bphash = $req->{bootparams}; @ARGV = @{ $req->{arg} }; @@ -120,9 +125,11 @@ sub setdestiny { #>>>>>>>used for trace log end>>>>>>> - my $state = $ARGV[0]; - my $reststates; - + if (@{ $req->{node} } == 0) { + xCAT::MsgUtils->trace($verbose, "d", "destiny->setdestiny: no nodes left to process, we are done"); + return; + } + my @nodes = @{ $req->{node} }; my $bptab = xCAT::Table->new('bootparams', -create => 1); my %tempbh = %{ $bptab->getNodesAttribs(\@nodes, [qw(addkcmdline)]) }; while(my ($key, $value) = each(%tempbh)) { @@ -134,9 +141,13 @@ sub setdestiny { } $bptab->close(); + my $state = $ARGV[0]; + my $reststates; + my %nstates; # to support the case that the state could be runimage=xxx,runimage=yyy,osimage=xxx ($state, $reststates) = split(/,/, $state, 2); - my %nstates; + chomp($state); + if ($state eq "enact") { my $nodetypetab = xCAT::Table->new('nodetype', -create => 1); my %nodestates; @@ -192,11 +203,9 @@ sub setdestiny { if ($ient->{kcmdline}) { $bphash->{kcmdline} = $ient->{kcmdline} } } } elsif ($state =~ /^install[=\$]/ or $state eq 'install' or $state =~ /^netboot[=\$]/ or $state eq 'netboot' or $state eq "image" or $state eq "winshell" or $state =~ /^osimage/ or $state =~ /^statelite/) { - my %state_hash; - chomp($state); + my $rawstate=$state; my $target; my $action; - my $rawstate=$state; if ($state =~ /=/) { ($state, $target) = split '=', $state, 2; @@ -213,16 +222,24 @@ sub setdestiny { ($state, $action) = split ':', $state, 2; } } - + xCAT::MsgUtils->trace($verbose, "d", "destiny->setdestiny: state=$state, target=$target, action=$action"); + my %state_hash; + # 1, Set an initial state for all requested nodes foreach my $tmpnode (@{ $req->{node} }) { + continue if ($failurenodes{$tmpnode}); $state_hash{$tmpnode} = $state; } + # 2, Filter those unsuitable nodes in 'state_hash' my $nodetypetable = xCAT::Table->new('nodetype', -create => 1); my $noderestable = xCAT::Table->new('noderes', -create => 1); - my $nbents = $noderestable->getNodeAttribs($req->{node}->[0], ["netboot"]); + my $nbents = $noderestable->getNodeAttribs($req->{node}->[0], ["netboot"]); # It is assumed that all nodes has the same `netboot` attribute my $curnetboot = $nbents->{netboot}; + if ($state ne 'osimage') { + $callback->({ error => "The options \"install\", \"netboot\", and \"statelite\" have been deprecated, use \"osimage=\" instead.", errorcode => [1] }); + return; + my $updateattribs; if ($target) { my $archentries = $nodetypetable->getNodesAttribs($req->{node}, ['supportedarchs']); @@ -233,33 +250,46 @@ sub setdestiny { my $nodearch = $2; foreach (@{ $req->{node} }) { if ($archentries->{$_}->[0]->{supportedarchs} and $archentries->{$_}->[0]->{supportedarchs} !~ /(^|,)$nodearch(\z|,)/) { - $callback->({ errorcode => [1], error => "Requested architecture " . $nodearch . " is not one of the architectures supported by $_ (per nodetype.supportedarchs, it supports " . $archentries->{$_}->[0]->{supportedarchs} . ")" }); - return; + my $rsp; + $rsp->{errorcode}->[0] = 1; + $rsp->{error}->[0] = "Requested architecture " . $nodearch . " is not one of the architectures supported by $_ (per nodetype.supportedarchs, it supports " . $archentries->{$_}->[0]->{supportedarchs} . ")"; + $callback->($rsp); + $failurenodes{$_} = 1; + next; } } #end foreach } else { $updateattribs->{profile} = $target; } } #end if($target) + $updateattribs->{provmethod} = $state; - my @tmpnodelist = @{ $req->{node} }; + my @tmpnodelist = (); + foreach (@{ $req->{node} }) { + if ($failurenodes{$_}) { + delete $state_hash{$_}; + continue; + } + push @tmpnodelist, $_; + } $nodetypetable->setNodesAttribs(\@tmpnodelist, $updateattribs); + } else { #state is osimage - if (@{ $req->{node} } == 0) { return; } if ($target) { my $osimagetable = xCAT::Table->new('osimage'); (my $ref) = $osimagetable->getAttribs({ imagename => $target }, 'provmethod', 'osvers', 'profile', 'osarch', 'imagetype'); + # TODO: valid the osimage also for more madatory checking if ($ref) { if ($ref->{provmethod}) { $state = $ref->{provmethod}; } else { - $errored = 1; $callback->({ errorcode => [1], error => "osimage.provmethod for $target must be set." }); + $callback->({ errorcode => [1], error => "osimage.provmethod for $target must be set." }); return; } } else { - $errored = 1; $callback->({ errorcode => [1], error => "Cannot find the OS image $target on the osimage table." }); + $callback->({ errorcode => [1], error => "Cannot find the OS image $target on the osimage table." }); return; } @@ -278,25 +308,39 @@ sub setdestiny { $updateattribs->{profile} = $ref->{profile}; $updateattribs->{os} = $ref->{osvers}; $updateattribs->{arch} = $ref->{osarch}; - my @tmpnodelist = @{ $req->{node} }; + my @tmpnodelist = (); + foreach (@{ $req->{node} }) { + if ($failurenodes{$_}) { + delete $state_hash{$_}; + continue; + } + $state_hash{$_} = $state; + push @tmpnodelist, $_; + } $nodetypetable->setNodesAttribs(\@tmpnodelist, $updateattribs); - - foreach my $tmpnode (@{ $req->{node} }) { - $state_hash{$tmpnode} = $state; - } - } else { - my @errornodes = (); + #my @errornodes = (); my $invalidosimghash; - my @validnodes; + #my @validnodes; my $updatestuff; my $nodetypetable = xCAT::Table->new('nodetype', -create => 1); my %ntents = %{ $nodetypetable->getNodesAttribs($req->{node}, "provmethod") }; foreach my $tmpnode (@{ $req->{node} }) { + continue if ($failurenodes{$tmpnode}); + my $osimage = $ntents{$tmpnode}->[0]->{provmethod}; if (($osimage) && ($osimage ne 'install') && ($osimage ne 'netboot') && ($osimage ne 'statelite')) { - if (!exists($updatestuff->{$osimage})) { + if (exists($updatestuff->{$osimage})) { #valid osimage + my $vnodes = $updatestuff->{$osimage}->{nodes}; + push(@$vnodes, $tmpnode); + #push(@validnodes, $tmpnode); + $state_hash{$tmpnode} = $updatestuff->{$osimage}->{state}; + } elsif (exists($invalidosimghash->{$osimage})) { #valid osimage + push(@{ $invalidosimghash->{$osimage}->{nodes} }, $tmpnode); + next; + } + else { #Get a new osimage, to valid it and put invalid osimage into `invalidosimghash` my $osimagetable = xCAT::Table->new('osimage'); (my $ref) = $osimagetable->getAttribs({ imagename => $osimage }, 'provmethod', 'osvers', 'profile', 'osarch', 'imagetype'); if ($ref) { @@ -305,7 +349,7 @@ sub setdestiny { #if not,push the nodes into $invalidosimghash->{$osimage}->{netboot} my $netbootval = xCAT::Utils->lookupNetboot($ref->{osvers}, $ref->{osarch}, $ref->{imagetype}); if ($netbootval =~ /$curnetboot/i) { - push(@validnodes, $tmpnode); + #push(@validnodes, $tmpnode); } else { push(@{ $invalidosimghash->{$osimage}->{nodes} }, $tmpnode); $invalidosimghash->{$osimage}->{netboot} = $netbootval; @@ -322,56 +366,69 @@ sub setdestiny { $updatestuff->{$osimage}->{os} = $ref->{osvers}; $updatestuff->{$osimage}->{arch} = $ref->{osarch}; } else { - $errored = 1; $callback->({ errorcode => [1], error => "osimage.provmethod for $osimage must be set." }); - return; + push(@{ $invalidosimghash->{$osimage}->{nodes} }, $tmpnode); + $invalidosimghash->{$osimage}->{error}->[0] = "osimage.provmethod for $osimage must be set"; + next; } } else { - $errored = 1; $callback->({ errorcode => [1], error => "Cannot find the OS image $osimage on the osimage table." }); - return; + push(@{ $invalidosimghash->{$osimage}->{nodes} }, $tmpnode); + $invalidosimghash->{$osimage}->{error}->[0] = "Cannot find the OS image $osimage on the osimage table"; + next; } - } else { - my $nodes = $updatestuff->{$osimage}->{nodes}; - push(@$nodes, $tmpnode); - push(@validnodes, $tmpnode); - $state_hash{$tmpnode} = $updatestuff->{$osimage}->{state}; } - } else { - push(@errornodes, $tmpnode); + # not supported legacy mode + push(@{ $invalidosimghash->{'__xcat_legacy_mode'}->{nodes} }, $tmpnode); + $invalidosimghash->{$osimage}->{error}->[0] = "OS image name must be specified in nodetype.provmethod"; + next; } } - if (@errornodes) { - $errored = 1; $callback->({ errorcode => [1], error => "OS image name must be specified in nodetype.provmethod for nodes: @errornodes." }); - return; - } else { - foreach my $tmpimage (keys %$updatestuff) { - my $updateattribs = $updatestuff->{$tmpimage}; - my @tmpnodelist = @{ $updateattribs->{nodes} }; - - delete $updateattribs->{nodes}; #not needed for nodetype table - delete $updateattribs->{state}; #node needed for nodetype table - $nodetypetable->setNodesAttribs(\@tmpnodelist, $updateattribs); + #if any node with inappropriate noderes.netboot,report the error and return + foreach my $tmpimage (keys %$invalidosimghash) { + my @fnodes = @{ $invalidosimghash->{$tmpimage}->{nodes} }; + for (@fnodes) { + $failurenodes{$_} = 1; + delete $state_hash{$_}; + if ($invalidosimghash->{$tmpimage}->{error}) { + my $rsp; + $rsp->{node}->[0]->{name}->[0] = $_; + #$rsp->{node}->[0]->{errorcode}->[0] = 1; + $rsp->{node}->[0]->{error}->[0] = $invalidosimghash->{$tmpimage}->{error}->[0]; + $callback->($rsp); + } } - - #if any node with inappropriate noderes.netboot,report the error and return - foreach my $tmpimage (keys %$invalidosimghash) { - - #$errored =1; - $callback->({ warning => [ join(",", @{ $invalidosimghash->{$tmpimage}->{nodes} }) . ": $curnetboot might be invalid when provisioning $tmpimage,valid options: \"$invalidosimghash->{$tmpimage}->{netboot}\". \nFor more details see the 'netboot' description in the output of \"tabdump -d noderes\"." ] }); + if ($invalidosimghash->{$tmpimage}->{warning}) + { + my $rsp; + $rsp->{warning}->[0] = join(",", @fnodes) . ": $curnetboot might be invalid when provisioning $tmpimage,valid options: \"$invalidosimghash->{$tmpimage}->{netboot}\". \nFor more details see the 'netboot' description in the output of \"tabdump -d noderes\"."; + $callback->($rsp); } - - if ("$errored" ne "0") { - return; - } - - #$req->{node}=(); - #push(@{$req->{node}},@validnodes); - #print Dumper($req->{node}); } + + foreach my $tmpimage (keys %$updatestuff) { + my $updateattribs = $updatestuff->{$tmpimage}; + my @tmpnodelist = @{ $updateattribs->{nodes} }; + + delete $updateattribs->{nodes}; #not needed for nodetype table + delete $updateattribs->{state}; #node needed for nodetype table + $nodetypetable->setNodesAttribs(\@tmpnodelist, $updateattribs); + } + + #if ("$errored" ne "0") { + # return; + #} } } + #print Dumper(\%state_hash); + my @validnodes = keys(%state_hash); + unless (@validnodes) { + # just return if no valid nodes left + $callback->({ errorcode => [1]}); + return; + } + #if the postscripts directory exists then make sure it is # world readable and executable by root; otherwise wget fails my $installdir = xCAT::TableUtils->getInstallDir(); @@ -384,41 +441,43 @@ sub setdestiny { if ($::RUNCMD_RC != 0) { $callback->({ info => "$cmd failed" }); - } - } - #print Dumper($req); - # if precreatemypostscripts=1, create each mypostscript for each node + # 3, if precreatemypostscripts=1, create each mypostscript for each valid node # otherwise, create it during installation /updatenode my $notmpfiles = 0; # create tmp files if precreate=0 my $nofiles = 0; # create files, do not return array require xCAT::Postage; - xCAT::Postage::create_mypostscript_or_not($request, $callback, $subreq, $notmpfiles, $nofiles); + my $reqcopy = {%$req}; + $reqcopy->{node} = \@validnodes; + xCAT::Postage::create_mypostscript_or_not($reqcopy, $callback, $subreq, $notmpfiles, $nofiles); + # 4, Issue the sub-request for each state in 'state_hash' my %state_hash1; foreach my $tmpnode (keys(%state_hash)) { push @{ $state_hash1{ $state_hash{$tmpnode} } }, $tmpnode; } - #print Dumper(%state_hash); - #print Dumper(%state_hash1); + #print Dumper(\%state_hash1); foreach my $tempstate (keys %state_hash1) { my $samestatenodes = $state_hash1{$tempstate}; #print "state=$tempstate nodes=@$samestatenodes\n"; - xCAT::MsgUtils->trace($verbose_on_off, "d", "destiny->process_request: issue mk$tempstate request"); + xCAT::MsgUtils->trace($verbose_on_off, "d", "destiny->setdestiny: issue mk$tempstate request"); $errored = 0; $subreq->({ command => ["mk$tempstate"], node => $samestatenodes, noupdateinitrd => $noupdateinitrd, ignorekernelchk => $ignorekernelchk, bootparams => \$bphash}, \&relay_response); - if ($errored) { + if ($errored > 1) { # The error messeage for mkinstall/mknetboot/mkstatelite had been output within relay_response function above, don't need to output more - xCAT::MsgUtils->trace($verbose_on_off, "d", "destiny->process_request: Failed in processing mk$tempstate. Processing will not continue."); - return; + xCAT::MsgUtils->trace($verbose_on_off, "d", "destiny->setdestiny: Failed in processing mk$tempstate. Processing will not continue."); + for (@$samestatenodes) { + $failurenodes{$_} = 1; + } + next; } @@ -430,7 +489,8 @@ sub setdestiny { if ($tempstate ne "winshell") { if ($ntent and $ntent->{os}) { $nstates{$_} .= " " . $ntent->{os}; - } else { $errored = 1; $callback->({ errorcode => [1], error => "nodetype.os not defined for $_" }); } + } else { + $errored = 1; $callback->({ errorcode => [1], error => "nodetype.os not defined for $_" }); } } else { $nstates{$_} .= " winpe"; } @@ -461,6 +521,37 @@ sub setdestiny { } } } elsif ($state eq "shell" or $state eq "standby" or $state =~ /^runcmd/ or $state =~ /^runimage/) { + + if ($state =~ /^runimage/) { # try to check the existence of the image for runimage + + my @runimgcmds; + push @runimgcmds, $state; + if ($reststates) { + my @rstates = split(/,/, $reststates); + foreach (@rstates) { + if (/^runimage/) { + push @runimgcmds, $_; + } + } + } + + foreach (@runimgcmds) { + my (undef, $path) = split(/=/, $_); + if ($path) { + if ($path =~ /\$/) { next; } # Ignore the path with including variable like $xcatmaster + my $cmd = "wget --spider --timeout 3 --tries=1 $path"; + my @output = xCAT::Utils->runcmd("$cmd", -1); + unless (grep /^Remote file exists/, @output) { + $callback->({ error => ["Cannot get $path with wget. Could you confirm it's downloadable by wget?"], errorcode => [1] }); + return; + } + } else { + $callback->({ error => "An image path should be specified to runnimage.", errorcode => [1] }); + return; + } + } + } + $restab = xCAT::Table->new('noderes', -create => 1); my $nodetype = xCAT::Table->new('nodetype'); @@ -480,8 +571,11 @@ sub setdestiny { foreach (@nodes) { my $ent = $enthash->{$_}->[0]; #$nodetype->getNodeAttribs($_,[qw(arch)]); unless ($ent and $ent->{arch}) { - $callback->({ error => ["No archictecture defined in nodetype table for $_"], errorcode => [1] }); - return; + my $rsp; + $rsp->{errorcode}->[0] = 1; + $rsp->{error}->[0] = "No archictecture defined in nodetype table for $_"; + $callback->($rsp); + next; } my $arch = $ent->{arch}; if ($arch eq "ppc64le" or $arch eq "ppc64el") { @@ -510,6 +604,14 @@ sub setdestiny { $master = $master_entry; } } + unless ($master) { + my $rsp; + $rsp->{errorcode}->[0] = 1; + $rsp->{error}->[0] = "No master in site table nor noderes table for $_"; + $callback->($rsp); + $failurenodes{$_} = 1; + next; + } $ent = $hments->{$_}->[0]; #$nodehm->getNodeAttribs($_,['serialport','serialspeed','serialflow']); if ($ent and defined($ent->{serialport})) { @@ -521,8 +623,12 @@ sub setdestiny { #$ent = $nodehm->getNodeAttribs($_,['serialspeed']); unless ($ent and defined($ent->{serialspeed})) { - $callback->({ error => ["Serial port defined in noderes, but no nodehm.serialspeed set for $_"], errorcode => [1] }); - return; + my $rsp; + $rsp->{errorcode}->[0] = 1; + $rsp->{error}->[0] = "Serial port defined in noderes, but no nodehm.serialspeed set for $_"; + $callback->($rsp); + $failurenodes{$_} = 1; + next; } $kcmdline .= "," . $ent->{serialspeed}; @@ -530,10 +636,6 @@ sub setdestiny { $kcmdline .= " "; } - unless ($master) { - $callback->({ error => ["No master in site table nor noderes table for $_"], errorcode => [1] }); - return; - } my $xcatdport = "3001"; if (defined($port_entry)) { $xcatdport = $port_entry; @@ -563,35 +665,6 @@ sub setdestiny { } } - # try to check the existence of the image for runimage - my @runimgcmds; - if ($state =~ /^runimage/) { - push @runimgcmds, $state; - } - if ($reststates) { - my @rstates = split(/,/, $reststates); - foreach (@rstates) { - if (/^runimage/) { - push @runimgcmds, $_; - } - } - } - - foreach (@runimgcmds) { - my (undef, $path) = split(/=/, $_); - if ($path) { - if ($path =~ /\$/) { next; } # Ignore the path with including variable like $xcatmaster - my $cmd = "wget --spider --timeout 3 --tries=1 $path"; - my @output = xCAT::Utils->runcmd("$cmd", -1); - unless (grep /^Remote file exists/, @output) { - $callback->({ error => ["Cannot get $path with wget. Could you confirm it's downloadable by wget?"], errorcode => [1] }); - return; - } - } else { - $callback->({ error => "An image path should be specified to runnimage.", errorcode => [1] }); - return; - } - } } elsif ($state eq "offline" || $state eq "shutdown") { 1; } elsif (!($state eq "boot")) { @@ -644,6 +717,8 @@ sub setdestiny { if ($noupdate) { return; } #skip table manipulation if just doing 'enact' my $updates; foreach (@nodes) { + next if ($failurenodes{$_}); + my $lstate = $state; if ($nstates{$_}) { $lstate = $nstates{$_}; @@ -684,16 +759,16 @@ sub nextdestiny { $node = $request->{username}->[0]; } else { unless ($request->{'_xcat_clienthost'}->[0]) { - #ERROR? malformed request + xCAT::MsgUtils->trace(0, "d", "destiny->nextdestiny: Cannot determine the client from the received request"); return; #nothing to do here... } $node = $request->{'_xcat_clienthost'}->[0]; } ($node) = noderange($node); unless ($node) { - #not a node, don't trust it + xCAT::MsgUtils->trace(0, "d", "destiny->nextdestiny: $node is not managed yet."); return; } @nodes = ($node); diff --git a/xCAT-server/lib/xcat/plugins/petitboot.pm b/xCAT-server/lib/xcat/plugins/petitboot.pm index c6c9c7295..c1a1ce1cf 100644 --- a/xCAT-server/lib/xcat/plugins/petitboot.pm +++ b/xCAT-server/lib/xcat/plugins/petitboot.pm @@ -115,6 +115,7 @@ sub setstate { error => [ $ipfnd[1] ], errorcode => [1] }); + $failurenodes{$node} = 2; return; } elsif ($ipfnd[0] == 2) { @@ -145,6 +146,7 @@ sub setstate { errorcode => [1] } ); + $failurenodes{$node} = 2; return; } } else { @@ -223,6 +225,7 @@ sub setstate { my $ip = xCAT::NetworkUtils->getipaddr($node); unless ($ip) { syslog("local1|err", "xCAT unable to resolve IP for $node in petitboot plugin"); + $failurenodes{$node} = 2; return; } @@ -239,23 +242,33 @@ sub setstate { } - my $errored = 0; sub pass_along { my $resp = shift; - + return unless ($resp); # print Dumper($resp); $callback->($resp); - if ($resp and ($resp->{errorcode} and $resp->{errorcode}->[0]) or ($resp->{error} and $resp->{error}->[0])) { - $errored = 1; + # Global error, it normally means to stop the parent execution. For example, DB operation error. + if (($resp->{errorcode} and $resp->{errorcode}->[0]) or ($resp->{error} and $resp->{error}->[0])) { + $errored = 2; + return; } + + my $failure = 0; + # Partial error on nodes, it allows to continue the rest of business on the sucessful nodes. foreach (@{ $resp->{node} }) { if ($_->{error} or $_->{errorcode}) { - $errored = 1; + $failure = 1; + if ($_->{name}) { + $failurenodes{$_->{name}->[0]} = 2; + } } } + if ( $failure ) { + $errored = $failure; + } } @@ -410,6 +423,7 @@ sub process_request { my $command = $request->{command}->[0]; %breaknetbootnodes = (); %normalnodes = (); # It will be fill-up by method: setstate. + %failurenodes = (); #>>>>>>>used for trace log start>>>>>>> my @args = (); @@ -465,7 +479,6 @@ sub process_request { my @nodes = (); # Filter those nodes which have bad DNS: not resolvable or inconsistent IP - my %failurenodes = (); my %preparednodes = (); foreach (@rnodes) { my $ipret = xCAT::NetworkUtils->checkNodeIPaddress($_); @@ -551,7 +564,7 @@ sub process_request { node => \@nodes, arg => [ $args[0] ] }, \&pass_along); } - if ($errored) { + if ($errored > 1) { my $rsp; $rsp->{errorcode}->[0] = 1; $rsp->{error}->[0] = "Failed in running begin prescripts.\n"; @@ -575,7 +588,7 @@ sub process_request { arg => \@args, bootparams => \%bphash}, \&pass_along); - if ($errored) { + if ($errored > 1) { xCAT::MsgUtils->trace($verbose_on_off, "d", "petitboot: Failed in processing setdestiny. Processing will not continue."); return; } @@ -610,6 +623,8 @@ sub process_request { my $tftpdir; foreach (@nodes) { + next if ($failurenodes->{$_}); + my %response; if ($nodereshash->{$_} and $nodereshash->{$_}->[0] and $nodereshash->{$_}->[0]->{tftpdir}) { $tftpdir = $nodereshash->{$_}->[0]->{tftpdir}; @@ -680,12 +695,12 @@ sub process_request { if ($request->{'_disparatetftp'}->[0]) { #the call is distrubuted to the service node already, so only need to handles my own children xCAT::MsgUtils->trace($verbose_on_off, "d", "petitboot: issue runendpre request"); $sub_req->({ command => ['runendpre'], - node => \@nodes, + node => \@normalnodeset, arg => [ $args[0], '-l' ] }, \&pass_along); } else { #nodeset did not distribute to the service node, here we need to let runednpre to distribute the nodes to their masters xCAT::MsgUtils->trace($verbose_on_off, "d", "petitboot: issue runendpre request"); $sub_req->({ command => ['runendpre'], - node => \@nodes, + node => \@normalnodeset, arg => [ $args[0] ] }, \&pass_along); } if ($errored) {