From 320a93b5a46a867d68af8d56e433415c34c7e131 Mon Sep 17 00:00:00 2001 From: Quentin Garnier Date: Thu, 19 Mar 2015 14:41:26 +1100 Subject: [PATCH] + Add Juniper M Series plugin + Add options to hardware for junos --- .../server/hp/proliant/snmp/mode/hardware.pm | 3 +- .../common/junos/mode/components/fru.pm | 140 ++++++++ .../common/junos/mode/components/operating.pm | 90 +++++ network/juniper/common/junos/mode/hardware.pm | 318 ++++++++++++------ network/juniper/mseries/plugin.pm | 70 ++++ 5 files changed, 513 insertions(+), 108 deletions(-) create mode 100644 network/juniper/common/junos/mode/components/fru.pm create mode 100644 network/juniper/common/junos/mode/components/operating.pm create mode 100644 network/juniper/mseries/plugin.pm diff --git a/hardware/server/hp/proliant/snmp/mode/hardware.pm b/hardware/server/hp/proliant/snmp/mode/hardware.pm index e8c201cd1..7c42c4c5e 100644 --- a/hardware/server/hp/proliant/snmp/mode/hardware.pm +++ b/hardware/server/hp/proliant/snmp/mode/hardware.pm @@ -305,7 +305,7 @@ sub check_options { } my ($section, $regexp, $value) = ($1, $2, $3); if ($section !~ /(temperature)/) { - $self->{output}->add_option_msg(short_msg => "Wrong $option option '" . $val . "' (type must be: battery or temperature)."); + $self->{output}->add_option_msg(short_msg => "Wrong $option option '" . $val . "' (type must be: temperature)."); $self->{output}->option_exit(); } my $position = 0; @@ -440,7 +440,6 @@ sub absent_problem { return 1; } - sub get_severity_numeric { my ($self, %options) = @_; my $status = 'OK'; # default diff --git a/network/juniper/common/junos/mode/components/fru.pm b/network/juniper/common/junos/mode/components/fru.pm new file mode 100644 index 000000000..0dbc7fb7c --- /dev/null +++ b/network/juniper/common/junos/mode/components/fru.pm @@ -0,0 +1,140 @@ +################################################################################ +# Copyright 2005-2013 MERETHIS +# Centreon is developped by : Julien Mathis and Romain Le Merlus under +# GPL Licence 2.0. +# +# This program is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation ; either version 2 of the License. +# +# This program is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along with +# this program; if not, see . +# +# Linking this program statically or dynamically with other modules is making a +# combined work based on this program. Thus, the terms and conditions of the GNU +# General Public License cover the whole combination. +# +# As a special exception, the copyright holders of this program give MERETHIS +# permission to link this program with independent modules to produce an executable, +# regardless of the license terms of these independent modules, and to copy and +# distribute the resulting executable under terms of MERETHIS choice, provided that +# MERETHIS also meet, for each linked independent module, the terms and conditions +# of the license of that module. An independent module is a module which is not +# derived from this program. If you modify this program, you may extend this +# exception to your version of the program, but you are not obliged to do so. If you +# do not wish to do so, delete this exception statement from your version. +# +# For more information : contact@centreon.com +# Authors : Quentin Garnier +# +#################################################################################### + +package network::juniper::common::junos::mode::components::fru; + +use strict; +use warnings; + +my %map_fru_offline = ( + 1 => 'unknown', 2 => 'none', 3 => 'error', 4 => 'noPower', 5 => 'configPowerOff', 6 => 'configHoldInReset', + 7 => 'cliCommand', 8 => 'buttonPress', 9 => 'cliRestart', 10 => 'overtempShutdown', 11 => 'masterClockDown', + 12 => 'singleSfmModeChange', 13 => 'packetSchedulingModeChange', 14 => 'physicalRemoval', 15 => 'unresponsiveRestart', + 16 => 'sonetClockAbsent', 17 => 'rddPowerOff', 18 => 'majorErrors', 19 => 'minorErrors', 20 => 'lccHardRestart', + 21 => 'lccVersionMismatch', 22 => 'powerCycle', 23 => 'reconnect', 24 => 'overvoltage', 25 => 'pfeVersionMismatch', + 26 => 'febRddCfgChange', 27 => 'fpcMisconfig', 28 => 'fruReconnectFail', 29 => 'fruFwddReset', 30 => 'fruFebSwitch', + 31 => 'fruFebOffline', 32 => 'fruInServSoftUpgradeError', 33 => 'fruChasdPowerRatingExceed', 34 => 'fruConfigOffline', + 35 => 'fruServiceRestartRequest', 36 => 'spuResetRequest', 37 => 'spuFlowdDown', 38 => 'spuSpi4Down', 39 => 'spuWatchdogTimeout', + 40 => 'spuCoreDump', 41 => 'fpgaSpi4LinkDown', 42 => 'i3Spi4LinkDown', 43 => 'cppDisconnect', 44 => 'cpuNotBoot', + 45 => 'spuCoreDumpComplete', 46 => 'rstOnSpcSpuFailure', 47 => 'softRstOnSpcSpuFailure', 48 => 'hwAuthenticationFailure', + 49 => 'reconnectFpcFail', 50 => 'fpcAppFailed', 51 => 'fpcKernelCrash', 52 => 'spuFlowdDownNoCore', 53 => 'spuFlowdCoreDumpIncomplete', + 54 => 'spuFlowdCoreDumpComplete', 55 => 'spuIdpdDownNoCore', 56 => 'spuIdpdCoreDumpIncomplete', 57 => 'spuIdpdCoreDumpComplete', + 58 => 'spuCoreDumpIncomplete', 59 => 'spuIdpdDown', 60 => 'fruPfeReset', 61 => 'fruReconnectNotReady', 62 => 'fruSfLinkDown', + 63 => 'fruFabricDown', 64 => 'fruAntiCounterfeitRetry', 65 => 'fruFPCChassisClusterDisable', 66 => 'spuFipsError', + 67 => 'fruFPCFabricDownOffline', 68 => 'febCfgChange', 69 => 'routeLocalizationRoleChange', 70 => 'fruFpcUnsupported', + 71 => 'psdVersionMismatch', 72 => 'fruResetThresholdExceeded', 73 => 'picBounce', 74 => 'badVoltage', 75 => 'fruFPCReducedFabricBW', + 76 => 'fruAutoheal', 77 => 'builtinPicBounce', 78 => 'fruFabricDegraded', 79 => 'fruFPCFabricDegradedOffline', 80 => 'fruUnsupportedSlot', + 81 => 'fruRouteLocalizationMisCfg', 82 => 'fruTypeConfigMismatch', 83 => 'lccModeChanged', 84 => 'hwFault', 85 => 'fruPICOfflineOnEccErrors', + 86 => 'fruFpcIncompatible', 87 => 'fruFpcFanTrayPEMIncompatible', 88 => 'fruUnsupportedFirmware', + 89 => 'openflowConfigChange', 90 => 'fruFpcScbIncompatible', 91 => 'fruReUnresponsive' +); +my %map_fru_type = ( + 1 => 'other', 2 => 'clockGenerator', 3 => 'flexiblePicConcentrator', 4 => 'switchingAndForwardingModule', 5 => 'controlBoard', + 6 => 'routingEngine', 7 => 'powerEntryModule', 8 => 'frontPanelModule', 9 => 'switchInterfaceBoard', 10 => 'processorMezzanineBoardForSIB', + 11 => 'portInterfaceCard', 12 => 'craftInterfacePanel', 13 => 'fan', 14 => 'lineCardChassis', 15 => 'forwardingEngineBoard', + 16 => 'protectedSystemDomain', 17 => 'powerDistributionUnit', 18 => 'powerSupplyModule', 19 => 'switchFabricBoard', 20 => 'adapterCard' +); + +my %map_fru_states = ( + 1 => 'unknown', + 2 => 'empty', + 3 => 'present', + 4 => 'ready', + 5 => 'announce online', + 6 => 'online', + 7 => 'announce offline', + 8 => 'offline', + 9 => 'diagnostic', + 10 => 'standby', +); + +# In MIB 'mib-jnx-chassis' +my $mapping = { + jnxFruName => { oid => '.1.3.6.1.4.1.2636.3.1.15.1.5' }, + jnxFruType => { oid => '.1.3.6.1.4.1.2636.3.1.15.1.6', map => \%map_fru_type }, + jnxFruState => { oid => '.1.3.6.1.4.1.2636.3.1.15.1.8', map => \%map_fru_states }, + jnxFruTemp => { oid => '.1.3.6.1.4.1.2636.3.1.15.1.9' }, + jnxFruOfflineReason => { oid => '.1.3.6.1.4.1.2636.3.1.15.1.10', map => \%map_fru_offline }, +}; +my $oid_jnxFruEntry = '.1.3.6.1.4.1.2636.3.1.15.1'; + +sub load { + my (%options) = @_; + + push @{$options{request}}, { oid => $oid_jnxFruEntry, start => $mapping->{jnxFruName}->{oid}, end => $mapping->{jnxFruOfflineReason}->{oid} }; +} + +sub check { + my ($self) = @_; + + $self->{output}->output_add(long_msg => "Checking frus"); + $self->{components}->{fru} = {name => 'frus', total => 0, skip => 0}; + return if ($self->check_exclude(section => 'fru')); + + foreach my $oid ($self->{snmp}->oid_lex_sort(keys %{$self->{results}->{$oid_jnxFruEntry}})) { + next if ($oid !~ /^$mapping->{jnxFruName}->{oid}\.(.*)$/); + my $instance = $1; + my $result = $self->{snmp}->map_instance(mapping => $mapping, results => $self->{results}->{$oid_jnxFruEntry}, instance => $instance); + + next if ($self->check_exclude(section => 'fru', instance => $instance)); + next if ($result->{cpqHeFltTolFanPresent} =~ /empty/i && + $self->absent_problem(section => 'fru', instance => $instance)); + $self->{components}->{fru}->{total}++; + + $self->{output}->output_add(long_msg => sprintf("Fru '%s' state is %s [instance: %s, type: %s, offline reason: %s]", + $result->{jnxFruName}, $result->{jnxFruState}, + $instance, $result->{jnxFruType}, $result->{jnxFruOfflineReason})); + my $exit = $self->get_severity(section => 'fru', value => $result->{jnxFruState}); + if (!$self->{output}->is_status(value => $exit, compare => 'ok', litteral => 1)) { + $self->{output}->output_add(severity => $exit, + short_msg => sprintf("Fru '%s' state is %s [offline reason: %s]", $result->{jnxFruName}, $result->{jnxFruState}, + $result->{jnxFruOfflineReason})); + } + + if (defined($result->{jnxFruTemp}) && $result->{jnxFruTemp} != 0) { + my ($exit2, $warn, $crit, $checked) = $self->get_severity_numeric(section => 'fru-temperature', instance => $instance, value => $result->{jnxFruTemp}); + if (!$self->{output}->is_status(value => $exit2, compare => 'ok', litteral => 1)) { + $self->{output}->output_add(severity => $exit2, + short_msg => sprintf("Fru '%s' temperature is %s degree centigrade", $result->{jnxFruName}, $result->{jnxFruTemp})); + } + $self->{output}->perfdata_add(label => "temp_" . $result->{jnxFruName}, unit => 'C', + value => $result->{jnxFruTemp}, + warning => $warn, + critical => $crit); + } + } +} + +1; \ No newline at end of file diff --git a/network/juniper/common/junos/mode/components/operating.pm b/network/juniper/common/junos/mode/components/operating.pm new file mode 100644 index 000000000..7ca59834d --- /dev/null +++ b/network/juniper/common/junos/mode/components/operating.pm @@ -0,0 +1,90 @@ +################################################################################ +# Copyright 2005-2013 MERETHIS +# Centreon is developped by : Julien Mathis and Romain Le Merlus under +# GPL Licence 2.0. +# +# This program is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation ; either version 2 of the License. +# +# This program is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along with +# this program; if not, see . +# +# Linking this program statically or dynamically with other modules is making a +# combined work based on this program. Thus, the terms and conditions of the GNU +# General Public License cover the whole combination. +# +# As a special exception, the copyright holders of this program give MERETHIS +# permission to link this program with independent modules to produce an executable, +# regardless of the license terms of these independent modules, and to copy and +# distribute the resulting executable under terms of MERETHIS choice, provided that +# MERETHIS also meet, for each linked independent module, the terms and conditions +# of the license of that module. An independent module is a module which is not +# derived from this program. If you modify this program, you may extend this +# exception to your version of the program, but you are not obliged to do so. If you +# do not wish to do so, delete this exception statement from your version. +# +# For more information : contact@centreon.com +# Authors : Quentin Garnier +# +#################################################################################### + +package network::juniper::common::junos::mode::components::operating; + +use strict; +use warnings; + +my %map_operating_states = ( + 1 => 'unknown', + 2 => 'running', + 3 => 'ready', + 4 => 'reset', + 5 => 'runningAtFullSpeed', + 6 => 'down', + 7 => 'standby', +); + +# In MIB 'mib-jnx-chassis' +my $mapping = { + jnxOperatingDescr => { oid => '.1.3.6.1.4.1.2636.3.1.13.1.5' }, + jnxOperatingState => { oid => '.1.3.6.1.4.1.2636.3.1.13.1.6', map => \%map_operating_states }, +}; +my $oid_jnxOperatingEntry = '.1.3.6.1.4.1.2636.3.1.13.1'; + +sub load { + my (%options) = @_; + + push @{$options{request}}, { oid => $oid_jnxOperatingEntry, start => $mapping->{jnxOperatingDescr}->{oid}, end => $mapping->{jnxOperatingState}->{oid} }; +} + +sub check { + my ($self) = @_; + + $self->{output}->output_add(long_msg => "Checking operatings"); + $self->{components}->{operating} = {name => 'operatings', total => 0, skip => 0}; + return if ($self->check_exclude(section => 'operating')); + + foreach my $oid ($self->{snmp}->oid_lex_sort(keys %{$self->{results}->{$oid_jnxOperatingEntry}})) { + next if ($oid !~ /^$mapping->{jnxOperatingDescr}->{oid}\.(.*)$/); + my $instance = $1; + my $result = $self->{snmp}->map_instance(mapping => $mapping, results => $self->{results}->{$oid_jnxOperatingEntry}, instance => $instance); + + next if ($self->check_exclude(section => 'operating', instance => $instance)); + $self->{components}->{operating}->{total}++; + + $self->{output}->output_add(long_msg => sprintf("Operating '%s' state is %s [instance: %s]", + $result->{jnxOperatingDescr}, $result->{jnxOperatingState}, $instance)); + my $exit = $self->get_severity(section => 'operating', value => $result->{jnxOperatingState}); + if (!$self->{output}->is_status(value => $exit, compare => 'ok', litteral => 1)) { + $self->{output}->output_add(severity => $exit, + short_msg => sprintf("Operating '%s' state is %s", + $result->{jnxOperatingDescr}, $result->{jnxOperatingState})); + } + } +} + +1; \ No newline at end of file diff --git a/network/juniper/common/junos/mode/hardware.pm b/network/juniper/common/junos/mode/hardware.pm index 24e45babe..29c4837cd 100644 --- a/network/juniper/common/junos/mode/hardware.pm +++ b/network/juniper/common/junos/mode/hardware.pm @@ -40,55 +40,28 @@ use base qw(centreon::plugins::mode); use strict; use warnings; -my %map_fru_offline = ( - 1 => 'unknown', 2 => 'none', 3 => 'error', 4 => 'noPower', 5 => 'configPowerOff', 6 => 'configHoldInReset', - 7 => 'cliCommand', 8 => 'buttonPress', 9 => 'cliRestart', 10 => 'overtempShutdown', 11 => 'masterClockDown', - 12 => 'singleSfmModeChange', 13 => 'packetSchedulingModeChange', 14 => 'physicalRemoval', 15 => 'unresponsiveRestart', - 16 => 'sonetClockAbsent', 17 => 'rddPowerOff', 18 => 'majorErrors', 19 => 'minorErrors', 20 => 'lccHardRestart', - 21 => 'lccVersionMismatch', 22 => 'powerCycle', 23 => 'reconnect', 24 => 'overvoltage', 25 => 'pfeVersionMismatch', - 26 => 'febRddCfgChange', 27 => 'fpcMisconfig', 28 => 'fruReconnectFail', 29 => 'fruFwddReset', 30 => 'fruFebSwitch', - 31 => 'fruFebOffline', 32 => 'fruInServSoftUpgradeError', 33 => 'fruChasdPowerRatingExceed', 34 => 'fruConfigOffline', - 35 => 'fruServiceRestartRequest', 36 => 'spuResetRequest', 37 => 'spuFlowdDown', 38 => 'spuSpi4Down', 39 => 'spuWatchdogTimeout', - 40 => 'spuCoreDump', 41 => 'fpgaSpi4LinkDown', 42 => 'i3Spi4LinkDown', 43 => 'cppDisconnect', 44 => 'cpuNotBoot', - 45 => 'spuCoreDumpComplete', 46 => 'rstOnSpcSpuFailure', 47 => 'softRstOnSpcSpuFailure', 48 => 'hwAuthenticationFailure', - 49 => 'reconnectFpcFail', 50 => 'fpcAppFailed', 51 => 'fpcKernelCrash', 52 => 'spuFlowdDownNoCore', 53 => 'spuFlowdCoreDumpIncomplete', - 54 => 'spuFlowdCoreDumpComplete', 55 => 'spuIdpdDownNoCore', 56 => 'spuIdpdCoreDumpIncomplete', 57 => 'spuIdpdCoreDumpComplete', - 58 => 'spuCoreDumpIncomplete', 59 => 'spuIdpdDown', 60 => 'fruPfeReset', 61 => 'fruReconnectNotReady', 62 => 'fruSfLinkDown', - 63 => 'fruFabricDown', 64 => 'fruAntiCounterfeitRetry', 65 => 'fruFPCChassisClusterDisable', 66 => 'spuFipsError', - 67 => 'fruFPCFabricDownOffline', 68 => 'febCfgChange', 69 => 'routeLocalizationRoleChange', 70 => 'fruFpcUnsupported', - 71 => 'psdVersionMismatch', 72 => 'fruResetThresholdExceeded', 73 => 'picBounce', 74 => 'badVoltage', 75 => 'fruFPCReducedFabricBW', - 76 => 'fruAutoheal', 77 => 'builtinPicBounce', 78 => 'fruFabricDegraded', 79 => 'fruFPCFabricDegradedOffline', 80 => 'fruUnsupportedSlot', - 81 => 'fruRouteLocalizationMisCfg', 82 => 'fruTypeConfigMismatch', 83 => 'lccModeChanged', 84 => 'hwFault', 85 => 'fruPICOfflineOnEccErrors', - 86 => 'fruFpcIncompatible', 87 => 'fruFpcFanTrayPEMIncompatible', 88 => 'fruUnsupportedFirmware', - 89 => 'openflowConfigChange', 90 => 'fruFpcScbIncompatible', 91 => 'fruReUnresponsive' -); -my %map_fru_type = ( - 1 => 'other', 2 => 'clockGenerator', 3 => 'flexiblePicConcentrator', 4 => 'switchingAndForwardingModule', 5 => 'controlBoard', - 6 => 'routingEngine', 7 => 'powerEntryModule', 8 => 'frontPanelModule', 9 => 'switchInterfaceBoard', 10 => 'processorMezzanineBoardForSIB', - 11 => 'portInterfaceCard', 12 => 'craftInterfacePanel', 13 => 'fan', 14 => 'lineCardChassis', 15 => 'forwardingEngineBoard', - 16 => 'protectedSystemDomain', 17 => 'powerDistributionUnit', 18 => 'powerSupplyModule', 19 => 'switchFabricBoard', 20 => 'adapterCard' -); -my %fru_states = ( - 1 => ['unknown', 'UNKNOWN'], - 2 => ['empty', 'OK'], - 3 => ['present', 'OK'], - 4 => ['ready', 'OK'], - 5 => ['announce online', 'OK'], - 6 => ['online', 'OK'], - 7 => ['announce offline', 'WARNING'], - 8 => ['offline', 'CRITICAL'], - 9 => ['diagnostic', 'WARNING'], - 10 => ['standby', 'WARNING'], -); -my %operating_states = ( - 1 => ['unknown', 'UNKNOWN'], - 2 => ['running', 'OK'], - 3 => ['ready', 'OK'], - 4 => ['reset', 'WARNING'], - 5 => ['runningAtFullSpeed', 'WARNING'], - 6 => ['down', 'CRITICAL'], - 7 => ['standby', 'OK'], -); +my $thresholds = { + fru => [ + ['unknown', 'UNKNOWN'], + ['present', 'OK'], + ['ready', 'OK'], + ['announce online', 'OK'], + ['online', 'OK'], + ['announce offline', 'WARNING'], + ['offline', 'CRITICAL'], + ['diagnostic', 'WARNING'], + ['standby', 'WARNING'], + ], + operating => [ + ['unknown', 'UNKNOWN'], + ['running', 'OK'], + ['ready', 'OK'], + ['reset', 'WARNING'], + ['runningAtFullSpeed', 'WARNING'], + ['down', 'CRITICAL'], + ['standby', 'WARNING'], + ], +}; sub new { my ($class, %options) = @_; @@ -98,14 +71,71 @@ sub new { $self->{version} = '1.0'; $options{options}->add_options(arguments => { + "exclude:s" => { name => 'exclude' }, + "absent-problem:s" => { name => 'absent' }, + "component:s" => { name => 'component', default => '.*' }, + "no-component:s" => { name => 'no_component' }, + "threshold-overload:s@" => { name => 'threshold_overload' }, + "warning:s@" => { name => 'warning' }, + "critical:s@" => { name => 'critical' }, }); + $self->{components} = {}; + $self->{no_components} = undef; return $self; } sub check_options { my ($self, %options) = @_; $self->SUPER::init(%options); + + if (defined($self->{option_results}->{no_component})) { + if ($self->{option_results}->{no_component} ne '') { + $self->{no_components} = $self->{option_results}->{no_component}; + } else { + $self->{no_components} = 'critical'; + } + } + + $self->{overload_th} = {}; + foreach my $val (@{$self->{option_results}->{threshold_overload}}) { + if ($val !~ /^(.*?),(.*?),(.*)$/) { + $self->{output}->add_option_msg(short_msg => "Wrong threshold-overload option '" . $val . "'."); + $self->{output}->option_exit(); + } + my ($section, $status, $filter) = ($1, $2, $3); + if ($self->{output}->is_litteral_status(status => $status) == 0) { + $self->{output}->add_option_msg(short_msg => "Wrong threshold-overload status '" . $val . "'."); + $self->{output}->option_exit(); + } + $self->{overload_th}->{$section} = [] if (!defined($self->{overload_th}->{$section})); + push @{$self->{overload_th}->{$section}}, {filter => $filter, status => $status}; + } + + $self->{numeric_threshold} = {}; + foreach my $option (('warning', 'critical')) { + foreach my $val (@{$self->{option_results}->{$option}}) { + if ($val !~ /^(.*?),(.*?),(.*)$/) { + $self->{output}->add_option_msg(short_msg => "Wrong $option option '" . $val . "'."); + $self->{output}->option_exit(); + } + my ($section, $regexp, $value) = ($1, $2, $3); + if ($section !~ /(fru-temperature)/) { + $self->{output}->add_option_msg(short_msg => "Wrong $option option '" . $val . "' (type must be: fru-temperature)."); + $self->{output}->option_exit(); + } + my $position = 0; + if (defined($self->{numeric_threshold}->{$section})) { + $position = scalar(@{$self->{numeric_threshold}->{$section}}); + } + if (($self->{perfdata}->threshold_validate(label => $option . '-' . $section . '-' . $position, value => $value)) == 0) { + $self->{output}->add_option_msg(short_msg => "Wrong $option threshold '" . $value . "'."); + $self->{output}->option_exit(); + } + $self->{numeric_threshold}->{$section} = [] if (!defined($self->{numeric_threshold}->{$section})); + push @{$self->{numeric_threshold}->{$section}}, { label => $option . '-' . $section . '-' . $position, threshold => $option, regexp => $regexp }; + } + } } sub run { @@ -113,18 +143,57 @@ sub run { # $options{snmp} = snmp object $self->{snmp} = $options{snmp}; - $self->{components_frus} = 0; - $self->{components_operating} = 0; - $self->get_type(); - $self->check_frus(); - $self->check_operating(); + + my $snmp_request = []; + my @components = ('fru', 'operating'); + foreach (@components) { + if (/$self->{option_results}->{component}/) { + my $mod_name = "network::juniper::common::junos::mode::components::$_"; + centreon::plugins::misc::mymodule_load(output => $self->{output}, module => $mod_name, + error_msg => "Cannot load module '$mod_name'."); + my $func = $mod_name->can('load'); + $func->(request => $snmp_request); + } + } + + if (scalar(@{$snmp_request}) == 0) { + $self->{output}->add_option_msg(short_msg => "Wrong option. Cannot find component '" . $self->{option_results}->{component} . "'."); + $self->{output}->option_exit(); + } + $self->{results} = $self->{snmp}->get_multiple_table(oids => $snmp_request); + + foreach (@components) { + if (/$self->{option_results}->{component}/) { + my $mod_name = "network::juniper::common::junos::mode::components::$_"; + my $func = $mod_name->can('check'); + $func->($self); + } + } + + my $total_components = 0; + my $display_by_component = ''; + my $display_by_component_append = ''; + foreach my $comp (sort(keys %{$self->{components}})) { + # Skipping short msg when no components + next if ($self->{components}->{$comp}->{total} == 0 && $self->{components}->{$comp}->{skip} == 0); + $total_components += $self->{components}->{$comp}->{total} + $self->{components}->{$comp}->{skip}; + my $count_by_components = $self->{components}->{$comp}->{total} + $self->{components}->{$comp}->{skip}; + $display_by_component .= $display_by_component_append . $self->{components}->{$comp}->{total} . '/' . $count_by_components . ' ' . $self->{components}->{$comp}->{name}; + $display_by_component_append = ', '; + } $self->{output}->output_add(severity => 'OK', - short_msg => sprintf("All %d components [%d frus, %d operating] are ok, Environment type: %s", - ($self->{components_frus} + $self->{components_operating}), - $self->{components_frus}, $self->{components_operating}, $self->{env_type})); - + short_msg => sprintf("All %s components are ok [%s].", + $total_components, + $display_by_component) + ); + + if (defined($self->{option_results}->{no_component}) && $total_components == 0) { + $self->{output}->output_add(severity => $self->{no_components}, + short_msg => 'No components are checked.'); + } + $self->{output}->display(); $self->{output}->exit(); } @@ -137,59 +206,61 @@ sub get_type { my $result = $self->{snmp}->get_leef(oids => [$oid_jnxBoxDescr]); $self->{env_type} = defined($result->{$oid_jnxBoxDescr}) ? $result->{$oid_jnxBoxDescr} : 'unknown'; + $self->{output}->output_add(long_msg => sprintf("Environment type: %s", $self->{env_type})); } -sub check_frus { - my ($self) = @_; - $self->{output}->output_add(long_msg => "Checking frus"); - - my $oid_jnxFruName = '.1.3.6.1.4.1.2636.3.1.15.1.5'; - my $oid_jnxFruType = '.1.3.6.1.4.1.2636.3.1.15.1.6'; - my $oid_jnxFruState = '.1.3.6.1.4.1.2636.3.1.15.1.8'; - my $oid_jnxFruTemp = '.1.3.6.1.4.1.2636.3.1.15.1.9'; - my $oid_jnxFruOfflineReason = '.1.3.6.1.4.1.2636.3.1.15.1.10'; - - my $result = $self->{snmp}->get_table(oid => $oid_jnxFruName); - return if (scalar(keys %$result) <= 0); +sub check_exclude { + my ($self, %options) = @_; - $self->{snmp}->load(oids => [$oid_jnxFruType, $oid_jnxFruState, $oid_jnxFruTemp, $oid_jnxFruOfflineReason], - instances => [keys %$result], - instance_regexp => "^" . $oid_jnxFruName . '\.(.+)'); - my $result2 = $self->{snmp}->get_leef(); + if (defined($options{instance})) { + if (defined($self->{option_results}->{exclude}) && $self->{option_results}->{exclude} =~ /(^|\s|,)${options{section}}[^,]*#\Q$options{instance}\E#/) { + $self->{components}->{$options{section}}->{skip}++; + $self->{output}->output_add(long_msg => sprintf("Skipping $options{section} section $options{instance} instance.")); + return 1; + } + } elsif (defined($self->{option_results}->{exclude}) && $self->{option_results}->{exclude} =~ /(^|\s|,)$options{section}(\s|,|$)/) { + $self->{output}->output_add(long_msg => sprintf("Skipping $options{section} section.")); + return 1; + } + return 0; +} + +sub absent_problem { + my ($self, %options) = @_; - foreach my $oid (keys %$result) { - $oid =~ /^$oid_jnxFruName\.(.+)/; - my $instance = $1; - - my $fru_name = $result->{$oid}; - my $fru_type = $result2->{$oid_jnxFruType . "." . $instance}; - my $fru_state = $result2->{$oid_jnxFruState . "." . $instance}; - my $fru_temp = $result2->{$oid_jnxFruTemp . "." . $instance}; - my $fru_offlinereason = $result2->{$oid_jnxFruOfflineReason . "." . $instance}; - - # Empty. Skip - if ($fru_state == 2) { - $self->{output}->output_add(long_msg => sprintf("Skipping fru '%s' [type: %s]: empty.", - $fru_name, $map_fru_type{$fru_type})); - next; - } - - $self->{components_frus}++; - $self->{output}->output_add(long_msg => sprintf("Fru '%s' state is %s [type: %s, offline reason: %s]", - $fru_name, ${$fru_states{$fru_state}}[0], - $map_fru_type{$fru_type}, $map_fru_offline{$fru_offlinereason})); - if (${$fru_states{$fru_state}}[1] ne 'OK') { - $self->{output}->output_add(severity => ${$fru_states{$fru_state}}[1], - short_msg => sprintf("Fru '%s' state is %s [offline reason: %s]", $fru_name, ${$fru_states{$fru_state}}[0], - $map_fru_offline{$fru_offlinereason})); - } - - if ($fru_temp != 0) { - $self->{output}->perfdata_add(label => 'temp_' . $fru_name, unit => 'C', - value => $fru_temp); + if (defined($self->{option_results}->{absent}) && + $self->{option_results}->{absent} =~ /(^|\s|,)($options{section}(\s*,|$)|${options{section}}[^,]*#\Q$options{instance}\E#)/) { + $self->{output}->output_add(severity => 'CRITICAL', + short_msg => sprintf("Component '%s' instance '%s' is not present", + $options{section}, $options{instance})); + } + + $self->{output}->output_add(long_msg => sprintf("Skipping $options{section} section $options{instance} instance (not present)")); + $self->{components}->{$options{section}}->{skip}++; + return 1; +} + +sub get_severity { + my ($self, %options) = @_; + my $status = 'UNKNOWN'; # default + + if (defined($self->{overload_th}->{$options{section}})) { + foreach (@{$self->{overload_th}->{$options{section}}}) { + if ($options{value} =~ /$_->{filter}/i) { + $status = $_->{status}; + return $status; + } } } + foreach (@{$thresholds->{$options{section}}}) { + if ($options{value} =~ /$$_[0]/i) { + $status = $$_[1]; + return $status; + } + } + + return $status; } sub check_operating { @@ -197,8 +268,7 @@ sub check_operating { $self->{output}->output_add(long_msg => "Checking operating"); - my $oid_jnxOperatingDescr = '.1.3.6.1.4.1.2636.3.1.13.1.5'; - my $oid_jnxOperatingState = '.1.3.6.1.4.1.2636.3.1.13.1.6'; + my $result = $self->{snmp}->get_table(oid => $oid_jnxOperatingDescr); return if (scalar(keys %$result) <= 0); @@ -236,6 +306,42 @@ Check Hardware (mib-jnx-chassis) (frus, operating). =over 8 +=item B<--component> + +Which component to check (Default: '.*'). +Can be: 'fru', 'operating'. + +=item B<--exclude> + +Exclude some parts (comma seperated list) (Example: --exclude=fan,cpu) +Can also exclude specific instance: --exclude=fan#1.2#,lnic#1#,cpu + +=item B<--absent-problem> + +Return an error if an entity is not 'present' (default is skipping) (comma seperated list) +Can be specific or global: --absent-problem=fan#1.2#,cpu + +=item B<--no-component> + +Return an error if no compenents are checked. +If total (with skipped) is 0. (Default: 'critical' returns). + +=item B<--threshold-overload> + +Set to overload default threshold values (syntax: section,status,regexp) +It used before default thresholds (order stays). +Example: --threshold-overload='temperature,CRITICAL,^(?!(ok)$)' + +=item B<--warning> + +Set warning threshold for fru temperatures (syntax: type,regexp,treshold) +Example: --warning='fru-temperature,.*,30' + +=item B<--critical> + +Set critical threshold for fru temperatures (syntax: type,regexp,treshold) +Example: --critical='fru-temperature,.*,40' + =back =cut diff --git a/network/juniper/mseries/plugin.pm b/network/juniper/mseries/plugin.pm new file mode 100644 index 000000000..2679be767 --- /dev/null +++ b/network/juniper/mseries/plugin.pm @@ -0,0 +1,70 @@ +################################################################################ +# Copyright 2005-2013 MERETHIS +# Centreon is developped by : Julien Mathis and Romain Le Merlus under +# GPL Licence 2.0. +# +# This program is free software; you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation ; either version 2 of the License. +# +# This program is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along with +# this program; if not, see . +# +# Linking this program statically or dynamically with other modules is making a +# combined work based on this program. Thus, the terms and conditions of the GNU +# General Public License cover the whole combination. +# +# As a special exception, the copyright holders of this program give MERETHIS +# permission to link this program with independent modules to produce an executable, +# regardless of the license terms of these independent modules, and to copy and +# distribute the resulting executable under terms of MERETHIS choice, provided that +# MERETHIS also meet, for each linked independent module, the terms and conditions +# of the license of that module. An independent module is a module which is not +# derived from this program. If you modify this program, you may extend this +# exception to your version of the program, but you are not obliged to do so. If you +# do not wish to do so, delete this exception statement from your version. +# +# For more information : contact@centreon.com +# Authors : Quentin Garnier +# +#################################################################################### + +package network::juniper::mseries::plugin; + +use strict; +use warnings; +use base qw(centreon::plugins::script_snmp); + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + # $options->{options} = options object + + $self->{version} = '1.0'; + %{$self->{modes}} = ( + 'hardware' => 'network::juniper::common::junos::mode::hardware', + 'cpu-routing' => 'network::juniper::common::junos::mode::cpurouting', # routing engine + 'memory-routing' => 'network::juniper::common::junos::mode::memoryrouting', # routing engine + 'traffic' => 'snmp_standard::mode::traffic', + 'list-interfaces' => 'snmp_standard::mode::listinterfaces', + 'list-storages' => 'snmp_standard::mode::liststorages', + 'storage' => 'snmp_standard::mode::storage', + ); + + return $self; +} + +1; + +__END__ + +=head1 PLUGIN DESCRIPTION + +Check Juniper M Series in SNMP. + +=cut