diff options
Diffstat (limited to 'check_speedtest_servers')
-rwxr-xr-x | check_speedtest_servers | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/check_speedtest_servers b/check_speedtest_servers new file mode 100755 index 0000000..6b0aa10 --- /dev/null +++ b/check_speedtest_servers @@ -0,0 +1,134 @@ +#!/usr/bin/perl + +# +# Check an Ookla Speedtest server with a specified URL and/or host is present +# on the list of servers. +# +# Author: Tom Ryder <tom@sanctum.geek.nz> +# Copyright: 2018 Tom Ryder +# +package Monitoring::Plugin::Speedtest::Servers; + +# Force me to write this properly +use strict; +use warnings; +use utf8; + +# Require at least this Perl version +# Should work even on very old Perls +use 5.006; + +# Import required modules +use English '-no_match_vars'; +use LWP::UserAgent (); +use Monitoring::Plugin qw(%ERRORS); +use XML::LibXML; + +# Decree package version +our $VERSION = '0.01'; + +# Add description and license package variables +our $DESCRIPTION = <<'EOF'; +This plugin retrieves the list of speedtest servers from speedtest.net and +checks for the presence of at least one server with the given host and/or URL. +EOF +our $LICENSE = <<'EOF'; +This plugin is distributed under an MIT license. See LICENSE, or visit +<https://opensource.org/licenses/MIT>. Thanks to Inspire Net Ltd for allowing +this open-source fork. +EOF + +# Define custom options +our @OPTS = ( + { + spec => 'host|h=s', + label => 'HOSTNAME:PORT', + help => 'Hostname:port pair to find in list, usually *:8080', + }, + { + spec => 'url|u=s', + label => 'URL', + help => 'URL to find in list, usually ends in /upload.php', + }, +); + +# URL from which the server list should be retrieved +our $SERVERS_LIST_URL = 'https://www.speedtest.net/speedtest-servers.php'; + +# Build Monitoring::Plugin object +my $mp = Monitoring::Plugin->new( + usage => 'Usage: %s --host|-H HOSTNAME:PORT --url|-u URL', + version => $VERSION, + blurb => $DESCRIPTION, + license => $LICENSE, +) or die "Failed plugin construct\n"; + +# Anything that dies in here will raise ->plugin_die() +eval { + + # Define and parse custom options + for my $opt (@OPTS) { + $mp->add_arg( %{$opt} ); + } + $mp->getopts(); + + # At least one of --host and --url must be specified + length $mp->opts->host + or length $mp->opts->url + or die "One or both --host or --url must be specified\n"; + + # Build a user agent that accepts only XML + my $ua = LWP::UserAgent->new(); + $ua->default_header( Accept => 'application/xml;text/xml' ); + + # Attempt to retrieve the server list + my $response = $ua->get($SERVERS_LIST_URL); + $response->is_success + or die "$response->status_line\n"; + + # Parse the server list as an XML document + my $lxml = XML::LibXML->new(); + my $doc = $lxml->load_xml( string => $response->decoded_content ) + or die "Failed to parse response XML\n"; + + # Build an XPath query object + my $xpc = XML::LibXML::XPathContext->new($doc) + or die "Failed to build XPath query object on response XML\n"; + + # Build a query depending on which options we were provided + ## no critic (RequireInterpolationOfMetachars) + my $query = '/settings/servers/server'; + if ( $mp->opts->url ) { + $query .= sprintf q{[@url='%s']}, $mp->opts->url; + } + if ( $mp->opts->host ) { + $query .= sprintf q{[@host='%s']}, $mp->opts->host; + } + + # Check that we have at least one matching server + my @servers = $xpc->findnodes($query); + my $code = $mp->check_threshold( + check => scalar @servers, + critical => '1:', + ); + my $message = sprintf '%u matching servers', scalar @servers; + $mp->add_message( $code, $message ); + + # Add OK-level messages showing the conditions we applied + # If we find an actual problem, "OK" will get replaced by ->check_messages() + if ( $mp->opts->host ) { + $mp->add_message( $ERRORS{OK}, sprintf 'host=%s', $mp->opts->host ); + } + if ( $mp->opts->url ) { + $mp->add_message( $ERRORS{OK}, sprintf 'url=%s', $mp->opts->url ); + } + + # Exit with determined code and messages + $mp->plugin_exit( + $mp->check_messages( + join => q{, }, + join_all => q{, }, + ), + ); + +} or $mp->plugin_die($EVAL_ERROR); |