From 7818bb75ede7512fb503887df9cb58debecfb8cd Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Fri, 4 Oct 2013 15:40:43 +0200 Subject: [PATCH] Add an action to cancel all builds in a jobset eval --- src/lib/Hydra/Controller/Admin.pm | 8 +++--- src/lib/Hydra/Controller/Build.pm | 34 ++++++-------------------- src/lib/Hydra/Controller/JobsetEval.pm | 9 +++++++ src/lib/Hydra/Helper/Nix.pm | 25 ++++++++++++++++--- src/root/jobset-eval.tt | 1 + src/root/topbar.tt | 2 +- 6 files changed, 44 insertions(+), 35 deletions(-) diff --git a/src/lib/Hydra/Controller/Admin.pm b/src/lib/Hydra/Controller/Admin.pm index f2a34459..a73762dc 100644 --- a/src/lib/Hydra/Controller/Admin.pm +++ b/src/lib/Hydra/Controller/Admin.pm @@ -34,12 +34,12 @@ sub machines : Chained('admin') PathPart('machines') Args(0) { sub clear_queue_non_current : Chained('admin') PathPart('clear-queue-non-current') Args(0) { my ($self, $c) = @_; - my $time = time(); - $c->model('DB::Builds')->search( + my $builds = $c->model('DB::Builds')->search( { finished => 0, busy => 0 , id => { -not_in => \ "select build from JobsetEvalMembers where eval in (select max(id) from JobsetEvals where hasNewBuilds = 1 group by project, jobset)" } - }, {}) - ->update({ finished => 1, buildstatus => 4, starttime => $time, stoptime => $time }); + }); + my $n = cancelBuilds($c->model('DB')->schema, $builds); + $c->flash->{successMsg} = "$n builds have been cancelled."; $c->res->redirect($c->request->referer // "/admin"); } diff --git a/src/lib/Hydra/Controller/Build.pm b/src/lib/Hydra/Controller/Build.pm index f0524aa4..7d62ebba 100644 --- a/src/lib/Hydra/Controller/Build.pm +++ b/src/lib/Hydra/Controller/Build.pm @@ -60,7 +60,6 @@ sub build_GET { $c->stash->{template} = 'build.tt'; $c->stash->{available} = all { isValidPath($_->path) } $build->buildoutputs->all; $c->stash->{drvAvailable} = isValidPath $build->drvpath; - $c->stash->{flashMsg} = $c->flash->{buildMsg}; if (!$build->finished && $build->busy) { $c->stash->{logtext} = read_file($build->logfile, err_mode => 'quiet') // ""; @@ -448,7 +447,7 @@ sub restart : Chained('buildChain') PathPart Args(0) { restartBuild($c->model('DB')->schema, $build); - $c->flash->{buildMsg} = "Build has been restarted."; + $c->flash->{successMsg} = "Build has been restarted."; $c->res->redirect($c->uri_for($self->action_for("build"), $c->req->captures)); } @@ -456,30 +455,11 @@ sub restart : Chained('buildChain') PathPart Args(0) { sub cancel : Chained('buildChain') PathPart Args(0) { my ($self, $c) = @_; - my $build = $c->stash->{build}; - requireProjectOwner($c, $build->project); - - txn_do($c->model('DB')->schema, sub { - error($c, "This build cannot be cancelled.") - if $build->finished || $build->busy; - - # !!! Actually, it would be nice to be able to cancel busy - # builds as well, but we would have to send a signal or - # something to the build process. - - my $time = time(); - $build->update( - { finished => 1, busy => 0 - , iscachedbuild => 0, buildstatus => 4 # = cancelled - , starttime => $time - , stoptime => $time - }); - }); - - $c->flash->{buildMsg} = "Build has been cancelled."; - + my $n = cancelBuilds($c->model('DB')->schema, $c->model('DB::Builds')->search({ id => $build->id })); + error($c, "This build cannot be cancelled.") if $n != 1; + $c->flash->{successMsg} = "Build has been cancelled."; $c->res->redirect($c->uri_for($self->action_for("build"), $c->req->captures)); } @@ -500,7 +480,7 @@ sub keep : Chained('buildChain') PathPart Args(1) { $build->update({keep => $keep}); }); - $c->flash->{buildMsg} = + $c->flash->{successMsg} = $keep ? "Build will be kept." : "Build will not be kept."; $c->res->redirect($c->uri_for($self->action_for("build"), $c->req->captures)); @@ -530,7 +510,7 @@ sub add_to_release : Chained('buildChain') PathPart('add-to-release') Args(0) { $release->releasemembers->create({build => $build->id, description => $build->description}); - $c->flash->{buildMsg} = "Build added to project $releaseName."; + $c->flash->{successMsg} = "Build added to project $releaseName."; $c->res->redirect($c->uri_for($self->action_for("build"), $c->req->captures)); } @@ -607,7 +587,7 @@ sub clone_submit : Chained('buildChain') PathPart('clone/submit') Args(0) { error($c, "This build has already been performed.") unless $newBuild; - $c->flash->{buildMsg} = "Build " . $newBuild->id . " added to the queue."; + $c->flash->{successMsg} = "Build " . $newBuild->id . " added to the queue."; $c->res->redirect($c->uri_for($c->controller('Root')->action_for('queue'))); } diff --git a/src/lib/Hydra/Controller/JobsetEval.pm b/src/lib/Hydra/Controller/JobsetEval.pm index 9fa99dd8..b3291166 100644 --- a/src/lib/Hydra/Controller/JobsetEval.pm +++ b/src/lib/Hydra/Controller/JobsetEval.pm @@ -152,6 +152,15 @@ sub release : Chained('eval') PathPart('release') Args(0) { } +sub cancel : Chained('eval') PathPart('cancel') Args(0) { + my ($self, $c) = @_; + requireProjectOwner($c, $c->stash->{eval}->project); + my $n = cancelBuilds($c->model('DB')->schema, $c->stash->{eval}->builds); + $c->flash->{successMsg} = "$n builds have been cancelled."; + $c->res->redirect($c->uri_for($c->controller('JobsetEval')->action_for('view'), $c->req->captures)); +} + + # Hydra::Base::Controller::NixChannel needs this. sub nix : Chained('eval') PathPart('channel') CaptureArgs(0) { my ($self, $c) = @_; diff --git a/src/lib/Hydra/Helper/Nix.pm b/src/lib/Hydra/Helper/Nix.pm index d12c569c..f5d62c7a 100644 --- a/src/lib/Hydra/Helper/Nix.pm +++ b/src/lib/Hydra/Helper/Nix.pm @@ -21,7 +21,8 @@ our @EXPORT = qw( getEvals getMachines pathIsInsidePrefix captureStdoutStderr run grab - getTotalShares); + getTotalShares + cancelBuilds); sub getHydraHome { @@ -43,11 +44,12 @@ sub getHydraConfig { # doesn't work. sub txn_do { my ($db, $coderef) = @_; + my $res; while (1) { eval { - $db->txn_do($coderef); + $res = $db->txn_do($coderef); }; - last if !$@; + return $res if !$@; die $@ unless $@ =~ "database is locked"; } } @@ -542,4 +544,21 @@ sub getTotalShares { } +sub cancelBuilds($$) { + my ($db, $builds) = @_; + return txn_do($db, sub { + $builds = $builds->search({ finished => 0, busy => 0 }); + my $n = $builds->count; + my $time = time(); + $builds->update( + { finished => 1, + , iscachedbuild => 0, buildstatus => 4 # = cancelled + , starttime => $time + , stoptime => $time + }); + return $n; + }); +} + + 1; diff --git a/src/root/jobset-eval.tt b/src/root/jobset-eval.tt index e6d579ef..81044b0a 100644 --- a/src/root/jobset-eval.tt +++ b/src/root/jobset-eval.tt @@ -42,6 +42,7 @@ c.uri_for(c.controller('JobsetEval').action_for('view'), [% END %] diff --git a/src/root/topbar.tt b/src/root/topbar.tt index af539ffa..f3a8a89d 100644 --- a/src/root/topbar.tt +++ b/src/root/topbar.tt @@ -91,7 +91,7 @@ class = "" %] [% INCLUDE menuItem uri = c.uri_for(c.controller('Admin').action_for('clear_queue_non_current')) - title = "Clear all non-running old builds from queue" + title = "Clear scheduled non-current builds from queue" confirmmsg = "Are you sure you want to clear the queue?" class = "" %] [% INCLUDE menuItem