enh(hp/p2000): missing entries and add psu component in health mode + add cpu metric for controllers + add ntp mode (#3019)

This commit is contained in:
qgarnier 2021-08-05 10:46:01 +02:00 committed by GitHub
parent 0867de9366
commit de441cd5bf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 352 additions and 26 deletions

View File

@ -29,7 +29,7 @@ sub check {
$self->{output}->output_add(long_msg => "Checking frus");
$self->{components}->{fru} = {name => 'frus', total => 0, skip => 0};
return if ($self->check_filter(section => 'fru'));
my ($entries) = $self->{custom}->get_infos(
cmd => 'show frus',
base_type => 'enclosure-fru',
@ -44,14 +44,13 @@ sub check {
if (defined($results->{$name})) {
$duplicated->{$name} = 1;
my $instance = $results->{$name}->{'fru-location'} . ':' . $results->{$name}->{oid};
$results->{$instance} = $results->{$name};
delete $results->{$name};
$results->{$instance} = delete $results->{$name};
$name = $_->{'fru-location'} . ':' . $_->{oid};
}
$results->{$name} = $_;
}
foreach my $instance (keys %$results) {
foreach my $instance (sort keys %$results) {
next if ($self->check_filter(section => 'fru', instance => $instance));
$self->{components}->{fru}->{total}++;

View File

@ -0,0 +1,83 @@
#
# Copyright 2021 Centreon (http://www.centreon.com/)
#
# Centreon is a full-fledged industry-strength solution that meets
# the needs in IT infrastructure and application monitoring for
# service performance.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
package storage::hp::p2000::xmlapi::mode::components::psu;
use strict;
use warnings;
my %health = (
0 => 'ok',
1 => 'degraded',
2 => 'fault',
3 => 'unknown',
4 => 'not available'
);
sub check {
my ($self) = @_;
$self->{output}->output_add(long_msg => "Checking power supplies");
$self->{components}->{psu} = { name => 'psu', total => 0, skip => 0 };
return if ($self->check_filter(section => 'psu'));
my ($entries) = $self->{custom}->get_infos(
cmd => 'show power-supplies',
base_type => 'power-supplies',
properties_name => '^durable-id|health-numeric|name$',
no_quit => 1
);
my ($results, $duplicated) = ({}, {});
foreach (@$entries) {
my $name = $_->{name};
$name = $_->{name} . ':' . $_->{'durable-id'} if (defined($duplicated->{$name}));
if (defined($results->{$name})) {
$duplicated->{$name} = 1;
my $instance = $results->{$name}->{name} . ':' . $results->{$name}->{'durable-id'};
$results->{$instance} = delete $results->{$name};
$name = $_->{name} . ':' . $_->{'durable-id'};
}
$results->{$name} = $_;
}
foreach my $psu_id (sort keys %$results) {
next if ($self->check_filter(section => 'psu', instance => $results->{$psu_id}->{'durable-id'}));
$self->{components}->{psu}->{total}++;
my $state = $health{$results->{$psu_id}->{'health-numeric'}};
$self->{output}->output_add(
long_msg => sprintf(
"power supply '%s' status is %s [instance: %s]",
$psu_id, $state, $results->{$psu_id}->{'durable-id'}
)
);
my $exit = $self->get_severity(label => 'default', section => 'psu', value => $state);
if (!$self->{output}->is_status(value => $exit, compare => 'ok', litteral => 1)) {
$self->{output}->output_add(
severity => $exit,
short_msg => sprintf("Power supply '%s' status is '%s'", $psu_id, $state)
);
}
}
}
1;

View File

@ -27,13 +27,13 @@ my %sensor_type = (
# 2 it's other. Can be ok or '%'. Need to regexp
3 => { unit => 'C', nunit => 'celsius', type => 'temperature' },
6 => { unit => 'V', nunit => 'volt', type => 'voltage' },
9 => { unit => 'V', nunit => 'volt', type => 'voltage' },
9 => { unit => 'V', nunit => 'volt', type => 'voltage' }
);
my %units = (
C => { long => 'celsius', type => 'temperature' },
V => { long => 'volt', type => 'voltage' },
'' => { long => undef, type => 'misc' },
'%' => { long => 'percentage', type => 'misc' },
'%' => { long => 'percentage', type => 'misc' }
);
sub check {
@ -42,15 +42,27 @@ sub check {
$self->{output}->output_add(long_msg => "Checking sensor");
$self->{components}->{sensor} = {name => 'sensor', total => 0, skip => 0};
return if ($self->check_filter(section => 'sensor'));
# We don't use status-numeric. Values are buggy !!!???
my ($results) = $self->{custom}->get_infos(
my ($entries) = $self->{custom}->get_infos(
cmd => 'show sensor-status',
base_type => 'sensors',
key => 'sensor-name',
properties_name => '^(?:value|sensor-type|status)$'
properties_name => '^(?:sensor-name|value|sensor-type|status|enclosure-id)$'
);
my ($results, $duplicated) = ({}, {});
foreach (@$entries) {
my $name = $_->{'sensor-name'};
$name = $_->{'sensor-name'} . ':' . $_->{'enclosure-id'} if (defined($duplicated->{$name}));
if (defined($results->{$name})) {
$duplicated->{$name} = 1;
my $instance = $results->{$name}->{'sensor-name'} . ':' . $results->{$name}->{'enclosure-id'};
$results->{$instance} = delete $results->{$name};
$name = $_->{'sensor-name'} . ':' . $_->{'enclosure-id'};
}
$results->{$name} = $_;
}
#<OBJECT basetype="sensors" name="sensor" oid="22" format="rows">
# <PROPERTY name="sensor-name" key="true" type="string" size="33" draw="true" sort="string" display-name="Sensor Name">Capacitor Charge-Ctlr B</PROPERTY>
# <PROPERTY name="value" type="string" size="8" draw="true" sort="string" display-name="Value">100%</PROPERTY>
@ -61,7 +73,7 @@ sub check {
# <PROPERTY name="value" type="string" size="8" draw="true" sort="string" display-name="Value">Warning</PROPERTY>
# <PROPERTY name="status" type="string" size="8" draw="true" sort="string" display-name="Status">Warning</PROPERTY>
#</OBJECT>
foreach my $sensor_id (keys %$results) {
foreach my $sensor_id (sort keys %$results) {
my ($value, $unit) = (undef, '');;
($value, $unit) = ($1, $2) if ($results->{$sensor_id}->{value} =~ /\s*([0-9\.,]+)\s*(\S*)\s*/);
if (defined($results->{$sensor_id}->{'sensor-type'}) && defined($sensor_type{$results->{$sensor_id}->{'sensor-type'}})) {
@ -71,24 +83,31 @@ sub check {
next if ($self->check_filter(section => 'sensor', instance => $type . '.' . $sensor_id));
$self->{components}->{sensor}->{total}++;
my $state = $results->{$sensor_id}->{status};
$self->{output}->output_add(long_msg => sprintf("sensor '%s' status is %s (value: %s %s)",
$sensor_id, $state, defined($value) ? $value : '-', defined($unit) ? $unit : '-')
);
$self->{output}->output_add(
long_msg => sprintf(
"sensor '%s' status is %s (value: %s %s)",
$sensor_id, $state, defined($value) ? $value : '-', defined($unit) ? $unit : '-'
)
);
my $exit = $self->get_severity(section => 'sensor', value => $state);
if (!$self->{output}->is_status(value => $exit, compare => 'ok', litteral => 1)) {
$self->{output}->output_add(severity => $exit,
short_msg => sprintf("sensor '%s' status is '%s'", $sensor_id, $state));
$self->{output}->output_add(
severity => $exit,
short_msg => sprintf("sensor '%s' status is '%s'", $sensor_id, $state)
);
}
next if (!defined($value));
my ($exit2, $warn, $crit, $checked) = $self->get_severity_numeric(section => 'sensor', instance => $type . '.' . $sensor_id, value => $value);
if (!$self->{output}->is_status(value => $exit2, compare => 'ok', litteral => 1)) {
$self->{output}->output_add(severity => $exit,
short_msg => sprintf("Sensor '%s' is %s %s", $sensor_id, $value, defined($unit) ? $unit : '-'));
$self->{output}->output_add(
severity => $exit,
short_msg => sprintf("Sensor '%s' is %s %s", $sensor_id, $value, defined($unit) ? $unit : '-')
);
}
$self->{output}->perfdata_add(

View File

@ -218,6 +218,14 @@ sub set_counters {
];
$self->{maps_counters}->{controller_stats} = [
{ label => 'cpu-utilization', nlabel => 'cpu.utilization.percentage', set => {
key_values => [ { name => 'cpu-load' } ],
output_template => 'cpu utilization: %.2f%%',
perfdatas => [
{ template => '%.2f', min => 0, max => 100, unit => '%', label_extra_instance => 1 }
]
}
},
{ label => 'read', nlabel => 'controller.io.read.usage.bytespersecond', set => {
key_values => [ { name => 'data-read-numeric', per_second => 1 } ],
output_template => 'read i/o: %s %s/s',
@ -353,7 +361,7 @@ sub manage_selection {
my ($stats) = $options{custom}->get_infos(
cmd => 'show controller-statistics',
base_type => 'controller-statistics',
properties_name => '^durable-id|data-read-numeric|data-written-numeric|write-cache-hits|write-cache-misses|read-cache-hits|read-cache-misses|iops$'
properties_name => '^durable-id|cpu-load|data-read-numeric|data-written-numeric|write-cache-hits|write-cache-misses|read-cache-hits|read-cache-misses|iops$'
);
foreach (@$stats) {
@ -459,7 +467,7 @@ Can used special variables like: %{status}, %{name}
=item B<--warning-*> B<--critical-*>
Thresholds.
Can be: 'read', 'write', 'iops', 'write-cache-hits', 'read-cache-hits'.
Can be: 'cpu-utilization', 'read', 'write', 'iops', 'write-cache-hits', 'read-cache-hits'.
=back

View File

@ -29,7 +29,7 @@ sub set_system {
my ($self, %options) = @_;
$self->{regexp_threshold_numeric_check_section_option} =
'^(sensor)$';
'^(?:sensor)$';
$self->{cb_hook1} = 'init_health';
@ -52,12 +52,12 @@ sub set_system {
['warning|not installed|unavailable', 'WARNING'],
['error|unrecoverable', 'CRITICAL'],
['unknown|unsupported', 'UNKNOWN']
],
]
};
$self->{components_exec_load} = 0;
$self->{components_path} = 'storage::hp::p2000::xmlapi::mode::components';
$self->{components_module} = ['disk', 'enclosure', 'fru', 'sensor', 'vdisk'];
$self->{components_module} = ['disk', 'enclosure', 'fru', 'psu', 'sensor', 'vdisk'];
}
sub init_health {
@ -90,7 +90,7 @@ Check health status of storage.
=item B<--component>
Which component to check (Default: '.*').
Can be: 'disk', 'enclosure', 'fru', 'sensor', 'vdisk'.
Can be: 'disk', 'enclosure', 'fru', 'psu', 'sensor', 'vdisk'.
=item B<--filter>

View File

@ -0,0 +1,216 @@
#
# Copyright 2021 Centreon (http://www.centreon.com/)
#
# Centreon is a full-fledged industry-strength solution that meets
# the needs in IT infrastructure and application monitoring for
# service performance.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
package storage::hp::p2000::xmlapi::mode::ntp;
use base qw(centreon::plugins::templates::counter);
use strict;
use warnings;
use centreon::plugins::misc;
use DateTime;
use POSIX;
use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold_ng);
my $unitdiv = { s => 1, w => 604800, d => 86400, h => 3600, m => 60 };
my $unitdiv_long = { s => 'seconds', w => 'weeks', d => 'days', h => 'hours', m => 'minutes' };
sub custom_contact_perfdata {
my ($self, %options) = @_;
$self->{output}->perfdata_add(
nlabel => $self->{nlabel} . '.' . $unitdiv_long->{ $self->{instance_mode}->{option_results}->{unit} },
unit => $self->{instance_mode}->{option_results}->{unit},
value => floor($self->{result_values}->{contact_seconds} / $unitdiv->{ $self->{instance_mode}->{option_results}->{unit} }),
warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{thlabel}),
critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{thlabel}),
min => 0
);
}
sub custom_contact_threshold {
my ($self, %options) = @_;
return $self->{perfdata}->threshold_check(
value => floor($self->{result_values}->{contact_seconds} / $unitdiv->{ $self->{instance_mode}->{option_results}->{unit} }),
threshold => [
{ label => 'critical-' . $self->{thlabel}, exit_litteral => 'critical' },
{ label => 'warning-'. $self->{thlabel}, exit_litteral => 'warning' },
{ label => 'unknown-'. $self->{thlabel}, exit_litteral => 'unknown' }
]
);
}
sub custom_status_output {
my ($self, %options) = @_;
return sprintf('status is %s', $self->{result_values}->{status});
}
sub license_long_output {
my ($self, %options) = @_;
return 'checking ntp';
}
sub set_counters {
my ($self, %options) = @_;
$self->{maps_counters_type} = [
{ name => 'ntp', type => 3, cb_long_output => 'ntp_long_output', indent_long_output => ' ',
group => [
{ name => 'status', type => 0, display_short => 0, skipped_code => { -10 => 1 } },
{ name => 'contact', type => 0, display_short => 0, skipped_code => { -10 => 1 } }
]
}
];
$self->{maps_counters}->{status} = [
{
label => 'status',
type => 2,
critical_default => '%{status} =~ /deactivated/i',
set => {
key_values => [ { name => 'status' } ],
closure_custom_output => $self->can('custom_status_output'),
closure_custom_perfdata => sub { return 0; },
closure_custom_threshold_check => \&catalog_status_threshold_ng
}
}
];
$self->{maps_counters}->{contact} = [
{ label => 'contact-last-time', nlabel => 'ntp.contact.last.time.', set => {
key_values => [ { name => 'contact_seconds' }, { name => 'contact_human' } ],
output_template => 'last server contact: %s',
output_use => 'contact_human',
closure_custom_perfdata => $self->can('custom_contact_perfdata'),
closure_custom_threshold_check => $self->can('custom_contact_threshold')
}
}
];
}
sub new {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1);
bless $self, $class;
$options{options}->add_options(arguments => {
'unit:s' => { name => 'unit', default => 's' },
'timezone:s' => { name => 'timezone' }
});
return $self;
}
sub check_options {
my ($self, %options) = @_;
$self->SUPER::check_options(%options);
if ($self->{option_results}->{unit} eq '' || !defined($unitdiv->{$self->{option_results}->{unit}})) {
$self->{option_results}->{unit} = 's';
}
$self->{option_results}->{timezone} = 'UTC' if (!defined($self->{option_results}->{timezone}) || $self->{option_results}->{timezone} eq '');
}
sub manage_selection {
my ($self, %options) = @_;
my ($result) = $options{custom}->get_infos(
cmd => 'show ntp-status',
base_type => 'ntp-status',
properties_name => '^ntp-status|ntp-contact-time$'
);
if (!defined($result->[0])) {
$self->{output}->add_option_msg(short_msg => 'cannot get informations');
$self->{output}->option_exit();
}
$self->{output}->output_add(short_msg => 'ntp is ok');
$self->{ntp} = {
global => {
status => { status => $result->[0]->{'ntp-status'} },
contact => {}
}
};
if ($result->[0]->{'ntp-contact-time'} =~ /^(\d+)-(\d+)-(\d+)\s+(\d+):(\d+):(\d+)$/) {
my $tz = centreon::plugins::misc::set_timezone(name => $self->{option_results}->{timezone});
my $dt = DateTime->new(
year => $1,
month => $2,
day => $3,
hour => $4,
minute => $5,
second => $6,
%$tz
);
$self->{ntp}->{global}->{contact}->{contact_seconds} = time() - $dt->epoch();
$self->{ntp}->{global}->{contact}->{contact_human} = centreon::plugins::misc::change_seconds(
value => $self->{ntp}->{global}->{contact}->{contact_seconds}
);
}
}
1;
__END__
=head1 MODE
Check ntp status.
=over 8
=item B<--filter-counters>
Only display some counters (regexp can be used).
Example: --filter-counters='status'
=item B<--warning-status>
Set warning threshold for status.
Can use special variables like: %{status}
=item B<--critical-status>
Set critical threshold for status (Default: '%{status} =~ /deactivated/i').
Can use special variables like: %{status}
=item B<--timezone>
Set timezone for ntp contact time (Default is 'UTC').
=item B<--unit>
Select the unit for contact threshold. May be 's' for seconds, 'm' for minutes,
'h' for hours, 'd' for days, 'w' for weeks. Default is days.
=item B<--warning-*> B<--critical-*>
Thresholds.
Can be: 'contact-last-time'.
=back
=cut

View File

@ -35,6 +35,7 @@ sub new {
'controllers' => 'storage::hp::p2000::xmlapi::mode::controllers',
'health' => 'storage::hp::p2000::xmlapi::mode::health',
'list-volumes' => 'storage::hp::p2000::xmlapi::mode::listvolumes',
'ntp' => 'storage::hp::p2000::xmlapi::mode::ntp',
'vdisks' => 'storage::hp::p2000::xmlapi::mode::vdisks',
'volume-stats' => 'storage::hp::p2000::xmlapi::mode::volumesstats'
};