From c34e00a9ef50d2d37c4cda6d666f8d4a25fc44c9 Mon Sep 17 00:00:00 2001 From: Tom Ryder Date: Fri, 6 Apr 2018 15:57:42 +1200 Subject: First commit --- LICENSE | 21 ++++++++ README.markdown | 24 +++++++++ check_speedtest_servers | 134 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 179 insertions(+) create mode 100644 LICENSE create mode 100644 README.markdown create mode 100755 check_speedtest_servers diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..b3215fc --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2017 Tom Ryder + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.markdown b/README.markdown new file mode 100644 index 0000000..b9744da --- /dev/null +++ b/README.markdown @@ -0,0 +1,24 @@ +check\_speedtest\_servers +========================= + +Check that an Oookla Speedtest server with a specified URL and/or host is +present on the public list of servers. + + $ check_speedtest_servers --host example.com:8080 + $ check_speedtest_servers --url http://example.com/upload.php + $ check_speedtest_servers --host example.com:8080 http://example.com/upload.php + +Thanks +------ + +This was written on company time with my employer [Inspire Net][1], who has +generously allowed me to open source it. + +License +------- + +Copyright (c) [Tom Ryder][2]. Distributed under [MIT License][3]. + +[1]: https://www.inspire.net.nz/ +[2]: https://sanctum.geek.nz/ +[3]: https://opensource.org/licenses/MIT 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 +# 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 +. 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); -- cgit v1.2.3