From c83248f44ef7c15f1f2f0a5cf77a637e5f9ffaee Mon Sep 17 00:00:00 2001 From: qgarnier Date: Thu, 22 Dec 2022 09:35:40 +0000 Subject: [PATCH] (plugin) network::vectra::restapi - new (#4116) --- .../network/vectra/restapi/custom/api.pm | 199 +++++++++++++ .../network/vectra/restapi/mode/cpu.pm | 82 ++++++ .../network/vectra/restapi/mode/disk.pm | 156 ++++++++++ .../network/vectra/restapi/mode/interfaces.pm | 139 +++++++++ .../vectra/restapi/mode/listinterfaces.pm | 107 +++++++ .../vectra/restapi/mode/listsensors.pm | 107 +++++++ .../network/vectra/restapi/mode/memory.pm | 158 ++++++++++ .../network/vectra/restapi/mode/sensors.pm | 272 ++++++++++++++++++ .../network/vectra/restapi/mode/uptime.pm | 159 ++++++++++ .../network/vectra/restapi/plugin.pm | 55 ++++ 10 files changed, 1434 insertions(+) create mode 100644 centreon-plugins/network/vectra/restapi/custom/api.pm create mode 100644 centreon-plugins/network/vectra/restapi/mode/cpu.pm create mode 100644 centreon-plugins/network/vectra/restapi/mode/disk.pm create mode 100644 centreon-plugins/network/vectra/restapi/mode/interfaces.pm create mode 100644 centreon-plugins/network/vectra/restapi/mode/listinterfaces.pm create mode 100644 centreon-plugins/network/vectra/restapi/mode/listsensors.pm create mode 100644 centreon-plugins/network/vectra/restapi/mode/memory.pm create mode 100644 centreon-plugins/network/vectra/restapi/mode/sensors.pm create mode 100644 centreon-plugins/network/vectra/restapi/mode/uptime.pm create mode 100644 centreon-plugins/network/vectra/restapi/plugin.pm diff --git a/centreon-plugins/network/vectra/restapi/custom/api.pm b/centreon-plugins/network/vectra/restapi/custom/api.pm new file mode 100644 index 000000000..1b1af4d45 --- /dev/null +++ b/centreon-plugins/network/vectra/restapi/custom/api.pm @@ -0,0 +1,199 @@ +# +# Copyright 2022 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 network::vectra::restapi::custom::api; + +use strict; +use warnings; +use centreon::plugins::http; +use JSON::XS; + +sub new { + my ($class, %options) = @_; + my $self = {}; + bless $self, $class; + + if (!defined($options{output})) { + print "Class Custom: Need to specify 'output' argument.\n"; + exit 3; + } + if (!defined($options{options})) { + $options{output}->add_option_msg(short_msg => "Class Custom: Need to specify 'options' argument."); + $options{output}->option_exit(); + } + + if (!defined($options{noptions})) { + $options{options}->add_options(arguments => { + 'token:s' => { name => 'token' }, + 'hostname:s' => { name => 'hostname' }, + 'port:s' => { name => 'port' }, + 'proto:s' => { name => 'proto' }, + 'timeout:s' => { name => 'timeout' }, + 'api-path:s' => { name => 'api_path' }, + 'unknown-http-status:s' => { name => 'unknown_http_status' }, + 'warning-http-status:s' => { name => 'warning_http_status' }, + 'critical-http-status:s' => { name => 'critical_http_status' } + }); + } + $options{options}->add_help(package => __PACKAGE__, sections => 'REST API OPTIONS', once => 1); + + $self->{output} = $options{output}; + $self->{http} = centreon::plugins::http->new(%options, default_backend => 'curl'); + + return $self; +} + +sub set_options { + my ($self, %options) = @_; + + $self->{option_results} = $options{option_results}; +} + +sub set_defaults {} + +sub check_options { + my ($self, %options) = @_; + + $self->{hostname} = (defined($self->{option_results}->{hostname})) ? $self->{option_results}->{hostname} : ''; + $self->{port} = (defined($self->{option_results}->{port})) ? $self->{option_results}->{port} : 443; + $self->{proto} = (defined($self->{option_results}->{proto})) ? $self->{option_results}->{proto} : 'https'; + $self->{timeout} = (defined($self->{option_results}->{timeout})) ? $self->{option_results}->{timeout} : 50; + $self->{token} = (defined($self->{option_results}->{token})) ? $self->{option_results}->{token} : ''; + $self->{unknown_http_status} = (defined($self->{option_results}->{unknown_http_status})) ? $self->{option_results}->{unknown_http_status} : '%{http_code} < 200 or %{http_code} >= 300'; + $self->{warning_http_status} = (defined($self->{option_results}->{warning_http_status})) ? $self->{option_results}->{warning_http_status} : ''; + $self->{critical_http_status} = (defined($self->{option_results}->{critical_http_status})) ? $self->{option_results}->{critical_http_status} : ''; + $self->{api_path} = (defined($self->{option_results}->{api_path})) ? $self->{option_results}->{api_path} : '/api/v2.2'; + + if ($self->{hostname} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --hostname option."); + $self->{output}->option_exit(); + } + if ($self->{token} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --token option."); + $self->{output}->option_exit(); + } + + return 0; +} + +sub build_options_for_httplib { + my ($self, %options) = @_; + + $self->{option_results}->{hostname} = $self->{hostname}; + $self->{option_results}->{timeout} = $self->{timeout}; + $self->{option_results}->{port} = $self->{port}; + $self->{option_results}->{proto} = $self->{proto}; + $self->{option_results}->{timeout} = $self->{timeout}; +} + +sub settings { + my ($self, %options) = @_; + + return if (defined($self->{settings_done})); + $self->build_options_for_httplib(); + $self->{http}->add_header(key => 'Accept', value => 'application/json'); + $self->{http}->set_options(%{$self->{option_results}}); + $self->{settings_done} = 1; +} + +sub get_hostname { + my ($self, %options) = @_; + + return $self->{hostname}; +} + +sub get_port { + my ($self, %options) = @_; + + return $self->{port}; +} + +sub request_api { + my ($self, %options) = @_; + + $self->settings(); + my $content = $self->{http}->request( + url_path => $self->{api_path} . $options{endpoint}, + get_param => $options{get_param}, + header => ['Authorization: Token ' . $self->{token}], + query_form_post => $options{query_form_post}, + unknown_status => $self->{unknown_http_status}, + warning_status => $self->{warning_http_status}, + critical_status => $self->{critical_http_status} + ); + + if (!defined($content) || $content eq '') { + $self->{output}->add_option_msg(short_msg => "API returns empty content [code: '" . $self->{http}->get_code() . "'] [message: '" . $self->{http}->get_message() . "']"); + $self->{output}->option_exit(); + } + + my $decoded; + eval { + $decoded = JSON::XS->new->utf8->decode($content); + }; + if ($@) { + $self->{output}->add_option_msg(short_msg => "Cannot decode response (add --debug option to display returned content)"); + $self->{output}->option_exit(); + } + + return $decoded; +} + +1; + +__END__ + +=head1 NAME + +Vectra Rest API + +=head1 REST API OPTIONS + +Vectra Rest API + +=over 8 + +=item B<--hostname> + +Set hostname. + +=item B<--port> + +Port used (Default: 443) + +=item B<--proto> + +Specify https if needed (Default: 'https') + +=item B<--token> + +API token. + +=item B<--timeout> + +Set timeout in seconds (Default: 50). + +=back + +=head1 DESCRIPTION + +B. + +=cut diff --git a/centreon-plugins/network/vectra/restapi/mode/cpu.pm b/centreon-plugins/network/vectra/restapi/mode/cpu.pm new file mode 100644 index 000000000..b658ad220 --- /dev/null +++ b/centreon-plugins/network/vectra/restapi/mode/cpu.pm @@ -0,0 +1,82 @@ +# +# Copyright 2022 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 network::vectra::restapi::mode::cpu; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'global', type => 0 } + ]; + + $self->{maps_counters}->{global} = [ + { label => 'cpu-utilization', nlabel => 'cpu.utilization.percentage', set => { + key_values => [ { name => 'cpu_util' } ], + output_template => 'Cpu utilization: %.2f%%', + perfdatas => [ + { template => '%s', min => 0, max => 100, unit => '%' } + ] + } + } + ]; +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1); + bless $self, $class; + + return $self; +} + +sub manage_selection { + my ($self, %options) = @_; + + my $result = $options{custom}->request_api(endpoint => '/health/cpu'); + + $self->{global} = { + cpu_util => 100 - $result->{cpu}->{idle_percent} + }; +} + +1; + +__END__ + +=head1 MODE + +Check cpu. + +=over 8 + +=item B<--warning-*> B<--critical-*> + +Thresholds. +Can be: 'cpu-utilization' (%). + +=back + +=cut diff --git a/centreon-plugins/network/vectra/restapi/mode/disk.pm b/centreon-plugins/network/vectra/restapi/mode/disk.pm new file mode 100644 index 000000000..c987bea42 --- /dev/null +++ b/centreon-plugins/network/vectra/restapi/mode/disk.pm @@ -0,0 +1,156 @@ +# +# Copyright 2022 Centreon (http://www.centreon.com/) +# +# Centreon is a full-fledged industry-strength solution that meets +# the needs in IT infrastructure and alarm 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 network::vectra::restapi::mode::disk; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; +use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold_ng); + +sub custom_usage_output { + my ($self, %options) = @_; + + return sprintf( + 'Disk total: %s %s used: %s %s (%.2f%%) free: %s %s (%.2f%%)', + $self->{perfdata}->change_bytes(value => $self->{result_values}->{total}), + $self->{perfdata}->change_bytes(value => $self->{result_values}->{used}), + $self->{result_values}->{prct_used}, + $self->{perfdata}->change_bytes(value => $self->{result_values}->{free}), + $self->{result_values}->{prct_free} + ); +} + +sub prefix_raid_output { + my ($self, %options) = @_; + + return "Raid '" . $options{instance_value}->{name} . "' "; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'global', type => 0, skipped_code => { -10 => 1 } }, + { name => 'raids', type => 1, cb_prefix_output => 'prefix_raid_output', message_multiple => 'All raid statuses are ok', skipped_code => { -10 => 1 } } + ]; + + $self->{maps_counters}->{global} = [ + { label => 'disk-usage', nlabel => 'disk.usage.bytes', set => { + key_values => [ { name => 'used' }, { name => 'free' }, { name => 'prct_used' }, { name => 'prct_free' }, { name => 'total' } ], + closure_custom_output => $self->can('custom_usage_output'), + perfdatas => [ + { template => '%d', min => 0, max => 'total', unit => 'B', cast_int => 1 } + ] + } + }, + { label => 'disk-usage-free', display_ok => 0, nlabel => 'disk.free.bytes', set => { + key_values => [ { name => 'free' }, { name => 'used' }, { name => 'prct_used' }, { name => 'prct_free' }, { name => 'total' } ], + closure_custom_output => $self->can('custom_usage_output'), + perfdatas => [ + { template => '%d', min => 0, max => 'total', unit => 'B', cast_int => 1 } + ] + } + }, + { label => 'disk-usage-prct', display_ok => 0, nlabel => 'disk.usage.percentage', set => { + key_values => [ { name => 'prct_used' }, { name => 'used' }, { name => 'free' }, { name => 'prct_free' }, { name => 'total' } ], + closure_custom_output => $self->can('custom_usage_output'), + perfdatas => [ + { template => '%.2f', min => 0, max => 100, unit => '%' } + ] + } + } + ]; + + $self->{maps_counters}->{raids} = [ + { label => 'raid-status', type => 2, critical_default => '%{status} !~ /ok/i', set => { + key_values => [ { name => 'status' }, { name => 'name' } ], + output_template => 'status: %s', + closure_custom_perfdata => sub { return 0; }, + closure_custom_threshold_check => \&catalog_status_threshold_ng + } + } + ]; +} + +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 => {}); + + return $self; +} + +sub manage_selection { + my ($self, %options) = @_; + + my $result = $options{custom}->request_api(endpoint => '/health/disk'); + + $self->{global} = { + total => $result->{disk}->{disk_utilization}->{total_bytes}, + used => $result->{disk}->{disk_utilization}->{used_bytes}, + free => $result->{disk}->{disk_utilization}->{free_bytes}, + prct_used => $result->{disk}->{disk_utilization}->{used_bytes} * 100 / $result->{disk}->{disk_utilization}->{total_bytes}, + prct_free => $result->{disk}->{disk_utilization}->{free_bytes} * 100 / $result->{disk}->{disk_utilization}->{total_bytes} + }; + + $self->{raids} = { + disks => { name => 'disks', status => lc($result->{disk}->{disk_raid}->{status}) }, + disks_missing => { name => 'disks_missing', status => lc($result->{disk}->{raid_disks_missing}->{status}) }, + degraded_volume => { name => 'degraded_volume', status => lc($result->{disk}->{degraded_raid_volume}->{status}) } + }; +} + +1; + +__END__ + +=head1 MODE + +Check disks. + +=over 8 + +=item B<--unknown-raid-status> + +Set warning threshold for status. +Can used special variables like: %{status}, %{name} + +=item B<--warning-raid-status> + +Set warning threshold for status. +Can used special variables like: %{status}, %{name} + +=item B<--critical-raid-status> + +Set critical threshold for status (Default: '%{status} !~ /ok/i'). +Can used special variables like: %{status}, %{name} + +=item B<--warning-*> B<--critical-*> + +Thresholds. Can be: +'disk-usage', 'disk-usage-free', 'disk-usage-prct' + +=back + +=cut diff --git a/centreon-plugins/network/vectra/restapi/mode/interfaces.pm b/centreon-plugins/network/vectra/restapi/mode/interfaces.pm new file mode 100644 index 000000000..9a1cce3fa --- /dev/null +++ b/centreon-plugins/network/vectra/restapi/mode/interfaces.pm @@ -0,0 +1,139 @@ +# +# Copyright 2022 Centreon (http://www.centreon.com/) +# +# Centreon is a full-fledged industry-strength solution that meets +# the needs in IT infrastructure and alarm 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 network::vectra::restapi::mode::interfaces; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; +use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold_ng); + +sub prefix_interface_output { + my ($self, %options) = @_; + + return "interface '" . $options{instance_value}->{name} . "' "; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'interfaces', cb_prefix_output => 'prefix_interface_output', message_multiple => 'All interfaces are ok', type => 1, skipped_code => { -10 => 1 } } + ]; + + $self->{maps_counters}->{interfaces} = [ + { label => 'interface-status', type => 2, critical_default => '%{status} =~ /down/i', set => { + key_values => [ { name => 'status' }, { name => 'name' } ], + output_template => 'status: %s', + closure_custom_perfdata => sub { return 0; }, + closure_custom_threshold_check => \&catalog_status_threshold_ng + } + }, + { label => 'interface-peak-traffic', nlabel => 'interface.traffic.peak.bitspersecond', set => { + key_values => [ { name => 'peakTraffic' }, { name => 'name' } ], + output_template => 'peak traffic: %s %s/s', + output_change_bytes => 2, + closure_custom_perfdata => sub { + my ($self, %options) = @_; + + $self->{output}->perfdata_add( + nlabel => $self->{nlabel}, + unit => 'b/s', + instances => $self->{result_values}->{name}, + value => $self->{result_values}->{peakTraffic}, + warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{thlabel}), + critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{thlabel}), + min => 0 + ); + } + } + } + ]; +} + +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 => { + 'filter-interface-name:s' => { name => 'filter_interface_name' } + }); + + return $self; +} + +sub manage_selection { + my ($self, %options) = @_; + + my $result = $options{custom}->request_api(endpoint => '/health/network'); + + $self->{interfaces} = {}; + foreach my $interface_name (keys %{$result->{network}->{interfaces}->{brain}}) { + $self->{interfaces}->{$interface_name} = { + name => $interface_name, + status => lc($result->{network}->{interfaces}->{brain}->{$interface_name}->{link}) + }; + + if (defined($result->{network}->{traffic}->{brain}->{interface_peak_traffic}->{$interface_name})) { + $self->{interfaces}->{$interface_name}->{peakTraffic} = + $result->{network}->{traffic}->{brain}->{interface_peak_traffic}->{$interface_name}->{peak_traffic_mbps} * 1000 * 1000; + } + } +} + +1; + +__END__ + +=head1 MODE + +Check interfaces. + +=over 8 + +=item B<--filter-interface-name> + +Filter interfaces by name (can be a regexp). + +=item B<--unknown-interface-status> + +Set warning threshold for status. +Can used special variables like: %{status}, %{name} + +=item B<--warning-interface-status> + +Set warning threshold for status. +Can used special variables like: %{status}, %{name} + +=item B<--critical-interface-status> + +Set critical threshold for status (Default: '%{status} =~ /down/i'). +Can used special variables like: %{status}, %{name} + +=item B<--warning-*> B<--critical-*> + +Thresholds. Can be: +'interface-peak-traffic'. + +=back + +=cut diff --git a/centreon-plugins/network/vectra/restapi/mode/listinterfaces.pm b/centreon-plugins/network/vectra/restapi/mode/listinterfaces.pm new file mode 100644 index 000000000..e8c50dba3 --- /dev/null +++ b/centreon-plugins/network/vectra/restapi/mode/listinterfaces.pm @@ -0,0 +1,107 @@ +# +# Copyright 2022 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 network::vectra::restapi::mode::listinterfaces; + +use base qw(centreon::plugins::mode); + +use strict; +use warnings; + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $options{options}->add_options(arguments => {}); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::init(%options); +} + +my @labels = ('name', 'status'); + +sub manage_selection { + my ($self, %options) = @_; + + my $network = $options{custom}->request_api(endpoint => '/health/network'); + + my $results = {}; + foreach my $interface_name (keys %{$network->{network}->{interfaces}->{brain}}) { + $results->{ $interface_name } = { + name => $interface_name, + status => lc($network->{network}->{interfaces}->{brain}->{$interface_name}->{link}) + }; + } + + return $results; +} + +sub run { + my ($self, %options) = @_; + + my $results = $self->manage_selection(custom => $options{custom}); + foreach my $instance (sort keys %$results) { + $self->{output}->output_add(long_msg => + join('', map("[$_: " . $results->{$instance}->{$_} . ']', @labels)) + ); + } + + $self->{output}->output_add( + severity => 'OK', + short_msg => 'List interfaces:' + ); + $self->{output}->display(nolabel => 1, force_ignore_perfdata => 1, force_long_output => 1); + $self->{output}->exit(); +} + +sub disco_format { + my ($self, %options) = @_; + + $self->{output}->add_disco_format(elements => [@labels]); +} + +sub disco_show { + my ($self, %options) = @_; + + my $results = $self->manage_selection(custom => $options{custom}); + foreach (sort keys %$results) { + $self->{output}->add_disco_entry( + %{$results->{$_}} + ); + } +} +1; + +__END__ + +=head1 MODE + +List interfaces. + +=over 8 + +=back + +=cut diff --git a/centreon-plugins/network/vectra/restapi/mode/listsensors.pm b/centreon-plugins/network/vectra/restapi/mode/listsensors.pm new file mode 100644 index 000000000..8eb8df48b --- /dev/null +++ b/centreon-plugins/network/vectra/restapi/mode/listsensors.pm @@ -0,0 +1,107 @@ +# +# Copyright 2022 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 network::vectra::restapi::mode::listsensors; + +use base qw(centreon::plugins::mode); + +use strict; +use warnings; + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $options{options}->add_options(arguments => {}); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::init(%options); +} + +my @labels = ('name', 'status'); + +sub manage_selection { + my ($self, %options) = @_; + + my $sensors = $options{custom}->request_api(endpoint => '/health/sensors'); + + my $results = {}; + foreach (@{$sensors->{sensors}}) { + $results->{ $_->{name} } = { + name => $_->{name}, + status => lc($_->{status}) + }; + } + + return $results; +} + +sub run { + my ($self, %options) = @_; + + my $results = $self->manage_selection(custom => $options{custom}); + foreach my $instance (sort keys %$results) { + $self->{output}->output_add(long_msg => + join('', map("[$_: " . $results->{$instance}->{$_} . ']', @labels)) + ); + } + + $self->{output}->output_add( + severity => 'OK', + short_msg => 'List sensors:' + ); + $self->{output}->display(nolabel => 1, force_ignore_perfdata => 1, force_long_output => 1); + $self->{output}->exit(); +} + +sub disco_format { + my ($self, %options) = @_; + + $self->{output}->add_disco_format(elements => [@labels]); +} + +sub disco_show { + my ($self, %options) = @_; + + my $results = $self->manage_selection(custom => $options{custom}); + foreach (sort keys %$results) { + $self->{output}->add_disco_entry( + %{$results->{$_}} + ); + } +} +1; + +__END__ + +=head1 MODE + +List sensors. + +=over 8 + +=back + +=cut diff --git a/centreon-plugins/network/vectra/restapi/mode/memory.pm b/centreon-plugins/network/vectra/restapi/mode/memory.pm new file mode 100644 index 000000000..4358c2b01 --- /dev/null +++ b/centreon-plugins/network/vectra/restapi/mode/memory.pm @@ -0,0 +1,158 @@ +# +# Copyright 2022 Centreon (http://www.centreon.com/) +# +# Centreon is a full-fledged industry-strength solution that meets +# the needs in IT infrastructure and alarm 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 network::vectra::restapi::mode::memory; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; +use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold_ng); + +sub custom_usage_output { + my ($self, %options) = @_; + + return sprintf( + 'Ram total: %s %s used: %s %s (%.2f%%) free: %s %s (%.2f%%)', + $self->{perfdata}->change_bytes(value => $self->{result_values}->{total}), + $self->{perfdata}->change_bytes(value => $self->{result_values}->{used}), + $self->{result_values}->{prct_used}, + $self->{perfdata}->change_bytes(value => $self->{result_values}->{free}), + $self->{result_values}->{prct_free} + ); +} + +sub prefix_dimm_output { + my ($self, %options) = @_; + + return "Dimm '" . $options{instance_value}->{name} . "' "; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'global', type => 0, skipped_code => { -10 => 1 } }, + { name => 'dimm', type => 1, cb_prefix_output => 'prefix_dimm_output', message_multiple => 'All dimm are ok', skipped_code => { -10 => 1 } } + ]; + + $self->{maps_counters}->{global} = [ + { label => 'memory-usage', nlabel => 'memory.usage.bytes', set => { + key_values => [ { name => 'used' }, { name => 'free' }, { name => 'prct_used' }, { name => 'prct_free' }, { name => 'total' } ], + closure_custom_output => $self->can('custom_usage_output'), + perfdatas => [ + { template => '%d', min => 0, max => 'total', unit => 'B', cast_int => 1 } + ] + } + }, + { label => 'memory-usage-free', display_ok => 0, nlabel => 'memory.free.bytes', set => { + key_values => [ { name => 'free' }, { name => 'used' }, { name => 'prct_used' }, { name => 'prct_free' }, { name => 'total' } ], + closure_custom_output => $self->can('custom_usage_output'), + perfdatas => [ + { template => '%d', min => 0, max => 'total', unit => 'B', cast_int => 1 } + ] + } + }, + { label => 'memory-usage-prct', display_ok => 0, nlabel => 'memory.usage.percentage', set => { + key_values => [ { name => 'prct_used' }, { name => 'used' }, { name => 'free' }, { name => 'prct_free' }, { name => 'total' } ], + closure_custom_output => $self->can('custom_usage_output'), + perfdatas => [ + { template => '%.2f', min => 0, max => 100, unit => '%' } + ] + } + } + ]; + + $self->{maps_counters}->{dimm} = [ + { label => 'dimm-status', type => 2, critical_default => '%{status} !~ /ok/i', set => { + key_values => [ { name => 'status' }, { name => 'name' } ], + output_template => 'status: %s', + closure_custom_perfdata => sub { return 0; }, + closure_custom_threshold_check => \&catalog_status_threshold_ng + } + } + ]; +} + +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 => {}); + + return $self; +} + +sub manage_selection { + my ($self, %options) = @_; + + my $result = $options{custom}->request_api(endpoint => '/health/memory'); + + $self->{global} = { + total => $result->{memory}->{total_bytes}, + used => $result->{memory}->{used_bytes}, + free => $result->{memory}->{free_bytes}, + prct_used => $result->{memory}->{used_bytes} * 100 / $result->{memory}->{total_bytes}, + prct_free => $result->{memory}->{free_bytes} * 100 / $result->{memory}->{total_bytes} + }; + + $self->{dimm} = {}; + foreach (@{$result->{memory}->{dimm_status}}) { + $self->{dimm}->{ $_->{dimm} } = { + name => $_->{dimm}, + status => lc($_->{status}) + }; + } +} + +1; + +__END__ + +=head1 MODE + +Check memory usage. + +=over 8 + +=item B<--unknown-dimm-status> + +Set warning threshold for status. +Can used special variables like: %{status}, %{name} + +=item B<--warning-dimm-status> + +Set warning threshold for status. +Can used special variables like: %{status}, %{name} + +=item B<--critical-dimm-status> + +Set critical threshold for status (Default: '%{status} !~ /ok/i'). +Can used special variables like: %{status}, %{name} + +=item B<--warning-*> B<--critical-*> + +Thresholds. Can be: +'memory-usage', 'memory-usage-free', 'memory-usage-prct' + +=back + +=cut diff --git a/centreon-plugins/network/vectra/restapi/mode/sensors.pm b/centreon-plugins/network/vectra/restapi/mode/sensors.pm new file mode 100644 index 000000000..2e08ba2d2 --- /dev/null +++ b/centreon-plugins/network/vectra/restapi/mode/sensors.pm @@ -0,0 +1,272 @@ +# +# Copyright 2022 Centreon (http://www.centreon.com/) +# +# Centreon is a full-fledged industry-strength solution that meets +# the needs in IT infrastructure and alarm 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 network::vectra::restapi::mode::sensors; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; +use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold_ng); + +sub sensor_long_output { + my ($self, %options) = @_; + + return sprintf( + "checking sensor '%s'", + $options{instance_value}->{name} + ); +} + +sub prefix_sensor_output { + my ($self, %options) = @_; + + return sprintf( + "sensor '%s' ", + $options{instance_value}->{name} + ); +} + +sub prefix_interface_output { + my ($self, %options) = @_; + + return "interface '" . $options{instance_value}->{interfaceName} . "' "; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { + name => 'sensors', type => 3, cb_prefix_output => 'prefix_sensor_output', cb_long_output => 'sensor_long_output', indent_long_output => ' ', message_multiple => 'All sensors are ok', + group => [ + { name => 'global', type => 0 }, + { name => 'interfaces', display_long => 1, cb_prefix_output => 'prefix_interface_output', + message_multiple => 'all interfaces are ok', type => 1, skipped_code => { -10 => 1 } } + ] + } + ]; + + $self->{maps_counters}->{global} = [ + { label => 'sensor-status', type => 2, critical_default => '%{status} !~ /^paired/i', set => { + key_values => [ { name => 'status' }, { name => 'name' } ], + output_template => 'status: %s', + closure_custom_perfdata => sub { return 0; }, + closure_custom_threshold_check => \&catalog_status_threshold_ng + } + }, + { label => 'trafficdrop-status', type => 2, warning_default => '%{trafficDropStatus} =~ /warning|unknown|skip/i', set => { + key_values => [ { name => 'trafficDropStatus' }, { name => 'name' } ], + output_template => 'traffic drop status: %s', + closure_custom_perfdata => sub { return 0; }, + closure_custom_threshold_check => \&catalog_status_threshold_ng + } + }, + { + label => 'connectivity-status', + type => 2, + unknown_default => '%{connectivityStatus} =~ /unknown/i', + warning_default => '%{connectivityStatus} =~ /warning/i', + critical_default => '%{connectivityStatus} =~ /critical/i', + set => { + key_values => [ { name => 'connectivityStatus' }, { name => 'name' } ], + output_template => 'connectivity status: %s', + closure_custom_perfdata => sub { return 0; }, + closure_custom_threshold_check => \&catalog_status_threshold_ng + } + } + ]; + + $self->{maps_counters}->{interfaces} = [ + { label => 'interface-status', type => 2, critical_default => '%{status} =~ /down/i', set => { + key_values => [ { name => 'status' }, { name => 'interfaceName' }, { name => 'sensorName' } ], + output_template => 'status: %s', + closure_custom_perfdata => sub { return 0; }, + closure_custom_threshold_check => \&catalog_status_threshold_ng + } + }, + { label => 'interface-peak-traffic', nlabel => 'interface.traffic.peak.bitspersecond', set => { + key_values => [ { name => 'peakTraffic' }, { name => 'interfaceName' }, { name => 'sensorName' } ], + output_template => 'peak traffic: %s %s/s', + output_change_bytes => 2, + closure_custom_perfdata => sub { + my ($self, %options) = @_; + + $self->{output}->perfdata_add( + nlabel => $self->{nlabel}, + unit => 'b/s', + instances => [$self->{result_values}->{sensorName}, $self->{result_values}->{interfaceName}], + value => $self->{result_values}->{peakTraffic}, + warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{thlabel}), + critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{thlabel}), + min => 0 + ); + } + } + } + ]; +} + +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 => { + 'filter-sensor-name:s' => { name => 'filter_sensor_name' } + }); + + return $self; +} + +sub manage_selection { + my ($self, %options) = @_; + + my $result = $options{custom}->request_api(endpoint => '/health/sensors'); + + $self->{sensors} = {}; + foreach (@{$result->{sensors}}) { + next if (defined($self->{option_results}->{filter_sensor_name}) && $self->{option_results}->{filter_sensor_name} ne '' && + $_->{name} !~ /$self->{option_results}->{filter_sensor_name}/); + + $self->{sensors}->{ $_->{luid} } = { + name => $_->{name}, + global => { name => $_->{name}, status => lc($_->{status}) }, + interfaces => {} + }; + } + + $result = $options{custom}->request_api(endpoint => '/health/trafficdrop'); + foreach (@{$result->{trafficdrop}->{sensors}}) { + next if (!defined($self->{sensors}->{ $_->{luid} })); + + $self->{sensors}->{ $_->{luid} }->{global}->{trafficDropStatus} = lc($_->{status}); + } + + $result = $options{custom}->request_api(endpoint => '/health/connectivity'); + foreach (@{$result->{connectivity}->{sensors}}) { + next if (!defined($self->{sensors}->{ $_->{luid} })); + + $self->{sensors}->{ $_->{luid} }->{global}->{connectivityStatus} = lc($_->{status}); + } + + $result = $options{custom}->request_api(endpoint => '/health/network'); + foreach my $luid (keys %{$result->{network}->{interfaces}->{sensors}}) { + next if (!defined($self->{sensors}->{$luid})); + + foreach my $interface_name (keys %{$result->{network}->{interfaces}->{sensors}->{$luid}}) { + $self->{sensors}->{$luid}->{interfaces}->{$interface_name} = { + interfaceName => $interface_name, + sensorName => $self->{sensors}->{$luid}->{name}, + status => lc($result->{network}->{interfaces}->{sensors}->{$luid}->{$interface_name}->{link}) + }; + } + + if (defined($result->{network}->{traffic}->{sensors}->{ $self->{sensors}->{$luid}->{name} })) { + foreach my $interface_name (keys %{$result->{network}->{traffic}->{sensors}->{ $self->{sensors}->{$luid}->{name} }->{interface_peak_traffic}}) { + $self->{sensors}->{$luid}->{interfaces}->{$interface_name}->{peakTraffic} = + $result->{network}->{traffic}->{sensors}->{ $self->{sensors}->{$luid}->{name} }->{interface_peak_traffic}->{$interface_name}->{peak_traffic_mbps} * 1000 * 1000; + } + } + } +} + +1; + +__END__ + +=head1 MODE + +Check sensors. + +=over 8 + +=item B<--filter-sensor-name> + +Filter sensors by name (can be a regexp). + +=item B<--unknown-sensor-status> + +Set warning threshold for status. +Can used special variables like: %{status}, %{name} + +=item B<--warning-sensor-status> + +Set warning threshold for status. +Can used special variables like: %{status}, %{name} + +=item B<--critical-sensor-status> + +Set critical threshold for status (Default: '%{status} !~ /^paired/i'). +Can used special variables like: %{status}, %{name} + +=item B<--unknown-trafficdrop-status> + +Set warning threshold for status. +Can used special variables like: %{trafficDropStatus}, %{name} + +=item B<--warning-trafficdrop-status> + +Set warning threshold for status (Default: '%{trafficDropStatus} =~ /warning|unknown|skip/i'). +Can used special variables like: %{trafficDropStatus}, %{name} + +=item B<--critical-trafficdrop-status> + +Set critical threshold for status. +Can used special variables like: %{trafficDropStatus}, %{name} + +=item B<--unknown-connectivity-status> + +Set warning threshold for status (Default: '%{connectivityStatus} =~ /unknown/i'). +Can used special variables like: %{connectivityStatus}, %{name} + +=item B<--warning-connectivity-status> + +Set warning threshold for status (Default: '%{connectivityStatus} =~ /warning/i'). +Can used special variables like: %{connectivityStatus}, %{name} + +=item B<--critical-connectivity-status> + +Set critical threshold for status (Default: '%{connectivityStatus} =~ /critical/i'). +Can used special variables like: %{connectivityStatus}, %{name} + +=item B<--unknown-interface-status> + +Set warning threshold for status. +Can used special variables like: %{status}, %{interfaceName}, %{sensorName} + +=item B<--warning-interface-status> + +Set warning threshold for status. +Can used special variables like: %{status}, %{interfaceName}, %{sensorName} + +=item B<--critical-interface-status> + +Set critical threshold for status (Default: '%{status} =~ /down/i'). +Can used special variables like: %{status}, %{interfaceName}, %{sensorName} + +=item B<--warning-*> B<--critical-*> + +Thresholds. Can be: +'interface-peak-traffic'. + +=back + +=cut diff --git a/centreon-plugins/network/vectra/restapi/mode/uptime.pm b/centreon-plugins/network/vectra/restapi/mode/uptime.pm new file mode 100644 index 000000000..b51f5404c --- /dev/null +++ b/centreon-plugins/network/vectra/restapi/mode/uptime.pm @@ -0,0 +1,159 @@ +# +# Copyright 2022 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 network::vectra::restapi::mode::uptime; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; +use DateTime; +use POSIX; +use centreon::plugins::misc; + +my $unitdiv = { s => 1, w => 604800, d => 86400, h => 3600, m => 60 }; +my $unitdiv_long = { s => 'seconds', w => 'weeks', d => 'days', h => 'hours', m => 'minutes' }; + +sub custom_uptime_output { + my ($self, %options) = @_; + + return sprintf( + 'uptime is: %s', + centreon::plugins::misc::change_seconds(value => $self->{result_values}->{uptime}, start => 'd') + ); +} + +sub custom_uptime_perfdata { + my ($self, %options) = @_; + + $self->{output}->perfdata_add( + nlabel => 'system.uptime.' . $unitdiv_long->{ $self->{instance_mode}->{option_results}->{unit} }, + unit => $self->{instance_mode}->{option_results}->{unit}, + value => floor($self->{result_values}->{uptime} / $unitdiv->{ $self->{instance_mode}->{option_results}->{unit} }), + warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{thlabel}), + critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{thlabel}), + min => 0 + ); +} + +sub custom_uptime_threshold { + my ($self, %options) = @_; + + return $self->{perfdata}->threshold_check( + value => floor($self->{result_values}->{uptime} / $unitdiv->{ $self->{instance_mode}->{option_results}->{unit} }), + threshold => [ + { label => 'critical-' . $self->{thlabel}, exit_litteral => 'critical' }, + { label => 'warning-'. $self->{thlabel}, exit_litteral => 'warning' }, + { label => 'unknown-'. $self->{thlabel}, exit_litteral => 'unknown' } + ] + ); +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'global', type => 0 } + ]; + + $self->{maps_counters}->{global} = [ + { label => 'uptime', set => { + key_values => [ { name => 'uptime' } ], + closure_custom_output => $self->can('custom_uptime_output'), + closure_custom_perfdata => $self->can('custom_uptime_perfdata'), + closure_custom_threshold_check => $self->can('custom_uptime_threshold') + } + } + ]; +} + +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 => { + 'add-system-info' => { name => 'add_system_info' }, + 'unit:s' => { name => 'unit', default => 's' } + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + if ($self->{option_results}->{unit} eq '' || !defined($unitdiv->{$self->{option_results}->{unit}})) { + $self->{option_results}->{unit} = 's'; + } +} + +sub manage_selection { + my ($self, %options) = @_; + + my $system = $options{custom}->request_api(endpoint => '/health/system'); + + my ($day, $hour, $min) = (0, 0, 0); + $day = $1 if ($system->{system}->{uptime} =~ /(\d+)\s+day/); + $hour = $1 if ($system->{system}->{uptime} =~ /(\d+)\s+hour/); + $min = $1 if ($system->{system}->{uptime} =~ /(\d+)\s+minute/); + + $self->{global} = { + uptime => ($day * 86400) + ($hour * 3600) + ($min * 60) + }; + + if (defined($self->{option_results}->{add_system_info})) { + $self->{output}->output_add(short_msg => sprintf( + 'model: %s, firmware: %s', + $system->{system}->{version}->{model}, + $system->{system}->{version}->{vectra_version} + ) + ); + } +} + +1; + +__END__ + +=head1 MODE + +Check uptime. + +=over 8 + +=item B<--add-system-info> + +Display model and firmware informations + +=item B<--unit> + +Select the unit for performance data and thresholds. May be 's' for seconds, 'm' for minutes, +'h' for hours, 'd' for days, 'w' for weeks. Default is seconds + +=item B<--warning-*> B<--critical-*> + +Thresholds. +Can be: 'uptime'. + +=back + +=cut diff --git a/centreon-plugins/network/vectra/restapi/plugin.pm b/centreon-plugins/network/vectra/restapi/plugin.pm new file mode 100644 index 000000000..b4b9f9c9d --- /dev/null +++ b/centreon-plugins/network/vectra/restapi/plugin.pm @@ -0,0 +1,55 @@ +# +# Copyright 2022 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 network::vectra::restapi::plugin; + +use strict; +use warnings; +use base qw(centreon::plugins::script_custom); + +sub new { + my ( $class, %options ) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $self->{modes} = { + 'cpu' => 'network::vectra::restapi::mode::cpu', + 'disk' => 'network::vectra::restapi::mode::disk', + 'interfaces' => 'network::vectra::restapi::mode::interfaces', + 'list-interfaces' => 'network::vectra::restapi::mode::listinterfaces', + 'list-sensors' => 'network::vectra::restapi::mode::listsensors', + 'memory' => 'network::vectra::restapi::mode::memory', + 'sensors' => 'network::vectra::restapi::mode::sensors', + 'uptime' => 'network::vectra::restapi::mode::uptime' + }; + + $self->{custom_modes}->{api} = 'network::vectra::restapi::custom::api'; + return $self; +} + +1; + +__END__ + +=head1 PLUGIN DESCRIPTION + +Check Vectra devices using Rest API. + +=cut