(plugin) storage::emc::vplex::restapi - handle api v2 (#3880)
This commit is contained in:
parent
3c8e83fb1e
commit
7d8c202d41
|
@ -0,0 +1,325 @@
|
||||||
|
#
|
||||||
|
# Copyright 2022 Centreon (http://www.centreon.com/)
|
||||||
|
#
|
||||||
|
# Centreon is a full-fledged industry-strength solution that meets
|
||||||
|
# the needs in IT infrastructure and application monitoring for
|
||||||
|
# service performance.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
#
|
||||||
|
|
||||||
|
package storage::emc::vplex::restapi::custom::apiv1;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use centreon::plugins::http;
|
||||||
|
use JSON::XS;
|
||||||
|
|
||||||
|
sub new {
|
||||||
|
my ($class, %options) = @_;
|
||||||
|
my $self = {};
|
||||||
|
bless $self, $class;
|
||||||
|
|
||||||
|
if (!defined($options{output})) {
|
||||||
|
print "Class Custom: Need to specify 'output' argument.\n";
|
||||||
|
exit 3;
|
||||||
|
}
|
||||||
|
if (!defined($options{options})) {
|
||||||
|
$options{output}->add_option_msg(short_msg => "Class Custom: Need to specify 'options' argument.");
|
||||||
|
$options{output}->option_exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!defined($options{noptions})) {
|
||||||
|
$options{options}->add_options(arguments => {
|
||||||
|
'hostname:s' => { name => 'hostname' },
|
||||||
|
'port:s' => { name => 'port' },
|
||||||
|
'proto:s' => { name => 'proto' },
|
||||||
|
'vplex-username:s' => { name => 'vplex_username' },
|
||||||
|
'vplex-password:s' => { name => 'vplex_password' },
|
||||||
|
'timeout:s' => { name => 'timeout' }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
$options{options}->add_help(package => __PACKAGE__, sections => 'REST API V1 OPTIONS', once => 1);
|
||||||
|
|
||||||
|
$self->{output} = $options{output};
|
||||||
|
$self->{http} = centreon::plugins::http->new(%options);
|
||||||
|
|
||||||
|
return $self;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub set_options {
|
||||||
|
my ($self, %options) = @_;
|
||||||
|
|
||||||
|
$self->{option_results} = $options{option_results};
|
||||||
|
}
|
||||||
|
|
||||||
|
sub set_defaults {}
|
||||||
|
|
||||||
|
sub check_options {
|
||||||
|
my ($self, %options) = @_;
|
||||||
|
|
||||||
|
$self->{hostname} = defined($self->{option_results}->{hostname}) ? $self->{option_results}->{hostname} : '';
|
||||||
|
$self->{port} = defined($self->{option_results}->{port}) ? $self->{option_results}->{port} : 443;
|
||||||
|
$self->{proto} = defined($self->{option_results}->{proto}) ? $self->{option_results}->{proto} : 'https';
|
||||||
|
$self->{vplex_username} = defined($self->{option_results}->{vplex_username}) ? $self->{option_results}->{vplex_username} : '';
|
||||||
|
$self->{vplex_password} = defined($self->{option_results}->{vplex_password}) ? $self->{option_results}->{vplex_password} : '';
|
||||||
|
$self->{timeout} = defined($self->{option_results}->{timeout}) ? $self->{option_results}->{timeout} : 30;
|
||||||
|
|
||||||
|
if ($self->{hostname} eq '') {
|
||||||
|
$self->{output}->add_option_msg(short_msg => "Need to specify --hostname option.");
|
||||||
|
$self->{output}->option_exit();
|
||||||
|
}
|
||||||
|
if ($self->{vplex_username} eq '') {
|
||||||
|
$self->{output}->add_option_msg(short_msg => "Need to specify --vplex-username option.");
|
||||||
|
$self->{output}->option_exit();
|
||||||
|
}
|
||||||
|
if ($self->{vplex_password} eq '') {
|
||||||
|
$self->{output}->add_option_msg(short_msg => "Need to specify --vplex-password option.");
|
||||||
|
$self->{output}->option_exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub build_options_for_httplib {
|
||||||
|
my ($self, %options) = @_;
|
||||||
|
|
||||||
|
$self->{option_results}->{hostname} = $self->{hostname};
|
||||||
|
$self->{option_results}->{timeout} = $self->{timeout};
|
||||||
|
$self->{option_results}->{port} = $self->{port};
|
||||||
|
$self->{option_results}->{proto} = $self->{proto};
|
||||||
|
}
|
||||||
|
|
||||||
|
sub settings {
|
||||||
|
my ($self, %options) = @_;
|
||||||
|
|
||||||
|
$self->build_options_for_httplib();
|
||||||
|
$self->{http}->add_header(key => 'Username', value => $self->{vplex_username});
|
||||||
|
$self->{http}->add_header(key => 'Password', value => $self->{vplex_password});
|
||||||
|
$self->{http}->set_options(%{$self->{option_results}});
|
||||||
|
}
|
||||||
|
|
||||||
|
sub request_api {
|
||||||
|
my ($self, %options) = @_;
|
||||||
|
|
||||||
|
$self->settings();
|
||||||
|
|
||||||
|
my $content = $self->{http}->request(url_path => $options{endpoint});
|
||||||
|
|
||||||
|
my $decoded;
|
||||||
|
eval {
|
||||||
|
$decoded = JSON::XS->new->utf8->decode($content);
|
||||||
|
};
|
||||||
|
if ($@) {
|
||||||
|
$self->{output}->add_option_msg(short_msg => "Cannot decode json response");
|
||||||
|
$self->{output}->option_exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $decoded;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub get_cluster_communication {
|
||||||
|
my ($self, %options) = @_;
|
||||||
|
|
||||||
|
my $items = $self->request_api(endpoint => '/vplex/cluster-witness/components/*');
|
||||||
|
|
||||||
|
my $results = [];
|
||||||
|
foreach my $context (@{$items->{response}->{context}}) {
|
||||||
|
my $entry = {};
|
||||||
|
foreach my $attribute (@{$context->{attributes}}) {
|
||||||
|
$attribute->{name} =~ s/-/_/g;
|
||||||
|
$entry->{ $attribute->{name} } = $attribute->{value};
|
||||||
|
}
|
||||||
|
|
||||||
|
push @$results, $entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $results;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub get_distributed_devices {
|
||||||
|
my ($self, %options) = @_;
|
||||||
|
|
||||||
|
my $items = $self->request_api(endpoint => '/vplex/distributed-storage/distributed-devices/*');
|
||||||
|
|
||||||
|
my $results = [];
|
||||||
|
foreach my $context (@{$items->{response}->{context}}) {
|
||||||
|
my $entry = {};
|
||||||
|
foreach my $attribute (@{$context->{attributes}}) {
|
||||||
|
$attribute->{name} =~ s/-/_/g;
|
||||||
|
$entry->{ $attribute->{name} } = $attribute->{value};
|
||||||
|
}
|
||||||
|
|
||||||
|
push @$results, $entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $results;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub get_storage_volumes {
|
||||||
|
my ($self, %options) = @_;
|
||||||
|
|
||||||
|
my $items = $self->request_api(endpoint => '/vplex/clusters/*/storage-elements/storage-volumes/*');
|
||||||
|
|
||||||
|
my $results = [];
|
||||||
|
foreach my $context (@{$items->{response}->{context}}) {
|
||||||
|
my $entry = {};
|
||||||
|
foreach my $attribute (@{$context->{attributes}}) {
|
||||||
|
$attribute->{name} =~ s/-/_/g;
|
||||||
|
$entry->{ $attribute->{name} } = $attribute->{value};
|
||||||
|
}
|
||||||
|
my $cluster_name = 'unknown';
|
||||||
|
$cluster_name = $1 if ($context->{parent} =~ /^\/clusters\/(.*?)\//);
|
||||||
|
$entry->{cluster_name} = $cluster_name;
|
||||||
|
|
||||||
|
push @$results, $entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $results;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub get_devices {
|
||||||
|
my ($self, %options) = @_;
|
||||||
|
|
||||||
|
my $items = $self->request_api(endpoint => '/vplex/clusters/*/devices/*');
|
||||||
|
|
||||||
|
my $results = [];
|
||||||
|
foreach my $context (@{$items->{response}->{context}}) {
|
||||||
|
my $entry = {};
|
||||||
|
foreach my $attribute (@{$context->{attributes}}) {
|
||||||
|
$attribute->{name} =~ s/-/_/g;
|
||||||
|
$entry->{ $attribute->{name} } = $attribute->{value};
|
||||||
|
}
|
||||||
|
my $cluster_name = 'unknown';
|
||||||
|
$cluster_name = $1 if ($context->{parent} =~ /^\/clusters\/(.*?)\//);
|
||||||
|
$entry->{cluster_name} = $cluster_name;
|
||||||
|
|
||||||
|
push @$results, $entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $results;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub get_fans {
|
||||||
|
my ($self, %options) = @_;
|
||||||
|
|
||||||
|
my $items = $self->request_api(endpoint => '/vplex/engines/*/fans/*');
|
||||||
|
|
||||||
|
my $results = [];
|
||||||
|
foreach my $context (@{$items->{response}->{context}}) {
|
||||||
|
my $entry = {};
|
||||||
|
foreach my $attribute (@{$context->{attributes}}) {
|
||||||
|
$attribute->{name} =~ s/-/_/g;
|
||||||
|
$entry->{ $attribute->{name} } = $attribute->{value};
|
||||||
|
}
|
||||||
|
my $engine_name = 'unknown';
|
||||||
|
$engine_name = $1 if ($context->{parent} =~ /^\/engines\/engine-(.*?)\//);
|
||||||
|
$entry->{engine_id} = $engine_name;
|
||||||
|
|
||||||
|
push @$results, $entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $results;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub get_psus {
|
||||||
|
my ($self, %options) = @_;
|
||||||
|
|
||||||
|
my $items = $self->request_api(endpoint => '/vplex/engines/*/power-supplies/*');
|
||||||
|
|
||||||
|
my $results = [];
|
||||||
|
foreach my $context (@{$items->{response}->{context}}) {
|
||||||
|
my $entry = {};
|
||||||
|
foreach my $attribute (@{$context->{attributes}}) {
|
||||||
|
$attribute->{name} =~ s/-/_/g;
|
||||||
|
$entry->{ $attribute->{name} } = $attribute->{value};
|
||||||
|
}
|
||||||
|
my $engine_name = 'unknown';
|
||||||
|
$engine_name = $1 if ($context->{parent} =~ /^\/engines\/engine-(.*?)\//);
|
||||||
|
$entry->{engine_id} = $engine_name;
|
||||||
|
|
||||||
|
push @$results, $entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $results;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub get_directors {
|
||||||
|
my ($self, %options) = @_;
|
||||||
|
|
||||||
|
my $items = $self->request_api(endpoint => '/vplex/engines/*/directors/*');
|
||||||
|
|
||||||
|
my $results = [];
|
||||||
|
foreach my $context (@{$items->{response}->{context}}) {
|
||||||
|
my $entry = {};
|
||||||
|
foreach my $attribute (@{$context->{attributes}}) {
|
||||||
|
$attribute->{name} =~ s/-/_/g;
|
||||||
|
$entry->{ $attribute->{name} } = $attribute->{value};
|
||||||
|
}
|
||||||
|
my $engine_name = 'unknown';
|
||||||
|
$engine_name = $1 if ($context->{parent} =~ /^\/engines\/engine-(.*?)\//);
|
||||||
|
$entry->{engine_id} = $engine_name;
|
||||||
|
|
||||||
|
push @$results, $entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $results;
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
||||||
|
|
||||||
|
__END__
|
||||||
|
|
||||||
|
=head1 NAME
|
||||||
|
|
||||||
|
VPLEX REST API V1
|
||||||
|
|
||||||
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
|
Vplex rest api v1
|
||||||
|
|
||||||
|
=head1 REST API V1 OPTIONS
|
||||||
|
|
||||||
|
=over 8
|
||||||
|
|
||||||
|
=item B<--hostname>
|
||||||
|
|
||||||
|
Hostname.
|
||||||
|
|
||||||
|
=item B<--port>
|
||||||
|
|
||||||
|
Port used (Default: 443)
|
||||||
|
|
||||||
|
=item B<--proto>
|
||||||
|
|
||||||
|
Specify https if needed (Default: 'https')
|
||||||
|
|
||||||
|
=item B<--vplex-username>
|
||||||
|
|
||||||
|
API Username.
|
||||||
|
|
||||||
|
=item B<--vplex-password>
|
||||||
|
|
||||||
|
API Password.
|
||||||
|
|
||||||
|
=item B<--timeout>
|
||||||
|
|
||||||
|
Set HTTP timeout
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
|
B<custom>.
|
||||||
|
|
||||||
|
=cut
|
|
@ -0,0 +1,363 @@
|
||||||
|
#
|
||||||
|
# Copyright 2022 Centreon (http://www.centreon.com/)
|
||||||
|
#
|
||||||
|
# Centreon is a full-fledged industry-strength solution that meets
|
||||||
|
# the needs in IT infrastructure and application monitoring for
|
||||||
|
# service performance.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
# Authors : Roman Morandell - ivertix
|
||||||
|
#
|
||||||
|
|
||||||
|
package storage::emc::vplex::restapi::custom::apiv2;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
use centreon::plugins::http;
|
||||||
|
use centreon::plugins::statefile;
|
||||||
|
use JSON::XS;
|
||||||
|
use Digest::MD5 qw(md5_hex);
|
||||||
|
|
||||||
|
sub new {
|
||||||
|
my ($class, %options) = @_;
|
||||||
|
my $self = {};
|
||||||
|
bless $self, $class;
|
||||||
|
|
||||||
|
if (!defined($options{output})) {
|
||||||
|
print "Class Custom: Need to specify 'output' argument.\n";
|
||||||
|
exit 3;
|
||||||
|
}
|
||||||
|
if (!defined($options{options})) {
|
||||||
|
$options{output}->add_option_msg(short_msg => "Class Custom: Need to specify 'options' argument.");
|
||||||
|
$options{output}->option_exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!defined($options{noptions})) {
|
||||||
|
$options{options}->add_options(arguments => {
|
||||||
|
'hostname:s' => { name => 'hostname' },
|
||||||
|
'port:s' => { name => 'port' },
|
||||||
|
'proto:s' => { name => 'proto' },
|
||||||
|
'vplex-username:s' => { name => 'vplex_username' },
|
||||||
|
'vplex-password:s' => { name => 'vplex_password' },
|
||||||
|
'timeout:s' => { name => 'timeout' }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
$options{options}->add_help(package => __PACKAGE__, sections => 'REST API V2 OPTIONS', once => 1);
|
||||||
|
|
||||||
|
$self->{output} = $options{output};
|
||||||
|
$self->{http} = centreon::plugins::http->new(%options);
|
||||||
|
$self->{cache} = centreon::plugins::statefile->new(%options);
|
||||||
|
|
||||||
|
return $self;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub set_options {
|
||||||
|
my ($self, %options) = @_;
|
||||||
|
|
||||||
|
$self->{option_results} = $options{option_results};
|
||||||
|
}
|
||||||
|
|
||||||
|
sub set_defaults {}
|
||||||
|
|
||||||
|
sub check_options {
|
||||||
|
my ($self, %options) = @_;
|
||||||
|
|
||||||
|
$self->{hostname} = (defined($self->{option_results}->{hostname})) ? $self->{option_results}->{hostname} : '';
|
||||||
|
$self->{proto} = (defined($self->{option_results}->{proto})) ? $self->{option_results}->{proto} : 'https';
|
||||||
|
$self->{port} = (defined($self->{option_results}->{port})) ? $self->{option_results}->{port} : 443;
|
||||||
|
$self->{api_username} = defined($self->{option_results}->{vplex_username}) ? $self->{option_results}->{vplex_username} : '';
|
||||||
|
$self->{api_password} = defined($self->{option_results}->{vplex_password}) ? $self->{option_results}->{vplex_password} : '';
|
||||||
|
$self->{timeout} = (defined($self->{option_results}->{timeout})) ? $self->{option_results}->{timeout} : 10;
|
||||||
|
|
||||||
|
if ($self->{hostname} eq '') {
|
||||||
|
$self->{output}->add_option_msg(short_msg => 'Need to specify hostname option.');
|
||||||
|
$self->{output}->option_exit();
|
||||||
|
}
|
||||||
|
if ($self->{api_username} eq '') {
|
||||||
|
$self->{output}->add_option_msg(short_msg => "Need to specify --api-username option.");
|
||||||
|
$self->{output}->option_exit();
|
||||||
|
}
|
||||||
|
if ($self->{api_password} eq '') {
|
||||||
|
$self->{output}->add_option_msg(short_msg => "Need to specify --api-password option.");
|
||||||
|
$self->{output}->option_exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
$self->{cache}->check_options(option_results => $self->{option_results});
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub get_connection_infos {
|
||||||
|
my ($self, %options) = @_;
|
||||||
|
|
||||||
|
return $self->{hostname} . '_' . $self->{http}->get_port();
|
||||||
|
}
|
||||||
|
|
||||||
|
sub get_hostname {
|
||||||
|
my ($self, %options) = @_;
|
||||||
|
|
||||||
|
return $self->{hostname};
|
||||||
|
}
|
||||||
|
|
||||||
|
sub get_port {
|
||||||
|
my ($self, %options) = @_;
|
||||||
|
|
||||||
|
return $self->{port};
|
||||||
|
}
|
||||||
|
|
||||||
|
sub json_decode {
|
||||||
|
my ($self, %options) = @_;
|
||||||
|
|
||||||
|
my $decoded;
|
||||||
|
eval {
|
||||||
|
$decoded = JSON::XS->new->utf8->decode($options{content});
|
||||||
|
};
|
||||||
|
if ($@) {
|
||||||
|
$self->{output}->add_option_msg(short_msg => "Cannot decode json response: $@");
|
||||||
|
$self->{output}->option_exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $decoded;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub build_options_for_httplib {
|
||||||
|
my ($self, %options) = @_;
|
||||||
|
|
||||||
|
$self->{option_results}->{port} = $self->{port};
|
||||||
|
$self->{option_results}->{proto} = $self->{proto};
|
||||||
|
}
|
||||||
|
|
||||||
|
sub settings {
|
||||||
|
my ($self, %options) = @_;
|
||||||
|
|
||||||
|
$self->build_options_for_httplib();
|
||||||
|
$self->{http}->add_header(key => 'Accept', value => 'application/json');
|
||||||
|
$self->{http}->set_options(%{$self->{option_results}});
|
||||||
|
}
|
||||||
|
|
||||||
|
sub clean_token {
|
||||||
|
my ($self, %options) = @_;
|
||||||
|
|
||||||
|
my $datas = {};
|
||||||
|
$self->{cache}->write(data => $datas);
|
||||||
|
$self->{access_token} = undef;
|
||||||
|
$self->{http}->add_header(key => 'Authorization', value => undef);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub get_auth_token {
|
||||||
|
my ($self, %options) = @_;
|
||||||
|
|
||||||
|
my $has_cache_file = $self->{cache}->read(statefile => 'emc_vplex_api_' . md5_hex($self->{option_results}->{hostname}) . '_' . md5_hex($self->{api_username}));
|
||||||
|
my $access_token = $self->{cache}->get(name => 'access_token');
|
||||||
|
my $expires_on = $self->{cache}->get(name => 'expires_on');
|
||||||
|
my $md5_secret_cache = $self->{cache}->get(name => 'md5_secret');
|
||||||
|
my $md5_secret = md5_hex($self->{api_username} . $self->{api_password});
|
||||||
|
|
||||||
|
if ($has_cache_file == 0 || !defined($access_token) || (time() > $expires_on) ||
|
||||||
|
(defined($md5_secret_cache) && $md5_secret_cache ne $md5_secret)) {
|
||||||
|
my ($content) = $self->{http}->request(
|
||||||
|
method => 'POST',
|
||||||
|
hostname => $self->{hostname},
|
||||||
|
url_path => '/vplex/v2/token',
|
||||||
|
credentials => 1,
|
||||||
|
basic => 1,
|
||||||
|
username => $self->{api_username},
|
||||||
|
password => $self->{api_password},
|
||||||
|
warning_status => '',
|
||||||
|
unknown_status => '',
|
||||||
|
critical_status => ''
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($self->{http}->get_code() != 200) {
|
||||||
|
$self->{output}->add_option_msg(short_msg => "Authentication error [code: '" . $self->{http}->get_code() . "'] [message: '" . $self->{http}->get_message() . "']");
|
||||||
|
$self->{output}->option_exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
my $decoded = $self->json_decode(content => $content);
|
||||||
|
if (!defined($decoded->{access_token})) {
|
||||||
|
$self->{output}->add_option_msg(short_msg => "Cannot get token");
|
||||||
|
$self->{output}->option_exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
$access_token = $decoded->{token};
|
||||||
|
my $datas = {
|
||||||
|
access_token => $access_token,
|
||||||
|
expires_on => time() + $decoded->{expiry},
|
||||||
|
md5_secret => $md5_secret
|
||||||
|
};
|
||||||
|
$options{statefile}->write(data => $datas);
|
||||||
|
}
|
||||||
|
|
||||||
|
$self->{access_token} = $access_token;
|
||||||
|
$self->{http}->add_header(key => 'Authorization', value => 'Bearer ' . $self->{access_token});
|
||||||
|
}
|
||||||
|
|
||||||
|
sub request_api {
|
||||||
|
my ($self, %options) = @_;
|
||||||
|
|
||||||
|
$self->settings();
|
||||||
|
if (!defined($self->{access_token})) {
|
||||||
|
$self->get_auth_token();
|
||||||
|
}
|
||||||
|
|
||||||
|
my $content = $self->{http}->request(
|
||||||
|
method => 'GET',
|
||||||
|
hostname => $self->{hostname},
|
||||||
|
url_path => $options{endpoint},
|
||||||
|
get_param => $options{get_param},
|
||||||
|
warning_status => '',
|
||||||
|
unknown_status => '',
|
||||||
|
critical_status => ''
|
||||||
|
);
|
||||||
|
|
||||||
|
# Maybe there is an issue with the token. So we retry.
|
||||||
|
if ($self->{http}->get_code() < 200 || $self->{http}->get_code() >= 300) {
|
||||||
|
$self->clean_token();
|
||||||
|
$self->get_auth_token();
|
||||||
|
$content = $self->{http}->request(
|
||||||
|
method => 'GET',
|
||||||
|
hostname => $self->{hostname},
|
||||||
|
url_path => $options{endpoint},
|
||||||
|
get_param => $options{get_param},
|
||||||
|
warning_status => '', unknown_status => '', critical_status => ''
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($self->{http}->get_code() < 200 || $self->{http}->get_code() >= 300) {
|
||||||
|
$self->{output}->add_option_msg(short_msg => "API returns empty content [code: '" . $self->{http}->get_code() . "'] [message: '" . $self->{http}->get_message() . "']");
|
||||||
|
$self->{output}->option_exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
my $decoded = $self->json_decode(content => $content);
|
||||||
|
if (!defined($decoded)) {
|
||||||
|
$self->{output}->add_option_msg(short_msg => 'Error while retrieving data (add --debug option for detailed message)');
|
||||||
|
$self->{output}->option_exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $decoded;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub get_cluster_communication {
|
||||||
|
my ($self, %options) = @_;
|
||||||
|
|
||||||
|
my $items = $self->request_api(endpoint => '/vplex/v2/cluster_witness');
|
||||||
|
|
||||||
|
return $items->{components};
|
||||||
|
}
|
||||||
|
|
||||||
|
sub get_storage_volumes {
|
||||||
|
my ($self, %options) = @_;
|
||||||
|
|
||||||
|
my $clusters = $self->request_api(endpoint => '/vplex/v2/clusters');
|
||||||
|
|
||||||
|
my $results = [];
|
||||||
|
foreach my $cluster (@$clusters) {
|
||||||
|
my $items = $self->request_api(endpoint => '/vplex/v2/clusters/' . $cluster->{name} . '/storage_volumes');
|
||||||
|
foreach my $item (@$items) {
|
||||||
|
$item->{cluster_name} = $cluster->{name};
|
||||||
|
push @$results, $item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $results;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub get_devices {
|
||||||
|
my ($self, %options) = @_;
|
||||||
|
|
||||||
|
my $clusters = $self->request_api(endpoint => '/vplex/v2/clusters');
|
||||||
|
|
||||||
|
my $results = [];
|
||||||
|
foreach my $cluster (@$clusters) {
|
||||||
|
my $items = $self->request_api(endpoint => '/vplex/v2/clusters/' . $cluster->{name} . '/devices');
|
||||||
|
foreach my $item (@$items) {
|
||||||
|
$item->{cluster_name} = $cluster->{name};
|
||||||
|
push @$results, $item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $results;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub get_fans {
|
||||||
|
my ($self, %options) = @_;
|
||||||
|
|
||||||
|
$self->{output}->add_option_msg(short_msg => 'fans information unsupported by rest api v2');
|
||||||
|
$self->{output}->option_exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
sub get_psus {
|
||||||
|
my ($self, %options) = @_;
|
||||||
|
|
||||||
|
$self->{output}->add_option_msg(short_msg => 'power supplies information unsupported by rest api v2');
|
||||||
|
$self->{output}->option_exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
sub get_directors {
|
||||||
|
my ($self, %options) = @_;
|
||||||
|
|
||||||
|
return $self->request_api(endpoint => '/vplex/v2/directors');
|
||||||
|
}
|
||||||
|
|
||||||
|
sub get_distributed_devices {
|
||||||
|
my ($self, %options) = @_;
|
||||||
|
|
||||||
|
return $self->request_api(endpoint => '/vplex/v2/distributed_storage/distributed_devices');
|
||||||
|
}
|
||||||
|
|
||||||
|
1;
|
||||||
|
|
||||||
|
__END__
|
||||||
|
|
||||||
|
=head1 NAME
|
||||||
|
|
||||||
|
VPLEX REST API V2
|
||||||
|
|
||||||
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
|
Vplex rest api v2
|
||||||
|
|
||||||
|
=head1 REST API V2 OPTIONS
|
||||||
|
|
||||||
|
=over 8
|
||||||
|
|
||||||
|
=item B<--hostname>
|
||||||
|
|
||||||
|
API hostname.
|
||||||
|
|
||||||
|
=item B<--port>
|
||||||
|
|
||||||
|
API port (Default: 443)
|
||||||
|
|
||||||
|
=item B<--proto>
|
||||||
|
|
||||||
|
Specify https if needed (Default: 'https')
|
||||||
|
|
||||||
|
=item B<--vplex-username>
|
||||||
|
|
||||||
|
API Username.
|
||||||
|
|
||||||
|
=item B<--vplex-password>
|
||||||
|
|
||||||
|
API Password.
|
||||||
|
|
||||||
|
=item B<--timeout>
|
||||||
|
|
||||||
|
Set HTTP timeout
|
||||||
|
|
||||||
|
=back
|
||||||
|
|
||||||
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
|
B<custom>.
|
||||||
|
|
||||||
|
=cut
|
|
@ -1,198 +0,0 @@
|
||||||
#
|
|
||||||
# Copyright 2022 Centreon (http://www.centreon.com/)
|
|
||||||
#
|
|
||||||
# Centreon is a full-fledged industry-strength solution that meets
|
|
||||||
# the needs in IT infrastructure and application monitoring for
|
|
||||||
# service performance.
|
|
||||||
#
|
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
# you may not use this file except in compliance with the License.
|
|
||||||
# You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
# See the License for the specific language governing permissions and
|
|
||||||
# limitations under the License.
|
|
||||||
#
|
|
||||||
|
|
||||||
package storage::emc::vplex::restapi::custom::vplexapi;
|
|
||||||
|
|
||||||
use strict;
|
|
||||||
use warnings;
|
|
||||||
use centreon::plugins::http;
|
|
||||||
use JSON;
|
|
||||||
|
|
||||||
sub new {
|
|
||||||
my ($class, %options) = @_;
|
|
||||||
my $self = {};
|
|
||||||
bless $self, $class;
|
|
||||||
|
|
||||||
if (!defined($options{output})) {
|
|
||||||
print "Class Custom: Need to specify 'output' argument.\n";
|
|
||||||
exit 3;
|
|
||||||
}
|
|
||||||
if (!defined($options{options})) {
|
|
||||||
$options{output}->add_option_msg(short_msg => "Class Custom: Need to specify 'options' argument.");
|
|
||||||
$options{output}->option_exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!defined($options{noptions})) {
|
|
||||||
$options{options}->add_options(arguments => {
|
|
||||||
'hostname:s@' => { name => 'hostname' },
|
|
||||||
'vplex-username:s@' => { name => 'vplex_username' },
|
|
||||||
'vplex-password:s@' => { name => 'vplex_password' },
|
|
||||||
'timeout:s@' => { name => 'timeout' },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
$options{options}->add_help(package => __PACKAGE__, sections => 'REST API OPTIONS', once => 1);
|
|
||||||
|
|
||||||
$self->{output} = $options{output};
|
|
||||||
$self->{http} = centreon::plugins::http->new(%options);
|
|
||||||
|
|
||||||
return $self;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub set_options {
|
|
||||||
my ($self, %options) = @_;
|
|
||||||
|
|
||||||
$self->{option_results} = $options{option_results};
|
|
||||||
}
|
|
||||||
|
|
||||||
sub set_defaults {}
|
|
||||||
|
|
||||||
sub check_options {
|
|
||||||
my ($self, %options) = @_;
|
|
||||||
|
|
||||||
$self->{hostname} = (defined($self->{option_results}->{hostname})) ? shift(@{$self->{option_results}->{hostname}}) : undef;
|
|
||||||
$self->{vplex_username} = (defined($self->{option_results}->{vplex_username})) ? shift(@{$self->{option_results}->{vplex_username}}) : '';
|
|
||||||
$self->{vplex_password} = (defined($self->{option_results}->{vplex_password})) ? shift(@{$self->{option_results}->{vplex_password}}) : '';
|
|
||||||
$self->{timeout} = (defined($self->{option_results}->{timeout})) ? shift(@{$self->{option_results}->{timeout}}) : 30;
|
|
||||||
|
|
||||||
if (!defined($self->{hostname})) {
|
|
||||||
$self->{output}->add_option_msg(short_msg => "Need to specify hostname option.");
|
|
||||||
$self->{output}->option_exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!defined($self->{hostname}) ||
|
|
||||||
scalar(@{$self->{option_results}->{hostname}}) == 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub build_options_for_httplib {
|
|
||||||
my ($self, %options) = @_;
|
|
||||||
|
|
||||||
$self->{option_results}->{hostname} = $self->{hostname};
|
|
||||||
$self->{option_results}->{timeout} = $self->{timeout};
|
|
||||||
$self->{option_results}->{port} = 443;
|
|
||||||
$self->{option_results}->{proto} = 'https';
|
|
||||||
}
|
|
||||||
|
|
||||||
sub settings {
|
|
||||||
my ($self, %options) = @_;
|
|
||||||
|
|
||||||
$self->build_options_for_httplib();
|
|
||||||
$self->{http}->add_header(key => 'Username', value => $self->{vplex_username});
|
|
||||||
$self->{http}->add_header(key => 'Password', value => $self->{vplex_password});
|
|
||||||
$self->{http}->set_options(%{$self->{option_results}});
|
|
||||||
}
|
|
||||||
|
|
||||||
sub get_items {
|
|
||||||
my ($self, %options) = @_;
|
|
||||||
|
|
||||||
$self->settings();
|
|
||||||
|
|
||||||
if (defined($options{parent})) {
|
|
||||||
if (defined($options{parent_filter}) && $options{parent_filter} ne '') {
|
|
||||||
if ($options{parent_filter} =~ /^[0-9\-]+$/) {
|
|
||||||
$options{url} .= $options{parent_filter_prefix} . $options{parent_filter} . '/';
|
|
||||||
} else {
|
|
||||||
$options{url} .= $options{parent_filter} . '/';
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$options{url} .= '*' . '/';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (defined($options{obj}) && $options{obj} ne '') {
|
|
||||||
$options{url} .= $options{obj} . '/';
|
|
||||||
}
|
|
||||||
$options{url} .= '*';
|
|
||||||
|
|
||||||
my $response = $self->{http}->request(url_path => $options{url});
|
|
||||||
my $decoded;
|
|
||||||
eval {
|
|
||||||
$decoded = decode_json($response);
|
|
||||||
};
|
|
||||||
if ($@) {
|
|
||||||
$self->{output}->add_option_msg(short_msg => "Cannot decode json response");
|
|
||||||
$self->{output}->option_exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
my $items = {};
|
|
||||||
foreach my $context (@{$decoded->{response}->{context}}) {
|
|
||||||
my $engine_name;
|
|
||||||
|
|
||||||
if (defined($options{parent})) {
|
|
||||||
$context->{parent} =~ /$options{parent_select}/;
|
|
||||||
$engine_name = $1;
|
|
||||||
$items->{$engine_name} = {} if (!defined($items->{$engine_name}));
|
|
||||||
}
|
|
||||||
|
|
||||||
my $attributes = {};
|
|
||||||
foreach my $attribute (@{$context->{attributes}}) {
|
|
||||||
$attributes->{ $attribute->{name} } = $attribute->{value};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (defined($engine_name)) {
|
|
||||||
$items->{$engine_name}->{ $attributes->{name} } = $attributes;
|
|
||||||
} else {
|
|
||||||
$items->{ $attributes->{name} } = $attributes;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $items;
|
|
||||||
}
|
|
||||||
|
|
||||||
1;
|
|
||||||
|
|
||||||
__END__
|
|
||||||
|
|
||||||
=head1 NAME
|
|
||||||
|
|
||||||
VPLEX REST API
|
|
||||||
|
|
||||||
=head1 SYNOPSIS
|
|
||||||
|
|
||||||
Vplex Rest API custom mode
|
|
||||||
|
|
||||||
=head1 REST API OPTIONS
|
|
||||||
|
|
||||||
=over 8
|
|
||||||
|
|
||||||
=item B<--hostname>
|
|
||||||
|
|
||||||
Vplex hostname.
|
|
||||||
|
|
||||||
=item B<--vplex-username>
|
|
||||||
|
|
||||||
Vplex username.
|
|
||||||
|
|
||||||
=item B<--vplex-password>
|
|
||||||
|
|
||||||
Vplex password.
|
|
||||||
|
|
||||||
=item B<--timeout>
|
|
||||||
|
|
||||||
Set HTTP timeout
|
|
||||||
|
|
||||||
=back
|
|
||||||
|
|
||||||
=head1 DESCRIPTION
|
|
||||||
|
|
||||||
B<custom>.
|
|
||||||
|
|
||||||
=cut
|
|
|
@ -20,140 +20,70 @@
|
||||||
|
|
||||||
package storage::emc::vplex::restapi::mode::clustercommunication;
|
package storage::emc::vplex::restapi::mode::clustercommunication;
|
||||||
|
|
||||||
use base qw(centreon::plugins::mode);
|
use base qw(centreon::plugins::templates::counter);
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold_ng);
|
||||||
|
|
||||||
my $thresholds = {
|
sub custom_status_output {
|
||||||
component_opstatus => [
|
my ($self, %options) = @_;
|
||||||
['cluster-in-contact', 'OK'],
|
|
||||||
['in-contact', 'OK'],
|
return sprintf(
|
||||||
['.*', 'CRITICAL']
|
'operational state: %s [admin: %s]',
|
||||||
]
|
$self->{result_values}->{operational_state},
|
||||||
};
|
$self->{result_values}->{admin_state}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub prefix_component_output {
|
||||||
|
my ($self, %options) = @_;
|
||||||
|
|
||||||
|
return "Cluster witness component '" . $options{instance_value}->{name} . "' ";
|
||||||
|
}
|
||||||
|
|
||||||
|
sub set_counters {
|
||||||
|
my ($self, %options) = @_;
|
||||||
|
|
||||||
|
$self->{maps_counters_type} = [
|
||||||
|
{ name => 'components', type => 1, cb_prefix_output => 'prefix_component_output', message_multiple => 'All cluster witness components are ok' }
|
||||||
|
];
|
||||||
|
|
||||||
|
$self->{maps_counters}->{components} = [
|
||||||
|
{ label => 'operational-status', type => 2, critical_default => '%{admin_state} eq "enabled" and %{operational_state} !~ /cluster-in-contact|in-contact/i', set => {
|
||||||
|
key_values => [ { name => 'operational_state' }, { name => 'admin_state' }, { name => 'name' } ],
|
||||||
|
closure_custom_output => $self->can('custom_status_output'),
|
||||||
|
closure_custom_perfdata => sub { return 0; },
|
||||||
|
closure_custom_threshold_check => \&catalog_status_threshold_ng
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
sub new {
|
sub new {
|
||||||
my ($class, %options) = @_;
|
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;
|
bless $self, $class;
|
||||||
|
|
||||||
$options{options}->add_options(arguments => {
|
$options{options}->add_options(arguments => {
|
||||||
'filter:s@' => { name => 'filter' },
|
'filter-component-name:s' => { name => 'filter_component_name' }
|
||||||
'threshold-overload:s@' => { name => 'threshold_overload' }
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return $self;
|
return $self;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub check_options {
|
sub manage_selection {
|
||||||
my ($self, %options) = @_;
|
|
||||||
$self->SUPER::init(%options);
|
|
||||||
|
|
||||||
$self->{filter} = [];
|
|
||||||
foreach my $val (@{$self->{option_results}->{filter}}) {
|
|
||||||
next if (!defined($val) || $val eq '');
|
|
||||||
my @values = split (/,/, $val);
|
|
||||||
push @{$self->{filter}}, { filter => $values[0], instance => $values[1] };
|
|
||||||
}
|
|
||||||
|
|
||||||
$self->{overload_th} = {};
|
|
||||||
foreach my $val (@{$self->{option_results}->{threshold_overload}}) {
|
|
||||||
next if (!defined($val) || $val eq '');
|
|
||||||
my @values = split (/,/, $val);
|
|
||||||
if (scalar(@values) < 3) {
|
|
||||||
$self->{output}->add_option_msg(short_msg => "Wrong threshold-overload option '" . $val . "'.");
|
|
||||||
$self->{output}->option_exit();
|
|
||||||
}
|
|
||||||
my ($section, $instance, $status, $filter);
|
|
||||||
if (scalar(@values) == 3) {
|
|
||||||
($section, $status, $filter) = @values;
|
|
||||||
$instance = '.*';
|
|
||||||
} else {
|
|
||||||
($section, $instance, $status, $filter) = @values;
|
|
||||||
}
|
|
||||||
if ($section !~ /^component/) {
|
|
||||||
$self->{output}->add_option_msg(short_msg => "Wrong threshold-overload section '" . $val . "'.");
|
|
||||||
$self->{output}->option_exit();
|
|
||||||
}
|
|
||||||
if ($self->{output}->is_litteral_status(status => $status) == 0) {
|
|
||||||
$self->{output}->add_option_msg(short_msg => "Wrong threshold-overload status '" . $val . "'.");
|
|
||||||
$self->{output}->option_exit();
|
|
||||||
}
|
|
||||||
$self->{overload_th}->{$section} = [] if (!defined($self->{overload_th}->{$section}));
|
|
||||||
push @{$self->{overload_th}->{$section}}, {filter => $filter, status => $status, instance => $instance };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub run {
|
|
||||||
my ($self, %options) = @_;
|
|
||||||
my $vplex = $options{custom};
|
|
||||||
|
|
||||||
$self->{output}->output_add(severity => 'OK',
|
|
||||||
short_msg => 'All Cluster Witness components are OK');
|
|
||||||
|
|
||||||
my $items = $vplex->get_items(url => '/vplex/cluster-witness/components/');
|
|
||||||
foreach my $name (sort keys %{$items}) {
|
|
||||||
my $instance = $name;
|
|
||||||
|
|
||||||
next if ($self->check_filter(section => 'component', instance => $instance));
|
|
||||||
|
|
||||||
$self->{output}->output_add(long_msg => sprintf("Cluster Witness component '%s' state is '%s'",
|
|
||||||
$instance,
|
|
||||||
$items->{$name}->{'operational-state'}));
|
|
||||||
|
|
||||||
my $exit = $self->get_severity(section => 'component_opstatus', instance => $instance, value => $items->{$name}->{'operational-state'});
|
|
||||||
if (!$self->{output}->is_status(value => $exit, compare => 'ok', litteral => 1)) {
|
|
||||||
$self->{output}->output_add(severity => $exit,
|
|
||||||
short_msg => sprintf("Cluster Witness component '%s' state is '%s'",
|
|
||||||
$instance, $items->{$name}->{'operational-state'}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$self->{output}->display();
|
|
||||||
$self->{output}->exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
sub check_filter {
|
|
||||||
my ($self, %options) = @_;
|
my ($self, %options) = @_;
|
||||||
|
|
||||||
foreach (@{$self->{filter}}) {
|
my $items = $options{custom}->get_cluster_communication();
|
||||||
if ($options{section} =~ /$_->{filter}/) {
|
|
||||||
if (!defined($options{instance}) && !defined($_->{instance})) {
|
|
||||||
$self->{output}->output_add(long_msg => sprintf("Skipping $options{section} section."));
|
|
||||||
return 1;
|
|
||||||
} elsif (defined($options{instance}) && $options{instance} =~ /$_->{instance}/) {
|
|
||||||
$self->{output}->output_add(long_msg => sprintf("Skipping $options{section} section $options{instance} instance."));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub get_severity {
|
$self->{components} = {};
|
||||||
my ($self, %options) = @_;
|
foreach my $item (@$items) {
|
||||||
my $status = 'UNKNOWN'; # default
|
next if (defined($self->{option_results}->{filter_component_name}) && $self->{option_results}->{filter_component_name} ne '' &&
|
||||||
|
$item->{name} !~ /$self->{option_results}->{filter_component_name}/);
|
||||||
if (defined($self->{overload_th}->{$options{section}})) {
|
|
||||||
foreach (@{$self->{overload_th}->{$options{section}}}) {
|
$self->{components}->{ $item->{name} } = $item;
|
||||||
if ($options{value} =~ /$_->{filter}/i &&
|
|
||||||
(!defined($options{instance}) || $options{instance} =~ /$_->{instance}/)) {
|
|
||||||
$status = $_->{status};
|
|
||||||
return $status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
my $label = defined($options{label}) ? $options{label} : $options{section};
|
|
||||||
foreach (@{$thresholds->{$label}}) {
|
|
||||||
if ($options{value} =~ /$$_[0]/i) {
|
|
||||||
$status = $$_[1];
|
|
||||||
return $status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
@ -162,20 +92,23 @@ __END__
|
||||||
|
|
||||||
=head1 MODE
|
=head1 MODE
|
||||||
|
|
||||||
Check Cluster communication state for VPlex
|
Check cluster communication state.
|
||||||
|
|
||||||
=over 8
|
=over 8
|
||||||
|
|
||||||
=item B<--filter>
|
=item B<--filter-component-name>
|
||||||
|
|
||||||
Filter some parts (comma seperated list)
|
Filter components by name (can be a regexp).
|
||||||
Can also exclude specific instance: --filter=component,cluster-1
|
|
||||||
|
|
||||||
=item B<--threshold-overload>
|
=item B<--warning-operational-status>
|
||||||
|
|
||||||
Set to overload default threshold values (syntax: section,[instance,]status,regexp)
|
Set warning threshold for status.
|
||||||
It used before default thresholds (order stays).
|
Can used special variables like: %{operational_state}, %{admin_state}, %{name}
|
||||||
Example: --threshold-overload='component_opstatus,CRITICAL,^(?!(in-contact|cluster-in-contact)$)'
|
|
||||||
|
=item B<--critical-operational-status>
|
||||||
|
|
||||||
|
Set critical threshold for status (Default: '%{admin_state} eq "enabled" and %{operational_state} !~ /cluster-in-contact|in-contact/i').
|
||||||
|
Can used special variables like: %{operational_state}, %{admin_state}, %{name}
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
|
|
|
@ -20,151 +20,77 @@
|
||||||
|
|
||||||
package storage::emc::vplex::restapi::mode::clusterdevices;
|
package storage::emc::vplex::restapi::mode::clusterdevices;
|
||||||
|
|
||||||
use base qw(centreon::plugins::mode);
|
use base qw(centreon::plugins::templates::counter);
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold_ng);
|
||||||
|
|
||||||
my $thresholds = {
|
sub custom_status_output {
|
||||||
device_health => [
|
my ($self, %options) = @_;
|
||||||
['ok', 'ok'],
|
|
||||||
['.*', 'CRITICAL'],
|
return sprintf(
|
||||||
],
|
'health state: %s',
|
||||||
};
|
$self->{result_values}->{health_state}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub prefix_device_output {
|
||||||
|
my ($self, %options) = @_;
|
||||||
|
|
||||||
|
return sprintf(
|
||||||
|
"device '%s' [cluster: %s] ",
|
||||||
|
$options{instance_value}->{device_name},
|
||||||
|
$options{instance_value}->{cluster_name}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub set_counters {
|
||||||
|
my ($self, %options) = @_;
|
||||||
|
|
||||||
|
$self->{maps_counters_type} = [
|
||||||
|
{ name => 'devices', type => 1, cb_prefix_output => 'prefix_device_output', message_multiple => 'All devices are ok' }
|
||||||
|
];
|
||||||
|
|
||||||
|
$self->{maps_counters}->{devices} = [
|
||||||
|
{ label => 'health-status', type => 2, critical_default => '%{health_state} ne "ok"', set => {
|
||||||
|
key_values => [ { name => 'health_state' }, { name => 'cluster_name' }, { name => 'device_name' } ],
|
||||||
|
closure_custom_output => $self->can('custom_status_output'),
|
||||||
|
closure_custom_perfdata => sub { return 0; },
|
||||||
|
closure_custom_threshold_check => \&catalog_status_threshold_ng
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
sub new {
|
sub new {
|
||||||
my ($class, %options) = @_;
|
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;
|
bless $self, $class;
|
||||||
|
|
||||||
$options{options}->add_options(arguments =>
|
$options{options}->add_options(arguments => {
|
||||||
{
|
'filter-cluster-name:s' => { name => 'filter_cluster_name' },
|
||||||
"cluster:s" => { name => 'cluster' },
|
'filter-device-name:s' => { name => 'filter_device_name' }
|
||||||
"filter:s@" => { name => 'filter' },
|
});
|
||||||
"threshold-overload:s@" => { name => 'threshold_overload' },
|
|
||||||
});
|
|
||||||
|
|
||||||
return $self;
|
return $self;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub check_options {
|
sub manage_selection {
|
||||||
my ($self, %options) = @_;
|
|
||||||
$self->SUPER::init(%options);
|
|
||||||
|
|
||||||
$self->{filter} = [];
|
|
||||||
foreach my $val (@{$self->{option_results}->{filter}}) {
|
|
||||||
next if (!defined($val) || $val eq '');
|
|
||||||
my @values = split (/,/, $val);
|
|
||||||
push @{$self->{filter}}, { filter => $values[0], instance => $values[1] };
|
|
||||||
}
|
|
||||||
|
|
||||||
$self->{overload_th} = {};
|
|
||||||
foreach my $val (@{$self->{option_results}->{threshold_overload}}) {
|
|
||||||
next if (!defined($val) || $val eq '');
|
|
||||||
my @values = split (/,/, $val);
|
|
||||||
if (scalar(@values) < 3) {
|
|
||||||
$self->{output}->add_option_msg(short_msg => "Wrong threshold-overload option '" . $val . "'.");
|
|
||||||
$self->{output}->option_exit();
|
|
||||||
}
|
|
||||||
my ($section, $instance, $status, $filter);
|
|
||||||
if (scalar(@values) == 3) {
|
|
||||||
($section, $status, $filter) = @values;
|
|
||||||
$instance = '.*';
|
|
||||||
} else {
|
|
||||||
($section, $instance, $status, $filter) = @values;
|
|
||||||
}
|
|
||||||
if ($section !~ /^device/) {
|
|
||||||
$self->{output}->add_option_msg(short_msg => "Wrong threshold-overload section '" . $val . "'.");
|
|
||||||
$self->{output}->option_exit();
|
|
||||||
}
|
|
||||||
if ($self->{output}->is_litteral_status(status => $status) == 0) {
|
|
||||||
$self->{output}->add_option_msg(short_msg => "Wrong threshold-overload status '" . $val . "'.");
|
|
||||||
$self->{output}->option_exit();
|
|
||||||
}
|
|
||||||
$self->{overload_th}->{$section} = [] if (!defined($self->{overload_th}->{$section}));
|
|
||||||
push @{$self->{overload_th}->{$section}}, {filter => $filter, status => $status, instance => $instance };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub run {
|
|
||||||
my ($self, %options) = @_;
|
|
||||||
my $vplex = $options{custom};
|
|
||||||
|
|
||||||
my $items = $vplex->get_items(
|
|
||||||
url => '/vplex/clusters/',
|
|
||||||
parent => 1,
|
|
||||||
parent_filter => $self->{option_results}->{cluster},
|
|
||||||
parent_filter_prefix => 'cluster-',
|
|
||||||
parent_select => '/clusters/(.*?)/',
|
|
||||||
obj => 'devices'
|
|
||||||
);
|
|
||||||
|
|
||||||
$self->{output}->output_add(severity => 'OK',
|
|
||||||
short_msg => 'All Cluster Devices are OK');
|
|
||||||
|
|
||||||
foreach my $cluster_name (sort keys %{$items}) {
|
|
||||||
foreach my $device_name (sort keys %{$items->{$cluster_name}}) {
|
|
||||||
my $instance = $cluster_name . '_' . $device_name;
|
|
||||||
|
|
||||||
next if ($self->check_filter(section => 'device', instance => $instance));
|
|
||||||
|
|
||||||
$self->{output}->output_add(long_msg => sprintf("Device '%s' health state is '%s'",
|
|
||||||
$instance,
|
|
||||||
$items->{$cluster_name}->{$device_name}->{'health-state'}));
|
|
||||||
|
|
||||||
my $exit = $self->get_severity(section => 'device_health', instance => $instance, value => $items->{$cluster_name}->{$device_name}->{'health-state'});
|
|
||||||
if (!$self->{output}->is_status(value => $exit, compare => 'ok', litteral => 1)) {
|
|
||||||
$self->{output}->output_add(severity => $exit,
|
|
||||||
short_msg => sprintf("Device '%s' health state is '%s'",
|
|
||||||
$instance, $items->{$cluster_name}->{$device_name}->{'health-state'}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$self->{output}->display();
|
|
||||||
$self->{output}->exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
sub check_filter {
|
|
||||||
my ($self, %options) = @_;
|
my ($self, %options) = @_;
|
||||||
|
|
||||||
foreach (@{$self->{filter}}) {
|
my $items = $options{custom}->get_devices();
|
||||||
if ($options{section} =~ /$_->{filter}/) {
|
|
||||||
if (!defined($options{instance}) && !defined($_->{instance})) {
|
|
||||||
$self->{output}->output_add(long_msg => sprintf("Skipping $options{section} section."));
|
|
||||||
return 1;
|
|
||||||
} elsif (defined($options{instance}) && $options{instance} =~ /$_->{instance}/) {
|
|
||||||
$self->{output}->output_add(long_msg => sprintf("Skipping $options{section} section $options{instance} instance."));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub get_severity {
|
$self->{devices} = {};
|
||||||
my ($self, %options) = @_;
|
foreach my $item (@$items) {
|
||||||
my $status = 'UNKNOWN'; # default
|
next if (defined($self->{option_results}->{filter_cluster_name}) && $self->{option_results}->{filter_cluster_name} ne '' &&
|
||||||
|
$item->{cluster_name} !~ /$self->{option_results}->{filter_cluster_name}/);
|
||||||
if (defined($self->{overload_th}->{$options{section}})) {
|
next if (defined($self->{option_results}->{filter_device_name}) && $self->{option_results}->{filter_device_name} ne '' &&
|
||||||
foreach (@{$self->{overload_th}->{$options{section}}}) {
|
$item->{name} !~ /$self->{option_results}->{filter_device_name}/);
|
||||||
if ($options{value} =~ /$_->{filter}/i &&
|
|
||||||
(!defined($options{instance}) || $options{instance} =~ /$_->{instance}/)) {
|
$self->{devices}->{ $item->{name} } = $item;
|
||||||
$status = $_->{status};
|
$self->{devices}->{ $item->{name} }->{device_name} = $item->{name};
|
||||||
return $status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
my $label = defined($options{label}) ? $options{label} : $options{section};
|
|
||||||
foreach (@{$thresholds->{$label}}) {
|
|
||||||
if ($options{value} =~ /$$_[0]/i) {
|
|
||||||
$status = $$_[1];
|
|
||||||
return $status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
@ -173,24 +99,27 @@ __END__
|
||||||
|
|
||||||
=head1 MODE
|
=head1 MODE
|
||||||
|
|
||||||
Check Cluster devices health for VPlex
|
Check cluster devices.
|
||||||
|
|
||||||
=over 8
|
=over 8
|
||||||
|
|
||||||
=item B<--cluster>
|
=item B<--filter-cluster-name>
|
||||||
|
|
||||||
Set cluster name to check (Example: '1')
|
Filter devices by cluster name (can be a regexp).
|
||||||
|
|
||||||
=item B<--filter>
|
=item B<--filter-device-name>
|
||||||
|
|
||||||
Filter some parts (comma seperated list)
|
Filter devices by device name (can be a regexp).
|
||||||
Can also exclude specific instance: --filter=device,cluster-1_xxxx
|
|
||||||
|
|
||||||
=item B<--threshold-overload>
|
=item B<--warning-health-status>
|
||||||
|
|
||||||
Set to overload default threshold values (syntax: section,[instance,]status,regexp)
|
Set warning threshold for status.
|
||||||
It used before default thresholds (order stays).
|
Can used special variables like: %{health_state}, %{cluster_name}, %{device_name}
|
||||||
Example: --threshold-overload='device_health,CRITICAL,^(?!(ok)$)'
|
|
||||||
|
=item B<--critical-health-status>
|
||||||
|
|
||||||
|
Set critical threshold for status (Default: '%{health_state} ne "ok"').
|
||||||
|
Can used special variables like: %{health_state}, %{cluster_name}, %{device_name}
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
|
|
|
@ -20,196 +20,100 @@
|
||||||
|
|
||||||
package storage::emc::vplex::restapi::mode::directors;
|
package storage::emc::vplex::restapi::mode::directors;
|
||||||
|
|
||||||
use base qw(centreon::plugins::mode);
|
use base qw(centreon::plugins::templates::counter);
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold_ng);
|
||||||
|
|
||||||
my $thresholds = {
|
sub prefix_director_output {
|
||||||
director_health => [
|
my ($self, %options) = @_;
|
||||||
['ok', 'OK'],
|
|
||||||
['.*', 'CRITICAL'],
|
return sprintf(
|
||||||
],
|
"director '%s' [engine: %s] ",
|
||||||
director_communication => [
|
$options{instance_value}->{director_name},
|
||||||
['ok', 'OK'],
|
$options{instance_value}->{engine_id}
|
||||||
['.*', 'CRITICAL'],
|
);
|
||||||
],
|
}
|
||||||
director_temperature => [
|
|
||||||
['false', 'OK'],
|
sub set_counters {
|
||||||
['.*', 'CRITICAL'],
|
my ($self, %options) = @_;
|
||||||
],
|
|
||||||
director_voltage => [
|
$self->{maps_counters_type} = [
|
||||||
['false', 'OK'],
|
{ name => 'directors', type => 1, cb_prefix_output => 'prefix_director_output', message_multiple => 'All directors are ok' }
|
||||||
['.*', 'CRITICAL'],
|
];
|
||||||
],
|
|
||||||
director_vplex_splitter => [
|
$self->{maps_counters}->{directors} = [
|
||||||
['ok', 'OK'],
|
{ label => 'health-status', type => 2, critical_default => '%{health_state} ne "ok"', set => {
|
||||||
['.*', 'CRITICAL'],
|
key_values => [ { name => 'health_state' }, { name => 'engine_id' }, { name => 'director_name' } ],
|
||||||
],
|
output_template => 'health state: %s',
|
||||||
};
|
closure_custom_perfdata => sub { return 0; },
|
||||||
|
closure_custom_threshold_check => \&catalog_status_threshold_ng
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ label => 'communication-status', type => 2, critical_default => '%{communication_status} ne "ok"', set => {
|
||||||
|
key_values => [ { name => 'communication_status' }, { name => 'engine_id' }, { name => 'director_name' } ],
|
||||||
|
output_template => 'communication status: %s',
|
||||||
|
closure_custom_perfdata => sub { return 0; },
|
||||||
|
closure_custom_threshold_check => \&catalog_status_threshold_ng
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ label => 'temperature-status', type => 2, critical_default => '%{temperature_threshold_exceeded} ne "false"', set => {
|
||||||
|
key_values => [ { name => 'temperature_threshold_exceeded' }, { name => 'engine_id' }, { name => 'director_name' } ],
|
||||||
|
output_template => 'temperature threshold exceeded: %s',
|
||||||
|
closure_custom_perfdata => sub { return 0; },
|
||||||
|
closure_custom_threshold_check => \&catalog_status_threshold_ng
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ label => 'voltage-status', type => 2, critical_default => '%{voltage_threshold_exceeded} ne "false"', set => {
|
||||||
|
key_values => [ { name => 'voltage_threshold_exceeded' }, { name => 'engine_id' }, { name => 'director_name' } ],
|
||||||
|
output_template => 'voltage threshold exceeded: %s',
|
||||||
|
closure_custom_perfdata => sub { return 0; },
|
||||||
|
closure_custom_threshold_check => \&catalog_status_threshold_ng
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ label => 'vplex-kdriver-status', type => 2, critical_default => '%{vplex_kdriver_status} ne "ok"', set => {
|
||||||
|
key_values => [ { name => 'vplex_kdriver_status' }, { name => 'engine_id' }, { name => 'director_name' } ],
|
||||||
|
output_template => 'vplex kdriver status: %s',
|
||||||
|
closure_custom_perfdata => sub { return 0; },
|
||||||
|
closure_custom_threshold_check => \&catalog_status_threshold_ng
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
sub new {
|
sub new {
|
||||||
my ($class, %options) = @_;
|
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;
|
bless $self, $class;
|
||||||
|
|
||||||
$options{options}->add_options(arguments =>
|
$options{options}->add_options(arguments => {
|
||||||
{
|
'filter-engine-id:s' => { name => 'filter_engine_id' },
|
||||||
"engine:s" => { name => 'engine' },
|
'filter-director-name:s' => { name => 'filter_director_name' }
|
||||||
"filter:s@" => { name => 'filter' },
|
});
|
||||||
"threshold-overload:s@" => { name => 'threshold_overload' },
|
|
||||||
});
|
|
||||||
return $self;
|
return $self;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub check_options {
|
sub manage_selection {
|
||||||
my ($self, %options) = @_;
|
|
||||||
$self->SUPER::init(%options);
|
|
||||||
|
|
||||||
$self->{filter} = [];
|
|
||||||
foreach my $val (@{$self->{option_results}->{filter}}) {
|
|
||||||
next if (!defined($val) || $val eq '');
|
|
||||||
my @values = split (/,/, $val);
|
|
||||||
push @{$self->{filter}}, { filter => $values[0], instance => $values[1] };
|
|
||||||
}
|
|
||||||
|
|
||||||
$self->{overload_th} = {};
|
|
||||||
foreach my $val (@{$self->{option_results}->{threshold_overload}}) {
|
|
||||||
next if (!defined($val) || $val eq '');
|
|
||||||
my @values = split (/,/, $val);
|
|
||||||
if (scalar(@values) < 3) {
|
|
||||||
$self->{output}->add_option_msg(short_msg => "Wrong threshold-overload option '" . $val . "'.");
|
|
||||||
$self->{output}->option_exit();
|
|
||||||
}
|
|
||||||
my ($section, $instance, $status, $filter);
|
|
||||||
if (scalar(@values) == 3) {
|
|
||||||
($section, $status, $filter) = @values;
|
|
||||||
$instance = '.*';
|
|
||||||
} else {
|
|
||||||
($section, $instance, $status, $filter) = @values;
|
|
||||||
}
|
|
||||||
if ($section !~ /^director/) {
|
|
||||||
$self->{output}->add_option_msg(short_msg => "Wrong threshold-overload section '" . $val . "'.");
|
|
||||||
$self->{output}->option_exit();
|
|
||||||
}
|
|
||||||
if ($self->{output}->is_litteral_status(status => $status) == 0) {
|
|
||||||
$self->{output}->add_option_msg(short_msg => "Wrong threshold-overload status '" . $val . "'.");
|
|
||||||
$self->{output}->option_exit();
|
|
||||||
}
|
|
||||||
$self->{overload_th}->{$section} = [] if (!defined($self->{overload_th}->{$section}));
|
|
||||||
push @{$self->{overload_th}->{$section}}, {filter => $filter, status => $status, instance => $instance };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub run {
|
|
||||||
my ($self, %options) = @_;
|
|
||||||
my $vplex = $options{custom};
|
|
||||||
|
|
||||||
my $items = $vplex->get_items(
|
|
||||||
url => '/vplex/engines/',
|
|
||||||
parent => 1,
|
|
||||||
parent_filter => $self->{option_results}->{engine},
|
|
||||||
parent_filter_prefix => 'engine-',
|
|
||||||
parent_select => '/engines/(.*?)/',
|
|
||||||
obj => 'directors'
|
|
||||||
);
|
|
||||||
|
|
||||||
$self->{output}->output_add(severity => 'OK',
|
|
||||||
short_msg => 'All Directors are OK');
|
|
||||||
foreach my $engine_name (sort keys %{$items}) {
|
|
||||||
foreach my $director_name (sort keys %{$items->{$engine_name}}) {
|
|
||||||
my $instance = $engine_name . '_' . $director_name;
|
|
||||||
|
|
||||||
next if ($self->check_filter(section => 'director', instance => $instance));
|
|
||||||
|
|
||||||
$self->{output}->output_add(long_msg => sprintf("Director '%s' health state is '%s' [communication status: %s, temperature threshold exceeded: %s, voltage threshold exceeded: %s, vplex splitter status: %s]",
|
|
||||||
$instance,
|
|
||||||
$items->{$engine_name}->{$director_name}->{'health-state'},
|
|
||||||
$items->{$engine_name}->{$director_name}->{'communication-status'},
|
|
||||||
$items->{$engine_name}->{$director_name}->{'temperature-threshold-exceeded'},
|
|
||||||
$items->{$engine_name}->{$director_name}->{'voltage-threshold-exceeded'},
|
|
||||||
defined($items->{$engine_name}->{$director_name}->{'vplex-splitter-status'}) ? $items->{$engine_name}->{$director_name}->{'vplex-splitter-status'} : '-'));
|
|
||||||
|
|
||||||
my $exit = $self->get_severity(section => 'director_health', instance => $instance, value => $items->{$engine_name}->{$director_name}->{'health-state'});
|
|
||||||
if (!$self->{output}->is_status(value => $exit, compare => 'ok', litteral => 1)) {
|
|
||||||
$self->{output}->output_add(severity => $exit,
|
|
||||||
short_msg => sprintf("Director '%s' health state is %s",
|
|
||||||
$instance, $items->{$engine_name}->{$director_name}->{'health-state'}));
|
|
||||||
}
|
|
||||||
$exit = $self->get_severity(section => 'director_communication', value => $items->{$engine_name}->{$director_name}->{'communication-status'});
|
|
||||||
if (!$self->{output}->is_status(value => $exit, compare => 'ok', litteral => 1)) {
|
|
||||||
$self->{output}->output_add(severity => $exit,
|
|
||||||
short_msg => sprintf("Director '%s' communication status is %s",
|
|
||||||
$instance, $items->{$engine_name}->{$director_name}->{'communication-status'}));
|
|
||||||
}
|
|
||||||
$exit = $self->get_severity(section => 'director_temperature', value => $items->{$engine_name}->{$director_name}->{'temperature-threshold-exceeded'});
|
|
||||||
if (!$self->{output}->is_status(value => $exit, compare => 'ok', litteral => 1)) {
|
|
||||||
$self->{output}->output_add(severity => $exit,
|
|
||||||
short_msg => sprintf("Director '%s' temperature threshold exceeded is %s",
|
|
||||||
$instance, $items->{$engine_name}->{$director_name}->{'temperature-threshold-exceeded'}));
|
|
||||||
}
|
|
||||||
$exit = $self->get_severity(section => 'director_voltage', value => $items->{$engine_name}->{$director_name}->{'voltage-threshold-exceeded'});
|
|
||||||
if (!$self->{output}->is_status(value => $exit, compare => 'ok', litteral => 1)) {
|
|
||||||
$self->{output}->output_add(severity => $exit,
|
|
||||||
short_msg => sprintf("Director '%s' voltage threshold exceeded is %s",
|
|
||||||
$instance, $items->{$engine_name}->{$director_name}->{'voltage-threshold-exceeded'}));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (defined($items->{$engine_name}->{$director_name}->{'vplex-splitter-status'})) {
|
|
||||||
$exit = $self->get_severity(section => 'director_vplex_splitter', value => $items->{$engine_name}->{$director_name}->{'vplex-splitter-status'});
|
|
||||||
if (!$self->{output}->is_status(value => $exit, compare => 'ok', litteral => 1)) {
|
|
||||||
$self->{output}->output_add(severity => $exit,
|
|
||||||
short_msg => sprintf("Director '%s' vplex splitter status is %s",
|
|
||||||
$instance, $items->{$engine_name}->{$director_name}->{'vplex-splitter-status'}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$self->{output}->display();
|
|
||||||
$self->{output}->exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
sub check_filter {
|
|
||||||
my ($self, %options) = @_;
|
my ($self, %options) = @_;
|
||||||
|
|
||||||
foreach (@{$self->{filter}}) {
|
my $items = $options{custom}->get_directors();
|
||||||
if ($options{section} =~ /$_->{filter}/) {
|
|
||||||
if (!defined($options{instance}) && !defined($_->{instance})) {
|
|
||||||
$self->{output}->output_add(long_msg => sprintf("Skipping $options{section} section."));
|
|
||||||
return 1;
|
|
||||||
} elsif (defined($options{instance}) && $options{instance} =~ /$_->{instance}/) {
|
|
||||||
$self->{output}->output_add(long_msg => sprintf("Skipping $options{section} section $options{instance} instance."));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub get_severity {
|
$self->{directors} = {};
|
||||||
my ($self, %options) = @_;
|
foreach my $item (@$items) {
|
||||||
my $status = 'UNKNOWN'; # default
|
next if (defined($self->{option_results}->{filter_engine_id}) && $self->{option_results}->{filter_engine_id} ne '' &&
|
||||||
|
$item->{engine_id} !~ /$self->{option_results}->{filter_engine_id}/);
|
||||||
if (defined($self->{overload_th}->{$options{section}})) {
|
next if (defined($self->{option_results}->{filter_director_name}) && $self->{option_results}->{filter_director_name} ne '' &&
|
||||||
foreach (@{$self->{overload_th}->{$options{section}}}) {
|
$item->{name} !~ /$self->{option_results}->{filter_director_name}/);
|
||||||
if ($options{value} =~ /$_->{filter}/i &&
|
|
||||||
(!defined($options{instance}) || $options{instance} =~ /$_->{instance}/)) {
|
$self->{directors}->{ $item->{name} } = $item;
|
||||||
$status = $_->{status};
|
$self->{directors}->{ $item->{name} }->{director_name} = $item->{name};
|
||||||
return $status;
|
$self->{directors}->{ $item->{name} }->{temperature_threshold_exceeded} =
|
||||||
}
|
$self->{directors}->{ $item->{name} }->{temperature_threshold_exceeded} =~ /^(?:true|1)$/i ? 'true' : 'false';
|
||||||
}
|
$self->{directors}->{ $item->{name} }->{voltage_threshold_exceeded} =
|
||||||
|
$self->{directors}->{ $item->{name} }->{voltage_threshold_exceeded} =~ /^(?:true|1)$/i ? 'true' : 'false';
|
||||||
}
|
}
|
||||||
my $label = defined($options{label}) ? $options{label} : $options{section};
|
|
||||||
foreach (@{$thresholds->{$label}}) {
|
|
||||||
if ($options{value} =~ /$$_[0]/i) {
|
|
||||||
$status = $$_[1];
|
|
||||||
return $status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
@ -218,24 +122,67 @@ __END__
|
||||||
|
|
||||||
=head1 MODE
|
=head1 MODE
|
||||||
|
|
||||||
Check Directors state for VPlex
|
Check directors.
|
||||||
|
|
||||||
=over 8
|
=over 8
|
||||||
|
|
||||||
=item B<--engine>
|
=item B<--filter-engine-id>
|
||||||
|
|
||||||
Specify the engine number to be checked (1-1 or 2-1 usually)
|
Filter directors by engine id (can be a regexp).
|
||||||
|
|
||||||
=item B<--filter>
|
=item B<--filter-director-name>
|
||||||
|
|
||||||
Filter some parts (comma seperated list)
|
Filter directors by director name (can be a regexp).
|
||||||
Can also exclude specific instance: --filter=director,engine-1-1_director-1-1-B
|
|
||||||
|
|
||||||
=item B<--threshold-overload>
|
=item B<--warning-health-status>
|
||||||
|
|
||||||
Set to overload default threshold values (syntax: section,[instance,]status,regexp)
|
Set warning threshold for status.
|
||||||
It used before default thresholds (order stays).
|
Can used special variables like: %{operational_status}, %{engine_id}, %{director_name}
|
||||||
Example: --threshold-overload='director_temperature,CRITICAL,^(?!(false)$)'
|
|
||||||
|
=item B<--critical-health-status>
|
||||||
|
|
||||||
|
Set critical threshold for status (Default: '%{health_state} ne "ok"').
|
||||||
|
Can used special variables like: %{operational_status}, %{engine_id}, %{director_name}
|
||||||
|
|
||||||
|
=item B<--warning-communication-status>
|
||||||
|
|
||||||
|
Set warning threshold for status.
|
||||||
|
Can used special variables like: %{communication_status}, %{engine_id}, %{director_name}
|
||||||
|
|
||||||
|
=item B<--critical-communication-status>
|
||||||
|
|
||||||
|
Set critical threshold for status (Default: '%{communication_status} ne "ok"').
|
||||||
|
Can used special variables like: %{communication_status}, %{engine_id}, %{director_name}
|
||||||
|
|
||||||
|
=item B<--warning-temperature-status>
|
||||||
|
|
||||||
|
Set warning threshold for status.
|
||||||
|
Can used special variables like: %{temperature_threshold_exceeded}, %{engine_id}, %{director_name}
|
||||||
|
|
||||||
|
=item B<--critical-temperature-status>
|
||||||
|
|
||||||
|
Set critical threshold for status (Default: '%{temperature_threshold_exceeded} ne "false"').
|
||||||
|
Can used special variables like: %{temperature_threshold_exceeded}, %{engine_id}, %{director_name}
|
||||||
|
|
||||||
|
=item B<--warning-voltage-status>
|
||||||
|
|
||||||
|
Set warning threshold for status.
|
||||||
|
Can used special variables like: %{voltage_threshold_exceeded}, %{engine_id}, %{director_name}
|
||||||
|
|
||||||
|
=item B<--critical-voltage-status>
|
||||||
|
|
||||||
|
Set critical threshold for status (Default: '%{voltage_threshold_exceeded} ne "false"').
|
||||||
|
Can used special variables like: %{voltage_threshold_exceeded}, %{engine_id}, %{director_name}
|
||||||
|
|
||||||
|
=item B<--warning-vplex-kdriver-status>
|
||||||
|
|
||||||
|
Set warning threshold for status.
|
||||||
|
Can used special variables like: %{vplex_kdriver_status}, %{engine_id}, %{director_name}
|
||||||
|
|
||||||
|
=item B<--critical-vplex-kdriver-status>
|
||||||
|
|
||||||
|
Set critical threshold for status (Default: '%{vplex_kdriver_status} ne "ok"').
|
||||||
|
Can used special variables like: %{vplex_kdriver_status}, %{engine_id}, %{director_name}
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
|
|
|
@ -20,163 +20,78 @@
|
||||||
|
|
||||||
package storage::emc::vplex::restapi::mode::distributeddevices;
|
package storage::emc::vplex::restapi::mode::distributeddevices;
|
||||||
|
|
||||||
use base qw(centreon::plugins::mode);
|
use base qw(centreon::plugins::templates::counter);
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold_ng);
|
||||||
|
|
||||||
my $thresholds = {
|
sub prefix_device_output {
|
||||||
device_health => [
|
my ($self, %options) = @_;
|
||||||
['ok', 'OK'],
|
|
||||||
['.*', 'CRITICAL'],
|
return sprintf(
|
||||||
],
|
"distributed device '%s' ",
|
||||||
device_opstatus => [
|
$options{instance_value}->{device_name}
|
||||||
['ok', 'OK'],
|
);
|
||||||
['.*', 'CRITICAL'],
|
}
|
||||||
],
|
|
||||||
device_service => [
|
sub set_counters {
|
||||||
['running', 'OK'],
|
my ($self, %options) = @_;
|
||||||
['.*', 'CRITICAL'],
|
|
||||||
],
|
$self->{maps_counters_type} = [
|
||||||
};
|
{ name => 'devices', type => 1, cb_prefix_output => 'prefix_device_output', message_multiple => 'All distributed devices are ok' }
|
||||||
|
];
|
||||||
|
|
||||||
|
$self->{maps_counters}->{devices} = [
|
||||||
|
{ label => 'health-status', type => 2, critical_default => '%{health_state} ne "ok"', set => {
|
||||||
|
key_values => [ { name => 'health_state' }, { name => 'device_name' } ],
|
||||||
|
output_template => 'health state: %s',
|
||||||
|
closure_custom_perfdata => sub { return 0; },
|
||||||
|
closure_custom_threshold_check => \&catalog_status_threshold_ng
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ label => 'operational-status', type => 2, critical_default => '%{operational_status} ne "ok"', set => {
|
||||||
|
key_values => [ { name => 'operational_status' }, { name => 'device_name' } ],
|
||||||
|
output_template => 'operational status: %s',
|
||||||
|
closure_custom_perfdata => sub { return 0; },
|
||||||
|
closure_custom_threshold_check => \&catalog_status_threshold_ng
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ label => 'service-status', type => 2, critical_default => '%{service_status} ne "running"', set => {
|
||||||
|
key_values => [ { name => 'service_status' }, { name => 'device_name' } ],
|
||||||
|
output_template => 'service status: %s',
|
||||||
|
closure_custom_perfdata => sub { return 0; },
|
||||||
|
closure_custom_threshold_check => \&catalog_status_threshold_ng
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
sub new {
|
sub new {
|
||||||
my ($class, %options) = @_;
|
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;
|
bless $self, $class;
|
||||||
|
|
||||||
$options{options}->add_options(arguments =>
|
$options{options}->add_options(arguments => {
|
||||||
{
|
'filter-device-name:s' => { name => 'filter_device_name' }
|
||||||
"filter:s@" => { name => 'filter' },
|
});
|
||||||
"threshold-overload:s@" => { name => 'threshold_overload' },
|
|
||||||
});
|
|
||||||
|
|
||||||
return $self;
|
return $self;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub check_options {
|
sub manage_selection {
|
||||||
my ($self, %options) = @_;
|
|
||||||
$self->SUPER::init(%options);
|
|
||||||
|
|
||||||
$self->{filter} = [];
|
|
||||||
foreach my $val (@{$self->{option_results}->{filter}}) {
|
|
||||||
next if (!defined($val) || $val eq '');
|
|
||||||
my @values = split (/,/, $val);
|
|
||||||
push @{$self->{filter}}, { filter => $values[0], instance => $values[1] };
|
|
||||||
}
|
|
||||||
|
|
||||||
$self->{overload_th} = {};
|
|
||||||
foreach my $val (@{$self->{option_results}->{threshold_overload}}) {
|
|
||||||
next if (!defined($val) || $val eq '');
|
|
||||||
my @values = split (/,/, $val);
|
|
||||||
if (scalar(@values) < 3) {
|
|
||||||
$self->{output}->add_option_msg(short_msg => "Wrong threshold-overload option '" . $val . "'.");
|
|
||||||
$self->{output}->option_exit();
|
|
||||||
}
|
|
||||||
my ($section, $instance, $status, $filter);
|
|
||||||
if (scalar(@values) == 3) {
|
|
||||||
($section, $status, $filter) = @values;
|
|
||||||
$instance = '.*';
|
|
||||||
} else {
|
|
||||||
($section, $instance, $status, $filter) = @values;
|
|
||||||
}
|
|
||||||
if ($section !~ /^device/) {
|
|
||||||
$self->{output}->add_option_msg(short_msg => "Wrong threshold-overload section '" . $val . "'.");
|
|
||||||
$self->{output}->option_exit();
|
|
||||||
}
|
|
||||||
if ($self->{output}->is_litteral_status(status => $status) == 0) {
|
|
||||||
$self->{output}->add_option_msg(short_msg => "Wrong threshold-overload status '" . $val . "'.");
|
|
||||||
$self->{output}->option_exit();
|
|
||||||
}
|
|
||||||
$self->{overload_th}->{$section} = [] if (!defined($self->{overload_th}->{$section}));
|
|
||||||
push @{$self->{overload_th}->{$section}}, {filter => $filter, status => $status, instance => $instance };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub run {
|
|
||||||
my ($self, %options) = @_;
|
|
||||||
my $vplex = $options{custom};
|
|
||||||
|
|
||||||
$self->{output}->output_add(severity => 'OK',
|
|
||||||
short_msg => 'All Distributed devices are OK');
|
|
||||||
|
|
||||||
my $items = $vplex->get_items(url => '/vplex/distributed-storage/distributed-devices/');
|
|
||||||
foreach my $name (sort keys %{$items}) {
|
|
||||||
my $instance = $name;
|
|
||||||
|
|
||||||
next if ($self->check_filter(section => 'device', instance => $instance));
|
|
||||||
|
|
||||||
$self->{output}->output_add(long_msg => sprintf("Distributed device '%s' health state is '%s' [service status: %s, operational status: %s]",
|
|
||||||
$instance,
|
|
||||||
$items->{$name}->{'health-state'},
|
|
||||||
$items->{$name}->{'service-status'},
|
|
||||||
$items->{$name}->{'operational-status'},
|
|
||||||
));
|
|
||||||
|
|
||||||
my $exit = $self->get_severity(section => 'device_health', instance => $instance, value => $items->{$name}->{'health-state'});
|
|
||||||
if (!$self->{output}->is_status(value => $exit, compare => 'ok', litteral => 1)) {
|
|
||||||
$self->{output}->output_add(severity => $exit,
|
|
||||||
short_msg => sprintf("Distributed device '%s' health state is %s",
|
|
||||||
$instance, $items->{$name}->{'health-state'}));
|
|
||||||
}
|
|
||||||
$exit = $self->get_severity(section => 'device_service', value => $items->{$name}->{'service-status'});
|
|
||||||
if (!$self->{output}->is_status(value => $exit, compare => 'ok', litteral => 1)) {
|
|
||||||
$self->{output}->output_add(severity => $exit,
|
|
||||||
short_msg => sprintf("Distributed device '%s' service status is %s",
|
|
||||||
$instance, $items->{$name}->{'service-status'}));
|
|
||||||
}
|
|
||||||
$exit = $self->get_severity(section => 'device_opstatus', value => $items->{$name}->{'operational-status'});
|
|
||||||
if (!$self->{output}->is_status(value => $exit, compare => 'ok', litteral => 1)) {
|
|
||||||
$self->{output}->output_add(severity => $exit,
|
|
||||||
short_msg => sprintf("Distributed device '%s' operational status is %s",
|
|
||||||
$instance, $items->{$name}->{'operational-status'}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$self->{output}->display();
|
|
||||||
$self->{output}->exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
sub check_filter {
|
|
||||||
my ($self, %options) = @_;
|
my ($self, %options) = @_;
|
||||||
|
|
||||||
foreach (@{$self->{filter}}) {
|
my $items = $options{custom}->get_distributed_devices();
|
||||||
if ($options{section} =~ /$_->{filter}/) {
|
|
||||||
if (!defined($options{instance}) && !defined($_->{instance})) {
|
|
||||||
$self->{output}->output_add(long_msg => sprintf("Skipping $options{section} section."));
|
|
||||||
return 1;
|
|
||||||
} elsif (defined($options{instance}) && $options{instance} =~ /$_->{instance}/) {
|
|
||||||
$self->{output}->output_add(long_msg => sprintf("Skipping $options{section} section $options{instance} instance."));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub get_severity {
|
$self->{devices} = {};
|
||||||
my ($self, %options) = @_;
|
foreach my $item (@$items) {
|
||||||
my $status = 'UNKNOWN'; # default
|
next if (defined($self->{option_results}->{filter_device_name}) && $self->{option_results}->{filter_device_name} ne '' &&
|
||||||
|
$item->{name} !~ /$self->{option_results}->{filter_device_name}/);
|
||||||
if (defined($self->{overload_th}->{$options{section}})) {
|
|
||||||
foreach (@{$self->{overload_th}->{$options{section}}}) {
|
$self->{devices}->{ $item->{name} } = $item;
|
||||||
if ($options{value} =~ /$_->{filter}/i &&
|
$self->{devices}->{ $item->{name} }->{device_name} = $item->{name};
|
||||||
(!defined($options{instance}) || $options{instance} =~ /$_->{instance}/)) {
|
|
||||||
$status = $_->{status};
|
|
||||||
return $status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
my $label = defined($options{label}) ? $options{label} : $options{section};
|
|
||||||
foreach (@{$thresholds->{$label}}) {
|
|
||||||
if ($options{value} =~ /$$_[0]/i) {
|
|
||||||
$status = $$_[1];
|
|
||||||
return $status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
@ -185,20 +100,43 @@ __END__
|
||||||
|
|
||||||
=head1 MODE
|
=head1 MODE
|
||||||
|
|
||||||
Check distributed devices for VPlex
|
Check distributed devices.
|
||||||
|
|
||||||
=over 8
|
=over 8
|
||||||
|
|
||||||
=item B<--filter>
|
=item B<--filter-device-name>
|
||||||
|
|
||||||
Filter some parts (comma seperated list)
|
Filter devices by device name (can be a regexp).
|
||||||
Can also exclude specific instance: --filter=component,cluster-1
|
|
||||||
|
|
||||||
=item B<--threshold-overload>
|
=item B<--warning-operational-status>
|
||||||
|
|
||||||
Set to overload default threshold values (syntax: section,[instance,]status,regexp)
|
Set warning threshold for status.
|
||||||
It used before default thresholds (order stays).
|
Can used special variables like: %{operational_status}, %{device_name}
|
||||||
Example: --threshold-overload='component_opstatus,CRITICAL,^(?!(in-contact|cluster-in-contact)$)'
|
|
||||||
|
=item B<--critical-operational-status>
|
||||||
|
|
||||||
|
Set critical threshold for status (Default: '%{operational_status} ne "ok"').
|
||||||
|
Can used special variables like: %{operational_status}, %{device_name}
|
||||||
|
|
||||||
|
=item B<--warning-health-status>
|
||||||
|
|
||||||
|
Set warning threshold for status.
|
||||||
|
Can used special variables like: %{health_state}, %{device_name}
|
||||||
|
|
||||||
|
=item B<--critical-health-status>
|
||||||
|
|
||||||
|
Set critical threshold for status (Default: '%{health_state} ne "ok"').
|
||||||
|
Can used special variables like: %{health_state}, %{device_name}
|
||||||
|
|
||||||
|
=item B<--warning-service-status>
|
||||||
|
|
||||||
|
Set warning threshold for status.
|
||||||
|
Can used special variables like: %{service_status}, %{device_name}
|
||||||
|
|
||||||
|
=item B<--critical-service-status>
|
||||||
|
|
||||||
|
Set critical threshold for status (Default: '%{service_status} ne "running"').
|
||||||
|
Can used special variables like: %{service_status}, %{device_name}
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
|
|
|
@ -20,161 +20,75 @@
|
||||||
|
|
||||||
package storage::emc::vplex::restapi::mode::fans;
|
package storage::emc::vplex::restapi::mode::fans;
|
||||||
|
|
||||||
use base qw(centreon::plugins::mode);
|
use base qw(centreon::plugins::templates::counter);
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold_ng);
|
||||||
|
|
||||||
my $thresholds = {
|
sub prefix_fan_output {
|
||||||
fan_opstatus => [
|
my ($self, %options) = @_;
|
||||||
['online', 'OK'],
|
|
||||||
['.*', 'CRITICAL'],
|
return sprintf(
|
||||||
],
|
"fan '%s' [engine: %s] ",
|
||||||
fan => [
|
$options{instance_value}->{fan_name},
|
||||||
['false', 'OK'],
|
$options{instance_value}->{engine_id}
|
||||||
['.*', 'CRITICAL'],
|
);
|
||||||
],
|
}
|
||||||
};
|
|
||||||
|
sub set_counters {
|
||||||
|
my ($self, %options) = @_;
|
||||||
|
|
||||||
|
$self->{maps_counters_type} = [
|
||||||
|
{ name => 'fans', type => 1, cb_prefix_output => 'prefix_fan_output', message_multiple => 'All fans are ok' }
|
||||||
|
];
|
||||||
|
|
||||||
|
$self->{maps_counters}->{fans} = [
|
||||||
|
{ label => 'operational-status', type => 2, critical_default => '%{operational_status} ne "online"', set => {
|
||||||
|
key_values => [ { name => 'operational_status' }, { name => 'engine_id' }, { name => 'fan_name' } ],
|
||||||
|
output_template => 'operational status: %s',
|
||||||
|
closure_custom_perfdata => sub { return 0; },
|
||||||
|
closure_custom_threshold_check => \&catalog_status_threshold_ng
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ label => 'speed-status', type => 2, critical_default => '%{speed_threshold_exceeded} ne "false"', set => {
|
||||||
|
key_values => [ { name => 'speed_threshold_exceeded' }, { name => 'engine_id' }, { name => 'fan_name' } ],
|
||||||
|
output_template => 'speed threshold exceeded: %s',
|
||||||
|
closure_custom_perfdata => sub { return 0; },
|
||||||
|
closure_custom_threshold_check => \&catalog_status_threshold_ng
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
sub new {
|
sub new {
|
||||||
my ($class, %options) = @_;
|
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;
|
bless $self, $class;
|
||||||
|
|
||||||
$options{options}->add_options(arguments =>
|
$options{options}->add_options(arguments => {
|
||||||
{
|
'filter-engine-id:s' => { name => 'filter_engine_id' },
|
||||||
"engine:s" => { name => 'engine' },
|
'filter-fan-name:s' => { name => 'filter_fan_name' }
|
||||||
"filter:s@" => { name => 'filter' },
|
});
|
||||||
"threshold-overload:s@" => { name => 'threshold_overload' },
|
|
||||||
});
|
|
||||||
|
|
||||||
return $self;
|
return $self;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub check_options {
|
sub manage_selection {
|
||||||
my ($self, %options) = @_;
|
|
||||||
$self->SUPER::init(%options);
|
|
||||||
|
|
||||||
$self->{filter} = [];
|
|
||||||
foreach my $val (@{$self->{option_results}->{filter}}) {
|
|
||||||
next if (!defined($val) || $val eq '');
|
|
||||||
my @values = split (/,/, $val);
|
|
||||||
push @{$self->{filter}}, { filter => $values[0], instance => $values[1] };
|
|
||||||
}
|
|
||||||
|
|
||||||
$self->{overload_th} = {};
|
|
||||||
foreach my $val (@{$self->{option_results}->{threshold_overload}}) {
|
|
||||||
next if (!defined($val) || $val eq '');
|
|
||||||
my @values = split (/,/, $val);
|
|
||||||
if (scalar(@values) < 3) {
|
|
||||||
$self->{output}->add_option_msg(short_msg => "Wrong threshold-overload option '" . $val . "'.");
|
|
||||||
$self->{output}->option_exit();
|
|
||||||
}
|
|
||||||
my ($section, $instance, $status, $filter);
|
|
||||||
if (scalar(@values) == 3) {
|
|
||||||
($section, $status, $filter) = @values;
|
|
||||||
$instance = '.*';
|
|
||||||
} else {
|
|
||||||
($section, $instance, $status, $filter) = @values;
|
|
||||||
}
|
|
||||||
if ($section !~ /^fan|fan_opstatus$/) {
|
|
||||||
$self->{output}->add_option_msg(short_msg => "Wrong threshold-overload section '" . $val . "'.");
|
|
||||||
$self->{output}->option_exit();
|
|
||||||
}
|
|
||||||
if ($self->{output}->is_litteral_status(status => $status) == 0) {
|
|
||||||
$self->{output}->add_option_msg(short_msg => "Wrong threshold-overload status '" . $val . "'.");
|
|
||||||
$self->{output}->option_exit();
|
|
||||||
}
|
|
||||||
$self->{overload_th}->{$section} = [] if (!defined($self->{overload_th}->{$section}));
|
|
||||||
push @{$self->{overload_th}->{$section}}, {filter => $filter, status => $status, instance => $instance };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub run {
|
|
||||||
my ($self, %options) = @_;
|
|
||||||
my $vplex = $options{custom};
|
|
||||||
|
|
||||||
$self->{output}->output_add(severity => 'OK',
|
|
||||||
short_msg => 'All Fans are OK');
|
|
||||||
|
|
||||||
my $items = $vplex->get_items(
|
|
||||||
url => '/vplex/engines/',
|
|
||||||
parent => 1,
|
|
||||||
parent_filter => $self->{option_results}->{engine},
|
|
||||||
parent_filter_prefix => 'engine-',
|
|
||||||
parent_select => '/engines/(.*?)/',
|
|
||||||
obj => 'fans'
|
|
||||||
);
|
|
||||||
foreach my $engine_name (sort keys %{$items}) {
|
|
||||||
foreach my $fan_name (sort keys %{$items->{$engine_name}}) {
|
|
||||||
my $instance = $engine_name . '_' . $fan_name;
|
|
||||||
|
|
||||||
next if ($self->check_filter(section => 'fan', instance => $instance));
|
|
||||||
|
|
||||||
$self->{output}->output_add(long_msg => sprintf("Fan '%s' state is '%s' and speed-threshold-exceeded is '%s'",
|
|
||||||
$instance,
|
|
||||||
$items->{$engine_name}->{$fan_name}->{'operational-status'},
|
|
||||||
$items->{$engine_name}->{$fan_name}->{'speed-threshold-exceeded'}));
|
|
||||||
|
|
||||||
my $exit = $self->get_severity(section => 'fan_opstatus', instance => $instance, value => $items->{$engine_name}->{$fan_name}->{'operational-status'});
|
|
||||||
if (!$self->{output}->is_status(value => $exit, compare => 'ok', litteral => 1)) {
|
|
||||||
$self->{output}->output_add(severity => $exit,
|
|
||||||
short_msg => sprintf("Fan '%s' operational status is %s",
|
|
||||||
$instance, $items->{$engine_name}->{$fan_name}->{'operational-status'}));
|
|
||||||
}
|
|
||||||
$exit = $self->get_severity(section => 'fan', instance => $instance, value => $items->{$engine_name}->{$fan_name}->{'speed-threshold-exceeded'});
|
|
||||||
if (!$self->{output}->is_status(value => $exit, compare => 'ok', litteral => 1)) {
|
|
||||||
$self->{output}->output_add(severity => $exit,
|
|
||||||
short_msg => sprintf("Fan '%s' is over speed threshold (%s)",
|
|
||||||
$instance, $items->{$engine_name}->{$fan_name}->{'speed-threshold-exceeded'}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$self->{output}->display();
|
|
||||||
$self->{output}->exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
sub check_filter {
|
|
||||||
my ($self, %options) = @_;
|
my ($self, %options) = @_;
|
||||||
|
|
||||||
foreach (@{$self->{filter}}) {
|
my $items = $options{custom}->get_fans();
|
||||||
if ($options{section} =~ /$_->{filter}/) {
|
|
||||||
if (!defined($options{instance}) && !defined($_->{instance})) {
|
|
||||||
$self->{output}->output_add(long_msg => sprintf("Skipping $options{section} section."));
|
|
||||||
return 1;
|
|
||||||
} elsif (defined($options{instance}) && $options{instance} =~ /$_->{instance}/) {
|
|
||||||
$self->{output}->output_add(long_msg => sprintf("Skipping $options{section} section $options{instance} instance."));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub get_severity {
|
$self->{fans} = {};
|
||||||
my ($self, %options) = @_;
|
foreach my $item (@$items) {
|
||||||
my $status = 'UNKNOWN'; # default
|
next if (defined($self->{option_results}->{filter_engine_id}) && $self->{option_results}->{filter_engine_id} ne '' &&
|
||||||
|
$item->{engine_id} !~ /$self->{option_results}->{filter_engine_id}/);
|
||||||
if (defined($self->{overload_th}->{$options{section}})) {
|
next if (defined($self->{option_results}->{filter_fan_name}) && $self->{option_results}->{filter_fan_name} ne '' &&
|
||||||
foreach (@{$self->{overload_th}->{$options{section}}}) {
|
$item->{name} !~ /$self->{option_results}->{filter_fan_name}/);
|
||||||
if ($options{value} =~ /$_->{filter}/i &&
|
|
||||||
(!defined($options{instance}) || $options{instance} =~ /$_->{instance}/)) {
|
$self->{fans}->{ $item->{name} } = $item;
|
||||||
$status = $_->{status};
|
$self->{fans}->{ $item->{name} }->{fan_name} = $item->{name};
|
||||||
return $status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
my $label = defined($options{label}) ? $options{label} : $options{section};
|
|
||||||
foreach (@{$thresholds->{$label}}) {
|
|
||||||
if ($options{value} =~ /$$_[0]/i) {
|
|
||||||
$status = $$_[1];
|
|
||||||
return $status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
@ -183,24 +97,37 @@ __END__
|
||||||
|
|
||||||
=head1 MODE
|
=head1 MODE
|
||||||
|
|
||||||
Check Fan state for VPlex
|
Check fans.
|
||||||
|
|
||||||
=over 8
|
=over 8
|
||||||
|
|
||||||
=item B<--engine>
|
=item B<--filter-engine-id>
|
||||||
|
|
||||||
Specify the engine number to be checked (1-1 or 2-1 usually)
|
Filter fans by engine id (can be a regexp).
|
||||||
|
|
||||||
=item B<--filter>
|
=item B<--filter-fan-name>
|
||||||
|
|
||||||
Filter some parts (comma seperated list)
|
Filter fans by fan name (can be a regexp).
|
||||||
Can also exclude specific instance: --filter=fan,engine-1-1_fan-psa0-intake
|
|
||||||
|
|
||||||
=item B<--threshold-overload>
|
=item B<--warning-operational-status>
|
||||||
|
|
||||||
Set to overload default threshold values (syntax: section,[instance,]status,regexp)
|
Set warning threshold for status.
|
||||||
It used before default thresholds (order stays).
|
Can used special variables like: %{operational_status}, %{engine_id}, %{fan_name}
|
||||||
Example: --threshold-overload='fan,CRITICAL,^(?!(false)$)'
|
|
||||||
|
=item B<--critical-operational-status>
|
||||||
|
|
||||||
|
Set critical threshold for status (Default: '%{operational_status} ne "online"').
|
||||||
|
Can used special variables like: %{operational_status}, %{engine_id}, %{fan_name}
|
||||||
|
|
||||||
|
=item B<--warning-speed-status>
|
||||||
|
|
||||||
|
Set warning threshold for status.
|
||||||
|
Can used special variables like: %{speed_threshold_exceeded}, %{engine_id}, %{fan_name}
|
||||||
|
|
||||||
|
=item B<--critical-speed-status>
|
||||||
|
|
||||||
|
Set critical threshold for status (Default: '%{operational_status} ne "online"').
|
||||||
|
Can used special variables like: %{speed_threshold_exceeded}, %{engine_id}, %{fan_name}
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
|
|
|
@ -19,163 +19,75 @@
|
||||||
|
|
||||||
package storage::emc::vplex::restapi::mode::psus;
|
package storage::emc::vplex::restapi::mode::psus;
|
||||||
|
|
||||||
use base qw(centreon::plugins::mode);
|
use base qw(centreon::plugins::templates::counter);
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold_ng);
|
||||||
|
|
||||||
my $thresholds = {
|
sub prefix_psu_output {
|
||||||
psu_opstatus => [
|
my ($self, %options) = @_;
|
||||||
['online', 'OK'],
|
|
||||||
['.*', 'CRITICAL'],
|
return sprintf(
|
||||||
],
|
"power supply '%s' [engine: %s] ",
|
||||||
psu => [
|
$options{instance_value}->{psu_name},
|
||||||
['false', 'OK'],
|
$options{instance_value}->{engine_id}
|
||||||
['.*', 'CRITICAL'],
|
);
|
||||||
],
|
}
|
||||||
};
|
|
||||||
|
sub set_counters {
|
||||||
|
my ($self, %options) = @_;
|
||||||
|
|
||||||
|
$self->{maps_counters_type} = [
|
||||||
|
{ name => 'psu', type => 1, cb_prefix_output => 'prefix_psu_output', message_multiple => 'All power supplies are ok' }
|
||||||
|
];
|
||||||
|
|
||||||
|
$self->{maps_counters}->{psu} = [
|
||||||
|
{ label => 'operational-status', type => 2, critical_default => '%{operational_status} ne "online"', set => {
|
||||||
|
key_values => [ { name => 'operational_status' }, { name => 'engine_id' }, { name => 'psu_name' } ],
|
||||||
|
output_template => 'operational status: %s',
|
||||||
|
closure_custom_perfdata => sub { return 0; },
|
||||||
|
closure_custom_threshold_check => \&catalog_status_threshold_ng
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ label => 'temperature-status', type => 2, critical_default => '%{temperature_threshold_exceeded} ne "false"', set => {
|
||||||
|
key_values => [ { name => 'temperature_threshold_exceeded' }, { name => 'engine_id' }, { name => 'psu_name' } ],
|
||||||
|
output_template => 'temperature threshold exceeded: %s',
|
||||||
|
closure_custom_perfdata => sub { return 0; },
|
||||||
|
closure_custom_threshold_check => \&catalog_status_threshold_ng
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
sub new {
|
sub new {
|
||||||
my ($class, %options) = @_;
|
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;
|
bless $self, $class;
|
||||||
|
|
||||||
$options{options}->add_options(arguments =>
|
$options{options}->add_options(arguments => {
|
||||||
{
|
'filter-engine-id:s' => { name => 'filter_engine_id' },
|
||||||
"engine:s" => { name => 'engine' },
|
'filter-psu-name:s' => { name => 'filter_psu_name' }
|
||||||
"filter:s@" => { name => 'filter' },
|
});
|
||||||
"threshold-overload:s@" => { name => 'threshold_overload' },
|
|
||||||
});
|
|
||||||
|
|
||||||
return $self;
|
return $self;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub check_options {
|
sub manage_selection {
|
||||||
my ($self, %options) = @_;
|
|
||||||
$self->SUPER::init(%options);
|
|
||||||
|
|
||||||
$self->{filter} = [];
|
|
||||||
foreach my $val (@{$self->{option_results}->{filter}}) {
|
|
||||||
next if (!defined($val) || $val eq '');
|
|
||||||
my @values = split (/,/, $val);
|
|
||||||
push @{$self->{filter}}, { filter => $values[0], instance => $values[1] };
|
|
||||||
}
|
|
||||||
|
|
||||||
$self->{overload_th} = {};
|
|
||||||
foreach my $val (@{$self->{option_results}->{threshold_overload}}) {
|
|
||||||
next if (!defined($val) || $val eq '');
|
|
||||||
my @values = split (/,/, $val);
|
|
||||||
if (scalar(@values) < 3) {
|
|
||||||
$self->{output}->add_option_msg(short_msg => "Wrong threshold-overload option '" . $val . "'.");
|
|
||||||
$self->{output}->option_exit();
|
|
||||||
}
|
|
||||||
my ($section, $instance, $status, $filter);
|
|
||||||
if (scalar(@values) == 3) {
|
|
||||||
($section, $status, $filter) = @values;
|
|
||||||
$instance = '.*';
|
|
||||||
} else {
|
|
||||||
($section, $instance, $status, $filter) = @values;
|
|
||||||
}
|
|
||||||
if ($section !~ /^psu|psu_opstatus$/) {
|
|
||||||
$self->{output}->add_option_msg(short_msg => "Wrong threshold-overload section '" . $val . "'.");
|
|
||||||
$self->{output}->option_exit();
|
|
||||||
}
|
|
||||||
if ($self->{output}->is_litteral_status(status => $status) == 0) {
|
|
||||||
$self->{output}->add_option_msg(short_msg => "Wrong threshold-overload status '" . $val . "'.");
|
|
||||||
$self->{output}->option_exit();
|
|
||||||
}
|
|
||||||
$self->{overload_th}->{$section} = [] if (!defined($self->{overload_th}->{$section}));
|
|
||||||
push @{$self->{overload_th}->{$section}}, {filter => $filter, status => $status, instance => $instance };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub run {
|
|
||||||
my ($self, %options) = @_;
|
|
||||||
my $vplex = $options{custom};
|
|
||||||
|
|
||||||
my $items = $vplex->get_items(
|
|
||||||
url => '/vplex/engines/',
|
|
||||||
parent => 1,
|
|
||||||
parent_filter => $self->{option_results}->{engine},
|
|
||||||
parent_filter_prefix => 'engine-',
|
|
||||||
parent_select => '/engines/(.*?)/',
|
|
||||||
obj => 'power-supplies'
|
|
||||||
);
|
|
||||||
|
|
||||||
$self->{output}->output_add(severity => 'OK',
|
|
||||||
short_msg => 'All Power supplies are OK');
|
|
||||||
|
|
||||||
foreach my $engine_name (sort keys %{$items}) {
|
|
||||||
foreach my $psu_name (sort keys %{$items->{$engine_name}}) {
|
|
||||||
my $instance = $engine_name . '_' . $psu_name;
|
|
||||||
|
|
||||||
next if ($self->check_filter(section => 'psu', instance => $instance));
|
|
||||||
|
|
||||||
$self->{output}->output_add(long_msg => sprintf("Power supply '%s' state is '%s' and temperature-threshold-exceeded is '%s'",
|
|
||||||
$instance,
|
|
||||||
$items->{$engine_name}->{$psu_name}->{'operational-status'},
|
|
||||||
$items->{$engine_name}->{$psu_name}->{'temperature-threshold-exceeded'}));
|
|
||||||
|
|
||||||
my $exit = $self->get_severity(section => 'psu_opstatus', instance => $instance, value => $items->{$engine_name}->{$psu_name}->{'operational-status'});
|
|
||||||
if (!$self->{output}->is_status(value => $exit, compare => 'ok', litteral => 1)) {
|
|
||||||
$self->{output}->output_add(severity => $exit,
|
|
||||||
short_msg => sprintf("Power supply '%s' operational status is %s",
|
|
||||||
$instance, $items->{$engine_name}->{$psu_name}->{'operational-status'}));
|
|
||||||
}
|
|
||||||
$exit = $self->get_severity(section => 'psu', instance => $instance, value => $items->{$engine_name}->{$psu_name}->{'temperature-threshold-exceeded'});
|
|
||||||
if (!$self->{output}->is_status(value => $exit, compare => 'ok', litteral => 1)) {
|
|
||||||
$self->{output}->output_add(severity => $exit,
|
|
||||||
short_msg => sprintf("Power supply '%s' is over temperature threshold (%s)",
|
|
||||||
$instance, $items->{$engine_name}->{$psu_name}->{'temperature-threshold-exceeded'}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$self->{output}->display();
|
|
||||||
$self->{output}->exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
sub check_filter {
|
|
||||||
my ($self, %options) = @_;
|
my ($self, %options) = @_;
|
||||||
|
|
||||||
foreach (@{$self->{filter}}) {
|
my $items = $options{custom}->get_psus();
|
||||||
if ($options{section} =~ /$_->{filter}/) {
|
|
||||||
if (!defined($options{instance}) && !defined($_->{instance})) {
|
|
||||||
$self->{output}->output_add(long_msg => sprintf("Skipping $options{section} section."));
|
|
||||||
return 1;
|
|
||||||
} elsif (defined($options{instance}) && $options{instance} =~ /$_->{instance}/) {
|
|
||||||
$self->{output}->output_add(long_msg => sprintf("Skipping $options{section} section $options{instance} instance."));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub get_severity {
|
$self->{psu} = {};
|
||||||
my ($self, %options) = @_;
|
foreach my $item (@$items) {
|
||||||
my $status = 'UNKNOWN'; # default
|
next if (defined($self->{option_results}->{filter_engine_id}) && $self->{option_results}->{filter_engine_id} ne '' &&
|
||||||
|
$item->{engine_id} !~ /$self->{option_results}->{filter_engine_id}/);
|
||||||
if (defined($self->{overload_th}->{$options{section}})) {
|
next if (defined($self->{option_results}->{filter_psu_name}) && $self->{option_results}->{filter_psu_name} ne '' &&
|
||||||
foreach (@{$self->{overload_th}->{$options{section}}}) {
|
$item->{name} !~ /$self->{option_results}->{filter_psu_name}/);
|
||||||
if ($options{value} =~ /$_->{filter}/i &&
|
|
||||||
(!defined($options{instance}) || $options{instance} =~ /$_->{instance}/)) {
|
$self->{psu}->{ $item->{name} } = $item;
|
||||||
$status = $_->{status};
|
$self->{psu}->{ $item->{name} }->{psu_name} = $item->{name};
|
||||||
return $status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
my $label = defined($options{label}) ? $options{label} : $options{section};
|
|
||||||
foreach (@{$thresholds->{$label}}) {
|
|
||||||
if ($options{value} =~ /$$_[0]/i) {
|
|
||||||
$status = $$_[1];
|
|
||||||
return $status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
@ -184,24 +96,37 @@ __END__
|
||||||
|
|
||||||
=head1 MODE
|
=head1 MODE
|
||||||
|
|
||||||
Check Power-supplies infos for VPlex
|
Check power-supplies.
|
||||||
|
|
||||||
=over 8
|
=over 8
|
||||||
|
|
||||||
=item B<--engine>
|
=item B<--filter-engine-id>
|
||||||
|
|
||||||
Specify the engine number to be checked (1-1 or 2-1 usually)
|
Filter power supplies by engine id (can be a regexp).
|
||||||
|
|
||||||
=item B<--filter>
|
=item B<--filter-psu-name>
|
||||||
|
|
||||||
Filter some parts (comma seperated list)
|
Filter power supplies by power supply name (can be a regexp).
|
||||||
Can also exclude specific instance: --filter=psu,engine-1-1_power-supply-b1
|
|
||||||
|
|
||||||
=item B<--threshold-overload>
|
=item B<--warning-operational-status>
|
||||||
|
|
||||||
Set to overload default threshold values (syntax: section,[instance,]status,regexp)
|
Set warning threshold for status.
|
||||||
It used before default thresholds (order stays).
|
Can used special variables like: %{operational_status}, %{engine_id}, %{psu_name}
|
||||||
Example: --threshold-overload='psu,CRITICAL,^(?!(false)$)'
|
|
||||||
|
=item B<--critical-operational-status>
|
||||||
|
|
||||||
|
Set critical threshold for status (Default: '%{operational_status} ne "online"').
|
||||||
|
Can used special variables like: %{operational_status}, %{engine_id}, %{psu_name}
|
||||||
|
|
||||||
|
=item B<--warning-temperature-status>
|
||||||
|
|
||||||
|
Set warning threshold for status.
|
||||||
|
Can used special variables like: %{temperature_threshold_exceeded}, %{engine_id}, %{psu_name}
|
||||||
|
|
||||||
|
=item B<--critical-temperature-status>
|
||||||
|
|
||||||
|
Set critical threshold for status (Default: '%{operational_status} ne "online"').
|
||||||
|
Can used special variables like: %{temperature_threshold_exceeded}, %{engine_id}, %{psu_name}
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
|
|
|
@ -20,150 +20,77 @@
|
||||||
|
|
||||||
package storage::emc::vplex::restapi::mode::storagevolumes;
|
package storage::emc::vplex::restapi::mode::storagevolumes;
|
||||||
|
|
||||||
use base qw(centreon::plugins::mode);
|
use base qw(centreon::plugins::templates::counter);
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold_ng);
|
||||||
|
|
||||||
my $thresholds = {
|
sub custom_status_output {
|
||||||
volume_health => [
|
my ($self, %options) = @_;
|
||||||
['ok', 'ok'],
|
|
||||||
['.*', 'CRITICAL'],
|
return sprintf(
|
||||||
],
|
'health state: %s',
|
||||||
};
|
$self->{result_values}->{health_state}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub prefix_volume_output {
|
||||||
|
my ($self, %options) = @_;
|
||||||
|
|
||||||
|
return sprintf(
|
||||||
|
"storage volume '%s' [cluster: %s] ",
|
||||||
|
$options{instance_value}->{volume_name},
|
||||||
|
$options{instance_value}->{cluster_name}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub set_counters {
|
||||||
|
my ($self, %options) = @_;
|
||||||
|
|
||||||
|
$self->{maps_counters_type} = [
|
||||||
|
{ name => 'volumes', type => 1, cb_prefix_output => 'prefix_volume_output', message_multiple => 'All storage volumes are ok' }
|
||||||
|
];
|
||||||
|
|
||||||
|
$self->{maps_counters}->{volumes} = [
|
||||||
|
{ label => 'health-status', type => 2, critical_default => '%{health_state} ne "ok"', set => {
|
||||||
|
key_values => [ { name => 'health_state' }, { name => 'cluster_name' }, { name => 'volume_name' } ],
|
||||||
|
closure_custom_output => $self->can('custom_status_output'),
|
||||||
|
closure_custom_perfdata => sub { return 0; },
|
||||||
|
closure_custom_threshold_check => \&catalog_status_threshold_ng
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
sub new {
|
sub new {
|
||||||
my ($class, %options) = @_;
|
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;
|
bless $self, $class;
|
||||||
|
|
||||||
$options{options}->add_options(arguments => {
|
$options{options}->add_options(arguments => {
|
||||||
'cluster:s' => { name => 'cluster' },
|
'filter-cluster-name:s' => { name => 'filter_cluster_name' },
|
||||||
'filter:s@' => { name => 'filter' },
|
'filter-volume-name:s' => { name => 'filter_volume_name' }
|
||||||
'threshold-overload:s@' => { name => 'threshold_overload' },
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return $self;
|
return $self;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub check_options {
|
sub manage_selection {
|
||||||
my ($self, %options) = @_;
|
|
||||||
$self->SUPER::init(%options);
|
|
||||||
|
|
||||||
$self->{filter} = [];
|
|
||||||
foreach my $val (@{$self->{option_results}->{filter}}) {
|
|
||||||
next if (!defined($val) || $val eq '');
|
|
||||||
my @values = split (/,/, $val);
|
|
||||||
push @{$self->{filter}}, { filter => $values[0], instance => $values[1] };
|
|
||||||
}
|
|
||||||
|
|
||||||
$self->{overload_th} = {};
|
|
||||||
foreach my $val (@{$self->{option_results}->{threshold_overload}}) {
|
|
||||||
next if (!defined($val) || $val eq '');
|
|
||||||
my @values = split (/,/, $val);
|
|
||||||
if (scalar(@values) < 3) {
|
|
||||||
$self->{output}->add_option_msg(short_msg => "Wrong threshold-overload option '" . $val . "'.");
|
|
||||||
$self->{output}->option_exit();
|
|
||||||
}
|
|
||||||
my ($section, $instance, $status, $filter);
|
|
||||||
if (scalar(@values) == 3) {
|
|
||||||
($section, $status, $filter) = @values;
|
|
||||||
$instance = '.*';
|
|
||||||
} else {
|
|
||||||
($section, $instance, $status, $filter) = @values;
|
|
||||||
}
|
|
||||||
if ($section !~ /^volume/) {
|
|
||||||
$self->{output}->add_option_msg(short_msg => "Wrong threshold-overload section '" . $val . "'.");
|
|
||||||
$self->{output}->option_exit();
|
|
||||||
}
|
|
||||||
if ($self->{output}->is_litteral_status(status => $status) == 0) {
|
|
||||||
$self->{output}->add_option_msg(short_msg => "Wrong threshold-overload status '" . $val . "'.");
|
|
||||||
$self->{output}->option_exit();
|
|
||||||
}
|
|
||||||
$self->{overload_th}->{$section} = [] if (!defined($self->{overload_th}->{$section}));
|
|
||||||
push @{$self->{overload_th}->{$section}}, {filter => $filter, status => $status, instance => $instance };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub run {
|
|
||||||
my ($self, %options) = @_;
|
|
||||||
my $vplex = $options{custom};
|
|
||||||
|
|
||||||
my $items = $vplex->get_items(
|
|
||||||
url => '/vplex/clusters/',
|
|
||||||
parent => 1,
|
|
||||||
parent_filter => $self->{option_results}->{cluster},
|
|
||||||
parent_filter_prefix => 'cluster-',
|
|
||||||
parent_select => '/clusters/(.*?)/',
|
|
||||||
obj => 'storage-elements/storage-volumes'
|
|
||||||
);
|
|
||||||
|
|
||||||
$self->{output}->output_add(severity => 'OK',
|
|
||||||
short_msg => 'All storage volumes are OK');
|
|
||||||
|
|
||||||
foreach my $cluster_name (sort keys %{$items}) {
|
|
||||||
foreach my $volume_name (sort keys %{$items->{$cluster_name}}) {
|
|
||||||
my $instance = $cluster_name . '_' . $volume_name;
|
|
||||||
|
|
||||||
next if ($self->check_filter(section => 'volume', instance => $instance));
|
|
||||||
|
|
||||||
$self->{output}->output_add(long_msg => sprintf("Storage volume '%s' health state is '%s'",
|
|
||||||
$instance,
|
|
||||||
$items->{$cluster_name}->{$volume_name}->{'health-state'}));
|
|
||||||
|
|
||||||
my $exit = $self->get_severity(section => 'volume_health', instance => $instance, value => $items->{$cluster_name}->{$volume_name}->{'health-state'});
|
|
||||||
if (!$self->{output}->is_status(value => $exit, compare => 'ok', litteral => 1)) {
|
|
||||||
$self->{output}->output_add(severity => $exit,
|
|
||||||
short_msg => sprintf("Storage volume '%s' health state is '%s'",
|
|
||||||
$instance, $items->{$cluster_name}->{$volume_name}->{'health-state'}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$self->{output}->display();
|
|
||||||
$self->{output}->exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
sub check_filter {
|
|
||||||
my ($self, %options) = @_;
|
my ($self, %options) = @_;
|
||||||
|
|
||||||
foreach (@{$self->{filter}}) {
|
my $items = $options{custom}->get_storage_volumes();
|
||||||
if ($options{section} =~ /$_->{filter}/) {
|
|
||||||
if (!defined($options{instance}) && !defined($_->{instance})) {
|
|
||||||
$self->{output}->output_add(long_msg => sprintf("Skipping $options{section} section."));
|
|
||||||
return 1;
|
|
||||||
} elsif (defined($options{instance}) && $options{instance} =~ /$_->{instance}/) {
|
|
||||||
$self->{output}->output_add(long_msg => sprintf("Skipping $options{section} section $options{instance} instance."));
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub get_severity {
|
$self->{volumes} = {};
|
||||||
my ($self, %options) = @_;
|
foreach my $item (@$items) {
|
||||||
my $status = 'UNKNOWN'; # default
|
next if (defined($self->{option_results}->{filter_cluster_name}) && $self->{option_results}->{filter_cluster_name} ne '' &&
|
||||||
|
$item->{cluster_name} !~ /$self->{option_results}->{filter_cluster_name}/);
|
||||||
if (defined($self->{overload_th}->{$options{section}})) {
|
next if (defined($self->{option_results}->{filter_volume_name}) && $self->{option_results}->{filter_volume_name} ne '' &&
|
||||||
foreach (@{$self->{overload_th}->{$options{section}}}) {
|
$item->{name} !~ /$self->{option_results}->{filter_volume_name}/);
|
||||||
if ($options{value} =~ /$_->{filter}/i &&
|
|
||||||
(!defined($options{instance}) || $options{instance} =~ /$_->{instance}/)) {
|
$self->{volumes}->{ $item->{name} } = $item;
|
||||||
$status = $_->{status};
|
$self->{volumes}->{ $item->{name} }->{volume_name} = $item->{name};
|
||||||
return $status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
my $label = defined($options{label}) ? $options{label} : $options{section};
|
|
||||||
foreach (@{$thresholds->{$label}}) {
|
|
||||||
if ($options{value} =~ /$$_[0]/i) {
|
|
||||||
$status = $$_[1];
|
|
||||||
return $status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
@ -172,24 +99,27 @@ __END__
|
||||||
|
|
||||||
=head1 MODE
|
=head1 MODE
|
||||||
|
|
||||||
Check Cluster Storage Volume health for VPlex
|
Check storage volumes.
|
||||||
|
|
||||||
=over 8
|
=over 8
|
||||||
|
|
||||||
=item B<--cluster>
|
=item B<--filter-cluster-name>
|
||||||
|
|
||||||
Set cluster name to check (Example: '1')
|
Filter volumes by cluster name (can be a regexp).
|
||||||
|
|
||||||
=item B<--filter>
|
=item B<--filter-volume-name>
|
||||||
|
|
||||||
Filter some parts (comma seperated list)
|
Filter volumes by volume name (can be a regexp).
|
||||||
Can also exclude specific instance: --filter=volume,cluster-1_xxxx
|
|
||||||
|
|
||||||
=item B<--threshold-overload>
|
=item B<--warning-health-status>
|
||||||
|
|
||||||
Set to overload default threshold values (syntax: section,[instance,]status,regexp)
|
Set warning threshold for status.
|
||||||
It used before default thresholds (order stays).
|
Can used special variables like: %{health_state}, %{cluster_name}, %{volume_name}
|
||||||
Example: --threshold-overload='volume_health,CRITICAL,^(?!(ok)$)'
|
|
||||||
|
=item B<--critical-health-status>
|
||||||
|
|
||||||
|
Set critical threshold for status (Default: '%{health_state} ne "ok"').
|
||||||
|
Can used special variables like: %{health_state}, %{cluster_name}, %{volume_name}
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
|
|
|
@ -29,18 +29,18 @@ sub new {
|
||||||
my $self = $class->SUPER::new(package => __PACKAGE__, %options);
|
my $self = $class->SUPER::new(package => __PACKAGE__, %options);
|
||||||
bless $self, $class;
|
bless $self, $class;
|
||||||
|
|
||||||
$self->{version} = '1.0';
|
|
||||||
$self->{modes} = {
|
$self->{modes} = {
|
||||||
'psus' => 'storage::emc::vplex::restapi::mode::psus',
|
'cluster-communication' => 'storage::emc::vplex::restapi::mode::clustercommunication',
|
||||||
'fans' => 'storage::emc::vplex::restapi::mode::fans',
|
|
||||||
'distributed-devices' => 'storage::emc::vplex::restapi::mode::distributeddevices',
|
|
||||||
'cluster-devices' => 'storage::emc::vplex::restapi::mode::clusterdevices',
|
'cluster-devices' => 'storage::emc::vplex::restapi::mode::clusterdevices',
|
||||||
'storage-volumes' => 'storage::emc::vplex::restapi::mode::storagevolumes',
|
|
||||||
'directors' => 'storage::emc::vplex::restapi::mode::directors',
|
'directors' => 'storage::emc::vplex::restapi::mode::directors',
|
||||||
'cluster-communication' => 'storage::emc::vplex::restapi::mode::clustercommunication'
|
'distributed-devices' => 'storage::emc::vplex::restapi::mode::distributeddevices',
|
||||||
|
'fans' => 'storage::emc::vplex::restapi::mode::fans',
|
||||||
|
'psus' => 'storage::emc::vplex::restapi::mode::psus',
|
||||||
|
'storage-volumes' => 'storage::emc::vplex::restapi::mode::storagevolumes'
|
||||||
};
|
};
|
||||||
|
|
||||||
$self->{custom_modes}->{vplexapi} = 'storage::emc::vplex::restapi::custom::vplexapi';
|
$self->{custom_modes}->{apiv1} = 'storage::emc::vplex::restapi::custom::apiv1';
|
||||||
|
$self->{custom_modes}->{apiv2} = 'storage::emc::vplex::restapi::custom::apiv2';
|
||||||
return $self;
|
return $self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,3 +51,5 @@ __END__
|
||||||
=head1 PLUGIN DESCRIPTION
|
=head1 PLUGIN DESCRIPTION
|
||||||
|
|
||||||
Check EMC Vplex through HTTP/REST API.
|
Check EMC Vplex through HTTP/REST API.
|
||||||
|
|
||||||
|
=cut
|
||||||
|
|
Loading…
Reference in New Issue