diff --git a/snmp_standard/mode/spanningtree.pm b/snmp_standard/mode/spanningtree.pm index 411094242..375599f95 100644 --- a/snmp_standard/mode/spanningtree.pm +++ b/snmp_standard/mode/spanningtree.pm @@ -20,43 +20,126 @@ package snmp_standard::mode::spanningtree; -use base qw(centreon::plugins::mode); +use base qw(centreon::plugins::templates::counter); use strict; use warnings; -my %states = ( - 1 => ['disabled', 'OK'], - 2 => ['blocking', 'CRITICAL'], - 3 => ['listening', 'OK'], - 4 => ['learning', 'OK'], - 5 => ['forwarding', 'OK'], - 6 => ['broken', 'CRITICAL'], - - 10 => ['not defined', 'UNKNOWN'], # mine status -); +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 = " spanning tree state is '" . $self->{result_values}->{state} . "' [index: '" . $self->{result_values}->{index} . "']"; + + return $msg; +} + +sub custom_status_calc { + my ($self, %options) = @_; + + $self->{result_values}->{port} = $options{new_datas}->{$self->{instance} . '_display'}; + $self->{result_values}->{state} = $options{new_datas}->{$self->{instance} . '_state'}; + $self->{result_values}->{index} = $options{new_datas}->{$self->{instance} . '_index'}; + + + return 0; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'stp_port', type => 1, cb_prefix_output => 'prefix_peers_output', message_multiple => 'Spanning tree is OK' }, + ]; + $self->{maps_counters}->{stp_port} = [ + { label => 'status', threshold => 0, set => { + key_values => [ { name => 'state' }, { name => 'index' }, { name => 'display' } ], + 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 prefix_peers_output { + my ($self, %options) = @_; + + return "Port: '" . $options{instance_value}->{display} . "' "; +} 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-port:s" => { name => 'filter_port' }, + "warning-status:s" => { name => 'warning_status', default => '' }, + "critical-status:s" => { name => 'critical_status', default => '%{state} =~ /blocking|broken/' }, }); return $self; } -sub check_options { +sub change_macros { my ($self, %options) = @_; - $self->SUPER::init(%options); + + foreach (('warning_status', 'critical_status')) { + if (defined($self->{option_results}->{$_})) { + $self->{option_results}->{$_} =~ s/%\{(.*?)\}/\$self->{result_values}->{$1}/g; + } + } } -sub run { +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + $instance_mode = $self; + $self->change_macros(); +} + + +my %states = ( + 1 => 'disabled', + 2 => 'blocking', + 3 => 'listening', + 4 => 'learning', + 5 => 'forwarding', + 6 => 'broken', + 10 => 'not defined' +); + +sub manage_selection { my ($self, %options) = @_; $self->{snmp} = $options{snmp}; + $self->{stp_port} = {}; my $oid_dot1dStpPortEnable = '.1.3.6.1.2.1.17.2.15.1.4'; my $oid_dot1dStpPortState = '.1.3.6.1.2.1.17.2.15.1.3'; @@ -76,41 +159,40 @@ sub run { $self->{output}->output_add(long_msg => sprintf("Skipping interface '%d': Stp port disabled", $instance)); next; } - + push @instances, $instance; - + } - + $self->{snmp}->load(oids => [$oid_dot1dBasePortIfIndex], instances => [@instances]); my $result = $self->{snmp}->get_leef(nothing_quit => 1); - $self->{output}->output_add(severity => 'OK', - short_msg => 'Spanning Tree is ok on all interfaces'); + # Get description foreach my $oid (keys %$result) { next if ($oid !~ /^$oid_dot1dBasePortIfIndex\./ || !defined($result->{$oid})); - + $self->{snmp}->load(oids => [$oid_ifDesc . "." . $result->{$oid}]); } my $result_desc = $self->{snmp}->get_leef(); - + foreach my $instance (@instances) { - my $stp_state = defined($results->{$oid_dot1dStpPortState}->{$oid_dot1dStpPortState . '.' . $instance}) ? + my $stp_state = defined($results->{$oid_dot1dStpPortState}->{$oid_dot1dStpPortState . '.' . $instance}) ? $results->{$oid_dot1dStpPortState}->{$oid_dot1dStpPortState . '.' . $instance} : 10; - my $descr = (defined($result->{$oid_dot1dBasePortIfIndex . '.' . $instance}) && defined($result_desc->{$oid_ifDesc . '.' . $result->{$oid_dot1dBasePortIfIndex . '.' . $instance}})) ? + my $descr = (defined($result->{$oid_dot1dBasePortIfIndex . '.' . $instance}) && defined($result_desc->{$oid_ifDesc . '.' . $result->{$oid_dot1dBasePortIfIndex . '.' . $instance}})) ? $result_desc->{$oid_ifDesc . '.' . $result->{$oid_dot1dBasePortIfIndex . '.' . $instance}} : 'unknown'; - - $self->{output}->output_add(long_msg => sprintf("Spanning Tree interface '%s' state is %s", $descr, - ${$states{$stp_state}}[0])); - if (${$states{$stp_state}}[1] ne 'OK') { - $self->{output}->output_add(severity => ${$states{$stp_state}}[1], - short_msg => sprintf("Spanning Tree interface '%s' state is %s", $descr, - ${$states{$stp_state}}[0])); + + + if (defined($self->{option_results}->{filter_port}) && $self->{option_results}->{filter_port} ne '' && + $descr !~ /$self->{option_results}->{filter_port}/) { + $self->{output}->output_add(long_msg => sprintf("Skipping interface '%s': filtered with options", $descr)); + next; } + $self->{stp_port}->{$descr} = { state => $states{$stp_state}, + index => $result->{$oid_dot1dBasePortIfIndex . '.' . $instance}, + display => $descr }; } - - $self->{output}->display(); - $self->{output}->exit(); + } 1; @@ -120,10 +202,21 @@ __END__ =head1 MODE Check Spanning-Tree current state of ports (BRIDGE-MIB). +example: perl centreon_plugins.pl --plugin=network::cisco::standard::snmp::plugin --mode=spanning-tree --hostname=X.X.X.X --snmp-version='2c' --snmp-community='snmpcommunity' --verbose --warning-status='%{state} =~ /forwarding/ && %{port} !~ /^Port/' =over 8 +=item B<--warning-status> +Specify logical expression to trigger a warning alert. Can use %{port} and %{state} or %{index} +e.g --warning-status "%{port} eq 'Port-Channel' && %{state} !~ /forwarding/" + +=item B<--critical-status> +Specify logical expression to trigger a critical alert. Can use %{port} and %{state} or %{index} +Default is --critical-status='%{state} =~ /blocking|broken/' + +=item B<--filter-port> +Filter on port description, can be a regexp + =back =cut - \ No newline at end of file