From f6d7a21e9a1cfd63ec10fdc7e25cccc2abfbac98 Mon Sep 17 00:00:00 2001 From: Simon Lauger Date: Sat, 12 Aug 2017 19:44:22 +0200 Subject: [PATCH 01/21] removed whitespace from sub check_server --- check_netscaler.pl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/check_netscaler.pl b/check_netscaler.pl index a78591f..3ad5688 100755 --- a/check_netscaler.pl +++ b/check_netscaler.pl @@ -563,9 +563,9 @@ sub check_server # check if any server is in disabled state foreach $response (@{$response}) { if ($response->{'state'} ne 'ENABLED') { - $plugin->add_message(WARNING, $response->{'name'} . '('. $response->{'ipaddress'} .') ' . $response->{'state'} . ' ;'); + $plugin->add_message(WARNING, $response->{'name'} . '('. $response->{'ipaddress'} .') ' . $response->{'state'} . ';'); } else { - $plugin->add_message(OK, $response->{'name'} . '('. $response->{'ipaddress'} .') ' . $response->{'state'} . ' ;'); + $plugin->add_message(OK, $response->{'name'} . '('. $response->{'ipaddress'} .') ' . $response->{'state'} . ';'); $critical = 0; } } From 97ff84b06be92539ff7ac17fdde64ac408de6057 Mon Sep 17 00:00:00 2001 From: Simon Lauger Date: Sat, 12 Aug 2017 23:34:05 +0200 Subject: [PATCH 02/21] added sub check_license to check the expiry date of a license file (#17) --- CHANGELOG.md | 4 ++++ README.md | 15 +++++++++++- check_netscaler.pl | 59 ++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 72 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ac18469..689366c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.3.0 (2017-XX-XX) +- added command license to check the status of a local license file +- added perl-Time-Piece as new dependency (Time::Piece for license check) + ## 1.2.0 (2017-08-12) - merged pull request from @bb-Ricardo - added command server to check status of Load Balancing Servers diff --git a/README.md b/README.md index 3e877cb..39cd52c 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ Currently the plugin has the following subcommands: **above, below** | check if a value is above/below a threshold (e.g. traffic limits, concurrent connections) **sslcert** | check the lifetime for installed ssl certificates **nsconfig** | check for configuration changes which are not saved to disk +**license** | check the expiry date of a local installed license file **server** | check status of Load Balancing Servers **staserver** | check if configured STA (secure ticket authority) servers are available **servicegroup** | check the state of a servicegroup and its members @@ -28,12 +29,14 @@ Example configurations for Nagios and Icinga 2 can be found in the examples dire Feedback and feature requests are appreciated. Just create an issue on GitHub or send me a pull request. +If you looking for a plugin to test your NetScaler Gateway vServer and Storefront see also [check_netscaler_gateway](https://github.com/slauger/check_netscaler_gateway). + ## Installation On a Enterprise Linux machine (CentOS, RHEL) execute the following commands to install all Perl dependencies (Nagios::Plugin, LWP, JSON): ``` -yum install perl-libwww-perl perl-JSON perl-Nagios-Plugin +yum install perl-libwww-perl perl-JSON perl-Nagios-Plugin perl-Time-Piece ``` If you want to connect to your NetScaler with SSL/HTTPS you should also install the LWP HTTPS package. @@ -154,6 +157,16 @@ define member quorum (in percent) with warning and critical values ./check_netscaler.pl -H ${IPADDR} -s -C nsconfig ``` +### Check the expiry date of a local license file + +The license file must be placed in `/nsconfig/license` and the filename must be given as objectname. +Also the NITRO user needs permissions to access the filesystem directly (NITRO command systemfile). + +``` +# NetScaler::License +./check_netscaler.pl -H ${IPADDR} -s -C license -n FID_4c9a2c7e_14292ea2df2_2a97.lic -w 30 -c 10 +``` + ### Check if STA servers are working ``` diff --git a/check_netscaler.pl b/check_netscaler.pl index 3ad5688..e8a38f2 100755 --- a/check_netscaler.pl +++ b/check_netscaler.pl @@ -6,7 +6,7 @@ # # https://github.com/slauger/check_netscaler # -# Version: 1.2.0 (2017-08-12) +# Version: 1.3.0 (2017-XX-XX) # # Copyright 2015-2017 Simon Lauger # @@ -29,13 +29,15 @@ use LWP; use JSON; use URI::Escape; +use MIME::Base64; use Data::Dumper; use Nagios::Plugin; +use Time::Piece; my $plugin = Nagios::Plugin->new( plugin => 'check_netscaler', shortname => 'NetScaler', - version => '1.2.0', + version => '1.3.0', url => 'https://github.com/slauger/check_netscaler', blurb => 'Nagios Plugin for Citrix NetScaler Appliance (VPX/MPX/SDX/CPX)', usage => 'Usage: %s -H [ -u ] [ -p ] @@ -175,6 +177,9 @@ } elsif ($plugin->opts->command eq 'servicegroup') { # check the state of a servicegroup and its members check_servicegroup($plugin); +} elsif ($plugin->opts->command eq 'license') { + # check a installed license file + check_license($plugin); } elsif ($plugin->opts->command eq 'debug') { # dump the full response of the nitro api check_debug($plugin); @@ -453,7 +458,6 @@ sub check_threshold my $response = nitro_client($plugin, \%params); $response = $response->{$plugin->opts->objecttype}; - $plugin->add_perfdata( label => $plugin->opts->objecttype . '::' . $plugin->opts->objectname, value => $response->{$plugin->opts->objectname}, @@ -563,9 +567,9 @@ sub check_server # check if any server is in disabled state foreach $response (@{$response}) { if ($response->{'state'} ne 'ENABLED') { - $plugin->add_message(WARNING, $response->{'name'} . '('. $response->{'ipaddress'} .') ' . $response->{'state'} . ';'); + $plugin->add_message(WARNING, $response->{'name'} . '('. $response->{'ipaddress'} .') ' . $response->{'state'} . ' ;'); } else { - $plugin->add_message(OK, $response->{'name'} . '('. $response->{'ipaddress'} .') ' . $response->{'state'} . ';'); + $plugin->add_message(OK, $response->{'name'} . '('. $response->{'ipaddress'} .') ' . $response->{'state'} . ' ;'); $critical = 0; } } @@ -862,6 +866,51 @@ sub check_servicegroup $plugin->nagios_exit($servicegroup_state, 'servicegroup: ' . $message); } +sub check_license +{ + my $plugin = shift; + + my %params; + $params{'endpoint'} = $plugin->opts->endpoint || 'config'; + $params{'objecttype'} = 'systemfile'; + $params{'objectname'} = undef; + + if (!defined $plugin->opts->warning || !$plugin->opts->critical) { + $plugin->nagios_die('command requires parameter for warning and critical'); + } + + if (!defined $plugin->opts->objectname) { + $plugin->nagios_die('license filename must be given as objectname via "-n"') + } + + $params{'options'} = 'args=filelocation:'.uri_escape('/nsconfig/license').',filename:'.uri_escape($plugin->opts->objectname); + + my $response = nitro_client($plugin, \%params); + + my @stripped; + my $timepiece; + + foreach (split(/\n/, decode_base64($response->{'systemfile'}[0]->{'filecontent'}))) { + if ($_ =~ /^INCREMENT .*/) { + @stripped = split(' ', $_); + + # date format in license file, e.g. 18-jan-2018 + $timepiece = Time::Piece->strptime(($stripped[4], '%d-%b-%Y')); + + if ($timepiece->epoch - time < (60*60*24*$plugin->opts->critical)) { + $plugin->add_message(CRITICAL, $stripped[1] . ' expires on ' . $stripped[4] . ';'); + } elsif ($timepiece->epoch - time < (60*60*24*$plugin->opts->warning)) { + $plugin->add_message(WARNING, $stripped[1] . ' expires on ' . $stripped[4] . ';'); + } else { + $plugin->add_message(OK, $stripped[1] . ' expires on ' . $stripped[4] . ';'); + } + } + } + + my ($code, $message) = $plugin->check_messages; + $plugin->nagios_exit($code, 'license: ' . $message); +} + sub check_debug { my $plugin = shift; From 60761c5e1c3098670851c2d6ddd0d087f2447634 Mon Sep 17 00:00:00 2001 From: Simon Lauger Date: Sat, 12 Aug 2017 23:56:10 +0200 Subject: [PATCH 03/21] allow usage of urlopts everywhere (also fixes #13) --- check_netscaler.pl | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/check_netscaler.pl b/check_netscaler.pl index e8a38f2..6d7c7ad 100755 --- a/check_netscaler.pl +++ b/check_netscaler.pl @@ -127,7 +127,7 @@ { spec => 'urlopts|x=s', usage => '-x, --urlopts=STRING', - desc => 'DEBUG ONLY: add additional url options', + desc => 'add additional url options', required => 0, }, ); @@ -325,7 +325,7 @@ sub check_state $params{'objecttype'} = $plugin->opts->objecttype; $params{'objectname'} = $plugin->opts->objectname; - $params{'options'} = undef; + $params{'options'} = $plugin->opts->urlopts; my $response = nitro_client($plugin, \%params); $response = $response->{$plugin->opts->objecttype}; @@ -414,7 +414,7 @@ sub check_string $params{'endpoint'} = $plugin->opts->endpoint || 'stat'; $params{'objecttype'} = $plugin->opts->objecttype; $params{'objectname'} = undef; - $params{'options'} = undef; + $params{'options'} = $plugin->opts->urlopts; my $response = nitro_client($plugin, \%params); $response = $response->{$plugin->opts->objecttype}; @@ -453,7 +453,7 @@ sub check_threshold $params{'endpoint'} = $plugin->opts->endpoint || 'stat'; $params{'objecttype'} = $plugin->opts->objecttype; $params{'objectname'} = undef; - $params{'options'} = undef; + $params{'options'} = $plugin->opts->urlopts; my $response = nitro_client($plugin, \%params); $response = $response->{$plugin->opts->objecttype}; @@ -488,7 +488,7 @@ sub check_sslcert $params{'endpoint'} = $plugin->opts->endpoint || 'config'; $params{'objecttype'} = $plugin->opts->objecttype || 'sslcertkey'; $params{'objectname'} = $plugin->opts->objectname; - $params{'options'} = undef; + $params{'options'} = $plugin->opts->urlopts; my $response = nitro_client($plugin, \%params); $response = $response->{$params{'objecttype'}}; @@ -517,7 +517,7 @@ sub check_staserver my %params; $params{'endpoint'} = $plugin->opts->endpoint || 'config'; $params{'objectname'} = $plugin->opts->objectname || ''; - $params{'options'} = undef; + $params{'options'} = $plugin->opts->urlopts; if ($params{'objectname'} eq '') { $params{'objecttype'} = $plugin->opts->objecttype || 'vpnglobal_staserver_binding'; @@ -555,7 +555,7 @@ sub check_server my %params; $params{'endpoint'} = $plugin->opts->endpoint || 'config'; $params{'objectname'} = $plugin->opts->objectname || ''; - $params{'options'} = undef; + $params{'options'} = $plugin->opts->urlopts; $params{'objecttype'} = 'server'; my $response = nitro_client($plugin, \%params); @@ -589,7 +589,7 @@ sub check_nsconfig $params{'endpoint'} = $plugin->opts->endpoint || 'config'; $params{'objecttype'} = $plugin->opts->objecttype || 'nsconfig'; $params{'objectname'} = undef; - $params{'options'} = undef; + $params{'options'} = $plugin->opts->urlopts; my $response = nitro_client($plugin, \%params); $response = $response->{$params{'objecttype'}}; @@ -609,7 +609,7 @@ sub get_hardware_info $params{'endpoint'} = 'config'; $params{'objecttype'} = 'nshardware'; $params{'objectname'} = undef; - $params{'options'} = undef; + $params{'options'} = $plugin->opts->urlopts; my $response = nitro_client($plugin, \%params); $response = $response->{$params{'objecttype'}}; @@ -638,7 +638,7 @@ sub get_performancedata $params{'endpoint'} = $plugin->opts->endpoint || 'stat'; $params{'objecttype'} = $plugin->opts->objecttype; $params{'objectname'} = undef; - $params{'options'} = undef; + $params{'options'} = $plugin->opts->urlopts; if (!defined $plugin->opts->objectname) { $plugin->nagios_die('performancedata: command requires parameter for objectname'); @@ -708,7 +708,7 @@ sub check_interfaces $params{'endpoint'} = 'config'; $params{'objecttype'} = 'interface'; $params{'objectname'} = undef; - $params{'options'} = undef; + $params{'options'} = $plugin->opts->urlopts; my $response = nitro_client($plugin, \%params); @@ -774,7 +774,7 @@ sub check_servicegroup $params{'endpoint'} = 'config'; $params{'objecttype'} = 'servicegroup'; $params{'objectname'} = $plugin->opts->objectname; - $params{'options'} = undef; + $params{'options'} = $plugin->opts->urlopts; if (not defined ($plugin->opts->objectname)) { $plugin->nagios_die('servicegroup: no object name "-n" set'); @@ -873,7 +873,7 @@ sub check_license my %params; $params{'endpoint'} = $plugin->opts->endpoint || 'config'; $params{'objecttype'} = 'systemfile'; - $params{'objectname'} = undef; + $params{'options'} = $plugin->opts->urlopts; if (!defined $plugin->opts->warning || !$plugin->opts->critical) { $plugin->nagios_die('command requires parameter for warning and critical'); From b1d3c2d310c2b9293876086964b9ad37690e9964 Mon Sep 17 00:00:00 2001 From: Simon Lauger Date: Sun, 13 Aug 2017 00:02:10 +0200 Subject: [PATCH 04/21] added example for requesting performance data from global counters (#13) --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 39cd52c..02cbb91 100644 --- a/README.md +++ b/README.md @@ -212,6 +212,12 @@ All fields must be defined via "-n" option and be seperated with a comma. /check_netscaler.pl -H ${IPADDR} -s -C debug -o ns ``` +[Global counters](https://docs.citrix.com/en-us/netscaler/12/nitro-api/nitro-rest/nitro-rest-usage-scenarios/view-individual-counter-info.html) can be accessed as follows (NetScaler 12.0 and newer). + +``` +./check_netscaler.pl -H ${IPADDR} -s -C performancedata -n http_tot_Requests,http_tot_Responses -x 'args=counters:http_tot_Requests;http_tot_Responses' +``` + For more interesting performance data object types see the following API methods. - ns From dfc8c2d407c2a1dd2c94f8fe5f2a18a67b956f31 Mon Sep 17 00:00:00 2001 From: Simon Lauger Date: Sun, 13 Aug 2017 00:09:10 +0200 Subject: [PATCH 05/21] added switch --api to select a different version of the NITRO API (#16) --- check_netscaler.pl | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/check_netscaler.pl b/check_netscaler.pl index 6d7c7ad..f81b16f 100755 --- a/check_netscaler.pl +++ b/check_netscaler.pl @@ -130,6 +130,13 @@ desc => 'add additional url options', required => 0, }, + { + spec => 'api|a=s', + usage => '-a, --api=STRING', + desc => 'version of the NITRO API to use', + required => 0, + default => 'v1', + } ); foreach my $arg (@args) { @@ -252,7 +259,7 @@ sub nitro_client { $port = ''; } - my $url = $protocol . $plugin->opts->hostname . $port . '/nitro/v1/' . $params->{'endpoint'} . '/' . $params->{'objecttype'}; + my $url = $protocol . $plugin->opts->hostname . $port . '/nitro/' . $plugin->opts->api . '/' . $params->{'endpoint'} . '/' . $params->{'objecttype'}; if ($params->{'objectname'} && $params->{'objectname'} ne '') { $url = $url . '/' . uri_escape(uri_escape($params->{'objectname'})); From 5677fdf5eddbd70872c8bb5d1892ae34e570f3ec Mon Sep 17 00:00:00 2001 From: Simon Lauger Date: Sun, 13 Aug 2017 00:14:13 +0200 Subject: [PATCH 06/21] updated CHANGELOG.md with the recent changes --- CHANGELOG.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 689366c..d12d1a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ ## 1.3.0 (2017-XX-XX) -- added command license to check the status of a local license file +- added command license to check the status of a local license file (#17) - added perl-Time-Piece as new dependency (Time::Piece for license check) +- added switch for selecting a different version of the NITRO API (fixes #16) +- allow the usage of urlopts everywhere (fixes #13) ## 1.2.0 (2017-08-12) - merged pull request from @bb-Ricardo From 41299d41d83bcaf20a750e7c60f43ab94806ab1c Mon Sep 17 00:00:00 2001 From: Simon Lauger Date: Sun, 13 Aug 2017 00:53:55 +0200 Subject: [PATCH 07/21] added perl-Data-Dumper to the dependencies --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 02cbb91..4d9927f 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ If you looking for a plugin to test your NetScaler Gateway vServer and Storefron On a Enterprise Linux machine (CentOS, RHEL) execute the following commands to install all Perl dependencies (Nagios::Plugin, LWP, JSON): ``` -yum install perl-libwww-perl perl-JSON perl-Nagios-Plugin perl-Time-Piece +yum install perl-libwww-perl perl-JSON perl-Nagios-Plugin perl-Time-Piece perl-Data-Dumper ``` If you want to connect to your NetScaler with SSL/HTTPS you should also install the LWP HTTPS package. From 1db4413b37444acead8b607554bd4914a3974c98 Mon Sep 17 00:00:00 2001 From: Simon Lauger Date: Sun, 13 Aug 2017 01:34:19 +0200 Subject: [PATCH 08/21] accept multiple values for threshold checks (#7) --- check_netscaler.pl | 58 ++++++++++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 22 deletions(-) diff --git a/check_netscaler.pl b/check_netscaler.pl index f81b16f..61e4896 100755 --- a/check_netscaler.pl +++ b/check_netscaler.pl @@ -154,10 +154,12 @@ } elsif ($plugin->opts->command eq 'below') { # check if a response is below a threshold check_threshold($plugin, $plugin->opts->command); -} elsif ($plugin->opts->command eq 'string') { +# be backwards compatible; also accept command 'string' +} elsif ($plugin->opts->command eq 'matches' || $plugin->opts->command eq 'string') { # check if a response does contains a specific string check_string($plugin, 'matches'); -} elsif ($plugin->opts->command eq 'string_not') { +# be backwards compatible; also accept command 'string_not' +} elsif ($plugin->opts->command eq 'matches_not' || $plugin->opts->command eq 'string_not') { # check if a response does not contains a specific string check_string($plugin, 'matches not'); } elsif ($plugin->opts->command eq 'sslcert') { @@ -426,13 +428,19 @@ sub check_string my $response = nitro_client($plugin, \%params); $response = $response->{$plugin->opts->objecttype}; - if (($type_of_string_comparison eq 'matches' && $response->{$plugin->opts->objectname} eq $plugin->opts->critical) || ($type_of_string_comparison eq 'matches not' && $response->{$plugin->opts->objectname} ne $plugin->opts->critical)) { - $plugin->nagios_exit(CRITICAL, $plugin->opts->objecttype . '::' . $plugin->opts->objectname . ' ' . $type_of_string_comparison . ' keyword (current: ' . $response->{$plugin->opts->objectname} . ', critical: ' . $plugin->opts->critical . ')'); - } elsif (($type_of_string_comparison eq 'matches' && $response->{$plugin->opts->objectname} eq $plugin->opts->warning) || ($type_of_string_comparison eq 'matches not' && $response->{$plugin->opts->objectname} ne $plugin->opts->warning)) { - $plugin->nagios_exit(WARNING, $plugin->opts->objecttype . '::' . $plugin->opts->objectname . ' ' . $type_of_string_comparison . ' keyword (current: ' . $response->{$plugin->opts->objectname} . ', warning: ' . $plugin->opts->warning . ')'); - } else { - $plugin->nagios_exit(OK, $plugin->opts->objecttype . '::' . $plugin->opts->objectname . ' OK ('.$response->{$plugin->opts->objectname}.')'); + foreach ( split(',', $plugin->opts->objectname) ) { + if (($type_of_string_comparison eq 'matches' && $response->{$_} eq $plugin->opts->critical) || ($type_of_string_comparison eq 'matches not' && $response->{$_} ne $plugin->opts->critical)) { + $plugin->add_message(CRITICAL, $plugin->opts->objecttype . '::' . $_ . ' ' . $type_of_string_comparison . ' keyword (current: ' . $response->{$_} . ', critical: ' . $plugin->opts->critical . ');'); + } elsif (($type_of_string_comparison eq 'matches' && $response->{$_} eq $plugin->opts->warning) || ($type_of_string_comparison eq 'matches not' && $response->{$_} ne $plugin->opts->warning)) { + $plugin->add_message(WARNING, $plugin->opts->objecttype . '::' . $_ . ' ' . $type_of_string_comparison . ' keyword (current: ' . $response->{$_} . ', warning: ' . $plugin->opts->warning . ');'); + } else { + $plugin->add_message(OK, $plugin->opts->objecttype . '::' . $_ . ' OK ('.$response->{$_}.');'); + } } + + my ($code, $message) = $plugin->check_messages; + + $plugin->nagios_exit($code, $message); } sub check_threshold @@ -465,22 +473,28 @@ sub check_threshold my $response = nitro_client($plugin, \%params); $response = $response->{$plugin->opts->objecttype}; - $plugin->add_perfdata( - label => $plugin->opts->objecttype . '::' . $plugin->opts->objectname, - value => $response->{$plugin->opts->objectname}, - min => undef, - max => undef, - warning => $plugin->opts->warning, - critical => $plugin->opts->critical, - ); + foreach ( split(',', $plugin->opts->objectname) ) { + $plugin->add_perfdata( + label => $plugin->opts->objecttype . '::' . $_, + value => $response->{$_}, + min => undef, + max => undef, + warning => $plugin->opts->warning, + critical => $plugin->opts->critical, + ); - if (($direction eq 'above' && $response->{$plugin->opts->objectname} >= $plugin->opts->critical) || ($direction eq 'below' && $response->{$plugin->opts->objectname} <= $plugin->opts->critical)) { - $plugin->nagios_exit(CRITICAL, $plugin->opts->objecttype . '::' . $plugin->opts->objectname . ' is ' . $direction . ' threshold (current: ' . $response->{$plugin->opts->objectname} . ', critical: ' . $plugin->opts->critical . ')'); - } elsif (($direction eq 'above' && $response->{$plugin->opts->objectname} >= $plugin->opts->warning) || ($direction eq 'below' && $response->{$plugin->opts->objectname} <= $plugin->opts->warning)) { - $plugin->nagios_exit(WARNING, $plugin->opts->objecttype . '::' . $plugin->opts->objectname . ' is ' . $direction . ' threshold (current: ' . $response->{$plugin->opts->objectname} . ', warning: ' . $plugin->opts->warning . ')'); - } else { - $plugin->nagios_exit(OK, $plugin->opts->objecttype . '::' . $plugin->opts->objectname . ' OK ('.$response->{$plugin->opts->objectname}.')'); + if (($direction eq 'above' && $response->{$_} >= $plugin->opts->critical) || ($direction eq 'below' && $response->{$_} <= $plugin->opts->critical)) { + $plugin->add_message(CRITICAL, $plugin->opts->objecttype . '::' . $_ . ' is ' . $direction . ' threshold (current: ' . $response->{$_} . ', critical: ' . $plugin->opts->critical . ');'); + } elsif (($direction eq 'above' && $response->{$_} >= $plugin->opts->warning) || ($direction eq 'below' && $response->{$_} <= $plugin->opts->warning)) { + $plugin->add_message(WARNING, $plugin->opts->objecttype . '::' . $_ . ' is ' . $direction . ' threshold (current: ' . $response->{$_} . ', warning: ' . $plugin->opts->warning . ');'); + } else { + $plugin->add_message(OK, $_ . '::' . $_ . ' ('.$response->{$_}.')'); + } } + + my ($code, $message) = $plugin->check_messages; + + $plugin->nagios_exit($code, $message); } sub check_sslcert From 73eabdf1844d64e59d76a03f5f382fc17d9a8a60 Mon Sep 17 00:00:00 2001 From: Simon Lauger Date: Sun, 13 Aug 2017 01:40:02 +0200 Subject: [PATCH 09/21] renamed checks 'string' and 'string_not' to 'matches' and 'matches_not' (with backwards compatibility) --- README.md | 34 ++++++++++++------------- examples/icinga2_service_templates.conf | 4 +-- examples/nagios_command.cfg | 14 +++++----- examples/plugin_test.sh | 4 +-- 4 files changed, 28 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 4d9927f..d48fe2b 100644 --- a/README.md +++ b/README.md @@ -5,21 +5,21 @@ A Nagios Plugin written for the Citrix NetScaler Application Delivery Controller Currently the plugin has the following subcommands: -| command | description | ---- | --- | -**state** | check the current service state of vservers (e.g. lb, vpn, gslb), services and service groups -**string, string_not** | check if a string exists in the api response or not (e.g. HA or cluster status) -**above, below** | check if a value is above/below a threshold (e.g. traffic limits, concurrent connections) -**sslcert** | check the lifetime for installed ssl certificates -**nsconfig** | check for configuration changes which are not saved to disk -**license** | check the expiry date of a local installed license file -**server** | check status of Load Balancing Servers -**staserver** | check if configured STA (secure ticket authority) servers are available -**servicegroup** | check the state of a servicegroup and its members -**hwinfo** | just print information about the Netscaler itself -**interfaces** | check state of all interfaces and add performance data for each interface -**performancedata** | gather performancedata from all sorts of API endpoints -**debug** | debug command, print all data for a endpoint +| command | description | +--- | --- | +**state** | check the current service state of vservers (e.g. lb, vpn, gslb), services and service groups +**matches, matches_not** | check if a string exists in the api response or not (e.g. HA or cluster status) +**above, below** | check if a value is above/below a threshold (e.g. traffic limits, concurrent connections) +**sslcert** | check the lifetime for installed ssl certificates +**nsconfig** | check for configuration changes which are not saved to disk +**license** | check the expiry date of a local installed license file +**server** | check status of Load Balancing Servers +**staserver** | check if configured STA (secure ticket authority) servers are available +**servicegroup** | check the state of a servicegroup and its members +**hwinfo** | just print information about the Netscaler itself +**interfaces** | check state of all interfaces and add performance data for each interface +**performancedata** | gather performancedata from all sorts of API endpoints +**debug** | debug command, print all data for a endpoint This plugin works with VPX, MPX, SDX and CPX NetScaler Appliances. The api responses may differ by build, appliance type and your installed license. @@ -134,10 +134,10 @@ define member quorum (in percent) with warning and critical values ``` # NetScaler::HA::Status -./check_netscaler.pl -H ${IPADDR} -s -C string_not -o hanode -n hacurstatus -w YES -c YES +./check_netscaler.pl -H ${IPADDR} -s -C matches_not -o hanode -n hacurstatus -w YES -c YES # NetScaler::HA::State -./check_netscaler.pl -H ${IPADDR} -s -C string_not -o hanode -n hacurstate -w UP -c UP +./check_netscaler.pl -H ${IPADDR} -s -C matches_not -o hanode -n hacurstate -w UP -c UP ``` ### Check expiration of installed ssl certificates diff --git a/examples/icinga2_service_templates.conf b/examples/icinga2_service_templates.conf index c755847..9d3e522 100644 --- a/examples/icinga2_service_templates.conf +++ b/examples/icinga2_service_templates.conf @@ -79,7 +79,7 @@ template Service "netscaler_ha_status_template" { check_command = "netscaler" - vars.netscaler_command = "string_not" + vars.netscaler_command = "matches_not" vars.netscaler_objecttype = "hanode" vars.netscaler_objectname = "hacurstatus" @@ -92,7 +92,7 @@ template Service "netscaler_ha_state_template" { check_command = "netscaler" - vars.netscaler_command = "string_not" + vars.netscaler_command = "matches_not" vars.netscaler_objecttype = "hanode" vars.netscaler_objectname = "hacurstate" diff --git a/examples/nagios_command.cfg b/examples/nagios_command.cfg index be823ff..0c854da 100644 --- a/examples/nagios_command.cfg +++ b/examples/nagios_command.cfg @@ -22,16 +22,16 @@ define command { command_line /opt/check_netscaler/check_netscaler.pl -H $HOSTADDRESS$ --extra-opts=netscaler@$USER11$/plugins.ini -C below -o '$ARG1$' -n '$ARG2$' -w '$ARG3$' -c '$ARG4$' } -# check_netscaler_string!objecttype!objectname!warning!critical +# check_netscaler_matches!objecttype!objectname!warning!critical define command { - command_name check_netscaler_string - command_line /opt/check_netscaler/check_netscaler.pl -H $HOSTADDRESS$ --extra-opts=netscaler@$USER11$/plugins.ini -C string -o '$ARG1$' -n '$ARG2$' -w '$ARG3$' -c '$ARG4$' + command_name check_netscaler_matches + command_line /opt/check_netscaler/check_netscaler.pl -H $HOSTADDRESS$ --extra-opts=netscaler@$USER11$/plugins.ini -C matches -o '$ARG1$' -n '$ARG2$' -w '$ARG3$' -c '$ARG4$' } -# check_netscaler_string_not!objecttype!objectname!warning!critical +# check_netscaler_matches_not!objecttype!objectname!warning!critical define command { - command_name check_netscaler_string_not - command_line /opt/check_netscaler/check_netscaler.pl -H $HOSTADDRESS$ --extra-opts=netscaler@$USER11$/plugins.ini -C string_now -o '$ARG1$' -n '$ARG2$' -w '$ARG3$' -c '$ARG4$' + command_name check_netscaler_matches_not + command_line /opt/check_netscaler/check_netscaler.pl -H $HOSTADDRESS$ --extra-opts=netscaler@$USER11$/plugins.ini -C matches_not -o '$ARG1$' -n '$ARG2$' -w '$ARG3$' -c '$ARG4$' } # check_netscaler_sslcert!warning!critical @@ -43,7 +43,7 @@ define command { # check_netscaler_sslcert_single!objectname!warning!critical define command { command_name check_netscaler_sslcert_single - command_line /opt/check_netscaler/check_netscaler.pl -H $HOSTADDRESS$ --extra-opts=netscaler@$USER11$/plugins.ini -C string -n '$ARG1$' -w '$ARG2$' -c '$ARG3$' + command_line /opt/check_netscaler/check_netscaler.pl -H $HOSTADDRESS$ --extra-opts=netscaler@$USER11$/plugins.ini -C matches -n '$ARG1$' -w '$ARG2$' -c '$ARG3$' } # check_netscaler_nsconfig diff --git a/examples/plugin_test.sh b/examples/plugin_test.sh index dafc3d3..204da90 100755 --- a/examples/plugin_test.sh +++ b/examples/plugin_test.sh @@ -109,11 +109,11 @@ echo NetScaler::System::Disk1 echo echo NetScaler::HA::Status -./check_netscaler.pl -H ${IPADDR} ${PORT} ${SSL} -u ${USERNAME} -p ${PASSWORD} -C string_not -o hanode -n hacurstatus -w YES -c YES +./check_netscaler.pl -H ${IPADDR} ${PORT} ${SSL} -u ${USERNAME} -p ${PASSWORD} -C matches_not -o hanode -n hacurstatus -w YES -c YES echo echo NetScaler::HA::State -./check_netscaler.pl -H ${IPADDR} ${PORT} ${SSL} -u ${USERNAME} -p ${PASSWORD} -C string_not -o hanode -n hacurstate -w UP -c UP +./check_netscaler.pl -H ${IPADDR} ${PORT} ${SSL} -u ${USERNAME} -p ${PASSWORD} -C matches_not -o hanode -n hacurstate -w UP -c UP echo From 8af2e0dc0a19990e2c08f615ff6d7fcaaf1a63b3 Mon Sep 17 00:00:00 2001 From: Simon Lauger Date: Sun, 13 Aug 2017 01:48:41 +0200 Subject: [PATCH 10/21] updated examples for threshold and string checks (#7); updated CHANGELOG.md with recent changes --- CHANGELOG.md | 3 +++ README.md | 18 +++++------------- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d12d1a6..90e3cdc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,11 @@ ## 1.3.0 (2017-XX-XX) - added command license to check the status of a local license file (#17) - added perl-Time-Piece as new dependency (Time::Piece for license check) +- added perl-Data-Dumper to the install instructions in the README.md - added switch for selecting a different version of the NITRO API (fixes #16) - allow the usage of urlopts everywhere (fixes #13) +- check_threshold and check_string accept arrays (seperated by colon) (fixes #7) +- renamed checks 'string' and 'string_not' to 'matches' and 'matches_not' ( backwards compatibility given) ## 1.2.0 (2017-08-12) - merged pull request from @bb-Ricardo diff --git a/README.md b/README.md index d48fe2b..81b95a4 100644 --- a/README.md +++ b/README.md @@ -111,28 +111,20 @@ define member quorum (in percent) with warning and critical values ./check_netscaler.pl -H ${IPADDR} -s -C server -n web01.example.com ``` -### Check system health +### Check for thresholds or matching strings + +Multiple fields need to be seperated by a colon. ``` # NetScaler::Memory ./check_netscaler.pl -H ${IPADDR} -s -C above -o system -n memusagepcnt -w 75 -c 80 # NetScaler::CPU -./check_netscaler.pl -H ${IPADDR} -s -C above -o system -n cpuusagepcnt -w 75 -c 80 - -# NetScaler::CPUMGMT -./check_netscaler.pl -H ${IPADDR} -s -C above -o system -n mgmtcpuusagepcnt -w 75 -c 80 - -# NetScaler::Disk0 -./check_netscaler.pl -H ${IPADDR} -s -C above -o system -n disk0perusage -w 75 -c 80 +./check_netscaler.pl -H ${IPADDR} -s -C above -o system -n cpuusagepcnt,mgmtcpuusagepcnt -w 75 -c 80 # NetScaler::Disk1 -./check_netscaler.pl -H ${IPADDR} -s -C above -o system -n disk1perusage -w 75 -c 80 -``` - -### Check high availability status +./check_netscaler.pl -H ${IPADDR} -s -C above -o system -n disk0perusage,disk1perusage -w 75 -c 80 -``` # NetScaler::HA::Status ./check_netscaler.pl -H ${IPADDR} -s -C matches_not -o hanode -n hacurstatus -w YES -c YES From 794dc8aa404450310b7f7177c75f98eae7759ca8 Mon Sep 17 00:00:00 2001 From: Simon Lauger Date: Sun, 13 Aug 2017 01:51:00 +0200 Subject: [PATCH 11/21] Disk1 -> Disk --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 81b95a4..785cea0 100644 --- a/README.md +++ b/README.md @@ -122,7 +122,7 @@ Multiple fields need to be seperated by a colon. # NetScaler::CPU ./check_netscaler.pl -H ${IPADDR} -s -C above -o system -n cpuusagepcnt,mgmtcpuusagepcnt -w 75 -c 80 -# NetScaler::Disk1 +# NetScaler::Disk ./check_netscaler.pl -H ${IPADDR} -s -C above -o system -n disk0perusage,disk1perusage -w 75 -c 80 # NetScaler::HA::Status From 37fbe3d98649317c398a9d13d410a8ed7fc1d289 Mon Sep 17 00:00:00 2001 From: Simon Lauger Date: Sun, 13 Aug 2017 02:00:48 +0200 Subject: [PATCH 12/21] added usage examples to README.md --- README.md | 48 ++++++++++++++++++++++++++++++++++++++++++++++ check_netscaler.pl | 7 +++---- 2 files changed, 51 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 785cea0..e9634c5 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,54 @@ If you want to connect to your NetScaler with SSL/HTTPS you should also install yum install perl-LWP-Protocol-https ``` +## Usage +``` +Usage: check_netscaler -H [ -P ] [ -u ] [ -p ] +-C [ -o ] [ -n ] [ -e ] +[ -w ] [ -c ] [ -v|--verbose ] [ -s|--ssl ] +[ -t ] [ -x ] [ -a|--api ] + + -?, --usage + Print usage information + -h, --help + Print detailed help screen + -V, --version + Print version information + --extra-opts=[section][@file] + Read options from an ini file. See http://nagiosplugins.org/extra-opts + for usage and examples. + -H, --hostname=STRING + Hostname of the NetScaler appliance to connect to + -u, --username=STRING + Username to log into box as (default: nsroot) + -p, --password=STRING + Password for login username (default: nsroot) + -s, --ssl + Establish connection to NetScaler using SSL + -P, --port=INTEGER + Establish connection to a alternate TCP Port + -C, --command=STRING + Check to be executed on the appliance + -o, --objecttype=STRING + Objecttype (target) to for the check command + -n, --objectname=STRING + Filter request to a specific objectname + -e, --endpoint=STRING + Override option for the API endpoint (stat or config) + -w, --warning=STRING + Value for warning + -c, --critical=STRING + Value for critical + -x, --urlopts=STRING + add additional url options + -a, --api=STRING + version of the NITRO API to use (default: v1) + -t, --timeout=INTEGER + Seconds before plugin times out (default: 15) + -v, --verbose + Show details for command-line debugging (can repeat up to 3 times) +``` + ## Usage Examples ### Check status of vServers diff --git a/check_netscaler.pl b/check_netscaler.pl index 61e4896..25b40d4 100755 --- a/check_netscaler.pl +++ b/check_netscaler.pl @@ -40,9 +40,8 @@ version => '1.3.0', url => 'https://github.com/slauger/check_netscaler', blurb => 'Nagios Plugin for Citrix NetScaler Appliance (VPX/MPX/SDX/CPX)', - usage => 'Usage: %s -H [ -u ] [ -p ] --C [ -o ] [ -n ] [ -e ] -[ -w ] [ -c ] [ -v|--verbose ] [ -s|--ssl ] [ -t ]', + usage => 'Usage: %s -H [ -P ] [ -u ] [ -p ] -C [ -o ] [ -n ] [ -e ] +[ -w ] [ -c ] [ -v|--verbose ] [ -s|--ssl ] [ -t ] [ -x ] [ -a|--api ]', license => 'http://www.apache.org/licenses/LICENSE-2.0', extra => ' This is a Nagios monitoring plugin for the Citrix NetScaler. The plugin works with @@ -133,7 +132,7 @@ { spec => 'api|a=s', usage => '-a, --api=STRING', - desc => 'version of the NITRO API to use', + desc => 'version of the NITRO API to use (default: v1)', required => 0, default => 'v1', } From 41764df67f342774656d9094ee0c9a475edcb075 Mon Sep 17 00:00:00 2001 From: Simon Lauger Date: Sun, 13 Aug 2017 17:53:25 +0200 Subject: [PATCH 13/21] renamed check performancedata to perfdata (backwards compatible); small documentation changes --- CHANGELOG.md | 5 +++-- README.md | 25 ++++++++++++++----------- check_netscaler.pl | 34 ++++++++++++++++++++-------------- 3 files changed, 37 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 90e3cdc..d697520 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,12 @@ -## 1.3.0 (2017-XX-XX) +## 1.3.0 (2017-08-13) - added command license to check the status of a local license file (#17) - added perl-Time-Piece as new dependency (Time::Piece for license check) - added perl-Data-Dumper to the install instructions in the README.md - added switch for selecting a different version of the NITRO API (fixes #16) - allow the usage of urlopts everywhere (fixes #13) - check_threshold and check_string accept arrays (seperated by colon) (fixes #7) -- renamed checks 'string' and 'string_not' to 'matches' and 'matches_not' ( backwards compatibility given) +- renamed checks 'string' and 'string_not' to 'matches' and 'matches_not' (backwards compatibility given) +- renamed check 'performancedata' to 'perfdata' (backwards compatibility given) ## 1.2.0 (2017-08-12) - merged pull request from @bb-Ricardo diff --git a/README.md b/README.md index e9634c5..8d11b8e 100644 --- a/README.md +++ b/README.md @@ -18,12 +18,12 @@ Currently the plugin has the following subcommands: **servicegroup** | check the state of a servicegroup and its members **hwinfo** | just print information about the Netscaler itself **interfaces** | check state of all interfaces and add performance data for each interface -**performancedata** | gather performancedata from all sorts of API endpoints +**perfdata** | gather performancedata from all sorts of API endpoints **debug** | debug command, print all data for a endpoint This plugin works with VPX, MPX, SDX and CPX NetScaler Appliances. The api responses may differ by build, appliance type and your installed license. -The plugin supports performance data for the commands state and the above or below threshold checks. Also there is a performancedata command to gather information from your NetScaler. +The plugin supports performance data for the commands state and the above or below threshold checks. Also there is a perfdata command to gather information from your NetScaler. Example configurations for Nagios and Icinga 2 can be found in the examples directory of this repository. @@ -47,10 +47,13 @@ yum install perl-LWP-Protocol-https ## Usage ``` -Usage: check_netscaler -H [ -P ] [ -u ] [ -p ] --C [ -o ] [ -n ] [ -e ] -[ -w ] [ -c ] [ -v|--verbose ] [ -s|--ssl ] -[ -t ] [ -x ] [ -a|--api ] +Usage: check_netscaler +-H|--hostname= -C|--command= +[ -o|--objecttype= ] [ -n|--objectname= ] +[ -u|--username= ] [ -p|--password= ] +[ -s|--ssl ] [ -a|--api= ] [ -P|--port= ] +[ -e|--endpoint= ] [ -w|--warning= ] [ -c|--critical= ] +[ -v|--verbose ] [ -t|--timeout= ] [ -x|--urlopts= ] -?, --usage Print usage information @@ -237,16 +240,16 @@ All fields must be defined via "-n" option and be seperated with a comma. ``` # NetScaler::Performancedata on Cache hit/misses -./check_netscaler.pl -H ${IPADDR} -s -C performancedata -o ns -n cachetothits,cachetotmisses +./check_netscaler.pl -H ${IPADDR} -s -C perfdata -o ns -n cachetothits,cachetotmisses # NetScaler::Performancedata on tcp connections -./check_netscaler.pl -H ${IPADDR} -s -C performancedata -o ns -n tcpcurclientconn,tcpcurclientconnestablished,tcpcurserverconn,tcpcurserverconnestablished +./check_netscaler.pl -H ${IPADDR} -s -C perfdata -o ns -n tcpcurclientconn,tcpcurclientconnestablished,tcpcurserverconn,tcpcurserverconnestablished # NetScaler::Performancedata on network interfaces -./check_netscaler.pl -H ${IPADDR} -s -C performancedata -o Interface -n id.totrxbytes +./check_netscaler.pl -H ${IPADDR} -s -C perfdata -o Interface -n id.totrxbytes # NetScaler::Current user sessions -./check_netscaler.pl -H ${IPADDR} -s -C performancedata -o aaa -n aaacuricasessions,aaacuricaonlyconn +./check_netscaler.pl -H ${IPADDR} -s -C perfdata -o aaa -n aaacuricasessions,aaacuricaonlyconn # find more object names to check out for object type "ns" /check_netscaler.pl -H ${IPADDR} -s -C debug -o ns @@ -255,7 +258,7 @@ All fields must be defined via "-n" option and be seperated with a comma. [Global counters](https://docs.citrix.com/en-us/netscaler/12/nitro-api/nitro-rest/nitro-rest-usage-scenarios/view-individual-counter-info.html) can be accessed as follows (NetScaler 12.0 and newer). ``` -./check_netscaler.pl -H ${IPADDR} -s -C performancedata -n http_tot_Requests,http_tot_Responses -x 'args=counters:http_tot_Requests;http_tot_Responses' +./check_netscaler.pl -H ${IPADDR} -s -C perfdata -n http_tot_Requests,http_tot_Responses -x 'args=counters:http_tot_Requests;http_tot_Responses' ``` For more interesting performance data object types see the following API methods. diff --git a/check_netscaler.pl b/check_netscaler.pl index 25b40d4..caf97d9 100755 --- a/check_netscaler.pl +++ b/check_netscaler.pl @@ -6,7 +6,7 @@ # # https://github.com/slauger/check_netscaler # -# Version: 1.3.0 (2017-XX-XX) +# Version: 1.3.0 (2017-08-13) # # Copyright 2015-2017 Simon Lauger # @@ -40,8 +40,13 @@ version => '1.3.0', url => 'https://github.com/slauger/check_netscaler', blurb => 'Nagios Plugin for Citrix NetScaler Appliance (VPX/MPX/SDX/CPX)', - usage => 'Usage: %s -H [ -P ] [ -u ] [ -p ] -C [ -o ] [ -n ] [ -e ] -[ -w ] [ -c ] [ -v|--verbose ] [ -s|--ssl ] [ -t ] [ -x ] [ -a|--api ]', + usage => 'Usage: %s +-H|--hostname= -C|--command= +[ -o|--objecttype= ] [ -n|--objectname= ] +[ -u|--username= ] [ -p|--password= ] +[ -s|--ssl ] [ -a|--api= ] [ -P|--port= ] +[ -e|--endpoint= ] [ -w|--warning= ] [ -c|--critical= ] +[ -v|--verbose ] [ -t|--timeout= ] [ -x|--urlopts= ]', license => 'http://www.apache.org/licenses/LICENSE-2.0', extra => ' This is a Nagios monitoring plugin for the Citrix NetScaler. The plugin works with @@ -90,7 +95,7 @@ { spec => 'command|C=s', usage => '-C, --command=STRING', - desc => 'Check to be executed on the appliance', + desc => 'Check to be executed on the appliance.', required => 1, }, { @@ -176,9 +181,10 @@ } elsif ($plugin->opts->command eq 'hwinfo') { # print infos about hardware and build version get_hardware_info($plugin); -} elsif ($plugin->opts->command eq 'performancedata') { +# be backwards compatible; also accept command 'performancedata' +} elsif ($plugin->opts->command eq 'perfdata' || $plugin->opts->command eq 'performancedata') { # print performance data of protocol stats - get_performancedata($plugin); + get_perfdata($plugin); } elsif ($plugin->opts->command eq 'interfaces') { # check the state of all interfaces check_interfaces($plugin); @@ -650,7 +656,7 @@ sub get_hardware_info $plugin->nagios_exit($code, 'INFO: ' . $message); } -sub get_performancedata +sub get_perfdata { my $plugin = shift; @@ -661,7 +667,7 @@ sub get_performancedata $params{'options'} = $plugin->opts->urlopts; if (!defined $plugin->opts->objectname) { - $plugin->nagios_die('performancedata: command requires parameter for objectname'); + $plugin->nagios_die('perfdata: command requires parameter for objectname'); } my $response = nitro_client($plugin, \%params); @@ -671,16 +677,16 @@ sub get_performancedata foreach $response (@{$response}) { foreach my $objectname (split(',', $plugin->opts->objectname)) { if (not index($objectname, '.') != -1) { - $plugin->nagios_die('performancedata: return data is an array and contains multible objects. You need te seperate id and name with a ".".'); + $plugin->nagios_die('perfdata: return data is an array and contains multible objects. You need te seperate id and name with a ".".'); } my ($objectname_id, $objectname_name) = split /\./, $objectname; if (not defined($response->{$objectname_id})) { - $plugin->nagios_die('performancedata: object id "' . $objectname_id . '" not found in output.'); + $plugin->nagios_die('perfdata: object id "' . $objectname_id . '" not found in output.'); } if (not defined($response->{$objectname_name})) { - $plugin->nagios_die('performancedata: object name "' . $objectname_name . '" not found in output.'); + $plugin->nagios_die('perfdata: object name "' . $objectname_name . '" not found in output.'); } $plugin->add_message(OK, $params{'objecttype'} . '.' . $response->{$objectname_id} . '.' . $objectname_name . ":" . $response->{$objectname_name} . ","); @@ -698,7 +704,7 @@ sub get_performancedata } elsif ( ref $response eq 'HASH' ) { foreach my $objectname (split(',', $plugin->opts->objectname)) { if (not defined($response->{$objectname})) { - $plugin->nagios_die('performancedata: object name "' . $objectname . '" not found in output.'); + $plugin->nagios_die('perfdata: object name "' . $objectname . '" not found in output.'); } $plugin->add_message(OK, $params{'objecttype'} . '.' . $objectname . ':', $response->{$objectname}. ','); @@ -712,11 +718,11 @@ sub get_performancedata ); } } else { - $plugin->nagios_die('performancedata: unable to parse data. Returned data is not a HASH or ARRAY!'); + $plugin->nagios_die('perfdata: unable to parse data. Returned data is not a HASH or ARRAY!'); } my ($code, $message) = $plugin->check_messages; - $plugin->nagios_exit($code, 'performancedata: ' . $message); + $plugin->nagios_exit($code, 'perfdata: ' . $message); } sub check_interfaces From d5d534abeaf30b7b74380aeda8ab9ec9922502fa Mon Sep 17 00:00:00 2001 From: Simon Lauger Date: Sun, 13 Aug 2017 17:54:15 +0200 Subject: [PATCH 14/21] added Time-Piece and Data-Dumper in the installation instructions --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8d11b8e..5a93589 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ If you looking for a plugin to test your NetScaler Gateway vServer and Storefron ## Installation -On a Enterprise Linux machine (CentOS, RHEL) execute the following commands to install all Perl dependencies (Nagios::Plugin, LWP, JSON): +On a Enterprise Linux machine (CentOS, RHEL) execute the following commands to install all Perl dependencies (Nagios::Plugin, LWP, JSON, Time-Piece, Data-Dumper): ``` yum install perl-libwww-perl perl-JSON perl-Nagios-Plugin perl-Time-Piece perl-Data-Dumper From 8cf4f6f2f4fd568464580c572093990ab0ccce23 Mon Sep 17 00:00:00 2001 From: Simon Lauger Date: Sun, 13 Aug 2017 18:03:55 +0200 Subject: [PATCH 15/21] plugin_test.sh now uses --extra-opts --- examples/plugin_test.sh | 89 ++++++++++++++++------------------------- 1 file changed, 35 insertions(+), 54 deletions(-) diff --git a/examples/plugin_test.sh b/examples/plugin_test.sh index 204da90..70089f0 100755 --- a/examples/plugin_test.sh +++ b/examples/plugin_test.sh @@ -1,119 +1,100 @@ #!/bin/bash -# default ipaddr -if [ "${1}" = "" ]; -then - echo "Syntax: $0 [] [] [(bool) ssl]" - exit 1 -else - IPADDR="${1}" -fi - -# default username -if [ "${2}" = "" ]; -then - USERNAME="nsroot" -else - USERNAME=${2} -fi - -# default password -if [ "${3}" = "" ]; -then - PASSWORD="nsroot" -else - PASSWORD=${3} -fi - -# enable ssl -if [ "${4}" == "true" ]; -then - SSL="-s" -else - SSL="" +if [ ! -f "${1}" ]; then + echo "ERROR: config file not found or not readable" + echo "" + echo "Syntax: $0 " + echo "" + echo "Configuration example:" + echo "" + echo " [netscaler]" + echo " username=nsroot" + echo " password=nsroot" + echo " hostname=netscaler01.example.local" + echo " ssl=true" + exit 1 fi -if [ "${5}" = "" ]; -then - PORT="" +if [ "${2}" != "" ]; then + section="${2}" else - PORT="-P ${5}" + section="netscaler" fi echo NetScaler::SSLCerts -./check_netscaler.pl -H ${IPADDR} ${PORT} ${SSL} -u ${USERNAME} -p ${PASSWORD} -C sslcert -w 30 -c 10 +./check_netscaler.pl --extra-opts=${section}@${1} -C sslcert -w 30 -c 10 echo echo NetScaler::NSConfig -./check_netscaler.pl -H ${IPADDR} ${PORT} ${SSL} -u ${USERNAME} -p ${PASSWORD} -C nsconfig +./check_netscaler.pl --extra-opts=${section}@${1} -C nsconfig echo echo NetScaler::HWInfo -./check_netscaler.pl -H ${IPADDR} ${PORT} ${SSL} -u ${USERNAME} -p ${PASSWORD} -C hwinfo +./check_netscaler.pl --extra-opts=${section}@${1} -C hwinfo echo echo NetScaler::Interfaces -./check_netscaler.pl -H ${IPADDR} ${PORT} ${SSL} -u ${USERNAME} -p ${PASSWORD} -C interfaces +./check_netscaler.pl --extra-opts=${section}@${1} -C interfaces echo echo NetScaler::Perfdata::AAA -./check_netscaler.pl -H ${IPADDR} ${PORT} ${SSL} -u ${USERNAME} -p ${PASSWORD} -C performancedata -o aaa -n aaacuricasessions,aaacuricaonlyconn +./check_netscaler.pl --extra-opts=${section}@${1} -C performancedata -o aaa -n aaacuricasessions,aaacuricaonlyconn echo echo NetScaler::VPNvServer::State -./check_netscaler.pl -H ${IPADDR} ${PORT} ${SSL} -u ${USERNAME} -p ${PASSWORD} -C state -o vpnvserver +./check_netscaler.pl --extra-opts=${section}@${1} -C state -o vpnvserver echo echo NetScaler::LBvServer::State -./check_netscaler.pl -H ${IPADDR} ${PORT} ${SSL} -u ${USERNAME} -p ${PASSWORD} -C state -o lbvserver +./check_netscaler.pl --extra-opts=${section}@${1} -C state -o lbvserver echo echo NetScaler::GSLBvServer::State -./check_netscaler.pl -H ${IPADDR} ${PORT} ${SSL} -u ${USERNAME} -p ${PASSWORD} -C state -o gslbvserver +./check_netscaler.pl --extra-opts=${section}@${1} -C state -o gslbvserver echo echo NetScaler:::AAAvServer::State -./check_netscaler.pl -H ${IPADDR} ${PORT} ${SSL} -u ${USERNAME} -p ${PASSWORD} -C state -o authenticationvserver +./check_netscaler.pl --extra-opts=${section}@${1} -C state -o authenticationvserver echo echo NetScaler:::CSvServer::State -./check_netscaler.pl -H ${IPADDR} ${PORT} ${SSL} -u ${USERNAME} -p ${PASSWORD} -C state -o csvserver +./check_netscaler.pl --extra-opts=${section}@${1} -C state -o csvserver echo #echo NetScaler::SSLvServer::State -#./check_netscaler.pl -H ${IPADDR} ${PORT} ${SSL} -u ${USERNAME} -p ${PASSWORD} -C state -o sslvserver +#./check_netscaler.pl --extra-opts=${section}@${1} -C state -o sslvserver #echo echo NetScaler::Server -./check_netscaler.pl -H ${IPADDR} ${PORT} ${SSL} -u ${USERNAME} -p ${PASSWORD} -C server +./check_netscaler.pl --extra-opts=${section}@${1} -C server echo echo NetScaler::System::Memory -./check_netscaler.pl -H ${IPADDR} ${PORT} ${SSL} -u ${USERNAME} -p ${PASSWORD} -C above -o system -n memusagepcnt -w 75 -c 80 +./check_netscaler.pl --extra-opts=${section}@${1} -C above -o system -n memusagepcnt -w 75 -c 80 echo echo NetScaler::System::CPU -./check_netscaler.pl -H ${IPADDR} ${PORT} ${SSL} -u ${USERNAME} -p ${PASSWORD} -C above -o system -n cpuusagepcnt -w 75 -c 80 +./check_netscaler.pl --extra-opts=${section}@${1} -C above -o system -n cpuusagepcnt -w 75 -c 80 echo echo NetScaler::System::CPU::MGMT -./check_netscaler.pl -H ${IPADDR} ${PORT} ${SSL} -u ${USERNAME} -p ${PASSWORD} -C above -o system -n mgmtcpuusagepcnt -w 75 -c 80 +./check_netscaler.pl --extra-opts=${section}@${1} -C above -o system -n mgmtcpuusagepcnt -w 75 -c 80 echo echo NetScaler::System::Disk0 -./check_netscaler.pl -H ${IPADDR} ${PORT} ${SSL} -u ${USERNAME} -p ${PASSWORD} -C above -o system -n disk0perusage -w 75 -c 80 +./check_netscaler.pl --extra-opts=${section}@${1} -C above -o system -n disk0perusage -w 75 -c 80 echo echo NetScaler::System::Disk1 -./check_netscaler.pl -H ${IPADDR} ${PORT} ${SSL} -u ${USERNAME} -p ${PASSWORD} -C above -o system -n disk1perusage -w 75 -c 80 +./check_netscaler.pl --extra-opts=${section}@${1} -C above -o system -n disk1perusage -w 75 -c 80 echo echo NetScaler::HA::Status -./check_netscaler.pl -H ${IPADDR} ${PORT} ${SSL} -u ${USERNAME} -p ${PASSWORD} -C matches_not -o hanode -n hacurstatus -w YES -c YES +./check_netscaler.pl --extra-opts=${section}@${1} -C matches_not -o hanode -n hacurstatus -w YES -c YES echo echo NetScaler::HA::State -./check_netscaler.pl -H ${IPADDR} ${PORT} ${SSL} -u ${USERNAME} -p ${PASSWORD} -C matches_not -o hanode -n hacurstate -w UP -c UP +./check_netscaler.pl --extra-opts=${section}@${1} -C matches_not -o hanode -n hacurstate -w UP -c UP echo From 12181b500b66763fa9cf0b41cdd3a094ea94d52a Mon Sep 17 00:00:00 2001 From: Simon Lauger Date: Sun, 13 Aug 2017 18:06:48 +0200 Subject: [PATCH 16/21] smalld documentation fixes --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5a93589..5f22e17 100644 --- a/README.md +++ b/README.md @@ -145,7 +145,7 @@ Usage: check_netscaler ### Check status and quorum of a service group -define member quorum (in percent) with warning and critical values +Define member quorum (in percent) with warning and critical values. ``` # NetScaler::Servicegroup::Webservers @@ -292,8 +292,10 @@ define command { ``` [netscaler] +hostname=netscaler01 username=nagios password=password +ssl=true ``` ## Authors From 905cb90ee0bac1060914ac6ca0478eb017a6e358 Mon Sep 17 00:00:00 2001 From: Simon Lauger Date: Sun, 13 Aug 2017 19:43:35 +0200 Subject: [PATCH 17/21] harmonize plugin output for all commands fixed documentation bug (nsglobalcntr) check_license does now support testing of multiple license files in a single check plugin_test.sh does now use --extra-opts to be more flexible --- README.md | 6 +- check_netscaler.pl | 118 ++++++++++++++++++++++------------------ examples/plugin_test.sh | 24 ++++---- 3 files changed, 81 insertions(+), 67 deletions(-) diff --git a/README.md b/README.md index 5f22e17..55c663c 100644 --- a/README.md +++ b/README.md @@ -205,9 +205,11 @@ Multiple fields need to be seperated by a colon. The license file must be placed in `/nsconfig/license` and the filename must be given as objectname. Also the NITRO user needs permissions to access the filesystem directly (NITRO command systemfile). +Multiple fasta files can be passed, separated with a colon. + ``` # NetScaler::License -./check_netscaler.pl -H ${IPADDR} -s -C license -n FID_4c9a2c7e_14292ea2df2_2a97.lic -w 30 -c 10 +./check_netscaler.pl -H ${IPADDR} -s -C license -n FID_4c9a2c7e_14292ea2df2_2a97.lic,FID_2b9a2c7e_14212ef2d27_4b87.lic -w 30 -c 10 ``` ### Check if STA servers are working @@ -258,7 +260,7 @@ All fields must be defined via "-n" option and be seperated with a comma. [Global counters](https://docs.citrix.com/en-us/netscaler/12/nitro-api/nitro-rest/nitro-rest-usage-scenarios/view-individual-counter-info.html) can be accessed as follows (NetScaler 12.0 and newer). ``` -./check_netscaler.pl -H ${IPADDR} -s -C perfdata -n http_tot_Requests,http_tot_Responses -x 'args=counters:http_tot_Requests;http_tot_Responses' +./check_netscaler.pl -H ${IPADDR} -s -C perfdata -o nsglobalcntr -n http_tot_Requests,http_tot_Responses -x 'args=counters:http_tot_Requests;http_tot_Responses' ``` For more interesting performance data object types see the following API methods. diff --git a/check_netscaler.pl b/check_netscaler.pl index caf97d9..85a506b 100755 --- a/check_netscaler.pl +++ b/check_netscaler.pl @@ -307,7 +307,7 @@ sub check_state my $plugin = shift; if (!defined $plugin->opts->objecttype) { - $plugin->nagios_die('command requires objecttype parameter'); + $plugin->nagios_die($plugin->opts->command . ': command requires objecttype parameter'); } my %counter; @@ -397,9 +397,9 @@ sub check_state ); if ($code == OK) { - $plugin->nagios_exit($code, $plugin->opts->objecttype . ' OK' . $stats); + $plugin->nagios_exit($code, $plugin->opts->command . ' ' . $plugin->opts->objecttype . ': OK' . $stats); } else { - $plugin->nagios_exit($code, $plugin->opts->objecttype . ' ' . $message . $stats); + $plugin->nagios_exit($code, $plugin->opts->command . ' ' . $plugin->opts->objecttype . ': ' . $message . $stats); } } @@ -409,19 +409,19 @@ sub check_string my $type_of_string_comparison = shift; if (!defined $plugin->opts->objecttype) { - $plugin->nagios_die('command requires parameter for objecttype'); + $plugin->nagios_die($plugin->opts->command . ': command requires parameter for objecttype'); } if (!defined $plugin->opts->objectname) { - $plugin->nagios_die('command requires parameter for objectname'); + $plugin->nagios_die($plugin->opts->command . ': command requires parameter for objectname'); } if (!defined $plugin->opts->warning || !defined $plugin->opts->critical) { - $plugin->nagios_die('command requires parameter for warning and critical'); + $plugin->nagios_die($plugin->opts->command . ': command requires parameter for warning and critical'); } if ($type_of_string_comparison ne 'matches' && $type_of_string_comparison ne 'matches not') { - $plugin->nagios_die('string can only be checked for "matches" and "matches not"'); + $plugin->nagios_die($plugin->opts->command . ': string can only be checked for "matches" and "matches not"'); } my %params; @@ -445,7 +445,7 @@ sub check_string my ($code, $message) = $plugin->check_messages; - $plugin->nagios_exit($code, $message); + $plugin->nagios_exit($code, $plugin->opts->command . ': ' . $message); } sub check_threshold @@ -454,19 +454,19 @@ sub check_threshold my $direction = shift; if (!defined $plugin->opts->objecttype) { - $plugin->nagios_die('command requires parameter for objecttype'); + $plugin->nagios_die($plugin->opts->command . ': command requires parameter for objecttype'); } if (!defined $plugin->opts->objectname) { - $plugin->nagios_die('command requires parameter for objectname'); + $plugin->nagios_die($plugin->opts->command . ': command requires parameter for objectname'); } if (!defined $plugin->opts->warning || !defined $plugin->opts->critical) { - $plugin->nagios_die('command requires parameter for warning and critical'); + $plugin->nagios_die($plugin->opts->command . ': command requires parameter for warning and critical'); } if ($direction ne 'above' && $direction ne 'below') { - $plugin->nagios_die('threshold can only be checked for "above" and "below"'); + $plugin->nagios_die($plugin->opts->command . ': threshold can only be checked for "above" and "below"'); } my %params; @@ -498,8 +498,7 @@ sub check_threshold } my ($code, $message) = $plugin->check_messages; - - $plugin->nagios_exit($code, $message); + $plugin->nagios_exit($code, $plugin->opts->command . ': ' . $message); } sub check_sslcert @@ -507,7 +506,7 @@ sub check_sslcert my $plugin = shift; if (!defined $plugin->opts->warning || !defined $plugin->opts->critical) { - $plugin->nagios_die('command requires parameter for warning and critical'); + $plugin->nagios_die($plugin->opts->command . ': command requires parameter for warning and critical'); } my %params; @@ -530,9 +529,9 @@ sub check_sslcert my ($code, $message) = $plugin->check_messages; if ($code == OK) { - $plugin->nagios_exit($code, 'sslcertkey OK'); + $plugin->nagios_exit($code, $plugin->opts->command . ': certificate lifetime OK'); } else { - $plugin->nagios_exit($code, 'sslcertkey ' . $message); + $plugin->nagios_exit($code, $plugin->opts->command . ': ' . $message); } } @@ -554,6 +553,10 @@ sub check_staserver my $response = nitro_client($plugin, \%params); $response = $response->{$params{'objecttype'}}; + if (!scalar($response)) { + $plugin->nagios_exit(CRITICAL, $plugin->opts->command . ': no staserver found in configuration') + } + # return critical if all staservers are down at once my $critical = 1; @@ -571,7 +574,7 @@ sub check_staserver if ( $critical == 1) { $code = CRITICAL; } - $plugin->nagios_exit($code, 'server ' . $message); + $plugin->nagios_exit($code, $plugin->opts->command . ': ' . $message); } sub check_server @@ -587,15 +590,19 @@ sub check_server my $response = nitro_client($plugin, \%params); $response = $response->{$params{'objecttype'}}; + if (!scalar($response)) { + $plugin->nagios_exit(CRITICAL, $plugin->opts->command . ': no server found in configuration') + } + # return critical if all servers are disabled at once my $critical = 1; # check if any server is in disabled state foreach $response (@{$response}) { if ($response->{'state'} ne 'ENABLED') { - $plugin->add_message(WARNING, $response->{'name'} . '('. $response->{'ipaddress'} .') ' . $response->{'state'} . ' ;'); + $plugin->add_message(WARNING, $response->{'name'} . '('. $response->{'ipaddress'} .') ' . $response->{'state'} . ';'); } else { - $plugin->add_message(OK, $response->{'name'} . '('. $response->{'ipaddress'} .') ' . $response->{'state'} . ' ;'); + $plugin->add_message(OK, $response->{'name'} . '('. $response->{'ipaddress'} .') ' . $response->{'state'} . ';'); $critical = 0; } } @@ -604,7 +611,7 @@ sub check_server if ( $critical == 1) { $code = CRITICAL; } - $plugin->nagios_exit($code, 'server ' . $message); + $plugin->nagios_exit($code, $plugin->opts->command . ': ' . $message); } sub check_nsconfig @@ -621,9 +628,9 @@ sub check_nsconfig $response = $response->{$params{'objecttype'}}; if (!defined $response->{'configchanged'} || $response->{'configchanged'}) { - $plugin->nagios_exit(WARNING, 'nsconfig::configchanged unsaved configuration changes'); + $plugin->nagios_exit(WARNING, $plugin->opts->command . ': unsaved configuration changes'); } else { - $plugin->nagios_exit(OK, 'nsconfig::configchanged OK'); + $plugin->nagios_exit(OK, $plugin->opts->command . ': no unsaved configuration changes'); } } @@ -653,7 +660,7 @@ sub get_hardware_info $plugin->add_message(OK, 'Build Version: ' . $response->{'version'} . ';'); my ($code, $message) = $plugin->check_messages; - $plugin->nagios_exit($code, 'INFO: ' . $message); + $plugin->nagios_exit($code, $plugin->opts->command . ': ' . $message); } sub get_perfdata @@ -665,9 +672,13 @@ sub get_perfdata $params{'objecttype'} = $plugin->opts->objecttype; $params{'objectname'} = undef; $params{'options'} = $plugin->opts->urlopts; + + if (!defined $plugin->opts->objecttype) { + $plugin->nagios_die($plugin->opts->command . ': command requires parameter for objecttype'); + } if (!defined $plugin->opts->objectname) { - $plugin->nagios_die('perfdata: command requires parameter for objectname'); + $plugin->nagios_die($plugin->opts->command . ': command requires parameter for objectname'); } my $response = nitro_client($plugin, \%params); @@ -677,16 +688,16 @@ sub get_perfdata foreach $response (@{$response}) { foreach my $objectname (split(',', $plugin->opts->objectname)) { if (not index($objectname, '.') != -1) { - $plugin->nagios_die('perfdata: return data is an array and contains multible objects. You need te seperate id and name with a ".".'); + $plugin->nagios_die($plugin->opts->command . ': return data is an array and contains multible objects. You need te seperate id and name with a ".".'); } my ($objectname_id, $objectname_name) = split /\./, $objectname; if (not defined($response->{$objectname_id})) { - $plugin->nagios_die('perfdata: object id "' . $objectname_id . '" not found in output.'); + $plugin->nagios_die($plugin->opts->command . ': object id "' . $objectname_id . '" not found in output.'); } if (not defined($response->{$objectname_name})) { - $plugin->nagios_die('perfdata: object name "' . $objectname_name . '" not found in output.'); + $plugin->nagios_die($plugin->opts->command . ': object name "' . $objectname_name . '" not found in output.'); } $plugin->add_message(OK, $params{'objecttype'} . '.' . $response->{$objectname_id} . '.' . $objectname_name . ":" . $response->{$objectname_name} . ","); @@ -704,7 +715,7 @@ sub get_perfdata } elsif ( ref $response eq 'HASH' ) { foreach my $objectname (split(',', $plugin->opts->objectname)) { if (not defined($response->{$objectname})) { - $plugin->nagios_die('perfdata: object name "' . $objectname . '" not found in output.'); + $plugin->nagios_die($plugin->opts->command . ': object name "' . $objectname . '" not found in output.'); } $plugin->add_message(OK, $params{'objecttype'} . '.' . $objectname . ':', $response->{$objectname}. ','); @@ -718,11 +729,11 @@ sub get_perfdata ); } } else { - $plugin->nagios_die('perfdata: unable to parse data. Returned data is not a HASH or ARRAY!'); + $plugin->nagios_die($plugin->opts->command . ': unable to parse data. Returned data is not a HASH or ARRAY!'); } my ($code, $message) = $plugin->check_messages; - $plugin->nagios_exit($code, 'perfdata: ' . $message); + $plugin->nagios_exit($code, $plugin->opts->command . ': ' . $message); } sub check_interfaces @@ -782,7 +793,7 @@ sub check_interfaces if (scalar @interface_errors != 0 ) { $message = join(', ', @interface_errors). ' - '. $message } - $plugin->nagios_exit($code, 'Interfaces: ' . $message); + $plugin->nagios_exit($code, $plugin->opts->command . ': ' . $message); } sub check_servicegroup @@ -803,7 +814,7 @@ sub check_servicegroup $params{'options'} = $plugin->opts->urlopts; if (not defined ($plugin->opts->objectname)) { - $plugin->nagios_die('servicegroup: no object name "-n" set'); + $plugin->nagios_die($plugin->opts->command . ': no object name "-n" set'); } my %healthy_servicegroup_states; @@ -889,7 +900,7 @@ sub check_servicegroup if (scalar @servicegroup_errors != 0 ) { $message = join(', ', @servicegroup_errors). ' - '. $message } - $plugin->nagios_exit($servicegroup_state, 'servicegroup: ' . $message); + $plugin->nagios_exit($servicegroup_state, $plugin->opts->command . ': ' . $message); } sub check_license @@ -902,39 +913,42 @@ sub check_license $params{'options'} = $plugin->opts->urlopts; if (!defined $plugin->opts->warning || !$plugin->opts->critical) { - $plugin->nagios_die('command requires parameter for warning and critical'); + $plugin->nagios_die($plugin->opts->command . ': command requires parameter for warning and critical'); } if (!defined $plugin->opts->objectname) { - $plugin->nagios_die('license filename must be given as objectname via "-n"') + $plugin->nagios_die($plugin->opts->command . ': filename must be given as objectname via "-n"') } - $params{'options'} = 'args=filelocation:'.uri_escape('/nsconfig/license').',filename:'.uri_escape($plugin->opts->objectname); - - my $response = nitro_client($plugin, \%params); - + my $response; my @stripped; my $timepiece; - foreach (split(/\n/, decode_base64($response->{'systemfile'}[0]->{'filecontent'}))) { - if ($_ =~ /^INCREMENT .*/) { - @stripped = split(' ', $_); + foreach (split(',', $plugin->opts->objectname)) { + $params{'options'} = 'args=filelocation:'.uri_escape('/nsconfig/license').',filename:'.uri_escape($_); - # date format in license file, e.g. 18-jan-2018 - $timepiece = Time::Piece->strptime(($stripped[4], '%d-%b-%Y')); + $response = nitro_client($plugin, \%params); - if ($timepiece->epoch - time < (60*60*24*$plugin->opts->critical)) { - $plugin->add_message(CRITICAL, $stripped[1] . ' expires on ' . $stripped[4] . ';'); - } elsif ($timepiece->epoch - time < (60*60*24*$plugin->opts->warning)) { - $plugin->add_message(WARNING, $stripped[1] . ' expires on ' . $stripped[4] . ';'); - } else { - $plugin->add_message(OK, $stripped[1] . ' expires on ' . $stripped[4] . ';'); + foreach (split(/\n/, decode_base64($response->{'systemfile'}[0]->{'filecontent'}))) { + if ($_ =~ /^INCREMENT .*/) { + @stripped = split(' ', $_); + + # date format in license file, e.g. 18-jan-2018 + $timepiece = Time::Piece->strptime(($stripped[4], '%d-%b-%Y')); + + if ($timepiece->epoch - time < (60*60*24*$plugin->opts->critical)) { + $plugin->add_message(CRITICAL, $stripped[1] . ' expires on ' . $stripped[4] . ';'); + } elsif ($timepiece->epoch - time < (60*60*24*$plugin->opts->warning)) { + $plugin->add_message(WARNING, $stripped[1] . ' expires on ' . $stripped[4] . ';'); + } else { + $plugin->add_message(OK, $stripped[1] . ' expires on ' . $stripped[4] . ';'); + } } } } my ($code, $message) = $plugin->check_messages; - $plugin->nagios_exit($code, 'license: ' . $message); + $plugin->nagios_exit($code, $plugin->opts->command . ': ' . $message); } sub check_debug diff --git a/examples/plugin_test.sh b/examples/plugin_test.sh index 70089f0..7181f1a 100755 --- a/examples/plugin_test.sh +++ b/examples/plugin_test.sh @@ -3,7 +3,7 @@ if [ ! -f "${1}" ]; then echo "ERROR: config file not found or not readable" echo "" - echo "Syntax: $0 " + echo "Syntax: $0 [
]" echo "" echo "Configuration example:" echo "" @@ -69,24 +69,20 @@ echo NetScaler::Server ./check_netscaler.pl --extra-opts=${section}@${1} -C server echo +echo NetScaler::STA +./check_netscaler.pl --extra-opts=${section}@${1} -C staserver +echo + echo NetScaler::System::Memory ./check_netscaler.pl --extra-opts=${section}@${1} -C above -o system -n memusagepcnt -w 75 -c 80 echo echo NetScaler::System::CPU -./check_netscaler.pl --extra-opts=${section}@${1} -C above -o system -n cpuusagepcnt -w 75 -c 80 -echo - -echo NetScaler::System::CPU::MGMT -./check_netscaler.pl --extra-opts=${section}@${1} -C above -o system -n mgmtcpuusagepcnt -w 75 -c 80 +./check_netscaler.pl --extra-opts=${section}@${1} -C above -o system -n cpuusagepcnt,mgmtcpuusagepcnt -w 75 -c 80 echo -echo NetScaler::System::Disk0 -./check_netscaler.pl --extra-opts=${section}@${1} -C above -o system -n disk0perusage -w 75 -c 80 -echo - -echo NetScaler::System::Disk1 -./check_netscaler.pl --extra-opts=${section}@${1} -C above -o system -n disk1perusage -w 75 -c 80 +echo NetScaler::System::Disk +./check_netscaler.pl --extra-opts=${section}@${1} -C above -o system -n disk0perusage,disk1perusage -w 75 -c 80 echo echo NetScaler::HA::Status @@ -97,4 +93,6 @@ echo NetScaler::HA::State ./check_netscaler.pl --extra-opts=${section}@${1} -C matches_not -o hanode -n hacurstate -w UP -c UP echo - +echo NetScaler::Perfdata::HTTP +./check_netscaler.pl --extra-opts=${section}@${1} -C perfdata -o nsglobalcntr -n http_tot_Requests,http_tot_Responses -x 'args=counters:http_tot_Requests;http_tot_Responses' +echo \ No newline at end of file From da217741ceaf9c74917f6e8002d6eeac39f74398 Mon Sep 17 00:00:00 2001 From: Simon Lauger Date: Sun, 13 Aug 2017 21:31:21 +0200 Subject: [PATCH 18/21] harmonize output of threshold and keyword check --- check_netscaler.pl | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/check_netscaler.pl b/check_netscaler.pl index 85a506b..479c9fc 100755 --- a/check_netscaler.pl +++ b/check_netscaler.pl @@ -161,11 +161,11 @@ # be backwards compatible; also accept command 'string' } elsif ($plugin->opts->command eq 'matches' || $plugin->opts->command eq 'string') { # check if a response does contains a specific string - check_string($plugin, 'matches'); + check_keyword($plugin, 'matches'); # be backwards compatible; also accept command 'string_not' } elsif ($plugin->opts->command eq 'matches_not' || $plugin->opts->command eq 'string_not') { # check if a response does not contains a specific string - check_string($plugin, 'matches not'); + check_keyword($plugin, 'matches not'); } elsif ($plugin->opts->command eq 'sslcert') { # check for the lifetime of installed certificates check_sslcert($plugin); @@ -403,7 +403,7 @@ sub check_state } } -sub check_string +sub check_keyword { my $plugin = shift; my $type_of_string_comparison = shift; @@ -435,17 +435,17 @@ sub check_string foreach ( split(',', $plugin->opts->objectname) ) { if (($type_of_string_comparison eq 'matches' && $response->{$_} eq $plugin->opts->critical) || ($type_of_string_comparison eq 'matches not' && $response->{$_} ne $plugin->opts->critical)) { - $plugin->add_message(CRITICAL, $plugin->opts->objecttype . '::' . $_ . ' ' . $type_of_string_comparison . ' keyword (current: ' . $response->{$_} . ', critical: ' . $plugin->opts->critical . ');'); + $plugin->add_message(CRITICAL, $plugin->opts->objecttype . '.' . $_ . ': "' . $response->{$_} . '" ' . $type_of_string_comparison . ' keyword "' . $plugin->opts->critical . '";'); } elsif (($type_of_string_comparison eq 'matches' && $response->{$_} eq $plugin->opts->warning) || ($type_of_string_comparison eq 'matches not' && $response->{$_} ne $plugin->opts->warning)) { - $plugin->add_message(WARNING, $plugin->opts->objecttype . '::' . $_ . ' ' . $type_of_string_comparison . ' keyword (current: ' . $response->{$_} . ', warning: ' . $plugin->opts->warning . ');'); + $plugin->add_message(WARNING, $plugin->opts->objecttype . '.' . $_ . ': "' . $response->{$_} . '" ' . $type_of_string_comparison . ' keyword "' . $plugin->opts->warning . '";'); } else { - $plugin->add_message(OK, $plugin->opts->objecttype . '::' . $_ . ' OK ('.$response->{$_}.');'); + $plugin->add_message(OK, $plugin->opts->objecttype . '.' . $_ . ': '.$response->{$_}.';'); } } my ($code, $message) = $plugin->check_messages; - $plugin->nagios_exit($code, $plugin->opts->command . ': ' . $message); + $plugin->nagios_exit($code, 'keyword ' . $type_of_string_comparison . ': ' . $message); } sub check_threshold @@ -480,7 +480,7 @@ sub check_threshold foreach ( split(',', $plugin->opts->objectname) ) { $plugin->add_perfdata( - label => $plugin->opts->objecttype . '::' . $_, + label => $plugin->opts->objecttype . '.' . $_, value => $response->{$_}, min => undef, max => undef, @@ -489,16 +489,16 @@ sub check_threshold ); if (($direction eq 'above' && $response->{$_} >= $plugin->opts->critical) || ($direction eq 'below' && $response->{$_} <= $plugin->opts->critical)) { - $plugin->add_message(CRITICAL, $plugin->opts->objecttype . '::' . $_ . ' is ' . $direction . ' threshold (current: ' . $response->{$_} . ', critical: ' . $plugin->opts->critical . ');'); + $plugin->add_message(CRITICAL, $plugin->opts->objecttype . '.' . $_ . ' is ' . $direction . ' threshold (current: ' . $response->{$_} . ', critical: ' . $plugin->opts->critical . ');'); } elsif (($direction eq 'above' && $response->{$_} >= $plugin->opts->warning) || ($direction eq 'below' && $response->{$_} <= $plugin->opts->warning)) { - $plugin->add_message(WARNING, $plugin->opts->objecttype . '::' . $_ . ' is ' . $direction . ' threshold (current: ' . $response->{$_} . ', warning: ' . $plugin->opts->warning . ');'); + $plugin->add_message(WARNING, $plugin->opts->objecttype . '.' . $_ . ' is ' . $direction . ' threshold (current: ' . $response->{$_} . ', warning: ' . $plugin->opts->warning . ');'); } else { - $plugin->add_message(OK, $_ . '::' . $_ . ' ('.$response->{$_}.')'); + $plugin->add_message(OK, $_ . '.' . $_ . ': '.$response->{$_} . ';'); } } my ($code, $message) = $plugin->check_messages; - $plugin->nagios_exit($code, $plugin->opts->command . ': ' . $message); + $plugin->nagios_exit($code, 'threshold ' . $plugin->opts->command . ': ' . $message); } sub check_sslcert From cd60efa309fa0eb0a154342202786c7658abf61d Mon Sep 17 00:00:00 2001 From: Simon Lauger Date: Sun, 13 Aug 2017 22:28:05 +0200 Subject: [PATCH 19/21] refactoring of check_state cleanup and simplified code (counter etc.) added support for testing servers (makes check_server obsolet) added warning level for DISABLED and PARTIAL-UP --- check_netscaler.pl | 90 +++++++++++++++++++--------------------------- 1 file changed, 37 insertions(+), 53 deletions(-) diff --git a/check_netscaler.pl b/check_netscaler.pl index 479c9fc..e4dd7b1 100755 --- a/check_netscaler.pl +++ b/check_netscaler.pl @@ -312,10 +312,21 @@ sub check_state my %counter; - $counter{'up'} = 0; - $counter{'down'} = 0; - $counter{'oos'} = 0; - $counter{'unkown'} = 0; + # special handling for objecttype server + if ($plugin->opts->objecttype eq 'server') { + $counter{'ENABLED'} = 0; + $counter{'DISABLED'} = 0; + } else { + $counter{'UP'} = 0; + $counter{'DOWN'} = 0; + $counter{'OUT OF SERVICE'} = 0; + $counter{'UNKOWN'} = 0; + } + + # for servicegroups: PARTIAL-UP (not critical event) + if ($plugin->opts->objecttype eq 'servicegroup') { + $counter{'PARTIAL-UP'} = 0; + } my %params; @@ -331,6 +342,10 @@ sub check_state $params{'endpoint'} = $plugin->opts->endpoint || 'config'; $field_name = 'servicegroupname'; $field_state = 'servicegroupeffectivestate'; + } elsif ($plugin->opts->objecttype eq 'server') { + $params{'endpoint'} = $plugin->opts->endpoint || 'config'; + $field_name = 'name'; + $field_state = 'state'; } else { $params{'endpoint'} = $plugin->opts->endpoint || 'stat'; $field_name = 'name'; @@ -345,62 +360,31 @@ sub check_state $response = $response->{$plugin->opts->objecttype}; foreach my $response (@{$response}) { - if ($response->{$field_state} eq 'UP') { - $counter{'up'}++; + if (defined ($counter{$response->{$field_state}})) { + $counter{$response->{$field_state}}++; } - elsif ($response->{$field_state} eq 'DOWN') { - $counter{'down'}++; - $plugin->add_message(CRITICAL, $response->{$field_name} . ' down;'); - } - elsif ($response->{$field_state} eq 'OUT OF SERVICE') { - $counter{'oos'}++; - $plugin->add_message(CRITICAL, $response->{$field_name} . ' oos;'); - } - elsif ($response->{$field_state} eq 'UNKOWN') { - $counter{'unkown'}++; - $plugin->add_message(CRITICAL, $response->{$field_name} . ' unkown;'); + if ($response->{$field_state} eq 'UP' || $response->{$field_state} eq 'ENABLED') { + $plugin->add_message(OK, $response->{$field_name} . ' ' . $response->{$field_state} . ';'); + } elsif ($response->{$field_state} eq 'PARTIAL-UP' || $response->{$field_state} eq 'DISABLED') { + $plugin->add_message(WARNING, $response->{$field_name} . ' ' . $response->{$field_state} . ';'); } else { - $counter{'unkown'}++; - $plugin->add_message(CRITICAL, $response->{$field_name} . ' unknown;'); + $plugin->add_message(CRITICAL, $response->{$field_name} . ' ' . $response->{$field_state} . ';'); } } - my ($code, $message) = $plugin->check_messages; - - my $stats = ' (' . $counter{'up'} . ' up, ' . $counter{'down'} . ' down, ' . $counter{'oos'} . ' oos, ' . $counter{'unkown'} . ' unkown)'; - - $plugin->add_perfdata( - label => 'up', - value => $counter{'up'}, - min => 0, - max => undef, - ); - $plugin->add_perfdata( - label => 'down', - value => $counter{'down'}, - min => 0, - max => undef, - ); - - $plugin->add_perfdata( - label => 'oos', - value => $counter{'oos'}, - min => 0, - max => undef, - ); + foreach my $key (keys %counter) { + $plugin->add_message(OK, $counter{$key} . ' ' . $key . ';'); + $plugin->add_perfdata( + label => $key, + value => $counter{$key}, + min => 0, + max => undef, + ); + } - $plugin->add_perfdata( - label => 'unkown', - value => $counter{'unkown'}, - min => 0, - max => undef, - ); + my ($code, $message) = $plugin->check_messages; - if ($code == OK) { - $plugin->nagios_exit($code, $plugin->opts->command . ' ' . $plugin->opts->objecttype . ': OK' . $stats); - } else { - $plugin->nagios_exit($code, $plugin->opts->command . ' ' . $plugin->opts->objecttype . ': ' . $message . $stats); - } + $plugin->nagios_exit($code, $plugin->opts->command . ' ' . $plugin->opts->objecttype . ': ' . $message); } sub check_keyword From 492e4d04ae3ecceeeab6d72ff1ff49ad4f9f68fb Mon Sep 17 00:00:00 2001 From: Simon Lauger Date: Sun, 13 Aug 2017 22:45:30 +0200 Subject: [PATCH 20/21] removed command server from the plugin (replaced by state in v1.3.0) --- README.md | 13 ++++---- check_netscaler.pl | 44 +++---------------------- examples/icinga2_service_templates.conf | 3 +- examples/plugin_test.sh | 2 +- 4 files changed, 13 insertions(+), 49 deletions(-) diff --git a/README.md b/README.md index 55c663c..02140ed 100644 --- a/README.md +++ b/README.md @@ -7,13 +7,12 @@ Currently the plugin has the following subcommands: | command | description | --- | --- | -**state** | check the current service state of vservers (e.g. lb, vpn, gslb), services and service groups +**state** | check the current service state of vservers (e.g. lb, vpn, gslb), services and service groups and servers **matches, matches_not** | check if a string exists in the api response or not (e.g. HA or cluster status) **above, below** | check if a value is above/below a threshold (e.g. traffic limits, concurrent connections) **sslcert** | check the lifetime for installed ssl certificates **nsconfig** | check for configuration changes which are not saved to disk **license** | check the expiry date of a local installed license file -**server** | check status of Load Balancing Servers **staserver** | check if configured STA (secure ticket authority) servers are available **servicegroup** | check the state of a servicegroup and its members **hwinfo** | just print information about the Netscaler itself @@ -152,14 +151,14 @@ Define member quorum (in percent) with warning and critical values. ./check_netscaler.pl -H ${IPADDR} -s -C servicegroup -n sg_webservers -w 75 -c 50 ``` -### Check if Load Balancing servers are enabled +### Check status of server objects ``` -# NetScaler::Server -./check_netscaler.pl -H ${IPADDR} -s -C server +# NetScaler::Servers +./check_netscaler.pl -H ${IPADDR} -s -C state -o server -# NetScaler::Server -./check_netscaler.pl -H ${IPADDR} -s -C server -n web01.example.com +# NetScaler::Servers::web01.example.com +./check_netscaler.pl -H ${IPADDR} -s -C state -o server -n web01.example.com ``` ### Check for thresholds or matching strings diff --git a/check_netscaler.pl b/check_netscaler.pl index e4dd7b1..53e6116 100755 --- a/check_netscaler.pl +++ b/check_netscaler.pl @@ -175,9 +175,6 @@ } elsif ($plugin->opts->command eq 'staserver') { # check the state of the staservers check_staserver($plugin); -} elsif ($plugin->opts->command eq 'server') { - # check the state of the servers - check_server($plugin); } elsif ($plugin->opts->command eq 'hwinfo') { # print infos about hardware and build version get_hardware_info($plugin); @@ -359,6 +356,10 @@ sub check_state my $response = nitro_client($plugin, \%params); $response = $response->{$plugin->opts->objecttype}; + if (!scalar($response)) { + $plugin->nagios_exit(CRITICAL, $plugin->opts->command . ': no ' . $plugin->opts->objecttype . ' found in configuration') + } + foreach my $response (@{$response}) { if (defined ($counter{$response->{$field_state}})) { $counter{$response->{$field_state}}++; @@ -561,43 +562,6 @@ sub check_staserver $plugin->nagios_exit($code, $plugin->opts->command . ': ' . $message); } -sub check_server -{ - my $plugin = shift; - - my %params; - $params{'endpoint'} = $plugin->opts->endpoint || 'config'; - $params{'objectname'} = $plugin->opts->objectname || ''; - $params{'options'} = $plugin->opts->urlopts; - $params{'objecttype'} = 'server'; - - my $response = nitro_client($plugin, \%params); - $response = $response->{$params{'objecttype'}}; - - if (!scalar($response)) { - $plugin->nagios_exit(CRITICAL, $plugin->opts->command . ': no server found in configuration') - } - - # return critical if all servers are disabled at once - my $critical = 1; - - # check if any server is in disabled state - foreach $response (@{$response}) { - if ($response->{'state'} ne 'ENABLED') { - $plugin->add_message(WARNING, $response->{'name'} . '('. $response->{'ipaddress'} .') ' . $response->{'state'} . ';'); - } else { - $plugin->add_message(OK, $response->{'name'} . '('. $response->{'ipaddress'} .') ' . $response->{'state'} . ';'); - $critical = 0; - } - } - - my ($code, $message) = $plugin->check_messages; - - if ( $critical == 1) { $code = CRITICAL; } - - $plugin->nagios_exit($code, $plugin->opts->command . ': ' . $message); -} - sub check_nsconfig { my $plugin = shift; diff --git a/examples/icinga2_service_templates.conf b/examples/icinga2_service_templates.conf index 9d3e522..9c6aaa9 100644 --- a/examples/icinga2_service_templates.conf +++ b/examples/icinga2_service_templates.conf @@ -142,7 +142,8 @@ template Service "netscaler_server_template" { check_command = "netscaler" - vars.netscaler_command = "server" + vars.netscaler_command = "state" + vars.netscaler_objecttype = "server" } template Service "netscaler_lbvserver_template" { diff --git a/examples/plugin_test.sh b/examples/plugin_test.sh index 7181f1a..4fe2f54 100755 --- a/examples/plugin_test.sh +++ b/examples/plugin_test.sh @@ -66,7 +66,7 @@ echo #echo echo NetScaler::Server -./check_netscaler.pl --extra-opts=${section}@${1} -C server +./check_netscaler.pl --extra-opts=${section}@${1} -C state -o server echo echo NetScaler::STA From 9f0aa8e9b1c83533fe22f8e13f68ba552f177ecb Mon Sep 17 00:00:00 2001 From: Simon Lauger Date: Sun, 13 Aug 2017 23:14:14 +0200 Subject: [PATCH 21/21] updated CHANGELOG.md for release v1.3.0 --- CHANGELOG.md | 28 +++++++++++++++++----------- README.md | 2 +- check_netscaler.pl | 4 ++-- 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d697520..33ae954 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## 1.3.0 (2017-08-13) +## v1.3.0 (2017-08-13) - added command license to check the status of a local license file (#17) - added perl-Time-Piece as new dependency (Time::Piece for license check) - added perl-Data-Dumper to the install instructions in the README.md @@ -6,9 +6,15 @@ - allow the usage of urlopts everywhere (fixes #13) - check_threshold and check_string accept arrays (seperated by colon) (fixes #7) - renamed checks 'string' and 'string_not' to 'matches' and 'matches_not' (backwards compatibility given) -- renamed check 'performancedata' to 'perfdata' (backwards compatibility given) - -## 1.2.0 (2017-08-12) +- renamed check 'performancedata' to 'perfdata' (backwards compatibility given); +- backwards compatibility will be removed in a future release, please update your nagios configuration +- harmonized plugin output for all subcommands +- refactored sub check_state (cleanup and simplified code) + - added support for testing the status of server objects + - added a new warning level for DISABLED and PARTIAL-UP objects +- removed command server (as it might be confusing for users to have two checks with the same function) + +## v1.2.0 (2017-08-12) - merged pull request from @bb-Ricardo - added command server to check status of Load Balancing Servers - added command hwinfo to just print information about the Netscaler itself @@ -18,15 +24,15 @@ - added Icinga2 config templates - updated documentation and plugin_test.sh -## 1.1.1 (2017-06-10) +## v1.1.1 (2017-06-10) - bugfix for servicegroups in 12.0 (#12) - new option to connect to an alternate port (for CPX instances) -## 1.1.0 (2017-05-13) +## v1.1.0 (2017-05-13) - new check command for STA services - small documentation fixes -## 1.0.0 (2017-02-01) +## v1.0.0 (2017-02-01) - huge rewrite of the Plugin, changed nearly every parameters - upgrading from versions prior to 1.0.0 require to change your monitoring configuration - added own nitro implementation and dropped the dependency to Nitro.pm by Citrix @@ -34,17 +40,17 @@ - improved check for ssl certificates to only check for a specific certificate - fixed a bug in check_state to support services and servicegroups again -## 0.2.0 2017-01-04 +## v0.2.0 2017-01-04 - patch for Nitro.pm to support ssl connections - added check to test the validity and expiry of installed certificates -## 0.1.2 2016-12-02 +## v0.1.2 2016-12-02 - added performance data feature - updated sub add_arg and added default values for parameters - Bugfix in vserver checks loop by @macampo -## 0.1.1 2016-11-10 +## v0.1.1 2016-11-10 - documentation fixes by @Velociraptor85 -## 0.1.0 (2015-12-17) +## v0.1.0 (2015-12-17) - First release based on Nitro.pm diff --git a/README.md b/README.md index 02140ed..cee0e50 100644 --- a/README.md +++ b/README.md @@ -204,7 +204,7 @@ Multiple fields need to be seperated by a colon. The license file must be placed in `/nsconfig/license` and the filename must be given as objectname. Also the NITRO user needs permissions to access the filesystem directly (NITRO command systemfile). -Multiple fasta files can be passed, separated with a colon. +Multiple license files can be passed, separated with a colon. ``` # NetScaler::License diff --git a/check_netscaler.pl b/check_netscaler.pl index 53e6116..a41c54d 100755 --- a/check_netscaler.pl +++ b/check_netscaler.pl @@ -6,7 +6,7 @@ # # https://github.com/slauger/check_netscaler # -# Version: 1.3.0 (2017-08-13) +# Version: v1.3.0 (2017-08-13) # # Copyright 2015-2017 Simon Lauger # @@ -37,7 +37,7 @@ my $plugin = Nagios::Plugin->new( plugin => 'check_netscaler', shortname => 'NetScaler', - version => '1.3.0', + version => 'v1.3.0', url => 'https://github.com/slauger/check_netscaler', blurb => 'Nagios Plugin for Citrix NetScaler Appliance (VPX/MPX/SDX/CPX)', usage => 'Usage: %s