From dcd186de246b48cd5356fb4efef98195f5085e53 Mon Sep 17 00:00:00 2001 From: scresto Date: Tue, 6 May 2025 11:22:54 +0200 Subject: [PATCH] enh(F5OS): New pack f5 os snmp (#5567) Co-authored-by: Sylvain Cresto Refs:CTOR-293 --- .../deb.json | 5 + .../pkg.json | 10 + .../rpm.json | 5 + src/os/f5os/snmp/mode/cpuusage.pm | 248 +++++++++++++++++ src/os/f5os/snmp/mode/hardware.pm | 255 ++++++++++++++++++ src/os/f5os/snmp/mode/memory.pm | 192 +++++++++++++ src/os/f5os/snmp/plugin.pm | 50 ++++ tests/os/f5os/snmp/cpu-usage.robot | 32 +++ tests/os/f5os/snmp/f5os.snmpwalk | 29 ++ tests/os/f5os/snmp/hardware.robot | 34 +++ tests/os/f5os/snmp/memory.robot | 31 +++ tests/resources/spellcheck/stopwords.txt | 1 + 12 files changed, 892 insertions(+) create mode 100644 packaging/centreon-plugin-Operatingsystems-F5os-Snmp/deb.json create mode 100644 packaging/centreon-plugin-Operatingsystems-F5os-Snmp/pkg.json create mode 100644 packaging/centreon-plugin-Operatingsystems-F5os-Snmp/rpm.json create mode 100644 src/os/f5os/snmp/mode/cpuusage.pm create mode 100644 src/os/f5os/snmp/mode/hardware.pm create mode 100644 src/os/f5os/snmp/mode/memory.pm create mode 100644 src/os/f5os/snmp/plugin.pm create mode 100644 tests/os/f5os/snmp/cpu-usage.robot create mode 100644 tests/os/f5os/snmp/f5os.snmpwalk create mode 100644 tests/os/f5os/snmp/hardware.robot create mode 100644 tests/os/f5os/snmp/memory.robot diff --git a/packaging/centreon-plugin-Operatingsystems-F5os-Snmp/deb.json b/packaging/centreon-plugin-Operatingsystems-F5os-Snmp/deb.json new file mode 100644 index 000000000..663aaaceb --- /dev/null +++ b/packaging/centreon-plugin-Operatingsystems-F5os-Snmp/deb.json @@ -0,0 +1,5 @@ +{ + "dependencies": [ + "libsnmp-perl" + ] +} \ No newline at end of file diff --git a/packaging/centreon-plugin-Operatingsystems-F5os-Snmp/pkg.json b/packaging/centreon-plugin-Operatingsystems-F5os-Snmp/pkg.json new file mode 100644 index 000000000..e729e8166 --- /dev/null +++ b/packaging/centreon-plugin-Operatingsystems-F5os-Snmp/pkg.json @@ -0,0 +1,10 @@ +{ + "pkg_name": "centreon-plugin-Operatingsystems-F5os-Snmp", + "pkg_summary": "Centreon Plugin", + "plugin_name": "centreon_f5os_snmp.pl", + "files": [ + "centreon/plugins/script_snmp.pm", + "centreon/plugins/snmp.pm", + "os/f5os/snmp/" + ] +} diff --git a/packaging/centreon-plugin-Operatingsystems-F5os-Snmp/rpm.json b/packaging/centreon-plugin-Operatingsystems-F5os-Snmp/rpm.json new file mode 100644 index 000000000..418a331fc --- /dev/null +++ b/packaging/centreon-plugin-Operatingsystems-F5os-Snmp/rpm.json @@ -0,0 +1,5 @@ +{ + "dependencies": [ + "perl(SNMP)" + ] +} \ No newline at end of file diff --git a/src/os/f5os/snmp/mode/cpuusage.pm b/src/os/f5os/snmp/mode/cpuusage.pm new file mode 100644 index 000000000..8b62ab1e5 --- /dev/null +++ b/src/os/f5os/snmp/mode/cpuusage.pm @@ -0,0 +1,248 @@ +# +# Copyright 2025 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 os::f5os::snmp::mode::cpuusage; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'cpu_avg', type => 0 }, + { name => 'cpu_core', type => 1, cb_prefix_output => 'prefix_cpu_output' }, + ]; + + $self->{maps_counters}->{cpu_avg} = [ + { label => 'average', nlabel => 'cpu.usage.percent', set => { + key_values => [ { name => 'average' } ], + output_template => 'CPU(s) average usage is: %.2f %%', + perfdatas => [ + { label => 'total_cpu_avg', value => 'average', template => '%.2f', + min => 0, max => 100, unit => '%' }, + ] + } + } + ]; + + $self->{maps_counters}->{cpu_core} = [ + { label => 'core-current', nlabel => 'cpu.core.current.usage.percent', set => { + key_values => [ { name => 'CoreCurrent' }, { name => 'display' } ], + output_template => 'CPU Usage Current : %s %%', output_error_template => "CPU Usage Current : %s", + perfdatas => [ + { value => 'CoreCurrent', template => '%s', + unit => '%', min => 0, max => 100, label_extra_instance => 1, instance_use => 'display' }, + ], + } + }, + { label => 'core-avg-5s', nlabel => 'cpu.core.usage.avg.5s.percent', set => { + key_values => [ { name => 'CoreTotal5secAvg' }, { name => 'display' } ], + output_template => 'CPU Usage 5sec : %s %%', output_error_template => "CPU Usage 5sec : %s", + perfdatas => [ + { value => 'CoreTotal5secAvg', template => '%s', + unit => '%', min => 0, max => 100, label_extra_instance => 1, instance_use => 'display' }, + ], + } + }, + { label => 'core-avg-1m', nlabel => 'cpu.core.usage.avg.1m.percent', set => { + key_values => [ { name => 'CoreTotal1minAvg' }, { name => 'display' } ], + output_template => 'CPU Usage 1min : %s %%', output_error_template => "CPU Usage 1min : %s", + perfdatas => [ + { value => 'CoreTotal1minAvg', template => '%s', + unit => '%', min => 0, max => 100, label_extra_instance => 1, instance_use => 'display' }, + ], + } + }, + { label => 'core-avg-5m', nlabel => 'cpu.core.usage.avg.5m.percent', set => { + key_values => [ { name => 'CoreTotal5minAvg' }, { name => 'display' } ], + output_template => 'CPU Usage 5min : %s %%', output_error_template => "CPU Usage 5min : %s", + perfdatas => [ + { value => 'CoreTotal5minAvg', template => '%s', + unit => '%', min => 0, max => 100, label_extra_instance => 1, instance_use => 'display' }, + ], + } + }, + ]; +} + +sub prefix_cpu_output { + my ($self, %options) = @_; + + return "CPU '" . $options{instance_value}->{display} . "' " + unless $self->{output}->is_verbose(); + + return "CPU '" . $options{instance_value}->{display} . " [" . $options{instance_value}->{CoreName}. "]' "; +} + +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 => { + 'include-name:s' => { name => 'include_name', default => '' }, + 'include-id:s' => { name => 'include_id', default => '' }, + 'exclude-name:s' => { name => 'exclude_name', default => '' }, + 'exclude-id:s' => { name => 'exclude_id', default => '' }, + }); + + return $self; +} + +my $mapping = { + CoreIndex => { oid => '.1.3.6.1.4.1.12276.1.2.1.1.3.1.1' }, + CoreName => { oid => '.1.3.6.1.4.1.12276.1.2.1.1.3.1.2' }, + CoreCurrent => { oid => '.1.3.6.1.4.1.12276.1.2.1.1.3.1.3' }, + CoreTotal5secAvg => { oid => '.1.3.6.1.4.1.12276.1.2.1.1.3.1.4' }, + CoreTotal1minAvg => { oid => '.1.3.6.1.4.1.12276.1.2.1.1.3.1.5' }, + CoreTotal5minAvg => { oid => '.1.3.6.1.4.1.12276.1.2.1.1.3.1.6' }, +}; +my $oid_cpuCoreStatsEntry = '.1.3.6.1.4.1.12276.1.2.1.1.3.1'; + +sub manage_selection { + my ($self, %options) = @_; + + my $results = $options{snmp}->get_table( + oid => $oid_cpuCoreStatsEntry, + nothing_quit => 1 + ); + + $self->{cpu_core} = {}; + $self->{cpu_avg} = {}; + + my $cpu = 0; + foreach my $oid (keys %$results) { + next if ($oid !~ /^$mapping->{CoreIndex}->{oid}\.(.*)$/); + my $instance = $1; + my $result = $options{snmp}->map_instance(mapping => $mapping, results => $results, instance => $instance); + + if ($self->{option_results}->{include_name} ne '' || $self->{option_results}->{include_id} ne '') { + my $whitelist = 0; + $whitelist = 1 if $self->{option_results}->{include_name} ne '' && $result->{CoreName} =~ /$self->{option_results}->{include_name}/; + $whitelist = 1 if $self->{option_results}->{include_id} ne '' && $result->{CoreIndex} =~ /$self->{option_results}->{include_id}/; + + if ($whitelist == 0) { + $self->{output}->output_add(long_msg => "skipping '" . $result->{CoreIndex} .'-'. $result->{CoreName}. "': no including filter match.", debug => 1); + next + } + } + + if (($self->{option_results}->{exclude_name} ne '' && $result->{CoreName} =~ /$self->{option_results}->{exclude_name}/) || + ($self->{option_results}->{exclude_id} ne '' && $result->{CoreIndex} =~ /$self->{option_results}->{exclude_id}/)) { + $self->{output}->output_add(long_msg => "skipping '" . $result->{CoreIndex} .'-'. $result->{CoreName}. "': excluding filter match.", debug => 1); + next + } + + $self->{cpu_core}->{$result->{CoreIndex}} = { + display => $result->{CoreIndex}, + %$result + }; + + $cpu += $result->{CoreCurrent}; + } + + my $num_core = scalar(keys %{$self->{cpu_core}}); + if ($num_core <= 0) { + $self->{output}->add_option_msg(short_msg => "No CPU found."); + $self->{output}->option_exit(); + } else { + $self->{cpu_avg}->{average} = $cpu / $num_core; + } +} + +1; + +__END__ + +=head1 MODE + +Check CPU usages. + + - cpu.core.current.usage.percent CPU core current utilization percentage. + - cpu.core.usage.avg.5s.percent CPU core utilization average over the last five second. + - cpu.core.usage.avg.1m.percent CPU core utilization average over the last one minute. + - cpu.core.usage.avg.5m.percent CPU core utilization average over the last five minute. + +=over 8 + +=item B<--filter-counters> + +Only display some counters (regexp can be used). +Can be : core-current, core-avg-5s, core-avg-1m, core-avg-5m +Example : --filter-counters='^core-current$' + +=item B<--include-id> + +Filter by CPU id (regexp can be used). +Example : --include-id='2' + +=item B<--include-name> + +Filter by CPU name (regexp can be used). +Example : --include-name='cpu02' + +=item B<--exclude-id> + +Exclude CPU id from check (regexp can be used). +Example : --exclude-id='21' + +=item B<--exclude-name> + +Exclude CPU name from check (regexp can be used). +Example : --exclude-name='cpu02' + +=item B<--warning-core-current> + +Threshold in percentage. + +=item B<--critical-core-current> + +Threshold in percentage. + +=item B<--warning-core-avg-5s> + +Threshold in percentage. + +=item B<--critical-core-avg-5s> + +Threshold in percentage. + +=item B<--warning-core-avg-1m> + +Threshold in percentage. + +=item B<--critical-core-avg-1m> + +Threshold in percentage. + +=item B<--warning-core-avg-5m> + +Threshold in percentage. + +=item B<--critical-core-avg-5m> + +Threshold in percentage. + +=back + +=cut diff --git a/src/os/f5os/snmp/mode/hardware.pm b/src/os/f5os/snmp/mode/hardware.pm new file mode 100644 index 000000000..27a2c41e7 --- /dev/null +++ b/src/os/f5os/snmp/mode/hardware.pm @@ -0,0 +1,255 @@ +# +# Copyright 2024 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 os::f5os::snmp::mode::hardware; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +sub prefix_fan_output { + my ($self, %options) = @_; + return "fan '" . $options{instance} . "' "; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'temperature', type => 0, skipped_code => { -10 => 1 } }, + { name => 'fans', type => 1, cb_prefix_output => 'prefix_fan_output', message_multiple => 'All fans are ok', skipped_code => { -10 => 1 } } + ]; + + $self->{maps_counters}->{temperature} = [ + { label => 'current-temperature', nlabel => 'temperature.current.celsius', set => { + key_values => [ { name => 'tempCurrent' } ], + output_template => 'Current temperature: %s C', + perfdatas => [ + { template => '%.1f', unit => 'C', label_extra_instance => 0 } + ] + } + }, + { label => 'average-temperature', nlabel => 'temperature.average.1h.celsius', set => { + key_values => [ { name => 'tempAverage' } ], + output_template => 'average: %s C', + perfdatas => [ + { template => '%.1f', unit => 'C', label_extra_instance => 0 } + ] + } + }, + { label => 'min-temperature', nlabel => 'temperature.min.1h.celsius', set => { + key_values => [ { name => 'tempMinimum' } ], + output_template => 'minimum: %s C', + perfdatas => [ + { template => '%.1f', unit => 'C', label_extra_instance => 0 } + ] + } + }, + { label => 'max-temperature', nlabel => 'temperature.max.1h.celsius', set => { + key_values => [ { name => 'tempMaximum' } ], + output_template => 'maximum: %s C', + perfdatas => [ + { template => '%.1f', unit => 'C', label_extra_instance => 1 } + ] + } + } + + + ]; + + $self->{maps_counters}->{fans} = [ + { label => 'fantray-fan-speed', nlabel => 'fantray.fanspeed.rpm', set => { + key_values => [ { name => 'speed' } ], + output_template => 'speed is %s rpm', + perfdatas => [ + { template => '%s', unit => 'rpm', min => 0, label_extra_instance => 1 } + ] + } + } + ]; + +} + +my $mapping = { + tempCurrent => { oid => '.1.3.6.1.4.1.12276.1.2.1.3.1.1.2' }, + tempAverage => { oid => '.1.3.6.1.4.1.12276.1.2.1.3.1.1.3' }, + tempMinimum => { oid => '.1.3.6.1.4.1.12276.1.2.1.3.1.1.4' }, + tempMaximum => { oid => '.1.3.6.1.4.1.12276.1.2.1.3.1.1.5' }, +}; + +my $oid_temperatureStatsEntry = '.1.3.6.1.4.1.12276.1.2.1.3.1.1'; +my $oid_fantrayStatsEntry = '.1.3.6.1.4.1.12276.1.2.1.7.1.1'; + +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 => { + 'component:s' => { name => 'component', default => '.*' }, + 'no-component:s' => { name => 'no_component', default => 'CRITICAL' }, + 'include-id:s' => { name => 'include_id', default => '' }, + 'exclude-id:s' => { name => 'exclude_id', default => '' }, + }); + + return $self; +} + +sub manage_selection { + my ($self, %options) = @_; + + my $results = $options{snmp}->get_multiple_table( + oids => [ + { oid => $oid_temperatureStatsEntry }, + { oid => $oid_fantrayStatsEntry }, + ]); + + if ('temperature' =~ /$self->{option_results}->{component}/) { + my $result; + foreach (keys %{$results->{$oid_temperatureStatsEntry}}) { + next unless /^$mapping->{tempCurrent}->{oid}\.(.*)$/; + + $result = $options{snmp}->map_instance(mapping => $mapping, results => $results->{$oid_temperatureStatsEntry}, instance => $1); + $result->{$_} *= 0.1 for keys %{$result}; + + last + } + + if ($result) { + $self->{temperature} = $result; + } else { + $self->{output}->output_add( + severity => $self->{option_results}->{no_component}, + short_msg => 'Temperature not retrieved.' + ); + } + } + + if ('fantray' =~ /$self->{option_results}->{component}/) { + while (my ($oid, $values) = each %{$results->{$oid_fantrayStatsEntry}}) { + next unless $oid =~ /^$oid_fantrayStatsEntry\.(\d+)/; + my $fan_id = $1; + + if ($self->{option_results}->{include_id} && $fan_id !~ /$self->{option_results}->{include_id}/) { + $self->{output}->output_add(long_msg => "skipping fantray fan '$fan_id': no including filter match.", debug => 1); + next + } + if ($self->{option_results}->{exclude_id} && $fan_id =~ /$self->{option_results}->{exclude_id}/) { + $self->{output}->output_add(long_msg => "skipping fantray fan '$fan_id': excluding filter match.", debug => 1); + next + } + + $self->{fans}->{$fan_id} = { speed => $values }; + } + + unless ($self->{fans}) { + $self->{output}->output_add( + severity => $self->{option_results}->{no_component}, + short_msg => 'Fantray Fan speed not retrieved.' + ); + } + } +} + +1; + +__END__ + +=head1 MODE + +Check hardware. + + - temperature.current.celsius The current temperature in celsius + - temperature.average.1h.celsius The arithmetic mean value of the temperature + - temperature.min.1h.celsius The minimum value of the temperature statistic over the past hour + - temperature.max.1h.celsius The maximum value of the temperature statistic over the past hour + - fantray.fanspeed.rpm The current fan speed in RPM + +=over 8 + +=item B<--component> + +Which component to check (default: '.*'). +Can be: 'temperature', 'fantray'. + +=item B<--no-component> + +Define the expected status if no components are found (default: critical). + +=item B<--filter-counters> + +Only display some counters (regexp can be used). +Can be : fantray-fan-speed current-temperature average-temperature min-temperature max-temperature +Example : --filter-counters='^current-temperature$' + +=item B<--include-id> + +Filter by fan id (regexp can be used). +Example : --include-id='2' + +=item B<--exclude-id> + +Exclude fan id from check (can be a regexp). +Example : --exclude-id='10' + +=item B<--warning-current-temperature> + +Threshold in C. + +=item B<--critical-current-temperature> + +Threshold in C. + +=item B<--warning-average-temperature> + +Threshold in C. + +=item B<--critical-average-temperature> + +Threshold in C. + +=item B<--warning-min-temperature> + +Threshold in C. + +=item B<--critical-min-temperature> + +Threshold in C. + +=item B<--warning-max-temperature> + +Threshold in C. + +=item B<--critical-max-temperature> + +Threshold in C. + +=item B<--warning-fantray-speed> + +Threshold in rpm. + +=item B<--critical-fantray-speed> + +Threshold in rpm. + +=back + +=cut diff --git a/src/os/f5os/snmp/mode/memory.pm b/src/os/f5os/snmp/mode/memory.pm new file mode 100644 index 000000000..ea8f0a8ef --- /dev/null +++ b/src/os/f5os/snmp/mode/memory.pm @@ -0,0 +1,192 @@ +# +# Copyright 2024 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 os::f5os::snmp::mode::memory; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +sub custom_usage_output { + my ($self, %options) = @_; + + return sprintf( + 'total: %s %s used: %s %s (%.2f%%) free: %s %s (%.2f%%)', + $self->{perfdata}->change_bytes(value => $self->{result_values}->{total}), + $self->{perfdata}->change_bytes(value => $self->{result_values}->{used}), + $self->{result_values}->{prct_used}, + $self->{perfdata}->change_bytes(value => $self->{result_values}->{free}), + $self->{result_values}->{prct_free} + ); +} + +sub prefix_memory_output { + my ($self, %options) = @_; + + return "Memory "; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'memory', type => 0, cb_prefix_output => 'prefix_memory_output', message_multiple => 'All memory usages are ok', skipped_code => { -10 => 1 } } + ]; + + $self->{maps_counters}->{memory} = [ + { label => 'usage', nlabel => 'memory.usage.bytes', set => { + key_values => [ { name => 'used' }, { name => 'free' }, { name => 'prct_used' }, { name => 'total'}, { name => 'prct_free' }], + closure_custom_output => $self->can('custom_usage_output'), + perfdatas => [ + { template => '%d', min => 0, max => 'total', unit => 'B', cast_int => 1 } + ] + } + }, + { label => 'free', display_ok => 0, nlabel => 'memory.free.bytes', display_ok => 0, set => { + key_values => [ { name => 'free' }, { name => 'used' }, { name => 'prct_used' }, { name => 'total' }, { name => 'prct_free' } ], + closure_custom_output => $self->can('custom_usage_output'), + perfdatas => [ + { template => '%d', min => 0, max => 'total', unit => 'B', cast_int => 1 } + ] + } + }, + { label => 'usage-prct', nlabel => 'memory.usage.percent', display_ok => 0, set => { + key_values => [ { name => 'prct_used' }, { name => 'used' }, { name => 'free' }, { name => 'total' }, { name => 'prct_free' },], + closure_custom_output => $self->can('custom_usage_output'), + perfdatas => [ + { template => '%.2f', min => 0, max => 100, unit => '%' } + ] + } + }, + { label => 'free-prct', nlabel => 'memory.free.percent', display_ok => 0, set => { + key_values => [ { name => 'prct_free' }, { name => 'used' }, { name => 'free' }, { name => 'total' }, { name => 'prct_used' }, ], + closure_custom_output => $self->can('custom_usage_output'), + perfdatas => [ + { template => '%.2f', min => 0, max => 100, unit => '%' } + ] + } + } + ]; +} + +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 => {}); + + return $self; +} + +my $mapping = { + memPlatformTotal => { oid => '.1.3.6.1.4.1.12276.1.2.1.4.1.1.5' }, + memPlatformUsed => { oid => '.1.3.6.1.4.1.12276.1.2.1.4.1.1.6' }, +}; +my $oid_memoryStatsEntry = '.1.3.6.1.4.1.12276.1.2.1.4.1.1'; + +sub manage_selection { + my ($self, %options) = @_; + + if ($options{snmp}->is_snmpv1()) { + $self->{output}->add_option_msg(short_msg => "Need to use SNMP v2c or v3."); + $self->{output}->option_exit(); + } + + my $results = $options{snmp}->get_table( + oid => $oid_memoryStatsEntry, + nothing_quit => 1 + ); + + my $result; + foreach (keys %$results) { + if (/^$mapping->{memPlatformUsed}->{oid}\.(.*)$/) { + $result = $options{snmp}->map_instance(mapping => $mapping, results => $results, instance => $1); + last + } + } + + my $free = $result->{memPlatformTotal} - $result->{memPlatformUsed}; + $self->{memory} = { + total => $result->{memPlatformTotal}, + used => $result->{memPlatformUsed}, + free => $free, + prct_used => ($result->{memPlatformUsed} / $result->{memPlatformTotal}) * 100, + prct_free => $free * 100 / $result->{memPlatformTotal}, + }; +} + +1; + +__END__ + +=head1 MODE + +Check memory usage. + + - memory.free.bytes Total amount of platform free memory in bytes + - memory.free.percent Total amount of platform used memory in percent + - memory.usage.bytes Total amount of platform used memory in bytes + - memory.usage.percent Total amount of platform used memory in percent + +=over 8 + +=item B<--filter-counters> + +Only display some counters (regexp can be used). +Can be : usage free usage-prct free-prct +Example : --filter-counters='^usage$' + +=item B<--warning-free> + +Threshold in bytes. + +=item B<--critical-free> + +Threshold in bytes. + +=item B<--warning-free-prct> + +Threshold in percentage. + +=item B<--critical-free-prct> + +Threshold in percentage. + +=item B<--warning-usage> + +Threshold in bytes. + +=item B<--critical-usage> + +Threshold in bytes. + +=item B<--warning-usage-prct> + +Threshold in percentage. + +=item B<--critical-usage-prct> + +Threshold in percentage. + +=back + +=cut diff --git a/src/os/f5os/snmp/plugin.pm b/src/os/f5os/snmp/plugin.pm new file mode 100644 index 000000000..1111d9be1 --- /dev/null +++ b/src/os/f5os/snmp/plugin.pm @@ -0,0 +1,50 @@ +# +# Copyright 2025 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 os::f5os::snmp::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; + + $self->{modes} = { + 'cpu-usage' => 'os::f5os::snmp::mode::cpuusage', + 'hardware' => 'os::f5os::snmp::mode::hardware', + 'memory' => 'os::f5os::snmp::mode::memory', + }; + + return $self; +} + +1; + +__END__ + +=head1 PLUGIN DESCRIPTION + +Check F5OS in SNMP. +Please use the SNMP F5OS plugin for system checks (CPU, memory, hardware, ...). + +=cut diff --git a/tests/os/f5os/snmp/cpu-usage.robot b/tests/os/f5os/snmp/cpu-usage.robot new file mode 100644 index 000000000..eb672a527 --- /dev/null +++ b/tests/os/f5os/snmp/cpu-usage.robot @@ -0,0 +1,32 @@ +*** Settings *** + +Resource ${CURDIR}${/}..${/}..${/}..${/}resources/import.resource + +Suite Setup Ctn Generic Suite Setup +Test Timeout 120s + + +*** Variables *** +${CMD} ${CENTREON_PLUGINS} --plugin=os::f5os::snmp::plugin + +*** Test Cases *** +cpu-usage ${tc} + [Tags] os f5os snmp + ${command} Catenate + ... ${CMD} + ... --mode=cpu-usage + ... --hostname=${HOSTNAME} + ... --snmp-version=${SNMPVERSION} + ... --snmp-port=${SNMPPORT} + ... --snmp-community=os/f5os/snmp/f5os + ... ${extra_options} + + Ctn Run Command And Check Result As Strings ${command} ${expected_result} + + Examples: tc extra_options expected_result -- + ... 1 ${EMPTY} OK: CPU(s) average usage is: 8.00 % | 'cpu.usage.percent'=8.00%;;;0;100 '0#cpu.core.current.usage.percent'=0%;;;0;100 '0#cpu.core.usage.avg.5s.percent'=0%;;;0;100 '0#cpu.core.usage.avg.1m.percent'=1%;;;0;100 '0#cpu.core.usage.avg.5m.percent'=1%;;;0;100 '1#cpu.core.current.usage.percent'=16%;;;0;100 '1#cpu.core.usage.avg.5s.percent'=10%;;;0;100 '1#cpu.core.usage.avg.1m.percent'=15%;;;0;100 '1#cpu.core.usage.avg.5m.percent'=50%;;;0;100 + ... 2 --include-id='1' OK: CPU(s) average usage is: 16.00 % - CPU '1' CPU Usage Current : 16 %, CPU Usage 5sec : 10 %, CPU Usage 1min : 15 %, CPU Usage 5min : 50 % | 'cpu.usage.percent'=16.00%;;;0;100 '1#cpu.core.current.usage.percent'=16%;;;0;100 '1#cpu.core.usage.avg.5s.percent'=10%;;;0;100 '1#cpu.core.usage.avg.1m.percent'=15%;;;0;100 '1#cpu.core.usage.avg.5m.percent'=50%;;;0;100 + ... 3 --include-name='Anonymized 118' OK: CPU(s) average usage is: 0.00 % - CPU '0' CPU Usage Current : 0 %, CPU Usage 5sec : 0 %, CPU Usage 1min : 1 %, CPU Usage 5min : 1 % | 'cpu.usage.percent'=0.00%;;;0;100 '0#cpu.core.current.usage.percent'=0%;;;0;100 '0#cpu.core.usage.avg.5s.percent'=0%;;;0;100 '0#cpu.core.usage.avg.1m.percent'=1%;;;0;100 '0#cpu.core.usage.avg.5m.percent'=1%;;;0;100 + ... 4 --critical-core-avg-1m=10 CRITICAL: CPU '1' CPU Usage 1min : 15 % | 'cpu.usage.percent'=8.00%;;;0;100 '0#cpu.core.current.usage.percent'=0%;;;0;100 '0#cpu.core.usage.avg.5s.percent'=0%;;;0;100 '0#cpu.core.usage.avg.1m.percent'=1%;;0:10;0;100 '0#cpu.core.usage.avg.5m.percent'=1%;;;0;100 '1#cpu.core.current.usage.percent'=16%;;;0;100 '1#cpu.core.usage.avg.5s.percent'=10%;;;0;100 '1#cpu.core.usage.avg.1m.percent'=15%;;0:10;0;100 '1#cpu.core.usage.avg.5m.percent'=50%;;;0;100 + ... 5 --warning-core-avg-5m=20 WARNING: CPU '1' CPU Usage 5min : 50 % | 'cpu.usage.percent'=8.00%;;;0;100 '0#cpu.core.current.usage.percent'=0%;;;0;100 '0#cpu.core.usage.avg.5s.percent'=0%;;;0;100 '0#cpu.core.usage.avg.1m.percent'=1%;;;0;100 '0#cpu.core.usage.avg.5m.percent'=1%;0:20;;0;100 '1#cpu.core.current.usage.percent'=16%;;;0;100 '1#cpu.core.usage.avg.5s.percent'=10%;;;0;100 '1#cpu.core.usage.avg.1m.percent'=15%;;;0;100 '1#cpu.core.usage.avg.5m.percent'=50%;0:20;;0;100 + ... 6 --include-id=1 --include-name='Anonymized 118' OK: CPU(s) average usage is: 8.00 % | 'cpu.usage.percent'=8.00%;;;0;100 '0#cpu.core.current.usage.percent'=0%;;;0;100 '0#cpu.core.usage.avg.5s.percent'=0%;;;0;100 '0#cpu.core.usage.avg.1m.percent'=1%;;;0;100 '0#cpu.core.usage.avg.5m.percent'=1%;;;0;100 '1#cpu.core.current.usage.percent'=16%;;;0;100 '1#cpu.core.usage.avg.5s.percent'=10%;;;0;100 '1#cpu.core.usage.avg.1m.percent'=15%;;;0;100 '1#cpu.core.usage.avg.5m.percent'=50%;;;0;100 diff --git a/tests/os/f5os/snmp/f5os.snmpwalk b/tests/os/f5os/snmp/f5os.snmpwalk new file mode 100644 index 000000000..fad3dd12e --- /dev/null +++ b/tests/os/f5os/snmp/f5os.snmpwalk @@ -0,0 +1,29 @@ +.1.3.6.1.4.1.12276.1.2.1.1.3.1.1.8.112.108.97.116.102.111.114.109.0 = INTEGER: 0 +.1.3.6.1.4.1.12276.1.2.1.1.3.1.1.8.112.108.97.116.102.111.114.109.1 = INTEGER: 1 +.1.3.6.1.4.1.12276.1.2.1.1.3.1.2.8.112.108.97.116.102.111.114.109.0 = STRING: Anonymized 118 +.1.3.6.1.4.1.12276.1.2.1.1.3.1.2.8.112.108.97.116.102.111.114.109.1 = STRING: Anonymized 040 +.1.3.6.1.4.1.12276.1.2.1.1.3.1.3.8.112.108.97.116.102.111.114.109.0 = INTEGER: 0 +.1.3.6.1.4.1.12276.1.2.1.1.3.1.3.8.112.108.97.116.102.111.114.109.1 = INTEGER: 16 +.1.3.6.1.4.1.12276.1.2.1.1.3.1.4.8.112.108.97.116.102.111.114.109.0 = INTEGER: 0 +.1.3.6.1.4.1.12276.1.2.1.1.3.1.4.8.112.108.97.116.102.111.114.109.1 = INTEGER: 10 +.1.3.6.1.4.1.12276.1.2.1.1.3.1.5.8.112.108.97.116.102.111.114.109.0 = INTEGER: 1 +.1.3.6.1.4.1.12276.1.2.1.1.3.1.5.8.112.108.97.116.102.111.114.109.1 = INTEGER: 15 +.1.3.6.1.4.1.12276.1.2.1.1.3.1.6.8.112.108.97.116.102.111.114.109.0 = INTEGER: 1 +.1.3.6.1.4.1.12276.1.2.1.1.3.1.6.8.112.108.97.116.102.111.114.109.1 = INTEGER: 50 +.1.3.6.1.4.1.12276.1.2.1.3.1.1.2.8.112.108.97.116.102.111.114.109 = INTEGER: 316 +.1.3.6.1.4.1.12276.1.2.1.3.1.1.3.8.112.108.97.116.102.111.114.109 = INTEGER: 321 +.1.3.6.1.4.1.12276.1.2.1.3.1.1.4.8.112.108.97.116.102.111.114.109 = INTEGER: 312 +.1.3.6.1.4.1.12276.1.2.1.3.1.1.5.8.112.108.97.116.102.111.114.109 = INTEGER: 338 +.1.3.6.1.4.1.12276.1.2.1.4.1.1.2.8.112.108.97.116.102.111.114.109 = Counter64: 9355182080 +.1.3.6.1.4.1.12276.1.2.1.4.1.1.3.8.112.108.97.116.102.111.114.109 = Counter64: 1082265600 +.1.3.6.1.4.1.12276.1.2.1.4.1.1.4.8.112.108.97.116.102.111.114.109 = INTEGER: 93 +.1.3.6.1.4.1.12276.1.2.1.4.1.1.5.8.112.108.97.116.102.111.114.109 = Counter64: 16107667456 +.1.3.6.1.4.1.12276.1.2.1.4.1.1.6.8.112.108.97.116.102.111.114.109 = Counter64: 7085105152 +.1.3.6.1.4.1.12276.1.2.1.7.1.1.1.8.112.108.97.116.102.111.114.109 = INTEGER: 15482 +.1.3.6.1.4.1.12276.1.2.1.7.1.1.2.8.112.108.97.116.102.111.114.109 = INTEGER: 17323 +.1.3.6.1.4.1.12276.1.2.1.7.1.1.3.8.112.108.97.116.102.111.114.109 = INTEGER: 17121 +.1.3.6.1.4.1.12276.1.2.1.7.1.1.4.8.112.108.97.116.102.111.114.109 = INTEGER: 17512 +.1.3.6.1.4.1.12276.1.2.1.7.1.1.5.8.112.108.97.116.102.111.114.109 = INTEGER: 17695 +.1.3.6.1.4.1.12276.1.2.1.7.1.1.6.8.112.108.97.116.102.111.114.109 = INTEGER: 13543 +.1.3.6.1.4.1.12276.1.2.1.7.1.1.7.8.112.108.97.116.102.111.114.109 = INTEGER: 16678 +.1.3.6.1.4.1.12276.1.2.1.7.1.1.8.8.112.108.97.116.102.111.114.109 = INTEGER: 17843 diff --git a/tests/os/f5os/snmp/hardware.robot b/tests/os/f5os/snmp/hardware.robot new file mode 100644 index 000000000..38fffc04d --- /dev/null +++ b/tests/os/f5os/snmp/hardware.robot @@ -0,0 +1,34 @@ +*** Settings *** + +Resource ${CURDIR}${/}..${/}..${/}..${/}resources/import.resource + +Suite Setup Ctn Generic Suite Setup +Test Timeout 120s + + +*** Variables *** +${CMD} ${CENTREON_PLUGINS} --plugin=os::f5os::snmp::plugin + +*** Test Cases *** +hardware ${tc} + [Tags] os f5os snmp + ${command} Catenate + ... ${CMD} + ... --mode=hardware + ... --hostname=${HOSTNAME} + ... --snmp-version=${SNMPVERSION} + ... --snmp-port=${SNMPPORT} + ... --snmp-community=os/f5os/snmp/f5os + ... ${extra_options} + + Ctn Run Command And Check Result As Strings ${command} ${expected_result} + + Examples: tc extra_options expected_result -- + ... 1 ${EMPTY} OK: Current temperature: 31.6 C, average: 32.1 C, minimum: 31.2 C, maximum: 33.8 C - All fans are ok | 'temperature.current.celsius'=31.6C;;;; 'temperature.average.1h.celsius'=32.1C;;;; 'temperature.min.1h.celsius'=31.2C;;;; 'temperature#temperature.max.1h.celsius'=33.8C;;;; '1#fantray.fanspeed.rpm'=15482rpm;;;0; '2#fantray.fanspeed.rpm'=17323rpm;;;0; '3#fantray.fanspeed.rpm'=17121rpm;;;0; '4#fantray.fanspeed.rpm'=17512rpm;;;0; '5#fantray.fanspeed.rpm'=17695rpm;;;0; '6#fantray.fanspeed.rpm'=13543rpm;;;0; '7#fantray.fanspeed.rpm'=16678rpm;;;0; '8#fantray.fanspeed.rpm'=17843rpm;;;0; + ... 2 --filter-counters=min-temperature OK: minimum: 31.2 C | 'temperature.min.1h.celsius'=31.2C;;;; + ... 3 --include-id=2 OK: Current temperature: 31.6 C, average: 32.1 C, minimum: 31.2 C, maximum: 33.8 C - fan '2' speed is 17323 rpm | 'temperature.current.celsius'=31.6C;;;; 'temperature.average.1h.celsius'=32.1C;;;; 'temperature.min.1h.celsius'=31.2C;;;; 'temperature#temperature.max.1h.celsius'=33.8C;;;; '2#fantray.fanspeed.rpm'=17323rpm;;;0; + ... 4 --warning-current-temperature=10 WARNING: Current temperature: 31.6 C | 'temperature.current.celsius'=31.6C;0:10;;; 'temperature.average.1h.celsius'=32.1C;;;; 'temperature.min.1h.celsius'=31.2C;;;; 'temperature#temperature.max.1h.celsius'=33.8C;;;; '1#fantray.fanspeed.rpm'=15482rpm;;;0; '2#fantray.fanspeed.rpm'=17323rpm;;;0; '3#fantray.fanspeed.rpm'=17121rpm;;;0; '4#fantray.fanspeed.rpm'=17512rpm;;;0; '5#fantray.fanspeed.rpm'=17695rpm;;;0; '6#fantray.fanspeed.rpm'=13543rpm;;;0; '7#fantray.fanspeed.rpm'=16678rpm;;;0; '8#fantray.fanspeed.rpm'=17843rpm;;;0; + ... 5 --warning-average-temperature=10 WARNING: average: 32.1 C | 'temperature.current.celsius'=31.6C;;;; 'temperature.average.1h.celsius'=32.1C;0:10;;; 'temperature.min.1h.celsius'=31.2C;;;; 'temperature#temperature.max.1h.celsius'=33.8C;;;; '1#fantray.fanspeed.rpm'=15482rpm;;;0; '2#fantray.fanspeed.rpm'=17323rpm;;;0; '3#fantray.fanspeed.rpm'=17121rpm;;;0; '4#fantray.fanspeed.rpm'=17512rpm;;;0; '5#fantray.fanspeed.rpm'=17695rpm;;;0; '6#fantray.fanspeed.rpm'=13543rpm;;;0; '7#fantray.fanspeed.rpm'=16678rpm;;;0; '8#fantray.fanspeed.rpm'=17843rpm;;;0; + ... 6 --critical-min-temperature=20 CRITICAL: minimum: 31.2 C | 'temperature.current.celsius'=31.6C;;;; 'temperature.average.1h.celsius'=32.1C;;;; 'temperature.min.1h.celsius'=31.2C;;0:20;; 'temperature#temperature.max.1h.celsius'=33.8C;;;; '1#fantray.fanspeed.rpm'=15482rpm;;;0; '2#fantray.fanspeed.rpm'=17323rpm;;;0; '3#fantray.fanspeed.rpm'=17121rpm;;;0; '4#fantray.fanspeed.rpm'=17512rpm;;;0; '5#fantray.fanspeed.rpm'=17695rpm;;;0; '6#fantray.fanspeed.rpm'=13543rpm;;;0; '7#fantray.fanspeed.rpm'=16678rpm;;;0; '8#fantray.fanspeed.rpm'=17843rpm;;;0; + ... 7 --critical-max-temperature=10 CRITICAL: maximum: 33.8 C | 'temperature.current.celsius'=31.6C;;;; 'temperature.average.1h.celsius'=32.1C;;;; 'temperature.min.1h.celsius'=31.2C;;;; 'temperature#temperature.max.1h.celsius'=33.8C;;0:10;; '1#fantray.fanspeed.rpm'=15482rpm;;;0; '2#fantray.fanspeed.rpm'=17323rpm;;;0; '3#fantray.fanspeed.rpm'=17121rpm;;;0; '4#fantray.fanspeed.rpm'=17512rpm;;;0; '5#fantray.fanspeed.rpm'=17695rpm;;;0; '6#fantray.fanspeed.rpm'=13543rpm;;;0; '7#fantray.fanspeed.rpm'=16678rpm;;;0; '8#fantray.fanspeed.rpm'=17843rpm;;;0; + ... 8 --component=temperature OK: Current temperature: 31.6 C, average: 32.1 C, minimum: 31.2 C, maximum: 33.8 C | 'temperature.current.celsius'=31.6C;;;; 'temperature.average.1h.celsius'=32.1C;;;; 'temperature.min.1h.celsius'=31.2C;;;; 'temperature#temperature.max.1h.celsius'=33.8C;;;; diff --git a/tests/os/f5os/snmp/memory.robot b/tests/os/f5os/snmp/memory.robot new file mode 100644 index 000000000..c9f5e5bd6 --- /dev/null +++ b/tests/os/f5os/snmp/memory.robot @@ -0,0 +1,31 @@ +*** Settings *** + +Resource ${CURDIR}${/}..${/}..${/}..${/}resources/import.resource + +Suite Setup Ctn Generic Suite Setup +Test Timeout 120s + + +*** Variables *** +${CMD} ${CENTREON_PLUGINS} --plugin=os::f5os::snmp::plugin + +*** Test Cases *** +memory ${tc} + [Tags] os f5os snmp + ${command} Catenate + ... ${CMD} + ... --mode=memory + ... --hostname=${HOSTNAME} + ... --snmp-version=${SNMPVERSION} + ... --snmp-port=${SNMPPORT} + ... --snmp-community=os/f5os/snmp/f5os + ... ${extra_options} + + Ctn Run Command And Check Result As Strings ${command} ${expected_result} + + Examples: tc extra_options expected_result -- + ... 1 ${EMPTY} OK: Memory total: 15.00 GB used: 6.60 GB (43.99%) free: 8.40 GB (56.01%) | 'memory.usage.bytes'=7085105152B;;;0;16107667456 'memory.free.bytes'=9022562304B;;;0;16107667456 'memory.usage.percent'=43.99%;;;0;100 'memory.free.percent'=56.01%;;;0;100 + ... 2 --warning-usage=:5GB WARNING: Memory total: 15.00 GB used: 6.60 GB (43.99%) free: 8.40 GB (56.01%) | 'memory.usage.bytes'=7085105152B;0:5368709120;;0;16107667456 'memory.free.bytes'=9022562304B;;;0;16107667456 'memory.usage.percent'=43.99%;;;0;100 'memory.free.percent'=56.01%;;;0;100 + ... 3 --critical-free=:6GB CRITICAL: Memory total: 15.00 GB used: 6.60 GB (43.99%) free: 8.40 GB (56.01%) | 'memory.usage.bytes'=7085105152B;;;0;16107667456 'memory.free.bytes'=9022562304B;;0:6442450944;0;16107667456 'memory.usage.percent'=43.99%;;;0;100 'memory.free.percent'=56.01%;;;0;100 + ... 4 --critical-usage-prct=40 CRITICAL: Memory total: 15.00 GB used: 6.60 GB (43.99%) free: 8.40 GB (56.01%) | 'memory.usage.bytes'=7085105152B;;;0;16107667456 'memory.free.bytes'=9022562304B;;;0;16107667456 'memory.usage.percent'=43.99%;;0:40;0;100 'memory.free.percent'=56.01%;;;0;100 + ... 5 --warning-free-prct=60: WARNING: Memory total: 15.00 GB used: 6.60 GB (43.99%) free: 8.40 GB (56.01%) | 'memory.usage.bytes'=7085105152B;;;0;16107667456 'memory.free.bytes'=9022562304B;;;0;16107667456 'memory.usage.percent'=43.99%;;;0;100 'memory.free.percent'=56.01%;60:;;0;100 diff --git a/tests/resources/spellcheck/stopwords.txt b/tests/resources/spellcheck/stopwords.txt index 7f437970f..5b863375f 100644 --- a/tests/resources/spellcheck/stopwords.txt +++ b/tests/resources/spellcheck/stopwords.txt @@ -76,6 +76,7 @@ eth Exense ext4 F5 +F5OS failover fanspeed FCCapacity