diff --git a/centreon-plugins/apps/monitoring/nodeexporter/mode/cpu.pm b/centreon-plugins/apps/monitoring/nodeexporter/mode/cpu.pm new file mode 100644 index 000000000..3a0b90851 --- /dev/null +++ b/centreon-plugins/apps/monitoring/nodeexporter/mode/cpu.pm @@ -0,0 +1,249 @@ +# +# 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 apps::monitoring::nodeexporter::mode::cpu; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; +use Digest::MD5 qw(md5_hex); +use centreon::plugins::statefile; +use centreon::common::monitoring::openmetrics::scrape; + +sub custom_usage_calc { + my ($self, %options) = @_; + + my $delta_total = $options{new_datas}->{$self->{instance} . '_' . $options{extra_options}->{label_ref}} - $options{old_datas}->{$self->{instance} . '_' . $options{extra_options}->{label_ref} }; + $self->{result_values}->{used_delta} = 100 * $delta_total / $options{delta_time}; + $self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_display'}; + + return 0; +} + +sub custom_usage_idle_calc { + my ($self, %options) = @_; + + my $delta_total = $options{new_datas}->{node_cpu_avg_idle_avg} - $options{old_datas}->{node_cpu_avg_idle_avg}; + $self->{result_values}->{idle_avg_delta} = 100 - ( 100 * $delta_total / $options{delta_time} ); + + return 0; +} + +sub prefix_node_cpu_avg_output { + my ($self, %options) = @_; + + return $self->{node_cpu_avg}->{count} . " CPU(s) average usage is "; +} + +sub prefix_node_cpu_output { + my ($self, %options) = @_; + + return "CPU '" . $options{instance_value}->{display} . "' "; +} + + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'node_cpu_avg', type => 0, cb_prefix_output => 'prefix_node_cpu_avg_output' }, + { name => 'node_cpu', type => 1, cb_prefix_output => 'prefix_node_cpu_output', message_multiple => 'All CPU types are ok' } + ]; + + $self->{maps_counters}->{node_cpu_avg} = [ + { label => 'average', nlabel => 'cpu.utilization.percentage', set => { + key_values => [ { name => 'idle_avg', diff => 1 } , { name => 'count'} ], + closure_custom_calc => $self->can('custom_usage_idle_calc'), + output_template => '%.2f %%', + output_template => 'average usage : %.2f %%', output_use => 'idle_avg_delta', threshold_use => 'idle_avg_delta', + perfdatas => [ + { label => 'average', value => 'idle_avg_delta', template => '%.2f', + min => 0, max => 100, unit => '%' }, + ], + } + }, + ]; + + $self->{maps_counters}->{node_cpu} = [ + { + label => 'idle', nlabel => 'node.cpu.idle.utilization.percentage', set => { + key_values => [ { name => 'idle' , diff => 1 }, { name => 'display' } ], + closure_custom_calc => $self->can('custom_usage_calc'), closure_custom_calc_extra_options => { label_ref => 'idle' }, + output_template => 'idle usage : %.2f %%', output_use => 'used_delta', threshold_use => 'used_delta', + perfdatas => [ + { label => 'node_cpu_seconds_total_idle', value => 'used_delta', template => '%.2f', + min => 0, max => 100, unit => '%', label_extra_instance => 1, instance_use => 'display' }, + ], + } + }, + { + label => 'iowait', nlabel => 'node.cpu.iowait.utilization.percentage', set => { + key_values => [ { name => 'iowait', diff => 1 }, { name => 'display' } ], + closure_custom_calc => $self->can('custom_usage_calc'), closure_custom_calc_extra_options => { label_ref => 'iowait' }, + output_template => 'iowait usage : %.2f %%', output_use => 'used_delta', threshold_use => 'used_delta', + perfdatas => [ + { label => 'node_cpu_seconds_total_iowait', value => 'used_delta', template => '%.2f', + min => 0, max => 100, unit => '%', label_extra_instance => 1, instance_use => 'display' }, + ], + } + }, + { + label => 'irq', nlabel => 'node.cpu.irq.utilization.percentage', set => { + key_values => [ { name => 'irq', diff => 1 }, { name => 'display' } ], + closure_custom_calc => $self->can('custom_usage_calc'), closure_custom_calc_extra_options => { label_ref => 'irq' }, + output_template => 'irq usage : %.2f %%', output_use => 'used_delta', threshold_use => 'used_delta', + perfdatas => [ + { label => 'node_cpu_seconds_total_irq', value => 'used_delta', template => '%.2f', + min => 0, max => 100, unit => '%', label_extra_instance => 1, instance_use => 'display' }, + ], + } + }, + { + label => 'nice', nlabel => 'node.cpu.nice.utilization.percentage', set => { + key_values => [ { name => 'nice', diff => 1 }, { name => 'display' } ], + closure_custom_calc => $self->can('custom_usage_calc'), closure_custom_calc_extra_options => { label_ref => 'nice' }, + output_template => 'nice usage : %.2f %%', output_use => 'used_delta', threshold_use => 'used_delta', + perfdatas => [ + { label => 'node_cpu_seconds_total_nice', value => 'used_delta', template => '%.2f', + min => 0, max => 100, unit => '%', label_extra_instance => 1, instance_use => 'display' }, + ], + } + }, + { + label => 'softirq', nlabel => 'node.cpu.softirq.utilization.percentage', set => { + key_values => [ { name => 'softirq', diff => 1 }, { name => 'display' } ], + closure_custom_calc => $self->can('custom_usage_calc'), closure_custom_calc_extra_options => { label_ref => 'softirq' }, + output_template => 'softirq usage : %.2f %%', output_use => 'used_delta', threshold_use => 'used_delta', + perfdatas => [ + { label => 'node_cpu_seconds_total_softirq', value => 'used_delta', template => '%.2f', + min => 0, max => 100, unit => '%', label_extra_instance => 1, instance_use => 'display' }, + ], + } + }, + { + label => 'steal', nlabel => 'node.cpu.steal.utilization.percentage', set => { + key_values => [ { name => 'steal', diff => 1 }, { name => 'display' } ], + closure_custom_calc => $self->can('custom_usage_calc'), closure_custom_calc_extra_options => { label_ref => 'steal' }, + output_template => 'steal usage : %.2f %%', output_use => 'used_delta', threshold_use => 'used_delta', + perfdatas => [ + { label => 'node_cpu_seconds_total_steal', value => 'used_delta', template => '%.2f', + min => 0, max => 100, unit => '%', label_extra_instance => 1, instance_use => 'display' }, + ], + } + }, + { + label => 'system', nlabel => 'node.cpu.system.utilization.percentage', set => { + key_values => [ { name => 'system', diff => 1 }, { name => 'display' } ], + closure_custom_calc => $self->can('custom_usage_calc'), closure_custom_calc_extra_options => { label_ref => 'system' }, + output_template => 'system usage : %.2f %%', output_use => 'used_delta', threshold_use => 'used_delta', + perfdatas => [ + { label => 'node_cpu_seconds_total_system', value => 'used_delta', template => '%.2f', + min => 0, max => 100, unit => '%', label_extra_instance => 1, instance_use => 'display' }, + ], + } + }, + { + label => 'user', nlabel => 'node.cpu.user.utilization.percentage', set => { + key_values => [ { name => 'user', diff => 1 }, { name => 'display' } ], + closure_custom_calc => $self->can('custom_usage_calc'), closure_custom_calc_extra_options => { label_ref => 'user' }, + output_template => 'user usage : %.2f %%', output_use => 'used_delta', threshold_use => 'used_delta', + perfdatas => [ + { label => 'node_cpu_seconds_total_user', value => 'used_delta', template => '%.2f', + min => 0, max => 100, unit => '%', label_extra_instance => 1, instance_use => 'display' }, + ], + } + } + ]; +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options, statefile => 1, force_new_perfdata => 1); + bless $self, $class; + + $options{options}->add_options(arguments => { + }); + + return $self; +} + +sub manage_selection { + my ($self, %options) = @_; + + my $raw_metrics = centreon::common::monitoring::openmetrics::scrape::parse(%options, strip_chars => "[\"']"); + + $self->{cache_name} = 'linux_nodeexporter' . $options{custom}->get_uuid() . '_' . $self->{mode} . '_' . + (defined($self->{option_results}->{filter_counters}) ? md5_hex($self->{option_results}->{filter_counters}) : md5_hex('all')) . '_' . + (defined($self->{option_results}->{filter_channel}) ? md5_hex($self->{option_results}->{filter_channel}) : md5_hex('all')); + + $self->{node_cpu} = {}; + my $cpu_number; + my $cpu_idle; + my $avg_cpu_idle; + + foreach my $metric (keys %{$raw_metrics}) { + next if ($metric !~ /node_cpu_seconds_total/i); + + foreach my $data (@{$raw_metrics->{$metric}->{data}}) { + foreach my $cpu_index ($data->{dimensions}->{cpu}){ + $self->{node_cpu}->{$cpu_index}->{$data->{dimensions}->{mode}} = $data->{value}; + $self->{node_cpu}->{$cpu_index}->{display} = $data->{dimensions}->{cpu}; + + $cpu_idle += $data->{value} if ($data->{dimensions}->{mode} =~ /idle/i); + } + } + } + + $cpu_number = keys %{$self->{node_cpu}}; + $avg_cpu_idle = $cpu_idle / $cpu_number; + + $self->{node_cpu_avg}->{idle_avg} = $avg_cpu_idle; + $self->{node_cpu_avg}->{count} = $cpu_number; + +} + +1; + +__END__ + +=head1 MODE + +Check CPU based on node exporter metrics. + +=over 8 + +=item B<--warning-*> + +Threshold warning. + +Can be: 'average', 'idle', 'iowait', 'nice', 'irq' +'softirq', 'steal', 'system', 'user' + +=item B<--critical-*> + +Threshold critical. + +Can be: 'average', 'idle', 'iowait', 'nice', 'irq' +'softirq', 'steal', 'system', 'user' + +=back + +=cut \ No newline at end of file diff --git a/centreon-plugins/apps/monitoring/nodeexporter/mode/listinterfaces.pm b/centreon-plugins/apps/monitoring/nodeexporter/mode/listinterfaces.pm new file mode 100644 index 000000000..df413749a --- /dev/null +++ b/centreon-plugins/apps/monitoring/nodeexporter/mode/listinterfaces.pm @@ -0,0 +1,106 @@ +# +# 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 apps::monitoring::nodeexporter::mode::listinterfaces; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; +use centreon::common::monitoring::openmetrics::scrape; + +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); +} + +sub manage_selection { + my ($self, %options) = @_; + + my $raw_metrics = centreon::common::monitoring::openmetrics::scrape::parse(%options, strip_chars => "[\"']"); + + foreach my $metric (keys %{$raw_metrics}) { + next if ($metric ne "node_network_up" ); + + foreach my $data (@{$raw_metrics->{$metric}->{data}}) { + $self->{interfaces}->{$data->{dimensions}->{device}}->{name} = $data->{dimensions}->{device}; + $self->{interfaces}->{$data->{dimensions}->{device}}->{state} = ($data->{value} == 1) ? "up" : "down" ; + } + } +} + +sub run { + my ($self, %options) = @_; + + $self->manage_selection(%options); + foreach my $interface (sort keys %{$self->{interfaces}}) { + $self->{output}->output_add(long_msg => '[interface = ' . $interface . "]" . + "[state = '" . $self->{interfaces}->{$interface}->{state} . "']" + ); + } + + $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 => ['interface', 'state']); +} + +sub disco_show { + my ($self, %options) = @_; + + $self->manage_selection(%options); + foreach my $interface (sort keys %{$self->{interfaces}}) { + $self->{output}->add_disco_entry( + interface => $self->{interfaces}->{$interface}->{name}, + state => $self->{interfaces}->{$interface}->{state}, + ); + } +} + +1; + +__END__ + +=head1 MODE + +List interfaces + +=over 8 + +=back + +=cut \ No newline at end of file diff --git a/centreon-plugins/apps/monitoring/nodeexporter/mode/liststorages.pm b/centreon-plugins/apps/monitoring/nodeexporter/mode/liststorages.pm new file mode 100644 index 000000000..9b5fa4f79 --- /dev/null +++ b/centreon-plugins/apps/monitoring/nodeexporter/mode/liststorages.pm @@ -0,0 +1,106 @@ +# +# 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 apps::monitoring::nodeexporter::mode::liststorages; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; +use centreon::common::monitoring::openmetrics::scrape; + +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); +} + +sub manage_selection { + my ($self, %options) = @_; + + my $raw_metrics = centreon::common::monitoring::openmetrics::scrape::parse(%options, strip_chars => "[\"']"); + + foreach my $metric (keys %{$raw_metrics}) { + next if ($metric ne "node_filesystem_files" ); + + foreach my $data (@{$raw_metrics->{$metric}->{data}}) { + $self->{storages}->{$data->{dimensions}->{mountpoint}}->{name} = $data->{dimensions}->{mountpoint}; + $self->{storages}->{$data->{dimensions}->{mountpoint}}->{fstype} = $data->{dimensions}->{fstype}; + } + } +} + +sub run { + my ($self, %options) = @_; + + $self->manage_selection(%options); + foreach my $storage (sort keys %{$self->{storages}}) { + $self->{output}->output_add(long_msg => '[mountpoint = ' . $storage . "]" . + "[fstype = '" . $self->{storages}->{$storage}->{fstype} . "']" + ); + } + + $self->{output}->output_add(severity => 'OK', + short_msg => 'List Storages:'); + $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 => ['name', 'fstype']); +} + +sub disco_show { + my ($self, %options) = @_; + + $self->manage_selection(%options); + foreach my $storage (sort keys %{$self->{storages}}) { + $self->{output}->add_disco_entry( + name => $self->{storages}->{$storage}->{name}, + fstype => $self->{storages}->{$storage}->{fstype}, + ); + } +} + +1; + +__END__ + +=head1 MODE + +List storages + +=over 8 + +=back + +=cut \ No newline at end of file diff --git a/centreon-plugins/apps/monitoring/nodeexporter/mode/load.pm b/centreon-plugins/apps/monitoring/nodeexporter/mode/load.pm new file mode 100644 index 000000000..598d9b8a2 --- /dev/null +++ b/centreon-plugins/apps/monitoring/nodeexporter/mode/load.pm @@ -0,0 +1,119 @@ +# +# 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 apps::monitoring::nodeexporter::mode::load; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; +use centreon::common::monitoring::openmetrics::scrape; + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'load', type => 0, message_multiple => 'All nodes load are ok' }, + ]; + + $self->{maps_counters}->{load} = [ + { label => 'load1', nlabel => 'load.1minute.count', set => { + key_values => [ { name => 'node_load1' } ], + output_template => 'Load 1 minute: %.2f', + output_change_bytes => 1, + perfdatas => [ + { label => 'node_load1', value => 'node_load1', template => '%.2f', + min => 0 }, + ], + } + }, + { label => 'load5', nlabel => 'load.5minutes.count', set => { + key_values => [ { name => 'node_load5' } ], + output_template => 'Load 5 minutes: %.2f', + output_change_bytes => 1, + perfdatas => [ + { label => 'node_load5', value => 'node_load5', template => '%.2f', + min => 0 }, + ], + } + }, + { label => 'load15', nlabel => 'load.15minutes.count', set => { + key_values => [ { name => 'node_load15' } ], + output_template => 'Load 15 minutes: %.2f', + output_change_bytes => 1, + perfdatas => [ + { label => 'node_load15', value => 'node_load15', template => '%.2f', + 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 => { + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + +} + +sub manage_selection { + my ($self, %options) = @_; + + my $raw_metrics = centreon::common::monitoring::openmetrics::scrape::parse(%options, strip_chars => "[\"']"); + + foreach my $metric (keys %{$raw_metrics}) { + next if ($metric !~ /node_load1|node_load5|node_load15/i ); + + $self->{load}->{$metric} = $raw_metrics->{$metric}->{data}[0]->{value}; + } +} + +1; + +__END__ + +=head1 MODE + +Check node load based on node exporter metrics. + +=over 8 + +=item B<--warning-*> + +Threshold warning. + +Can be: 'load1', 'load5', 'load15'. + +=item B<--critical-*> + +Threshold warning. + +Can be: 'load1', 'load5', 'load15'. \ No newline at end of file diff --git a/centreon-plugins/apps/monitoring/nodeexporter/mode/memory.pm b/centreon-plugins/apps/monitoring/nodeexporter/mode/memory.pm new file mode 100644 index 000000000..434978412 --- /dev/null +++ b/centreon-plugins/apps/monitoring/nodeexporter/mode/memory.pm @@ -0,0 +1,189 @@ +# +# 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 apps::monitoring::nodeexporter::mode::memory; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; +use centreon::common::monitoring::openmetrics::scrape; + +sub custom_usage_perfdata { + my ($self, %options) = @_; + + my $label = 'used'; + my $value_perf = $self->{result_values}->{used}; + + my %total_options = (); + if ($self->{instance_mode}->{option_results}->{units} eq '%') { + $total_options{total} = $self->{result_values}->{node_memory_node_memory_MemTotal_bytes}; + $total_options{cast_int} = 1; + } + + $self->{output}->perfdata_add( + label => $label, unit => 'B', + nlabel => 'node.memory.usage.bytes', + value => $value_perf, + warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{thlabel}, %total_options), + critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{thlabel}, %total_options), + min => 0, max => $self->{result_values}->{node_memory_node_memory_MemTotal_bytes}, + ); +} + +sub custom_usage_threshold { + my ($self, %options) = @_; + + my ($exit, $threshold_value); + $threshold_value = $self->{result_values}->{used}; + if ($self->{instance_mode}->{option_results}->{units} eq '%') { + $threshold_value = $self->{result_values}->{prct_used}; + } + $exit = $self->{perfdata}->threshold_check(value => $threshold_value, + threshold => [ { label => 'critical-' . $self->{thlabel}, exit_litteral => 'critical' }, + { label => 'warning-'. $self->{thlabel}, exit_litteral => 'warning' } ]); + return $exit; +} + +sub custom_usage_output { + my ($self, %options) = @_; + + my ($total_size_value, $total_size_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{node_memory_node_memory_MemTotal_bytes}); + my ($total_used_value, $total_used_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{used}); + my $msg = sprintf("Ram Total: %s, Used (-buffers/cache): %s (%.2f%%)", + $total_size_value . " " . $total_size_unit, + $total_used_value . " " . $total_used_unit, $self->{result_values}->{prct_used}); + return $msg; +} + +sub custom_usage_calc { + my ($self, %options) = @_; + + $self->{result_values}->{node_memory_node_memory_MemTotal_bytes} = $options{new_datas}->{node_memory_node_memory_MemTotal_bytes}; + $self->{result_values}->{node_memory_node_memory_MemFree_bytes} = $options{new_datas}->{node_memory_node_memory_MemFree_bytes}; + $self->{result_values}->{node_memory_node_memory_Buffers_bytes} = $options{new_datas}->{node_memory_node_memory_Buffers_bytes}; + $self->{result_values}->{node_memory_node_memory_Cached_bytes} = $options{new_datas}->{node_memory_node_memory_Cached_bytes}; + $self->{result_values}->{used} = $self->{result_values}->{node_memory_node_memory_MemTotal_bytes} - $self->{result_values}->{node_memory_node_memory_MemFree_bytes} - $self->{result_values}->{node_memory_node_memory_Buffers_bytes} - $self->{result_values}->{node_memory_node_memory_Cached_bytes}; + $self->{result_values}->{prct_used} = ($self->{result_values}->{node_memory_node_memory_MemTotal_bytes} > 0) ? $self->{result_values}->{used} * 100 / $self->{result_values}->{node_memory_node_memory_MemTotal_bytes} : 0; + + return 0; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'node_memory', type => 0, message_multiple => 'All memory types are ok' } + ]; + + $self->{maps_counters}->{node_memory} = [ + { label => 'usage', set => { + key_values => [ { name => 'node_memory_MemTotal_bytes' }, { name => 'node_memory_MemFree_bytes' }, { name => 'node_memory_Buffers_bytes' }, { name => 'node_memory_Cached_bytes' } ], + closure_custom_calc => $self->can('custom_usage_calc'), + closure_custom_output => $self->can('custom_usage_output'), + closure_custom_perfdata => $self->can('custom_usage_perfdata'), + closure_custom_threshold_check => $self->can('custom_usage_threshold'), + } + }, + { + label => 'buffer', nlabel => 'node.memory.buffer.bytes', set => { + key_values => [ { name => 'node_memory_Buffers_bytes' } ], + output_template => 'Buffer: %.2f %s', + output_change_bytes => 1, + perfdatas => [ + { label => 'node_memory_Buffers_bytes', template => '%s', + min => 0, unit => 'B' } + ] + } + }, + { + label => 'cached', nlabel => 'node.memory.cached.bytes', set => { + key_values => [ { name => 'node_memory_Cached_bytes' } ], + output_template => 'Cached: %.2f %s', + output_change_bytes => 1, + perfdatas => [ + { label => 'node_memory_Cached_bytes', template => '%s', + min => 0, unit => 'B' } + ] + } + } + ]; +} + +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 => { + "units:s" => { name => 'units', default => '%' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + +} + +sub manage_selection { + my ($self, %options) = @_; + + my $raw_metrics = centreon::common::monitoring::openmetrics::scrape::parse(%options, strip_chars => "[\"']"); + + foreach my $metric (keys %{$raw_metrics}) { + next if ($metric !~ /node_memory_MemTotal_bytes|node_memory_MemFree_bytes|node_memory_Cached_bytes|node_memory_Buffers_bytes/i); + + $self->{node_memory}->{$metric} = $raw_metrics->{$metric}->{data}[0]->{value}; + } +} + +1; + +__END__ + +=head1 MODE + +Check memory based on node exporter metrics. + +=over 8 + +=item B<--units> + +Units of thresholds. Can be : '%', 'B' +Default: '%' + +=item B<--warning-*> + +Threshold warning. + +Can be: 'usage', 'buffer', 'cached'. + +=item B<--critical-*> + +Threshold critical. + +Can be: 'usage', 'buffer', 'cached'. + +=back + +=cut \ No newline at end of file diff --git a/centreon-plugins/apps/monitoring/nodeexporter/mode/storage.pm b/centreon-plugins/apps/monitoring/nodeexporter/mode/storage.pm new file mode 100644 index 000000000..67b0d8709 --- /dev/null +++ b/centreon-plugins/apps/monitoring/nodeexporter/mode/storage.pm @@ -0,0 +1,200 @@ +# +# 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 apps::monitoring::nodeexporter::mode::storage; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; +use centreon::common::monitoring::openmetrics::scrape; + +sub custom_usage_perfdata { + my ($self, %options) = @_; + + my $value_perf = $self->{result_values}->{used}; + + my %total_options = (); + if ($self->{instance_mode}->{option_results}->{units} eq '%') { + $total_options{total} = $self->{result_values}->{node_filesystem_size_bytes}; + $total_options{cast_int} = 1; + } + + $self->{output}->perfdata_add( + label => 'used', unit => 'B', + nlabel => 'node.storage.space.free.bytes', + value => $value_perf, + warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{thlabel}, %total_options), + critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{thlabel}, %total_options), + min => 0, max => $self->{result_values}->{node_filesystem_size_bytes}, + instances => $self->{result_values}->{display} + ); +} + +sub custom_usage_threshold { + my ($self, %options) = @_; + + my ($exit, $threshold_value); + $threshold_value = $self->{result_values}->{used}; + if ($self->{instance_mode}->{option_results}->{units} eq '%') { + $threshold_value = $self->{result_values}->{prct_used}; + $threshold_value = $self->{result_values}->{prct_free} if (defined($self->{instance_mode}->{option_results}->{free})); + } + $exit = $self->{perfdata}->threshold_check( + value => $threshold_value, + threshold => [ + { label => 'critical-' . $self->{thlabel}, exit_litteral => 'critical' }, + { label => 'warning-'. $self->{thlabel}, exit_litteral => 'warning' } + ] + ); + return $exit; +} + +sub custom_usage_output { + my ($self, %options) = @_; + + my ($total_size_value, $total_size_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{node_filesystem_size_bytes}); + my ($total_used_value, $total_used_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{used}); + my ($total_free_value, $total_free_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{node_filesystem_free_bytes}); + return sprintf( + "Usage Total: %s Used: %s (%.2f%%) Free: %s (%.2f%%)", + $total_size_value . " " . $total_size_unit, + $total_used_value . " " . $total_used_unit, $self->{result_values}->{prct_used}, + $total_free_value . " " . $total_free_unit, $self->{result_values}->{prct_free} + ); +} + +sub custom_usage_calc { + my ($self, %options) = @_; + + $self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_display'}; + $self->{result_values}->{node_filesystem_size_bytes} = $options{new_datas}->{$self->{instance} . '_node_filesystem_size_bytes'}; + $self->{result_values}->{node_filesystem_free_bytes} = $options{new_datas}->{$self->{instance} . '_node_filesystem_free_bytes'}; + $self->{result_values}->{used} = $self->{result_values}->{node_filesystem_size_bytes} - $self->{result_values}->{node_filesystem_free_bytes}; + $self->{result_values}->{prct_used} = ($self->{result_values}->{node_filesystem_size_bytes} > 0) ? $self->{result_values}->{used} * 100 / $self->{result_values}->{node_filesystem_size_bytes} : 0; + $self->{result_values}->{prct_free} = 100 - $self->{result_values}->{prct_used}; + + # limit to 100. Better output. + if ($self->{result_values}->{prct_used} > 100) { + $self->{result_values}->{node_filesystem_free_bytes} = 0; + $self->{result_values}->{prct_used} = 100; + $self->{result_values}->{prct_free} = 0; + } + + return 0; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'node_storage', type => 1, message_multiple => 'All memory types are ok', display_long => 1, cb_prefix_output => 'prefix_storage_output', } + ]; + + $self->{maps_counters}->{node_storage} = [ + { label => 'usage', set => { + key_values => [ { name => 'node_filesystem_free_bytes' }, { name => 'node_filesystem_size_bytes' }, { name => 'display' } ], + closure_custom_calc => $self->can('custom_usage_calc'), + closure_custom_output => $self->can('custom_usage_output'), + closure_custom_perfdata => $self->can('custom_usage_perfdata'), + closure_custom_threshold_check => $self->can('custom_usage_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 => { + "units:s" => { name => 'units', default => '%' }, + 'fstype:s' => { name => 'fstype', default => 'linuxfs|rootfs|tmpfs' }, + }); + + return $self; +} + +sub prefix_storage_output { + my ($self, %options) = @_; + + return "Storage '" . $options{instance_value}->{display} . "' "; +} + + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + +} + +sub manage_selection { + my ($self, %options) = @_; + + my $raw_metrics = centreon::common::monitoring::openmetrics::scrape::parse(%options, strip_chars => "[\"']"); + + foreach my $metric (keys %{$raw_metrics}) { + next if ($metric !~ /node_filesystem_free_bytes|node_filesystem_size_bytes/i ); + + foreach my $data (@{$raw_metrics->{$metric}->{data}}) { + next if ( $data->{dimensions}->{fstype} !~ /$self->{option_results}->{fstype}/i ); + + foreach my $mountpoint ($data->{dimensions}->{mountpoint}) { + $self->{node_storage}->{$mountpoint}->{$metric} = $data->{value}; + $self->{node_storage}->{$mountpoint}->{display} = $mountpoint; + } + } + } +} + +1; + +__END__ + +=head1 MODE + +Check storage based on node exporter metrics. + +=over 8 + +=item B<--fstype> + +Inclusion filter on fstype. + +Can be used to exclude fstypes. Example : --fstype='^(?!(tmpfs))' + +=item B<--units> + +Units of thresholds. Can be : '%', 'B' +Default: '%' + +=item B<--warning-usage> + +Threshold warning. + +=item B<--critical-usage> + +Threshold critical. + +=back + +=cut \ No newline at end of file diff --git a/centreon-plugins/apps/monitoring/nodeexporter/mode/traffic.pm b/centreon-plugins/apps/monitoring/nodeexporter/mode/traffic.pm new file mode 100644 index 000000000..19efbb143 --- /dev/null +++ b/centreon-plugins/apps/monitoring/nodeexporter/mode/traffic.pm @@ -0,0 +1,197 @@ +# +# 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 apps::monitoring::nodeexporter::mode::traffic; + +use base qw(centreon::plugins::templates::counter); +use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold_ng); + +use strict; +use warnings; +use Digest::MD5 qw(md5_hex); +use centreon::plugins::statefile; +use centreon::common::monitoring::openmetrics::scrape; + + +sub interface_long_output { + my ($self, %options) = @_; + + return sprintf( + "checking interfaces %s ", + $options{instance_value}->{status}->{display} + ); +} + +sub prefix_interface_output { + my ($self, %options) = @_; + + return sprintf( + "interface %s ", + $options{instance_value}->{status}->{display} + ); +} + +sub prefix_packet_output { + my ($self, %options) = @_; + + return 'packets '; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'interface', type => 3, message_multiple => 'All interfaces are OK. ', cb_prefix_output => 'prefix_interface_output', cb_long_output => 'interface_long_output', + indent_long_output => ' ' , + group => [ + { name => 'status', type => 0, skipped_code => { -10 => 1 } }, + { name => 'traffic', type => 0, cb_prefix_output => 'prefix_traffic_output', skipped_code => { -10 => 1 } } + ] + } + ]; + + $self->{maps_counters}->{status} = [ + { + label => 'status', + type => 2, + critical_default => '%{operState} ne "up"', + set => { + key_values => [ + { name => 'operState' }, { name => 'display' } + ], + output_template => "status: %s", + closure_custom_perfdata => sub { return 0; }, + closure_custom_threshold_check => \&catalog_status_threshold_ng + } + } + ]; + + $self->{maps_counters}->{traffic} = [ + { label => 'packets-in', nlabel => 'node.packets.in.count', display_ok => 0, set => { + key_values => [ { name => 'node_network_receive_packets_total', diff => 1 }, { name => 'display' } ], + output_template => 'packets in: %s', + perfdatas => [ + { template => '%s', min => 0, label_extra_instance => 1, instance_use => 'display' } + ] + } + }, + { label => 'packets-out', nlabel => 'node.packets.out.count', display_ok => 0, set => { + key_values => [ + { name => 'node_network_transmit_packets_total', diff => 1 }, { name => 'display' } + ], + output_template => 'packets out: %s', + perfdatas => [ + { template => '%s', min => 0, label_extra_instance => 1, instance_use => 'display' } + ] + } + }, + { label => 'traffic-in', nlabel => 'node.traffic.in.bitspersecond', set => { + key_values => [ + { name => 'node_network_receive_bytes_total', per_second => 1 }, { name => 'display' } + ], + output_template => 'traffic in: %.2f %s/s', + output_change_bytes => 2, + perfdatas => [ + { template => '%.2f', unit => 'b/s', min => 0, label_extra_instance => 1, instance_use => 'display' } + ] + } + }, + { label => 'traffic-out', nlabel => 'node.traffic.out.bitspersecond', set => { + key_values => [ + { name => 'node_network_transmit_bytes_total', per_second => 1 }, { name => 'display' } + ], + output_template => 'traffic in: %.2f %s/s', + output_change_bytes => 2, + perfdatas => [ + { template => '%.2f', unit => 'b/s', min => 0, label_extra_instance => 1, instance_use => 'display' } + ] + } + } + ]; +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1, statefile => 1); + bless $self, $class; + + $options{options}->add_options(arguments => { + "filter:s" => { name => 'filter', default => 'lo' }, + }); + + return $self; +} + +sub manage_selection { + my ($self, %options) = @_; + + my $raw_metrics = centreon::common::monitoring::openmetrics::scrape::parse(%options, strip_chars => "[\"']"); + + $self->{cache_name} = 'linux_nodeexporter' . $options{custom}->get_uuid() . '_' . $self->{mode} . '_' . + (defined($self->{option_results}->{filter_counters}) ? md5_hex($self->{option_results}->{filter_counters}) : md5_hex('all')) . '_' . + (defined($self->{option_results}->{filter_channel}) ? md5_hex($self->{option_results}->{filter_channel}) : md5_hex('all')); + + + my $traffic_metrics; + $self->{interface} = {}; + + foreach my $metric (keys %{$raw_metrics}) { + next if ($metric !~ /node_network_receive_packets_total|node_network_transmit_packets_total|node_network_receive_bytes_total|node_network_transmit_bytes_total|node_network_up/i ); + + foreach my $data (@{$raw_metrics->{$metric}->{data}}) { + next if (defined($self->{option_results}->{filter}) && $data->{dimensions}->{device} =~ $self->{option_results}->{filter}); + $self->{interface}->{$data->{dimensions}->{device}}->{traffic}->{$metric} = $data->{value} if ($metric ne 'node_network_up'); + $self->{interface}->{$data->{dimensions}->{device}}->{traffic}->{display} = $data->{dimensions}->{device} if ($metric ne 'node_network_up'); + + if ($metric eq 'node_network_up') { + $self->{interface}->{$data->{dimensions}->{device}}->{status}->{operState} = ($data->{value} == 1) ? "up" : "down"; + $self->{interface}->{$data->{dimensions}->{device}}->{status}->{display} = $data->{dimensions}->{device}; + } + } + } +} + +1; + +__END__ + +=head1 MODE + +=item B<--filter> + +Filter to exclude interfaces. Is a regex. + +=item B<--warning-*> + +Warning thresholds. + +Can be: 'traffic-in', 'traffic-out', +'packets-in', 'packets-out'. + +=item B<--critical-*> + +Critical thresholds. + +Can be: 'traffic-in', 'traffic-out', +'packets-in', 'packets-out'. + +=back + +=cut \ No newline at end of file diff --git a/centreon-plugins/apps/monitoring/nodeexporter/plugin.pm b/centreon-plugins/apps/monitoring/nodeexporter/plugin.pm new file mode 100644 index 000000000..0287de03a --- /dev/null +++ b/centreon-plugins/apps/monitoring/nodeexporter/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 apps::monitoring::nodeexporter::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, force_new_perfdata => 1); + bless $self, $class; + + $self->{version} = '0.1'; + %{$self->{modes}} = ( + 'cpu' => 'apps::monitoring::nodeexporter::mode::cpu', + 'list-interfaces' => 'apps::monitoring::nodeexporter::mode::listinterfaces', + 'list-storages' => 'apps::monitoring::nodeexporter::mode::liststorages', + 'load' => 'apps::monitoring::nodeexporter::mode::load', + 'memory' => 'apps::monitoring::nodeexporter::mode::memory', + 'storage' => 'apps::monitoring::nodeexporter::mode::storage', + 'traffic' => 'apps::monitoring::nodeexporter::mode::traffic' + ); + + $self->{custom_modes}{web} = 'centreon::common::monitoring::openmetrics::custom::web'; + return $self; +} + +1; + +__END__ + +=head1 PLUGIN DESCRIPTION + +Check host metrics based on node exporter's metrics. + +=cut