(plugin) storage::emc::vplex::restapi - handle api v2 (#3880)

This commit is contained in:
qgarnier 2022-09-05 15:33:30 +02:00 committed by GitHub
parent 3c8e83fb1e
commit 7d8c202d41
11 changed files with 1252 additions and 1231 deletions

View File

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

View File

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

View File

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

View File

@ -20,140 +20,70 @@
package storage::emc::vplex::restapi::mode::clustercommunication;
use base qw(centreon::plugins::mode);
use base qw(centreon::plugins::templates::counter);
use strict;
use warnings;
use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold_ng);
my $thresholds = {
component_opstatus => [
['cluster-in-contact', 'OK'],
['in-contact', 'OK'],
['.*', 'CRITICAL']
]
};
sub custom_status_output {
my ($self, %options) = @_;
return sprintf(
'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 {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options);
my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1);
bless $self, $class;
$options{options}->add_options(arguments => {
'filter:s@' => { name => 'filter' },
'threshold-overload:s@' => { name => 'threshold_overload' }
'filter-component-name:s' => { name => 'filter_component_name' }
});
return $self;
}
sub check_options {
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 {
sub manage_selection {
my ($self, %options) = @_;
foreach (@{$self->{filter}}) {
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;
}
my $items = $options{custom}->get_cluster_communication();
sub get_severity {
my ($self, %options) = @_;
my $status = 'UNKNOWN'; # default
if (defined($self->{overload_th}->{$options{section}})) {
foreach (@{$self->{overload_th}->{$options{section}}}) {
if ($options{value} =~ /$_->{filter}/i &&
(!defined($options{instance}) || $options{instance} =~ /$_->{instance}/)) {
$status = $_->{status};
return $status;
}
}
$self->{components} = {};
foreach my $item (@$items) {
next if (defined($self->{option_results}->{filter_component_name}) && $self->{option_results}->{filter_component_name} ne '' &&
$item->{name} !~ /$self->{option_results}->{filter_component_name}/);
$self->{components}->{ $item->{name} } = $item;
}
my $label = defined($options{label}) ? $options{label} : $options{section};
foreach (@{$thresholds->{$label}}) {
if ($options{value} =~ /$$_[0]/i) {
$status = $$_[1];
return $status;
}
}
return $status;
}
1;
@ -162,20 +92,23 @@ __END__
=head1 MODE
Check Cluster communication state for VPlex
Check cluster communication state.
=over 8
=item B<--filter>
=item B<--filter-component-name>
Filter some parts (comma seperated list)
Can also exclude specific instance: --filter=component,cluster-1
Filter components by name (can be a regexp).
=item B<--threshold-overload>
=item B<--warning-operational-status>
Set to overload default threshold values (syntax: section,[instance,]status,regexp)
It used before default thresholds (order stays).
Example: --threshold-overload='component_opstatus,CRITICAL,^(?!(in-contact|cluster-in-contact)$)'
Set warning threshold for status.
Can used special variables like: %{operational_state}, %{admin_state}, %{name}
=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

View File

@ -20,151 +20,77 @@
package storage::emc::vplex::restapi::mode::clusterdevices;
use base qw(centreon::plugins::mode);
use base qw(centreon::plugins::templates::counter);
use strict;
use warnings;
use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold_ng);
my $thresholds = {
device_health => [
['ok', 'ok'],
['.*', 'CRITICAL'],
],
};
sub custom_status_output {
my ($self, %options) = @_;
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 {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options);
my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1);
bless $self, $class;
$options{options}->add_options(arguments =>
{
"cluster:s" => { name => 'cluster' },
"filter:s@" => { name => 'filter' },
"threshold-overload:s@" => { name => 'threshold_overload' },
});
$options{options}->add_options(arguments => {
'filter-cluster-name:s' => { name => 'filter_cluster_name' },
'filter-device-name:s' => { name => 'filter_device_name' }
});
return $self;
}
sub check_options {
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 {
sub manage_selection {
my ($self, %options) = @_;
foreach (@{$self->{filter}}) {
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;
}
my $items = $options{custom}->get_devices();
sub get_severity {
my ($self, %options) = @_;
my $status = 'UNKNOWN'; # default
if (defined($self->{overload_th}->{$options{section}})) {
foreach (@{$self->{overload_th}->{$options{section}}}) {
if ($options{value} =~ /$_->{filter}/i &&
(!defined($options{instance}) || $options{instance} =~ /$_->{instance}/)) {
$status = $_->{status};
return $status;
}
}
$self->{devices} = {};
foreach my $item (@$items) {
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}/);
next if (defined($self->{option_results}->{filter_device_name}) && $self->{option_results}->{filter_device_name} ne '' &&
$item->{name} !~ /$self->{option_results}->{filter_device_name}/);
$self->{devices}->{ $item->{name} } = $item;
$self->{devices}->{ $item->{name} }->{device_name} = $item->{name};
}
my $label = defined($options{label}) ? $options{label} : $options{section};
foreach (@{$thresholds->{$label}}) {
if ($options{value} =~ /$$_[0]/i) {
$status = $$_[1];
return $status;
}
}
return $status;
}
1;
@ -173,24 +99,27 @@ __END__
=head1 MODE
Check Cluster devices health for VPlex
Check cluster devices.
=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)
Can also exclude specific instance: --filter=device,cluster-1_xxxx
Filter devices by device name (can be a regexp).
=item B<--threshold-overload>
=item B<--warning-health-status>
Set to overload default threshold values (syntax: section,[instance,]status,regexp)
It used before default thresholds (order stays).
Example: --threshold-overload='device_health,CRITICAL,^(?!(ok)$)'
Set warning threshold for status.
Can used special variables like: %{health_state}, %{cluster_name}, %{device_name}
=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

View File

@ -20,196 +20,100 @@
package storage::emc::vplex::restapi::mode::directors;
use base qw(centreon::plugins::mode);
use base qw(centreon::plugins::templates::counter);
use strict;
use warnings;
use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold_ng);
my $thresholds = {
director_health => [
['ok', 'OK'],
['.*', 'CRITICAL'],
],
director_communication => [
['ok', 'OK'],
['.*', 'CRITICAL'],
],
director_temperature => [
['false', 'OK'],
['.*', 'CRITICAL'],
],
director_voltage => [
['false', 'OK'],
['.*', 'CRITICAL'],
],
director_vplex_splitter => [
['ok', 'OK'],
['.*', 'CRITICAL'],
],
};
sub prefix_director_output {
my ($self, %options) = @_;
return sprintf(
"director '%s' [engine: %s] ",
$options{instance_value}->{director_name},
$options{instance_value}->{engine_id}
);
}
sub set_counters {
my ($self, %options) = @_;
$self->{maps_counters_type} = [
{ name => 'directors', type => 1, cb_prefix_output => 'prefix_director_output', message_multiple => 'All directors are ok' }
];
$self->{maps_counters}->{directors} = [
{ label => 'health-status', type => 2, critical_default => '%{health_state} ne "ok"', set => {
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 {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options);
my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1);
bless $self, $class;
$options{options}->add_options(arguments =>
{
"engine:s" => { name => 'engine' },
"filter:s@" => { name => 'filter' },
"threshold-overload:s@" => { name => 'threshold_overload' },
});
$options{options}->add_options(arguments => {
'filter-engine-id:s' => { name => 'filter_engine_id' },
'filter-director-name:s' => { name => 'filter_director_name' }
});
return $self;
}
sub check_options {
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 {
sub manage_selection {
my ($self, %options) = @_;
foreach (@{$self->{filter}}) {
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;
}
my $items = $options{custom}->get_directors();
sub get_severity {
my ($self, %options) = @_;
my $status = 'UNKNOWN'; # default
if (defined($self->{overload_th}->{$options{section}})) {
foreach (@{$self->{overload_th}->{$options{section}}}) {
if ($options{value} =~ /$_->{filter}/i &&
(!defined($options{instance}) || $options{instance} =~ /$_->{instance}/)) {
$status = $_->{status};
return $status;
}
}
$self->{directors} = {};
foreach my $item (@$items) {
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}/);
next if (defined($self->{option_results}->{filter_director_name}) && $self->{option_results}->{filter_director_name} ne '' &&
$item->{name} !~ /$self->{option_results}->{filter_director_name}/);
$self->{directors}->{ $item->{name} } = $item;
$self->{directors}->{ $item->{name} }->{director_name} = $item->{name};
$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;
@ -218,24 +122,67 @@ __END__
=head1 MODE
Check Directors state for VPlex
Check directors.
=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)
Can also exclude specific instance: --filter=director,engine-1-1_director-1-1-B
Filter directors by director name (can be a regexp).
=item B<--threshold-overload>
=item B<--warning-health-status>
Set to overload default threshold values (syntax: section,[instance,]status,regexp)
It used before default thresholds (order stays).
Example: --threshold-overload='director_temperature,CRITICAL,^(?!(false)$)'
Set warning threshold for status.
Can used special variables like: %{operational_status}, %{engine_id}, %{director_name}
=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

View File

@ -20,163 +20,78 @@
package storage::emc::vplex::restapi::mode::distributeddevices;
use base qw(centreon::plugins::mode);
use base qw(centreon::plugins::templates::counter);
use strict;
use warnings;
use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold_ng);
my $thresholds = {
device_health => [
['ok', 'OK'],
['.*', 'CRITICAL'],
],
device_opstatus => [
['ok', 'OK'],
['.*', 'CRITICAL'],
],
device_service => [
['running', 'OK'],
['.*', 'CRITICAL'],
],
};
sub prefix_device_output {
my ($self, %options) = @_;
return sprintf(
"distributed device '%s' ",
$options{instance_value}->{device_name}
);
}
sub set_counters {
my ($self, %options) = @_;
$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 {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options);
my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1);
bless $self, $class;
$options{options}->add_options(arguments =>
{
"filter:s@" => { name => 'filter' },
"threshold-overload:s@" => { name => 'threshold_overload' },
});
$options{options}->add_options(arguments => {
'filter-device-name:s' => { name => 'filter_device_name' }
});
return $self;
}
sub check_options {
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 {
sub manage_selection {
my ($self, %options) = @_;
foreach (@{$self->{filter}}) {
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;
}
my $items = $options{custom}->get_distributed_devices();
sub get_severity {
my ($self, %options) = @_;
my $status = 'UNKNOWN'; # default
if (defined($self->{overload_th}->{$options{section}})) {
foreach (@{$self->{overload_th}->{$options{section}}}) {
if ($options{value} =~ /$_->{filter}/i &&
(!defined($options{instance}) || $options{instance} =~ /$_->{instance}/)) {
$status = $_->{status};
return $status;
}
}
$self->{devices} = {};
foreach my $item (@$items) {
next if (defined($self->{option_results}->{filter_device_name}) && $self->{option_results}->{filter_device_name} ne '' &&
$item->{name} !~ /$self->{option_results}->{filter_device_name}/);
$self->{devices}->{ $item->{name} } = $item;
$self->{devices}->{ $item->{name} }->{device_name} = $item->{name};
}
my $label = defined($options{label}) ? $options{label} : $options{section};
foreach (@{$thresholds->{$label}}) {
if ($options{value} =~ /$$_[0]/i) {
$status = $$_[1];
return $status;
}
}
return $status;
}
1;
@ -185,20 +100,43 @@ __END__
=head1 MODE
Check distributed devices for VPlex
Check distributed devices.
=over 8
=item B<--filter>
=item B<--filter-device-name>
Filter some parts (comma seperated list)
Can also exclude specific instance: --filter=component,cluster-1
Filter devices by device name (can be a regexp).
=item B<--threshold-overload>
=item B<--warning-operational-status>
Set to overload default threshold values (syntax: section,[instance,]status,regexp)
It used before default thresholds (order stays).
Example: --threshold-overload='component_opstatus,CRITICAL,^(?!(in-contact|cluster-in-contact)$)'
Set warning threshold for status.
Can used special variables like: %{operational_status}, %{device_name}
=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

View File

@ -20,161 +20,75 @@
package storage::emc::vplex::restapi::mode::fans;
use base qw(centreon::plugins::mode);
use base qw(centreon::plugins::templates::counter);
use strict;
use warnings;
use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold_ng);
my $thresholds = {
fan_opstatus => [
['online', 'OK'],
['.*', 'CRITICAL'],
],
fan => [
['false', 'OK'],
['.*', 'CRITICAL'],
],
};
sub prefix_fan_output {
my ($self, %options) = @_;
return sprintf(
"fan '%s' [engine: %s] ",
$options{instance_value}->{fan_name},
$options{instance_value}->{engine_id}
);
}
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 {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options);
my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1);
bless $self, $class;
$options{options}->add_options(arguments =>
{
"engine:s" => { name => 'engine' },
"filter:s@" => { name => 'filter' },
"threshold-overload:s@" => { name => 'threshold_overload' },
});
$options{options}->add_options(arguments => {
'filter-engine-id:s' => { name => 'filter_engine_id' },
'filter-fan-name:s' => { name => 'filter_fan_name' }
});
return $self;
}
sub check_options {
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 {
sub manage_selection {
my ($self, %options) = @_;
foreach (@{$self->{filter}}) {
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;
}
my $items = $options{custom}->get_fans();
sub get_severity {
my ($self, %options) = @_;
my $status = 'UNKNOWN'; # default
if (defined($self->{overload_th}->{$options{section}})) {
foreach (@{$self->{overload_th}->{$options{section}}}) {
if ($options{value} =~ /$_->{filter}/i &&
(!defined($options{instance}) || $options{instance} =~ /$_->{instance}/)) {
$status = $_->{status};
return $status;
}
}
$self->{fans} = {};
foreach my $item (@$items) {
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}/);
next if (defined($self->{option_results}->{filter_fan_name}) && $self->{option_results}->{filter_fan_name} ne '' &&
$item->{name} !~ /$self->{option_results}->{filter_fan_name}/);
$self->{fans}->{ $item->{name} } = $item;
$self->{fans}->{ $item->{name} }->{fan_name} = $item->{name};
}
my $label = defined($options{label}) ? $options{label} : $options{section};
foreach (@{$thresholds->{$label}}) {
if ($options{value} =~ /$$_[0]/i) {
$status = $$_[1];
return $status;
}
}
return $status;
}
1;
@ -183,24 +97,37 @@ __END__
=head1 MODE
Check Fan state for VPlex
Check fans.
=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)
Can also exclude specific instance: --filter=fan,engine-1-1_fan-psa0-intake
Filter fans by fan name (can be a regexp).
=item B<--threshold-overload>
=item B<--warning-operational-status>
Set to overload default threshold values (syntax: section,[instance,]status,regexp)
It used before default thresholds (order stays).
Example: --threshold-overload='fan,CRITICAL,^(?!(false)$)'
Set warning threshold for status.
Can used special variables like: %{operational_status}, %{engine_id}, %{fan_name}
=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

View File

@ -19,163 +19,75 @@
package storage::emc::vplex::restapi::mode::psus;
use base qw(centreon::plugins::mode);
use base qw(centreon::plugins::templates::counter);
use strict;
use warnings;
use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold_ng);
my $thresholds = {
psu_opstatus => [
['online', 'OK'],
['.*', 'CRITICAL'],
],
psu => [
['false', 'OK'],
['.*', 'CRITICAL'],
],
};
sub prefix_psu_output {
my ($self, %options) = @_;
return sprintf(
"power supply '%s' [engine: %s] ",
$options{instance_value}->{psu_name},
$options{instance_value}->{engine_id}
);
}
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 {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options);
my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1);
bless $self, $class;
$options{options}->add_options(arguments =>
{
"engine:s" => { name => 'engine' },
"filter:s@" => { name => 'filter' },
"threshold-overload:s@" => { name => 'threshold_overload' },
});
$options{options}->add_options(arguments => {
'filter-engine-id:s' => { name => 'filter_engine_id' },
'filter-psu-name:s' => { name => 'filter_psu_name' }
});
return $self;
}
sub check_options {
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 {
sub manage_selection {
my ($self, %options) = @_;
foreach (@{$self->{filter}}) {
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;
}
my $items = $options{custom}->get_psus();
sub get_severity {
my ($self, %options) = @_;
my $status = 'UNKNOWN'; # default
if (defined($self->{overload_th}->{$options{section}})) {
foreach (@{$self->{overload_th}->{$options{section}}}) {
if ($options{value} =~ /$_->{filter}/i &&
(!defined($options{instance}) || $options{instance} =~ /$_->{instance}/)) {
$status = $_->{status};
return $status;
}
}
$self->{psu} = {};
foreach my $item (@$items) {
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}/);
next if (defined($self->{option_results}->{filter_psu_name}) && $self->{option_results}->{filter_psu_name} ne '' &&
$item->{name} !~ /$self->{option_results}->{filter_psu_name}/);
$self->{psu}->{ $item->{name} } = $item;
$self->{psu}->{ $item->{name} }->{psu_name} = $item->{name};
}
my $label = defined($options{label}) ? $options{label} : $options{section};
foreach (@{$thresholds->{$label}}) {
if ($options{value} =~ /$$_[0]/i) {
$status = $$_[1];
return $status;
}
}
return $status;
}
1;
@ -184,24 +96,37 @@ __END__
=head1 MODE
Check Power-supplies infos for VPlex
Check power-supplies.
=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)
Can also exclude specific instance: --filter=psu,engine-1-1_power-supply-b1
Filter power supplies by power supply name (can be a regexp).
=item B<--threshold-overload>
=item B<--warning-operational-status>
Set to overload default threshold values (syntax: section,[instance,]status,regexp)
It used before default thresholds (order stays).
Example: --threshold-overload='psu,CRITICAL,^(?!(false)$)'
Set warning threshold for status.
Can used special variables like: %{operational_status}, %{engine_id}, %{psu_name}
=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

View File

@ -20,150 +20,77 @@
package storage::emc::vplex::restapi::mode::storagevolumes;
use base qw(centreon::plugins::mode);
use base qw(centreon::plugins::templates::counter);
use strict;
use warnings;
use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold_ng);
my $thresholds = {
volume_health => [
['ok', 'ok'],
['.*', 'CRITICAL'],
],
};
sub custom_status_output {
my ($self, %options) = @_;
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 {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options);
my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1);
bless $self, $class;
$options{options}->add_options(arguments => {
'cluster:s' => { name => 'cluster' },
'filter:s@' => { name => 'filter' },
'threshold-overload:s@' => { name => 'threshold_overload' },
'filter-cluster-name:s' => { name => 'filter_cluster_name' },
'filter-volume-name:s' => { name => 'filter_volume_name' }
});
return $self;
}
sub check_options {
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 {
sub manage_selection {
my ($self, %options) = @_;
foreach (@{$self->{filter}}) {
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;
}
my $items = $options{custom}->get_storage_volumes();
sub get_severity {
my ($self, %options) = @_;
my $status = 'UNKNOWN'; # default
if (defined($self->{overload_th}->{$options{section}})) {
foreach (@{$self->{overload_th}->{$options{section}}}) {
if ($options{value} =~ /$_->{filter}/i &&
(!defined($options{instance}) || $options{instance} =~ /$_->{instance}/)) {
$status = $_->{status};
return $status;
}
}
$self->{volumes} = {};
foreach my $item (@$items) {
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}/);
next if (defined($self->{option_results}->{filter_volume_name}) && $self->{option_results}->{filter_volume_name} ne '' &&
$item->{name} !~ /$self->{option_results}->{filter_volume_name}/);
$self->{volumes}->{ $item->{name} } = $item;
$self->{volumes}->{ $item->{name} }->{volume_name} = $item->{name};
}
my $label = defined($options{label}) ? $options{label} : $options{section};
foreach (@{$thresholds->{$label}}) {
if ($options{value} =~ /$$_[0]/i) {
$status = $$_[1];
return $status;
}
}
return $status;
}
1;
@ -172,24 +99,27 @@ __END__
=head1 MODE
Check Cluster Storage Volume health for VPlex
Check storage volumes.
=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)
Can also exclude specific instance: --filter=volume,cluster-1_xxxx
Filter volumes by volume name (can be a regexp).
=item B<--threshold-overload>
=item B<--warning-health-status>
Set to overload default threshold values (syntax: section,[instance,]status,regexp)
It used before default thresholds (order stays).
Example: --threshold-overload='volume_health,CRITICAL,^(?!(ok)$)'
Set warning threshold for status.
Can used special variables like: %{health_state}, %{cluster_name}, %{volume_name}
=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

View File

@ -29,18 +29,18 @@ sub new {
my $self = $class->SUPER::new(package => __PACKAGE__, %options);
bless $self, $class;
$self->{version} = '1.0';
$self->{modes} = {
'psus' => 'storage::emc::vplex::restapi::mode::psus',
'fans' => 'storage::emc::vplex::restapi::mode::fans',
'distributed-devices' => 'storage::emc::vplex::restapi::mode::distributeddevices',
'cluster-communication' => 'storage::emc::vplex::restapi::mode::clustercommunication',
'cluster-devices' => 'storage::emc::vplex::restapi::mode::clusterdevices',
'storage-volumes' => 'storage::emc::vplex::restapi::mode::storagevolumes',
'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;
}
@ -51,3 +51,5 @@ __END__
=head1 PLUGIN DESCRIPTION
Check EMC Vplex through HTTP/REST API.
=cut