centreon-plugins/apps/protocols/snmp/mode/collection.pm

1481 lines
57 KiB
Perl

#
# 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 apps::protocols::snmp::mode::collection;
use base qw(centreon::plugins::templates::counter);
use strict;
use warnings;
use JSON::XS;
use Safe;
use centreon::plugins::statefile;
use Digest::MD5 qw(md5_hex);
sub custom_select_threshold {
my ($self, %options) = @_;
my $status = 'ok';
my $message;
eval {
local $SIG{__WARN__} = sub { $message = $_[0]; };
local $SIG{__DIE__} = sub { $message = $_[0]; };
our $expand = $self->{result_values}->{expand};
if (defined($self->{result_values}->{config}->{critical}) && $self->{result_values}->{config}->{critical} &&
$self->{instance_mode}->{safe}->reval($self->{result_values}->{config}->{critical})) {
$status = 'critical';
} elsif (defined($self->{result_values}->{config}->{warning}) && $self->{result_values}->{config}->{warning} ne '' &&
$self->{instance_mode}->{safe}->reval($self->{result_values}->{config}->{warning})) {
$status = 'warning';
} elsif (defined($self->{result_values}->{config}->{unknown}) && $self->{result_values}->{config}->{unknown} &&
$self->{instance_mode}->reval($self->{result_values}->{config}->{unknown})) {
$status = 'unknown';
}
if ($@) {
$self->{output}->add_option_msg(short_msg => 'Unsafe code evaluation: ' . $@);
$self->{output}->option_exit();
}
};
if (defined($message)) {
$self->{output}->output_add(long_msg => 'filter status issue: ' . $message);
}
$self->{result_values}->{last_status} = $status;
return $status;
}
sub custom_select_perfdata {
my ($self, %options) = @_;
return if (!defined($self->{result_values}->{config}->{perfdatas}));
foreach (@{$self->{result_values}->{config}->{perfdatas}}) {
next if (!defined($_->{value}) || $_->{value} !~ /^\d+(?:\.\d+)?$/);
$self->{output}->perfdata_add(%$_);
}
}
sub custom_select_output {
my ($self, %options) = @_;
return '' if (
$self->{result_values}->{last_status} eq 'ok' && defined($self->{result_values}->{config}->{formatting}) &&
defined($self->{result_values}->{config}->{formatting}->{display_ok}) &&
$self->{result_values}->{config}->{formatting}->{display_ok} =~ /^false|0$/
);
my $format;
if (defined($self->{result_values}->{config}->{ 'formatting_' . $self->{result_values}->{last_status} })) {
$format = $self->{result_values}->{config}->{ 'formatting_' . $self->{result_values}->{last_status} };
} elsif (defined($self->{result_values}->{config}->{formatting})) {
$format = $self->{result_values}->{config}->{formatting};
}
if (defined($format)) {
return sprintf(
$format->{printf_msg}, @{$format->{printf_var}}
);
}
# without formatting: [name: xxxxxx][test: xxxx][test2: xxx][mytable.plcRead: xxx][mytable.plcWrite: xxx]
my $output = '';
foreach (sort keys %{$self->{result_values}->{expand}}) {
next if (/^(?:constants|builtin)\./);
$output .= '[' . $_ . ': ' . $self->{result_values}->{expand}->{$_} . ']';
}
return $output;
}
sub set_counters {
my ($self, %options) = @_;
$self->{maps_counters_type} = [
{ name => 'selections', type => 1, message_multiple => 'All selections are ok', skipped_code => { -10 => 1 } }
];
$self->{maps_counters}->{selections} = [
{ label => 'select', threshold => 0, set => {
key_values => [ { name => 'expand' }, { name => 'config' } ],
closure_custom_output => $self->can('custom_select_output'),
closure_custom_perfdata => $self->can('custom_select_perfdata'),
closure_custom_threshold_check => $self->can('custom_select_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 => {
'config:s' => { name => 'config' },
'filter-selection:s%' => { name => 'filter_selection' },
'constant:s%' => { name => 'constant' }
});
$self->{safe} = Safe->new();
$self->{safe}->share('$expand');
$self->{safe_func} = Safe->new();
$self->{safe_func}->share('$assign_var');
$self->{builtin} = {};
$self->{snmp_cache} = centreon::plugins::statefile->new(%options);
return $self;
}
sub check_options {
my ($self, %options) = @_;
$self->SUPER::check_options(%options);
if (!defined($self->{option_results}->{config})) {
$self->{output}->add_option_msg(short_msg => 'Please set config option');
$self->{output}->option_exit();
}
$self->{snmp_cache}->check_options(option_results => $self->{option_results});
}
sub read_config {
my ($self, %options) = @_;
my $content;
if ($self->{option_results}->{config} =~ /\n/m || ! -f "$self->{option_results}->{config}") {
$content = $self->{option_results}->{config};
} else {
$content = do {
local $/ = undef;
if (!open my $fh, '<', $self->{option_results}->{config}) {
$self->{output}->add_option_msg(short_msg => "Could not open file $self->{option_results}->{config} : $!");
$self->{output}->option_exit();
}
<$fh>;
};
}
eval {
$self->{config} = JSON::XS->new->decode($content);
};
if ($@) {
$self->{output}->output_add(long_msg => "json config error: $@", debug => 1);
$self->{output}->add_option_msg(short_msg => 'Cannot decode json config');
$self->{output}->option_exit();
}
}
sub get_map_value {
my ($self, %options) = @_;
return undef if (
!defined($self->{config}->{mapping}) ||
!defined($self->{config}->{mapping}->{ $options{map} })
);
return '' if (!defined($self->{config}->{mapping}->{ $options{map} }->{ $options{value} }));
return $self->{config}->{mapping}->{ $options{map} }->{ $options{value} };
}
sub validate_name {
my ($self, %options) = @_;
if (!defined($options{name})) {
$self->{output}->add_option_msg(short_msg => "name attribute is missing $options{section}");
$self->{output}->option_exit();
}
if ($options{name} !~ /^[a-zA-Z0-9]+$/) {
$self->{output}->add_option_msg(short_msg => 'incorrect name attribute: ' . $options{name});
$self->{output}->option_exit();
}
}
sub collect_snmp_tables {
my ($self, %options) = @_;
return if (!defined($self->{config}->{snmp}->{tables}));
foreach my $table (@{$self->{config}->{snmp}->{tables}}) {
$self->validate_name(name => $table->{name}, section => "[snmp > tables]");
if (!defined($table->{oid}) || $table->{oid} eq '') {
$self->{output}->add_option_msg(short_msg => "oid attribute is missing [snmp > tables > $table->{name}]");
$self->{output}->option_exit();
}
if (!defined($table->{entries})) {
$self->{output}->add_option_msg(short_msg => "entries section is missing [snmp > tables > $table->{name}]");
$self->{output}->option_exit();
}
my $mapping = {};
my $sampling = {};
foreach (@{$table->{entries}}) {
$self->validate_name(name => $_->{name}, section => "[snmp > tables > $table->{name}]");
if (!defined($_->{oid}) || $_->{oid} eq '') {
$self->{output}->add_option_msg(short_msg => "oid attribute is missing [snmp > tables > $table->{name} > $_->{name}]");
$self->{output}->option_exit();
}
$mapping->{ $_->{name} } = { oid => $_->{oid} };
$sampling->{ $_->{name} } = 1 if (defined($_->{sampling}) && $_->{sampling} == 1);
if (defined($_->{map}) && $_->{map} ne '') {
if (!defined($self->{config}->{mapping}) || !defined($self->{config}->{mapping}->{ $_->{map} })) {
$self->{output}->add_option_msg(short_msg => "unknown map attribute [snmp > tables > $table->{name} > $_->{name}]: $_->{map}");
$self->{output}->option_exit();
}
$mapping->{ $_->{name} }->{map} = $self->{config}->{mapping}->{ $_->{map} };
}
}
if (scalar(keys %$mapping) <= 0) {
$self->{output}->add_option_msg(short_msg => "entries section is empty [snmp > tables > $table->{name}]");
$self->{output}->option_exit();
}
$self->{snmp_collected}->{tables}->{ $table->{name} } = {};
my $used_instance = defined($table->{used_instance}) && $table->{used_instance} ne '' ? $table->{used_instance} : '\.(\d+)$';
my $snmp_result = $options{snmp}->get_table(oid => $table->{oid});
foreach (keys %$snmp_result) {
/$used_instance/;
next if (defined($self->{snmp_collected}->{tables}->{ $table->{name} }->{$1}));
$self->{snmp_collected}->{tables}->{ $table->{name} }->{$1} = $options{snmp}->map_instance(mapping => $mapping, results => $snmp_result, instance => $1);
foreach my $sample_name (keys %$sampling) {
$self->{snmp_collected_sampling}->{tables}->{ $table->{name} } = {}
if (!defined($self->{snmp_collected_sampling}->{tables}->{ $table->{name} }));
$self->{snmp_collected_sampling}->{tables}->{ $table->{name} }->{$1}->{$sample_name} =
$self->{snmp_collected}->{tables}->{ $table->{name} }->{$1}->{$sample_name};
}
}
}
}
sub collect_snmp_leefs {
my ($self, %options) = @_;
return if (!defined($self->{config}->{snmp}->{leefs}));
my $oids = [ map($_->{oid}, @{$self->{config}->{snmp}->{leefs}}) ];
return if (scalar(@$oids) <= 0);
my $snmp_result = $options{snmp}->get_leef(oids => $oids);
foreach (@{$self->{config}->{snmp}->{leefs}}) {
$self->validate_name(name => $_->{name}, section => "[snmp > leefs]");
$self->{snmp_collected}->{leefs}->{ $_->{name} } = defined($_->{default}) ? $_->{default} : '';
next if (!defined($_->{oid}) || !defined($snmp_result->{ $_->{oid } }));
$self->{snmp_collected}->{leefs}->{ $_->{name} } = $snmp_result->{ $_->{oid } };
if (defined($_->{sampling}) && $_->{sampling} == 1) {
$self->{snmp_collected_sampling}->{leefs}->{ $_->{name} } = $snmp_result->{ $_->{oid } };
}
if (defined($_->{map}) && $_->{map} ne '') {
my $value = $self->get_map_value(value => $snmp_result->{ $_->{oid } }, map => $_->{map});
if (!defined($value)) {
$self->{output}->add_option_msg(short_msg => "unknown map attribute [snmp > leefs > $_->{name}]: $_->{map}");
$self->{output}->option_exit();
}
$self->{snmp_collected}->{leefs}->{ $_->{name} } = $value;
}
}
}
sub is_snmp_cache_enabled {
my ($self, %options) = @_;
return 0 if (
!defined($self->{config}->{snmp}->{cache}) ||
!defined($self->{config}->{snmp}->{cache}->{enable}) ||
$self->{config}->{snmp}->{cache}->{enable} !~ /^true|1$/i
);
return 1;
}
sub use_snmp_cache {
my ($self, %options) = @_;
return 0 if ($self->is_snmp_cache_enabled() == 0);
my $has_cache_file = $self->{snmp_cache}->read(
statefile => 'cache_snmp_collection_' . $options{snmp}->get_hostname() . '_' . $options{snmp}->get_port() . '_' .
md5_hex($self->{option_results}->{config})
);
$self->{snmp_collected} = $self->{snmp_cache}->get(name => 'snmp_collected');
my $reload = defined($self->{config}->{snmp}->{cache}->{reload}) && $self->{config}->{snmp}->{cache}->{reload} =~ /(\d+)/ ?
$self->{config}->{snmp}->{cache}->{reload} : 30;
return 0 if (
$has_cache_file == 0 ||
!defined($self->{snmp_collected}) ||
((time() - $self->{snmp_collected}->{epoch}) > ($reload * 60))
);
return 1;
}
sub save_snmp_cache {
my ($self, %options) = @_;
return 0 if ($self->is_snmp_cache_enabled() == 0);
$self->{snmp_cache}->write(data => { snmp_collected => $self->{snmp_collected} });
}
sub collect_snmp_sampling {
my ($self, %options) = @_;
return if ($self->{snmp_collected}->{sampling} == 0);
my $has_cache_file = $self->{snmp_cache}->read(
statefile => 'cache_snmp_collection_sampling_' . $options{snmp}->get_hostname() . '_' . $options{snmp}->get_port() . '_' .
md5_hex($self->{option_results}->{config})
);
my $snmp_collected_sampling_old = $self->{snmp_cache}->get(name => 'snmp_collected_sampling');
# with cache, we need to load the sampling cache maybe. please a statefile-suffix to get uniq files.
# sampling with a global cache can be a nonsense
if (!defined($self->{snmp_collected_sampling})) {
$self->{snmp_collected_sampling} = $snmp_collected_sampling_old;
}
my $delta_time;
if (defined($snmp_collected_sampling_old->{epoch})) {
$delta_time = $self->{snmp_collected_sampling}->{epoch} - $snmp_collected_sampling_old->{epoch};
$delta_time = 1 if ($delta_time <= 0);
}
foreach (keys %{$self->{snmp_collected_sampling}->{leefs}}) {
next if (!defined($snmp_collected_sampling_old->{leefs}->{$_}) || $snmp_collected_sampling_old->{leefs}->{$_} !~ /\d/);
my $old = $snmp_collected_sampling_old->{leefs}->{$_};
my $diff = $self->{snmp_collected_sampling}->{leefs}->{$_} - $old;
my $diff_counter = $diff;
$diff_counter = $self->{snmp_collected_sampling}->{leefs}->{$_} if ($diff_counter < 0);
$self->{snmp_collected}->{leefs}->{ $_ . 'Diff' } = $diff;
$self->{snmp_collected}->{leefs}->{ $_ . 'DiffCounter' } = $diff_counter;
if (defined($delta_time)) {
$self->{snmp_collected}->{leefs}->{ $_ . 'PerSeconds' } = $diff_counter / $delta_time;
$self->{snmp_collected}->{leefs}->{ $_ . 'PerMinutes' } = $diff_counter / $delta_time / 60;
}
}
foreach my $tbl_name (keys %{$self->{snmp_collected_sampling}->{tables}}) {
foreach my $instance (keys %{$self->{snmp_collected_sampling}->{tables}->{$tbl_name}}) {
foreach my $attr (keys %{$self->{snmp_collected_sampling}->{tables}->{$tbl_name}->{$instance}}) {
next if (
!defined($snmp_collected_sampling_old->{tables}->{$tbl_name}) ||
!defined($snmp_collected_sampling_old->{tables}->{$tbl_name}->{$instance}) ||
!defined($snmp_collected_sampling_old->{tables}->{$tbl_name}->{$instance}->{$attr}) ||
$snmp_collected_sampling_old->{tables}->{$tbl_name}->{$instance}->{$attr} !~ /\d/
);
my $old = $snmp_collected_sampling_old->{tables}->{$tbl_name}->{$instance}->{$attr};
my $diff = $self->{snmp_collected_sampling}->{tables}->{$tbl_name}->{$instance}->{$attr} - $old;
my $diff_counter = $diff;
$diff_counter = $self->{snmp_collected_sampling}->{tables}->{$tbl_name}->{$instance}->{$attr} if ($diff_counter < 0);
$self->{snmp_collected}->{tables}->{$tbl_name}->{$instance}->{ $attr . 'Diff' } = $diff;
$self->{snmp_collected}->{tables}->{$tbl_name}->{$instance}->{ $attr . 'DiffCounter' } = $diff_counter;
if (defined($delta_time)) {
$self->{snmp_collected}->{tables}->{$tbl_name}->{$instance}->{ $attr . 'PerSeconds' } = $diff_counter / $delta_time;
$self->{snmp_collected}->{tables}->{$tbl_name}->{$instance}->{ $attr . 'PerMinutes' } = $diff_counter / $delta_time / 60;
}
}
}
}
$self->{snmp_cache}->write(data => { snmp_collected_sampling => $self->{snmp_collected_sampling} });
}
sub collect_snmp {
my ($self, %options) = @_;
if (!defined($self->{config}->{snmp})) {
$self->{output}->add_option_msg(short_msg => 'please set snmp config');
$self->{output}->option_exit();
}
$self->add_builtin(name => 'currentTime', value => time());
if ($self->use_snmp_cache(snmp => $options{snmp}) == 0) {
$self->{snmp_collected_sampling} = { tables => {}, leefs => {}, epoch => time() };
$self->{snmp_collected} = { tables => {}, leefs => {}, epoch => time(), sampling => 0 };
$self->collect_snmp_tables(snmp => $options{snmp});
$self->collect_snmp_leefs(snmp => $options{snmp});
$self->{snmp_collected}->{sampling} = 1 if (
scalar(keys(%{$self->{snmp_collected_sampling}->{tables}})) > 0 ||
scalar(keys(%{$self->{snmp_collected_sampling}->{leefs}})) > 0
);
$self->save_snmp_cache();
}
$self->collect_snmp_sampling(snmp => $options{snmp});
}
sub exist_table_name {
my ($self, %options) = @_;
return 1 if (defined($self->{snmp_collected}->{tables}->{ $options{name} }));
return 0;
}
sub get_local_variable {
my ($self, %options) = @_;
return $self->{expand}->{ $options{name} };
}
sub set_local_variable {
my ($self, %options) = @_;
$self->{expand}->{ $options{name} } = $options{value};
}
sub get_leef_variable {
my ($self, %options) = @_;
return $self->{snmp_collected}->{leefs}->{ $options{name} };
}
sub set_leef_variable {
my ($self, %options) = @_;
$self->{snmp_collected}->{leefs}->{ $options{name} } = $options{value};
}
sub get_table {
my ($self, %options) = @_;
return undef if (
!defined($self->{snmp_collected}->{tables}->{ $options{table} })
);
return $self->{snmp_collected}->{tables}->{ $options{table} };
}
sub get_table_instance {
my ($self, %options) = @_;
return undef if (
!defined($self->{snmp_collected}->{tables}->{ $options{table} }) ||
!defined($self->{snmp_collected}->{tables}->{ $options{table} }->{ $options{instance} })
);
return $self->{snmp_collected}->{tables}->{ $options{table} }->{ $options{instance} };
}
sub get_table_attribute_value {
my ($self, %options) = @_;
return undef if (
!defined($self->{snmp_collected}->{tables}->{ $options{table} }) ||
!defined($self->{snmp_collected}->{tables}->{ $options{table} }->{ $options{instance} }) ||
!defined($self->{snmp_collected}->{tables}->{ $options{table} }->{ $options{instance} }->{ $options{attribute} })
);
return $self->{snmp_collected}->{tables}->{ $options{table} }->{ $options{instance} }->{ $options{attribute} };
}
sub set_table_attribute_value {
my ($self, %options) = @_;
$self->{snmp_collected}->{tables}->{ $options{table} } = {}
if (!defined($self->{snmp_collected}->{tables}->{ $options{table} }));
$self->{snmp_collected}->{tables}->{ $options{table} } = {}
if (!defined($self->{snmp_collected}->{tables}->{ $options{table} }->{ $options{instance} }));
$self->{snmp_collected}->{tables}->{ $options{table} }->{ $options{instance} }->{ $options{attribute} } = $options{value};
}
sub get_special_variable_value {
my ($self, %options) = @_;
my $data;
if ($options{type} == 0) {
$data = $self->get_local_variable(name => $options{label});
} elsif ($options{type} == 1) {
$data = $self->get_leef_variable(name => $options{label});
} elsif ($options{type} == 2) {
$data = $self->get_table(table => $options{table});
} elsif ($options{type} == 4) {
$data = $self->get_table_attribute_value(
table => $options{table},
instance => $options{instance},
attribute => $options{label}
);
}
return $data;
}
sub set_special_variable_value {
my ($self, %options) = @_;
my $data;
if ($options{type} == 0) {
$data = $self->set_local_variable(name => $options{label}, value => $options{value});
} elsif ($options{type} == 1) {
$data = $self->set_leef_variable(name => $options{label}, value => $options{value});
} elsif ($options{type} == 4) {
$data = $self->set_table_attribute_value(
table => $options{table},
instance => $options{instance},
attribute => $options{label},
value => $options{value}
);
}
return $data;
}
sub strcmp {
my ($self, %options) = @_;
my @cmp = split //, $options{test};
for (my $i = 0; $i < scalar(@cmp); $i++) {
return 0 if (
!defined($options{chars}->[ $options{start} + $i ]) ||
$options{chars}->[ $options{start} + $i ] ne $cmp[$i]
);
}
return 1;
}
sub parse_forward {
my ($self, %options) = @_;
my ($string, $i) = ('', 0);
while (1) {
return (1, 'cannot find ' . $options{stop} . ' character')
if (!defined($options{chars}->[ $options{start} + $i ]));
last if ($options{chars}->[ $options{start} + $i ] =~ /$options{stop}/);
return (1, "character '" . $options{chars}->[ $options{start} + $i ] . "' forbidden")
if ($options{chars}->[ $options{start} + $i ] !~ /$options{allowed}/);
$string .= $options{chars}->[ $options{start} + $i ];
$i++;
}
return (0, undef, $options{start} + $i, $string);
}
=pod
managed variables:
%(snmp.tables.plcData)
%(snmp.tables.plcData.[1])
%(snmp.tables.plcOther.[1].plop)
%(snmp.tables.plcOther.[%(mytable.instance)]
%(snmp.tables.plcOther.[%(snmp.tables.plcOther.[%(mytable.instance)].test)]
%(test2)
%(mytable.test)
result:
- type:
0=%(test) (label)
1=%(snmp.leefs.variable)
2=%(snmp.tables.test)
3=%(snmp.tables.test.[2])
4=%(snmp.tables.test.[2].attrname)
=cut
sub parse_snmp_tables {
my ($self, %options) = @_;
my ($code, $msg_error, $end, $table_label, $instance_label, $label);
($code, $msg_error, $end, $table_label) = $self->parse_forward(
chars => $options{chars},
start => $options{start},
allowed => '[a-zA-Z0-9]',
stop => '[).]'
);
if ($code) {
$self->{output}->add_option_msg(short_msg => $self->{current_section} . " $msg_error");
$self->{output}->option_exit();
}
if (!$self->exist_table_name(name => $table_label)) {
$self->{output}->add_option_msg(short_msg => $self->{current_section} . " unknown table '$table_label'");
$self->{output}->option_exit();
}
if ($options{chars}->[$end] eq ')') {
return { type => 2, end => $end, table => $table_label };
}
# instance part managenent
if (!defined($options{chars}->[$end + 1]) || $options{chars}->[$end + 1] ne '[') {
$self->{output}->add_option_msg(short_msg => $self->{current_section} . " special variable snmp.tables character '[' mandatory");
$self->{output}->option_exit();
}
if ($self->strcmp(chars => $options{chars}, start => $end + 2, test => '%(')) {
my $result = $self->parse_special_variable(chars => $options{chars}, start => $end + 2);
# type allowed: 0,1,4
if ($result->{type} !~ /^(?:0|1|4)$/) {
$self->{output}->add_option_msg(short_msg => $self->{current_section} . ' special variable type not allowed');
$self->{output}->option_exit();
}
$end = $result->{end} + 1;
if ($result->{type} == 0) {
$instance_label = $self->get_local_variable(name => $result->{label});
} elsif ($result->{type} == 1) {
$instance_label = $self->get_leef_variable(name => $result->{label});
} elsif ($result->{type} == 4) {
$instance_label = $self->get_table_attribute_value(
table => $result->{table},
instance => $result->{instance},
attribute => $result->{label}
);
}
$instance_label = defined($instance_label) ? $instance_label : '';
} else {
($code, $msg_error, $end, $instance_label) = $self->parse_forward(
chars => $options{chars},
start => $end + 2,
allowed => '[0-9\.]',
stop => '[\]]'
);
if ($code) {
$self->{output}->add_option_msg(short_msg => $self->{current_section} . " $msg_error");
$self->{output}->option_exit();
}
}
if (!defined($options{chars}->[$end + 1]) ||
$options{chars}->[$end + 1] !~ /[.)]/) {
$self->{output}->add_option_msg(short_msg => $self->{current_section} . ' special variable snmp.tables character [.)] missing');
$self->{output}->option_exit();
}
if ($options{chars}->[$end + 1] eq ')') {
return { type => 3, end => $end + 1, table => $table_label, instance => $instance_label };
}
($code, $msg_error, $end, $label) = $self->parse_forward(
chars => $options{chars},
start => $end + 2,
allowed => '[a-zA-Z0-9]',
stop => '[)]'
);
if ($code) {
$self->{output}->add_option_msg(short_msg => $self->{current_section} . " $msg_error");
$self->{output}->option_exit();
}
return { type => 4, end => $end, table => $table_label, instance => $instance_label, label => $label };
}
sub parse_snmp_type {
my ($self, %options) = @_;
if ($self->strcmp(chars => $options{chars}, start => $options{start}, test => 'leefs.')) {
my ($code, $msg_error, $end, $label) = $self->parse_forward(
chars => $options{chars},
start => $options{start} + 6,
allowed => '[a-zA-Z0-9]',
stop => '[)]'
);
if ($code) {
$self->{output}->add_option_msg(short_msg => $self->{current_section} . " $msg_error");
$self->{output}->option_exit();
}
return { type => 1, end => $end, label => $label };
} elsif ($self->strcmp(chars => $options{chars}, start => $options{start}, test => 'tables.')) {
return $self->parse_snmp_tables(chars => $options{chars}, start => $options{start} + 7);
} else {
$self->{output}->add_option_msg(short_msg => $self->{current_section} . ' special variable snmp not followed by leefs/tables');
$self->{output}->option_exit();
}
}
sub parse_special_variable {
my ($self, %options) = @_;
my $start = $options{start};
if ($options{chars}->[$start] ne '%' ||
$options{chars}->[$start + 1] ne '(') {
$self->{output}->add_option_msg(short_msg => $self->{current_section} . ' special variable not starting by %(');
$self->{output}->option_exit();
}
my $result = { start => $options{start} };
if ($self->strcmp(chars => $options{chars}, start => $start + 2, test => 'snmp.')) {
my $parse = $self->parse_snmp_type(chars => $options{chars}, start => $start + 2 + 5);
$result = { %$parse, %$result };
} else {
my ($code, $msg_error, $end, $label) = $self->parse_forward(
chars => $options{chars},
start => $start + 2,
allowed => '[a-zA-Z0-9.]',
stop => '[)]'
);
if ($code) {
$self->{output}->add_option_msg(short_msg => $self->{current_section} . " $msg_error");
$self->{output}->option_exit();
}
$result->{end} = $end;
$result->{type} = 0;
$result->{label} = $label;
}
return $result;
}
sub substitute_string {
my ($self, %options) = @_;
my $arr = [split //, $options{value}];
my $results = {};
my $last_end = -1;
while ($options{value} =~ /\Q%(\E/g) {
next if ($-[0] < $last_end);
my $result = $self->parse_special_variable(chars => $arr, start => $-[0]);
if ($result->{type} !~ /^(?:0|1|4)$/) {
$self->{output}->add_option_msg(short_msg => $self->{current_section} . " special variable type not allowed");
$self->{output}->option_exit();
}
$last_end = $result->{end};
$results->{ $result->{start} } = $result;
}
my $end = -1;
my $str = '';
for (my $i = 0; $i < scalar(@$arr); $i++) {
next if ($i <= $end);
if (defined($results->{$i})) {
my $data = $self->get_special_variable_value(%{$results->{$i}});
$end = $results->{$i}->{end};
$str .= defined($data) ? $data : '';
} else {
$str .= $arr->[$i];
}
}
return $str;
}
sub add_builtin {
my ($self, %options) = @_;
$self->{builtin}->{ $options{name} } = $options{value};
}
sub set_builtin {
my ($self, %options) = @_;
foreach (keys %{$self->{builtin}}) {
$self->{expand}->{ 'builtin.' . $_ } = $self->{builtin}->{$_};
}
}
sub set_constants {
my ($self, %options) = @_;
my $constants = {};
if (defined($self->{config}->{constants})) {
foreach (keys %{$self->{config}->{constants}}) {
$constants->{'constants.' . $_} = $self->{config}->{constants}->{$_};
}
}
foreach (keys %{$self->{option_results}->{constant}}) {
$constants->{'constants.' . $_} = $self->{option_results}->{constant}->{$_};
}
return $constants;
}
sub set_expand_table {
my ($self, %options) = @_;
return if (!defined($options{expand}));
foreach my $name (keys %{$options{expand}}) {
$self->{current_section} = '[' . $options{section} . ' > ' . $name . ']';
my $result = $self->parse_special_variable(chars => [split //, $options{expand}->{$name}], start => 0);
if ($result->{type} != 3) {
$self->{output}->add_option_msg(short_msg => $self->{current_section} . " special variable type not allowed");
$self->{output}->option_exit();
}
my $table = $self->get_table_instance(table => $result->{table}, instance => $result->{instance});
next if (!defined($table));
$self->{expand}->{ $name . '.instance' } = $result->{instance};
foreach (keys %$table) {
$self->{expand}->{ $name . '.' . $_ } = $table->{$_};
}
}
}
sub set_expand {
my ($self, %options) = @_;
return if (!defined($options{expand}));
foreach my $name (keys %{$options{expand}}) {
$self->{current_section} = '[' . $options{section} . ' > ' . $name . ']';
$self->{expand}->{$name} = $self->substitute_string(value => $options{expand}->{$name});
}
}
sub exec_func_map {
my ($self, %options) = @_;
if (!defined($options{map_name}) || $options{map_name} eq '') {
$self->{output}->add_option_msg(short_msg => "$self->{current_section} please set map_name attribute");
$self->{output}->option_exit();
}
if (!defined($options{src}) || $options{src} eq '') {
$self->{output}->add_option_msg(short_msg => "$self->{current_section} please set src attribute");
$self->{output}->option_exit();
}
my $result = $self->parse_special_variable(chars => [split //, $options{src}], start => 0);
if ($result->{type} !~ /^(?:0|1|4)$/) {
$self->{output}->add_option_msg(short_msg => $self->{current_section} . " special variable type not allowed in src attribute");
$self->{output}->option_exit();
}
my $data = $self->get_special_variable_value(%$result);
my $value = $self->get_map_value(value => $data, map => $options{map_name});
if (!defined($value)) {
$self->{output}->add_option_msg(short_msg => "$self->{current_section} unknown map attribute: $options{map_name}");
$self->{output}->option_exit();
}
my $save = $result;
if (defined($options{save}) && $options{save} ne '') {
$save = $self->parse_special_variable(chars => [split //, $options{save}], start => 0);
if ($save->{type} !~ /^(?:0|1|4)$/) {
$self->{output}->add_option_msg(short_msg => $self->{current_section} . " special variable type not allowed in save attribute");
$self->{output}->option_exit();
}
} elsif (defined($options{dst}) && $options{dst} ne '') {
$save = $self->parse_special_variable(chars => [split //, $options{dst}], start => 0);
if ($save->{type} !~ /^(?:0|1|4)$/) {
$self->{output}->add_option_msg(short_msg => $self->{current_section} . " special variable type not allowed in dst attribute");
$self->{output}->option_exit();
}
}
$self->set_special_variable_value(value => $value, %$save);
}
sub scale {
my ($self, %options) = @_;
my ($src_quantity, $src_unit) = (undef, 'B');
if ($options{src_unit} =~ /([kmgtpe])?(b)/i) {
$src_quantity = $1;
$src_unit = $2;
}
my ($dst_quantity, $dst_unit) = ('auto', $src_unit);
if ($options{dst_unit} =~ /([kmgtpe])?(b)/i) {
$dst_quantity = $1;
$dst_unit = $2;
}
my $base = 1024;
$options{value} *= 8 if ($dst_unit eq 'b' && $src_unit eq 'B');
$options{value} /= 8 if ($dst_unit eq 'B' && $src_unit eq 'b');
$base = 1000 if ($dst_unit eq 'b');
my %expo = (k => 1, m => 2, g => 3, t => 4, p => 5, e => 6);
my $src_expo = 0;
$src_expo = $expo{ lc($src_quantity) } if (defined($src_quantity));
if (defined($dst_quantity) && $dst_quantity eq 'auto') {
my @auto = ('', 'k', 'm', 'g', 't', 'p', 'e');
for (; $src_expo < scalar(@auto); $src_expo++) {
last if ($options{value} < $base);
$options{value} = $options{value} / $base;
}
return ($options{value}, uc($auto[$src_expo]) . $dst_unit);
}
my $dst_expo = 0;
$dst_expo = $expo{ lc($dst_quantity) } if (defined($dst_quantity));
if ($dst_expo - $src_expo > 0) {
$options{value} = $options{value} / ($base ** ($dst_expo - $src_expo));
} elsif ($dst_expo - $src_expo < 0) {
$options{value} = $options{value} * ($base ** (($dst_expo - $src_expo) * -1));
}
return ($options{value}, $options{dst_unit});
}
sub exec_func_scale {
my ($self, %options) = @_;
#{
# "type": "scale",
# "src": "%(memoryUsed)",
# "src_unit": "KB", (default: 'B')
# "dst_unit": "auto", (default: 'auto')
# "save_value": "%(memoryUsedScaled)",
# "save_unit": "%(memoryUsedUnit)"
#}
if (!defined($options{src}) || $options{src} eq '') {
$self->{output}->add_option_msg(short_msg => "$self->{current_section} please set src attribute");
$self->{output}->option_exit();
}
my $result = $self->parse_special_variable(chars => [split //, $options{src}], start => 0);
if ($result->{type} !~ /^(?:0|1|4)$/) {
$self->{output}->add_option_msg(short_msg => $self->{current_section} . " special variable type not allowed in src attribute");
$self->{output}->option_exit();
}
my $data = $self->get_special_variable_value(%$result);
my ($save_value, $save_unit) = $self->scale(
value => $data,
src_unit => $options{src_unit},
dst_unit => $options{dst_unit}
);
if (defined($options{save_value}) && $options{save_value} ne '') {
my $var_save_value = $self->parse_special_variable(chars => [split //, $options{save_value}], start => 0);
if ($var_save_value->{type} !~ /^(?:0|1|4)$/) {
$self->{output}->add_option_msg(short_msg => $self->{current_section} . " special variable type not allowed in save_value attribute");
$self->{output}->option_exit();
}
$self->set_special_variable_value(value => $save_value, %$var_save_value);
}
if (defined($options{save_unit}) && $options{save_unit} ne '') {
my $var_save_unit = $self->parse_special_variable(chars => [split //, $options{save_unit}], start => 0);
if ($var_save_unit->{type} !~ /^(?:0|1|4)$/) {
$self->{output}->add_option_msg(short_msg => $self->{current_section} . " special variable type not allowed in save_value attribute");
$self->{output}->option_exit();
}
$self->set_special_variable_value(value => $save_unit, %$var_save_unit);
}
}
sub exec_func_date2epoch {
my ($self, %options) = @_;
if (!defined($self->{module_datetime_loaded})) {
centreon::plugins::misc::mymodule_load(
module => 'DateTime',
error_msg => "Cannot load module 'DateTime'."
);
$self->{module_datetime_loaded} = 1;
}
#{
# "type": "date2epoch",
# "src": "%(dateTest)",
# "format": "DateAndTime",
# "timezone": "Europe/Paris",
# "save_epoch": "%(plopDateEpoch)",
# "save_diff1": "%(plopDateDiff1)",
# "save_diff2": "%(plopDateDiff2)"
#},
#{
# "type": "date2epoch",
# "src": "%(dateTest2)",
# "format_custom": "(\\d+)-(\\d+)-(\\d+)",
# "year": 1,
# "month": 2,
# "day": 3,
# "timezone": "Europe/Paris"
#}
if (!defined($options{src}) || $options{src} eq '') {
$self->{output}->add_option_msg(short_msg => "$self->{current_section} please set src attribute");
$self->{output}->option_exit();
}
my $result = $self->parse_special_variable(chars => [split //, $options{src}], start => 0);
if ($result->{type} !~ /^(?:0|1|4)$/) {
$self->{output}->add_option_msg(short_msg => $self->{current_section} . " special variable type not allowed in src attribute");
$self->{output}->option_exit();
}
my $data = $self->get_special_variable_value(%$result);
my $tz = {};
$tz->{time_zone} = $options{timezone} if (defined($options{timezone}) && $options{timezone} ne '');
my $dt;
if (defined($options{format}) && lc($options{format}) eq 'dateandtime') {
my @date = unpack('n C6 a C2', $data);
my $timezone;
if (defined($date[7]) && !defined($tz->{time_zone})) {
$tz->{time_zone} = sprintf('%s%02d%02d', $date[7], $date[8], $date[9]);
}
$dt = DateTime->new(
year => $date[0],
month => $date[1],
day => $date[2],
hour => $date[3],
minute => $date[4],
second => $date[5],
%$tz
);
} elsif (defined($options{format_custom}) && $options{format_custom} ne '') {
my @matches = ($data =~ /$options{format_custom}/);
my $date = {};
foreach (('year', 'month', 'day', 'hour', 'minute', 'second')) {
$date->{$_} = $matches[ $options{$_} -1 ]
if (defined($options{$_}) && $options{$_} =~ /^\d+$/ && defined($matches[ $options{$_} -1 ]));
}
foreach (('year', 'month', 'day')) {
if (!defined($date->{$_})) {
$self->{output}->add_option_msg(short_msg => "$self->{current_section} cannot find $_ attribute");
$self->{output}->option_exit();
}
}
$dt = DateTime->new(%$date, %$tz);
} else {
$self->{output}->add_option_msg(short_msg => "$self->{current_section} please set format or format_custom attribute");
$self->{output}->option_exit();
}
my $results = {
epoch => $dt->epoch(),
diff1 => time() - $dt->epoch(),
diff2 => $dt->epoch() - time()
};
foreach (keys %$results) {
my $attr = '%(' . $result->{label} . ucfirst($_) . ')';
$attr = $options{'save_' . $_}
if (defined($options{'save_' . $_}) && $options{'save_' . $_} ne '');
my $var_save_value = $self->parse_special_variable(chars => [split //, $attr], start => 0);
if ($var_save_value->{type} !~ /^(?:0|1|4)$/) {
$self->{output}->add_option_msg(short_msg => $self->{current_section} . " special variable type not allowed in save_$_ attribute");
$self->{output}->option_exit();
}
$self->set_special_variable_value(value => $results->{$_}, %$var_save_value);
}
}
sub exec_func_epoch2date {
my ($self, %options) = @_;
if (!defined($self->{module_datetime_loaded})) {
centreon::plugins::misc::mymodule_load(
module => 'DateTime',
error_msg => "Cannot load module 'DateTime'."
);
$self->{module_datetime_loaded} = 1;
}
#{
# "type": "epoch2date",
# "src": "%(dateTestEpoch)",
# "format": "%a %b %e %H:%M:%S %Y",
# "timezone": "Asia/Tokyo",
# "locale": "fr",
# "save": "%(dateTestReformat)"
#}
if (!defined($options{src}) || $options{src} eq '') {
$self->{output}->add_option_msg(short_msg => "$self->{current_section} please set src attribute");
$self->{output}->option_exit();
}
my $result = $self->parse_special_variable(chars => [split //, $options{src}], start => 0);
if ($result->{type} !~ /^(?:0|1|4)$/) {
$self->{output}->add_option_msg(short_msg => $self->{current_section} . " special variable type not allowed in src attribute");
$self->{output}->option_exit();
}
my $data = $self->get_special_variable_value(%$result);
my $extras = {};
$extras->{time_zone} = $options{timezone} if (defined($options{timezone}) && $options{timezone} ne '');
$extras->{locale} = $options{locale} if (defined($options{locale}) && $options{locale} ne '');
my $dt = DateTime->from_epoch(
epoch => $data,
%$extras
);
my $time_value = $dt->strftime($options{format});
if (defined($options{save}) && $options{save} ne '') {
my $var_save_value = $self->parse_special_variable(chars => [split //, $options{save}], start => 0);
if ($var_save_value->{type} !~ /^(?:0|1|4)$/) {
$self->{output}->add_option_msg(short_msg => $self->{current_section} . " special variable type not allowed in save attribute");
$self->{output}->option_exit();
}
$self->set_special_variable_value(value => $time_value, %$var_save_value);
}
}
sub exec_func_count {
my ($self, %options) = @_;
#{
# "type": "count",
# "src": "%(snmp.tables.test)",
# "save": "%(testCount)"
#}
if (!defined($options{src}) || $options{src} eq '') {
$self->{output}->add_option_msg(short_msg => "$self->{current_section} please set src attribute");
$self->{output}->option_exit();
}
my $result = $self->parse_special_variable(chars => [split //, $options{src}], start => 0);
if ($result->{type} !~ /^2$/) {
$self->{output}->add_option_msg(short_msg => $self->{current_section} . " special variable type not allowed in src attribute");
$self->{output}->option_exit();
}
my $data = $self->get_special_variable_value(%$result);
my $value = 0;
if (defined($data)) {
if (defined($options{filter}) && $options{filter} ne '') {
my $count = 0;
foreach my $instance (keys %$data) {
my $values = $self->{expand};
foreach my $label (keys %{$data->{$instance}}) {
$values->{'src.' . $label} = $data->{$instance}->{$label};
}
$count++ unless ($self->check_filter(filter => $options{filter}, values => $values));
}
$value = $count;
} else {
$value = scalar(keys %$data);
}
}
if (defined($options{save}) && $options{save} ne '') {
my $save = $self->parse_special_variable(chars => [split //, $options{save}], start => 0);
if ($save->{type} !~ /^(?:0|1|4)$/) {
$self->{output}->add_option_msg(short_msg => $self->{current_section} . " special variable type not allowed in save attribute");
$self->{output}->option_exit();
}
$self->set_special_variable_value(value => $value, %$save);
}
}
sub exec_func_replace {
my ($self, %options) = @_;
#{
# "type": "replace",
# "src": "%(sql.tables.test)",
# "expression": "s/name/name is/"
#}
if (!defined($options{src}) || $options{src} eq '') {
$self->{output}->add_option_msg(short_msg => "$self->{current_section} please set src attribute");
$self->{output}->option_exit();
}
if (!defined($options{expression}) || $options{expression} eq '') {
$self->{output}->add_option_msg(short_msg => "$self->{current_section} please set expression attribute");
$self->{output}->option_exit();
}
my $result = $self->parse_special_variable(chars => [split //, $options{src}], start => 0);
if ($result->{type} !~ /^(?:0|4)$/) {
$self->{output}->add_option_msg(short_msg => $self->{current_section} . " special variable type not allowed in src attribute");
$self->{output}->option_exit();
}
my $data = $self->get_special_variable_value(%$result);
if (defined($data)) {
my $expression = $self->substitute_string(value => $options{expression});
our $assign_var = $data;
$self->{safe_func}->reval("\$assign_var =~ $expression", 1);
if ($@) {
die 'Unsafe code evaluation: ' . $@;
}
$self->set_special_variable_value(value => $assign_var, %$result);
}
}
sub exec_func_assign {
my ($self, %options) = @_;
#{
# "type": "assign",
# "save": "%(sql.tables.test)",
# "expression": "'%(sql.tables.test)' . 'toto'"
#}
if (!defined($options{save}) || $options{save} eq '') {
$self->{output}->add_option_msg(short_msg => "$self->{current_section} please set save attribute");
$self->{output}->option_exit();
}
if (!defined($options{expression}) || $options{expression} eq '') {
$self->{output}->add_option_msg(short_msg => "$self->{current_section} please set expression attribute");
$self->{output}->option_exit();
}
my $result = $self->parse_special_variable(chars => [split //, $options{save}], start => 0);
if ($result->{type} !~ /^(?:0|4)$/) {
$self->{output}->add_option_msg(short_msg => $self->{current_section} . " special variable type not allowed in src attribute");
$self->{output}->option_exit();
}
my $expression = $self->substitute_string(value => $options{expression});
our $assign_var;
$self->{safe_func}->reval("\$assign_var = $expression", 1);
if ($@) {
die 'Unsafe code evaluation: ' . $@;
}
$self->set_special_variable_value(value => $assign_var, %$result);
}
sub set_functions {
my ($self, %options) = @_;
return if (!defined($options{functions}));
my $i = -1;
foreach (@{$options{functions}}) {
$i++;
$self->{current_section} = '[' . $options{section} . ' > ' . $i . ']';
next if (defined($_->{position}) && $options{position} ne $_->{position});
next if (!defined($_->{position}) && !(defined($options{default}) && $options{default} == 1));
next if (!defined($_->{type}));
if ($_->{type} eq 'map') {
$self->exec_func_map(%$_);
} elsif ($_->{type} eq 'scale') {
$self->exec_func_scale(%$_);
} elsif (lc($_->{type}) eq 'date2epoch') {
$self->exec_func_date2epoch(%$_);
} elsif (lc($_->{type}) eq 'epoch2date') {
$self->exec_func_epoch2date(%$_);
} elsif (lc($_->{type}) eq 'count') {
$self->exec_func_count(%$_);
} elsif (lc($_->{type}) eq 'replace') {
$self->exec_func_replace(%$_);
} elsif (lc($_->{type}) eq 'assign') {
$self->exec_func_assign(%$_);
}
}
}
sub prepare_variables {
my ($self, %options) = @_;
return undef if (!defined($options{value}));
$options{value} =~ s/%\(([a-zA-Z0-9\.]+?)\)/\$expand->{'$1'}/g;
return $options{value};
}
sub check_filter {
my ($self, %options) = @_;
return 0 if (!defined($options{filter}) || $options{filter} eq '');
our $expand = $options{values};
$options{filter} =~ s/%\(([a-zA-Z0-9\.]+?)\)/\$expand->{'$1'}/g;
my $result = $self->{safe}->reval("$options{filter}");
if ($@) {
$self->{output}->add_option_msg(short_msg => 'Unsafe code evaluation: ' . $@);
$self->{output}->option_exit();
}
return 0 if ($result);
return 1;
}
sub check_filter_option {
my ($self, %options) = @_;
foreach (keys %{$self->{option_results}->{filter_selection}}) {
return 1 if (
defined($self->{expand}->{$_}) && $self->{option_results}->{filter_selection}->{$_} ne '' &&
$self->{expand}->{$_} !~ /$self->{option_results}->{filter_selection}->{$_}/
);
}
return 0;
}
sub prepare_perfdatas {
my ($self, %options) = @_;
return undef if (!defined($options{perfdatas}));
my $perfdatas = [];
foreach (@{$options{perfdatas}}) {
next if (!defined($_->{nlabel}) || $_->{nlabel} eq '');
next if (!defined($_->{value}) || $_->{value} eq '');
my $perf = {};
$perf->{nlabel} = $self->substitute_string(value => $_->{nlabel});
$perf->{value} = $self->substitute_string(value => $_->{value});
foreach my $label (('warning', 'critical', 'min', 'max', 'unit')) {
next if (!defined($_->{$label}));
$perf->{$label} = $self->substitute_string(value => $_->{$label});
}
if (defined($_->{instances})) {
$perf->{instances} = [];
foreach my $instance (@{$_->{instances}}) {
push @{$perf->{instances}}, $self->substitute_string(value => $instance);
}
}
push @$perfdatas, $perf;
}
return $perfdatas;
}
sub prepare_formatting {
my ($self, %options) = @_;
return undef if (!defined($options{formatting}));
my $format = {};
$format->{printf_msg} = $options{formatting}->{printf_msg};
$format->{display_ok} = $options{formatting}->{display_ok};
if (defined($options{formatting}->{printf_var})) {
$format->{printf_var} = [];
foreach my $var (@{$options{formatting}->{printf_var}}) {
push @{$format->{printf_var}}, $self->substitute_string(value => $var);
}
}
return $format
}
sub add_selection {
my ($self, %options) = @_;
return if (!defined($self->{config}->{selection}));
my $i = -1;
foreach (@{$self->{config}->{selection}}) {
$i++;
my $config = {};
$self->{expand} = $self->set_constants();
$self->set_builtin();
$self->{expand}->{name} = $_->{name} if (defined($_->{name}));
$self->set_functions(section => "selection > $i > functions", functions => $_->{functions}, position => 'before_expand');
$self->set_expand_table(section => "selection > $i > expand_table", expand => $_->{expand_table});
$self->set_expand(section => "selection > $i > expand", expand => $_->{expand});
$self->set_functions(section => "selection > $i > functions", functions => $_->{functions}, position => 'after_expand', default => 1);
next if ($self->check_filter(filter => $_->{filter}, values => $self->{expand}));
next if ($self->check_filter_option());
$config->{unknown} = $self->prepare_variables(section => "selection > $i > unknown", value => $_->{unknown});
$config->{warning} = $self->prepare_variables(section => "selection > $i > warning", value => $_->{warning});
$config->{critical} = $self->prepare_variables(section => "selection > $i > critical", value => $_->{critical});
$config->{perfdatas} = $self->prepare_perfdatas(section => "selection > $i > perfdatas", perfdatas => $_->{perfdatas});
$config->{formatting} = $self->prepare_formatting(section => "selection > $i > formatting", formatting => $_->{formatting});
$config->{formatting_unknown} = $self->prepare_formatting(section => "selection > $i > formatting_unknown", formatting => $_->{formatting_unknown});
$config->{formatting_warning} = $self->prepare_formatting(section => "selection > $i > formatting_warning", formatting => $_->{formatting_warning});
$config->{formatting_critical} = $self->prepare_formatting(section => "selection > $i > formatting_critical", formatting => $_->{formatting_critical});
$self->{selections}->{'s' . $i} = { expand => $self->{expand}, config => $config };
}
}
sub add_selection_loop {
my ($self, %options) = @_;
return if (!defined($self->{config}->{selection_loop}));
my $i = -1;
foreach (@{$self->{config}->{selection_loop}}) {
$i++;
next if (!defined($_->{source}) || $_->{source} eq '');
$self->{current_section} = '[selection_loop > ' . $i . ' > source]';
my $result = $self->parse_special_variable(chars => [split //, $_->{source}], start => 0);
if ($result->{type} != 2) {
$self->{output}->add_option_msg(short_msg => $self->{current_section} . " special variable type not allowed");
$self->{output}->option_exit();
}
next if (!defined($self->{snmp_collected}->{tables}->{ $result->{table} }));
foreach my $instance (keys %{$self->{snmp_collected}->{tables}->{ $result->{table} }}) {
$self->{expand} = $self->set_constants();
$self->set_builtin();
$self->{expand}->{ $result->{table} . '.instance' } = $instance;
foreach my $label (keys %{$self->{snmp_collected}->{tables}->{ $result->{table} }->{$instance}}) {
$self->{expand}->{ $result->{table} . '.' . $label } =
$self->{snmp_collected}->{tables}->{ $result->{table} }->{$instance}->{$label};
}
my $config = {};
$self->{expand}->{name} = $_->{name} if (defined($_->{name}));
$self->set_functions(section => "selection_loop > $i > functions", functions => $_->{functions}, position => 'before_expand');
$self->set_expand_table(section => "selection_loop > $i > expand_table", expand => $_->{expand_table});
$self->set_expand(section => "selection_loop > $i > expand", expand => $_->{expand});
$self->set_functions(section => "selection_loop > $i > functions", functions => $_->{functions}, position => 'after_expand', default => 1);
next if ($self->check_filter(filter => $_->{filter}, values => $self->{expand}));
next if ($self->check_filter_option());
$config->{unknown} = $self->prepare_variables(section => "selection_loop > $i > unknown", value => $_->{unknown});
$config->{warning} = $self->prepare_variables(section => "selection_loop > $i > warning", value => $_->{warning});
$config->{critical} = $self->prepare_variables(section => "selection_loop > $i > critical", value => $_->{critical});
$config->{perfdatas} = $self->prepare_perfdatas(section => "selection_loop > $i > perfdatas", perfdatas => $_->{perfdatas});
$config->{formatting} = $self->prepare_formatting(section => "selection_loop > $i > formatting", formatting => $_->{formatting});
$config->{formatting_unknown} = $self->prepare_formatting(section => "selection_loop > $i > formatting_unknown", formatting => $_->{formatting_unknown});
$config->{formatting_warning} = $self->prepare_formatting(section => "selection_loop > $i > formatting_warning", formatting => $_->{formatting_warning});
$config->{formatting_critical} = $self->prepare_formatting(section => "selection_loop > $i > formatting_critical", formatting => $_->{formatting_critical});
$self->{selections}->{'s' . $i . '-' . $instance} = { expand => $self->{expand}, config => $config };
}
}
}
sub set_formatting {
my ($self, %options) = @_;
return if (!defined($self->{config}->{formatting}));
if (defined($self->{config}->{formatting}->{custom_message_global})) {
$self->{maps_counters_type}->[0]->{message_multiple} = $self->{config}->{formatting}->{custom_message_global};
}
if (defined($self->{config}->{formatting}->{separator})) {
$self->{maps_counters_type}->[0]->{message_separator} = $self->{config}->{formatting}->{separator};
}
}
sub disco_format {
my ($self, %options) = @_;
$self->{output}->add_disco_format(elements => ['name']);
}
sub disco_show {
my ($self, %options) = @_;
$self->read_config();
$self->collect_snmp(snmp => $options{snmp});
$self->{selections} = {};
$self->add_selection();
$self->add_selection_loop();
foreach (values %{$self->{selections}}) {
my $entry = {};
foreach my $label (keys %{$_->{expand}}) {
next if ($label =~ /^(?:constants|builtin)\./);
my $name = $label;
$name =~ s/\./_/g;
$entry->{$name} = defined($_->{expand}->{$label}) ? $_->{expand}->{$label} : '';
}
$self->{output}->add_disco_entry(%$entry);
}
}
sub manage_selection {
my ($self, %options) = @_;
# TODO:
# add some functions types:
# decode snmp type: ipAddress
# can cache only some parts of snmp requests:
# use an array for "snmp" ?
$self->read_config();
$self->collect_snmp(snmp => $options{snmp});
$self->{selections} = {};
$self->add_selection();
$self->add_selection_loop();
$self->set_formatting();
}
1;
__END__
=head1 MODE
Collect and compute SNMP datas.
=over 8
=item B<--config>
config used (Required).
Can be a file or json content.
=item B<--filter-selection>
Filter selections.
Eg: --filter-selection='name=test'
=item B<--constant>
Add a constant.
Eg: --constant='warning=30' --constant='critical=45'
=back
=cut