Francois Gouget : testbot: Make it possible to restart a failed job.
Alexandre Julliard
julliard at winehq.org
Tue Jan 22 12:57:44 CST 2013
Module: tools
Branch: master
Commit: b8fbfb378bbaa359068131d038280b5a1d05f2c7
URL: http://source.winehq.org/git/tools.git/?a=commit;h=b8fbfb378bbaa359068131d038280b5a1d05f2c7
Author: Francois Gouget <fgouget at 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);
- at EXPORT = qw(&PingEngine &JobSubmit &JobStatusChange &JobCancel &TaskComplete
- &VMStatusChange &ExpectWinetestUpdate &FoundWinetestUpdate
+ at 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;
}
More information about the wine-cvs
mailing list