From 937e16532880ea447d2e1ea19cc6997cbeb371b5 Mon Sep 17 00:00:00 2001 From: Graham Christensen Date: Tue, 24 Sep 2019 16:34:16 -0400 Subject: [PATCH 1/5] export a /prometheus endpoint Currently only shows per-machine build times --- release.nix | 1 + src/lib/Hydra/Controller/Root.pm | 45 ++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/release.nix b/release.nix index 04fdc682..92760b3c 100644 --- a/release.nix +++ b/release.nix @@ -99,6 +99,7 @@ rec { LWP LWPProtocolHttps NetAmazonS3 + NetPrometheus NetStatsd PadWalker Readonly diff --git a/src/lib/Hydra/Controller/Root.pm b/src/lib/Hydra/Controller/Root.pm index 188d73bd..32c841b0 100644 --- a/src/lib/Hydra/Controller/Root.pm +++ b/src/lib/Hydra/Controller/Root.pm @@ -6,6 +6,7 @@ use warnings; use base 'Hydra::Base::Controller::ListBuilds'; use Hydra::Helper::Nix; use Hydra::Helper::CatalystUtils; +use Hydra::View::TT; use Digest::SHA1 qw(sha1_hex); use Nix::Store; use Nix::Config; @@ -13,6 +14,7 @@ use Encode; use File::Basename; use JSON; use List::MoreUtils qw{any}; +use Net::Prometheus; # Put this controller at top-level. __PACKAGE__->config->{namespace} = ''; @@ -200,6 +202,49 @@ sub machines :Local Args(0) { $self->status_ok($c, entity => $c->stash->{machines}); } +sub prometheus :Local Args(0) { + my ($self, $c) = @_; + my $machines = getMachines; + + my $client = Net::Prometheus->new; + my $duration = $client->new_histogram( + name => "hydra_machine_build_duration", + help => "How long builds are taking per server. Note: counts are gauges, NOT counters.", + labels => [ "machine" ], + buckets => [ + 60, + 600, + 1800, + 3600, + 7200, + 21600, + 43200, + 86400, + 172800, + 259200, + 345600, + 518400, + 604800, + 691200 + ] + ); + + my $steps = dbh($c)->selectall_arrayref( + "select machine, s.starttime as starttime " . + "from BuildSteps s join Builds b on s.build = b.id " . + "where busy != 0 order by machine, stepnr", + { Slice => {} }); + + foreach my $step (@$steps) { + my $name = $step->{machine} ? Hydra::View::TT->stripSSHUser(undef, $step->{machine}) : ""; + $name = "localhost" unless $name; + $duration->labels($name)->observe(time - $step->{starttime}); + } + + $c->stash->{'plain'} = { data => $client->render }; + $c->forward('Hydra::View::Plain'); +} + # Hydra::Base::Controller::ListBuilds needs this. sub get_builds : Chained('/') PathPart('') CaptureArgs(0) { From 3a04f28459743033d3711e7a6ecde2ae937b5349 Mon Sep 17 00:00:00 2001 From: Graham Christensen Date: Tue, 24 Sep 2019 16:51:18 -0400 Subject: [PATCH 2/5] hydra: upgrade nixpkgs to 19.09 --- release.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release.nix b/release.nix index 92760b3c..408e3f69 100644 --- a/release.nix +++ b/release.nix @@ -1,5 +1,5 @@ { hydraSrc ? builtins.fetchGit ./. -, nixpkgs ? builtins.fetchGit { url = https://github.com/NixOS/nixpkgs-channels.git; ref = "nixos-19.03-small"; } +, nixpkgs ? builtins.fetchGit { url = https://github.com/NixOS/nixpkgs-channels.git; ref = "nixos-19.09-small"; } , officialRelease ? false , shell ? false }: From 840e99f85913c87db715b8757f4d7abb7c8eaae6 Mon Sep 17 00:00:00 2001 From: Bas van Dijk Date: Tue, 5 Nov 2019 13:58:40 +0100 Subject: [PATCH 3/5] hydra-eval-jobset: $firstOutput is not used so can be removed --- src/script/hydra-eval-jobset | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/script/hydra-eval-jobset b/src/script/hydra-eval-jobset index 2049fe24..fcc60a6c 100755 --- a/src/script/hydra-eval-jobset +++ b/src/script/hydra-eval-jobset @@ -431,8 +431,6 @@ sub checkBuild { # new build to be scheduled if the meta.maintainers field is # changed? if (defined $prevEval) { - # Only check one output: if it's the same, the other will be as well. - my $firstOutput = $outputNames[0]; my ($prevBuild) = $prevEval->builds->search( # The "project" and "jobset" constraints are # semantically unnecessary (because they're implied by From ce1e10c116aab5e4f77a28912e033ac3d554df06 Mon Sep 17 00:00:00 2001 From: Andreas Rammhold Date: Tue, 5 Nov 2019 19:24:51 +0100 Subject: [PATCH 4/5] Add bump-to-front role --- src/lib/Hydra/Controller/Build.pm | 2 +- src/lib/Hydra/Controller/JobsetEval.pm | 2 +- src/lib/Hydra/Helper/CatalystUtils.pm | 22 ++++++++++++++++++++++ src/root/user.tt | 1 + 4 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/lib/Hydra/Controller/Build.pm b/src/lib/Hydra/Controller/Build.pm index 3d490e06..b62b4994 100644 --- a/src/lib/Hydra/Controller/Build.pm +++ b/src/lib/Hydra/Controller/Build.pm @@ -540,7 +540,7 @@ sub bump : Chained('buildChain') PathPart('bump') { my $build = $c->stash->{build}; - requireProjectOwner($c, $build->project); # FIXME: require admin? + requireBumpPrivileges($c, $build->project); $c->model('DB')->schema->txn_do(sub { $build->update({globalpriority => time()}); diff --git a/src/lib/Hydra/Controller/JobsetEval.pm b/src/lib/Hydra/Controller/JobsetEval.pm index 77a4385f..31d5d4c4 100644 --- a/src/lib/Hydra/Controller/JobsetEval.pm +++ b/src/lib/Hydra/Controller/JobsetEval.pm @@ -210,7 +210,7 @@ sub restart_failed : Chained('evalChain') PathPart('restart-failed') Args(0) { sub bump : Chained('evalChain') PathPart('bump') Args(0) { my ($self, $c) = @_; - requireProjectOwner($c, $c->stash->{eval}->project); # FIXME: require admin? + requireBumpPrivileges($c, $c->stash->{eval}->project); # FIXME: require admin? my $builds = $c->stash->{eval}->builds->search({ finished => 0 }); my $n = $builds->count(); $c->model('DB')->schema->txn_do(sub { diff --git a/src/lib/Hydra/Helper/CatalystUtils.pm b/src/lib/Hydra/Helper/CatalystUtils.pm index b9019638..fa88aacb 100644 --- a/src/lib/Hydra/Helper/CatalystUtils.pm +++ b/src/lib/Hydra/Helper/CatalystUtils.pm @@ -13,6 +13,7 @@ our @EXPORT = qw( searchBuildsAndEvalsForJobset error notFound gone accessDenied forceLogin requireUser requireProjectOwner requireRestartPrivileges requireAdmin requirePost isAdmin isProjectOwner + requireBumpPrivileges trim getLatestFinishedEval getFirstEval paramToList @@ -181,6 +182,27 @@ sub isProjectOwner { defined $c->model('DB::ProjectMembers')->find({ project => $project, userName => $c->user->username })); } +sub hasBumpJobsRole { + my ($c) = @_; + return $c->user_exists && $c->check_user_roles('bump-to-front'); +} + +sub mayBumpJobs { + my ($c, $project) = @_; + return + $c->user_exists && + (isAdmin($c) || + hasBumpJobsRole($c) || + isProjectOwner($c, $project)); +} + +sub requireBumpPrivileges { + my ($c, $project) = @_; + requireUser($c); + accessDenied($c, "Only the project members, administrators, and accounts with bump-to-front privileges can perform this operation.") + unless mayBumpJobs($c, $project); +} + sub hasRestartJobsRole { my ($c) = @_; return $c->user_exists && $c->check_user_roles('restart-jobs'); diff --git a/src/root/user.tt b/src/root/user.tt index e95ee689..86f35916 100644 --- a/src/root/user.tt +++ b/src/root/user.tt @@ -81,6 +81,7 @@ [% INCLUDE roleoption role="admin" %] [% INCLUDE roleoption role="create-projects" %] [% INCLUDE roleoption role="restart-jobs" %] + [% INCLUDE roleoption role="bump-to-front" %] From 841a47cabed81299dea0972312216dfdfdb6d896 Mon Sep 17 00:00:00 2001 From: Andreas Rammhold Date: Tue, 5 Nov 2019 19:29:36 +0100 Subject: [PATCH 5/5] Add cancel-build role --- src/lib/Hydra/Controller/Build.pm | 2 +- src/lib/Hydra/Controller/JobsetEval.pm | 2 +- src/lib/Hydra/Helper/CatalystUtils.pm | 22 ++++++++++++++++++++++ src/root/user.tt | 1 + 4 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/lib/Hydra/Controller/Build.pm b/src/lib/Hydra/Controller/Build.pm index b62b4994..22bfd98e 100644 --- a/src/lib/Hydra/Controller/Build.pm +++ b/src/lib/Hydra/Controller/Build.pm @@ -504,7 +504,7 @@ 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); + requireCancelBuildPrivileges($c, $build->project); 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."; diff --git a/src/lib/Hydra/Controller/JobsetEval.pm b/src/lib/Hydra/Controller/JobsetEval.pm index 31d5d4c4..62c655e7 100644 --- a/src/lib/Hydra/Controller/JobsetEval.pm +++ b/src/lib/Hydra/Controller/JobsetEval.pm @@ -179,7 +179,7 @@ sub create_jobset : Chained('evalChain') PathPart('create-jobset') Args(0) { sub cancel : Chained('evalChain') PathPart('cancel') Args(0) { my ($self, $c) = @_; - requireProjectOwner($c, $c->stash->{eval}->project); + requireCancelBuildPrivileges($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)); diff --git a/src/lib/Hydra/Helper/CatalystUtils.pm b/src/lib/Hydra/Helper/CatalystUtils.pm index fa88aacb..d363f966 100644 --- a/src/lib/Hydra/Helper/CatalystUtils.pm +++ b/src/lib/Hydra/Helper/CatalystUtils.pm @@ -14,6 +14,7 @@ our @EXPORT = qw( error notFound gone accessDenied forceLogin requireUser requireProjectOwner requireRestartPrivileges requireAdmin requirePost isAdmin isProjectOwner requireBumpPrivileges + requireCancelBuildPrivileges trim getLatestFinishedEval getFirstEval paramToList @@ -182,6 +183,27 @@ sub isProjectOwner { defined $c->model('DB::ProjectMembers')->find({ project => $project, userName => $c->user->username })); } +sub hasCancelBuildRole { + my ($c) = @_; + return $c->user_exists && $c->check_user_roles('cancel-build'); +} + +sub mayCancelBuild { + my ($c, $project) = @_; + return + $c->user_exists && + (isAdmin($c) || + hasCancelBuildRole($c) || + isProjectOwner($c, $project)); +} + +sub requireCancelBuildPrivileges { + my ($c, $project) = @_; + requireUser($c); + accessDenied($c, "Only the project members, administrators, and accounts with cancel-build privileges can perform this operation.") + unless mayCancelBuild($c, $project); +} + sub hasBumpJobsRole { my ($c) = @_; return $c->user_exists && $c->check_user_roles('bump-to-front'); diff --git a/src/root/user.tt b/src/root/user.tt index 86f35916..d489d338 100644 --- a/src/root/user.tt +++ b/src/root/user.tt @@ -82,6 +82,7 @@ [% INCLUDE roleoption role="create-projects" %] [% INCLUDE roleoption role="restart-jobs" %] [% INCLUDE roleoption role="bump-to-front" %] + [% INCLUDE roleoption role="cancel-build" %]