From 7b40eb38d33011f1e5de918a5d46276eeade3dae Mon Sep 17 00:00:00 2001 From: qgarnier Date: Mon, 11 Sep 2023 09:48:01 +0200 Subject: [PATCH] (plugin) os::linux::local - new mode lvm (removed mode directlvm-usage) (#4570) --- src/os/linux/local/mode/directlvmusage.pm | 153 ------------ src/os/linux/local/mode/lvm.pm | 268 ++++++++++++++++++++++ src/os/linux/local/plugin.pm | 3 +- 3 files changed, 269 insertions(+), 155 deletions(-) delete mode 100644 src/os/linux/local/mode/directlvmusage.pm create mode 100644 src/os/linux/local/mode/lvm.pm diff --git a/src/os/linux/local/mode/directlvmusage.pm b/src/os/linux/local/mode/directlvmusage.pm deleted file mode 100644 index 62a384071..000000000 --- a/src/os/linux/local/mode/directlvmusage.pm +++ /dev/null @@ -1,153 +0,0 @@ -# -# Copyright 2023 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 os::linux::local::mode::directlvmusage; - -use base qw(centreon::plugins::templates::counter); - -use strict; -use warnings; -use centreon::plugins::misc; - -sub set_counters { - my ($self, %options) = @_; - - $self->{maps_counters_type} = [ - { name => 'dlvm', type => 1, cb_prefix_output => 'prefix_dlvm_output', message_multiple => 'All direct LVM are ok' } - ]; - - $self->{maps_counters}->{dlvm} = [ - { label => 'data-usage', set => { - key_values => [ { name => 'data' }, { name => 'display' } ], - output_template => 'Data Usage : %.2f %%', - perfdatas => [ - { label => 'data_used', template => '%.2f', - unit => '%', min => 0, max => 100, label_extra_instance => 1, instance_use => 'display' } - ] - } - }, - { label => 'meta-usage', set => { - key_values => [ { name => 'meta' }, { name => 'display' } ], - output_template => 'Meta Usage : %.2f %%', - perfdatas => [ - { label => 'meta_used', template => '%.2f', - unit => '%', min => 0, max => 100, label_extra_instance => 1, instance_use => 'display' } - ] - } - } - ]; -} - -sub prefix_dlvm_output { - my ($self, %options) = @_; - - return "Direct LVM '" . $options{instance_value}->{display} . "' "; -} - -sub new { - my ($class, %options) = @_; - my $self = $class->SUPER::new(package => __PACKAGE__, %options); - bless $self, $class; - - $options{options}->add_options(arguments => { - 'filter-lv:s' => { name => 'filter_lv' }, - 'filter-vg:s' => { name => 'filter_vg' } - }); - - return $self; -} - -sub manage_selection { - my ($self, %options) = @_; - - my ($stdout, $exit_code) = $options{custom}->execute_command( - command => 'lvs', - command_options => '--separator="," 2>&1', - no_quit => 1 - ); - - $self->{dlvm} = {}; - # LV,VG,Attr,LSize,Pool,Origin,Data%,Meta%,Move,Log,Cpy%Sync,Convert - # thinpool,docker,twi-aot---,71.25g,,,1.95,0.06,,,, - # lv_controlm,vg_sys,-wi-ao----,5.00g,,,,,,,, - # ... - my @lines = split /\n/, $stdout; - shift @lines; - foreach my $line (@lines) { - my @fields = split /,/, $line; - my ($vg, $lv, $data, $meta) = ($fields[1], $fields[0], $fields[6], $fields[7]); - next if (!defined($data) || $data !~ /[0-9]/); - - my $display = centreon::plugins::misc::trim($vg) . '.' . centreon::plugins::misc::trim($lv); - if (defined($self->{option_results}->{filter_lv}) && $self->{option_results}->{filter_lv} ne '' && - $lv !~ /$self->{option_results}->{filter_lv}/) { - $self->{output}->output_add(long_msg => "skipping '" . $display . "': no matching filter.", debug => 1); - next; - } - if (defined($self->{option_results}->{filter_vg}) && $self->{option_results}->{filter_vg} ne '' && - $vg !~ /$self->{option_results}->{filter_vg}/) { - $self->{output}->output_add(long_msg => "skipping '" . $display . "': no matching filter.", debug => 1); - next; - } - - $self->{dlvm}->{$display} = { display => $display, data => $data, meta => $meta }; - } - - if (scalar(keys %{$self->{dlvm}}) <= 0) { - if ($exit_code != 0) { - $self->{output}->output_add(long_msg => "command output:" . $stdout); - } - $self->{output}->add_option_msg(short_msg => "No direct lvm found (filters or command issue)"); - $self->{output}->option_exit(); - } -} - -1; - -__END__ - -=head1 MODE - -Check directl lvm usage. -Command used: lvs --separator="," 2>&1 - -=over 8 - -=item B<--warning-*> - -Warning threshold. -Can be: 'data-usage' (%), 'meta-usage' (%). - -=item B<--critical-*> - -Critical threshold. -Can be: 'data-usage' (%), 'meta-usage' (%). - -=item B<--filter-vg> - -Filter virtual group (regexp can be used). - -=item B<--filter-lv> - -Filter logical volume (regexp can be used). - -=back - -=cut diff --git a/src/os/linux/local/mode/lvm.pm b/src/os/linux/local/mode/lvm.pm new file mode 100644 index 000000000..1e8920050 --- /dev/null +++ b/src/os/linux/local/mode/lvm.pm @@ -0,0 +1,268 @@ +# +# Copyright 2023 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 os::linux::local::mode::lvm; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; +use centreon::plugins::misc; + +sub custom_space_usage_output { + my ($self, %options) = @_; + + my ($total_size_value, $total_size_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{total}); + 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}->{free}); + return sprintf( + 'space 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 prefix_vg_output { + my ($self, %options) = @_; + + return sprintf( + "VG '%s' ", + $options{instance_value}->{name} + ); +} + +sub prefix_dlv_output { + my ($self, %options) = @_; + + return sprintf( + "direct LV '%s' [VG: %s] ", + $options{instance_value}->{lvName}, + $options{instance_value}->{vgName} + ); +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'global', type => 0 }, + { name => 'vg', type => 1, cb_prefix_output => 'prefix_vg_output', message_multiple => 'All VGs are ok' }, + { name => 'dlv', type => 1, cb_prefix_output => 'prefix_dlv_output', message_multiple => 'All direct LVs are ok' } + ]; + + $self->{maps_counters}->{global} = [ + { label => 'lv-detected', display_ok => 0, nlabel => 'lv.detected.count', set => { + key_values => [ { name => 'lv_detected' } ], + output_template => 'number of direct LV detected: %s', + perfdatas => [ + { template => '%s', min => 0 } + ] + } + }, + { label => 'vg-detected', display_ok => 0, nlabel => 'vg.detected.count', set => { + key_values => [ { name => 'vg_detected' } ], + output_template => 'number of direct VG detected: %s', + perfdatas => [ + { template => '%s', min => 0 } + ] + } + } + ]; + + $self->{maps_counters}->{dlv} = [ + { label => 'lv-data-usage', nlabel => 'lv.data.usage.percentage', set => { + key_values => [ { name => 'data' }, { name => 'vgName' }, { name => 'lvName' } ], + output_template => 'data usage: %.2f %%', + closure_custom_perfdata => sub { + my ($self, %options) = @_; + + $self->{output}->perfdata_add( + nlabel => $self->{nlabel}, + unit => '%', + instances => [$self->{result_values}->{vgName}, $self->{result_values}->{lvName}], + value => sprintf('%.2f', $self->{result_values}->{data}), + warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{thlabel}), + critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{thlabel}), + min => 0, + max => 100 + ); + } + } + }, + { label => 'lv-meta-usage', nlabel => 'lv.meta.usage.percentage', set => { + key_values => [ { name => 'meta' }, { name => 'vgName' }, { name => 'lvName' } ], + output_template => 'meta usage: %.2f %%', + closure_custom_perfdata => sub { + my ($self, %options) = @_; + + $self->{output}->perfdata_add( + nlabel => $self->{nlabel}, + unit => '%', + instances => [$self->{result_values}->{vgName}, $self->{result_values}->{lvName}], + value => sprintf('%.2f', $self->{result_values}->{meta}), + warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{thlabel}), + critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{thlabel}), + min => 0, + max => 100 + ); + } + } + } + ]; + + $self->{maps_counters}->{vg} = [ + { label => 'vg-space-usage', nlabel => 'vg.space.usage.bytes', set => { + key_values => [ { name => 'used' }, { name => 'free' }, { name => 'prct_used' }, { name => 'prct_free' }, { name => 'total' } ], + closure_custom_output => $self->can('custom_space_usage_output'), + perfdatas => [ + { template => '%d', min => 0, max => 'total', unit => 'B', cast_int => 1, label_extra_instance => 1 } + ] + } + }, + { label => 'vg-space-usage-free', nlabel => 'vg.space.free.bytes', display_ok => 0, set => { + key_values => [ { name => 'free' }, { name => 'used' }, { name => 'prct_used' }, { name => 'prct_free' }, { name => 'total' } ], + closure_custom_output => $self->can('custom_space_usage_output'), + perfdatas => [ + { template => '%d', min => 0, max => 'total', unit => 'B', cast_int => 1, label_extra_instance => 1 } + ] + } + }, + { label => 'vg-space-usage-prct', nlabel => 'vg.space.usage.percentage', display_ok => 0, set => { + key_values => [ { name => 'prct_used' }, { name => 'used' }, { name => 'free' }, { name => 'prct_free' }, { name => 'total' } ], + closure_custom_output => $self->can('custom_space_usage_output'), + perfdatas => [ + { template => '%.2f', min => 0, max => 100, unit => '%', label_extra_instance => 1 } + ] + } + } + ]; +} + +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-lv:s' => { name => 'filter_lv' }, + 'filter-vg:s' => { name => 'filter_vg' } + }); + + return $self; +} + +sub manage_selection { + my ($self, %options) = @_; + + my ($stdout, $exit_code) = $options{custom}->execute_command( + command => 'lvs', + command_options => '--separator=, 2>&1', + no_quit => 1 + ); + + $self->{global} = { lv_detected => 0, vg_detected => 0 }; + $self->{dlv} = {}; + # LV,VG,Attr,LSize,Pool,Origin,Data%,Meta%,Move,Log,Cpy%Sync,Convert + # thinpool,docker,twi-aot---,71.25g,,,1.95,0.06,,,, + # lv_controlm,vg_sys,-wi-ao----,5.00g,,,,,,,, + my @lines = split(/\n/, $stdout); + shift @lines; + my $i = 0; + foreach my $line (@lines) { + my @fields = split(/,/, $line); + next if (!defined($fields[6]) || $fields[6] !~ /[0-9]/); + my ($vg, $lv, $data, $meta) = (centreon::plugins::misc::trim($fields[1]), centreon::plugins::misc::trim($fields[0]), $fields[6], $fields[7]); + + next if (defined($self->{option_results}->{filter_lv}) && $self->{option_results}->{filter_lv} ne '' && + $lv !~ /$self->{option_results}->{filter_lv}/); + next if (defined($self->{option_results}->{filter_vg}) && $self->{option_results}->{filter_vg} ne '' && + $vg !~ /$self->{option_results}->{filter_vg}/); + + $self->{lv_detected}++; + $self->{dlv}->{$i} = { lvName => $lv, vgName => $vg, data => $data, meta => $meta }; + $i++; + } + + ($stdout, $exit_code) = $options{custom}->execute_command( + command => 'vgs', + command_options => '--separator=, --units=b 2>&1', + no_quit => 1 + ); + + # VG,#PV,#LV,#SN,Attr,VSize,VFree + # test,1,1,0,wz--n-,5364514816B,3217031168B + $self->{vg} = {}; + @lines = split(/\n/, $stdout); + shift @lines; + foreach my $line (@lines) { + my @fields = split(/,/, $line); + next if (!defined($fields[5]) || $fields[5] !~ /[0-9]/); + my $vg = centreon::plugins::misc::trim($fields[0]); + $fields[5] =~ /^(\d+)/; + my $size = $1; + $fields[6] =~ /^(\d+)/; + my $free = $1; + + next if (defined($self->{option_results}->{filter_vg}) && $self->{option_results}->{filter_vg} ne '' && + $vg !~ /$self->{option_results}->{filter_vg}/); + + $self->{vg_detected}++; + $self->{vg}->{$vg} = { + name => $vg, + total => $size, + free => $free, + used => $size - $free, + prct_free => $free * 100 / $size, + prct_used => ($size - $free) * 100 / $size + }; + } +} + +1; + +__END__ + +=head1 MODE + +Check direct LV and VG free space. + +Command used: lvs --separator="," 2>&1 + +=over 8 + +=item B<--filter-vg> + +Filter volume group (regexp can be used). + +=item B<--filter-lv> + +Filter logical volume (regexp can be used). + +=item B<--warning-*> B<--critical-*> + +Thresholds. +Can be: 'lv-detected', 'vg-detected', +'vg-space-usage', 'vg-space-usage-free', 'vg-space-usage-prct', +'lv-data-usage', 'lv-meta-usage'. + +=back + +=cut diff --git a/src/os/linux/local/plugin.pm b/src/os/linux/local/plugin.pm index 87e7a48b1..c6ba53dc6 100644 --- a/src/os/linux/local/plugin.pm +++ b/src/os/linux/local/plugin.pm @@ -29,14 +29,12 @@ sub new { my $self = $class->SUPER::new(package => __PACKAGE__, %options); bless $self, $class; - $self->{version} = '0.1'; $self->{modes} = { 'check-plugin' => 'os::linux::local::mode::checkplugin', 'cpu' => 'os::linux::local::mode::cpu', 'cpu-detailed' => 'os::linux::local::mode::cpudetailed', 'cmd-return' => 'os::linux::local::mode::cmdreturn', 'connections' => 'os::linux::local::mode::connections', - 'directlvm-usage' => 'os::linux::local::mode::directlvmusage', 'discovery-snmp' => 'os::linux::local::mode::discoverysnmp', 'discovery-snmpv3' => 'os::linux::local::mode::discoverysnmpv3', 'diskio' => 'os::linux::local::mode::diskio', @@ -44,6 +42,7 @@ sub new { 'files-date' => 'os::linux::local::mode::filesdate', 'inodes' => 'os::linux::local::mode::inodes', 'load' => 'os::linux::local::mode::loadaverage', + 'lvm' => 'os::linux::local::mode::lvm', 'list-interfaces' => 'os::linux::local::mode::listinterfaces', 'list-partitions' => 'os::linux::local::mode::listpartitions', 'list-storages' => 'os::linux::local::mode::liststorages',