(plugin) apps::protocols::snmp - add snmp cache system (#4443)
This commit is contained in:
parent
4f8e3a2ea9
commit
1b79704575
|
@ -0,0 +1,115 @@
|
|||
#
|
||||
# Copyright 2023 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 apps::protocols::snmp::mode::cache;
|
||||
|
||||
use base qw(centreon::plugins::mode);
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use JSON::XS;
|
||||
|
||||
sub new {
|
||||
my ($class, %options) = @_;
|
||||
my $self = $class->SUPER::new(package => __PACKAGE__, %options);
|
||||
bless $self, $class;
|
||||
|
||||
$options{options}->add_options(arguments => {
|
||||
'file:s' => { name => 'file' },
|
||||
'snmpwalk:s@' => { name => 'snmpwalk' },
|
||||
'snmpget:s@' => { name => 'snmpget' }
|
||||
});
|
||||
|
||||
return $self;
|
||||
}
|
||||
|
||||
sub check_options {
|
||||
my ($self, %options) = @_;
|
||||
$self->SUPER::init(%options);
|
||||
|
||||
if (!defined($self->{option_results}->{file}) || $self->{option_results}->{file} eq '') {
|
||||
$self->{output}->add_option_msg(short_msg => "Missing parameter --file");
|
||||
$self->{output}->option_exit();
|
||||
}
|
||||
}
|
||||
|
||||
sub run {
|
||||
my ($self, %options) = @_;
|
||||
|
||||
my $snmp_datas = {};
|
||||
if (defined($self->{option_results}->{snmpwalk})) {
|
||||
foreach my $oid (@{$self->{option_results}->{snmpwalk}}) {
|
||||
my $result = $options{snmp}->get_table(oid => $oid);
|
||||
$snmp_datas = { %$snmp_datas, %$result };
|
||||
}
|
||||
}
|
||||
|
||||
if (defined($self->{option_results}->{snmpget})) {
|
||||
my $result = $options{snmp}->get_leef(oids => $self->{option_results}->{snmpget});
|
||||
$snmp_datas = { %$snmp_datas, %$result };
|
||||
}
|
||||
|
||||
my $json;
|
||||
eval {
|
||||
$json = JSON::XS->new->encode($snmp_datas);
|
||||
};
|
||||
|
||||
my $fh;
|
||||
if (!open($fh, '>', $self->{option_results}->{file})) {
|
||||
$self->{output}->add_option_msg(short_msg => "Can't open file '$self->{option_results}->{file}': $!");
|
||||
$self->{output}->option_exit();
|
||||
}
|
||||
print $fh $json;
|
||||
close($fh);
|
||||
|
||||
$self->{output}->output_add(
|
||||
severity => 'OK',
|
||||
short_msg => 'SNMP cache file created'
|
||||
);
|
||||
|
||||
$self->{output}->display(force_ignore_perfdata => 1);
|
||||
$self->{output}->exit();
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
||||
=head1 MODE
|
||||
|
||||
Cache SNMP datas in a JSON cache file.
|
||||
|
||||
=over 8
|
||||
|
||||
=item B<--file>
|
||||
|
||||
JSON cache file path.
|
||||
|
||||
=item B<--snmpget>
|
||||
|
||||
Retrieve a management value.
|
||||
|
||||
=item B<--snmpwalk>
|
||||
|
||||
Retrieve a subtree of management values.
|
||||
|
||||
=back
|
||||
|
||||
=cut
|
|
@ -30,6 +30,7 @@ sub new {
|
|||
bless $self, $class;
|
||||
|
||||
$self->{modes} = {
|
||||
'cache' => 'apps::protocols::snmp::mode::cache',
|
||||
'collection' => 'apps::protocols::snmp::mode::collection',
|
||||
'discovery' => 'snmp_standard::mode::discovery',
|
||||
'dynamic-command' => 'snmp_standard::mode::dynamiccommand',
|
||||
|
|
|
@ -22,6 +22,7 @@ package centreon::plugins::snmp;
|
|||
|
||||
use strict;
|
||||
use warnings;
|
||||
use centreon::plugins::misc;
|
||||
use SNMP;
|
||||
use Socket;
|
||||
use POSIX;
|
||||
|
@ -54,6 +55,7 @@ sub new {
|
|||
'maxrepetitions:s' => { name => 'maxrepetitions', default => 50 },
|
||||
'subsetleef:s' => { name => 'subsetleef', default => 50 },
|
||||
'subsettable:s' => { name => 'subsettable', default => 100 },
|
||||
'snmp-cache-file:s' => { name => 'snmp_cache_file' },
|
||||
'snmp-autoreduce:s' => { name => 'snmp_autoreduce' },
|
||||
'snmp-force-getnext' => { name => 'snmp_force_getnext' },
|
||||
'snmp-username:s' => { name => 'snmp_security_name' },
|
||||
|
@ -221,6 +223,24 @@ sub autoreduce_leef {
|
|||
return 0;
|
||||
}
|
||||
|
||||
sub get_leef_cache {
|
||||
my ($self, %options) = @_;
|
||||
|
||||
my $results = {};
|
||||
foreach my $oid (@{$options{oids}}) {
|
||||
if (defined($self->{snmp_cache}->{$oid})) {
|
||||
$results->{$oid} = $self->{snmp_cache}->{$oid};
|
||||
}
|
||||
}
|
||||
|
||||
if ($options{nothing_quit} == 1 && scalar(keys %$results) <= 0) {
|
||||
$self->{output}->add_option_msg(short_msg => 'SNMP GET Request: Cant get a single value.');
|
||||
$self->{output}->option_exit(exit_litteral => $self->{snmp_errors_exit});
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
sub get_leef {
|
||||
my ($self, %options) = @_;
|
||||
# $options{dont_quit} = integer
|
||||
|
@ -247,6 +267,10 @@ sub get_leef {
|
|||
@{$self->{oids_loaded}} = ();
|
||||
}
|
||||
|
||||
if ($self->{use_snmp_cache} == 1) {
|
||||
return $self->get_leef_cache(oids => $options{oids}, nothing_quit => $nothing_quit);
|
||||
}
|
||||
|
||||
my $results = {};
|
||||
$self->{array_ref_ar} = [];
|
||||
my $subset_current = 0;
|
||||
|
@ -396,6 +420,43 @@ sub multiple_find_bigger {
|
|||
return $getting->{pop(@values)};
|
||||
}
|
||||
|
||||
sub get_multiple_table_cache {
|
||||
my ($self, %options) = @_;
|
||||
|
||||
my $results = {};
|
||||
foreach my $entry (@{$options{oids}}) {
|
||||
my $result = $self->get_table_cache(
|
||||
oid => $entry->{oid},
|
||||
start => $entry->{start},
|
||||
end => $entry->{end},
|
||||
nothing_quit => 0
|
||||
);
|
||||
if ($options{return_type} == 0) {
|
||||
$results->{ $entry->{oid} } = $result;
|
||||
} else {
|
||||
$results = { %$results, %$result };
|
||||
}
|
||||
}
|
||||
|
||||
my $total = 0;
|
||||
if ($options{nothing_quit} == 1) {
|
||||
if ($options{return_type} == 1) {
|
||||
$total = scalar(keys %$results);
|
||||
} else {
|
||||
foreach (keys %$results) {
|
||||
$total += scalar(keys %{$results->{$_}});
|
||||
}
|
||||
}
|
||||
|
||||
if ($total == 0) {
|
||||
$self->{output}->add_option_msg(short_msg => 'SNMP Table Request: Cant get a single value.');
|
||||
$self->{output}->option_exit(exit_litteral => $self->{snmp_errors_exit});
|
||||
}
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
sub get_multiple_table {
|
||||
my ($self, %options) = @_;
|
||||
# $options{dont_quit} = integer
|
||||
|
@ -408,6 +469,14 @@ sub get_multiple_table {
|
|||
my ($nothing_quit) = (defined($options{nothing_quit}) && $options{nothing_quit} == 1) ? 1 : 0;
|
||||
$self->set_error();
|
||||
|
||||
if ($self->{use_snmp_cache} == 1) {
|
||||
return $self->get_multiple_table_cache(
|
||||
oids => $options{oids},
|
||||
return_type => $return_type,
|
||||
nothing_quit => $nothing_quit
|
||||
);
|
||||
}
|
||||
|
||||
my $working_oids = {};
|
||||
my $results = {};
|
||||
# Check overlap
|
||||
|
@ -429,7 +498,7 @@ sub get_multiple_table {
|
|||
}
|
||||
|
||||
if ($return_type == 0) {
|
||||
$results->{$entry->{oid}} = {};
|
||||
$results->{ $entry->{oid} } = {};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -560,6 +629,29 @@ sub get_multiple_table {
|
|||
return $results;
|
||||
}
|
||||
|
||||
sub get_table_cache {
|
||||
my ($self, %options) = @_;
|
||||
|
||||
my $branch = defined($options{start}) ? $options{start} : $options{oid};
|
||||
|
||||
my $results = {};
|
||||
foreach my $oid ($self->oid_lex_sort(keys %{$self->{snmp_cache}})) {
|
||||
if ($oid =~ /^$branch\./) {
|
||||
$results->{$oid} = $self->{snmp_cache}->{$oid};
|
||||
if (defined($options{end}) && $self->check_oid_up(current => $oid, end => $options{end})) {
|
||||
last;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($options{nothing_quit} == 1 && scalar(keys %$results) <= 0) {
|
||||
$self->{output}->add_option_msg(short_msg => 'SNMP Table Request: Cant get a single value.');
|
||||
$self->{output}->option_exit(exit_litteral => $self->{snmp_errors_exit});
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
sub get_table {
|
||||
my ($self, %options) = @_;
|
||||
# $options{dont_quit} = integer
|
||||
|
@ -578,6 +670,15 @@ sub get_table {
|
|||
$options{end} = $self->clean_oid($options{end});
|
||||
}
|
||||
|
||||
if ($self->{use_snmp_cache} == 1) {
|
||||
return $self->get_table_cache(
|
||||
oid => $options{oid},
|
||||
start => $options{start},
|
||||
end => $options{end},
|
||||
nothing_quit => $nothing_quit
|
||||
);
|
||||
}
|
||||
|
||||
# we use a medium (UDP have a PDU limit. SNMP protcol cant send multiples for one request)
|
||||
# So we need to manage
|
||||
# It's for "bulk". We ask 50 next values. If you set 1, it's like a getnext (snmp v1)
|
||||
|
@ -597,7 +698,7 @@ sub get_table {
|
|||
$self->{output}->option_exit(exit_litteral => $self->{snmp_errors_exit});
|
||||
}
|
||||
|
||||
my $main_indice = $1 . "." . $2;
|
||||
my $main_indice = $1 . '.' . $2;
|
||||
my $results = {};
|
||||
|
||||
# Quit if base not the same or 'ENDOFMIBVIEW' value
|
||||
|
@ -751,7 +852,28 @@ sub check_oid_up {
|
|||
|
||||
sub check_options {
|
||||
my ($self, %options) = @_;
|
||||
# $options{option_results} = ref to options result
|
||||
|
||||
$self->{snmp_errors_exit} = $options{option_results}->{snmp_errors_exit};
|
||||
|
||||
$self->{use_snmp_cache} = 0;
|
||||
if (defined($options{option_results}->{snmp_cache_file}) && $options{option_results}->{snmp_cache_file} ne '') {
|
||||
centreon::plugins::misc::mymodule_load(
|
||||
output => $self->{output},
|
||||
module => 'JSON::XS',
|
||||
error_msg => "Cannot load module 'JSON::XS'."
|
||||
);
|
||||
my $content = centreon::plugins::misc::slurp_file(output => $self->{output}, file => $options{option_results}->{snmp_cache_file});
|
||||
eval {
|
||||
$self->{snmp_cache} = JSON::XS->new->decode($content);
|
||||
};
|
||||
if ($@) {
|
||||
$self->{output}->add_option_msg(short_msg => "Cannot decode json cache file: $@");
|
||||
$self->{output}->option_exit();
|
||||
}
|
||||
|
||||
$self->{use_snmp_cache} = 1;
|
||||
return ;
|
||||
}
|
||||
|
||||
if (!defined($options{option_results}->{host})) {
|
||||
$self->{output}->add_option_msg(short_msg => 'Missing parameter --hostname.');
|
||||
|
@ -768,7 +890,6 @@ sub check_options {
|
|||
$self->{maxrepetitions} = $options{option_results}->{maxrepetitions};
|
||||
$self->{subsetleef} = (defined($options{option_results}->{subsetleef}) && $options{option_results}->{subsetleef} =~ /^[0-9]+$/) ? $options{option_results}->{subsetleef} : 50;
|
||||
$self->{subsettable} = (defined($options{option_results}->{subsettable}) && $options{option_results}->{subsettable} =~ /^[0-9]+$/) ? $options{option_results}->{subsettable} : 100;
|
||||
$self->{snmp_errors_exit} = $options{option_results}->{snmp_errors_exit};
|
||||
$self->{snmp_autoreduce} = 0;
|
||||
$self->{snmp_autoreduce_divisor} = 2;
|
||||
if (defined($options{option_results}->{snmp_autoreduce})) {
|
||||
|
@ -1023,6 +1144,10 @@ Auto reduce SNMP request size in case of SNMP errors (By default, the divisor is
|
|||
|
||||
Use snmp getnext function (even in snmp v2c and v3).
|
||||
|
||||
=item B<--snmp-cache-file>
|
||||
|
||||
Use SNMP cache file.
|
||||
|
||||
=item B<--snmp-username>
|
||||
|
||||
Security name (only for SNMP v3).
|
||||
|
|
Loading…
Reference in New Issue