From e2d66391c6e25b0bd0535a4fbc611ca8d26fadaf Mon Sep 17 00:00:00 2001 From: UrBnW <40244829+UrBnW@users.noreply.github.com> Date: Thu, 19 May 2022 08:36:49 +0200 Subject: [PATCH] (plugin) apps::protocols::tcp - change responsetime mode and create mode connectionstatus (#2709) --- .../protocols/tcp/mode/connectionstatus.pm | 204 ++++++++++++++++++ .../apps/protocols/tcp/mode/responsetime.pm | 169 +++++++-------- centreon-plugins/apps/protocols/tcp/plugin.pm | 3 +- 3 files changed, 279 insertions(+), 97 deletions(-) create mode 100644 centreon-plugins/apps/protocols/tcp/mode/connectionstatus.pm diff --git a/centreon-plugins/apps/protocols/tcp/mode/connectionstatus.pm b/centreon-plugins/apps/protocols/tcp/mode/connectionstatus.pm new file mode 100644 index 000000000..e5a440823 --- /dev/null +++ b/centreon-plugins/apps/protocols/tcp/mode/connectionstatus.pm @@ -0,0 +1,204 @@ +# +# Copyright 2021 Centreon (http://www.centreon.com/) +# +# Centreon is a full-fledged industry-strength solution that meets +# the needs in IT infrastructure and application monitoring for +# service performance. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +package apps::protocols::tcp::mode::connectionstatus; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; +use Time::HiRes qw(gettimeofday tv_interval); +use IO::Socket::SSL; +use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold_ng); + +sub custom_status_output { + my ($self, %options) = @_; + + my $msg = sprintf( + 'Connection status on port %s is %s', + $self->{result_values}->{port}, + $self->{result_values}->{status} + ); + if ($self->{result_values}->{status} ne 'ok') { + $msg .= ': ' . $self->{result_values}->{error_message}; + } + return $msg; +} + +sub custom_time_output { + my ($self, %options) = @_; + + return sprintf( + "Response time on port %s is %.3fs", + $self->{result_values}->{port}, + $self->{result_values}->{response_time} + ); +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'global', type => 0 } + ]; + + $self->{maps_counters}->{global} = [ + { label => 'status', type => 2, critical_default => '%{status} eq "failed"', display_ok => 0, set => { + key_values => [ { name => 'status' }, { name => 'port' }, { name => 'error_message' } ], + closure_custom_output => $self->can('custom_status_output'), + closure_custom_perfdata => sub { return 0; }, + closure_custom_threshold_check => \&catalog_status_threshold_ng + } + }, + { label => 'time', nlabel => 'tcp.response.time.seconds', set => { + key_values => [ { name => 'response_time' }, { name => 'port' } ], + closure_custom_output => $self->can('custom_time_output'), + perfdatas => [ + { template => '%s', min => 0, unit => 's' } + ] + } + } + ]; +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1); + bless $self, $class; + + $options{options}->add_options(arguments => { + 'hostname:s' => { name => 'hostname' }, + 'port:s' => { name => 'port', }, + 'warning:s' => { name => 'warning', redirect => 'warning-tcp-response-time-seconds' }, + 'critical:s' => { name => 'critical', redirect => 'critical-tcp-response-time-seconds' }, + 'timeout:s' => { name => 'timeout', default => 3 }, + 'ssl' => { name => 'ssl' } + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + if (!defined($self->{option_results}->{hostname})) { + $self->{output}->add_option_msg(short_msg => 'Please set the hostname option'); + $self->{output}->option_exit(); + } + if (!defined($self->{option_results}->{port})) { + $self->{output}->add_option_msg(short_msg => 'Please set the port option'); + $self->{output}->option_exit(); + } +} + +sub manage_selection { + my ($self, %options) = @_; + + my $connection; + my $timing0 = [gettimeofday]; + if (defined($self->{option_results}->{ssl})) { + $connection = IO::Socket::SSL->new( + PeerAddr => $self->{option_results}->{hostname}, + PeerPort => $self->{option_results}->{port}, + Timeout => $self->{option_results}->{timeout}, + ); + } else { + $connection = IO::Socket::INET->new( + PeerAddr => $self->{option_results}->{hostname}, + PeerPort => $self->{option_results}->{port}, + Timeout => $self->{option_results}->{timeout}, + ); + } + + my $timeelapsed = tv_interval($timing0, [gettimeofday]); + $self->{global} = { + port => $self->{option_results}->{port}, + status => 'ok', + response_time => $timeelapsed, + error_message => '' + }; + + if (!defined($connection)) { + $self->{global}->{status} = 'failed'; + my $append = ''; + if (defined($!) && $! ne '') { + $self->{global}->{error_message} = "error=$!"; + $append = ', '; + } + $self->{global}->{error_message} .= "${append}ssl_error=$SSL_ERROR" if (defined($SSL_ERROR)); + } + + close($connection) if (defined($connection)); +} + +1; + +__END__ + +=head1 MODE + +Check TCP connection status + +=over 8 + +=item B<--hostname> + +IP Addr/FQDN of the host + +=item B<--port> + +Port used + +=item B<--ssl> + +Use SSL connection. +(no attempt is made to check the certificate validity by default). + +=item B<--timeout> + +Connection timeout in seconds (Default: 3) + +=item B<--unknown-status> + +Set unknown threshold for status. +Can used special variables like: %{status}, %{port}, %{error_message} + +=item B<--warning-status> + +Set warning threshold for status. +Can used special variables like: %{status}, %{port}, %{error_message} + +=item B<--critical-status> + +Set critical threshold for status (Default: '%{status} eq "failed"'). +Can used special variables like: %{status}, %{port}, %{error_message} + +=item B<--warning-time> + +Threshold warning in seconds + +=item B<--critical-time> + +Threshold critical in seconds + +=back + +=cut diff --git a/centreon-plugins/apps/protocols/tcp/mode/responsetime.pm b/centreon-plugins/apps/protocols/tcp/mode/responsetime.pm index 26d3f969a..14408dba6 100644 --- a/centreon-plugins/apps/protocols/tcp/mode/responsetime.pm +++ b/centreon-plugins/apps/protocols/tcp/mode/responsetime.pm @@ -25,53 +25,49 @@ use base qw(centreon::plugins::templates::counter); use strict; use warnings; use Time::HiRes qw(gettimeofday tv_interval); -use IO::Socket::SSL; -use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold_ng); +use IO::Socket::INET; -sub custom_status_output { +sub prefix_output { my ($self, %options) = @_; - my $msg = sprintf( - 'Connection status on port %s is %s', - $self->{result_values}->{port}, - $self->{result_values}->{status} - ); - if ($self->{result_values}->{status} ne 'ok') { - $msg .= ': ' . $self->{result_values}->{error_message}; - } - return $msg; -} - -sub custom_time_output { - my ($self, %options) = @_; - - return sprintf( - "Response time on port %s is %.3fs", - $self->{result_values}->{port}, - $self->{result_values}->{response_time} - ); + return 'TCP port ' . $self->{option_results}->{port} . ' '; } sub set_counters { my ($self, %options) = @_; - + $self->{maps_counters_type} = [ - { name => 'global', type => 0 } + { name => 'global', type => 0, cb_prefix_output => 'prefix_output' } ]; $self->{maps_counters}->{global} = [ - { label => 'status', type => 2, critical_default => '%{status} eq "failed"', display_ok => 0, set => { - key_values => [ { name => 'status' }, { name => 'port' }, { name => 'error_message' } ], - closure_custom_output => $self->can('custom_status_output'), - closure_custom_perfdata => sub { return 0; }, - closure_custom_threshold_check => \&catalog_status_threshold_ng + { label => 'rta', nlabel => 'roundtrip.time.average.milliseconds', set => { + key_values => [ { name => 'rta' } ], + output_template => 'rta %.3fms', + perfdatas => [ + { label => 'rta', template => '%.3f', min => 0, unit => 'ms' } + ] } }, - { label => 'time', nlabel => 'tcp.response.time.seconds', set => { - key_values => [ { name => 'response_time' }, { name => 'port' } ], - closure_custom_output => $self->can('custom_time_output'), + { label => 'rtmax', nlabel => 'roundtrip.time.maximum.milliseconds', display_ok => 0, set => { + key_values => [ { name => 'rtmax' } ], perfdatas => [ - { template => '%s', min => 0, unit => 's' } + { label => 'rtmax', template => '%.3f', min => 0, unit => 'ms' } + ] + } + }, + { label => 'rtmin', nlabel => 'roundtrip.time.minimum.milliseconds', display_ok => 0, set => { + key_values => [ { name => 'rtmin' } ], + perfdatas => [ + { label => 'rtmin', template => '%.3f', min => 0, unit => 'ms' } + ] + } + }, + { label => 'pl', nlabel => 'packets.loss.percentage', set => { + key_values => [ { name => 'pl' } ], + output_template => 'lost %s%%', + perfdatas => [ + { label => 'pl', template => '%s', min => 0, max => 100, unit => '%' } ] } } @@ -80,16 +76,14 @@ sub set_counters { sub new { my ($class, %options) = @_; - my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1); + my $self = $class->SUPER::new(package => __PACKAGE__, %options); bless $self, $class; $options{options}->add_options(arguments => { 'hostname:s' => { name => 'hostname' }, - 'port:s' => { name => 'port', }, - 'warning:s' => { name => 'warning', redirect => 'warning-tcp-response-time-seconds' }, - 'critical:s' => { name => 'critical', redirect => 'critical-tcp-response-time-seconds' }, - 'timeout:s' => { name => 'timeout', default => 3 }, - 'ssl' => { name => 'ssl' } + 'port:s' => { name => 'port' }, + 'timeout:s' => { name => 'timeout', default => 5}, + 'packets:s' => { name => 'packets', default => 5} }); return $self; @@ -99,11 +93,7 @@ sub check_options { my ($self, %options) = @_; $self->SUPER::check_options(%options); - if (!defined($self->{option_results}->{hostname})) { - $self->{output}->add_option_msg(short_msg => 'Please set the hostname option'); - $self->{output}->option_exit(); - } - if (!defined($self->{option_results}->{port})) { + if (!length($self->{option_results}->{port})) { $self->{output}->add_option_msg(short_msg => 'Please set the port option'); $self->{output}->option_exit(); } @@ -111,93 +101,80 @@ sub check_options { sub manage_selection { my ($self, %options) = @_; - - my $connection; - my $timing0 = [gettimeofday]; - if (defined($self->{option_results}->{ssl})) { - $connection = IO::Socket::SSL->new( + + my $total_time_elapsed = 0; + my $max_time_elapsed = 0; + my $min_time_elapsed = 0; + my $total_packet_lost = 0; + for (my $i = 0; $i < $self->{option_results}->{packets}; $i++) { + my $timing0 = [gettimeofday]; + my $return = IO::Socket::INET->new( PeerAddr => $self->{option_results}->{hostname}, PeerPort => $self->{option_results}->{port}, - Timeout => $self->{option_results}->{timeout}, + Timeout => $self->{option_results}->{timeout} ); - } else { - $connection = IO::Socket::INET->new( - PeerAddr => $self->{option_results}->{hostname}, - PeerPort => $self->{option_results}->{port}, - Timeout => $self->{option_results}->{timeout}, - ); - } + my $timeelapsed = tv_interval($timing0, [gettimeofday]); - my $timeelapsed = tv_interval($timing0, [gettimeofday]); - $self->{global} = { - port => $self->{option_results}->{port}, - status => 'ok', - response_time => $timeelapsed, - error_message => '' - }; - - if (!defined($connection)) { - $self->{global}->{status} = 'failed'; - my $append = ''; - if (defined($!) && $! ne '') { - $self->{global}->{error_message} = "error=$!"; - $append = ', '; + if (!defined($return)) { + $total_packet_lost++; + } else { + $total_time_elapsed += $timeelapsed; + $max_time_elapsed = $timeelapsed if ($timeelapsed > $max_time_elapsed); + $min_time_elapsed = $timeelapsed if ($timeelapsed < $min_time_elapsed || $min_time_elapsed == 0); + close($return); } - $self->{global}->{error_message} .= "${append}ssl_error=$SSL_ERROR" if (defined($SSL_ERROR)); } - close($connection) if (defined($connection)); + $self->{global} = { + rta => ($self->{option_results}->{packets} > $total_packet_lost) ? $total_time_elapsed * 1000 / ($self->{option_results}->{packets} - $total_packet_lost) : 0, + rtmax => $max_time_elapsed * 1000, + rtmin => $min_time_elapsed * 1000, + pl => int($total_packet_lost * 100 / $self->{option_results}->{packets}) + }; } - + 1; __END__ =head1 MODE -Check TCP connection time +Check TCP port response time. =over 8 -=item B<--hostname> +=item B<--filter-counters> -IP Addr/FQDN of the host +Only display some counters (regexp can be used). +Example : --filter-counters='rta' =item B<--port> Port used -=item B<--ssl> - -Use SSL connection. -(no attempt is made to check the certificate validity by default). - =item B<--timeout> -Connection timeout in seconds (Default: 3) +Set timeout in seconds (Default: 5). -=item B<--unknown-status> +=item B<--packets> -Set unknown threshold for status. -Can used special variables like: %{status}, %{port}, %{error_message} +Number of packets to send (Default: 5). -=item B<--warning-status> +=item B<--warning-rta> -Set warning threshold for status. -Can used special variables like: %{status}, %{port}, %{error_message} +Response time threshold warning in milliseconds -=item B<--critical-status> +=item B<--critical-rta> -Set critical threshold for status (Default: '%{status} eq "failed"'). -Can used special variables like: %{status}, %{port}, %{error_message} +Response time threshold critical in milliseconds -=item B<--warning-time> +=item B<--warning-pl> -Threshold warning in seconds +Packets lost threshold warning in % -=item B<--critical-time> +=item B<--critical-pl> -Threshold critical in seconds +Packets lost threshold critical in % =back diff --git a/centreon-plugins/apps/protocols/tcp/plugin.pm b/centreon-plugins/apps/protocols/tcp/plugin.pm index 4b7e37cec..afbcf40c9 100644 --- a/centreon-plugins/apps/protocols/tcp/plugin.pm +++ b/centreon-plugins/apps/protocols/tcp/plugin.pm @@ -31,7 +31,8 @@ sub new { $self->{version} = '0.1'; %{$self->{modes}} = ( - 'response-time' => 'apps::protocols::tcp::mode::responsetime', + 'connection-status' => 'apps::protocols::tcp::mode::connectionstatus', + 'response-time' => 'apps::protocols::tcp::mode::responsetime' ); return $self;