Repository
Munin (contrib)
Last change
2020-10-24
Graph Categories
Capabilities
Keywords
Language
Perl
License
JSON
Authors

jenkins_

Name

jenkins_ - Plugin for displaying Jenkins Stats

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 symlink:

  1. jenkins_results
  2. jenkins_queue
  3. jenkins_running

Configuration

This plugin is configurable via 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) env.jobDepth How far into job “folders” should the plugin check for jobs

Example:

[jenkins_*]
env.url localhost
env.port 4040
env.context /jenkins
env.user user
env.apiToken aaaa0f6e48b92cbbbbddecdb72dc1dad

Author

Philipp Haussleiter philipp@haussleiter.de (email)

License

GPLv2

#!/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 symlink:

1) jenkins_results
2) jenkins_queue
3) jenkins_running

=head1 CONFIGURATION

This plugin is configurable via 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)
env.jobDepth    How far into job "folders" should the plugin check for jobs

Example:

 [jenkins_*]
 env.url localhost
 env.port 4040
 env.context /jenkins
 env.user user
 env.apiToken aaaa0f6e48b92cbbbbddecdb72dc1dad


=head1 AUTHOR

Philipp Haussleiter <philipp@haussleiter.de> (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 $jobDepth = ($ENV{'jobDepth'} || 1);
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";
	} elsif( $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";
	} elsif( $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";
	} else {
		warn "Unknown mode requested: $type\n";
	}
} else {
	my $cmd = "$wgetBin $auth -qO- $url:$port$context";

	my $tree = 'jobs[name,color]';
	for (2..$jobDepth) {
		$tree = "jobs[name,color,$tree]";
	}

	if( $type eq "results" ) {
		my $result = `$cmd'/api/json?depth=$jobDepth&tree=$tree'`;
		my $parsed = decode_json($result);
		my $counts = parse_results($parsed->{'jobs'});

		foreach my $status (keys %{$counts}) {
			print "build_$status.value $counts->{$status}\n";
		}
	} elsif( $type eq "running" ) {
		my $result = `$cmd'/api/json?depth=$jobDepth&tree=$tree'`;
		my $parsed = decode_json($result);
		my $count = parse_running_builds($parsed->{'jobs'});
		print "build_running.value ", $count, "\n";
	} elsif( $type eq "queue" ) {
		my $result = `$cmd/queue/api/json`;
		my $parsed = decode_json($result);
		print "build_count.value ", scalar( @{$parsed->{'items'}} ), "\n";
	} else {
		warn "Unknown mode requested: $type\n";
	}
}

sub parse_running_builds {
	my $builds = shift;
	my $count = 0;
	foreach my $cur (@{$builds}) {
		if( defined($cur->{'jobs'}) ) {
			$count += parse_running_builds($cur->{'jobs'});
		} elsif( defined ($cur->{'color'}) and $cur->{'color'} =~ /anime$/ ) {
			$count += 1;
		}
	}
	return $count;
}

sub parse_results {
	my $builds = shift;
	my %counts = ('stable' => 0, 'unstable' => 0, 'failing' => 0, 'disabled' => 0);

	foreach my $cur(@{$builds}) {
		if( defined($cur->{'jobs'}) ) {
			my $new_counts = parse_results($cur->{'jobs'});
			foreach my $new_count_key (keys %{$new_counts}) {
				$counts{$new_count_key} += $new_counts->{$new_count_key};
			}
		} elsif (defined($cur->{'color'})) {
			if (defined($states{$cur->{'color'}})) {
				$counts{$states{$cur->{'color'}}} += 1;
			} else {
				warn "Ignoring unknown color " . $cur->{'color'} . "\n"
			}
		}
	}
	return \%counts;
}