diff --git a/apps/vmware/connector/custom/connector.pm b/apps/vmware/connector/custom/connector.pm index acdd97ad2..5adf5250d 100644 --- a/apps/vmware/connector/custom/connector.pm +++ b/apps/vmware/connector/custom/connector.pm @@ -218,6 +218,24 @@ sub connector_response_status { } } +sub host_is_connected { + my ($self, %options) = @_; + + if ($options{state} !~ /^connected$/i) { + return 0; + } + return 1; +} + +sub vm_is_running { + my ($self, %options) = @_; + + if ($options{power} !~ /^poweredOn$/i) { + return 0; + } + return 1; +} + sub get_id { my ($self, %options) = @_; diff --git a/apps/vmware/connector/mode/servicehost.pm b/apps/vmware/connector/mode/servicehost.pm index 92afb73fb..98e5750cf 100644 --- a/apps/vmware/connector/mode/servicehost.pm +++ b/apps/vmware/connector/mode/servicehost.pm @@ -20,10 +20,96 @@ package apps::vmware::connector::mode::servicehost; -use base qw(centreon::plugins::mode); +use base qw(centreon::plugins::templates::counter); use strict; use warnings; +use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold); + +sub custom_status_output { + my ($self, %options) = @_; + + my $msg = 'status ' . $self->{result_values}->{status} . ', maintenance mode is ' . $self->{result_values}->{maintenance}; + return $msg; +} + +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_service_output { + my ($self, %options) = @_; + + my $msg = '[policy ' . $self->{result_values}->{policy} . '][running ' . $self->{result_values}->{running} . ']'; + return $msg; +} + +sub custom_service_calc { + my ($self, %options) = @_; + + $self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_display'}; + $self->{result_values}->{policy} = $options{new_datas}->{$self->{instance} . '_policy'}; + $self->{result_values}->{running} = $options{new_datas}->{$self->{instance} . '_running'}; + $self->{result_values}->{key} = $options{new_datas}->{$self->{instance} . '_key'}; + return 0; +} + +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 => 'service', cb_prefix_output => 'prefix_service_output', message_multiple => 'All services are ok', type => 1, skipped_code => { -10 => 1 } }, + ] + } + ]; + + $self->{maps_counters}->{global} = [ + { label => 'status', threshold => 0, 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, + } + }, + ]; + + $self->{maps_counters}->{service} = [ + { label => 'service-status', threshold => 0, set => { + key_values => [ { name => 'display' }, { name => 'policy' }, { name => 'running' }, { name => 'key' } ], + closure_custom_calc => $self->can('custom_service_calc'), + closure_custom_output => $self->can('custom_service_output'), + closure_custom_perfdata => sub { return 0; }, + closure_custom_threshold_check => \&catalog_status_threshold, + } + }, + ]; +} + +sub prefix_host_output { + my ($self, %options) = @_; + + return "Host '" . $options{instance_value}->{display} . "' : "; +} + +sub host_long_output { + my ($self, %options) = @_; + + return "checking host '" . $options{instance_value}->{display} . "'"; +} + +sub prefix_service_output { + my ($self, %options) = @_; + + return "service '" . $options{instance_value}->{display} . "' "; +} sub new { my ($class, %options) = @_; @@ -31,35 +117,54 @@ sub new { bless $self, $class; $self->{version} = '1.0'; - $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' }, - "disconnect-status:s" => { name => 'disconnect_status', default => 'unknown' }, - "filter-services:s" => { name => 'filter_services' }, - }); + $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-services:s" => { name => 'filter_services' }, + "unknown-status:s" => { name => 'unknown_status', default => '%{status} !~ /^connected$/i && %{maintenance} =~ /false/i' }, + "warning-status:s" => { name => 'warning_status', default => '' }, + "critical-status:s" => { name => 'critical_status', default => '' }, + "warning-service-status:s" => { name => 'warning_service_status', default => '' }, + "critical-service-status:s" => { name => 'critical_service_status', default => '%{policy} =~ /^on|automatic/i && !%{running}' }, + }); + return $self; } sub check_options { my ($self, %options) = @_; - $self->SUPER::init(%options); - - if ($self->{output}->is_litteral_status(status => $self->{option_results}->{disconnect_status}) == 0) { - $self->{output}->add_option_msg(short_msg => "Wrong disconnect-status status option '" . $self->{option_results}->{disconnect_status} . "'."); - $self->{output}->option_exit(); - } + $self->SUPER::check_options(%options); + + $self->change_macros(macros => ['unknown_status', 'warning_status', 'critical_status', + 'warning_service_status', 'critical_service_status']); } -sub run { +sub manage_selection { my ($self, %options) = @_; - $self->{connector} = $options{custom}; - $self->{connector}->add_params(params => $self->{option_results}, - command => 'servicehost'); - $self->{connector}->run(); + $self->{host} = {}; + my $response = $options{custom}->execute(params => $self->{option_results}, + command => 'servicehost'); + + foreach my $host_id (keys %{$response->{data}}) { + my $host_name = $response->{data}->{$host_id}->{name}; + $self->{host}->{$host_name} = { display => $host_name, + global => { + state => $response->{data}->{$host_id}->{state}, + maintenance => $response->{data}->{$host_id}->{inMaintenanceMode}, + }, + }; + + foreach (@{$response->{data}->{$host_id}->{services}}) { + next if (defined($self->{option_results}->{filter_services}) && $self->{option_results}->{filter_services} ne '' && + $_->{key} !~ /$self->{option_results}->{filter_services}/); + + $self->{host}->{$host_name}->{service} = {} if (!defined($self->{host}->{$host_name}->{service})); + $self->{host}->{$host_name}->{service}->{$_->{label}} = { display => $_->{label}, policy => $_->{policy}, running => $_->{running}, key => $_->{key} }; + } + } } 1; @@ -89,14 +194,35 @@ Search in following datacenter(s) (can be a regexp). Search in following cluster(s) (can be a regexp). -=item B<--disconnect-status> - -Status if ESX host disconnected (default: 'unknown'). - =item B<--filter-services> Filter services you want to check (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} + +=item B<--warning-status> + +Set warning threshold for status (Default: ''). +Can used special variables like: %{status} + +=item B<--critical-status> + +Set critical threshold for status (Default: ''). +Can used special variables like: %{status} + +=item B<--warning-service-status> + +Set warning threshold for status (Default: ''). +Can used special variables like: %{running}, %{label}, %{policy} + +=item B<--critical-service-status> + +Set critical threshold for status (Default: '%{policy} =~ /^on|automatic/i && !%{running}'). +Can used special variables like: %{running}, %{label}, %{policy} + =back =cut diff --git a/apps/vmware/connector/mode/snapshotvm.pm b/apps/vmware/connector/mode/snapshotvm.pm index 31e2bdef1..fb0b74cc2 100644 --- a/apps/vmware/connector/mode/snapshotvm.pm +++ b/apps/vmware/connector/mode/snapshotvm.pm @@ -24,6 +24,7 @@ use base qw(centreon::plugins::mode); use strict; use warnings; +use Date::Parse; sub new { my ($class, %options) = @_; @@ -31,21 +32,21 @@ sub new { bless $self, $class; $self->{version} = '1.0'; - $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' }, - "disconnect-status:s" => { name => 'disconnect_status', default => 'unknown' }, - "nopoweredon-skip" => { name => 'nopoweredon_skip' }, - "display-description" => { name => 'display_description' }, - "check-consolidation" => { name => 'check_consolidation' }, - "warning:s" => { name => 'warning' }, - "critical:s" => { name => 'critical' }, - }); + $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' }, + "display-description" => { name => 'display_description' }, + "check-consolidation" => { name => 'check_consolidation' }, + "nopoweredon-skip" => { name => 'nopoweredon_skip' }, + "warning:s" => { name => 'warning' }, + "critical:s" => { name => 'critical' }, + "disconnect-status:s" => { name => 'disconnect_status', default => 'unknown' }, + }); + return $self; } @@ -70,11 +71,91 @@ sub check_options { sub run { my ($self, %options) = @_; - $self->{connector} = $options{custom}; - $self->{connector}->add_params(params => $self->{option_results}, - command => 'snapshotvm'); - $self->{connector}->run(); + my $response = $options{custom}->execute(params => $self->{option_results}, + command => 'snapshotvm'); + + my $multiple = 0; + my %vm_consolidate = (); + my %vm_errors = (warning => {}, critical => {}); + if (scalar(keys %{$response->{data}}) > 1) { + $multiple = 1; + } + if ($multiple == 1) { + $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")); + } + foreach my $vm_id (sort keys %{$response->{data}}) { + my $vm_name = $response->{data}->{$vm_id}->{name}; + + if ($options{custom}->host_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); + } + 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; + } + + 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 . "'"); + next; + } + + my $diff_time = time() - $create_time; + my $days = int($diff_time / 60 / 60 / 24); + my $exit = $self->{perfdata}->threshold_check(value => $diff_time, 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 '') { + $prefix_msg .= ' [' . $options{custom}->strip_cr(value => $response->{data}->{$vm_id}->{'config.annotation'}) . ']'; + } + if (!$self->{output}->is_status(value => $exit, compare => 'ok', litteral => 1)) { + $vm_errors{$exit}->{$vm_name} = 1; + $self->{output}->output_add(long_msg => "$prefix_msg snapshot create time: " . $_->{create_time}); + } + } + } + + $self->{output}->perfdata_add(label => 'num_warning', + value => scalar(keys %{$vm_errors{warning}}), + min => 0); + $self->{output}->perfdata_add(label => 'num_critical', + value => scalar(keys %{$vm_errors{critical}}), + min => 0); + if (scalar(keys %{$vm_errors{warning}}) > 0) { + $self->{output}->output_add(severity => 'WARNING', + short_msg => sprintf('Snapshots for VM older than %d days: [%s]', ($self->{warning} / 86400), + join('] [', sort keys %{$vm_errors{warning}}))); + } + if (scalar(keys %{$vm_errors{critical}}) > 0) { + $self->{output}->output_add(severity => 'CRITICAL', + short_msg => sprintf('Snapshots for VM older than %d days: [%s]', ($self->{critical} / 86400), + join('] [', sort keys %{$vm_errors{critical}}))); + } + if (scalar(keys %vm_consolidate) > 0) { + $self->{output}->output_add(severity => 'CRITICAL', + short_msg => sprintf('VMs need consolidation: [%s]', + join('] [', sort keys %vm_consolidate))); + } + + $self->{output}->display(); + $self->{output}->exit(); } 1; @@ -112,6 +193,14 @@ Search in following cluster(s) (can be a regexp). Search in following host(s) (can be a regexp). +=item B<--display-description> + +Display virtual machine description. + +=item B<--check-consolidation> + +Check if VM needs consolidation (since vsphere 5.0). + =item B<--disconnect-status> Status if VM disconnected (default: 'unknown'). @@ -120,10 +209,6 @@ Status if VM disconnected (default: 'unknown'). Skip check if VM is not poweredOn. -=item B<--display-description> - -Display virtual machine description. - =item B<--warning> Threshold warning in seconds. @@ -132,10 +217,6 @@ Threshold warning in seconds. Threshold critical in seconds. -=item B<--check-consolidation> - -Check if VM needs consolidation (since vsphere 5.0). - =back =cut