add netapp restapi plugin

This commit is contained in:
cgagnaire 2018-04-03 10:31:55 +02:00
parent e0414e65bc
commit 1f4b834066
29 changed files with 5333 additions and 0 deletions

View File

@ -0,0 +1,263 @@
#
# Copyright 2018 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::netapp::restapi::custom::restapi;
use strict;
use warnings;
use centreon::plugins::http;
use JSON::XS;
use URI::Encode;
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' },
"url-path:s@" => { name => 'url_path' },
"port:s@" => { name => 'port' },
"proto:s@" => { name => 'proto' },
"username:s@" => { name => 'username' },
"password:s@" => { name => 'password' },
"proxyurl:s@" => { name => 'proxyurl' },
"timeout:s@" => { name => 'timeout' },
"ssl:s@" => { name => 'ssl' },
});
}
$options{options}->add_help(package => __PACKAGE__, sections => 'REST API OPTIONS', once => 1);
$self->{output} = $options{output};
$self->{mode} = $options{mode};
$self->{http} = centreon::plugins::http->new(output => $self->{output});
return $self;
}
sub set_options {
my ($self, %options) = @_;
$self->{option_results} = $options{option_results};
}
sub set_defaults {
my ($self, %options) = @_;
foreach (keys %{$options{default}}) {
if ($_ eq $self->{mode}) {
for (my $i = 0; $i < scalar(@{$options{default}->{$_}}); $i++) {
foreach my $opt (keys %{$options{default}->{$_}[$i]}) {
if (!defined($self->{option_results}->{$opt}[$i])) {
$self->{option_results}->{$opt}[$i] = $options{default}->{$_}[$i]->{$opt};
}
}
}
}
}
}
sub check_options {
my ($self, %options) = @_;
$self->{hostname} = (defined($self->{option_results}->{hostname})) ? shift(@{$self->{option_results}->{hostname}}) : undef;
$self->{url_path} = (defined($self->{option_results}->{url_path})) ? shift(@{$self->{option_results}->{url_path}}) : '/api/4.0/ontap';
$self->{port} = (defined($self->{option_results}->{port})) ? shift(@{$self->{option_results}->{port}}) : 8443;
$self->{proto} = (defined($self->{option_results}->{proto})) ? shift(@{$self->{option_results}->{proto}}) : 'https';
$self->{username} = (defined($self->{option_results}->{username})) ? shift(@{$self->{option_results}->{username}}) : '';
$self->{password} = (defined($self->{option_results}->{password})) ? shift(@{$self->{option_results}->{password}}) : '';
$self->{timeout} = (defined($self->{option_results}->{timeout})) ? shift(@{$self->{option_results}->{timeout}}) : 10;
$self->{proxyurl} = (defined($self->{option_results}->{proxyurl})) ? shift(@{$self->{option_results}->{proxyurl}}) : undef;
$self->{ssl} = (defined($self->{option_results}->{ssl})) ? shift(@{$self->{option_results}->{ssl}}) : 'tlsv1';
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} = $self->{port};
$self->{option_results}->{proto} = $self->{proto};
$self->{option_results}->{proxyurl} = $self->{proxyurl};
$self->{option_results}->{credentials} = 1;
$self->{option_results}->{username} = $self->{username};
$self->{option_results}->{password} = $self->{password};
$self->{option_results}->{ssl} = $self->{ssl};
$self->{option_results}->{warning_status} = '';
$self->{option_results}->{critical_status} = '';
}
sub settings {
my ($self, %options) = @_;
$self->build_options_for_httplib();
$self->{http}->set_options(%{$self->{option_results}});
}
sub get_connection_info {
my ($self, %options) = @_;
return $self->{hostname} . ":" . $self->{port};
}
sub get_objects {
my ($self, %options) = @_;
my %objects;
my $objects = $self->get(%options);
foreach my $object (@{$objects}) {
$objects{$object->{$options{key}}} = $object->{$options{name}};
}
return \%objects;
}
sub get_next {
my ($self, %options) = @_;
my $encoded_tag = '';
if (defined($options{nextTag})) {
my $uri = URI::Encode->new({encode_reserved => 1});
$encoded_tag = "nextTag=" . $uri->encode($options{nextTag});
}
my $url_path = $self->{url_path} . $options{path};
$url_path .= '?' . $options{uri} if (defined($options{args}));
$url_path .= '?' . $encoded_tag if (defined($options{nextTag}) && !defined($options{args}));
$url_path .= '&' . $encoded_tag if (defined($options{nextTag}) && defined($options{args}));
my $response = $self->{http}->request(url_path => $url_path);
my $content;
eval {
$content = JSON::XS->new->utf8->decode($response);
};
if ($@) {
$self->{output}->add_option_msg(short_msg => "Cannot decode json response: $@");
$self->{output}->option_exit();
}
if (defined($content->{errmsg})) {
$self->{output}->add_option_msg(short_msg => "Cannot get data: " . $content->{errmsg});
$self->{output}->option_exit();
}
return $content;
}
sub get {
my ($self, %options) = @_;
$self->settings();
my @result;
while(my $content = $self->get_next(%options)) {
push @result, @{$content->{result}->{records}};
last if (!defined($content->{result}->{nextTag}));
$options{nextTag} = $content->{result}->{nextTag};
}
return \@result;
}
1;
__END__
=head1 NAME
NetApp OnCommand REST API
=head1 SYNOPSIS
NetApp OnCommand Rest API custom mode
=head1 REST API OPTIONS
=over 8
=item B<--hostname>
NetApp hostname.
=item B<--url-path>
OnCommand API url path (Default: '/api/4.0/ontap')
=item B<--port>
OnCommand API port (Default: 8443)
=item B<--proto>
Specify https if needed (Default: 'https')
=item B<--username>
OnCommand API username.
=item B<--password>
OnCommand API password.
=item B<--proxyurl>
Proxy URL if any
=item B<--timeout>
Set HTTP timeout
=item B<--ssl>
SSL version (Default: tlsv1)
=back
=head1 DESCRIPTION
B<custom>.
=cut

View File

@ -0,0 +1,210 @@
#
# Copyright 2018 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::netapp::restapi::mode::aggregateraidstatus;
use base qw(centreon::plugins::templates::counter);
use strict;
use warnings;
my $instance_mode;
sub custom_status_threshold {
my ($self, %options) = @_;
my $status = 'ok';
my $message;
eval {
local $SIG{__WARN__} = sub { $message = $_[0]; };
local $SIG{__DIE__} = sub { $message = $_[0]; };
if (defined($instance_mode->{option_results}->{critical_status}) && $instance_mode->{option_results}->{critical_status} ne '' &&
eval "$instance_mode->{option_results}->{critical_status}") {
$status = 'critical';
} elsif (defined($instance_mode->{option_results}->{warning_status}) && $instance_mode->{option_results}->{warning_status} ne '' &&
eval "$instance_mode->{option_results}->{warning_status}") {
$status = 'warning';
}
};
if (defined($message)) {
$self->{output}->output_add(long_msg => 'filter status issue: ' . $message);
}
return $status;
}
sub custom_status_output {
my ($self, %options) = @_;
my $msg = sprintf("Raid status is '%s' [type: %s] [size: %s]",
$self->{result_values}->{status}, $self->{result_values}->{type}, $self->{result_values}->{size});
return $msg;
}
sub custom_status_calc {
my ($self, %options) = @_;
$self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_name'};
$self->{result_values}->{status} = $options{new_datas}->{$self->{instance} . '_raid_status'};
$self->{result_values}->{type} = $options{new_datas}->{$self->{instance} . '_raid_type'};
$self->{result_values}->{size} = $options{new_datas}->{$self->{instance} . '_raid_size'};
return 0;
}
sub prefix_output {
my ($self, %options) = @_;
return "Aggregate '" . $options{instance_value}->{name} . "' ";
}
sub set_counters {
my ($self, %options) = @_;
$self->{maps_counters_type} = [
{ name => 'aggregates', type => 1, cb_prefix_output => 'prefix_output', message_multiple => 'All aggregates raid status are ok' },
];
$self->{maps_counters}->{aggregates} = [
{ label => 'status', set => {
key_values => [ { name => 'raid_status' }, { name => 'raid_type' }, { name => 'raid_size' }, { name => 'name' } ],
closure_custom_calc => $self->can('custom_status_calc'),
closure_custom_output => $self->can('custom_status_output'),
closure_custom_perfdata => sub { return 0; },
closure_custom_threshold_check => $self->can('custom_status_threshold'),
}
},
];
}
sub new {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options);
bless $self, $class;
$self->{version} = '1.0';
$options{options}->add_options(arguments =>
{
"filter-name:s" => { name => 'filter_name' },
"filter-node:s" => { name => 'filter_node' },
"filter-cluster:s" => { name => 'filter_cluster' },
"warning-status:s" => { name => 'warning_status' },
"critical-status:s" => { name => 'critical_status', default => '%{status} !~ /normal/i' },
});
return $self;
}
sub change_macros {
my ($self, %options) = @_;
foreach ('warning_status', 'critical_status') {
if (defined($self->{option_results}->{$_})) {
$self->{option_results}->{$_} =~ s/%\{(.*?)\}/\$self->{result_values}->{$1}/g;
}
}
}
sub check_options {
my ($self, %options) = @_;
$self->SUPER::check_options(%options);
$instance_mode = $self;
$self->change_macros();
}
sub manage_selection {
my ($self, %options) = @_;
my $clusters;
my $nodes;
if (defined($self->{option_results}->{filter_cluster}) && $self->{option_results}->{filter_cluster} ne '') {
$clusters = $options{custom}->get_objects(path => '/clusters', key => 'key', name => 'name');
}
if (defined($self->{option_results}->{filter_node}) && $self->{option_results}->{filter_node} ne '') {
$nodes = $options{custom}->get_objects(path => '/nodes', key => 'key', name => 'name');
}
my $result = $options{custom}->get(path => '/aggregates');
foreach my $aggregate (@{$result}) {
if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' &&
$aggregate->{name} !~ /$self->{option_results}->{filter_name}/) {
$self->{output}->output_add(long_msg => "skipping '" . $aggregate->{name} . "': no matching filter name.", debug => 1);
next;
}
if (defined($self->{option_results}->{filter_node}) && $self->{option_results}->{filter_node} ne '' &&
defined($nodes->{$aggregate->{node_key}}) && $nodes->{$aggregate->{node_key}} !~ /$self->{option_results}->{filter_node}/) {
$self->{output}->output_add(long_msg => "skipping '" . $aggregate->{name} . "': no matching filter node '" . $nodes->{$aggregate->{node_key}} . "'", debug => 1);
next;
}
if (defined($self->{option_results}->{filter_cluster}) && $self->{option_results}->{filter_cluster} ne '' &&
defined($clusters->{$aggregate->{cluster_key}}) && $clusters->{$aggregate->{cluster_key}} !~ /$self->{option_results}->{filter_cluster}/) {
$self->{output}->output_add(long_msg => "skipping '" . $aggregate->{name} . "': no matching filter cluster '" . $clusters->{$aggregate->{cluster_key}} . "'", debug => 1);
next;
}
$self->{aggregates}->{$aggregate->{key}} = {
name => $aggregate->{name},
raid_status => $aggregate->{raid_status},
raid_type => $aggregate->{raid_type},
raid_size => $aggregate->{raid_size},
}
}
if (scalar(keys %{$self->{aggregates}}) <= 0) {
$self->{output}->add_option_msg(short_msg => "No entry found.");
$self->{output}->option_exit();
}
}
1;
__END__
=head1 MODE
Check NetApp aggregates raid status.
=over 8
=item B<--filter-*>
Filter volume.
Can be: 'name', 'node', 'cluster' (can be a regexp).
=item B<--warning-status>
Set warning threshold for status (Default: '').
Can used special variables like: %{status}, %{type}, %{size}
=item B<--critical-status>
Set critical threshold for status (Default: '%{status} !~ /normal/i').
Can used special variables like: %{status}, %{type}, %{size}
=back
=cut

View File

@ -0,0 +1,208 @@
#
# Copyright 2018 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::netapp::restapi::mode::aggregatestatus;
use base qw(centreon::plugins::templates::counter);
use strict;
use warnings;
my $instance_mode;
sub custom_status_threshold {
my ($self, %options) = @_;
my $status = 'ok';
my $message;
eval {
local $SIG{__WARN__} = sub { $message = $_[0]; };
local $SIG{__DIE__} = sub { $message = $_[0]; };
if (defined($instance_mode->{option_results}->{critical_status}) && $instance_mode->{option_results}->{critical_status} ne '' &&
eval "$instance_mode->{option_results}->{critical_status}") {
$status = 'critical';
} elsif (defined($instance_mode->{option_results}->{warning_status}) && $instance_mode->{option_results}->{warning_status} ne '' &&
eval "$instance_mode->{option_results}->{warning_status}") {
$status = 'warning';
}
};
if (defined($message)) {
$self->{output}->output_add(long_msg => 'filter status issue: ' . $message);
}
return $status;
}
sub custom_status_output {
my ($self, %options) = @_;
my $msg = sprintf("State is '%s', Mirror status is '%s'",
$self->{result_values}->{state}, $self->{result_values}->{mirror_status});
return $msg;
}
sub custom_status_calc {
my ($self, %options) = @_;
$self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_name'};
$self->{result_values}->{state} = $options{new_datas}->{$self->{instance} . '_state'};
$self->{result_values}->{mirror_status} = $options{new_datas}->{$self->{instance} . '_mirror_status'};
return 0;
}
sub prefix_output {
my ($self, %options) = @_;
return "Aggregate '" . $options{instance_value}->{name} . "' ";
}
sub set_counters {
my ($self, %options) = @_;
$self->{maps_counters_type} = [
{ name => 'aggregates', type => 1, cb_prefix_output => 'prefix_output', message_multiple => 'All aggregates status are ok' },
];
$self->{maps_counters}->{aggregates} = [
{ label => 'status', set => {
key_values => [ { name => 'state' }, { name => 'mirror_status' }, { name => 'name' } ],
closure_custom_calc => $self->can('custom_status_calc'),
closure_custom_output => $self->can('custom_status_output'),
closure_custom_perfdata => sub { return 0; },
closure_custom_threshold_check => $self->can('custom_status_threshold'),
}
},
];
}
sub new {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options);
bless $self, $class;
$self->{version} = '1.0';
$options{options}->add_options(arguments =>
{
"filter-name:s" => { name => 'filter_name' },
"filter-node:s" => { name => 'filter_node' },
"filter-cluster:s" => { name => 'filter_cluster' },
"warning-status:s" => { name => 'warning_status' },
"critical-status:s" => { name => 'critical_status', default => '%{state} !~ /online/i' },
});
return $self;
}
sub change_macros {
my ($self, %options) = @_;
foreach ('warning_status', 'critical_status') {
if (defined($self->{option_results}->{$_})) {
$self->{option_results}->{$_} =~ s/%\{(.*?)\}/\$self->{result_values}->{$1}/g;
}
}
}
sub check_options {
my ($self, %options) = @_;
$self->SUPER::check_options(%options);
$instance_mode = $self;
$self->change_macros();
}
sub manage_selection {
my ($self, %options) = @_;
my $clusters;
my $nodes;
if (defined($self->{option_results}->{filter_cluster}) && $self->{option_results}->{filter_cluster} ne '') {
$clusters = $options{custom}->get_objects(path => '/clusters', key => 'key', name => 'name');
}
if (defined($self->{option_results}->{filter_node}) && $self->{option_results}->{filter_node} ne '') {
$nodes = $options{custom}->get_objects(path => '/nodes', key => 'key', name => 'name');
}
my $result = $options{custom}->get(path => '/aggregates');
foreach my $aggregate (@{$result}) {
if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' &&
$aggregate->{name} !~ /$self->{option_results}->{filter_name}/) {
$self->{output}->output_add(long_msg => "skipping '" . $aggregate->{name} . "': no matching filter name.", debug => 1);
next;
}
if (defined($self->{option_results}->{filter_node}) && $self->{option_results}->{filter_node} ne '' &&
defined($nodes->{$aggregate->{node_key}}) && $nodes->{$aggregate->{node_key}} !~ /$self->{option_results}->{filter_node}/) {
$self->{output}->output_add(long_msg => "skipping '" . $aggregate->{name} . "': no matching filter node '" . $nodes->{$aggregate->{node_key}} . "'", debug => 1);
next;
}
if (defined($self->{option_results}->{filter_cluster}) && $self->{option_results}->{filter_cluster} ne '' &&
defined($clusters->{$aggregate->{cluster_key}}) && $clusters->{$aggregate->{cluster_key}} !~ /$self->{option_results}->{filter_cluster}/) {
$self->{output}->output_add(long_msg => "skipping '" . $aggregate->{name} . "': no matching filter cluster '" . $clusters->{$aggregate->{cluster_key}} . "'", debug => 1);
next;
}
$self->{aggregates}->{$aggregate->{key}} = {
name => $aggregate->{name},
state => $aggregate->{state},
mirror_status => $aggregate->{mirror_status},
}
}
if (scalar(keys %{$self->{aggregates}}) <= 0) {
$self->{output}->add_option_msg(short_msg => "No entry found.");
$self->{output}->option_exit();
}
}
1;
__END__
=head1 MODE
Check NetApp aggregates status.
=over 8
=item B<--filter-*>
Filter aggregate.
Can be: 'name', 'node', 'cluster' (can be a regexp).
=item B<--warning-status>
Set warning threshold for status (Default: '').
Can used special variables like: %{state}, %{mirror_status}
=item B<--critical-status>
Set critical threshold for status (Default: '%{state} !~ /online/i').
Can used special variables like: %{state}, %{mirror_status}
=back
=cut

View File

@ -0,0 +1,315 @@
#
# Copyright 2018 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::netapp::restapi::mode::aggregateusage;
use base qw(centreon::plugins::templates::counter);
use strict;
use warnings;
my $instance_mode;
sub custom_usage_perfdata {
my ($self, %options) = @_;
my $extra_label = '';
$extra_label = '_' . $self->{result_values}->{display} if (!defined($options{extra_instance}) || $options{extra_instance} != 0);
$self->{output}->perfdata_add(label => 'used' . $extra_label,
unit => 'B',
value => $self->{result_values}->{used},
warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{label}, total => $self->{result_values}->{total}, cast_int => 1),
critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{label}, total => $self->{result_values}->{total}, cast_int => 1),
min => 0, max => $self->{result_values}->{total});
}
sub custom_usage_threshold {
my ($self, %options) = @_;
my ($exit, $threshold_value);
$threshold_value = $self->{result_values}->{used};
$threshold_value = $self->{result_values}->{free} if (defined($instance_mode->{option_results}->{free}));
if ($instance_mode->{option_results}->{units} eq '%') {
$threshold_value = $self->{result_values}->{prct_used};
$threshold_value = $self->{result_values}->{prct_free} if (defined($instance_mode->{option_results}->{free}));
}
$exit = $self->{perfdata}->threshold_check(value => $threshold_value,
threshold => [ { label => 'critical-' . $self->{label}, exit_litteral => 'critical' },
{ label => 'warning-' . $self->{label}, exit_litteral => 'warning' } ]);
return $exit;
}
sub custom_usage_output {
my ($self, %options) = @_;
my ($used_value, $used_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{used});
my ($free_value, $free_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{free});
my ($total_value, $total_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{total});
my $msg = sprintf("Total: %s Used: %s (%.2f%%) Free: %s (%.2f%%)",
$total_value . " " . $total_unit,
$used_value . " " . $used_unit, $self->{result_values}->{prct_used},
$free_value . " " . $free_unit, $self->{result_values}->{prct_free});
return $msg;
}
sub custom_usage_calc {
my ($self, %options) = @_;
$self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_name'};
$self->{result_values}->{total} = $options{new_datas}->{$self->{instance} . '_size_total'};
$self->{result_values}->{used} = $options{new_datas}->{$self->{instance} . '_size_used'};
if ($self->{result_values}->{total} != 0) {
$self->{result_values}->{free} = $self->{result_values}->{total} - $self->{result_values}->{used};
$self->{result_values}->{prct_used} = $self->{result_values}->{used} * 100 / $self->{result_values}->{total};
$self->{result_values}->{prct_free} = 100 - $self->{result_values}->{prct_used};
} else {
$self->{result_values}->{free} = '0';
$self->{result_values}->{prct_used} = '0';
$self->{result_values}->{prct_free} = '0';
}
return 0;
}
sub custom_snapshot_perfdata {
my ($self, %options) = @_;
my $extra_label = '';
$extra_label = '_' . $self->{result_values}->{display} if (!defined($options{extra_instance}) || $options{extra_instance} != 0);
$self->{output}->perfdata_add(label => 'snapshot' . $extra_label,
unit => 'B',
value => $self->{result_values}->{used},
warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{label}, total => $self->{result_values}->{total}, cast_int => 1),
critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{label}, total => $self->{result_values}->{total}, cast_int => 1),
min => 0, max => $self->{result_values}->{total});
}
sub custom_snapshot_threshold {
my ($self, %options) = @_;
my ($exit, $threshold_value);
$threshold_value = $self->{result_values}->{used};
$threshold_value = $self->{result_values}->{free} if (defined($instance_mode->{option_results}->{free}));
if ($instance_mode->{option_results}->{units} eq '%') {
$threshold_value = $self->{result_values}->{prct_used};
$threshold_value = $self->{result_values}->{prct_free} if (defined($instance_mode->{option_results}->{free}));
}
$exit = $self->{perfdata}->threshold_check(value => $threshold_value,
threshold => [ { label => 'critical-' . $self->{label}, exit_litteral => 'critical' },
{ label => 'warning-' . $self->{label}, exit_litteral => 'warning' } ]);
return $exit;
}
sub custom_snapshot_output {
my ($self, %options) = @_;
my ($used_value, $used_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{used});
my ($free_value, $free_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{free});
my ($total_value, $total_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{total});
my $msg = sprintf("Snapshot Total: %s Used: %s (%.2f%%) Free: %s (%.2f%%)",
$total_value . " " . $total_unit,
$used_value . " " . $used_unit, $self->{result_values}->{prct_used},
$free_value . " " . $free_unit, $self->{result_values}->{prct_free});
return $msg;
}
sub custom_snapshot_calc {
my ($self, %options) = @_;
$self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_name'};
$self->{result_values}->{total} = $options{new_datas}->{$self->{instance} . '_snapshot_size_total'};
$self->{result_values}->{used} = $options{new_datas}->{$self->{instance} . '_snapshot_size_used'};
if ($self->{result_values}->{total} != 0) {
$self->{result_values}->{free} = $self->{result_values}->{total} - $self->{result_values}->{used};
$self->{result_values}->{prct_used} = $self->{result_values}->{used} * 100 / $self->{result_values}->{total};
$self->{result_values}->{prct_free} = 100 - $self->{result_values}->{prct_used};
} else {
$self->{result_values}->{free} = '0';
$self->{result_values}->{prct_used} = '0';
$self->{result_values}->{prct_free} = '0';
}
return 0;
}
sub prefix_output {
my ($self, %options) = @_;
return "Aggregate '" . $options{instance_value}->{name} . "' ";
}
sub set_counters {
my ($self, %options) = @_;
$self->{maps_counters_type} = [
{ name => 'aggregates', type => 1, cb_prefix_output => 'prefix_output', message_multiple => 'All aggregates usage are ok' },
];
$self->{maps_counters}->{aggregates} = [
{ label => 'usage', set => {
key_values => [ { name => 'size_used' }, { name => 'size_total' }, { name => 'name' } ],
closure_custom_calc => $self->can('custom_usage_calc'),
closure_custom_output => $self->can('custom_usage_output'),
closure_custom_perfdata => $self->can('custom_usage_perfdata'),
closure_custom_threshold_check => $self->can('custom_usage_threshold'),
}
},
{ label => 'snapshot', set => {
key_values => [ { name => 'snapshot_size_used' }, { name => 'snapshot_size_total' }, { name => 'name' } ],
closure_custom_calc => $self->can('custom_snapshot_calc'),
closure_custom_output => $self->can('custom_snapshot_output'),
closure_custom_perfdata => $self->can('custom_snapshot_perfdata'),
closure_custom_threshold_check => $self->can('custom_snapshot_threshold'),
}
},
];
}
sub new {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options);
bless $self, $class;
$self->{version} = '1.0';
$options{options}->add_options(arguments =>
{
"filter-name:s" => { name => 'filter_name' },
"filter-node:s" => { name => 'filter_node' },
"filter-cluster:s" => { name => 'filter_cluster' },
"filter-state:s" => { name => 'filter_state' },
"filter-type:s" => { name => 'filter_type' },
"units:s" => { name => 'units', default => '%' },
"free" => { name => 'free' },
});
return $self;
}
sub check_options {
my ($self, %options) = @_;
$self->SUPER::check_options(%options);
$instance_mode = $self;
}
sub manage_selection {
my ($self, %options) = @_;
my $clusters;
my $nodes;
if (defined($self->{option_results}->{filter_cluster}) && $self->{option_results}->{filter_cluster} ne '') {
$clusters = $options{custom}->get_objects(path => '/clusters', key => 'key', name => 'name');
}
if (defined($self->{option_results}->{filter_node}) && $self->{option_results}->{filter_node} ne '') {
$nodes = $options{custom}->get_objects(path => '/nodes', key => 'key', name => 'name');
}
my $result = $options{custom}->get(path => '/aggregates');
foreach my $aggregate (@{$result}) {
if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' &&
$aggregate->{name} !~ /$self->{option_results}->{filter_name}/) {
$self->{output}->output_add(long_msg => "skipping '" . $aggregate->{name} . "': no matching filter name.", debug => 1);
next;
}
if (defined($self->{option_results}->{filter_state}) && $self->{option_results}->{filter_state} ne '' &&
$aggregate->{state} !~ /$self->{option_results}->{filter_state}/) {
$self->{output}->output_add(long_msg => "skipping '" . $aggregate->{name} . "': no matching filter state : '" . $aggregate->{state} . "'", debug => 1);
next;
}
if (defined($self->{option_results}->{filter_type}) && $self->{option_results}->{filter_type} ne '' &&
$aggregate->{aggregate_type} !~ /$self->{option_results}->{filter_type}/) {
$self->{output}->output_add(long_msg => "skipping '" . $aggregate->{name} . "': no matching filter type : '" . $aggregate->{vol_type} . "'", debug => 1);
next;
}
if (defined($self->{option_results}->{filter_node}) && $self->{option_results}->{filter_node} ne '' &&
defined($nodes->{$aggregate->{node_key}}) && $nodes->{$aggregate->{node_key}} !~ /$self->{option_results}->{filter_node}/) {
$self->{output}->output_add(long_msg => "skipping '" . $aggregate->{name} . "': no matching filter node '" . $nodes->{$aggregate->{node_key}} . "'", debug => 1);
next;
}
if (defined($self->{option_results}->{filter_cluster}) && $self->{option_results}->{filter_cluster} ne '' &&
defined($clusters->{$aggregate->{cluster_key}}) && $clusters->{$aggregate->{cluster_key}} !~ /$self->{option_results}->{filter_cluster}/) {
$self->{output}->output_add(long_msg => "skipping '" . $aggregate->{name} . "': no matching filter cluster '" . $clusters->{$aggregate->{cluster_key}} . "'", debug => 1);
next;
}
$self->{aggregates}->{$aggregate->{key}} = {
name => $aggregate->{name},
size_total => $aggregate->{size_total},
size_used => $aggregate->{size_used},
snapshot_size_total => $aggregate->{snapshot_size_total},
snapshot_size_used => $aggregate->{snapshot_size_used},
}
}
if (scalar(keys %{$self->{aggregates}}) <= 0) {
$self->{output}->add_option_msg(short_msg => "No entry found.");
$self->{output}->option_exit();
}
}
1;
__END__
=head1 MODE
Check NetApp aggregates usage.
=over 8
=item B<--filter-*>
Filter volume.
Can be: 'name', 'node', 'cluster', 'state', 'type' (can be a regexp).
=item B<--warning-*>
Threshold warning.
Can be: 'usage', 'snapshot'.
=item B<--critical-*>
Threshold critical.
Can be: 'usage', 'snapshot'.
=item B<--units>
Units of thresholds (Default: '%') ('%', 'B').
=item B<--free>
Thresholds are on free space left.
=back
=cut

View File

@ -0,0 +1,149 @@
#
# Copyright 2018 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::netapp::restapi::mode::clusterio;
use base qw(centreon::plugins::templates::counter);
use strict;
use warnings;
sub prefix_output {
my ($self, %options) = @_;
return "Cluster '" . $options{instance_value}->{name} . "' ";
}
sub set_counters {
my ($self, %options) = @_;
$self->{maps_counters_type} = [
{ name => 'clusters', type => 1, cb_prefix_output => 'prefix_output', message_multiple => 'All clusters IOs are ok' },
];
$self->{maps_counters}->{clusters} = [
{ label => 'total-throughput', set => {
key_values => [ { name => 'total_throughput' }, { name => 'name' } ],
output_template => 'Total throughput: %.2f %s/s',
output_change_bytes => 1,
perfdatas => [
{ label => 'total_throughput', value => 'total_throughput_absolute', template => '%.2f',
min => 0, unit => 'B/s', label_extra_instance => 1, instance_use => 'name_absolute' },
],
}
},
{ label => 'total-ops', set => {
key_values => [ { name => 'total_ops' }, { name => 'name' } ],
output_template => 'Total IOPS: %.2f ops/s',
perfdatas => [
{ label => 'total_ops', value => 'total_ops_absolute', template => '%.2f',
min => 0, unit => 'ops/s', label_extra_instance => 1, instance_use => 'name_absolute' },
],
}
},
];
}
sub new {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options);
bless $self, $class;
$self->{version} = '1.0';
$options{options}->add_options(arguments =>
{
"filter-name:s" => { name => 'filter_name' },
});
return $self;
}
sub check_options {
my ($self, %options) = @_;
$self->SUPER::check_options(%options);
}
sub manage_selection {
my ($self, %options) = @_;
my %names_hash;
my $names = $options{custom}->get(path => '/clusters');
foreach my $cluster (@{$names}) {
$names_hash{$cluster->{key}} = {
name => $cluster->{name},
};
}
my $args = '';
my $append = '';
foreach my $metric ('total_ops', 'total_throughput') {
$args .= $append . 'name=' . $metric;
$append = '&';
}
my $result = $options{custom}->get(path => '/clusters/metrics', args => $args);
foreach my $cluster (@{$result}) {
if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' &&
defined($names_hash{$cluster->{resource_key}}) && $names_hash{$cluster->{resource_key}}->{name} !~ /$self->{option_results}->{filter_name}/) {
$self->{output}->output_add(long_msg => "skipping '" . $names_hash{$cluster->{resource_key}}->{name} . "': no matching filter name.", debug => 1);
next;
}
foreach my $metric (@{$cluster->{metrics}}) {
$self->{clusters}->{$cluster->{resource_key}}->{name} = $names_hash{$cluster->{resource_key}}->{name};
$self->{clusters}->{$cluster->{resource_key}}->{total_ops} = ${$metric->{samples}}[0]->{value} if ($metric->{name} eq 'total_ops');
$self->{clusters}->{$cluster->{resource_key}}->{total_throughput} = ${$metric->{samples}}[0]->{value} if ($metric->{name} eq 'total_throughput');
}
}
if (scalar(keys %{$self->{clusters}}) <= 0) {
$self->{output}->add_option_msg(short_msg => "No entry found.");
$self->{output}->option_exit();
}
}
1;
__END__
=head1 MODE
Check NetApp clusters IOs.
=over 8
=item B<--filter-name>
Filter snapmirror name (can be a regexp).
=item B<--warning-*>
Threshold warning.
Can be: 'total-throughput', 'total-ops'.
=item B<--critical-*>
Threshold critical.
Can be: 'total-throughput', 'total-ops'.
=back
=cut

View File

@ -0,0 +1,186 @@
#
# Copyright 2018 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::netapp::restapi::mode::clusterstatus;
use base qw(centreon::plugins::templates::counter);
use strict;
use warnings;
my $instance_mode;
sub custom_status_threshold {
my ($self, %options) = @_;
my $status = 'ok';
my $message;
eval {
local $SIG{__WARN__} = sub { $message = $_[0]; };
local $SIG{__DIE__} = sub { $message = $_[0]; };
if (defined($instance_mode->{option_results}->{critical_status}) && $instance_mode->{option_results}->{critical_status} ne '' &&
eval "$instance_mode->{option_results}->{critical_status}") {
$status = 'critical';
} elsif (defined($instance_mode->{option_results}->{warning_status}) && $instance_mode->{option_results}->{warning_status} ne '' &&
eval "$instance_mode->{option_results}->{warning_status}") {
$status = 'warning';
}
};
if (defined($message)) {
$self->{output}->output_add(long_msg => 'filter status issue: ' . $message);
}
return $status;
}
sub custom_status_output {
my ($self, %options) = @_;
my $msg = sprintf("Status is '%s'", $self->{result_values}->{status});
$msg .= sprintf(", Metro Cluster is '%s' [mode: %s]",
$self->{result_values}->{metro_cluster_configuration_state},
$self->{result_values}->{metro_cluster_mode}) if ($self->{result_values}->{metro_cluster_configuration_state} !~ /-/);
return $msg;
}
sub custom_status_calc {
my ($self, %options) = @_;
$self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_name'};
$self->{result_values}->{status} = $options{new_datas}->{$self->{instance} . '_status'};
$self->{result_values}->{metro_cluster_mode} = $options{new_datas}->{$self->{instance} . '_metro_cluster_mode'};
$self->{result_values}->{metro_cluster_configuration_state} = $options{new_datas}->{$self->{instance} . '_metro_cluster_configuration_state'};
return 0;
}
sub prefix_output {
my ($self, %options) = @_;
return "Cluster '" . $options{instance_value}->{name} . "' ";
}
sub set_counters {
my ($self, %options) = @_;
$self->{maps_counters_type} = [
{ name => 'clusters', type => 1, cb_prefix_output => 'prefix_output', message_multiple => 'All clusters status are ok' },
];
$self->{maps_counters}->{clusters} = [
{ label => 'status', set => {
key_values => [ { name => 'status' }, { name => 'metro_cluster_mode' }, { name => 'metro_cluster_configuration_state' }, { name => 'name' } ],
closure_custom_calc => $self->can('custom_status_calc'),
closure_custom_output => $self->can('custom_status_output'),
closure_custom_perfdata => sub { return 0; },
closure_custom_threshold_check => $self->can('custom_status_threshold'),
}
},
];
}
sub new {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options);
bless $self, $class;
$self->{version} = '1.0';
$options{options}->add_options(arguments =>
{
"filter-name:s" => { name => 'filter_name' },
"warning-status:s" => { name => 'warning_status' },
"critical-status:s" => { name => 'critical_status', default => '%{status} !~ /ok/i' },
});
return $self;
}
sub change_macros {
my ($self, %options) = @_;
foreach ('warning_status', 'critical_status') {
if (defined($self->{option_results}->{$_})) {
$self->{option_results}->{$_} =~ s/%\{(.*?)\}/\$self->{result_values}->{$1}/g;
}
}
}
sub check_options {
my ($self, %options) = @_;
$self->SUPER::check_options(%options);
$instance_mode = $self;
$self->change_macros();
}
sub manage_selection {
my ($self, %options) = @_;
my $result = $options{custom}->get(path => '/clusters');
foreach my $cluster (@{$result}) {
if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' &&
$cluster->{name} !~ /$self->{option_results}->{filter_name}/) {
$self->{output}->output_add(long_msg => "skipping '" . $cluster->{name} . "': no matching filter name.", debug => 1);
next;
}
$self->{clusters}->{$cluster->{key}} = {
name => $cluster->{name},
status => $cluster->{status},
metro_cluster_mode => defined($cluster->{metro_cluster_mode}) ? $cluster->{metro_cluster_mode} : "-",
metro_cluster_configuration_state => defined($cluster->{metro_cluster_configuration_state}) ? $cluster->{metro_cluster_configuration_state} : "-",
}
}
if (scalar(keys %{$self->{clusters}}) <= 0) {
$self->{output}->add_option_msg(short_msg => "No entry found.");
$self->{output}->option_exit();
}
}
1;
__END__
=head1 MODE
Check NetApp clusters status.
=over 8
=item B<--filter-name>
Filter snapmirror name (can be a regexp).
=item B<--warning-status>
Set warning threshold for status (Default: '').
Can used special variables like: %{status}, %{metro_cluster_mode}, %{metro_cluster_configuration_state}
=item B<--critical-status>
Set critical threshold for status (Default: '%{status} !~ /ok/i').
Can used special variables like: %{status}, %{metro_cluster_mode}, %{metro_cluster_configuration_state}
=back
=cut

View File

@ -0,0 +1,148 @@
#
# Copyright 2018 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::netapp::restapi::mode::clusterusage;
use base qw(centreon::plugins::templates::counter);
use strict;
use warnings;
sub prefix_output {
my ($self, %options) = @_;
return "Cluster '" . $options{instance_value}->{name} . "' ";
}
sub set_counters {
my ($self, %options) = @_;
$self->{maps_counters_type} = [
{ name => 'clusters', type => 1, cb_prefix_output => 'prefix_output', message_multiple => 'All clusters usage are ok' },
];
$self->{maps_counters}->{clusters} = [
{ label => 'max-node-utilization', set => {
key_values => [ { name => 'max_node_utilization' }, { name => 'name' } ],
output_template => 'Node utilization: %.2f %%',
perfdatas => [
{ label => 'max_node_utilization', value => 'max_node_utilization_absolute', template => '%.2f',
min => 0, max => 100, unit => '%', label_extra_instance => 1, instance_use => 'name_absolute' },
],
}
},
{ label => 'max-aggregate-utilization', set => {
key_values => [ { name => 'max_aggregate_utilization' }, { name => 'name' } ],
output_template => 'Aggregate utilization: %.2f %%',
perfdatas => [
{ label => 'max_aggregate_utilization', value => 'max_aggregate_utilization_absolute', template => '%.2f',
min => 0, max => 100, unit => '%', label_extra_instance => 1, instance_use => 'name_absolute' },
],
}
},
];
}
sub new {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options);
bless $self, $class;
$self->{version} = '1.0';
$options{options}->add_options(arguments =>
{
"filter-name:s" => { name => 'filter_name' },
});
return $self;
}
sub check_options {
my ($self, %options) = @_;
$self->SUPER::check_options(%options);
}
sub manage_selection {
my ($self, %options) = @_;
my %names_hash;
my $names = $options{custom}->get(path => '/clusters');
foreach my $cluster (@{$names}) {
$names_hash{$cluster->{key}} = {
name => $cluster->{name},
};
}
my $args = '';
my $append = '';
foreach my $metric ('max_node_utilization', 'max_aggregate_utilization') {
$args .= $append . 'name=' . $metric;
$append = '&';
}
my $result = $options{custom}->get(path => '/clusters/metrics', args => $args);
foreach my $cluster (@{$result}) {
if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' &&
defined($names_hash{$cluster->{resource_key}}) && $names_hash{$cluster->{resource_key}}->{name} !~ /$self->{option_results}->{filter_name}/) {
$self->{output}->output_add(long_msg => "skipping '" . $names_hash{$cluster->{resource_key}}->{name} . "': no matching filter name.", debug => 1);
next;
}
foreach my $metric (@{$cluster->{metrics}}) {
$self->{clusters}->{$cluster->{resource_key}}->{name} = $names_hash{$cluster->{resource_key}}->{name};
$self->{clusters}->{$cluster->{resource_key}}->{max_node_utilization} = ${$metric->{samples}}[0]->{value} if ($metric->{name} eq 'max_node_utilization');
$self->{clusters}->{$cluster->{resource_key}}->{max_aggregate_utilization} = ${$metric->{samples}}[0]->{value} if ($metric->{name} eq 'max_aggregate_utilization');
}
}
if (scalar(keys %{$self->{clusters}}) <= 0) {
$self->{output}->add_option_msg(short_msg => "No entry found.");
$self->{output}->option_exit();
}
}
1;
__END__
=head1 MODE
Check NetApp clusters usage.
=over 8
=item B<--filter-name>
Filter snapmirror name (can be a regexp).
=item B<--warning-*>
Threshold warning.
Can be: 'max-node-utilization', 'max-aggregate-utilization'.
=item B<--critical-*>
Threshold critical.
Can be: 'max-node-utilization', 'max-aggregate-utilization'.
=back
=cut

View File

@ -0,0 +1,147 @@
#
# Copyright 2018 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::netapp::restapi::mode::diskfailed;
use base qw(centreon::plugins::templates::counter);
use strict;
use warnings;
sub set_counters {
my ($self, %options) = @_;
$self->{maps_counters_type} = [
{ name => 'disks', type => 0},
];
$self->{maps_counters}->{disks} = [
{ label => 'failed', set => {
key_values => [ { name => 'failed' } ],
output_template => 'Failed disks: %d',
perfdatas => [
{ label => 'failed', value => 'failed_absolute', template => '%d',
min => 0 },
],
}
},
{ label => 'pre-failed', set => {
key_values => [ { name => 'pre_failed' } ],
output_template => 'Pre-failed disks: %d',
perfdatas => [
{ label => 'pre_failed', value => 'pre_failed_absolute', template => '%d',
min => 0 },
],
}
},
];
}
sub new {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options);
bless $self, $class;
$self->{version} = '1.0';
$options{options}->add_options(arguments =>
{
"filter-node:s" => { name => 'filter_node' },
"filter-cluster:s" => { name => 'filter_cluster' },
});
return $self;
}
sub check_options {
my ($self, %options) = @_;
$self->SUPER::check_options(%options);
}
sub manage_selection {
my ($self, %options) = @_;
my $clusters;
my $nodes;
if (defined($self->{option_results}->{filter_cluster}) && $self->{option_results}->{filter_cluster} ne '') {
$clusters = $options{custom}->get_objects(path => '/clusters', key => 'key', name => 'name');
}
if (defined($self->{option_results}->{filter_node}) && $self->{option_results}->{filter_node} ne '') {
$nodes = $options{custom}->get_objects(path => '/nodes', key => 'key', name => 'name');
}
my $result = $options{custom}->get(path => '/disks');
$self->{disks}->{failed} = 0;
$self->{disks}->{pre_failed} = 0;
foreach my $disk (@{$result}) {
if (defined($self->{option_results}->{filter_node}) && $self->{option_results}->{filter_node} ne '' &&
defined($nodes->{$disk->{owner_node_key}}) && $nodes->{$disk->{owner_node_key}} !~ /$self->{option_results}->{filter_node}/) {
$self->{output}->output_add(long_msg => "skipping '" . $disk->{name} . "': no matching filter node '" . $nodes->{$disk->{owner_node_key}} . "'", debug => 1);
next;
}
if (defined($self->{option_results}->{filter_cluster}) && $self->{option_results}->{filter_cluster} ne '' &&
defined($clusters->{$disk->{cluster_key}}) && $clusters->{$disk->{cluster_key}} !~ /$self->{option_results}->{filter_cluster}/) {
$self->{output}->output_add(long_msg => "skipping '" . $disk->{name} . "': no matching filter cluster '" . $clusters->{$disk->{cluster_key}} . "'", debug => 1);
next;
}
if ($disk->{is_failed}) {
$self->{disks}->{failed}++;
$self->{output}->output_add(long_msg => "Disk '" . $disk->{name} . "' from cluster '" . $clusters->{$disk->{cluster_key}} . "' is in 'failed' state (reason: '" . $disk->{failed_reason} . "') [shelf: " . $disk->{shelf} . "] [serial_number: " . $disk->{serial_number} . "] [model: " . $disk->{model} . "]");
}
if ($disk->{is_prefailed}) {
$self->{disks}->{pre_failed}++;
$self->{output}->output_add(long_msg => "Disk '" . $disk->{name} . "' from cluster '" . $clusters->{$disk->{cluster_key}} . "' is in 'pre-failed' state [shelf: " . $disk->{shelf} . "] [serial_number: " . $disk->{serial_number} . "] [model: " . $disk->{model} . "]");
}
}
}
1;
__END__
=head1 MODE
Check NetApp failed disks.
=over 8
=item B<--filter-*>
Filter disk.
Can be: 'node', 'cluster' (can be a regexp).
=item B<--warning-*>
Threshold warning.
Can be: 'failed', 'pre-failed'.
=item B<--critical-*>
Threshold critical.
Can be: 'failed', 'pre-failed'.
=back
=cut

View File

@ -0,0 +1,161 @@
#
# Copyright 2018 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::netapp::restapi::mode::diskspare;
use base qw(centreon::plugins::templates::counter);
use strict;
use warnings;
sub set_counters {
my ($self, %options) = @_;
$self->{maps_counters_type} = [
{ name => 'disks', type => 0},
];
$self->{maps_counters}->{disks} = [
{ label => 'spare', set => {
key_values => [ { name => 'spare' } ],
output_template => 'Spare disks: %d',
perfdatas => [
{ label => 'spare', value => 'spare_absolute', template => '%d',
min => 0 },
],
}
},
{ label => 'zeroed', set => {
key_values => [ { name => 'zeroed' } ],
output_template => 'Zeroed disks: %d',
perfdatas => [
{ label => 'zeroed', value => 'zeroed_absolute', template => '%d',
min => 0 },
],
}
},
{ label => 'not-zeroed', set => {
key_values => [ { name => 'not_zeroed' } ],
output_template => 'Not zeroed disks: %d',
perfdatas => [
{ label => 'not_zeroed', value => 'not_zeroed_absolute', template => '%d',
min => 0 },
],
}
},
];
}
sub new {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options);
bless $self, $class;
$self->{version} = '1.0';
$options{options}->add_options(arguments =>
{
"filter-node:s" => { name => 'filter_node' },
"filter-cluster:s" => { name => 'filter_cluster' },
});
return $self;
}
sub check_options {
my ($self, %options) = @_;
$self->SUPER::check_options(%options);
}
sub manage_selection {
my ($self, %options) = @_;
my $clusters;
my $nodes;
if (defined($self->{option_results}->{filter_cluster}) && $self->{option_results}->{filter_cluster} ne '') {
$clusters = $options{custom}->get_objects(path => '/clusters', key => 'key', name => 'name');
}
if (defined($self->{option_results}->{filter_node}) && $self->{option_results}->{filter_node} ne '') {
$nodes = $options{custom}->get_objects(path => '/nodes', key => 'key', name => 'name');
}
my $result = $options{custom}->get(path => '/disks');
$self->{disks}->{spare} = 0;
$self->{disks}->{zeroed} = 0;
$self->{disks}->{not_zeroed} = 0;
foreach my $disk (@{$result}) {
next if ($disk->{container_type} !~ /spare/i);
if (defined($self->{option_results}->{filter_node}) && $self->{option_results}->{filter_node} ne '' &&
defined($nodes->{$disk->{owner_node_key}}) && $nodes->{$disk->{owner_node_key}} !~ /$self->{option_results}->{filter_node}/) {
$self->{output}->output_add(long_msg => "skipping '" . $disk->{name} . "': no matching filter node '" . $nodes->{$disk->{owner_node_key}} . "'", debug => 1);
next;
}
if (defined($self->{option_results}->{filter_cluster}) && $self->{option_results}->{filter_cluster} ne '' &&
defined($clusters->{$disk->{cluster_key}}) && $clusters->{$disk->{cluster_key}} !~ /$self->{option_results}->{filter_cluster}/) {
$self->{output}->output_add(long_msg => "skipping '" . $disk->{name} . "': no matching filter cluster '" . $clusters->{$disk->{cluster_key}} . "'", debug => 1);
next;
}
$self->{disks}->{spare}++;
$self->{disks}->{zeroed}++ if ($disk->{is_zeroed});
if (!$disk->{is_zeroed}) {
$self->{disks}->{not_zeroed}++;
my $long_msg = "Spare disk '" . $disk->{name} . "' is not in 'zeroed' state [shelf: " . $disk->{shelf} . "]";
$long_msg .= " [node: " . $nodes->{$disk->{owner_node_key}} . "]" if (defined($self->{option_results}->{filter_node}) && $self->{option_results}->{filter_node} ne '');
$long_msg .= " [cluster: " . $clusters->{$disk->{cluster_key}} . "]" if (defined($self->{option_results}->{filter_cluster}) && $self->{option_results}->{filter_cluster} ne '');
$self->{output}->output_add(long_msg => $long_msg);
}
}
}
1;
__END__
=head1 MODE
Check NetApp spare disks.
=over 8
=item B<--filter-*>
Filter disk.
Can be: 'node', 'cluster' (can be a regexp).
=item B<--warning-*>
Threshold warning.
Can be: 'spare', 'zeroed', 'not-zeroed'.
=item B<--critical-*>
Threshold critical.
Can be: 'spare', 'zeroed', 'not-zeroed'.
=back
=cut

View File

@ -0,0 +1,191 @@
#
# Copyright 2018 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::netapp::restapi::mode::fcportstatus;
use base qw(centreon::plugins::templates::counter);
use strict;
use warnings;
my $instance_mode;
sub custom_status_threshold {
my ($self, %options) = @_;
my $status = 'ok';
my $message;
eval {
local $SIG{__WARN__} = sub { $message = $_[0]; };
local $SIG{__DIE__} = sub { $message = $_[0]; };
if (defined($instance_mode->{option_results}->{critical_status}) && $instance_mode->{option_results}->{critical_status} ne '' &&
eval "$instance_mode->{option_results}->{critical_status}") {
$status = 'critical';
} elsif (defined($instance_mode->{option_results}->{warning_status}) && $instance_mode->{option_results}->{warning_status} ne '' &&
eval "$instance_mode->{option_results}->{warning_status}") {
$status = 'warning';
}
};
if (defined($message)) {
$self->{output}->output_add(long_msg => 'filter status issue: ' . $message);
}
return $status;
}
sub custom_status_output {
my ($self, %options) = @_;
my $msg = sprintf("Status is '%s', State is '%s' [adapter: %s] [switch port: %s] [fabric established: %s]",
$self->{result_values}->{status}, $self->{result_values}->{state},
$self->{result_values}->{adapter}, $self->{result_values}->{switch_port},
$self->{result_values}->{fabric_established});
return $msg;
}
sub custom_status_calc {
my ($self, %options) = @_;
$self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_wwpn'};
$self->{result_values}->{adapter} = $options{new_datas}->{$self->{instance} . '_adapter'};
$self->{result_values}->{status} = $options{new_datas}->{$self->{instance} . '_status'};
$self->{result_values}->{state} = $options{new_datas}->{$self->{instance} . '_state'};
$self->{result_values}->{switch_port} = $options{new_datas}->{$self->{instance} . '_switch_port'};
$self->{result_values}->{fabric_established} = ($options{new_datas}->{$self->{instance} . '_fabric_established'}) ? "true" : "false";
return 0;
}
sub prefix_output {
my ($self, %options) = @_;
return "FC port '" . $options{instance_value}->{wwpn} . "' ";
}
sub set_counters {
my ($self, %options) = @_;
$self->{maps_counters_type} = [
{ name => 'fcports', type => 1, cb_prefix_output => 'prefix_output', message_multiple => 'All FC ports status are ok' },
];
$self->{maps_counters}->{fcports} = [
{ label => 'status', set => {
key_values => [ { name => 'wwpn' }, { name => 'status' }, { name => 'state' }, { name => 'switch_port' }, { name => 'fabric_established' }, { name => 'adapter' } ],
closure_custom_calc => $self->can('custom_status_calc'),
closure_custom_output => $self->can('custom_status_output'),
closure_custom_perfdata => sub { return 0; },
closure_custom_threshold_check => $self->can('custom_status_threshold'),
}
},
];
}
sub new {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options);
bless $self, $class;
$self->{version} = '1.0';
$options{options}->add_options(arguments =>
{
"filter-name:s" => { name => 'filter_name' },
"warning-status:s" => { name => 'warning_status' },
"critical-status:s" => { name => 'critical_status', default => '%{status} !~ /online/i || %{state} !~ /online/i' },
});
return $self;
}
sub change_macros {
my ($self, %options) = @_;
foreach ('warning_status', 'critical_status') {
if (defined($self->{option_results}->{$_})) {
$self->{option_results}->{$_} =~ s/%\{(.*?)\}/\$self->{result_values}->{$1}/g;
}
}
}
sub check_options {
my ($self, %options) = @_;
$self->SUPER::check_options(%options);
$instance_mode = $self;
$self->change_macros();
}
sub manage_selection {
my ($self, %options) = @_;
my $result = $options{custom}->get(path => '/fc-ports');
foreach my $fcport (@{$result}) {
if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' &&
$fcport->{wwpn} !~ /$self->{option_results}->{filter_name}/) {
$self->{output}->output_add(long_msg => "skipping '" . $fcport->{wwpn} . "': no matching filter name.", debug => 1);
next;
}
$self->{fcports}->{$fcport->{key}} = {
wwpn => $fcport->{wwpn},
adapter => $fcport->{adapter},
status => $fcport->{status},
state => $fcport->{state},
switch_port => $fcport->{switch_port},
fabric_established => $fcport->{fabric_established},
}
}
if (scalar(keys %{$self->{fcports}}) <= 0) {
$self->{output}->add_option_msg(short_msg => "No entry found.");
$self->{output}->option_exit();
}
}
1;
__END__
=head1 MODE
Check NetApp FC ports status.
=over 8
=item B<--filter-*>
Filter qtree.
Can be: 'name', 'volume' (can be a regexp).
=item B<--warning-status>
Set warning threshold for status (Default: '').
Can used special variables like: %{state}, %{state}
=item B<--critical-status>
Set critical threshold for status (Default: '%{status} !~ /online/i || %{state} !~ /online/i').
Can used special variables like: %{status}, %{state}
=back
=cut

View File

@ -0,0 +1,154 @@
#
# Copyright 2018 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::netapp::restapi::mode::listaggregates;
use base qw(centreon::plugins::templates::counter);
use strict;
use warnings;
sub new {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options);
bless $self, $class;
$self->{version} = '1.0';
$options{options}->add_options(arguments =>
{
"filter-name:s" => { name => 'filter_name' },
"filter-node:s" => { name => 'filter_node' },
"filter-cluster:s" => { name => 'filter_cluster' },
});
return $self;
}
sub check_options {
my ($self, %options) = @_;
$self->SUPER::check_options(%options);
}
sub manage_selection {
my ($self, %options) = @_;
$self->{clusters} = $options{custom}->get_objects(path => '/clusters', key => 'key', name => 'name');
$self->{nodes} = $options{custom}->get_objects(path => '/nodes', key => 'key', name => 'name');
my $result = $options{custom}->get(path => '/aggregates');
foreach my $aggregate (@{$result}) {
if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' &&
$aggregate->{name} !~ /$self->{option_results}->{filter_name}/) {
$self->{output}->output_add(long_msg => "skipping '" . $aggregate->{name} . "': no matching filter name.", debug => 1);
next;
}
if (defined($self->{option_results}->{filter_node}) && $self->{option_results}->{filter_node} ne '' &&
defined($self->{nodes}->{$aggregate->{node_key}}) && $self->{nodes}->{$aggregate->{node_key}} !~ /$self->{option_results}->{filter_node}/) {
$self->{output}->output_add(long_msg => "skipping '" . $aggregate->{name} . "': no matching filter node '" . $self->{nodes}->{$aggregate->{node_key}} . "'", debug => 1);
next;
}
if (defined($self->{option_results}->{filter_cluster}) && $self->{option_results}->{filter_cluster} ne '' &&
defined($self->{clusters}->{$aggregate->{cluster_key}}) && $self->{clusters}->{$aggregate->{cluster_key}} !~ /$self->{option_results}->{filter_cluster}/) {
$self->{output}->output_add(long_msg => "skipping '" . $aggregate->{name} . "': no matching filter cluster '" . $self->{clusters}->{$aggregate->{cluster_key}} . "'", debug => 1);
next;
}
$self->{aggregates}->{$aggregate->{key}} = {
name => $aggregate->{name},
state => $aggregate->{state},
mirror_status => $aggregate->{mirror_status},
raid_type => $aggregate->{raid_type},
aggregate_type => $aggregate->{aggregate_type},
snaplock_type => $aggregate->{snaplock_type},
cluster => $self->{clusters}->{$aggregate->{cluster_key}},
node => $self->{nodes}->{$aggregate->{node_key}},
}
}
}
sub run {
my ($self, %options) = @_;
$self->manage_selection(%options);
foreach my $aggregate (sort keys %{$self->{aggregates}}) {
$self->{output}->output_add(long_msg => sprintf("[name = %s] [state = %s] [mirror_status = %s] [raid_type = %s] [aggregate_type = %s] [snaplock_type = %s] [cluster = %s] [node = %s]",
$self->{aggregates}->{$aggregate}->{name},
$self->{aggregates}->{$aggregate}->{state},
$self->{aggregates}->{$aggregate}->{mirror_status},
$self->{aggregates}->{$aggregate}->{raid_type},
$self->{aggregates}->{$aggregate}->{aggregate_type},
$self->{aggregates}->{$aggregate}->{snaplock_type},
$self->{aggregates}->{$aggregate}->{cluster},
$self->{aggregates}->{$aggregate}->{node}));
}
$self->{output}->output_add(severity => 'OK',
short_msg => 'List aggregates:');
$self->{output}->display(nolabel => 1, force_ignore_perfdata => 1, force_long_output => 1);
$self->{output}->exit();
}
sub disco_format {
my ($self, %options) = @_;
$self->{output}->add_disco_format(elements => ['name', 'state', 'mirror_status',
'raid_type', 'aggregate_type', 'snaplock_type']);
}
sub disco_show {
my ($self, %options) = @_;
$self->manage_selection(%options);
foreach my $aggregate (sort keys %{$self->{aggregates}}) {
$self->{output}->add_disco_entry(
name => $self->{aggregates}->{$aggregate}->{name},
state => $self->{aggregates}->{$aggregate}->{state},
mirror_status => $self->{aggregates}->{$aggregate}->{mirror_status},
raid_type => $self->{aggregates}->{$aggregate}->{raid_type},
aggregate_type => $self->{aggregates}->{$aggregate}->{aggregate_type},
snaplock_type => $self->{aggregates}->{$aggregate}->{snaplock_type},
cluster => $self->{aggregates}->{$aggregate}->{cluster},
node => $self->{aggregates}->{$aggregate}->{node},
);
}
}
1;
__END__
=head1 MODE
List aggregates.
=over 8
=item B<--filter-*>
Filter aggregates.
Can be: 'name', 'node', 'cluster' (can be a regexp).
=back
=cut

View File

@ -0,0 +1,123 @@
#
# Copyright 2018 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::netapp::restapi::mode::listclusters;
use base qw(centreon::plugins::templates::counter);
use strict;
use warnings;
sub new {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options);
bless $self, $class;
$self->{version} = '1.0';
$options{options}->add_options(arguments =>
{
"filter-name:s" => { name => 'filter_name' },
});
return $self;
}
sub check_options {
my ($self, %options) = @_;
$self->SUPER::check_options(%options);
}
sub manage_selection {
my ($self, %options) = @_;
my $result = $options{custom}->get(path => '/clusters');
foreach my $cluster (@{$result}) {
if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' &&
$cluster->{name} !~ /$self->{option_results}->{filter_name}/) {
$self->{output}->output_add(long_msg => "skipping '" . $cluster->{name} . "': no matching filter name.", debug => 1);
next;
}
$self->{clusters}->{$cluster->{key}} = {
name => $cluster->{name},
status => $cluster->{status},
metro_cluster_mode => defined($cluster->{metro_cluster_mode}) ? $cluster->{metro_cluster_mode} : "-",
metro_cluster_configuration_state => defined($cluster->{metro_cluster_configuration_state}) ? $cluster->{metro_cluster_configuration_state} : "-",
}
}
}
sub run {
my ($self, %options) = @_;
$self->manage_selection(%options);
foreach my $cluster (sort keys %{$self->{clusters}}) {
$self->{output}->output_add(long_msg => sprintf("[name = %s] [status = %s] [metro_cluster_mode = %s] [metro_cluster_configuration_state = %s]",
$self->{clusters}->{$cluster}->{name},
$self->{clusters}->{$cluster}->{status},
$self->{clusters}->{$cluster}->{metro_cluster_mode},
$self->{clusters}->{$cluster}->{metro_cluster_configuration_state}));
}
$self->{output}->output_add(severity => 'OK',
short_msg => 'List clusters:');
$self->{output}->display(nolabel => 1, force_ignore_perfdata => 1, force_long_output => 1);
$self->{output}->exit();
}
sub disco_format {
my ($self, %options) = @_;
$self->{output}->add_disco_format(elements => ['name', 'status', 'metro_cluster_mode',
'metro_cluster_configuration_state']);
}
sub disco_show {
my ($self, %options) = @_;
$self->manage_selection(%options);
foreach my $cluster (sort keys %{$self->{clusters}}) {
$self->{output}->add_disco_entry(
name => $self->{clusters}->{$cluster}->{name},
status => $self->{clusters}->{$cluster}->{status},
metro_cluster_mode => $self->{clusters}->{$cluster}->{metro_cluster_mode},
metro_cluster_configuration_state => $self->{clusters}->{$cluster}->{metro_cluster_configuration_state},
);
}
}
1;
__END__
=head1 MODE
List clusters.
=over 8
=item B<--filter-name>
Filter snapmirror name (can be a regexp).
=back
=cut

View File

@ -0,0 +1,125 @@
#
# Copyright 2018 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::netapp::restapi::mode::listfcports;
use base qw(centreon::plugins::templates::counter);
use strict;
use warnings;
sub new {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options);
bless $self, $class;
$self->{version} = '1.0';
$options{options}->add_options(arguments =>
{
"filter-name:s" => { name => 'filter_name' },
});
return $self;
}
sub check_options {
my ($self, %options) = @_;
$self->SUPER::check_options(%options);
}
sub manage_selection {
my ($self, %options) = @_;
my $result = $options{custom}->get(path => '/fc-ports');
foreach my $fcport (@{$result}) {
if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' &&
$fcport->{wwpn} !~ /$self->{option_results}->{filter_name}/) {
$self->{output}->output_add(long_msg => "skipping '" . $fcport->{name} . "': no matching filter name.", debug => 1);
next;
}
$self->{fcports}->{$fcport->{key}} = {
wwpn => $fcport->{wwpn},
adapter => $fcport->{adapter},
status => $fcport->{status},
state => $fcport->{state},
switch_port => $fcport->{switch_port},
}
}
}
sub run {
my ($self, %options) = @_;
$self->manage_selection(%options);
foreach my $fcport (sort keys %{$self->{fcports}}) {
$self->{output}->output_add(long_msg => sprintf("[wwpn = %s] [adapter = %s] [status = %s] [state = %s] [switch_port = %s]",
$self->{fcports}->{$fcport}->{wwpn},
$self->{fcports}->{$fcport}->{adapter},
$self->{fcports}->{$fcport}->{status},
$self->{fcports}->{$fcport}->{state},
$self->{fcports}->{$fcport}->{switch_port}));
}
$self->{output}->output_add(severity => 'OK',
short_msg => 'List FC ports:');
$self->{output}->display(nolabel => 1, force_ignore_perfdata => 1, force_long_output => 1);
$self->{output}->exit();
}
sub disco_format {
my ($self, %options) = @_;
$self->{output}->add_disco_format(elements => ['wwpn', 'adapter', 'status', 'state', 'switch_port']);
}
sub disco_show {
my ($self, %options) = @_;
$self->manage_selection(%options);
foreach my $fcport (sort keys %{$self->{fcports}}) {
$self->{output}->add_disco_entry(
wwpn => $self->{fcports}->{$fcport}->{wwpn},
adapter => $self->{fcports}->{$fcport}->{adapter},
status => $self->{fcports}->{$fcport}->{status},
state => $self->{fcports}->{$fcport}->{state},
switch_port => $self->{fcports}->{$fcport}->{switch_port},
);
}
}
1;
__END__
=head1 MODE
List FC ports.
=over 8
=item B<--filter-name>
Filter FC ports name (can be a regexp).
=back
=cut

View File

@ -0,0 +1,129 @@
#
# Copyright 2018 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::netapp::restapi::mode::listluns;
use base qw(centreon::plugins::templates::counter);
use strict;
use warnings;
sub new {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options);
bless $self, $class;
$self->{version} = '1.0';
$options{options}->add_options(arguments =>
{
"filter-name:s" => { name => 'filter_name' },
});
return $self;
}
sub check_options {
my ($self, %options) = @_;
$self->SUPER::check_options(%options);
}
sub manage_selection {
my ($self, %options) = @_;
my $result = $options{custom}->get(path => '/luns');
foreach my $lun (@{$result}) {
if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' &&
$lun->{path} !~ /$self->{option_results}->{filter_name}/) {
$self->{output}->output_add(long_msg => "skipping '" . $lun->{path} . "': no matching filter name.", debug => 1);
next;
}
$self->{luns}->{$lun->{key}} = {
path => $lun->{path},
is_online => $lun->{is_online},
is_mapped => $lun->{is_mapped},
lun_class => $lun->{lun_class},
alignment => $lun->{alignment},
multi_protocol_type => $lun->{multi_protocol_type},
size => $lun->{size},
}
}
}
sub run {
my ($self, %options) = @_;
$self->manage_selection(%options);
foreach my $lun (sort keys %{$self->{luns}}) {
$self->{output}->output_add(long_msg => sprintf("[path = %s] [is_online = %s] [is_mapped = %s] [lun_class = %s] [alignment = %s] [multi_protocol_type = %s] [size = %s]",
$self->{luns}->{$lun}->{path}, $self->{luns}->{$lun}->{is_online},
$self->{luns}->{$lun}->{is_mapped}, $self->{luns}->{$lun}->{lun_class},
$self->{luns}->{$lun}->{alignment}, $self->{luns}->{$lun}->{multi_protocol_type},
$self->{luns}->{$lun}->{size}));
}
$self->{output}->output_add(severity => 'OK',
short_msg => 'List luns:');
$self->{output}->display(nolabel => 1, force_ignore_perfdata => 1, force_long_output => 1);
$self->{output}->exit();
}
sub disco_format {
my ($self, %options) = @_;
$self->{output}->add_disco_format(elements => ['path', 'is_online', 'is_mapped', 'lun_class', 'alignment',
'multi_protocol_type', 'size']);
}
sub disco_show {
my ($self, %options) = @_;
$self->manage_selection(%options);
foreach my $lun (sort keys %{$self->{luns}}) {
$self->{output}->add_disco_entry(
path => $self->{luns}->{$lun}->{path},
is_online => $self->{luns}->{$lun}->{is_online},
is_mapped => $self->{luns}->{$lun}->{is_mapped},
lun_class => $self->{luns}->{$lun}->{lun_class},
alignment => $self->{luns}->{$lun}->{alignment},
multi_protocol_type => $self->{luns}->{$lun}->{multi_protocol_type},
size => $self->{luns}->{$lun}->{size},
);
}
}
1;
__END__
=head1 MODE
List LUNs.
=over 8
=item B<--filter-name>
Filter lun name (can be a regexp).
=back
=cut

View File

@ -0,0 +1,123 @@
#
# Copyright 2018 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::netapp::restapi::mode::listnodes;
use base qw(centreon::plugins::templates::counter);
use strict;
use warnings;
sub new {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options);
bless $self, $class;
$self->{version} = '1.0';
$options{options}->add_options(arguments =>
{
"filter-name:s" => { name => 'filter_name' },
});
return $self;
}
sub check_options {
my ($self, %options) = @_;
$self->SUPER::check_options(%options);
}
sub manage_selection {
my ($self, %options) = @_;
my $result = $options{custom}->get(path => '/nodes');
foreach my $node (@{$result}) {
if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' &&
$node->{name} !~ /$self->{option_results}->{filter_name}/) {
$self->{output}->output_add(long_msg => "skipping '" . $node->{name} . "': no matching filter name.", debug => 1);
next;
}
$self->{nodes}->{$node->{key}} = {
name => $node->{name},
is_node_healthy => $node->{is_node_healthy},
current_mode => $node->{current_mode},
failover_state => $node->{failover_state},
is_failover_enabled => $node->{is_failover_enabled},
}
}
}
sub run {
my ($self, %options) = @_;
$self->manage_selection(%options);
foreach my $node (sort keys %{$self->{nodes}}) {
$self->{output}->output_add(long_msg => sprintf("[name = %s] [status = %s] [current_mode = %s] [failover_state = %s] [failover = %s]",
$self->{nodes}->{$node}->{name}, ($self->{nodes}->{$node}->{is_node_healthy}) ? "healthy" : "not healthy",
$self->{nodes}->{$node}->{current_mode}, $self->{nodes}->{$node}->{failover_state},
($self->{nodes}->{$node}->{is_failover_enabled}) ? "enabled" : "disabled"));
}
$self->{output}->output_add(severity => 'OK',
short_msg => 'List nodes:');
$self->{output}->display(nolabel => 1, force_ignore_perfdata => 1, force_long_output => 1);
$self->{output}->exit();
}
sub disco_format {
my ($self, %options) = @_;
$self->{output}->add_disco_format(elements => ['name', 'status', 'current_mode', 'failover_state', 'failover']);
}
sub disco_show {
my ($self, %options) = @_;
$self->manage_selection(%options);
foreach my $node (sort keys %{$self->{nodes}}) {
$self->{output}->add_disco_entry(
name => $self->{nodes}->{$node}->{name},
status => ($self->{nodes}->{$node}->{is_node_healthy}) ? "healthy" : "not healthy",
current_mode => $self->{nodes}->{$node}->{current_mode},
failover_state => $self->{nodes}->{$node}->{failover_state},
failover => ($self->{nodes}->{$node}->{is_failover_enabled}) ? "enabled" : "disabled",
);
}
}
1;
__END__
=head1 MODE
List nodes.
=over 8
=item B<--filter-name>
Filter node name (can be a regexp).
=back
=cut

View File

@ -0,0 +1,123 @@
#
# Copyright 2018 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::netapp::restapi::mode::listsnapmirrors;
use base qw(centreon::plugins::templates::counter);
use strict;
use warnings;
sub new {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options);
bless $self, $class;
$self->{version} = '1.0';
$options{options}->add_options(arguments =>
{
"filter-name:s" => { name => 'filter_name' },
});
return $self;
}
sub check_options {
my ($self, %options) = @_;
$self->SUPER::check_options(%options);
}
sub manage_selection {
my ($self, %options) = @_;
my $result = $options{custom}->get(path => '/snap-mirrors');
foreach my $snapmirror (@{$result}) {
if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' &&
$snapmirror->{source_location} !~ /$self->{option_results}->{filter_name}/) {
$self->{output}->output_add(long_msg => "skipping '" . $snapmirror->{name} . "': no matching filter name.", debug => 1);
next;
}
$self->{snapmirrors}->{$snapmirror->{key}} = {
source_location => $snapmirror->{source_location},
destination_location => $snapmirror->{destination_location},
mirror_state => $snapmirror->{mirror_state},
is_healthy => $snapmirror->{is_healthy},
}
}
}
sub run {
my ($self, %options) = @_;
$self->manage_selection(%options);
foreach my $snapmirror (sort keys %{$self->{snapmirrors}}) {
$self->{output}->output_add(long_msg => sprintf("[source_location = %s] [destination_location = %s] [mirror_state = %s] [is_healthy = %s]",
$self->{snapmirrors}->{$snapmirror}->{source_location},
$self->{snapmirrors}->{$snapmirror}->{destination_location},
$self->{snapmirrors}->{$snapmirror}->{mirror_state},
$self->{snapmirrors}->{$snapmirror}->{is_healthy}));
}
$self->{output}->output_add(severity => 'OK',
short_msg => 'List snap mirrors:');
$self->{output}->display(nolabel => 1, force_ignore_perfdata => 1, force_long_output => 1);
$self->{output}->exit();
}
sub disco_format {
my ($self, %options) = @_;
$self->{output}->add_disco_format(elements => ['source_location', 'destination_location', 'mirror_state',
'is_healthy']);
}
sub disco_show {
my ($self, %options) = @_;
$self->manage_selection(%options);
foreach my $snapmirror (sort keys %{$self->{snapmirrors}}) {
$self->{output}->add_disco_entry(
source_location => $self->{snapmirrors}->{$snapmirror}->{source_location},
destination_location => $self->{snapmirrors}->{$snapmirror}->{destination_location},
mirror_state => $self->{snapmirrors}->{$snapmirror}->{mirror_state},
is_healthy => $self->{snapmirrors}->{$snapmirror}->{is_healthy},
);
}
}
1;
__END__
=head1 MODE
List snap mirrors.
=over 8
=item B<--filter-name>
Filter snapmirror name (can be a regexp).
=back
=cut

View File

@ -0,0 +1,126 @@
#
# Copyright 2018 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::netapp::restapi::mode::listvolumes;
use base qw(centreon::plugins::templates::counter);
use strict;
use warnings;
sub new {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options);
bless $self, $class;
$self->{version} = '1.0';
$options{options}->add_options(arguments =>
{
"filter-name:s" => { name => 'filter_name' },
});
return $self;
}
sub check_options {
my ($self, %options) = @_;
$self->SUPER::check_options(%options);
}
sub manage_selection {
my ($self, %options) = @_;
my $result = $options{custom}->get(path => '/volumes');
foreach my $volume (@{$result}) {
if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' &&
$volume->{name} !~ /$self->{option_results}->{filter_name}/) {
$self->{output}->output_add(long_msg => "skipping '" . $volume->{name} . "': no matching filter name.", debug => 1);
next;
}
$self->{volumes}->{$volume->{key}} = {
name => $volume->{name},
state => $volume->{state},
vol_type => $volume->{vol_type},
style => $volume->{style},
is_replica_volume => $volume->{is_replica_volume},
size_total => $volume->{size_total},
}
}
}
sub run {
my ($self, %options) = @_;
$self->manage_selection(%options);
foreach my $volume (sort keys %{$self->{volumes}}) {
$self->{output}->output_add(long_msg => sprintf("[name = %s] [state = %s] [vol_type = %s] [style = %s] [is_replica_volume = %s] [size_total = %s]",
$self->{volumes}->{$volume}->{name}, $self->{volumes}->{$volume}->{state},
$self->{volumes}->{$volume}->{vol_type}, $self->{volumes}->{$volume}->{style},
$self->{volumes}->{$volume}->{is_replica_volume}, $self->{volumes}->{$volume}->{size_total}));
}
$self->{output}->output_add(severity => 'OK',
short_msg => 'List volumes:');
$self->{output}->display(nolabel => 1, force_ignore_perfdata => 1, force_long_output => 1);
$self->{output}->exit();
}
sub disco_format {
my ($self, %options) = @_;
$self->{output}->add_disco_format(elements => ['name', 'state', 'vol_type', 'style',
'is_replica_volume', 'size_total']);
}
sub disco_show {
my ($self, %options) = @_;
$self->manage_selection(%options);
foreach my $volume (sort keys %{$self->{volumes}}) {
$self->{output}->add_disco_entry(
name => $self->{volumes}->{$volume}->{name},
state => $self->{volumes}->{$volume}->{state},
vol_type => $self->{volumes}->{$volume}->{vol_type},
style => $self->{volumes}->{$volume}->{style},
is_replica_volume => $self->{volumes}->{$volume}->{is_replica_volume},
size_total => $self->{volumes}->{$volume}->{size_total},
);
}
}
1;
__END__
=head1 MODE
List volumes.
=over 8
=item B<--filter-name>
Filter volume name (can be a regexp).
=back
=cut

View File

@ -0,0 +1,170 @@
#
# Copyright 2018 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::netapp::restapi::mode::lunalignment;
use base qw(centreon::plugins::templates::counter);
use strict;
use warnings;
sub set_counters {
my ($self, %options) = @_;
$self->{maps_counters_type} = [
{ name => 'luns', type => 0},
];
$self->{maps_counters}->{luns} = [
{ label => 'aligned', set => {
key_values => [ { name => 'aligned' } ],
output_template => 'Luns aligned: %d',
perfdatas => [
{ label => 'aligned', value => 'aligned_absolute', template => '%d',
min => 0 },
],
}
},
{ label => 'misaligned', set => {
key_values => [ { name => 'misaligned' } ],
output_template => 'Luns misaligned: %d',
perfdatas => [
{ label => 'misaligned', value => 'misaligned_absolute', template => '%d',
min => 0 },
],
}
},
{ label => 'possibly-misaligned', set => {
key_values => [ { name => 'possibly_misaligned' } ],
output_template => 'Luns possibly misaligned: %d',
perfdatas => [
{ label => 'possibly_misaligned', value => 'possibly_misaligned_absolute', template => '%d',
min => 0 },
],
}
},
{ label => 'indeterminate', set => {
key_values => [ { name => 'indeterminate' } ],
output_template => 'Luns indeterminate: %d',
perfdatas => [
{ label => 'indeterminate', value => 'indeterminate_absolute', template => '%d',
min => 0 },
],
}
},
{ label => 'partial-writes', set => {
key_values => [ { name => 'partial_writes' } ],
output_template => 'Luns partial writes: %d',
perfdatas => [
{ label => 'partial_writes', value => 'partial_writes_absolute', template => '%d',
min => 0 },
],
}
},
{ label => 'not-mapped', set => {
key_values => [ { name => 'not_mapped' } ],
output_template => 'Luns not mapped: %d',
perfdatas => [
{ label => 'not_mapped', value => 'not_mapped_absolute', template => '%d',
min => 0 },
],
}
},
];
}
sub new {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options);
bless $self, $class;
$self->{version} = '1.0';
$options{options}->add_options(arguments =>
{
"filter-volume:s" => { name => 'filter_volume' },
});
return $self;
}
sub check_options {
my ($self, %options) = @_;
$self->SUPER::check_options(%options);
}
sub manage_selection {
my ($self, %options) = @_;
my $result = $options{custom}->get(path => '/luns');
$self->{luns}->{aligned} = 0;
$self->{luns}->{misaligned} = 0;
$self->{luns}->{possibly_misaligned} = 0;
$self->{luns}->{indeterminate} = 0;
$self->{luns}->{partial_writes} = 0;
$self->{luns}->{not_mapped} = 0;
foreach my $lun (@{$result}) {
my $volume = $2 if ($lun->{path} =~ /^\/(\S+)\/(\S+)\/(\S+)\s*/);
if (defined($self->{option_results}->{filter_volume}) && $self->{option_results}->{filter_volume} ne '' &&
defined($volume) && $volume !~ /$self->{option_results}->{filter_volume}/) {
$self->{output}->output_add(long_msg => "skipping '" . $lun->{path} . "': no matching filter volume '" . $volume . "'", debug => 1);
next;
}
$self->{luns}->{$lun->{alignment}}++;
if ($lun->{alignment} ne "aligned" && $lun->{alignment} ne "indeterminate") {
my $long_msg = "Lun '" . $lun->{path} . "' is '" . $lun->{alignment} . "'";
$long_msg .= " [volume: " . $volume . "]" if (defined($self->{option_results}->{filter_volume}) && $self->{option_results}->{filter_volume} ne '');
$self->{output}->output_add(long_msg => $long_msg);
}
}
}
1;
__END__
=head1 MODE
Check NetApp luns alignment.
=over 8
=item B<--filter-*>
Filter lun.
Can be: 'volume' (can be a regexp).
=item B<--warning-*>
Threshold warning.
'aligned', 'misaligned', 'possibly-misaligned', 'indeterminate', 'partial-writes', 'not-mapped'.
=item B<--critical-*>
Threshold critical.
'aligned', 'misaligned', 'possibly-misaligned', 'indeterminate', 'partial-writes', 'not-mapped'.
=back
=cut

View File

@ -0,0 +1,159 @@
#
# Copyright 2018 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::netapp::restapi::mode::lunonline;
use base qw(centreon::plugins::templates::counter);
use strict;
use warnings;
sub set_counters {
my ($self, %options) = @_;
$self->{maps_counters_type} = [
{ name => 'luns', type => 0},
];
$self->{maps_counters}->{luns} = [
{ label => 'online', set => {
key_values => [ { name => 'online' } ],
output_template => 'Luns online: %d',
perfdatas => [
{ label => 'online', value => 'online_absolute', template => '%d',
min => 0 },
],
}
},
{ label => 'not-online', set => {
key_values => [ { name => 'not_online' } ],
output_template => 'Luns not online: %d',
perfdatas => [
{ label => 'not_online', value => 'not_online_absolute', template => '%d',
min => 0 },
],
}
},
{ label => 'mapped', set => {
key_values => [ { name => 'mapped' } ],
output_template => 'Luns mapped: %d',
perfdatas => [
{ label => 'mapped', value => 'mapped_absolute', template => '%d',
min => 0 },
],
}
},
{ label => 'not-mapped', set => {
key_values => [ { name => 'not_mapped' } ],
output_template => 'Luns not mapped: %d',
perfdatas => [
{ label => 'not_mapped', value => 'not_mapped_absolute', template => '%d',
min => 0 },
],
}
},
];
}
sub new {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options);
bless $self, $class;
$self->{version} = '1.0';
$options{options}->add_options(arguments =>
{
"filter-volume:s" => { name => 'filter_volume' },
});
return $self;
}
sub check_options {
my ($self, %options) = @_;
$self->SUPER::check_options(%options);
}
sub manage_selection {
my ($self, %options) = @_;
my $result = $options{custom}->get(path => '/luns');
$self->{luns}->{online} = 0;
$self->{luns}->{not_online} = 0;
$self->{luns}->{mapped} = 0;
$self->{luns}->{not_mapped} = 0;
foreach my $lun (@{$result}) {
my $volume = $2 if ($lun->{path} =~ /^\/(\S+)\/(\S+)\/(\S+)\s*/);
if (defined($self->{option_results}->{filter_volume}) && $self->{option_results}->{filter_volume} ne '' &&
defined($volume) && $volume !~ /$self->{option_results}->{filter_volume}/) {
$self->{output}->output_add(long_msg => "skipping '" . $lun->{path} . "': no matching filter volume '" . $volume . "'", debug => 1);
next;
}
$self->{luns}->{online}++ if ($lun->{is_online});
$self->{luns}->{mapped}++ if ($lun->{is_mapped});
if (!$lun->{is_online}) {
$self->{luns}->{not_online}++;
my $long_msg = "Lun '" . $lun->{path} . "' is 'not online'";
$long_msg .= " [volume: " . $volume . "]" if (defined($self->{option_results}->{filter_volume}) && $self->{option_results}->{filter_volume} ne '');
$self->{output}->output_add(long_msg => $long_msg);
}
if (!$lun->{is_mapped}) {
$self->{luns}->{not_mapped}++;
my $long_msg = "Lun '" . $lun->{path} . "' is 'not mapped'";
$long_msg .= " [volume: " . $volume . "]" if (defined($self->{option_results}->{filter_volume}) && $self->{option_results}->{filter_volume} ne '');
$self->{output}->output_add(long_msg => $long_msg);
}
}
}
1;
__END__
=head1 MODE
Check NetApp luns status.
=over 8
=item B<--filter-*>
Filter lun.
Can be: 'volume' (can be a regexp).
=item B<--warning-*>
Threshold warning.
Can be: 'online', 'not-online', 'mapped', 'not-mapped'.
=item B<--critical-*>
Threshold critical.
Can be: 'online', 'not-online', 'mapped', 'not-mapped'.
=back
=cut

View File

@ -0,0 +1,199 @@
#
# Copyright 2018 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::netapp::restapi::mode::lunusage;
use base qw(centreon::plugins::templates::counter);
use strict;
use warnings;
my $instance_mode;
sub custom_usage_perfdata {
my ($self, %options) = @_;
my $extra_label = '';
$extra_label = '_' . $self->{result_values}->{display} if (!defined($options{extra_instance}) || $options{extra_instance} != 0);
$self->{output}->perfdata_add(label => 'used' . $extra_label,
unit => 'B',
value => $self->{result_values}->{used},
warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{label}, total => $self->{result_values}->{total}, cast_int => 1),
critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{label}, total => $self->{result_values}->{total}, cast_int => 1),
min => 0, max => $self->{result_values}->{total});
}
sub custom_usage_threshold {
my ($self, %options) = @_;
my ($exit, $threshold_value);
$threshold_value = $self->{result_values}->{used};
$threshold_value = $self->{result_values}->{free} if (defined($instance_mode->{option_results}->{free}));
if ($instance_mode->{option_results}->{units} eq '%') {
$threshold_value = $self->{result_values}->{prct_used};
$threshold_value = $self->{result_values}->{prct_free} if (defined($instance_mode->{option_results}->{free}));
}
$exit = $self->{perfdata}->threshold_check(value => $threshold_value,
threshold => [ { label => 'critical-' . $self->{label}, exit_litteral => 'critical' },
{ label => 'warning-' . $self->{label}, exit_litteral => 'warning' } ]);
return $exit;
}
sub custom_usage_output {
my ($self, %options) = @_;
my ($used_value, $used_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{used});
my ($free_value, $free_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{free});
my ($total_value, $total_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{total});
my $msg = sprintf("Total: %s Used: %s (%.2f%%) Free: %s (%.2f%%)",
$total_value . " " . $total_unit,
$used_value . " " . $used_unit, $self->{result_values}->{prct_used},
$free_value . " " . $free_unit, $self->{result_values}->{prct_free});
return $msg;
}
sub custom_usage_calc {
my ($self, %options) = @_;
$self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_path'};
$self->{result_values}->{total} = $options{new_datas}->{$self->{instance} . '_size'};
$self->{result_values}->{used} = $options{new_datas}->{$self->{instance} . '_size_used'};
if ($self->{result_values}->{total} != 0) {
$self->{result_values}->{free} = $self->{result_values}->{total} - $self->{result_values}->{used};
$self->{result_values}->{prct_used} = $self->{result_values}->{used} * 100 / $self->{result_values}->{total};
$self->{result_values}->{prct_free} = 100 - $self->{result_values}->{prct_used};
} else {
$self->{result_values}->{free} = '0';
$self->{result_values}->{prct_used} = '0';
$self->{result_values}->{prct_free} = '0';
}
return 0;
}
sub prefix_output {
my ($self, %options) = @_;
return "Lun '" . $options{instance_value}->{path} . "' ";
}
sub set_counters {
my ($self, %options) = @_;
$self->{maps_counters_type} = [
{ name => 'luns', type => 1, cb_prefix_output => 'prefix_output', message_multiple => 'All luns usage are ok' },
];
$self->{maps_counters}->{luns} = [
{ label => 'usage', set => {
key_values => [ { name => 'size_used' }, { name => 'size' }, { name => 'path' } ],
closure_custom_calc => $self->can('custom_usage_calc'),
closure_custom_output => $self->can('custom_usage_output'),
closure_custom_perfdata => $self->can('custom_usage_perfdata'),
closure_custom_threshold_check => $self->can('custom_usage_threshold'),
}
},
];
}
sub new {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options);
bless $self, $class;
$self->{version} = '1.0';
$options{options}->add_options(arguments =>
{
"filter-name:s" => { name => 'filter_name' },
"units:s" => { name => 'units', default => '%' },
"free" => { name => 'free' },
});
return $self;
}
sub check_options {
my ($self, %options) = @_;
$self->SUPER::check_options(%options);
$instance_mode = $self;
}
sub manage_selection {
my ($self, %options) = @_;
my $result = $options{custom}->get(path => '/luns');
foreach my $lun (@{$result}) {
if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' &&
$lun->{path} !~ /$self->{option_results}->{filter_name}/) {
$self->{output}->output_add(long_msg => "skipping '" . $lun->{path} . "': no matching filter name.", debug => 1);
next;
}
$self->{luns}->{$lun->{key}} = {
path => $lun->{path},
size => $lun->{size},
size_used => $lun->{size_used},
}
}
if (scalar(keys %{$self->{luns}}) <= 0) {
$self->{output}->add_option_msg(short_msg => "No entry found.");
$self->{output}->option_exit();
}
}
1;
__END__
=head1 MODE
Check NetApp luns usage.
=over 8
=item B<--filter-name>
Filter lun name (can be a regexp).
=item B<--warning-usage>
Threshold warning.
=item B<--critical-usage>
Threshold critical.
=item B<--units>
Units of thresholds (Default: '%') ('%', 'B').
=item B<--free>
Thresholds are on free space left.
=back
=cut

View File

@ -0,0 +1,204 @@
#
# Copyright 2018 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::netapp::restapi::mode::nodefailoverstatus;
use base qw(centreon::plugins::templates::counter);
use strict;
use warnings;
my $instance_mode;
sub custom_status_threshold {
my ($self, %options) = @_;
my $status = 'ok';
my $message;
eval {
local $SIG{__WARN__} = sub { $message = $_[0]; };
local $SIG{__DIE__} = sub { $message = $_[0]; };
if (defined($instance_mode->{option_results}->{critical_status}) && $instance_mode->{option_results}->{critical_status} ne '' &&
eval "$instance_mode->{option_results}->{critical_status}") {
$status = 'critical';
} elsif (defined($instance_mode->{option_results}->{warning_status}) && $instance_mode->{option_results}->{warning_status} ne '' &&
eval "$instance_mode->{option_results}->{warning_status}") {
$status = 'warning';
}
};
if (defined($message)) {
$self->{output}->output_add(long_msg => 'filter status issue: ' . $message);
}
return $status;
}
sub custom_status_output {
my ($self, %options) = @_;
my $msg = sprintf("Failover state is '%s', Interconnect is '%s' [current mode: %s] [take_over_possible: %s]",
$self->{result_values}->{state},
$self->{result_values}->{interconnect},
$self->{result_values}->{current_mode},
$self->{result_values}->{take_over_possible});
return $msg;
}
sub custom_status_calc {
my ($self, %options) = @_;
$self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_name'};
$self->{result_values}->{state} = $options{new_datas}->{$self->{instance} . '_failover_state'};
$self->{result_values}->{interconnect} = ($options{new_datas}->{$self->{instance} . '_is_interconnect_up'}) ? "up" : "down";
$self->{result_values}->{current_mode} = $options{new_datas}->{$self->{instance} . '_current_mode'};
$self->{result_values}->{take_over_possible} = ($options{new_datas}->{$self->{instance} . '_is_take_over_possible'}) ? "true" : "false";
return 0;
}
sub prefix_output {
my ($self, %options) = @_;
return "Node '" . $options{instance_value}->{name} . "' ";
}
sub set_counters {
my ($self, %options) = @_;
$self->{maps_counters_type} = [
{ name => 'nodes', type => 1, cb_prefix_output => 'prefix_output', message_multiple => 'All nodes status are ok' },
];
$self->{maps_counters}->{nodes} = [
{ label => 'status', set => {
key_values => [ { name => 'failover_state' }, { name => 'current_mode' }, { name => 'is_interconnect_up' },
{ name => 'is_take_over_possible' }, { name => 'name' } ],
closure_custom_calc => $self->can('custom_status_calc'),
closure_custom_output => $self->can('custom_status_output'),
closure_custom_perfdata => sub { return 0; },
closure_custom_threshold_check => $self->can('custom_status_threshold'),
}
},
];
}
sub new {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options);
bless $self, $class;
$self->{version} = '1.0';
$options{options}->add_options(arguments =>
{
"filter-name:s" => { name => 'filter_name' },
"filter-cluster:s" => { name => 'filter_cluster' },
"warning-status:s" => { name => 'warning_status' },
"critical-status:s" => { name => 'critical_status', default => '%{state} !~ /connected/i || %{interconnect} !~ /up/i'},
});
return $self;
}
sub change_macros {
my ($self, %options) = @_;
foreach ('warning_status', 'critical_status') {
if (defined($self->{option_results}->{$_})) {
$self->{option_results}->{$_} =~ s/%\{(.*?)\}/\$self->{result_values}->{$1}/g;
}
}
}
sub check_options {
my ($self, %options) = @_;
$self->SUPER::check_options(%options);
$instance_mode = $self;
$self->change_macros();
}
sub manage_selection {
my ($self, %options) = @_;
my $clusters;
if (defined($self->{option_results}->{filter_cluster}) && $self->{option_results}->{filter_cluster} ne '') {
$clusters = $options{custom}->get_objects(path => '/clusters', key => 'key', name => 'name');
}
my $result = $options{custom}->get(path => '/nodes');
foreach my $node (@{$result}) {
if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' &&
$node->{name} !~ /$self->{option_results}->{filter_name}/) {
$self->{output}->output_add(long_msg => "skipping '" . $node->{name} . "': no matching filter name.", debug => 1);
next;
}
if (defined($self->{option_results}->{filter_cluster}) && $self->{option_results}->{filter_cluster} ne '' &&
defined($clusters->{$node->{cluster_key}}) && $clusters->{$node->{cluster_key}} !~ /$self->{option_results}->{filter_cluster}/) {
$self->{output}->output_add(long_msg => "skipping '" . $node->{name} . "': no matching filter cluster '" . $clusters->{$node->{cluster_key}} . "'", debug => 1);
next;
}
$self->{nodes}->{$node->{key}} = {
name => $node->{name},
failover_state => $node->{failover_state},
current_mode => $node->{current_mode},
is_interconnect_up => $node->{is_interconnect_up},
is_take_over_possible => $node->{is_take_over_possible},
}
}
if (scalar(keys %{$self->{nodes}}) <= 0) {
$self->{output}->add_option_msg(short_msg => "No entry found.");
$self->{output}->option_exit();
}
}
1;
__END__
=head1 MODE
Check NetApp nodes status.
=over 8
=item B<--filter-*>
Filter node.
Can be: 'name', 'clusters' (can be a regexp).
=item B<--warning-status>
Set warning threshold for status (Default: '').
Can used special variables like: %{state}, %{interconnect}, %{current_mode}, %{take_over_possible}
=item B<--critical-status>
Set critical threshold for status (Default: '%{state} !~ /connected/i || %{interconnect} !~ /up/i').
Can used special variables like: %{state}, %{interconnect}, %{current_mode}, %{take_over_possible}
=back
=cut

View File

@ -0,0 +1,233 @@
#
# Copyright 2018 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::netapp::restapi::mode::nodehardwarestatus;
use base qw(centreon::plugins::templates::counter);
use strict;
use warnings;
my $instance_mode;
sub custom_status_threshold {
my ($self, %options) = @_;
my $status = 'ok';
my $message;
eval {
local $SIG{__WARN__} = sub { $message = $_[0]; };
local $SIG{__DIE__} = sub { $message = $_[0]; };
if (defined($instance_mode->{option_results}->{critical_status}) && $instance_mode->{option_results}->{critical_status} ne '' &&
eval "$instance_mode->{option_results}->{critical_status}") {
$status = 'critical';
} elsif (defined($instance_mode->{option_results}->{warning_status}) && $instance_mode->{option_results}->{warning_status} ne '' &&
eval "$instance_mode->{option_results}->{warning_status}") {
$status = 'warning';
}
};
if (defined($message)) {
$self->{output}->output_add(long_msg => 'filter status issue: ' . $message);
}
return $status;
}
sub custom_status_output {
my ($self, %options) = @_;
my $msg = sprintf("Status is '%s', Battery status is '%s', Temperature is '%s'",
$self->{result_values}->{status},
$self->{result_values}->{battery_status},
$self->{result_values}->{temperature});
return $msg;
}
sub custom_status_calc {
my ($self, %options) = @_;
$self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_name'};
$self->{result_values}->{status} = ($options{new_datas}->{$self->{instance} . '_is_node_healthy'}) ? "healthy" : "not healthy";
$self->{result_values}->{temperature} = ($options{new_datas}->{$self->{instance} . '_is_over_temperature'}) ? "critical" : "ok";
$self->{result_values}->{battery_status} = $options{new_datas}->{$self->{instance} . '_nvram_battery_status'};
return 0;
}
sub prefix_output {
my ($self, %options) = @_;
return "Node '" . $options{instance_value}->{name} . "' ";
}
sub set_counters {
my ($self, %options) = @_;
$self->{maps_counters_type} = [
{ name => 'nodes', type => 1, cb_prefix_output => 'prefix_output', message_multiple => 'All nodes status are ok' },
];
$self->{maps_counters}->{nodes} = [
{ label => 'status', set => {
key_values => [ { name => 'is_node_healthy' }, { name => 'is_over_temperature' },
{ name => 'nvram_battery_status' }, { name => 'name' } ],
closure_custom_calc => $self->can('custom_status_calc'),
closure_custom_output => $self->can('custom_status_output'),
closure_custom_perfdata => sub { return 0; },
closure_custom_threshold_check => $self->can('custom_status_threshold'),
}
},
{ label => 'failed-fans', set => {
key_values => [ { name => 'failed_fan_count' }, { name => 'name' } ],
output_template => '%d failed fan(s)',
perfdatas => [
{ label => 'failed_fans', value => 'failed_fan_count_absolute', template => '%d',
min => 0, label_extra_instance => 1, instance_use => 'name_absolute' },
],
}
},
{ label => 'failed-psu', set => {
key_values => [ { name => 'failed_power_supply_count' }, { name => 'name' } ],
output_template => '%d failed psu',
perfdatas => [
{ label => 'failed_psu', value => 'failed_power_supply_count_absolute', template => '%d',
min => 0, label_extra_instance => 1, instance_use => 'name_absolute' },
],
}
},
];
}
sub new {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options);
bless $self, $class;
$self->{version} = '1.0';
$options{options}->add_options(arguments =>
{
"filter-name:s" => { name => 'filter_name' },
"filter-cluster:s" => { name => 'filter_cluster' },
"warning-status:s" => { name => 'warning_status' },
"critical-status:s" => { name => 'critical_status', default => '%{status} =~ /not healthy/i || ' .
'%{temperature} !~ /ok/i || %{battery_status} !~ /battery_ok|battery_fully_charge|battery_over_charged/i' },
});
return $self;
}
sub change_macros {
my ($self, %options) = @_;
foreach ('warning_status', 'critical_status') {
if (defined($self->{option_results}->{$_})) {
$self->{option_results}->{$_} =~ s/%\{(.*?)\}/\$self->{result_values}->{$1}/g;
}
}
}
sub check_options {
my ($self, %options) = @_;
$self->SUPER::check_options(%options);
$instance_mode = $self;
$self->change_macros();
}
sub manage_selection {
my ($self, %options) = @_;
my $clusters;
if (defined($self->{option_results}->{filter_cluster}) && $self->{option_results}->{filter_cluster} ne '') {
$clusters = $options{custom}->get_objects(path => '/clusters', key => 'key', name => 'name');
}
my $result = $options{custom}->get(path => '/nodes');
foreach my $node (@{$result}) {
if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' &&
$node->{name} !~ /$self->{option_results}->{filter_name}/) {
$self->{output}->output_add(long_msg => "skipping '" . $node->{name} . "': no matching filter name.", debug => 1);
next;
}
if (defined($self->{option_results}->{filter_cluster}) && $self->{option_results}->{filter_cluster} ne '' &&
defined($clusters->{$node->{cluster_key}}) && $clusters->{$node->{cluster_key}} !~ /$self->{option_results}->{filter_cluster}/) {
$self->{output}->output_add(long_msg => "skipping '" . $node->{name} . "': no matching filter cluster '" . $clusters->{$node->{cluster_key}} . "'", debug => 1);
next;
}
$self->{nodes}->{$node->{key}} = {
name => $node->{name},
is_node_healthy => $node->{is_node_healthy},
is_over_temperature => $node->{is_over_temperature},
nvram_battery_status => $node->{nvram_battery_status},
failed_fan_count => $node->{failed_fan_count},
failed_power_supply_count => $node->{failed_power_supply_count},
}
}
if (scalar(keys %{$self->{nodes}}) <= 0) {
$self->{output}->add_option_msg(short_msg => "No entry found.");
$self->{output}->option_exit();
}
}
1;
__END__
=head1 MODE
Check NetApp nodes hardware status.
=over 8
=item B<--filter-*>
Filter node.
Can be: 'name', 'clusters' (can be a regexp).
=item B<--warning-*>
Threshold warning.
Can be: 'failed-fans', 'psu'.
=item B<--critical-*>
Threshold critical.
Can be: 'failed-fans', 'psu'.
=item B<--warning-status>
Set warning threshold for status (Default: '').
Can used special variables like: %{status}, %{temperature}, %{battery_status}
=item B<--critical-status>
Set critical threshold for status (Default: '%{status} =~ /not healthy/i || %{temperature} !~ /ok/i ||
%{battery_status} !~ /battery_ok|battery_fully_charge|battery_over_charged/i').
Can used special variables like: %{status}, %{temperature}, %{battery_status}
=back
=cut

View File

@ -0,0 +1,196 @@
#
# Copyright 2018 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::netapp::restapi::mode::qtreestatus;
use base qw(centreon::plugins::templates::counter);
use strict;
use warnings;
my $instance_mode;
sub custom_status_threshold {
my ($self, %options) = @_;
my $status = 'ok';
my $message;
eval {
local $SIG{__WARN__} = sub { $message = $_[0]; };
local $SIG{__DIE__} = sub { $message = $_[0]; };
if (defined($instance_mode->{option_results}->{critical_status}) && $instance_mode->{option_results}->{critical_status} ne '' &&
eval "$instance_mode->{option_results}->{critical_status}") {
$status = 'critical';
} elsif (defined($instance_mode->{option_results}->{warning_status}) && $instance_mode->{option_results}->{warning_status} ne '' &&
eval "$instance_mode->{option_results}->{warning_status}") {
$status = 'warning';
}
};
if (defined($message)) {
$self->{output}->output_add(long_msg => 'filter status issue: ' . $message);
}
return $status;
}
sub custom_status_output {
my ($self, %options) = @_;
my $msg = sprintf("Status is '%s' [path: %s] [volume: %s]",
$self->{result_values}->{status},
$self->{result_values}->{qtree_path},
$self->{result_values}->{volume});
return $msg;
}
sub custom_status_calc {
my ($self, %options) = @_;
$self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_name'};
$self->{result_values}->{status} = $options{new_datas}->{$self->{instance} . '_status'};
$self->{result_values}->{qtree_path} = $options{new_datas}->{$self->{instance} . '_qtree_path'};
$self->{result_values}->{volume} = $options{new_datas}->{$self->{instance} . '_volume'};
return 0;
}
sub prefix_output {
my ($self, %options) = @_;
return "Qtree '" . $options{instance_value}->{name} . "' ";
}
sub set_counters {
my ($self, %options) = @_;
$self->{maps_counters_type} = [
{ name => 'qtrees', type => 1, cb_prefix_output => 'prefix_output', message_multiple => 'All Qtrees status are ok' },
];
$self->{maps_counters}->{qtrees} = [
{ label => 'status', set => {
key_values => [ { name => 'status' }, { name => 'qtree_path' }, { name => 'volume' }, { name => 'name' } ],
closure_custom_calc => $self->can('custom_status_calc'),
closure_custom_output => $self->can('custom_status_output'),
closure_custom_perfdata => sub { return 0; },
closure_custom_threshold_check => $self->can('custom_status_threshold'),
}
},
];
}
sub new {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options);
bless $self, $class;
$self->{version} = '1.0';
$options{options}->add_options(arguments =>
{
"filter-name:s" => { name => 'filter_name' },
"filter-volume:s" => { name => 'filter_volume' },
"warning-status:s" => { name => 'warning_status' },
"critical-status:s" => { name => 'critical_status' },
});
return $self;
}
sub change_macros {
my ($self, %options) = @_;
foreach ('warning_status', 'critical_status') {
if (defined($self->{option_results}->{$_})) {
$self->{option_results}->{$_} =~ s/%\{(.*?)\}/\$self->{result_values}->{$1}/g;
}
}
}
sub check_options {
my ($self, %options) = @_;
$self->SUPER::check_options(%options);
$instance_mode = $self;
$self->change_macros();
}
sub manage_selection {
my ($self, %options) = @_;
my $result = $options{custom}->get(path => '/qtrees');
foreach my $qtree (@{$result}) {
if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' &&
$qtree->{name} !~ /$self->{option_results}->{filter_name}/) {
$self->{output}->output_add(long_msg => "skipping '" . $qtree->{name} . "': no matching filter name.", debug => 1);
next;
}
my $volume = $2 if ($qtree->{qtree_path} =~ /^\/(\S+)\/(\S+)\/(\S+)\s*/);
if (defined($self->{option_results}->{filter_volume}) && $self->{option_results}->{filter_volume} ne '' &&
defined($volume) && $volume !~ /$self->{option_results}->{filter_volume}/) {
$self->{output}->output_add(long_msg => "skipping '" . $qtree->{name} . "': no matching filter volume '" . $volume . "'", debug => 1);
next;
}
$self->{qtrees}->{$qtree->{key}} = {
name => $qtree->{name},
status => $qtree->{status},
qtree_path => $qtree->{qtree_path},
volume => $volume,
}
}
if (scalar(keys %{$self->{qtrees}}) <= 0) {
$self->{output}->add_option_msg(short_msg => "No entry found.");
$self->{output}->option_exit();
}
}
1;
__END__
=head1 MODE
Check NetApp Qtrees status.
=over 8
=item B<--filter-*>
Filter qtree.
Can be: 'name', 'volume' (can be a regexp).
=item B<--warning-status>
Set warning threshold for status (Default: '').
Can used special variables like: %{state}
=item B<--critical-status>
Set critical threshold for status (Default: '').
Can used special variables like: %{status}
=back
=cut

View File

@ -0,0 +1,181 @@
#
# Copyright 2018 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::netapp::restapi::mode::snapmirrorstatus;
use base qw(centreon::plugins::templates::counter);
use strict;
use warnings;
my $instance_mode;
sub custom_status_threshold {
my ($self, %options) = @_;
my $status = 'ok';
my $message;
eval {
local $SIG{__WARN__} = sub { $message = $_[0]; };
local $SIG{__DIE__} = sub { $message = $_[0]; };
if (defined($instance_mode->{option_results}->{critical_status}) && $instance_mode->{option_results}->{critical_status} ne '' &&
eval "$instance_mode->{option_results}->{critical_status}") {
$status = 'critical';
} elsif (defined($instance_mode->{option_results}->{warning_status}) && $instance_mode->{option_results}->{warning_status} ne '' &&
eval "$instance_mode->{option_results}->{warning_status}") {
$status = 'warning';
}
};
if (defined($message)) {
$self->{output}->output_add(long_msg => 'filter status issue: ' . $message);
}
return $status;
}
sub custom_status_output {
my ($self, %options) = @_;
my $msg = sprintf("State is '%s', Update is '%s'", $self->{result_values}->{state}, $self->{result_values}->{update});
return $msg;
}
sub custom_status_calc {
my ($self, %options) = @_;
$self->{result_values}->{source_location} = $options{new_datas}->{$self->{instance} . '_source_location'};
$self->{result_values}->{state} = $options{new_datas}->{$self->{instance} . '_mirror_state'};
$self->{result_values}->{update} = $options{new_datas}->{$self->{instance} . '_is_healthy'} ? "healthy" : "not healthy";
return 0;
}
sub prefix_output {
my ($self, %options) = @_;
return "Snap mirror '" . $options{instance_value}->{source_location} . "' ";
}
sub set_counters {
my ($self, %options) = @_;
$self->{maps_counters_type} = [
{ name => 'snapmirrors', type => 1, cb_prefix_output => 'prefix_output', message_multiple => 'All snap mirrors status are ok' },
];
$self->{maps_counters}->{snapmirrors} = [
{ label => 'status', set => {
key_values => [ { name => 'source_location' }, { name => 'mirror_state' }, { name => 'is_healthy' } ],
closure_custom_calc => $self->can('custom_status_calc'),
closure_custom_output => $self->can('custom_status_output'),
closure_custom_perfdata => sub { return 0; },
closure_custom_threshold_check => $self->can('custom_status_threshold'),
}
},
];
}
sub new {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options);
bless $self, $class;
$self->{version} = '1.0';
$options{options}->add_options(arguments =>
{
"filter-name:s" => { name => 'filter_name' },
"warning-status:s" => { name => 'warning_status' },
"critical-status:s" => { name => 'critical_status', default => '%{state} !~ /snapmirrored/i || %{update} =~ /not healthy/i' },
});
return $self;
}
sub change_macros {
my ($self, %options) = @_;
foreach ('warning_status', 'critical_status') {
if (defined($self->{option_results}->{$_})) {
$self->{option_results}->{$_} =~ s/%\{(.*?)\}/\$self->{result_values}->{$1}/g;
}
}
}
sub check_options {
my ($self, %options) = @_;
$self->SUPER::check_options(%options);
$instance_mode = $self;
$self->change_macros();
}
sub manage_selection {
my ($self, %options) = @_;
my $result = $options{custom}->get(path => '/snap-mirrors');
foreach my $snapmirror (@{$result}) {
if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' &&
$snapmirror->{source_location} !~ /$self->{option_results}->{filter_name}/) {
$self->{output}->output_add(long_msg => "skipping '" . $snapmirror->{name} . "': no matching filter name.", debug => 1);
next;
}
$self->{snapmirrors}->{$snapmirror->{key}} = {
source_location => $snapmirror->{source_location},
mirror_state => $snapmirror->{mirror_state},
is_healthy => $snapmirror->{is_healthy},
}
}
if (scalar(keys %{$self->{snapmirrors}}) <= 0) {
$self->{output}->add_option_msg(short_msg => "No entry found.");
$self->{output}->option_exit();
}
}
1;
__END__
=head1 MODE
Check NetApp snap mirrors status.
=over 8
=item B<--filter-name>
Filter snapmirror name (can be a regexp).
=item B<--warning-status>
Set warning threshold for status (Default: '').
Can used special variables like: %{state}, %{update}
=item B<--critical-status>
Set critical threshold for status (Default: '%{state} !~ /snapmirrored/i || %{update} =~ /not healthy/i').
Can used special variables like: %{state}, %{update}
=back
=cut

View File

@ -0,0 +1,144 @@
#
# Copyright 2018 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::netapp::restapi::mode::snapmirrorusage;
use base qw(centreon::plugins::templates::counter);
use strict;
use warnings;
sub prefix_output {
my ($self, %options) = @_;
return "Snap mirror '" . $options{instance_value}->{source_location} . "' ";
}
sub set_counters {
my ($self, %options) = @_;
$self->{maps_counters_type} = [
{ name => 'snapmirrors', type => 1, cb_prefix_output => 'prefix_output', message_multiple => 'All snap mirrors usage are ok' },
];
$self->{maps_counters}->{snapmirrors} = [
{ label => 'last-transfer-duration', set => {
key_values => [ { name => 'last_transfer_duration' }, { name => 'source_location' } ],
output_template => 'Last transfer duration: %.2f s',
perfdatas => [
{ label => 'last_transfer_duration', value => 'last_transfer_duration_absolute', template => '%.2f',
min => 0, unit => 's', label_extra_instance => 1, instance_use => 'source_location_absolute' },
],
}
},
{ label => 'last-transfer-size', set => {
key_values => [ { name => 'last_transfer_size' }, { name => 'source_location' } ],
output_template => 'Last transfer size: %s %s',
output_change_bytes => 1,
perfdatas => [
{ label => 'last_transfer_size', value => 'last_transfer_size_absolute', template => '%d',
min => 0, unit => 'B', label_extra_instance => 1, instance_use => 'source_location_absolute' },
],
}
},
{ label => 'lag-time', set => {
key_values => [ { name => 'lag_time' }, { name => 'source_location' } ],
output_template => 'Lag time: %.2f s',
perfdatas => [
{ label => 'lag_time', value => 'lag_time_absolute', template => '%.2f',
min => 0, unit => 's', label_extra_instance => 1, instance_use => 'source_location_absolute' },
],
}
},
];
}
sub new {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options);
bless $self, $class;
$self->{version} = '1.0';
$options{options}->add_options(arguments =>
{
"filter-name:s" => { name => 'filter_name' },
});
return $self;
}
sub check_options {
my ($self, %options) = @_;
$self->SUPER::check_options(%options);
}
sub manage_selection {
my ($self, %options) = @_;
my $result = $options{custom}->get(path => '/snap-mirrors');
foreach my $snapmirror (@{$result}) {
if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' &&
$snapmirror->{source_location} !~ /$self->{option_results}->{filter_name}/) {
$self->{output}->output_add(long_msg => "skipping '" . $snapmirror->{name} . "': no matching filter name.", debug => 1);
next;
}
$self->{snapmirrors}->{$snapmirror->{key}} = {
source_location => $snapmirror->{source_location},
last_transfer_duration => $snapmirror->{last_transfer_duration},
last_transfer_size => $snapmirror->{last_transfer_size},
lag_time => $snapmirror->{lag_time},
}
}
if (scalar(keys %{$self->{snapmirrors}}) <= 0) {
$self->{output}->add_option_msg(short_msg => "No entry found.");
$self->{output}->option_exit();
}
}
1;
__END__
=head1 MODE
Check NetApp snap mirrors usage.
=over 8
=item B<--filter-name>
Filter snapmirror name (can be a regexp).
=item B<--warning-*>
Threshold warning.
Can be: 'last-transfer-duration', 'last-transfer-size', 'lag-time'.
=item B<--critical-*>
Threshold critical.
Can be: 'last-transfer-duration', 'last-transfer-size', 'lag-time'.
=back
=cut

View File

@ -0,0 +1,225 @@
#
# Copyright 2018 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::netapp::restapi::mode::volumeio;
use base qw(centreon::plugins::templates::counter);
use strict;
use warnings;
sub prefix_output {
my ($self, %options) = @_;
return "Volume '" . $options{instance_value}->{name} . "' ";
}
sub set_counters {
my ($self, %options) = @_;
$self->{maps_counters_type} = [
{ name => 'volumes', type => 1, cb_prefix_output => 'prefix_output', message_multiple => 'All volumes IOs are ok' },
];
$self->{maps_counters}->{volumes} = [
{ label => 'read-iops', set => {
key_values => [ { name => 'read_ops' }, { name => 'name' } ],
output_template => 'Read IOPS: %.2f ops/s',
perfdatas => [
{ label => 'read_iops', value => 'read_ops_absolute', template => '%.2f',
min => 0, unit => 'ops/s', label_extra_instance => 1, instance_use => 'name_absolute' },
],
}
},
{ label => 'write-iops', set => {
key_values => [ { name => 'write_ops' }, { name => 'name' } ],
output_template => 'Write IOPS: %.2f ops/s',
perfdatas => [
{ label => 'write_iops', value => 'write_ops_absolute', template => '%.2f',
min => 0, unit => 'ops/s', label_extra_instance => 1, instance_use => 'name_absolute' },
],
}
},
{ label => 'other-iops', set => {
key_values => [ { name => 'other_ops' }, { name => 'name' } ],
output_template => 'Other IOPS: %.2f ops/s',
perfdatas => [
{ label => 'other_iops', value => 'other_ops_absolute', template => '%.2f',
min => 0, unit => 'ops/s', label_extra_instance => 1, instance_use => 'name_absolute' },
],
}
},
{ label => 'avg-latency', set => {
key_values => [ { name => 'avg_latency' }, { name => 'name' } ],
output_template => 'Average latency: %.2f ms',
perfdatas => [
{ label => 'avg_latency', value => 'avg_latency_absolute', template => '%.2f',
min => 0, unit => 'ms', label_extra_instance => 1, instance_use => 'name_absolute' },
],
}
},
{ label => 'read-latency', set => {
key_values => [ { name => 'read_latency' }, { name => 'name' } ],
output_template => 'Read latency: %.2f ms',
perfdatas => [
{ label => 'read_latency', value => 'read_latency_absolute', template => '%.2f',
min => 0, unit => 'ms', label_extra_instance => 1, instance_use => 'name_absolute' },
],
}
},
{ label => 'write-latency', set => {
key_values => [ { name => 'write_latency' }, { name => 'name' } ],
output_template => 'Write latency: %.2f ms',
perfdatas => [
{ label => 'write_latency', value => 'write_latency_absolute', template => '%.2f',
min => 0, unit => 'ms', label_extra_instance => 1, instance_use => 'name_absolute' },
],
}
},
{ label => 'other-latency', set => {
key_values => [ { name => 'other_latency' }, { name => 'name' } ],
output_template => 'Other latency: %.2f ms',
perfdatas => [
{ label => 'other_latency', value => 'other_latency_absolute', template => '%.2f',
min => 0, unit => 'ms', label_extra_instance => 1, instance_use => 'name_absolute' },
],
}
},
];
}
sub new {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options);
bless $self, $class;
$self->{version} = '1.0';
$options{options}->add_options(arguments =>
{
"filter-name:s" => { name => 'filter_name' },
"filter-state:s" => { name => 'filter_state' },
"filter-style:s" => { name => 'filter_style' },
"filter-type:s" => { name => 'filter_type' },
});
return $self;
}
sub check_options {
my ($self, %options) = @_;
$self->SUPER::check_options(%options);
}
sub manage_selection {
my ($self, %options) = @_;
my %names_hash;
my $names = $options{custom}->get(path => '/volumes');
foreach my $volume (@{$names}) {
$names_hash{$volume->{key}} = {
name => $volume->{name},
state => $volume->{state},
style => $volume->{style},
vol_type => $volume->{vol_type},
};
}
my $args = '';
my $append = '';
foreach my $metric ('read_ops', 'write_ops', 'other_ops', 'avg_latency', 'read_latency', 'write_latency', 'other_latency') {
$args .= $append . 'name=' . $metric;
$append = '&';
}
my $result = $options{custom}->get(path => '/volumes/metrics', args => $args);
foreach my $volume (@{$result}) {
if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' &&
defined($names_hash{$volume->{resource_key}}) && $names_hash{$volume->{resource_key}}->{name} !~ /$self->{option_results}->{filter_name}/) {
$self->{output}->output_add(long_msg => "skipping '" . $names_hash{$volume->{resource_key}}->{name} . "': no matching filter name.", debug => 1);
next;
}
if (defined($self->{option_results}->{filter_state}) && $self->{option_results}->{filter_state} ne '' &&
defined($names_hash{$volume->{resource_key}}) && $names_hash{$volume->{resource_key}}->{state} !~ /$self->{option_results}->{filter_state}/) {
$self->{output}->output_add(long_msg => "skipping '" . $names_hash{$volume->{resource_key}}->{name} . "': no matching filter state : '" . $names_hash{$volume->{resource_key}}->{state} . "'", debug => 1);
next;
}
if (defined($self->{option_results}->{filter_style}) && $self->{option_results}->{filter_style} ne '' &&
defined($names_hash{$volume->{resource_key}}) && $names_hash{$volume->{resource_key}}->{style} !~ /$self->{option_results}->{filter_style}/) {
$self->{output}->output_add(long_msg => "skipping '" . $names_hash{$volume->{resource_key}}->{name} . "': no matching filter style : '" . $names_hash{$volume->{resource_key}}->{style} . "'", debug => 1);
next;
}
if (defined($self->{option_results}->{filter_type}) && $self->{option_results}->{filter_type} ne '' &&
defined($names_hash{$volume->{resource_key}}) && $names_hash{$volume->{resource_key}}->{vol_type} !~ /$self->{option_results}->{filter_type}/) {
$self->{output}->output_add(long_msg => "skipping '" . $names_hash{$volume->{resource_key}}->{name} . "': no matching filter type : '" . $names_hash{$volume->{resource_key}}->{vol_type} . "'", debug => 1);
next;
}
foreach my $metric (@{$volume->{metrics}}) {
$self->{volumes}->{$volume->{resource_key}}->{name} = $names_hash{$volume->{resource_key}}->{name};
$self->{volumes}->{$volume->{resource_key}}->{read_ops} = ${$metric->{samples}}[0]->{value} if ($metric->{name} eq 'read_ops');
$self->{volumes}->{$volume->{resource_key}}->{write_ops} = ${$metric->{samples}}[0]->{value} if ($metric->{name} eq 'write_ops');
$self->{volumes}->{$volume->{resource_key}}->{other_ops} = ${$metric->{samples}}[0]->{value} if ($metric->{name} eq 'other_ops');
$self->{volumes}->{$volume->{resource_key}}->{avg_latency} = ${$metric->{samples}}[0]->{value} / 1000 if ($metric->{name} eq 'avg_latency');
$self->{volumes}->{$volume->{resource_key}}->{read_latency} = ${$metric->{samples}}[0]->{value} / 1000 if ($metric->{name} eq 'read_latency');
$self->{volumes}->{$volume->{resource_key}}->{write_latency} = ${$metric->{samples}}[0]->{value} / 1000 if ($metric->{name} eq 'write_latency');
$self->{volumes}->{$volume->{resource_key}}->{other_latency} = ${$metric->{samples}}[0]->{value} / 1000 if ($metric->{name} eq 'other_latency');
}
}
if (scalar(keys %{$self->{volumes}}) <= 0) {
$self->{output}->add_option_msg(short_msg => "No entry found.");
$self->{output}->option_exit();
}
}
1;
__END__
=head1 MODE
Check NetApp volumes IOs.
=over 8
=item B<--filter-*>
Filter volume.
Can be: 'name', 'state', 'style', 'type' (can be a regexp).
=item B<--warning-*>
Threshold warning.
Can be: 'read-iops', 'write-iops', 'other-iops',
'avg-latency', 'read-latency', 'write-latency', 'other-latency'.
=item B<--critical-*>
Threshold critical.
Can be: 'read-iops', 'write-iops', 'other-iops',
'avg-latency', 'read-latency', 'write-latency', 'other-latency'.
=back
=cut

View File

@ -0,0 +1,180 @@
#
# Copyright 2018 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::netapp::restapi::mode::volumestatus;
use base qw(centreon::plugins::templates::counter);
use strict;
use warnings;
my $instance_mode;
sub custom_status_threshold {
my ($self, %options) = @_;
my $status = 'ok';
my $message;
eval {
local $SIG{__WARN__} = sub { $message = $_[0]; };
local $SIG{__DIE__} = sub { $message = $_[0]; };
if (defined($instance_mode->{option_results}->{critical_status}) && $instance_mode->{option_results}->{critical_status} ne '' &&
eval "$instance_mode->{option_results}->{critical_status}") {
$status = 'critical';
} elsif (defined($instance_mode->{option_results}->{warning_status}) && $instance_mode->{option_results}->{warning_status} ne '' &&
eval "$instance_mode->{option_results}->{warning_status}") {
$status = 'warning';
}
};
if (defined($message)) {
$self->{output}->output_add(long_msg => 'filter status issue: ' . $message);
}
return $status;
}
sub custom_status_output {
my ($self, %options) = @_;
my $msg = sprintf("State is '%s'",
$self->{result_values}->{state}, $self->{result_values}->{mirror_status});
return $msg;
}
sub custom_status_calc {
my ($self, %options) = @_;
$self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_name'};
$self->{result_values}->{state} = $options{new_datas}->{$self->{instance} . '_state'};
return 0;
}
sub prefix_output {
my ($self, %options) = @_;
return "Volume '" . $options{instance_value}->{name} . "' ";
}
sub set_counters {
my ($self, %options) = @_;
$self->{maps_counters_type} = [
{ name => 'volumes', type => 1, cb_prefix_output => 'prefix_output', message_multiple => 'All volumes status are ok' },
];
$self->{maps_counters}->{volumes} = [
{ label => 'status', set => {
key_values => [ { name => 'state' }, { name => 'name' } ],
closure_custom_calc => $self->can('custom_status_calc'),
closure_custom_output => $self->can('custom_status_output'),
closure_custom_perfdata => sub { return 0; },
closure_custom_threshold_check => $self->can('custom_status_threshold'),
}
},
];
}
sub new {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options);
bless $self, $class;
$self->{version} = '1.0';
$options{options}->add_options(arguments =>
{
"filter-name:s" => { name => 'filter_name' },
"warning-status:s" => { name => 'warning_status' },
"critical-status:s" => { name => 'critical_status', default => '%{state} !~ /online/i' },
});
return $self;
}
sub change_macros {
my ($self, %options) = @_;
foreach ('warning_status', 'critical_status') {
if (defined($self->{option_results}->{$_})) {
$self->{option_results}->{$_} =~ s/%\{(.*?)\}/\$self->{result_values}->{$1}/g;
}
}
}
sub check_options {
my ($self, %options) = @_;
$self->SUPER::check_options(%options);
$instance_mode = $self;
$self->change_macros();
}
sub manage_selection {
my ($self, %options) = @_;
my $result = $options{custom}->get(path => '/volumes');
foreach my $volume (@{$result}) {
if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' &&
$volume->{name} !~ /$self->{option_results}->{filter_name}/) {
$self->{output}->output_add(long_msg => "skipping '" . $volume->{name} . "': no matching filter name.", debug => 1);
next;
}
$self->{volumes}->{$volume->{key}} = {
name => $volume->{name},
state => $volume->{state},
}
}
if (scalar(keys %{$self->{volumes}}) <= 0) {
$self->{output}->add_option_msg(short_msg => "No entry found.");
$self->{output}->option_exit();
}
}
1;
__END__
=head1 MODE
Check NetApp volumes status.
=over 8
=item B<--filter-name>
Filter volume name (can be a regexp).
=item B<--warning-status>
Set warning threshold for status (Default: '').
Can used special variables like: %{state}
=item B<--critical-status>
Set critical threshold for status (Default: '%{state} !~ /online/i').
Can used special variables like: %{state}
=back
=cut

View File

@ -0,0 +1,487 @@
#
# Copyright 2018 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::netapp::restapi::mode::volumeusage;
use base qw(centreon::plugins::templates::counter);
use strict;
use warnings;
my $instance_mode;
sub custom_usage_perfdata {
my ($self, %options) = @_;
my $extra_label = '';
$extra_label = '_' . $self->{result_values}->{display} if (!defined($options{extra_instance}) || $options{extra_instance} != 0);
$self->{output}->perfdata_add(label => 'used' . $extra_label,
unit => 'B',
value => $self->{result_values}->{used},
warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{label}, total => $self->{result_values}->{total}, cast_int => 1),
critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{label}, total => $self->{result_values}->{total}, cast_int => 1),
min => 0, max => $self->{result_values}->{total});
}
sub custom_usage_threshold {
my ($self, %options) = @_;
my ($exit, $threshold_value);
$threshold_value = $self->{result_values}->{used};
$threshold_value = $self->{result_values}->{free} if (defined($instance_mode->{option_results}->{free}));
if ($instance_mode->{option_results}->{units} eq '%') {
$threshold_value = $self->{result_values}->{prct_used};
$threshold_value = $self->{result_values}->{prct_free} if (defined($instance_mode->{option_results}->{free}));
}
$exit = $self->{perfdata}->threshold_check(value => $threshold_value,
threshold => [ { label => 'critical-' . $self->{label}, exit_litteral => 'critical' },
{ label => 'warning-' . $self->{label}, exit_litteral => 'warning' } ]);
return $exit;
}
sub custom_usage_output {
my ($self, %options) = @_;
my ($used_value, $used_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{used});
my ($free_value, $free_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{free});
my ($total_value, $total_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{total});
my $msg = sprintf("Total: %s Used: %s (%.2f%%) Free: %s (%.2f%%)",
$total_value . " " . $total_unit,
$used_value . " " . $used_unit, $self->{result_values}->{prct_used},
$free_value . " " . $free_unit, $self->{result_values}->{prct_free});
return $msg;
}
sub custom_usage_calc {
my ($self, %options) = @_;
$self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_name'};
$self->{result_values}->{total} = $options{new_datas}->{$self->{instance} . '_size_total'};
$self->{result_values}->{used} = $options{new_datas}->{$self->{instance} . '_size_used'};
if ($self->{result_values}->{total} != 0) {
$self->{result_values}->{free} = $self->{result_values}->{total} - $self->{result_values}->{used};
$self->{result_values}->{prct_used} = $self->{result_values}->{used} * 100 / $self->{result_values}->{total};
$self->{result_values}->{prct_free} = 100 - $self->{result_values}->{prct_used};
} else {
$self->{result_values}->{free} = '0';
$self->{result_values}->{prct_used} = '0';
$self->{result_values}->{prct_free} = '0';
}
return 0;
}
sub custom_inode_perfdata {
my ($self, %options) = @_;
my $extra_label = '';
$extra_label = '_' . $self->{result_values}->{display} if (!defined($options{extra_instance}) || $options{extra_instance} != 0);
$self->{output}->perfdata_add(label => 'inodes' . $extra_label,
unit => '%',
value => sprintf("%.2f", $self->{result_values}->{prct_used}),
warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{label}),
critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{label}),
min => 0, max => 100);
}
sub custom_inode_threshold {
my ($self, %options) = @_;
my $exit = $self->{perfdata}->threshold_check(value => $self->{result_values}->{prct_used},
threshold => [ { label => 'critical-' . $self->{label}, exit_litteral => 'critical' },
{ label => 'warning-' . $self->{label}, exit_litteral => 'warning' } ]);
return $exit;
}
sub custom_inode_output {
my ($self, %options) = @_;
my $msg = sprintf("Inodes Used: %.2f%%", $self->{result_values}->{prct_used});
return $msg;
}
sub custom_inode_calc {
my ($self, %options) = @_;
$self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_name'};
$self->{result_values}->{used} = $options{new_datas}->{$self->{instance} . '_inode_files_used'};
$self->{result_values}->{total} = $options{new_datas}->{$self->{instance} . '_inode_files_total'};
if ($self->{result_values}->{total} != 0) {
$self->{result_values}->{prct_used} = $self->{result_values}->{used} * 100 / $self->{result_values}->{total};
} else {
$self->{result_values}->{prct_used} = '0';
}
return 0;
}
sub custom_snapshot_perfdata {
my ($self, %options) = @_;
my $extra_label = '';
$extra_label = '_' . $self->{result_values}->{display} if (!defined($options{extra_instance}) || $options{extra_instance} != 0);
$self->{output}->perfdata_add(label => 'snapshot' . $extra_label,
unit => 'B',
value => $self->{result_values}->{used},
warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{label}, total => $self->{result_values}->{total}, cast_int => 1),
critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{label}, total => $self->{result_values}->{total}, cast_int => 1),
min => 0, max => $self->{result_values}->{total});
}
sub custom_snapshot_threshold {
my ($self, %options) = @_;
my ($exit, $threshold_value);
$threshold_value = $self->{result_values}->{used};
$threshold_value = $self->{result_values}->{free} if (defined($instance_mode->{option_results}->{free}));
if ($instance_mode->{option_results}->{units} eq '%') {
$threshold_value = $self->{result_values}->{prct_used};
$threshold_value = $self->{result_values}->{prct_free} if (defined($instance_mode->{option_results}->{free}));
}
$exit = $self->{perfdata}->threshold_check(value => $threshold_value,
threshold => [ { label => 'critical-' . $self->{label}, exit_litteral => 'critical' },
{ label => 'warning-' . $self->{label}, exit_litteral => 'warning' } ]);
return $exit;
}
sub custom_snapshot_output {
my ($self, %options) = @_;
my ($used_value, $used_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{used});
my ($free_value, $free_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{free});
my ($reserved_value, $reserved_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{reserved});
my $msg = sprintf("Snapshot Used: %s (%.2f%%) Free: %s (%.2f%%) Reserved: %s",
$used_value . " " . $used_unit, $self->{result_values}->{prct_used},
$free_value . " " . $free_unit, $self->{result_values}->{prct_free},
$reserved_value . " " . $reserved_unit);
return $msg;
}
sub custom_snapshot_calc {
my ($self, %options) = @_;
$self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_name'};
$self->{result_values}->{free} = $options{new_datas}->{$self->{instance} . '_size_available_for_snapshot'};
$self->{result_values}->{used} = $options{new_datas}->{$self->{instance} . '_size_used_by_snapshots'};
$self->{result_values}->{reserved} = $options{new_datas}->{$self->{instance} . '_snapshot_reserve_size'};
$self->{result_values}->{total} = $self->{result_values}->{used} + $self->{result_values}->{free};
$self->{result_values}->{prct_used} = $self->{result_values}->{used} * 100 / $self->{result_values}->{total};
$self->{result_values}->{prct_free} = 100 - $self->{result_values}->{prct_used};
return 0;
}
sub custom_compression_perfdata {
my ($self, %options) = @_;
my $extra_label = '';
$extra_label = '_' . $self->{result_values}->{display} if (!defined($options{extra_instance}) || $options{extra_instance} != 0);
$self->{output}->perfdata_add(label => 'compresssaved' . $extra_label,
unit => 'B',
value => $self->{result_values}->{used},
warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{label}, total => $self->{result_values}->{total}, cast_int => 1),
critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{label}, total => $self->{result_values}->{total}, cast_int => 1),
min => 0, max => $self->{result_values}->{total});
}
sub custom_compression_threshold {
my ($self, %options) = @_;
my ($exit, $threshold_value);
$threshold_value = $self->{result_values}->{used};
$threshold_value = $self->{result_values}->{free} if (defined($instance_mode->{option_results}->{free}));
if ($instance_mode->{option_results}->{units} eq '%') {
$threshold_value = $self->{result_values}->{prct_used};
$threshold_value = $self->{result_values}->{prct_free} if (defined($instance_mode->{option_results}->{free}));
}
$exit = $self->{perfdata}->threshold_check(value => $threshold_value,
threshold => [ { label => 'critical-' . $self->{label}, exit_litteral => 'critical' },
{ label => 'warning-' . $self->{label}, exit_litteral => 'warning' } ]);
return $exit;
}
sub custom_compression_output {
my ($self, %options) = @_;
my ($used_value, $used_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{used});
my $msg = sprintf("Compression Space Saved: %s (%.2f%%)",
$used_value . " " . $used_unit, $self->{result_values}->{prct_used});
return $msg;
}
sub custom_compression_calc {
my ($self, %options) = @_;
$self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_name'};
$self->{result_values}->{total} = $options{new_datas}->{$self->{instance} . '_size_total'};
$self->{result_values}->{used} = $options{new_datas}->{$self->{instance} . '_compression_space_saved'};
if ($self->{result_values}->{total} != 0) {
$self->{result_values}->{free} = $self->{result_values}->{total} - $self->{result_values}->{used};
$self->{result_values}->{prct_used} = $self->{result_values}->{used} * 100 / $self->{result_values}->{total};
$self->{result_values}->{prct_free} = 100 - $self->{result_values}->{prct_used};
} else {
$self->{result_values}->{free} = '0';
$self->{result_values}->{prct_used} = '0';
$self->{result_values}->{prct_free} = '0';
}
return 0;
}
sub custom_deduplication_perfdata {
my ($self, %options) = @_;
my $extra_label = '';
$extra_label = '_' . $self->{result_values}->{display} if (!defined($options{extra_instance}) || $options{extra_instance} != 0);
$self->{output}->perfdata_add(label => 'dedupsaved' . $extra_label,
unit => 'B',
value => $self->{result_values}->{used},
warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{label}, total => $self->{result_values}->{total}, cast_int => 1),
critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{label}, total => $self->{result_values}->{total}, cast_int => 1),
min => 0, max => $self->{result_values}->{total});
}
sub custom_deduplicationn_threshold {
my ($self, %options) = @_;
my ($exit, $threshold_value);
$threshold_value = $self->{result_values}->{used};
$threshold_value = $self->{result_values}->{free} if (defined($instance_mode->{option_results}->{free}));
if ($instance_mode->{option_results}->{units} eq '%') {
$threshold_value = $self->{result_values}->{prct_used};
$threshold_value = $self->{result_values}->{prct_free} if (defined($instance_mode->{option_results}->{free}));
}
$exit = $self->{perfdata}->threshold_check(value => $threshold_value,
threshold => [ { label => 'critical-' . $self->{label}, exit_litteral => 'critical' },
{ label => 'warning-' . $self->{label}, exit_litteral => 'warning' } ]);
return $exit;
}
sub custom_deduplication_output {
my ($self, %options) = @_;
my ($used_value, $used_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{used});
my $msg = sprintf("Deduplication Space Saved: %s (%.2f%%)",
$used_value . " " . $used_unit, $self->{result_values}->{prct_used});
return $msg;
}
sub custom_deduplication_calc {
my ($self, %options) = @_;
$self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_name'};
$self->{result_values}->{total} = $options{new_datas}->{$self->{instance} . '_size_total'};
$self->{result_values}->{used} = $options{new_datas}->{$self->{instance} . '_deduplication_space_saved'};
if ($self->{result_values}->{total} != 0) {
$self->{result_values}->{free} = $self->{result_values}->{total} - $self->{result_values}->{used};
$self->{result_values}->{prct_used} = $self->{result_values}->{used} * 100 / $self->{result_values}->{total};
$self->{result_values}->{prct_free} = 100 - $self->{result_values}->{prct_used};
} else {
$self->{result_values}->{free} = '0';
$self->{result_values}->{prct_used} = '0';
$self->{result_values}->{prct_free} = '0';
}
return 0;
}
sub prefix_output {
my ($self, %options) = @_;
return "Volume '" . $options{instance_value}->{name} . "' ";
}
sub set_counters {
my ($self, %options) = @_;
$self->{maps_counters_type} = [
{ name => 'volumes', type => 1, cb_prefix_output => 'prefix_output', message_multiple => 'All volumes usage are ok' },
];
$self->{maps_counters}->{volumes} = [
{ label => 'usage', set => {
key_values => [ { name => 'size_used' }, { name => 'size_total' }, { name => 'name' } ],
closure_custom_calc => $self->can('custom_usage_calc'),
closure_custom_output => $self->can('custom_usage_output'),
closure_custom_perfdata => $self->can('custom_usage_perfdata'),
closure_custom_threshold_check => $self->can('custom_usage_threshold'),
}
},
{ label => 'inodes', set => {
key_values => [ { name => 'inode_files_used' }, { name => 'inode_files_total' }, { name => 'name' } ],
closure_custom_calc => $self->can('custom_inode_calc'),
closure_custom_output => $self->can('custom_inode_output'),
closure_custom_perfdata => $self->can('custom_inode_perfdata'),
closure_custom_threshold_check => $self->can('custom_inode_threshold'),
}
},
{ label => 'snapshot', set => {
key_values => [ { name => 'size_available_for_snapshot' }, { name => 'size_used_by_snapshots' }, { name => 'snapshot_reserve_size' }, { name => 'name' } ],
closure_custom_calc => $self->can('custom_snapshot_calc'),
closure_custom_output => $self->can('custom_snapshot_output'),
closure_custom_perfdata => $self->can('custom_snapshot_perfdata'),
closure_custom_threshold_check => $self->can('custom_snapshot_threshold'),
}
},
{ label => 'compresssaved', set => {
key_values => [ { name => 'compression_space_saved' }, { name => 'size_total' }, { name => 'name' } ],
closure_custom_calc => $self->can('custom_compression_calc'),
closure_custom_output => $self->can('custom_compression_output'),
closure_custom_perfdata => $self->can('custom_compression_perfdata'),
closure_custom_threshold_check => $self->can('custom_compression_threshold'),
}
},
{ label => 'dedupsaved', set => {
key_values => [ { name => 'deduplication_space_saved' }, { name => 'size_total' }, { name => 'name' } ],
closure_custom_calc => $self->can('custom_deduplication_calc'),
closure_custom_output => $self->can('custom_deduplication_output'),
closure_custom_perfdata => $self->can('custom_deduplication_perfdata'),
closure_custom_threshold_check => $self->can('custom_deduplication_threshold'),
}
},
];
}
sub new {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options);
bless $self, $class;
$self->{version} = '1.0';
$options{options}->add_options(arguments =>
{
"filter-name:s" => { name => 'filter_name' },
"filter-state:s" => { name => 'filter_state' },
"filter-style:s" => { name => 'filter_style' },
"filter-type:s" => { name => 'filter_type' },
"units:s" => { name => 'units', default => '%' },
"free" => { name => 'free' },
});
return $self;
}
sub check_options {
my ($self, %options) = @_;
$self->SUPER::check_options(%options);
$instance_mode = $self;
}
sub manage_selection {
my ($self, %options) = @_;
my $result = $options{custom}->get(path => '/volumes');
foreach my $volume (@{$result}) {
if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' &&
$volume->{name} !~ /$self->{option_results}->{filter_name}/) {
$self->{output}->output_add(long_msg => "skipping '" . $volume->{name} . "': no matching filter name.", debug => 1);
next;
}
if (defined($self->{option_results}->{filter_state}) && $self->{option_results}->{filter_state} ne '' &&
$volume->{state} !~ /$self->{option_results}->{filter_state}/) {
$self->{output}->output_add(long_msg => "skipping '" . $volume->{name} . "': no matching filter state : '" . $volume->{state} . "'", debug => 1);
next;
}
if (defined($self->{option_results}->{filter_style}) && $self->{option_results}->{filter_style} ne '' &&
$volume->{style} !~ /$self->{option_results}->{filter_style}/) {
$self->{output}->output_add(long_msg => "skipping '" . $volume->{name} . "': no matching filter style : '" . $volume->{style} . "'", debug => 1);
next;
}
if (defined($self->{option_results}->{filter_type}) && $self->{option_results}->{filter_type} ne '' &&
$volume->{vol_type} !~ /$self->{option_results}->{filter_type}/) {
$self->{output}->output_add(long_msg => "skipping '" . $volume->{name} . "': no matching filter type : '" . $volume->{vol_type} . "'", debug => 1);
next;
}
$self->{volumes}->{$volume->{key}} = {
name => $volume->{name},
size_total => $volume->{size_total},
size_used => $volume->{size_used},
compression_space_saved => $volume->{compression_space_saved},
deduplication_space_saved => $volume->{deduplication_space_saved},
size_available_for_snapshot => $volume->{size_available_for_snapshot},
size_used_by_snapshots => $volume->{size_used_by_snapshots},
snapshot_reserve_size => $volume->{snapshot_reserve_size},
inode_files_used => $volume->{inode_files_used},
inode_files_total => $volume->{inode_files_total},
}
}
if (scalar(keys %{$self->{volumes}}) <= 0) {
$self->{output}->add_option_msg(short_msg => "No entry found.");
$self->{output}->option_exit();
}
}
1;
__END__
=head1 MODE
Check NetApp volumes usage (space, inodes, snapshot, compression and deduplication)
=over 8
=item B<--filter-*>
Filter volume.
Can be: 'name', 'state', 'style', 'type' (can be a regexp).
=item B<--warning-*>
Threshold warning.
Can be: 'usage', 'inodes', 'snapshot', 'compresssaved', 'dedupsaved'.
=item B<--critical-*>
Threshold critical.
Can be: 'usage', 'inodes', 'snapshot', 'compresssaved', 'dedupsaved'.
=item B<--units>
Units of thresholds (Default: '%') ('%', 'B').
=item B<--free>
Thresholds are on free space left.
=back
=cut

View File

@ -0,0 +1,74 @@
#
# Copyright 2018 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::netapp::restapi::plugin;
use strict;
use warnings;
use base qw(centreon::plugins::script_custom);
sub new {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options);
bless $self, $class;
$self->{version} = '1.0';
%{$self->{modes}} = (
'aggregate-raid-status' => 'storage::netapp::restapi::mode::aggregateraidstatus',
'aggregate-status' => 'storage::netapp::restapi::mode::aggregatestatus',
'aggregate-usage' => 'storage::netapp::restapi::mode::aggregateusage',
'cluster-io' => 'storage::netapp::restapi::mode::clusterio',
'cluster-status' => 'storage::netapp::restapi::mode::clusterstatus',
'cluster-usage' => 'storage::netapp::restapi::mode::clusterusage',
'disk-failed' => 'storage::netapp::restapi::mode::diskfailed',
'disk-spare' => 'storage::netapp::restapi::mode::diskspare',
'fc-port-status' => 'storage::netapp::restapi::mode::fcportstatus',
'list-aggregates' => 'storage::netapp::restapi::mode::listaggregates',
'list-clusters' => 'storage::netapp::restapi::mode::listclusters',
'list-fc-ports' => 'storage::netapp::restapi::mode::listfcports',
'list-luns' => 'storage::netapp::restapi::mode::listluns',
'list-nodes' => 'storage::netapp::restapi::mode::listnodes',
'list-snapmirrors' => 'storage::netapp::restapi::mode::listsnapmirrors',
'list-volumes' => 'storage::netapp::restapi::mode::listvolumes',
'lun-alignment' => 'storage::netapp::restapi::mode::lunalignment',
'lun-online' => 'storage::netapp::restapi::mode::lunonline',
'lun-usage' => 'storage::netapp::restapi::mode::lunusage',
'node-failover-status' => 'storage::netapp::restapi::mode::nodefailoverstatus',
'node-hardware-status' => 'storage::netapp::restapi::mode::nodehardwarestatus',
'qtree-status' => 'storage::netapp::restapi::mode::qtreestatus',
'snapmirror-status' => 'storage::netapp::restapi::mode::snapmirrorstatus',
'snapmirror-usage' => 'storage::netapp::restapi::mode::snapmirrorusage',
'volume-io' => 'storage::netapp::restapi::mode::volumeio',
'volume-status' => 'storage::netapp::restapi::mode::volumestatus',
'volume-usage' => 'storage::netapp::restapi::mode::volumeusage',
);
$self->{custom_modes}{api} = 'storage::netapp::restapi::custom::restapi';
return $self;
}
1;
__END__
=head1 PLUGIN DESCRIPTION
Check NetApp with OnCommand API.
=cut