diff --git a/centreon-plugins/apps/vmware/connector/custom/connector.pm b/centreon-plugins/apps/vmware/connector/custom/connector.pm index bfe5031b1..4da4b62d6 100644 --- a/centreon-plugins/apps/vmware/connector/custom/connector.pm +++ b/centreon-plugins/apps/vmware/connector/custom/connector.pm @@ -86,7 +86,7 @@ sub check_options { $self->{vsphere_username} = (defined($self->{option_results}->{vsphere_username})) ? shift(@{$self->{option_results}->{vsphere_username}}) : undef; $self->{vsphere_password} = (defined($self->{option_results}->{vsphere_password})) ? shift(@{$self->{option_results}->{vsphere_password}}) : undef; $self->{sampling_period} = (defined($self->{option_results}->{sampling_period})) ? shift(@{$self->{option_results}->{sampling_period}}) : undef; - $self->{time_shift} = (defined($self->{option_results}->{sampling_period})) ? shift(@{$self->{option_results}->{time_shift}}) : 0; + $self->{time_shift} = (defined($self->{option_results}->{time_shift})) ? shift(@{$self->{option_results}->{time_shift}}) : 0; $self->{unknown_connector_status} = (defined($self->{option_results}->{unknown_connector_status})) ? $self->{option_results}->{unknown_connector_status} : '%{code} < 0 || (%{code} > 0 && %{code} < 200)'; $self->{warning_connector_status} = (defined($self->{option_results}->{warning_connector_status})) ? $self->{option_results}->{warning_connector_status} : ''; $self->{critical_connector_status} = (defined($self->{option_results}->{critical_connector_status})) ? $self->{option_results}->{critical_connector_status} : ''; @@ -221,7 +221,7 @@ sub strip_cr { sub execute { my ($self, %options) = @_; - + $self->add_params(%options); # Build request diff --git a/centreon-plugins/apps/vmware/connector/mode/cpucluster.pm b/centreon-plugins/apps/vmware/connector/mode/cpucluster.pm new file mode 100644 index 000000000..a8f6b741a --- /dev/null +++ b/centreon-plugins/apps/vmware/connector/mode/cpucluster.pm @@ -0,0 +1,142 @@ +# +# Copyright 2021 Centreon (http://www.centreon.com/) +# +# Centreon is a full-fledged industry-strength solution that meets +# the needs in IT infrastructure and application monitoring for +# service performance. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +package apps::vmware::connector::mode::cpucluster; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +sub prefix_cluster_output { + my ($self, %options) = @_; + + return "Cluster '" . $options{instance} . "' : "; +} + +sub cluster_long_output { + my ($self, %options) = @_; + + return "checking cluster '" . $options{instance} . "'"; +} + +sub prefix_cpu_output { + my ($self, %options) = @_; + + return "cpu total average: "; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'clusters', type => 3, cb_prefix_output => 'prefix_cluster_output', cb_long_output => 'cluster_long_output', indent_long_output => ' ', message_multiple => 'All clusters are ok', + group => [ + { name => 'cpu', cb_prefix_output => 'prefix_cpu_output', type => 0, skipped_code => { -10 => 1 } } + ] + } + ]; + + $self->{maps_counters}->{cpu} = [ + { label => 'total-cpu', nlabel => 'cluster.cpu.utilization.percentage', set => { + key_values => [ { name => 'cpu_average' } ], + output_template => '%s %%', + perfdatas => [ + { template => '%s', unit => '%', min => 0, max => 100, label_extra_instance => 1 } + ] + } + }, + { label => 'total-cpu-mhz', nlabel => 'cluster.cpu.utilization.mhz', set => { + key_values => [ { name => 'cpu_average_mhz' } ], + output_template => '%s MHz', + perfdatas => [ + { template => '%s', unit => 'MHz', min => 0, 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 => { + 'cluster-name:s' => { name => 'cluster_name' }, + 'filter' => { name => 'filter' }, + 'scope-datacenter:s' => { name => 'scope_datacenter' } + }); + + return $self; +} + +sub manage_selection { + my ($self, %options) = @_; + + $self->{host} = {}; + my $response = $options{custom}->execute( + params => $self->{option_results}, + command => 'cpucluster' + ); + + $self->{clusters} = {}; + foreach my $cluster_id (keys %{$response->{data}}) { + my $cluster_name = $response->{data}->{$cluster_id}->{name}; + $self->{clusters}->{$cluster_name} = { + cpu => { + cpu_average => $response->{data}->{$cluster_id}->{'cpu.usage.average'}, + cpu_average_mhz => $response->{data}->{$cluster_id}->{'cpu.usagemhz.average'} + } + }; + } +} + +1; + +__END__ + +=head1 MODE + +Check cluster cpu usage. + +=over 8 + +=item B<--cluster-name> + +cluster to check. +If not set, we check all clusters. + +=item B<--filter> + +Cluster name is a regexp. + +=item B<--scope-datacenter> + +Search in following datacenter(s) (can be a regexp). + +=item B<--warning-*> B<--critical-*> + +Thresholds. +Can be: 'total-cpu', 'total-cpu-mhz'. + +=back + +=cut diff --git a/centreon-plugins/apps/vmware/connector/mode/cpuhost.pm b/centreon-plugins/apps/vmware/connector/mode/cpuhost.pm index 3fbb8df37..41a241589 100644 --- a/centreon-plugins/apps/vmware/connector/mode/cpuhost.pm +++ b/centreon-plugins/apps/vmware/connector/mode/cpuhost.pm @@ -52,7 +52,7 @@ sub set_counters { ] } ]; - + $self->{maps_counters}->{global} = [ { label => 'status', type => 2, unknown_default => '%{status} !~ /^connected$/i', @@ -86,7 +86,7 @@ sub set_counters { } } ]; - + $self->{maps_counters}->{cpu} = [ { label => 'cpu', nlabel => 'host.core.cpu.utilization.percentage', set => { key_values => [ { name => 'cpu_usage' }, { name => 'display' } ], diff --git a/centreon-plugins/apps/vmware/connector/mode/datastoreiops.pm b/centreon-plugins/apps/vmware/connector/mode/datastoreiops.pm index 8d0e1edf2..c2ada9399 100644 --- a/centreon-plugins/apps/vmware/connector/mode/datastoreiops.pm +++ b/centreon-plugins/apps/vmware/connector/mode/datastoreiops.pm @@ -33,20 +33,64 @@ sub custom_status_output { return 'accessible ' . $self->{result_values}->{accessible}; } +sub prefix_datastore_output { + my ($self, %options) = @_; + + return "Datastore '" . $options{instance_value}->{display} . "' : "; +} + +sub datastore_long_output { + my ($self, %options) = @_; + + return "checking datastore '" . $options{instance_value}->{display} . "'"; +} + +sub prefix_vm_output { + my ($self, %options) = @_; + + return "virtual machine '" . $options{instance_value}->{display} . "' "; +} + +sub prefix_global_iops_output { + my ($self, %options) = @_; + + return 'Total '; +} + sub set_counters { my ($self, %options) = @_; $self->{maps_counters_type} = [ + { name => 'global_iops', type => 0, cb_prefix_output => 'prefix_global_iops_output', skipped_code => { -10 => 1 } }, { name => 'datastore', type => 3, cb_prefix_output => 'prefix_datastore_output', cb_long_output => 'datastore_long_output', indent_long_output => ' ', message_multiple => 'All datastores are ok', group => [ - { name => 'global', type => 0, skipped_code => { -10 => 1 } }, - { name => 'global_iops', type => 0, skipped_code => { -10 => 1 } }, + { name => 'ds_global', type => 0, skipped_code => { -10 => 1 } }, + { name => 'ds_global_iops', type => 0, skipped_code => { -10 => 1 } }, { name => 'vm', cb_prefix_output => 'prefix_vm_output', message_multiple => 'All virtual machines IOPs are ok', type => 1, skipped_code => { -10 => 1 } } ] } ]; - - $self->{maps_counters}->{global} = [ + + $self->{maps_counters}->{global_iops} = [ + { label => 'read-total', nlabel => 'datastores.read.usage.iops', set => { + key_values => [ { name => 'read' } ], + output_template => 'read: %s iops', + perfdatas => [ + { label => 'total_riops', template => '%s', unit => 'iops', min => 0 } + ] + } + }, + { label => 'write-total', nlabel => 'datastores.write.usage.iops', set => { + key_values => [ { name => 'write' } ], + output_template => 'write: %s iops', + perfdatas => [ + { label => 'total_wiops', template => '%s', unit => 'iops', min => 0 } + ] + } + } + ]; + + $self->{maps_counters}->{ds_global} = [ { label => 'status', type => 2, unknown_default => '%{accessible} !~ /^true|1$/i', set => { @@ -58,7 +102,7 @@ sub set_counters { } ]; - $self->{maps_counters}->{global_iops} = [ + $self->{maps_counters}->{ds_global_iops} = [ { label => 'read', nlabel => 'datastore.read.usage.iops', set => { key_values => [ { name => 'read' } ], output_template => '%s read iops', @@ -101,24 +145,6 @@ sub set_counters { ]; } -sub prefix_datastore_output { - my ($self, %options) = @_; - - return "Datastore '" . $options{instance_value}->{display} . "' : "; -} - -sub datastore_long_output { - my ($self, %options) = @_; - - return "checking datastore '" . $options{instance_value}->{display} . "'"; -} - -sub prefix_vm_output { - my ($self, %options) = @_; - - return "virtual machine '" . $options{instance_value}->{display} . "' "; -} - sub new { my ($class, %options) = @_; my $self = $class->SUPER::new(package => __PACKAGE__, %options); @@ -152,24 +178,28 @@ sub manage_selection { $self->{output}->exit(); } + $self->{global_iops} = { write => 0, read => 0 }; foreach my $ds_id (keys %{$response->{data}}) { my $ds_name = $response->{data}->{$ds_id}->{name}; $self->{datastore}->{$ds_name} = { display => $ds_name, vm => {}, - global => { - accessible => $response->{data}->{$ds_id}->{accessible}, + ds_global => { + accessible => $response->{data}->{$ds_id}->{accessible} }, - global_iops => { + ds_global_iops => { write => $response->{data}->{$ds_id}->{'disk.numberWrite.summation'}, - read => $response->{data}->{$ds_id}->{'disk.numberRead.summation'}, - }, + read => $response->{data}->{$ds_id}->{'disk.numberRead.summation'} + } }; - + + $self->{global_iops}->{write} += $response->{data}->{$ds_id}->{'disk.numberWrite.summation'}; + $self->{global_iops}->{read} += $response->{data}->{$ds_id}->{'disk.numberRead.summation'}; + foreach my $vm_name (sort keys %{$response->{data}->{$ds_id}->{vm}}) { $self->{datastore}->{$ds_name}->{vm}->{$vm_name} = { - display => $vm_name, + display => $vm_name, write => $response->{data}->{$ds_id}->{vm}->{$vm_name}->{'disk.numberWrite.summation'}, - read => $response->{data}->{$ds_id}->{vm}->{$vm_name}->{'disk.numberRead.summation'}, + read => $response->{data}->{$ds_id}->{vm}->{$vm_name}->{'disk.numberRead.summation'} }; } } @@ -216,15 +246,11 @@ Can used special variables like: %{accessible} Set critical threshold for status (Default: ''). Can used special variables like: %{accessible} -=item B<--warning-*> +=item B<--warning-*> B<--critical-*> -Threshold warning. -Can be: 'read', 'write', 'read-vm', 'write-vm'. - -=item B<--critical-*> - -Threshold critical. -Can be: 'read', 'write', 'read-vm', 'write-vm'. +Thresholds. +Can be: 'read-total', 'write-total', +'read', 'write', 'read-vm', 'write-vm'. =back diff --git a/centreon-plugins/apps/vmware/connector/mode/datastoreusage.pm b/centreon-plugins/apps/vmware/connector/mode/datastoreusage.pm index cad33fe0a..ca659c9b4 100644 --- a/centreon-plugins/apps/vmware/connector/mode/datastoreusage.pm +++ b/centreon-plugins/apps/vmware/connector/mode/datastoreusage.pm @@ -151,7 +151,8 @@ sub new { 'scope-datacenter:s' => { name => 'scope_datacenter' }, 'filter-host:s' => { name => 'filter_host' }, 'units:s' => { name => 'units', default => '' }, - 'free' => { name => 'free' } + 'free' => { name => 'free' }, + 'refresh' => { name => 'refresh' } }); return $self; @@ -259,6 +260,10 @@ Search in following datacenter(s) (can be a regexp). Filter datastores attached to hosts (can be a regexp). +=item B<--refresh> + +Explicitly ask vmware to refreshes free-space and capacity values (slower). + =item B<--unknown-status> Set warning threshold for status (Default: '%{accessible} !~ /^true|1$/i'). diff --git a/centreon-plugins/apps/vmware/connector/mode/healthhost.pm b/centreon-plugins/apps/vmware/connector/mode/healthhost.pm index 0eb4bb5c2..e92c000bd 100644 --- a/centreon-plugins/apps/vmware/connector/mode/healthhost.pm +++ b/centreon-plugins/apps/vmware/connector/mode/healthhost.pm @@ -51,91 +51,6 @@ sub custom_summary_output { return $msg; } -sub set_counters { - my ($self, %options) = @_; - - $self->{maps_counters_type} = [ - { name => 'global', type => 0, skipped_code => { -10 => 1 } }, - { name => 'host', type => 3, cb_prefix_output => 'prefix_host_output', cb_long_output => 'host_long_output', indent_long_output => ' ', message_multiple => 'All ESX hosts are ok', - group => [ - { name => 'global_host', type => 0, skipped_code => { -10 => 1 } }, - { name => 'global_problems', type => 0, skipped_code => { -10 => 1 } }, - { name => 'global_summary', type => 1 } - ] - } - ]; - - $self->{maps_counters}->{global} = [ - { label => 'total-problems', nlabel => 'host.health.problems.current.count', set => { - key_values => [ { name => 'total_problems' }, { name => 'total' } ], - output_template => '%s total health issue(s) found', - perfdatas => [ - { label => 'total_problems', template => '%s', - min => 0, max => 'total' } - ] - } - } - ]; - - $self->{maps_counters}->{global_host} = [ - { - label => 'status', type => 2, unknown_default => '%{status} !~ /^connected$/i', - set => { - key_values => [ { name => 'state' } ], - closure_custom_calc => $self->can('custom_status_calc'), - closure_custom_output => $self->can('custom_status_output'), - closure_custom_perfdata => sub { return 0; }, - closure_custom_threshold_check => \&catalog_status_threshold_ng - } - } - ]; - - $self->{maps_counters}->{global_problems} = [ - { label => 'ok', threshold => 0, set => { - key_values => [ { name => 'ok' } ], - output_template => '%s health checks are green', - closure_custom_perfdata => sub { return 0; }, - } - }, - { label => 'problems', nlabel => 'host.health.problems.current.count', set => { - key_values => [ { name => 'total_problems' }, { name => 'total' } ], - output_template => '%s total health issue(s) found', - perfdatas => [ - { label => 'problems', template => '%s', - min => 0, max => 'total', label_extra_instance => 1 } - ] - } - }, - { label => 'problems-yellow', nlabel => 'host.health.yellow.current.count', set => { - key_values => [ { name => 'yellow' }, { name => 'total' } ], - output_template => '%s yellow health issue(s) found', - perfdatas => [ - { label => 'problems_yellow', template => '%s', - min => 0, max => 'total', label_extra_instance => 1 } - ] - } - }, - { label => 'problems-red', nlabel => 'host.health.red.current.count', set => { - key_values => [ { name => 'red' }, { name => 'total' } ], - output_template => '%s red health issue(s) found', - perfdatas => [ - { label => 'problems_red', template => '%s', - min => 0, max => 'total', label_extra_instance => 1 } - ] - } - }, - ]; - - $self->{maps_counters}->{global_summary} = [ - { label => 'global-summary', threshold => 0, set => { - key_values => [ { name => 'type' }, { name => 'name' }, { name => 'summary' } ], - closure_custom_output => $self->can('custom_summary_output'), - closure_custom_perfdata => sub { return 0; } - } - } - ]; -} - sub prefix_host_output { my ($self, %options) = @_; @@ -160,9 +75,144 @@ sub prefix_cpu_output { return "cpu '" . $options{instance_value}->{display} . "' "; } +sub prefix_sensor_output { + my ($self, %options) = @_; + + return "sensor '" . $options{instance} . "' "; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'global', type => 0, skipped_code => { -10 => 1 } }, + { name => 'host', type => 3, cb_prefix_output => 'prefix_host_output', cb_long_output => 'host_long_output', indent_long_output => ' ', message_multiple => 'All ESX hosts are ok', + group => [ + { name => 'global_host', type => 0, skipped_code => { -10 => 1 } }, + { name => 'global_problems', type => 0, skipped_code => { -10 => 1 } }, + { name => 'global_summary', type => 1 }, + { name => 'sensors_temp', display_long => 1, cb_prefix_output => 'prefix_sensor_output', message_multiple => 'temperature sensors are ok', type => 1, skipped_code => { -10 => 1 } }, + { name => 'sensors_fan', display_long => 1, cb_prefix_output => 'prefix_sensor_output', message_multiple => 'fan sensors are ok', type => 1, skipped_code => { -10 => 1 } }, + { name => 'sensors_voltage', display_long => 1, cb_prefix_output => 'prefix_sensor_output', message_multiple => 'voltage sensors are ok', type => 1, skipped_code => { -10 => 1 } }, + { name => 'sensors_power', display_long => 1, cb_prefix_output => 'prefix_sensor_output', message_multiple => 'power sensors are ok', type => 1, skipped_code => { -10 => 1 } } + ] + } + ]; + + $self->{maps_counters}->{global} = [ + { label => 'total-problems', nlabel => 'host.health.problems.current.count', set => { + key_values => [ { name => 'total_problems' }, { name => 'total' } ], + output_template => '%s total health issue(s) found', + perfdatas => [ + { template => '%s', min => 0, max => 'total' } + ] + } + } + ]; + + $self->{maps_counters}->{global_host} = [ + { + label => 'status', type => 2, unknown_default => '%{status} !~ /^connected$/i', + set => { + key_values => [ { name => 'state' } ], + closure_custom_calc => $self->can('custom_status_calc'), + closure_custom_output => $self->can('custom_status_output'), + closure_custom_perfdata => sub { return 0; }, + closure_custom_threshold_check => \&catalog_status_threshold_ng + } + } + ]; + + $self->{maps_counters}->{global_problems} = [ + { label => 'ok', threshold => 0, set => { + key_values => [ { name => 'ok' } ], + output_template => '%s health checks are green', + closure_custom_perfdata => sub { return 0; } + } + }, + { label => 'problems', nlabel => 'host.health.problems.current.count', set => { + key_values => [ { name => 'total_problems' }, { name => 'total' } ], + output_template => '%s total health issue(s) found', + perfdatas => [ + { template => '%s', min => 0, max => 'total', label_extra_instance => 1 } + ] + } + }, + { label => 'problems-yellow', nlabel => 'host.health.yellow.current.count', set => { + key_values => [ { name => 'yellow' }, { name => 'total' } ], + output_template => '%s yellow health issue(s) found', + perfdatas => [ + { template => '%s', min => 0, max => 'total', label_extra_instance => 1 } + ] + } + }, + { label => 'problems-red', nlabel => 'host.health.red.current.count', set => { + key_values => [ { name => 'red' }, { name => 'total' } ], + output_template => '%s red health issue(s) found', + perfdatas => [ + { template => '%s', min => 0, max => 'total', label_extra_instance => 1 } + ] + } + } + ]; + + $self->{maps_counters}->{global_summary} = [ + { label => 'global-summary', threshold => 0, set => { + key_values => [ { name => 'type' }, { name => 'name' }, { name => 'summary' } ], + closure_custom_output => $self->can('custom_summary_output'), + closure_custom_perfdata => sub { return 0; } + } + } + ]; + + $self->{maps_counters}->{sensors_temp} = [ + { label => 'sensor-temperature', nlabel => 'host.sensor.temperature.celsius', set => { + key_values => [ { name => 'value' } ], + output_template => 'temperature: %s C', + perfdatas => [ + { template => '%s', unit => 'C', min => 0, label_extra_instance => 1 } + ] + } + } + ]; + + $self->{maps_counters}->{sensors_fan} = [ + { label => 'sensor-fan', nlabel => 'host.sensor.fan.speed.rpm', set => { + key_values => [ { name => 'value' } ], + output_template => 'fan speed: %s rpm', + perfdatas => [ + { template => '%s', unit => 'rpm', min => 0, label_extra_instance => 1 } + ] + } + } + ]; + + $self->{maps_counters}->{sensors_voltage} = [ + { label => 'sensor-voltage', nlabel => 'host.sensor.voltage.volt', set => { + key_values => [ { name => 'value' } ], + output_template => 'voltage: %s V', + perfdatas => [ + { template => '%s', unit => 'V', min => 0, label_extra_instance => 1 } + ] + } + } + ]; + + $self->{maps_counters}->{sensors_power} = [ + { label => 'sensor-power', nlabel => 'host.sensor.power.watt', set => { + key_values => [ { name => 'value' } ], + output_template => 'power: %s W', + perfdatas => [ + { template => '%s', unit => 'W', min => 0, label_extra_instance => 1 } + ] + } + } + ]; +} + sub new { my ($class, %options) = @_; - my $self = $class->SUPER::new(package => __PACKAGE__, %options); + my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1); bless $self, $class; $options{options}->add_options(arguments => { @@ -195,9 +245,10 @@ sub manage_selection { global_summary => {}, global_problems => { ok => 0, total_problems => 0, red => 0, yellow => 0, total => 0 - } + }, + sensors_temp => {} }; - + my $i = 0; foreach (('memory_info', 'cpu_info', 'sensor_info', 'storage_info')) { if (defined($response->{data}->{$host_id}->{$_})) { @@ -221,6 +272,24 @@ sub manage_selection { } } + if (defined($response->{data}->{$host_id}->{sensor_info})) { + foreach my $entry (@{$response->{data}->{$host_id}->{sensor_info}}) { + next if ($entry->{current_reading} == 0); + + $entry->{current_reading} *= 10 ** $entry->{power10}; + $entry->{name} =~ s/\s---\s.+//; + if (lc($entry->{type}) eq 'temperature' && $entry->{unit} =~ /Degrees\s+C/i) { + $self->{host}->{$host_name}->{sensors_temp}->{ $entry->{name} } = { value => $entry->{current_reading} }; + } elsif (lc($entry->{type}) eq 'fan' && $entry->{unit} =~ /rpm/i) { + $self->{host}->{$host_name}->{sensors_fan}->{ $entry->{name} } = { value => $entry->{current_reading} }; + } elsif (lc($entry->{type}) eq 'voltage' && $entry->{unit} =~ /volts/i) { + $self->{host}->{$host_name}->{sensors_voltage}->{ $entry->{name} } = { value => $entry->{current_reading} }; + } elsif (lc($entry->{type}) eq 'power' && $entry->{unit} =~ /watts/i) { + $self->{host}->{$host_name}->{sensors_power}->{ $entry->{name} } = { value => $entry->{current_reading} }; + } + } + } + $self->{global}->{total_problems} += $self->{host}->{$host_name}->{global_problems}->{red} + $self->{host}->{$host_name}->{global_problems}->{yellow}; $self->{global}->{total} += $self->{host}->{$host_name}->{global_problems}->{total}; } @@ -272,15 +341,11 @@ Can used special variables like: %{status} Set critical threshold for status (Default: ''). Can used special variables like: %{status} -=item B<--warning-*> +=item B<--warning-*> B<--critical-*> -Threshold warning. -Can be: 'total-problems', 'problems', 'problems-yellow', 'problems-red'. - -=item B<--critical-*> - -Threshold critical. -Can be: 'total-problems', 'problems', 'problems-yellow', 'problems-red'. +Thresholds. +Can be: 'total-problems', 'problems', 'problems-yellow', 'problems-red', +'sensor-temperature', 'sensor-fan', 'sensor-voltage', 'sensor-power'. =back diff --git a/centreon-plugins/apps/vmware/connector/mode/licenses.pm b/centreon-plugins/apps/vmware/connector/mode/licenses.pm new file mode 100644 index 000000000..6f6781c2a --- /dev/null +++ b/centreon-plugins/apps/vmware/connector/mode/licenses.pm @@ -0,0 +1,345 @@ +# +# Copyright 2021 Centreon (http://www.centreon.com/) +# +# Centreon is a full-fledged industry-strength solution that meets +# the needs in IT infrastructure and application monitoring for +# service performance. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +package apps::vmware::connector::mode::licenses; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; +use centreon::plugins::misc; +use POSIX; + +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_expires_perfdata { + my ($self, %options) = @_; + + $self->{output}->perfdata_add( + nlabel => $self->{nlabel} . '.' . $unitdiv_long->{ $self->{instance_mode}->{option_results}->{unit} }, + unit => $self->{instance_mode}->{option_results}->{unit}, + instances => $self->{result_values}->{name}, + value => floor($self->{result_values}->{expires_seconds} / $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_expires_threshold { + my ($self, %options) = @_; + + return $self->{perfdata}->threshold_check( + value => floor($self->{result_values}->{expires_seconds} / $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 custom_expires_output { + my ($self, %options) = @_; + + my $msg; + if ($self->{result_values}->{expires_seconds} == 0) { + $msg = 'expired'; + } else { + $msg = 'expires in ' . $self->{result_values}->{expires_human}; + } + return $msg; +} + +sub custom_usage_output { + my ($self, %options) = @_; + + my $msg; + if ($self->{result_values}->{total} <= 0) { + $msg = sprintf('used: %s (unlimited)', $self->{result_values}->{used}); + } else { + $msg = sprintf( + "total: %s used: %s (%.2f%%) free: %s (%.2f%%)", + $self->{result_values}->{total}, + $self->{result_values}->{used}, $self->{result_values}->{prct_used}, + $self->{result_values}->{free}, $self->{result_values}->{prct_free} + ); + } + return $msg; +} + +sub custom_usage_calc { + my ($self, %options) = @_; + + $self->{result_values}->{name} = $options{new_datas}->{$self->{instance} . '_name'}; + $self->{result_values}->{edition} = $options{new_datas}->{$self->{instance} . '_edition'}; + $self->{result_values}->{total} = $options{new_datas}->{$self->{instance} . '_total'}; + $self->{result_values}->{used} = $options{new_datas}->{$self->{instance} . '_used'}; + + if ($self->{result_values}->{total} == 0) { + return -10 if ($options{extra_options}->{label} ne 'usage'); + return 0; + } + + $self->{result_values}->{prct_used} = $self->{result_values}->{used} * 100 / $self->{result_values}->{total}; + $self->{result_values}->{prct_free} = 100 - $self->{result_values}->{prct_used}; + $self->{result_values}->{free} = $self->{result_values}->{total} - $self->{result_values}->{used}; + + return 0; +} + +sub prefix_license_output { + my ($self, %options) = @_; + + return sprintf( + "License '%s' [edition: %s] ", + $options{instance}, + $options{instance_value}->{edition} + ); +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'global', type => 0, skipped_code => { -10 => 1 } }, + { name => 'licenses', type => 1, cb_prefix_output => 'prefix_license_output', message_multiple => 'All licenses are ok', skipped_code => { -10 => 1 } } + ]; + + $self->{maps_counters}->{global} = [ + { label => 'total-licenses', nlabel => 'licenses.total.count', set => { + key_values => [ { name => 'total' } ], + output_template => 'Number of licenses: %s', + perfdatas => [ + { template => '%s', min => 0 } + ] + } + } + ]; + + $self->{maps_counters}->{licenses} = [ + { label => 'usage', nlabel => 'license.usage.count', set => { + key_values => [ + { name => 'edition' }, { name => 'name' }, { name => 'used' }, { name => 'total' } + ], + closure_custom_calc_extra_options => { label => 'usage' }, + closure_custom_calc => $self->can('custom_usage_calc'), + closure_custom_output => $self->can('custom_usage_output'), + closure_custom_threshold_check => sub { + my ($self, %options) = @_; + + return $self->{perfdata}->threshold_check( + value => $self->{result_values}->{used}, threshold => [ + { label => 'critical-' . $self->{thlabel}, exit_litteral => 'critical' }, + { label => 'warning-' . $self->{thlabel}, exit_litteral => 'warning' } + ] + ); + }, + closure_custom_perfdata => sub { + my ($self, %options) = @_; + + $self->{output}->perfdata_add( + nlabel => $self->{nlabel}, + instances => $self->{result_values}->{name}, + value => $self->{result_values}->{used}, + 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 => $self->{result_values}->{total} > 0 ? $self->{result_values}->{total} : undef + ); + } + } + }, + { label => 'usage-free', nlabel => 'license.free.count', display_ok => 0, set => { + key_values => [ + { name => 'edition' }, { name => 'name' }, { name => 'used' }, { name => 'total' } + ], + closure_custom_calc_extra_options => { label => 'free' }, + closure_custom_calc => $self->can('custom_usage_calc'), + closure_custom_output => $self->can('custom_usage_output'), + closure_custom_threshold_check => sub { + my ($self, %options) = @_; + + return $self->{perfdata}->threshold_check( + value => $self->{result_values}->{free}, threshold => [ + { label => 'critical-' . $self->{thlabel}, exit_litteral => 'critical' }, + { label => 'warning-'. $self->{thlabel}, exit_litteral => 'warning' } + ] + ); + }, + closure_custom_perfdata => sub { + my ($self, %options) = @_; + + $self->{output}->perfdata_add( + nlabel => $self->{nlabel}, + instances => $self->{result_values}->{name}, + value => $self->{result_values}->{free}, + 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 => $self->{result_values}->{total} + ); + } + } + }, + { label => 'usage-prct', nlabel => 'license.usage.percentage', display_ok => 0, set => { + key_values => [ + { name => 'edition' }, { name => 'name' }, { name => 'used' }, { name => 'total' } + ], + closure_custom_calc_extra_options => { label => 'prct' }, + closure_custom_calc => $self->can('custom_usage_calc'), + closure_custom_output => $self->can('custom_usage_output'), + closure_custom_threshold_check => sub { + my ($self, %options) = @_; + + return $self->{perfdata}->threshold_check( + value => $self->{result_values}->{prct_used}, threshold => [ + { label => 'critical-' . $self->{thlabel}, exit_litteral => 'critical' }, + { label => 'warning-'. $self->{thlabel}, exit_litteral => 'warning' } + ] + ); + }, + closure_custom_perfdata => sub { + my ($self, %options) = @_; + + $self->{output}->perfdata_add( + nlabel => $self->{nlabel}, + unit => '%', + instances => $self->{result_values}->{name}, + value => $self->{result_values}->{prct_used}, + 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 => 'expires', nlabel => 'license.expires', set => { + key_values => [ { name => 'expires_seconds' }, { name => 'expires_human' }, { name => 'name' } ], + closure_custom_output => $self->can('custom_expires_output'), + closure_custom_perfdata => $self->can('custom_expires_perfdata'), + closure_custom_threshold_check => $self->can('custom_expires_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 => { + 'filter-name:s' => { name => 'filter_name' }, + 'exclude-name:s' => { name => 'exclude_name' }, + 'filter-edition:s' => { name => 'filter_edition' }, + 'exclude-edition:s' => { name => 'exclude_edition' }, + 'unit:s' => { name => 'unit', default => 'd' } + }); + + 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} = 'd'; + } +} + +sub manage_selection { + my ($self, %options) = @_; + + my $response = $options{custom}->execute( + params => $self->{option_results}, + command => 'licenses' + ); + + $self->{global} = { total => 0 }; + $self->{licenses} = {}; + foreach my $name (keys %{$response->{data}}) { + next if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' && + $name !~ /$self->{option_results}->{filter_name}/); + next if (defined($self->{option_results}->{exclude_name}) && $self->{option_results}->{exclude_name} ne '' && + $name =~ /$self->{option_results}->{exclude_name}/); + next if (defined($self->{option_results}->{filter_edition}) && $self->{option_results}->{filter_edition} ne '' && + $response->{data}->{$name}->{edition} !~ /$self->{option_results}->{filter_edition}/); + next if (defined($self->{option_results}->{exclude_edition}) && $self->{option_results}->{exclude_edition} ne '' && + $response->{data}->{$name}->{edition} =~ /$self->{option_results}->{exclude_edition}/); + next if (!defined($response->{data}->{$name}->{used}) && !defined($response->{data}->{$name}->{expiration_minutes})); + + $self->{licenses}->{$name} = { + name => $name, + edition => $response->{data}->{$name}->{edition}, + total => $response->{data}->{$name}->{total}, + used => $response->{data}->{$name}->{used} + }; + if (defined($response->{data}->{$name}->{expiration_minutes})) { + $self->{licenses}->{$name}->{expires_seconds} = $response->{data}->{$name}->{expiration_minutes} * 60; + $self->{licenses}->{$name}->{expires_human} = centreon::plugins::misc::change_seconds( + value => $self->{licenses}->{$name}->{expires_seconds} + ); + } + $self->{global}->{total}++; + } +} + +1; + +__END__ + +=head1 MODE + +Check licenses. + +=over 8 + +=item B<--filter-name> + +Filter licenses by name (can be a regexp). + +=item B<--exclude-name> + +Exclude licenses by name (can be a regexp). + +=item B<--filter-edition> + +Filter licenses by edition name (can be a regexp). + +=item B<--exclude-edition> + +Exclude licenses by edition name (can be a regexp). + +=item B<--unit> + +Select the unit for expires threshold. May be 's' for seconds, 'm' for minutes, +'h' for hours, 'd' for days, 'w' for weeks. Default is days. + +=item B<--warning-*> B<--critical-*> + +Thresholds. +Can be: 'total-licenses', 'usage', 'usage-free', 'usage-prct', 'expires'. + +=back + +=cut diff --git a/centreon-plugins/apps/vmware/connector/mode/nethost.pm b/centreon-plugins/apps/vmware/connector/mode/nethost.pm index e7ef8a170..6f45162c3 100644 --- a/centreon-plugins/apps/vmware/connector/mode/nethost.pm +++ b/centreon-plugins/apps/vmware/connector/mode/nethost.pm @@ -58,7 +58,7 @@ sub custom_traffic_output { my ($value, $unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{traffic}, network => 1); return sprintf( - "traffic %s : %s/s (%.2f %%)", + "traffic %s: %s/s (%.2f %%)", $self->{result_values}->{label_ref}, $value . $unit, $self->{result_values}->{traffic_prct} ); } @@ -79,7 +79,7 @@ sub custom_dropped_output { my ($self, %options) = @_; return sprintf( - 'packets %s dropped : %.2f %% (%d/%d packets)', + 'packets %s dropped: %.2f %% (%d/%d packets)', $self->{result_values}->{label_ref}, $self->{result_values}->{dropped_prct}, $self->{result_values}->{dropped}, $self->{result_values}->{packets} @@ -131,7 +131,7 @@ sub set_counters { $self->{maps_counters}->{global_host} = [ { label => 'host-traffic-in', nlabel => 'host.traffic.in.bitsperseconds', set => { key_values => [ { name => 'traffic_in' } ], - output_template => 'host traffic in : %s %s/s', + output_template => 'host traffic in: %s %s/s', output_change_bytes => 2, perfdatas => [ { label => 'host_traffic_in', template => '%s', @@ -141,7 +141,7 @@ sub set_counters { }, { label => 'host-traffic-out', nlabel => 'host.traffic.out.bitsperseconds', set => { key_values => [ { name => 'traffic_out' } ], - output_template => 'host traffic out : %s %s/s', + output_template => 'host traffic out: %s %s/s', output_change_bytes => 2, perfdatas => [ { label => 'host_traffic_out', template => '%s', @@ -154,17 +154,17 @@ sub set_counters { $self->{maps_counters}->{vswitch} = [ { label => 'vswitch-traffic-in', nlabel => 'host.vswitch.traffic.in.bitsperseconds', set => { key_values => [ { name => 'traffic_in' } ], - output_template => 'traffic in : %s %s/s', + output_template => 'traffic in: %s %s/s', output_change_bytes => 2, perfdatas => [ { label => 'vswitch_traffic_in', template => '%s', - unit => 'b/s', min => 0, label_extra_instance => 1 }, - ], + unit => 'b/s', min => 0, label_extra_instance => 1 } + ] } }, { label => 'vswitch-traffic-out', nlabel => 'host.vswitch.traffic.out.bitsperseconds', set => { key_values => [ { name => 'traffic_out' } ], - output_template => 'traffic out : %s %s/s', + output_template => 'traffic out: %s %s/s', output_change_bytes => 2, perfdatas => [ { label => 'vswitch_traffic_out', template => '%s', @@ -262,12 +262,13 @@ sub new { bless $self, $class; $options{options}->add_options(arguments => { - 'esx-hostname:s' => { name => 'esx_hostname' }, - 'nic-name:s' => { name => 'nic_name' }, - 'filter' => { name => 'filter' }, - 'scope-datacenter:s' => { name => 'scope_datacenter' }, - 'scope-cluster:s' => { name => 'scope_cluster' }, - 'no-proxyswitch' => { name => 'no_proxyswitch' } + 'esx-hostname:s' => { name => 'esx_hostname' }, + 'nic-name:s' => { name => 'nic_name' }, + 'filter' => { name => 'filter' }, + 'scope-datacenter:s' => { name => 'scope_datacenter' }, + 'scope-cluster:s' => { name => 'scope_cluster' }, + 'no-proxyswitch' => { name => 'no_proxyswitch' }, + 'filter-vswitch-name:s' => { name => 'filter_vswitch_name' } }); return $self; @@ -284,21 +285,36 @@ sub manage_selection { foreach my $host_id (keys %{$response->{data}}) { my $host_name = $response->{data}->{$host_id}->{name}; - $self->{host}->{$host_name} = { display => $host_name, + $self->{host}->{$host_name} = { + display => $host_name, global => { - state => $response->{data}->{$host_id}->{state}, + state => $response->{data}->{$host_id}->{state} }, global_host => { traffic_in => 0, traffic_out => 0 } }; - + foreach my $pnic_name (sort keys %{$response->{data}->{$host_id}->{pnic}}) { $self->{host}->{$host_name}->{pnic} = {} if (!defined($self->{host}->{$host_name}->{pnic})); + next if (defined($self->{option_results}->{nic_name}) && $self->{option_results}->{nic_name} ne '' && $pnic_name !~ /$self->{option_results}->{nic_name}/); - + + my $filtered = 1; + if (defined($self->{option_results}->{filter_vswitch_name}) && $self->{option_results}->{filter_vswitch_name} ne '') { + $filtered = 0; + foreach my $vswitch_name (keys %{$response->{data}->{$host_id}->{vswitch}}) { + next if (!defined($response->{data}->{$host_id}->{vswitch}->{$vswitch_name}->{pnic})); + next if ($vswitch_name !~ /$self->{option_results}->{filter_vswitch_name}/); + foreach (@{$response->{data}->{$host_id}->{vswitch}->{$vswitch_name}->{pnic}}) { + $filtered = 1 if ($_ eq $response->{data}->{$host_id}->{pnic}->{$pnic_name}->{key}); + } + } + } + next if ($filtered == 0); + $self->{host}->{$host_name}->{pnic}->{$pnic_name} = { display => $pnic_name, status => $response->{data}->{$host_id}->{pnic}->{$pnic_name}->{status} , @@ -310,9 +326,9 @@ sub manage_selection { dropped_in => $response->{data}->{$host_id}->{pnic}->{$pnic_name}->{'net.droppedRx.summation'}, dropped_out => $response->{data}->{$host_id}->{pnic}->{$pnic_name}->{'net.droppedTx.summation'} }; - + next if (!defined($response->{data}->{$host_id}->{pnic}->{$pnic_name}->{speed})); - + foreach my $vswitch_name (keys %{$response->{data}->{$host_id}->{vswitch}}) { next if (!defined($response->{data}->{$host_id}->{vswitch}->{$vswitch_name}->{pnic})); foreach (@{$response->{data}->{$host_id}->{vswitch}->{$vswitch_name}->{pnic}}) { @@ -326,7 +342,7 @@ sub manage_selection { } } } - + $self->{host}->{$host_name}->{global_host}->{traffic_in} += $response->{data}->{$host_id}->{pnic}->{$pnic_name}->{'net.received.average'} if (defined($response->{data}->{$host_id}->{pnic}->{$pnic_name}->{'net.received.average'})); $self->{host}->{$host_name}->{global_host}->{traffic_out} += $response->{data}->{$host_id}->{pnic}->{$pnic_name}->{'net.transmitted.average'} @@ -367,6 +383,11 @@ Search in following cluster(s) (can be a regexp). ESX nic to check. If not set, we check all nics. +=item B<--filter-vswitch-name> + +Filter vswitch by name. +It monitors only ESX nic that belongs to the filtered vswitches. + =item B<--unknown-status> Set warning threshold for status (Default: '%{status} !~ /^connected$/i'). diff --git a/centreon-plugins/apps/vmware/connector/mode/snapshotvm.pm b/centreon-plugins/apps/vmware/connector/mode/snapshotvm.pm index 51f83f131..5d437ff16 100644 --- a/centreon-plugins/apps/vmware/connector/mode/snapshotvm.pm +++ b/centreon-plugins/apps/vmware/connector/mode/snapshotvm.pm @@ -43,10 +43,11 @@ sub new { 'display-description' => { name => 'display_description' }, 'check-consolidation' => { name => 'check_consolidation' }, 'nopoweredon-skip' => { name => 'nopoweredon_skip' }, + 'empty-continue' => { name => 'empty_continue' }, 'warning:s' => { name => 'warning' }, 'critical:s' => { name => 'critical' }, 'disconnect-status:s' => { name => 'disconnect_status', default => 'unknown' }, - 'unit:s' => { name => 'unit', default => 's' }, + 'unit:s' => { name => 'unit', default => 's' } }); return $self; @@ -80,9 +81,11 @@ sub check_options { sub run { my ($self, %options) = @_; - my $response = $options{custom}->execute(params => $self->{option_results}, - command => 'snapshotvm'); - + my $response = $options{custom}->execute( + params => $self->{option_results}, + command => 'snapshotvm' + ); + my $multiple = 0; my %vm_consolidate = (); my %vm_errors = (warning => {}, critical => {}); @@ -90,28 +93,34 @@ sub run { $multiple = 1; } if ($multiple == 1) { - $self->{output}->output_add(severity => 'OK', - short_msg => sprintf("All snapshots are ok")); + $self->{output}->output_add( + severity => 'OK', + short_msg => sprintf("All snapshots are ok") + ); } else { - $self->{output}->output_add(severity => 'OK', - short_msg => sprintf("Snapshot(s) OK")); + $self->{output}->output_add( + severity => 'OK', + short_msg => sprintf("Snapshot(s) OK") + ); } foreach my $vm_id (sort keys %{$response->{data}}) { my $vm_name = $response->{data}->{$vm_id}->{name}; - + if ($options{custom}->entity_is_connected(state => $response->{data}->{$vm_id}->{connection_state}) == 0) { my $output = "VM '" . $vm_name . "' not connected. Current Connection State: '$response->{data}->{$vm_id}->{connection_state}'."; if ($multiple == 0 || !$self->{output}->is_status(value => $self->{option_results}->{disconnect_status}, compare => 'ok', litteral => 1)) { - $self->{output}->output_add(severity => $self->{option_results}->{disconnect_status}, - short_msg => $output); + $self->{output}->output_add( + severity => $self->{option_results}->{disconnect_status}, + short_msg => $output + ); } next; } next if (defined($self->{option_results}->{nopoweredon_skip}) && $options{custom}->vm_is_running(power => $response->{data}->{$vm_id}->{power_state}) == 0); - + if (defined($self->{check_consolidation}) && defined($response->{data}->{$vm_id}->{consolidation_needed}) && $response->{data}->{$vm_id}->{consolidation_needed} == 1) { $vm_consolidate{$response->{data}->{$vm_id}->{name}} = 1; } @@ -119,15 +128,17 @@ sub run { foreach (@{$response->{data}->{$vm_id}->{snapshosts}}) { my $create_time = Date::Parse::str2time($_->{create_time}); if (!defined($create_time)) { - $self->{output}->output_add(severity => 'UNKNOWN', - short_msg => "Can't Parse date '" . $_->{create_time} . "' for vm '" . $vm_name . "'"); + $self->{output}->output_add( + severity => 'UNKNOWN', + short_msg => "Can't Parse date '" . $_->{create_time} . "' for vm '" . $vm_name . "'" + ); next; } - + my $diff_time = time() - $create_time; my $days = int($diff_time / 60 / 60 / 24); my $exit = $self->{perfdata}->threshold_check(value => ($diff_time / $unitdiv->{$self->{option_results}->{unit}}->[1]), threshold => [ { label => 'critical', exit_litteral => 'critical' }, { label => 'warning', exit_litteral => 'warning' } ]); - + my $prefix_msg = "'$vm_name'"; if (defined($self->{display_description}) && defined($response->{data}->{$vm_id}->{'config.annotation'}) && $response->{data}->{$vm_id}->{'config.annotation'} ne '') { @@ -187,7 +198,7 @@ sub run { ) ); } - + $self->{output}->display(); $self->{output}->exit(); } @@ -247,6 +258,10 @@ Status if VM disconnected (default: 'unknown'). Skip check if VM is not poweredOn. +=item B<--empty-continue> + +Ask to the connector that an empty response is ok. + =item B<--unit> Select the unit for performance data and thresholds. May be 's' for seconds, 'm' for minutes, diff --git a/centreon-plugins/apps/vmware/connector/mode/statuscluster.pm b/centreon-plugins/apps/vmware/connector/mode/statuscluster.pm index 029d52067..e814b20b4 100644 --- a/centreon-plugins/apps/vmware/connector/mode/statuscluster.pm +++ b/centreon-plugins/apps/vmware/connector/mode/statuscluster.pm @@ -97,7 +97,7 @@ sub manage_selection { foreach my $cluster_id (keys %{$response->{data}}) { my $cluster_name = $response->{data}->{$cluster_id}->{name}; $self->{cluster}->{$cluster_name} = { - display => $cluster_name, + display => $cluster_name, overall_status => $response->{data}->{$cluster_id}->{overall_status}, vsan_status => defined($response->{data}->{$cluster_id}->{vsan_cluster_status}) ? $response->{data}->{$cluster_id}->{vsan_cluster_status} : '', ha_enabled => defined($response->{data}->{$cluster_id}->{ha_enabled}) ? $response->{data}->{$cluster_id}->{ha_enabled} : '', diff --git a/centreon-plugins/apps/vmware/connector/mode/storagehost.pm b/centreon-plugins/apps/vmware/connector/mode/storagehost.pm new file mode 100644 index 000000000..23451d7b3 --- /dev/null +++ b/centreon-plugins/apps/vmware/connector/mode/storagehost.pm @@ -0,0 +1,414 @@ +# +# Copyright 2021 Centreon (http://www.centreon.com/) +# +# Centreon is a full-fledged industry-strength solution that meets +# the needs in IT infrastructure and application monitoring for +# service performance. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +package apps::vmware::connector::mode::storagehost; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; +use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold_ng); + +sub custom_status_output { + my ($self, %options) = @_; + + return 'status ' . $self->{result_values}->{status} . ', maintenance mode is ' . $self->{result_values}->{maintenance}; +} + +sub custom_status_calc { + my ($self, %options) = @_; + + $self->{result_values}->{status} = $options{new_datas}->{$self->{instance} . '_state'}; + $self->{result_values}->{maintenance} = $options{new_datas}->{$self->{instance} . '_maintenance'}; + return 0; +} + +sub custom_adapter_output { + my ($self, %options) = @_; + + return sprintf( + 'status: %s', + $self->{result_values}->{status} + ); +} + +sub prefix_host_output { + my ($self, %options) = @_; + + return "Host '" . $options{instance} . "' : "; +} + +sub host_long_output { + my ($self, %options) = @_; + + return "checking host '" . $options{instance} . "'"; +} + +sub prefix_adapters_output { + my ($self, %options) = @_; + + return 'adapters '; +} + +sub prefix_adapter_output { + my ($self, %options) = @_; + + return "adapter '" . $options{instance_value}->{name} . "' "; +} + +sub prefix_luns_output { + my ($self, %options) = @_; + + return 'luns '; +} + +sub prefix_lun_output { + my ($self, %options) = @_; + + return "lun '" . $options{instance_value}->{name} . "' "; +} + +sub prefix_paths_output { + my ($self, %options) = @_; + + return 'paths '; +} + +sub prefix_path_output { + my ($self, %options) = @_; + + return "path '" . $options{instance_value}->{name} . "' "; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'host', type => 3, cb_prefix_output => 'prefix_host_output', cb_long_output => 'host_long_output', indent_long_output => ' ', message_multiple => 'All ESX hosts are ok', + group => [ + { name => 'global', type => 0, skipped_code => { -10 => 1 } }, + { name => 'adapters_global', type => 0, cb_prefix_output => 'prefix_adapters_output', skipped_code => { -10 => 1 } }, + { name => 'luns_global', type => 0, cb_prefix_output => 'prefix_luns_output', skipped_code => { -10 => 1 } }, + { name => 'paths_global', type => 0, cb_prefix_output => 'prefix_paths_output', skipped_code => { -10 => 1 } }, + { name => 'adapters', type => 1, display_long => 1, cb_prefix_output => 'prefix_adapter_output', message_multiple => 'All adapters are ok', skipped_code => { -10 => 1 } }, + { name => 'luns', type => 1, display_long => 1, cb_prefix_output => 'prefix_lun_output', message_multiple => 'All luns are ok', skipped_code => { -10 => 1 } }, + { name => 'paths', type => 1, display_long => 1, cb_prefix_output => 'prefix_path_output', message_multiple => 'All paths are ok', skipped_code => { -10 => 1 } } + ] + } + ]; + + $self->{maps_counters}->{global} = [ + { + label => 'status', type => 2, unknown_default => '%{status} !~ /^connected$/i && %{maintenance} =~ /false/i', + set => { + key_values => [ { name => 'state' }, { name => 'maintenance' } ], + closure_custom_calc => $self->can('custom_status_calc'), + closure_custom_output => $self->can('custom_status_output'), + closure_custom_perfdata => sub { return 0; }, + closure_custom_threshold_check => \&catalog_status_threshold_ng + } + } + ]; + + $self->{maps_counters}->{adapters_global} = []; + foreach ('total', 'online', 'offline', 'fault', 'unknown') { + push @{$self->{maps_counters}->{adapters_global}}, { + label => 'adapters-' . $_, nlabel => 'host.adapters.' . $_ . '.count', set => { + key_values => [ { name => $_ } ], + output_template => $_ . ': %s', + perfdatas => [ + { template => '%s', min => 0, label_extra_instance => 1 } + ] + } + }; + } + + $self->{maps_counters}->{luns_global} = []; + foreach ('total', 'ok', 'error', 'off', 'unknown', 'quiesced', 'degraded') { + push @{$self->{maps_counters}->{luns_global}}, { + label => 'luns-' . $_, nlabel => 'host.luns.' . $_ . '.count', set => { + key_values => [ { name => $_ } ], + output_template => $_ . ': %s', + perfdatas => [ + { template => '%s', min => 0, label_extra_instance => 1 } + ] + } + }; + } + + $self->{maps_counters}->{paths_global} = []; + foreach ('total', 'active', 'disabled', 'standby', 'dead', 'unknown') { + push @{$self->{maps_counters}->{paths_global}}, { + label => 'paths-' . $_, nlabel => 'host.paths.' . $_ . '.count', set => { + key_values => [ { name => $_ } ], + output_template => $_ . ': %s', + perfdatas => [ + { template => '%s', min => 0, label_extra_instance => 1 } + ] + } + }; + } + + $self->{maps_counters}->{adapters} = [ + { + label => 'adapter-status', type => 2, critical_default => '%{status} =~ /fault/', + set => { + key_values => [ { name => 'name' }, { name => 'status' }, { name => 'host' } ], + closure_custom_output => $self->can('custom_adapter_output'), + closure_custom_perfdata => sub { return 0; }, + closure_custom_threshold_check => \&catalog_status_threshold_ng + } + } + ]; + + $self->{maps_counters}->{luns} = [ + { + label => 'lun-status', + type => 2, + warning_default => '%{status} =~ /degraded|quiesced/', + critical_default => '%{status} =~ /lostcommunication|error/', + set => { + key_values => [ { name => 'name' }, { name => 'status' }, { name => 'host' } ], + closure_custom_output => $self->can('custom_adapter_output'), + closure_custom_perfdata => sub { return 0; }, + closure_custom_threshold_check => \&catalog_status_threshold_ng + } + } + ]; + + $self->{maps_counters}->{paths} = [ + { + label => 'path-status', + type => 2, + critical_default => '%{status} =~ /dead/', + set => { + key_values => [ { name => 'name' }, { name => 'status' }, { name => 'host' } ], + closure_custom_output => $self->can('custom_adapter_output'), + 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 => { + 'esx-hostname:s' => { name => 'esx_hostname' }, + 'filter' => { name => 'filter' }, + 'scope-datacenter:s' => { name => 'scope_datacenter' }, + 'scope-cluster:s' => { name => 'scope_cluster' }, + 'filter-adapter-name:s' => { name => 'filter_adapter_name' }, + 'filter-lun-name:s' => { name => 'filter_lun_name' }, + 'filter-path-name:s' => { name => 'filter_path_name' } + }); + + return $self; +} + +sub manage_selection { + my ($self, %options) = @_; + + $self->{host} = {}; + my $response = $options{custom}->execute( + params => $self->{option_results}, + command => 'storagehost' + ); + + foreach my $host_id (keys %{$response->{data}}) { + my $host_name = $response->{data}->{$host_id}->{name}; + $self->{host}->{$host_name} = { + global => { + state => $response->{data}->{$host_id}->{state}, + maintenance => $response->{data}->{$host_id}->{inMaintenanceMode} + } + }; + + if (defined($response->{data}->{$host_id}->{adapters})) { + $self->{host}->{$host_name}->{adapters} = {}; + $self->{host}->{$host_name}->{adapters_global} = { + online => 0, offline => 0, fault => 0, unknown => 0, total => 0 + }; + foreach (@{$response->{data}->{$host_id}->{adapters}}) { + next if (defined($self->{option_results}->{filter_adapter_name}) && $self->{option_results}->{filter_adapter_name} ne '' && + $_->{name} !~ /$self->{option_results}->{filter_adapter_name}/); + + $self->{host}->{$host_name}->{adapters_global}->{total}++; + if (defined($self->{host}->{$host_name}->{adapters_global}->{ $_->{status} })) { + $self->{host}->{$host_name}->{adapters_global}->{ $_->{status} }++; + } else { + $self->{host}->{$host_name}->{adapters_global}->{unknown}++; + } + $self->{host}->{$host_name}->{adapters}->{ $_->{name} } = { + name => $_->{name}, + host => $host_name, + status => $_->{status} + }; + } + } + + if (defined($response->{data}->{$host_id}->{luns})) { + $self->{host}->{$host_name}->{luns} = {}; + $self->{host}->{$host_name}->{luns_global} = { + ok => 0, error => 0, off => 0, unknown => 0, quiesced => 0, degraded => 0, total => 0 + }; + foreach (@{$response->{data}->{$host_id}->{luns}}) { + next if (defined($self->{option_results}->{filter_lun_name}) && $self->{option_results}->{filter_lun_name} ne '' && + $_->{name} !~ /$self->{option_results}->{filter_lun_name}/); + + $self->{host}->{$host_name}->{luns_global}->{total}++; + foreach my $state (@{$_->{operational_states}}) { + if (defined($self->{host}->{$host_name}->{luns_global}->{$state})) { + $self->{host}->{$host_name}->{luns_global}->{$state}++; + } else { + $self->{host}->{$host_name}->{luns_global}->{unknown}++; + } + } + + $self->{host}->{$host_name}->{luns}->{ $_->{name} } = { + name => $_->{name}, + host => $host_name, + status => join(',', @{$_->{operational_states}}) + }; + } + } + + if (defined($response->{data}->{$host_id}->{paths})) { + $self->{host}->{$host_name}->{paths} = {}; + $self->{host}->{$host_name}->{paths_global} = { + active => 0, disabled => 0, standby => 0, dead => 0, unknown => 0 + }; + foreach (@{$response->{data}->{$host_id}->{paths}}) { + next if (defined($self->{option_results}->{filter_path_name}) && $self->{option_results}->{filter_path_name} ne '' && + $_->{name} !~ /$self->{option_results}->{filter_path_name}/); + + $self->{host}->{$host_name}->{paths_global}->{total}++; + if (defined($self->{host}->{$host_name}->{paths_global}->{ $_->{state} })) { + $self->{host}->{$host_name}->{paths_global}->{ $_->{state} }++; + } else { + $self->{host}->{$host_name}->{paths_global}->{unknown}++; + } + + $self->{host}->{$host_name}->{paths}->{ $_->{name} } = { + name => $_->{name}, + host => $host_name, + status => $_->{state} + }; + } + } + } +} + +1; + +__END__ + +=head1 MODE + +Check ESX storage infos. + +=over 8 + +=item B<--esx-hostname> + +ESX hostname to check. +If not set, we check all ESX. + +=item B<--filter> + +ESX hostname is a regexp. + +=item B<--scope-datacenter> + +Search in following datacenter(s) (can be a regexp). + +=item B<--scope-cluster> + +Search in following cluster(s) (can be a regexp). + +=item B<--filter-adapter-name> + +Filter adapters by name (can be a regexp). + +=item B<--filter-lun-name> + +Filter luns by name (can be a regexp). + +=item B<--filter-path-name> + +Filter paths by name (can be a regexp). + +=item B<--unknown-status> + +Set warning threshold for status (Default: '%{status} !~ /^connected$/i && %{maintenance} =~ /false/i'). +Can used special variables like: %{status}, %{maintenance} + +=item B<--warning-status> + +Set warning threshold for status. +Can used special variables like: %{status}, %{maintenance} + +=item B<--critical-status> + +Set critical threshold for status. +Can used special variables like: %{status}, %{maintenance} + +=item B<--warning-adapter-status> + +Set warning threshold for adapter status. +Can used special variables like: %{name}, %{host}, %{status} + +=item B<--critical-adapter-status> + +Set critical threshold for adapter status (Default: '%{status} =~ /fault/'). +Can used special variables like: %{name}, %{host}, %{status} + +=item B<--warning-lun-status> + +Set warning threshold for lun status (Default: '%{status} =~ /degraded|quiesced/'). +Can used special variables like: %{name}, %{host}, %{status} + +=item B<--critical-lun-status> + +Set critical threshold for lun status (Default: '%{status} =~ /lostcommunication|error/'). +Can used special variables like: %{name}, %{host}, %{status} + +=item B<--warning-path-status> + +Set warning threshold for path status. +Can used special variables like: %{name}, %{host}, %{status} + +=item B<--critical-path-status> + +Set critical threshold for path status (Default: '%{status} =~ /dead/'). +Can used special variables like: %{name}, %{host}, %{status} + +=item B<--warning-*> B<--critical-*> + +Thresholds. +Can be: 'adapters-total', 'adapters-online', 'adapters-offline', 'adapters-fault', 'adapters-unknown', + + +=back + +=cut diff --git a/centreon-plugins/apps/vmware/connector/mode/toolsvm.pm b/centreon-plugins/apps/vmware/connector/mode/toolsvm.pm index 605f8fd67..1e1c1c372 100644 --- a/centreon-plugins/apps/vmware/connector/mode/toolsvm.pm +++ b/centreon-plugins/apps/vmware/connector/mode/toolsvm.pm @@ -31,20 +31,21 @@ sub new { bless $self, $class; $options{options}->add_options(arguments => { - "vm-hostname:s" => { name => 'vm_hostname' }, - "filter" => { name => 'filter' }, - "scope-datacenter:s" => { name => 'scope_datacenter' }, - "scope-cluster:s" => { name => 'scope_cluster' }, - "scope-host:s" => { name => 'scope_host' }, - "filter-description:s" => { name => 'filter_description' }, - "filter-os:s" => { name => 'filter_os' }, - "filter-uuid:s" => { name => 'filter_uuid' }, - "display-description" => { name => 'display_description' }, - "disconnect-status:s" => { name => 'disconnect_status', default => 'unknown' }, - "tools-notinstalled-status:s" => { name => 'tools_notinstalled_status', default => 'critical' }, - "tools-notrunning-status:s" => { name => 'tools_notrunning_status', default => 'critical' }, - "tools-notup2date-status:s" => { name => 'tools_notupd2date_status', default => 'warning' }, - "nopoweredon-skip" => { name => 'nopoweredon_skip' }, + 'vm-hostname:s' => { name => 'vm_hostname' }, + 'filter' => { name => 'filter' }, + 'scope-datacenter:s' => { name => 'scope_datacenter' }, + 'scope-cluster:s' => { name => 'scope_cluster' }, + 'scope-host:s' => { name => 'scope_host' }, + 'filter-description:s' => { name => 'filter_description' }, + 'filter-os:s' => { name => 'filter_os' }, + 'filter-uuid:s' => { name => 'filter_uuid' }, + 'display-description' => { name => 'display_description' }, + 'disconnect-status:s' => { name => 'disconnect_status', default => 'unknown' }, + 'tools-notinstalled-status:s' => { name => 'tools_notinstalled_status', default => 'critical' }, + 'tools-notrunning-status:s' => { name => 'tools_notrunning_status', default => 'critical' }, + 'tools-notup2date-status:s' => { name => 'tools_notupd2date_status', default => 'warning' }, + 'nopoweredon-skip' => { name => 'nopoweredon_skip' }, + 'empty-continue' => { name => 'empty_continue' } }); return $self; @@ -88,21 +89,27 @@ sub display_verbose { sub run { my ($self, %options) = @_; - my $response = $options{custom}->execute(params => $self->{option_results}, - command => 'toolsvm'); + my $response = $options{custom}->execute( + params => $self->{option_results}, + command => 'toolsvm' + ); my $multiple = 0; if (scalar(keys %{$response->{data}}) > 1) { $multiple = 1; } if ($multiple == 1) { - $self->{output}->output_add(severity => 'OK', - short_msg => 'All VMTools are OK'); + $self->{output}->output_add( + severity => 'OK', + short_msg => 'All VMTools are OK' + ); } else { - $self->{output}->output_add(severity => 'OK', - short_msg => 'VMTools are OK'); + $self->{output}->output_add( + severity => 'OK', + short_msg => 'VMTools are OK' + ); } - + my %not_installed = (); my %not_running = (); my %not_up2date = (); @@ -113,14 +120,16 @@ sub run { my $output = "VM '" . $vm_name . "' not connected. Current Connection State: '$response->{data}->{$vm_id}->{connection_state}'."; if ($multiple == 0 || !$self->{output}->is_status(value => $self->{option_results}->{disconnect_status}, compare => 'ok', litteral => 1)) { - $self->{output}->output_add(severity => $self->{option_results}->{disconnect_status}, - short_msg => $output); + $self->{output}->output_add( + severity => $self->{option_results}->{disconnect_status}, + short_msg => $output + ); } next; } next if (defined($self->{option_results}->{nopoweredon_skip}) && - $options{custom}->vm_is_running(power => $response->{data}->{$vm_id}->{power_state}) == 0); + $options{custom}->vm_is_running(power => $response->{data}->{$vm_id}->{power_state}) == 0); next if (!defined($response->{data}->{$vm_id}->{tools_status})); @@ -133,26 +142,32 @@ sub run { $not_up2date{$vm_name} = defined($response->{data}->{$vm_id}->{'config.annotation'}) ? $response->{data}->{$vm_id}->{'config.annotation'} : ''; } } - + if (scalar(keys %not_up2date) > 0 && !$self->{output}->is_status(value => $self->{option_results}->{tools_notupd2date_status}, compare => 'ok', litteral => 1)) { - $self->{output}->output_add(severity => $self->{option_results}->{tools_notupd2date_status}, - short_msg => sprintf('%d VM with VMTools not up-to-date', scalar(keys %not_up2date))); + $self->{output}->output_add( + severity => $self->{option_results}->{tools_notupd2date_status}, + short_msg => sprintf('%d VM with VMTools not up-to-date', scalar(keys %not_up2date)) + ); $self->display_verbose(label => 'vmtools not up-to-date:', vms => \%not_up2date, custom => $options{custom}); } if (scalar(keys %not_running) > 0 && !$self->{output}->is_status(value => $self->{option_results}->{tools_notrunning_status}, compare => 'ok', litteral => 1)) { - $self->{output}->output_add(severity => $self->{option_results}->{tools_notrunning_status}, - short_msg => sprintf('%d VM with VMTools not running', scalar(keys %not_running))); + $self->{output}->output_add( + severity => $self->{option_results}->{tools_notrunning_status}, + short_msg => sprintf('%d VM with VMTools not running', scalar(keys %not_running)) + ); $self->display_verbose(label => 'vmtools not running:', vms => \%not_running, custom => $options{custom}); } if (scalar(keys %not_installed) > 0 && !$self->{output}->is_status(value => $self->{option_results}->{tools_notinstalled_status}, compare => 'ok', litteral => 1)) { - $self->{output}->output_add(severity => $self->{option_results}->{tools_notinstalled_status}, - short_msg => sprintf('%d VM with VMTools not installed', scalar(keys %not_installed))); + $self->{output}->output_add( + severity => $self->{option_results}->{tools_notinstalled_status}, + short_msg => sprintf('%d VM with VMTools not installed', scalar(keys %not_installed)) + ); $self->display_verbose(label => 'vmtools not installed:', vms => \%not_installed, custom => $options{custom}); } - + if ($multiple == 1) { my $total = scalar(keys %not_up2date) + scalar(keys %not_running) + scalar(keys %not_installed); $self->{output}->perfdata_add( @@ -174,7 +189,7 @@ sub run { min => 0, max => $total ); } - + $self->{output}->display(); $self->{output}->exit(); } @@ -226,6 +241,10 @@ Status if VM disconnected (default: 'unknown'). Skip check if VM is not poweredOn. +=item B<--empty-continue> + +Ask to the connector that an empty response is ok. + =item B<--display-description> Display virtual machine description. diff --git a/centreon-plugins/apps/vmware/connector/plugin.pm b/centreon-plugins/apps/vmware/connector/plugin.pm index 5fe3f751b..e6e786d83 100644 --- a/centreon-plugins/apps/vmware/connector/plugin.pm +++ b/centreon-plugins/apps/vmware/connector/plugin.pm @@ -33,8 +33,9 @@ sub new { $self->{modes} = { 'alarm-datacenter' => 'apps::vmware::connector::mode::alarmdatacenter', 'alarm-host' => 'apps::vmware::connector::mode::alarmhost', - 'countvm-host' => 'apps::vmware::connector::mode::countvmhost', - 'cpu-host' => 'apps::vmware::connector::mode::cpuhost', + 'countvm-host' => 'apps::vmware::connector::mode::countvmhost', + 'cpu-cluster' => 'apps::vmware::connector::mode::cpucluster', + 'cpu-host' => 'apps::vmware::connector::mode::cpuhost', 'cpu-vm' => 'apps::vmware::connector::mode::cpuvm', 'datastore-countvm' => 'apps::vmware::connector::mode::datastorecountvm', 'datastore-host' => 'apps::vmware::connector::mode::datastorehost', @@ -47,6 +48,7 @@ sub new { 'discovery' => 'apps::vmware::connector::mode::discovery', 'getmap' => 'apps::vmware::connector::mode::getmap', 'health-host' => 'apps::vmware::connector::mode::healthhost', + 'licenses' => 'apps::vmware::connector::mode::licenses', 'limit-vm' => 'apps::vmware::connector::mode::limitvm', 'list-clusters' => 'apps::vmware::connector::mode::listclusters', 'list-datacenters' => 'apps::vmware::connector::mode::listdatacenters', @@ -63,6 +65,7 @@ sub new { 'status-cluster' => 'apps::vmware::connector::mode::statuscluster', 'status-host' => 'apps::vmware::connector::mode::statushost', 'status-vm' => 'apps::vmware::connector::mode::statusvm', + 'storage-host' => 'apps::vmware::connector::mode::storagehost', 'swap-host' => 'apps::vmware::connector::mode::swaphost', 'swap-vm' => 'apps::vmware::connector::mode::swapvm', 'thinprovisioning-vm' => 'apps::vmware::connector::mode::thinprovisioningvm',