Module: tools Branch: master Commit: b8fbfb378bbaa359068131d038280b5a1d05f2c7 URL: http://source.winehq.org/git/tools.git/?a=commit;h=b8fbfb378bbaa359068131d03...
Author: Francois Gouget fgouget@codeweavers.com Date: Tue Jan 22 04:15:50 2013 +0100
testbot: Make it possible to restart a failed job.
Mostly this is so that jobs that failed because of a transient WineTestBot error can be restarted by the administrator.
---
testbot/bin/Engine.pl | 31 +++++++++++++ testbot/lib/WineTestBot/Engine/Notify.pm | 22 ++++++++- testbot/lib/WineTestBot/Jobs.pm | 38 +++++++++++++++ testbot/web/JobDetails.pl | 73 ++++++++++++++++++++++++++++-- 4 files changed, 158 insertions(+), 6 deletions(-)
diff --git a/testbot/bin/Engine.pl b/testbot/bin/Engine.pl index e233e80..3d8f159 100755 --- a/testbot/bin/Engine.pl +++ b/testbot/bin/Engine.pl @@ -171,6 +171,36 @@ sub HandleJobCancel return "1OK"; }
+sub HandleJobRestart +{ + my $JobKey = $_[0]; + + my $Job = CreateJobs()->GetItem($JobKey); + if (! $Job) + { + LogMsg "JobRestart for nonexistent job $JobKey\n"; + return "0Job $JobKey not found"; + } + # We've already determined that JobKey is valid, untaint it + $JobKey =~ m/^(.*)$/; + $JobKey = $1; + + my $ErrMessage = $Job->Restart(); + if (defined($ErrMessage)) + { + LogMsg "Restart problem: $ErrMessage\n"; + return "0$ErrMessage"; + } + + $ErrMessage = ScheduleJobs(); + if (defined($ErrMessage)) + { + LogMsg "Scheduling problem in HandleJobRestart: $ErrMessage\n"; + } + + return "1OK"; +} + sub HandleTaskComplete { my $ErrMessage = ScheduleJobs(); @@ -452,6 +482,7 @@ my %Handlers=( "foundwinetestupdate" => &HandleFoundWinetestUpdate, "getscreenshot" => &HandleGetScreenshot, "jobcancel" => &HandleJobCancel, + "jobrestart" => &HandleJobRestart, "jobstatuschange" => &HandleJobStatusChange, "jobsubmit" => &HandleJobSubmit, "ping" => &HandlePing, diff --git a/testbot/lib/WineTestBot/Engine/Notify.pm b/testbot/lib/WineTestBot/Engine/Notify.pm index 6bbec87..b836751 100644 --- a/testbot/lib/WineTestBot/Engine/Notify.pm +++ b/testbot/lib/WineTestBot/Engine/Notify.pm @@ -33,8 +33,9 @@ use vars qw (@ISA @EXPORT @EXPORT_OK $RunningInEngine);
require Exporter; @ISA = qw(Exporter); -@EXPORT = qw(&PingEngine &JobSubmit &JobStatusChange &JobCancel &TaskComplete - &VMStatusChange &ExpectWinetestUpdate &FoundWinetestUpdate +@EXPORT = qw(&PingEngine &JobSubmit &JobStatusChange &JobCancel &JobRestart + &TaskComplete &VMStatusChange + &ExpectWinetestUpdate &FoundWinetestUpdate &WinePatchMLSubmission &WinePatchWebNotification &WinePatchWebSubmission &GetScreenshot); @EXPORT_OK = qw($RunningInEngine); @@ -132,6 +133,23 @@ sub JobCancel return substr($Reply, 1); }
+sub JobRestart +{ + my $JobKey = $_[0]; + + my $Reply = SendCmdReceiveReply("jobrestart $JobKey\n"); + if (length($Reply) < 1) + { + return "Unrecognized reply received from engine"; + } + if (substr($Reply, 0, 1) eq "1") + { + return undef; + } + + return substr($Reply, 1); +} + sub TaskComplete { my ($JobKey, $StepKey, $TaskKey) = @_; diff --git a/testbot/lib/WineTestBot/Jobs.pm b/testbot/lib/WineTestBot/Jobs.pm index 269643d..66f87ba 100644 --- a/testbot/lib/WineTestBot/Jobs.pm +++ b/testbot/lib/WineTestBot/Jobs.pm @@ -50,6 +50,7 @@ A Job is composed of multiple WineTestBot::Step objects.
=cut
+use WineTestBot::Config; use WineTestBot::Branches; use WineTestBot::Engine::Notify; use WineTestBot::WineTestBotObjects; @@ -205,6 +206,43 @@ sub Cancel return undef; }
+sub Restart +{ + my $self = shift; + + if ($self->Status ne "failed" && $self->Status ne "completed") + { + return "Only completed/failed jobs can be restarted"; + } + + my $JobDir = "$DataDir/jobs/" . $self->Id; + my $FirstStep = 1; + my $Steps = $self->Steps; + my @SortedSteps = sort { $a->No <=> $b->No } @{$Steps->GetItems()}; + foreach my $Step (@SortedSteps) + { + my $Tasks = $Step->Tasks; + foreach my $Task (@{$Tasks->GetItems()}) + { + if ($FirstStep) + { + # The first step contains the patch or test executable + # so only delete its task folders + system("rm", "-rf", "$JobDir/" . $Step->No . "/" . $Task->No); + } + $Task->Status("queued"); + } + # Subsequent steps only contain files generated by the previous steps + system("rm", "-rf", "$JobDir/" . $Step->No) if (!$FirstStep); + $FirstStep = undef; + $Step->Status("queued"); + } + $self->Status("queued"); + $self->Save(); # Save it all + + return undef; +} + sub GetEMailRecipient { my $self = shift; diff --git a/testbot/web/JobDetails.pl b/testbot/web/JobDetails.pl index 2ca81b8..b191327 100644 --- a/testbot/web/JobDetails.pl +++ b/testbot/web/JobDetails.pl @@ -27,6 +27,7 @@ use WineTestBot::Config; use WineTestBot::Jobs; use WineTestBot::StepsTasks; use WineTestBot::Engine::Notify; +use WineTestBot::Log;
@JobDetailsPage::ISA = qw(ObjectModel::CGI::CollectionPage);
@@ -112,13 +113,40 @@ sub CanCancel return undef; }
-sub GetActions +sub CanRestart { my $self = shift;
- my $ErrMessage = $self->CanCancel(); + my $Job = CreateJobs()->GetItem($self->{JobId}); + my $Status = $Job->Status; + if ($Status ne "failed") + { + return "Job did not fail"; + }
- return defined($ErrMessage) ? [] : ["Cancel job"]; + my $Session = $self->GetCurrentSession(); + if (! defined($Session)) + { + return "You are not authorized to restart this job"; + } + my $CurrentUser = $Session->User; + if (! $CurrentUser->HasRole("admin") && + $Job->User->GetKey() ne $CurrentUser->GetKey()) # FIXME: Admin only? + { + return "You are not authorized to restart this job"; + } + + return undef; +} + +sub GetActions +{ + my $self = shift; + + # These are mutually exclusive + return ["Cancel job"] if (!defined $self->CanCancel()); + return ["Restart job"] if (!defined $self->CanRestart()); + return []; }
sub OnCancel @@ -142,6 +170,27 @@ sub OnCancel return 1; }
+sub OnRestart +{ + my $self = shift; + + my $ErrMessage = $self->CanRestart(); + if (defined($ErrMessage)) + { + $self->{ErrMessage} = $ErrMessage; + return !1; + } + + $ErrMessage = JobRestart($self->{JobId}); + if (defined($ErrMessage)) + { + $self->{ErrMessage} = $ErrMessage; + return !1; + } + + return 1; +} + sub OnAction { my $self = shift; @@ -151,6 +200,10 @@ sub OnAction { return $self->OnCancel(); } + elsif ($Action eq "Restart job") + { + return $self->OnRestart(); + }
return $self->SUPER::OnAction(@_); } @@ -189,7 +242,19 @@ sub GenerateBody { print "<h1>" . $self->GetTitle() . "</h1>\n"; print "<div class='Content'>\n"; - print "<p>Job will be cancelled.</p>\n"; + my $Action = $self->GetParam("Action"); + if ($Action eq "Cancel job") + { + print "<p>Job will be cancelled.</p>\n"; + } + elsif ($Action eq "Restart job") + { + print "<p>Job will be restarted.</p>\n"; + } + else + { + print "<p>Unknown action $Action.</p>\n"; + } print "</div>\n"; return; }