aboutsummaryrefslogtreecommitdiff
path: root/check_speedtest_servers
diff options
context:
space:
mode:
Diffstat (limited to 'check_speedtest_servers')
-rwxr-xr-xcheck_speedtest_servers134
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);