From e33117366652003b00c2aad4288b3eb09c13ed6f Mon Sep 17 00:00:00 2001 From: qgarnier Date: Tue, 8 Aug 2017 10:29:44 +0200 Subject: [PATCH] fix #724 --- .../cloudcontroller/snmp/mode/deviceusage.pm | 172 +++++++++++++++++- 1 file changed, 164 insertions(+), 8 deletions(-) diff --git a/network/cisco/meraki/cloudcontroller/snmp/mode/deviceusage.pm b/network/cisco/meraki/cloudcontroller/snmp/mode/deviceusage.pm index 05730c43d..c8a763234 100644 --- a/network/cisco/meraki/cloudcontroller/snmp/mode/deviceusage.pm +++ b/network/cisco/meraki/cloudcontroller/snmp/mode/deviceusage.pm @@ -24,6 +24,7 @@ use base qw(centreon::plugins::templates::counter); use strict; use warnings; +use Digest::MD5 qw(md5_hex); my $instance_mode; @@ -66,12 +67,79 @@ sub custom_status_calc { return 0; } +sub custom_traffic_perfdata { + my ($self, %options) = @_; + + my $extra_label = ''; + if (!defined($options{extra_instance}) || $options{extra_instance} != 0) { + $extra_label .= '_' . $self->{result_values}->{display}; + } + + my ($warning, $critical); + if ($instance_mode->{option_results}->{units_traffic} eq '%' && defined($self->{result_values}->{speed})) { + $warning = $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{label}, total => $self->{result_values}->{speed}, cast_int => 1); + $critical = $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{label}, total => $self->{result_values}->{speed}, cast_int => 1); + } elsif ($instance_mode->{option_results}->{units_traffic} eq 'b/s') { + $warning = $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{label}); + $critical = $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{label}); + } + + $self->{output}->perfdata_add(label => 'traffic_' . $self->{result_values}->{label} . $extra_label, unit => 'b/s', + value => sprintf("%.2f", $self->{result_values}->{traffic}), + warning => $warning, + critical => $critical, + min => 0, max => $self->{result_values}->{speed}); +} + +sub custom_traffic_threshold { + my ($self, %options) = @_; + + my $exit = 'ok'; + if ($instance_mode->{option_results}->{units_traffic} eq '%' && defined($self->{result_values}->{speed})) { + $exit = $self->{perfdata}->threshold_check(value => $self->{result_values}->{traffic_prct}, threshold => [ { label => 'critical-' . $self->{label}, exit_litteral => 'critical' }, { label => 'warning-' . $self->{label}, exit_litteral => 'warning' } ]); + } elsif ($instance_mode->{option_results}->{units_traffic} eq 'b/s') { + $exit = $self->{perfdata}->threshold_check(value => $self->{result_values}->{traffic}, threshold => [ { label => 'critical-' . $self->{label}, exit_litteral => 'critical' }, { label => 'warning-' . $self->{label}, exit_litteral => 'warning' } ]); + } + return $exit; +} + +sub custom_traffic_output { + my ($self, %options) = @_; + + my ($traffic_value, $traffic_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{traffic}, network => 1); + my ($total_value, $total_unit); + if (defined($self->{result_values}->{speed}) && $self->{result_values}->{speed} =~ /[0-9]/) { + ($total_value, $total_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{speed}, network => 1); + } + + my $msg = sprintf("Traffic %s : %s/s (%s on %s)", + ucfirst($self->{result_values}->{label}), $traffic_value . $traffic_unit, + defined($self->{result_values}->{traffic_prct}) ? sprintf("%.2f%%", $self->{result_values}->{traffic_prct}) : '-', + defined($total_value) ? $total_value . $total_unit : '-'); + return $msg; +} + +sub custom_traffic_calc { + my ($self, %options) = @_; + + $self->{result_values}->{label} = $options{extra_options}->{label_ref}; + $self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_display'}; + my $diff_traffic = $options{new_datas}->{$self->{instance} . '_' . $self->{result_values}->{label}} - $options{old_datas}->{$self->{instance} . '_' . $self->{result_values}->{label}}; + $self->{result_values}->{traffic} = $diff_traffic / $options{delta_time}; + if (defined($instance_mode->{option_results}->{'speed_' . $self->{result_values}->{label}}) && $instance_mode->{option_results}->{'speed_' . $self->{result_values}->{label}} =~ /[0-9]/) { + $self->{result_values}->{traffic_prct} = $self->{result_values}->{traffic} * 100 / ($instance_mode->{option_results}->{'speed_' . $self->{result_values}->{label}} * 1000 * 1000); + $self->{result_values}->{speed} = $instance_mode->{option_results}->{'speed_' . $self->{result_values}->{label}} * 1000 * 1000; + } + return 0; +} + sub set_counters { my ($self, %options) = @_; $self->{maps_counters_type} = [ { name => 'global', type => 0 }, - { name => 'device', type => 1, cb_prefix_output => 'prefix_device_output', message_multiple => 'All devices are ok' } + { name => 'device', type => 1, cb_prefix_output => 'prefix_device_output', message_multiple => 'All devices are ok' }, + { name => 'interface', type => 1, cb_prefix_output => 'prefix_interface_output', message_multiple => 'All device interfaces are ok', skipped_code => { -10 => 1 } }, ]; $self->{maps_counters}->{global} = [ { label => 'total-devices', set => { @@ -103,19 +171,44 @@ sub set_counters { } }, ]; + + $self->{maps_counters}->{interface} = [ + { label => 'in', set => { + key_values => [ { name => 'in', diff => 1 }, { name => 'display' } ], + per_second => 1, + closure_custom_calc => $self->can('custom_traffic_calc'), closure_custom_calc_extra_options => { label_ref => 'in' }, + closure_custom_output => $self->can('custom_traffic_output'), + closure_custom_perfdata => $self->can('custom_traffic_perfdata'), + closure_custom_threshold_check => $self->can('custom_traffic_threshold'), + } + }, + { label => 'out', set => { + key_values => [ { name => 'out', diff => 1 }, { name => 'display' } ], + per_second => 1, + closure_custom_calc => $self->can('custom_traffic_calc'), closure_custom_calc_extra_options => { label_ref => 'out' }, + closure_custom_output => $self->can('custom_traffic_output'), + closure_custom_perfdata => $self->can('custom_traffic_perfdata'), + closure_custom_threshold_check => $self->can('custom_traffic_threshold'), + } + }, + ]; } sub new { my ($class, %options) = @_; - my $self = $class->SUPER::new(package => __PACKAGE__, %options); + my $self = $class->SUPER::new(package => __PACKAGE__, %options, statefile => 1); bless $self, $class; $self->{version} = '1.0'; $options{options}->add_options(arguments => { "filter-name:s" => { name => 'filter_name' }, + "filter-interface:s" => { name => 'filter_interface' }, "warning-status:s" => { name => 'warning_status', default => '' }, "critical-status:s" => { name => 'critical_status', default => '%{status} =~ /offline/' }, + "speed-in:s" => { name => 'speed_in' }, + "speed-out:s" => { name => 'speed_out' }, + "units-traffic:s" => { name => 'units_traffic', default => '%' }, }); return $self; @@ -135,6 +228,12 @@ sub prefix_device_output { return "Device '" . $options{instance_value}->{display} . "' "; } +sub prefix_interface_output { + my ($self, %options) = @_; + + return "Interface '" . $options{instance_value}->{display} . "' "; +} + sub change_macros { my ($self, %options) = @_; @@ -150,33 +249,74 @@ my %map_status = ( 1 => 'online', ); my $mapping = { + devMac => { oid => '.1.3.6.1.4.1.29671.1.1.4.1.1' }, devName => { oid => '.1.3.6.1.4.1.29671.1.1.4.1.2' }, devStatus => { oid => '.1.3.6.1.4.1.29671.1.1.4.1.3', map => \%map_status }, devClientCount => { oid => '.1.3.6.1.4.1.29671.1.1.4.1.5' }, }; my $oid_devEntry = '.1.3.6.1.4.1.29671.1.1.4.1'; +my $mapping2 = { + devInterfaceName => { oid => '.1.3.6.1.4.1.29671.1.1.5.1.3' }, + devInterfaceSentBytes => { oid => '.1.3.6.1.4.1.29671.1.1.5.1.6' }, + devInterfaceRecvBytes => { oid => '.1.3.6.1.4.1.29671.1.1.5.1.7' }, +}; sub manage_selection { my ($self, %options) = @_; $self->{device} = {}; + $self->{interface} = {}; $self->{global} = { total => 0 }; - my $results = $options{snmp}->get_table(oid => $oid_devEntry, nothing_quit => 1); - foreach my $oid (keys %{$results}) { + + my $snmp_result = $options{snmp}->get_multiple_table(oids => + [ { oid => $oid_devEntry, end => $mapping->{devClientCount}->{oid} }, + { oid => $mapping2->{devInterfaceName}->{oid} }, + ], nothing_quit => 1); + + foreach my $oid (keys %{$snmp_result->{ $oid_devEntry }}) { next if ($oid !~ /^$mapping->{devName}->{oid}\.(.*)$/); my $instance = $1; - my $result = $options{snmp}->map_instance(mapping => $mapping, results => $results, instance => $instance); + my $result = $options{snmp}->map_instance(mapping => $mapping, results => $snmp_result->{$oid_devEntry}, instance => $instance); if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' && $result->{devName} !~ /$self->{option_results}->{filter_name}/) { - $self->{output}->output_add(long_msg => "skipping '" . $result->{devName} . "': no matching filter.", debug => 1); + $self->{output}->output_add(long_msg => "skipping device '" . $result->{devName} . "': no matching filter.", debug => 1); next; } + foreach (keys %{$snmp_result->{ $mapping2->{devInterfaceName}->{oid} }}) { + next if (!/^$mapping2->{devInterfaceName}->{oid}\.$instance\.(.*)/); + + my $index = $1; + my $interface_name = $snmp_result->{ $mapping2->{devInterfaceName}->{oid} }->{$_}; + if (defined($self->{option_results}->{filter_interface}) && $self->{option_results}->{filter_interface} ne '' && + $interface_name !~ /$self->{option_results}->{filter_interface}/) { + $self->{output}->output_add(long_msg => "skipping interface '" . $result->{devName} . '.' . $interface_name . "': no matching filter.", debug => 1); + next; + } + + $self->{interface}->{$instance . '.' . $index} = { display => $result->{devName} . '.' . $interface_name }; + } + $self->{global}->{total}++; $self->{device}->{$instance} = { display => $result->{devName}, status => $result->{devStatus}, clients => $result->{devClientCount}}; } + + $options{snmp}->load(oids => [$mapping2->{devInterfaceSentBytes}->{oid}, $mapping2->{devInterfaceRecvBytes}->{oid}], + instances => [keys %{$self->{interface}}], instance_regexp => '^(.*)$'); + $snmp_result = $options{snmp}->get_leef(nothing_quit => 1); + foreach (keys %{$self->{interface}}) { + my $result = $options{snmp}->map_instance(mapping => $mapping2, results => $snmp_result, instance => $_); + + $self->{interface}->{$_}->{in} = $result->{devInterfaceRecvBytes} * 8; + $self->{interface}->{$_}->{out} = $result->{devInterfaceSentBytes} * 8; + } + + $self->{cache_name} = "cisco_meraki_" . $self->{mode} . '_' . $options{snmp}->get_hostname() . '_' . $options{snmp}->get_port() . '_' . + (defined($self->{option_results}->{filter_counters}) ? md5_hex($self->{option_results}->{filter_counters}) : md5_hex('all')) . '_' . + (defined($self->{option_results}->{filter_name}) ? md5_hex($self->{option_results}->{filter_name}) : md5_hex('all')) . '_' . + (defined($self->{option_results}->{filter_interface}) ? md5_hex($self->{option_results}->{filter_interface}) : md5_hex('all')); } 1; @@ -198,6 +338,22 @@ Example: --filter-counters='^clients$' Filter device name (can be a regexp). +=item B<--filter-interface> + +Filter interface name (can be a regexp). + +=item B<--speed-in> + +Set interface speed for incoming traffic (in Mb). + +=item B<--speed-out> + +Set interface speed for outgoing traffic (in Mb). + +=item B<--units-traffic> + +Units of thresholds for the traffic (Default: '%') ('%', 'b/s'). + =item B<--warning-status> Set warning threshold for status. @@ -211,12 +367,12 @@ Can used special variables like: %{status}, %{display} =item B<--warning-*> Threshold warning. -Can be: 'total-devices', 'clients'. +Can be: 'total-devices', 'clients', 'in', 'out'. =item B<--critical-*> Threshold critical. -Can be: 'total-devices', 'clients'. +Can be: 'total-devices', 'clients', 'in', 'out'. =back