Skip to content

Commit

Permalink
initial add for poudriere
Browse files Browse the repository at this point in the history
  • Loading branch information
VVelox committed Mar 25, 2024
1 parent ceef8c4 commit 6562441
Showing 1 changed file with 356 additions and 0 deletions.
356 changes: 356 additions & 0 deletions snmp/poudriere
Original file line number Diff line number Diff line change
@@ -0,0 +1,356 @@
#!/usr/bin/env perl

=head1 NAME
poudriere - LibreNMS JSON style SNMP extend for monitoring Poudriere
=head1 VERSION
0.0.1
=head1 SYNOPSIS
poudriere [B<-w>] [B<-b>] [B<-o> <cache base>]
poudriere --help|-h
poudriere --version|-v
=head1 SNMPD CONFIG
extend poudriere /etc/snmp/extends/poudriere -b
or if using cron...
extend poudriere cat /var/cache/poudriere.json.snmp
=head1 DESCRIPTION
Uses showmount and nfsstat to gather information for the OSes below for NFS.
FreeBSD
Linux
=head1 FLAGS
=head2 -w
Write the results out.
=head2 -b
Print out the compressed data if GZip+Base64 is smaller.
=head2 -o <cache base>
Where to write the results to. Defaults to '/var/cache/poudriere.json',
meaning it will be written out to the two locations.
/var/cache/poudriere.json
/var/cache/poudriere.json.snmp
The later is for use with returning data for SNMP. Will be compressed
if possible.
=cut

use strict;
use warnings;
use Getopt::Long;
use File::Slurp;
use MIME::Base64;
use IO::Compress::Gzip qw(gzip $GzipError);
use Pod::Usage;
use JSON;

sub time_to_seconds{
my $time=$_[0];

if (!defined($time)) {
return 0;
}

if ($time=~/^0\:[0-9]+\.[0-9]+$/) {
$time=~s/^0\://;
return $time;
}elsif ($time=~/^[0-9]+\:[0-9]+\.[0-9]+$/) {
my $minutes=$time;
$minutes=~s/\:.*//;
$time=~s/.*\://;
$time = ($minutes * 60) + $time;
return $time;
}elsif ($time=~/^[0-9]+D\:[0-9]+\:[0-9]+\.[0-9]+$/) {
my $days=$time;
$days=~s/D\:.*$//;
my $minutes=$time;
$minutes=~s/^.*D\://;
$minutes=~s/\:.*//;
$time = ($days * 86400) + ($minutes * 60) + $time;
return $time;
}

# return 0 for anything unknown
return 0;
}

#the version of returned data
my $VERSION = 1;

# ensure sbin is in the path
$ENV{PATH} = $ENV{PATH} . ':/sbin:/usr/sbin:/usr/local/sbin:/bin:/usr/bin:/usr/local/bin';

my $pretty;
my $cache_base = '/var/cache/poudriere.json';
my $write;
my $compress;
my $version;
my $help;
GetOptions(
'o=s' => \$cache_base,
w => \$write,
b => \$compress,
v => \$version,
version => \$version,
h => \$help,
help => \$help,
);

if ($version) {
pod2usage( -exitval => 255, -verbose => 99, -sections => qw(VERSION), -output => \*STDOUT, );
exit 255;
}

if ($help) {
pod2usage( -exitval => 255, -verbose => 2, -output => \*STDOUT, );
exit 255;
}

#the data to return
my $to_return = {
'version' => $VERSION,
'error' => '0',
'errorString' => '',
};
my $data = {
status => '',
build_info => '',
not_done => 0,
stats => {
'copy-on-write-faults' => 0,
'cpu-time' => 0,
'data-size' => 0,
'elapsed-times' => 0,
'involuntary-context-switches' => 0,
'job-control-count' => 0,
'major-faults' => 0,
'minor-faults' => 0,
'percent-cpu' => 0,
'percent-memory' => 0,
'read-blocks' => 0,
'received-messages' => 0,
'rss' => 0,
'sent-messages' => 0,
'stack-size' => 0,
'swaps' => 0,
'system-time' => 0,
'text-size' => 0,
'threads' => 0,
'user-time' => 0,
'voluntary-context-switches' => 0,
'written-blocks' => 0,
'QUEUE' => 0,
'BUILT' => 0,
'FAIL' => 0,
'SKIP' => 0,
'IGNORE' => 0,
'FETCH' => 0,
'REMAIN' => 0,
'TIME' => 0,
},
jailANDportsANDset => {}
};

my @ps_stats = (
'copy-on-write-faults', 'cpu-time',
'data-size', 'elapsed-times',
'involuntary-context-switches', 'job-control-count',
'major-faults', 'minor-faults',
'percent-cpu', 'percent-memory',
'read-blocks', 'received-messages',
'rss', 'sent-messages', 'stack-size',
'swaps', 'system-time',
'text-size', 'threads',
'user-time', 'voluntary-context-switches',
);

my @poudriere_stats = ( 'QUEUE', 'BUILT', 'FAIL', 'SKIP', 'IGNORE', 'FETCH', 'REMAIN', 'TIME' );

###
###
### get basic info via calling poudriere status
###
###

my $status_raw = `poudriere -N status -f 2> /dev/null`;
if ( $? == 0 ) {
$data->{status} = $status_raw;
$data->{build_info} = `poudriere -N status -f -b 2>&1`;

my @status_split = split( /\n/, $status_raw );
my $status_split_int = 1;
while ( defined( $status_split[$status_split_int] ) ) {

my $jls;
eval { $jls = decode_json(`jls --libxo json`); };
if ($@) {
$jls = { 'jail-information' => { jail => [] } };
}

my $found = {
'copy-on-write-faults' => 0,
'cpu-time' => 0,
'data-size' => 0,
'elapsed-times' => 0,
'involuntary-context-switches' => 0,
'job-control-count' => 0,
'major-faults' => 0,
'minor-faults' => 0,
'percent-cpu' => 0,
'percent-memory' => 0,
'read-blocks' => 0,
'received-messages' => 0,
'rss' => 0,
'sent-messages' => 0,
'stack-size' => 0,
'swaps' => 0,
'system-time' => 0,
'text-size' => 0,
'threads' => 0,
'user-time' => 0,
'voluntary-context-switches' => 0,
};
(
$found->{SET}, $found->{PORTS}, $found->{JAIL}, $found->{BUILD}, $found->{STATUS},
$found->{QUEUE}, $found->{BUILT}, $found->{FAIL}, $found->{SKIP}, $found->{IGNORE},
$found->{FETCH}, $found->{REMAIN}, $found->{TIME}, $found->{LOGS}
) = split( / +/, $status_split[$status_split_int], 14 );

if ($found->{STATUS} ne 'done') {
$data->{not_done}=1;
}

my $jailANDportsANDset;
if ( $found->{SET} eq '-' ) {
$jailANDportsANDset = $found->{JAIL} . '-' . $found->{PORTS};
} else {
$jailANDportsANDset = $found->{JAIL} . '-' . $found->{PORTS} . '-' . $found->{SET};
}

foreach my $item (@poudriere_stats) {
if ($item eq 'TIME') {
$found->{$item} = time_to_seconds($found->{$item});
}
$data->{stats}{$item} += $found->{$item};
}

##
## find the jails
##
my @jails;
my $jail_regex='^'.$jailANDportsANDset.'-job-[0-9]+';
my $jls_int=0;
while (defined( $jls->{'jail-information'}{jail}[$jls_int] )) {
if (
$jls->{'jail-information'}{jail}[$jls_int]{hostname} eq $jailANDportsANDset ||
$jls->{'jail-information'}{jail}[$jls_int]{hostname} =~ /$jail_regex/
) {
push(@jails, $jls->{'jail-information'}{jail}[$jls_int]{jid});
}
$jls_int++;
}

##
## if we have found jails, grab the information via ps
##
if (defined($jails[0])) {
my $jails_string=join(',', @jails);

my $ps;
eval {
$ps = decode_json(`ps -o 'jid %cpu %mem rss cow dsiz etimes inblk jobc majflt minflt msgrcv msgsnd nivcsw nlwp nsigs nswap nvcsw oublk ssiz systime time tsiz usertime' --libxo json -J $jails_string`);
};
if ($@) {
$ps = { 'process-information' => { process => [] } };
}
my $ps_int=0;
while (defined( $ps->{'process-information'}{process}[$ps_int] )) {
foreach my $item (@ps_stats) {
if ($item eq 'user-time' || $item eq 'cpu-time' || $item eq 'system-time') {
$ps->{'process-information'}{process}[$ps_int]{$item} = time_to_seconds($ps->{'process-information'}{process}[$ps_int]{$item});
}
$data->{stats}{$item} += $ps->{'process-information'}{process}[$ps_int]{$item};
$found->{$item} += $ps->{'process-information'}{process}[$ps_int]{$item};
}
$ps_int++;
}
}

$data->{jailANDportsANDset}{$jailANDportsANDset} = $found;
$status_split_int++;
} ## end while ( defined( $status_split[$status_split_int...]))
} else {
$to_return->{error} = 1;
$to_return->{errorString} = 'non-zero exit for "poudriere status -f"';
}

###
###
### finalize it
###
###

#add the data has to the return hash
$to_return->{data} = $data;

#finally render the JSON
my $raw_json = encode_json($to_return);
if ($write) {
write_file( $cache_base, $raw_json );
# compress and write to the cache file for it
my $compressed_string;
gzip \$raw_json => \$compressed_string;
my $compressed = encode_base64($compressed_string);
$compressed =~ s/\n//g;
$compressed = $compressed . "\n";
my $print_compressed = 0;
if ( length($compressed) > length($raw_json) ) {
write_file( $cache_base . '.snmp', $raw_json );
} else {
write_file( $cache_base . '.snmp', $compressed );
$print_compressed = 1;
}

if ( $compress && $print_compressed ) {
print $compressed;
} else {
print $raw_json;
}
} else {
if ( !$compress ) {
print $raw_json. "\n";
exit;
}

# compress and write to the cache file for it
my $compressed_string;
gzip \$raw_json => \$compressed_string;
my $compressed = encode_base64($compressed_string);
$compressed =~ s/\n//g;
$compressed = $compressed . "\n";
my $print_compressed = 0;
if ( length($compressed) > length($raw_json) ) {
print $raw_json;
} else {
print $compressed;
}
} ## end else [ if ($write) ]

0 comments on commit 6562441

Please sign in to comment.