#!/usr/bin/env perl # -*- perl -*- =head1 NAME jenkins_ - Plugin for displaying Jenkins Stats =head1 INTERPRETATION This plugin displays the following charts: 1) The Status of each Build 2) Number of Jobs in the Build Queue 3) Number of Builds, currently running You can set the modes with naming the softlink: 1) jenkins_results 2) jenkins_queue 3) jenkins_running =head1 CONFIGURATION This plugin is configurable environment variables. env.url Jenkins Host env.port Jenkins Port env.context Jenkins Context path env.user User for the API Tokent env.apiToken Jenkins API Token (see https://wiki.jenkins-ci.org/display/JENKINS/Authenticating+scripted+clients) Example: [jenkins_*] env.url localhost env.port 4040 env.context /jenkins env.user user env.apiToken aaaa0f6e48b92cbbbbddecdb72dc1dad =head1 AUTHOR Philipp Haussleiter (email) =head1 LICENSE GPLv2 =cut # MAIN use warnings; use strict; use JSON; use File::Basename; use URI; # VARS my $url = ($ENV{'url'} || 'localhost'); my $port = ($ENV{'port'} || '4040'); my $user = ($ENV{'user'} || ''); my $apiToken = ($ENV{'apiToken'} || ''); my $context = ($ENV{'context'} || ''); my $wgetBin = "/usr/bin/wget"; my $type = basename($0); $type =~ s/jenkins_//; my %states = ( 'blue' =>'stable', 'blue_anime' =>'stable', 'yellow'=>'unstable', 'yellow_anime'=>'unstable', 'red'=>'failing', 'red_anime'=>'failing', 'disabled'=>'disabled', 'notbuilt' => 'disabled', 'notbuilt_anime' =>'disabled', 'aborted'=>'failing', 'aborted_anime'=>'failing' ); my $auth = ( $user ne "" and $apiToken ne "" ? " --auth-no-challenge --user=$user --password=$apiToken" : "" ); if ( exists $ARGV[0] and $ARGV[0] eq "config" ) { if( $type eq "results" ) { print "graph_args --base 1000 -l 0\n"; print "graph_title Jenkins Build Results\n"; print "graph_vlabel Build Results\n"; print "graph_category devel\n"; print "graph_info The Graph shows the Status of each Build\n"; print "build_disabled.draw AREA\n"; print "build_disabled.label disabled\n"; print "build_disabled.type GAUGE\n"; print "build_disabled.colour 8A8A8A\n"; print "build_failing.draw STACK\n"; print "build_failing.label failing\n"; print "build_failing.type GAUGE\n"; print "build_failing.colour E61217\n"; print "build_unstable.draw STACK\n"; print "build_unstable.label unstable\n"; print "build_unstable.type GAUGE\n"; print "build_unstable.colour F3E438\n"; print "build_stable.draw STACK\n"; print "build_stable.label stable\n"; print "build_stable.type GAUGE\n"; print "build_stable.colour 294D99\n"; exit; } if( $type eq "queue" ) { print "graph_args --base 1000 -l 0\n"; print "graph_title Jenkins Queue Length\n"; print "graph_vlabel Number of Jobs in Queue\n"; print "graph_category devel\n"; print "graph_info The Graph shows the Number of Jobs in the Build Queue\n"; print "build_count.label Jobs in Queue\n"; print "build_count.type GAUGE\n"; exit; } if( $type eq "running" ) { print "graph_args --base 1000 -l 0\n"; print "graph_title Jenkins Builds Running\n"; print "graph_vlabel Builds currently running\n"; print "graph_category devel\n"; print "graph_info The Graph shows the Number of Builds, currently running\n"; print "build_running.label running Builds\n"; print "build_running.type GAUGE\n"; exit; } } else { my $cmd = "$wgetBin $auth -qO- $url:$port$context"; if( $type eq "results" ) { my $counts = get_results(''); foreach my $status (keys %{$counts}) { print "build_$status.value $counts->{$status}\n"; } exit; } if( $type eq "running" ) { my $running_count = get_running(''); print "build_running.value ", $running_count, "\n"; exit; } if( $type eq "queue" ) { my $result = `$cmd/queue/api/json`; my $parsed = decode_json($result); print "build_count.value ", scalar( @{$parsed->{'items'}} ), "\n"; exit; } } { my %counts; sub get_results{ my $query_context = shift; die "get_results requires an argument" unless defined $query_context; unless (%counts) { # initialise %counts = ('stable' => 0, 'unstable'=>0, 'failing'=>0, 'disabled'=>0); } my $cmd = "$wgetBin $auth -qO- $url:$port$context$query_context/api/json"; my $result = `$cmd`; my $parsed = decode_json($result); foreach my $cur(@{$parsed->{'jobs'}}) { if (exists $cur->{'color'} && defined $states{$cur->{'color'}}) { $counts{$states{$cur->{'color'}}} += 1; } elsif ($cur->{'_class'} eq 'com.cloudbees.hudson.plugins.folder.Folder'){ my $uri = URI->new($cur->{'url'}); my $folder = $uri->path; get_results($folder); } else { warn "Ignoring unknown color " . $cur->{'color'} . "\n" } } return \%counts; } } { my $running_count; sub get_running{ my $query_context = shift; die "get_results requires an argument" unless defined $query_context; $running_count //= 0; my $cmd = "$wgetBin $auth -qO- $url:$port$context$query_context/api/json"; my $result = `$cmd`; my $parsed = decode_json($result); foreach my $cur(@{$parsed->{'jobs'}}) { if( exists $cur->{'color'} && $cur->{'color'} =~ /anime$/ ) { $running_count += 1; } elsif ($cur->{'_class'} eq 'com.cloudbees.hudson.plugins.folder.Folder'){ my $uri = URI->new($cur->{'url'}); my $folder = $uri->path; get_running($folder); } } return $running_count; } }