enh(vmware/connector): see details (#3330)

- add modes: cpu-cluster, licences, storage-host
- mode datastore-iops: add total iops counters
- mode datastore-usage: add --refresh option
- add option --empty-continue for modes: snapshot-vm, tools-vm
- fix --time-shift option: now it's working
This commit is contained in:
qgarnier 2021-12-21 11:42:14 +01:00 committed by GitHub
parent a5139dd79b
commit b3e9d540fc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 1269 additions and 214 deletions

View File

@ -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

View File

@ -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

View File

@ -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' } ],

View File

@ -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

View File

@ -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').

View File

@ -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

View File

@ -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

View File

@ -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').

View File

@ -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,

View File

@ -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} : '',

View File

@ -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

View File

@ -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.

View File

@ -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',