diff --git a/.github/workflows/tests-functional.yml b/.github/workflows/tests-functional.yml index 89403d30f..88dc3ebc5 100644 --- a/.github/workflows/tests-functional.yml +++ b/.github/workflows/tests-functional.yml @@ -60,7 +60,9 @@ jobs: python-version: '3.11' - name: Install Robot Framework - run: pip3.11 install robotframework + run: | + pip3.11 install robotframework + pip3.11 install RobotFramework-Examples shell: bash - name: Run Robot Framework API tests diff --git a/packaging/centreon-plugin-Hardware-Ups-Inmatics-Sputnik-Snmp/deb.json b/packaging/centreon-plugin-Hardware-Ups-Inmatics-Sputnik-Snmp/deb.json new file mode 100644 index 000000000..663aaaceb --- /dev/null +++ b/packaging/centreon-plugin-Hardware-Ups-Inmatics-Sputnik-Snmp/deb.json @@ -0,0 +1,5 @@ +{ + "dependencies": [ + "libsnmp-perl" + ] +} \ No newline at end of file diff --git a/packaging/centreon-plugin-Hardware-Ups-Inmatics-Sputnik-Snmp/pkg.json b/packaging/centreon-plugin-Hardware-Ups-Inmatics-Sputnik-Snmp/pkg.json new file mode 100644 index 000000000..74ec4a298 --- /dev/null +++ b/packaging/centreon-plugin-Hardware-Ups-Inmatics-Sputnik-Snmp/pkg.json @@ -0,0 +1,11 @@ +{ + "pkg_name": "centreon-plugin-Hardware-Ups-Inmatics-Sputnik-Snmp", + "pkg_summary": "Centreon Plugin - Hardware UPS Inmatics PSU Sputnik SNMP", + "plugin_name": "centreon_ups_sputnik_snmp.pl", + "files": [ + "centreon/plugins/script_snmp.pm", + "centreon/plugins/snmp.pm", + "hardware/ups/standard/rfc1628/snmp/", + "hardware/ups/inmatics/sputnik/snmp/" + ] +} \ No newline at end of file diff --git a/packaging/centreon-plugin-Hardware-Ups-Inmatics-Sputnik-Snmp/rpm.json b/packaging/centreon-plugin-Hardware-Ups-Inmatics-Sputnik-Snmp/rpm.json new file mode 100644 index 000000000..418a331fc --- /dev/null +++ b/packaging/centreon-plugin-Hardware-Ups-Inmatics-Sputnik-Snmp/rpm.json @@ -0,0 +1,5 @@ +{ + "dependencies": [ + "perl(SNMP)" + ] +} \ No newline at end of file diff --git a/src/hardware/ups/inmatics/sputnik/snmp/mode/environment.pm b/src/hardware/ups/inmatics/sputnik/snmp/mode/environment.pm new file mode 100644 index 000000000..ca0ca148b --- /dev/null +++ b/src/hardware/ups/inmatics/sputnik/snmp/mode/environment.pm @@ -0,0 +1,153 @@ +# +# 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 hardware::ups::inmatics::sputnik::snmp::mode::environment; + +use base qw(centreon::plugins::templates::counter); + +# Needed libraries +use strict; +use warnings; + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1); + bless $self, $class; + + # Declare options + $options{options}->add_options(arguments => { + 'filter-id:s' => { name => 'filter_id' } + }); + + return $self; +} + +sub prefix_sensors_output { + my ($self, %options) = @_; + + return "'" . $options{instance_value}->{display} . "': "; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'sensors', type => 1, cb_prefix_output => 'prefix_sensors_output', message_multiple => 'All sensors are ok' } + ]; + + $self->{maps_counters}->{sensors} = [ + { label => 'temperature', nlabel => 'environment.temperature.celsius', set => { + key_values => [ { name => 'temperature' }, { name => 'display' } ], + output_template => 'temperature %.2f C', + perfdatas => [ + { label => 'temperature', template => '%.2f', unit => 'C', label_extra_instance => 1, instance_use => 'display' } + ] + } + }, + { label => 'humidity', nlabel => 'environment.humidity.percentage', set => { + key_values => [ { name => 'humidity' }, { name => 'display' } ], + output_template => 'humidity %s %%', + perfdatas => [ + { label => 'humidity', template => '%s', min => 0, max => 100, unit => '%', label_extra_instance => 1, instance_use => 'display' } + ] + } + } + ]; +} + +sub manage_selection { + my ($self, %options) = @_; + + # FI: upsEnvSensorCounts is not used but it gives the number of sensors + #my $oid_upsEnvSensorCounts = '.1.3.6.1.4.1.54661.1.1.1.2.1.0'; + my $oid_upsEnvSensors = '.1.3.6.1.4.1.54661.1.1.1.2.2.1'; + # FI: the actual MIB OIDs: + #my $oid_upsEnvSensorTemperature = '.1.3.6.1.4.1.54661.1.1.1.2.2.1.2'; + #my $oid_upsEnvSensorHumidity = '.1.3.6.1.4.1.54661.1.1.1.2.2.1.3'; + + # Each sensor will provide a temperature (in 100th of degrees) and a humidity percentage + my $mapping = { + upsEnvSensorTemperature => { oid => $oid_upsEnvSensors.'.2' }, + upsEnvSensorHumidity => { oid => $oid_upsEnvSensors.'.3' } + }; + my $snmp_result = $options{snmp}->get_table( + oid => $oid_upsEnvSensors, + nothing_quit => 1 + ); + + $self->{sensors} = {}; + foreach my $oid (sort(keys %{$snmp_result})) { + next if ($oid !~ /^$oid_upsEnvSensors\.2\.(.*)$/); + # The index of the sensor will be used in the instance name + my $sensor_index = $1; + + # Skip if a filter is defined and the current sensor does not match + if (defined($self->{option_results}->{filter_id}) && $sensor_index ne '' && $sensor_index !~ /$self->{option_results}->{filter_id}/ ) { + $self->{output}->output_add( + long_msg => "With filter-id: '$self->{option_results}->{filter_id}' - Skipping sensor '$sensor_index'.", + debug => 1 + ); + next; + } + + # Get all the metrics for the current instance + my $result = $options{snmp}->map_instance( + mapping => $mapping, + results => $snmp_result, + instance => $sensor_index + ); + + # The temperature is given multiplied by 100, so we have to divide it by 100 + # cf MIB: UNITS "0.01 degrees Centigrade" + $self->{sensors}->{$sensor_index} = { + display => 'Sensor '.$sensor_index, + temperature => $result->{upsEnvSensorTemperature} / 100, + humidity => $result->{upsEnvSensorHumidity} + }; + } + + # No results is not OK + if (scalar(keys %{$self->{sensors}}) <= 0) { + $self->{output}->add_option_msg(short_msg => "No sensors found."); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Monitor temperature and humidity using the device's environment sensors. + +=over 8 + +=item B<--warning-*> B<--critical-*> + +Thresholds. Can be: 'humidity' (%), 'temperature' (C). + +=item B<--filter-id> + +Define which sensors should be monitored based on their IDs. This option will be treated as a regular expression. + +=back + +=cut diff --git a/src/hardware/ups/inmatics/sputnik/snmp/plugin.pm b/src/hardware/ups/inmatics/sputnik/snmp/plugin.pm new file mode 100644 index 000000000..33efcdc9c --- /dev/null +++ b/src/hardware/ups/inmatics/sputnik/snmp/plugin.pm @@ -0,0 +1,52 @@ +# +# 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 hardware::ups::inmatics::sputnik::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} = { + 'alarms' => 'hardware::ups::standard::rfc1628::snmp::mode::alarms', + 'battery-status' => 'hardware::ups::standard::rfc1628::snmp::mode::batterystatus', + 'environment' => 'hardware::ups::inmatics::sputnik::snmp::mode::environment', + 'input-lines' => 'hardware::ups::standard::rfc1628::snmp::mode::inputlines', + 'output-lines' => 'hardware::ups::standard::rfc1628::snmp::mode::outputlines', + 'output-source' => 'hardware::ups::standard::rfc1628::snmp::mode::outputsource' + }; + + return $self; +} + +1; + +__END__ + +=head1 PLUGIN DESCRIPTION + +Check Sputnik UPS using SNMP. + +=cut diff --git a/tests/functional/snmp/hardware-ups-sputnik-snmp.robot b/tests/functional/snmp/hardware-ups-sputnik-snmp.robot new file mode 100644 index 000000000..59567b59e --- /dev/null +++ b/tests/functional/snmp/hardware-ups-sputnik-snmp.robot @@ -0,0 +1,63 @@ +*** Settings *** +Documentation Hardware UPS Sputnik SNMP plugin + +Library OperatingSystem +Library String +Library Examples + +Test Timeout 120s + + +*** Variables *** +${CENTREON_PLUGINS} ${CURDIR}${/}..${/}..${/}..${/}src${/}centreon_plugins.pl + +${CMD} perl ${CENTREON_PLUGINS} --plugin=hardware::ups::inmatics::sputnik::snmp::plugin + +*** Test Cases *** +Sputnik UPS - Environment ${tc}/9 + [Tags] hardware UPS snmp + ${command} Catenate + ... ${CMD} + ... --mode=environment + ... --hostname=127.0.0.1 + ... --snmp-version=2c + ... --snmp-port=2024 + ... --snmp-community=hardware-ups/hardware-ups-sputnik + + # Append options to command + ${opt} Append Option --warning-temperature ${w_temperature} + ${command} Catenate ${command} ${opt} + ${opt} Append Option --critical-temperature ${c_temperature} + ${command} Catenate ${command} ${opt} + ${opt} Append Option --warning-humidity ${w_humidity} + ${command} Catenate ${command} ${opt} + ${opt} Append Option --critical-humidity ${c_humidity} + ${command} Catenate ${command} ${opt} + ${opt} Append Option --filter-id ${filter_id} + ${command} Catenate ${command} ${opt} + + ${output} Run ${command} + ${output} Strip String ${output} + Should Be Equal As Strings + ... ${output} + ... ${expected_result} + ... Wrong output result for compliance of ${expected_result}{\n}Command output:{\n}${output}{\n}{\n}{\n} + + Examples: tc filter_id w_temperature c_temperature w_humidity c_humidity expected_result -- + ... 1 1 30 50 50 70 OK: 'Sensor 1': temperature 20.06 C, humidity 33 % | 'Sensor 1#environment.temperature.celsius'=20.06C;0:30;0:50;; 'Sensor 1#environment.humidity.percentage'=33%;0:50;0:70;0;100 + ... 2 1 20 50 50 70 WARNING: 'Sensor 1': temperature 20.06 C | 'Sensor 1#environment.temperature.celsius'=20.06C;0:20;0:50;; 'Sensor 1#environment.humidity.percentage'=33%;0:50;0:70;0;100 + ... 3 1 10 20 50 70 CRITICAL: 'Sensor 1': temperature 20.06 C | 'Sensor 1#environment.temperature.celsius'=20.06C;0:10;0:20;; 'Sensor 1#environment.humidity.percentage'=33%;0:50;0:70;0;100 + ... 4 1 30 50 20 70 WARNING: 'Sensor 1': humidity 33 % | 'Sensor 1#environment.temperature.celsius'=20.06C;0:30;0:50;; 'Sensor 1#environment.humidity.percentage'=33%;0:20;0:70;0;100 + ... 5 1 30 50 20 30 CRITICAL: 'Sensor 1': humidity 33 % | 'Sensor 1#environment.temperature.celsius'=20.06C;0:30;0:50;; 'Sensor 1#environment.humidity.percentage'=33%;0:20;0:30;0;100 + ... 6 1 10 50 20 70 WARNING: 'Sensor 1': temperature 20.06 C, humidity 33 % | 'Sensor 1#environment.temperature.celsius'=20.06C;0:10;0:50;; 'Sensor 1#environment.humidity.percentage'=33%;0:20;0:70;0;100 + ... 7 1 10 20 20 30 CRITICAL: 'Sensor 1': temperature 20.06 C, humidity 33 % | 'Sensor 1#environment.temperature.celsius'=20.06C;0:10;0:20;; 'Sensor 1#environment.humidity.percentage'=33%;0:20;0:30;0;100 + ... 8 2 30 50 50 70 UNKNOWN: No sensors found. + ... 9 1 _empty_ _empty_ _empty_ _empty_ OK: 'Sensor 1': temperature 20.06 C, humidity 33 % | 'Sensor 1#environment.temperature.celsius'=20.06C;;;; 'Sensor 1#environment.humidity.percentage'=33%;;;0;100 + +*** Keywords *** +Append Option + [Documentation] Concatenates the first argument (option) with the second (value) after having replaced the value with "" if its content is '_empty_' + [Arguments] ${option} ${value} + ${value} Set Variable If '${value}' == '_empty_' '' ${value} + [return] ${option}=${value} + diff --git a/tests/resources/snmp/hardware-ups/hardware-ups-sputnik.snmpwalk b/tests/resources/snmp/hardware-ups/hardware-ups-sputnik.snmpwalk new file mode 100644 index 000000000..3ae444b01 --- /dev/null +++ b/tests/resources/snmp/hardware-ups/hardware-ups-sputnik.snmpwalk @@ -0,0 +1,61 @@ +.1.3.6.1.4.1.54661.1.1.1.1.1.1.1.0 = INTEGER: 0 +.1.3.6.1.4.1.54661.1.1.1.1.1.1.2.0 = INTEGER: 0 +.1.3.6.1.4.1.54661.1.1.1.1.1.1.3.0 = INTEGER: 0 +.1.3.6.1.4.1.54661.1.1.1.1.1.1.4.0 = INTEGER: 0 +.1.3.6.1.4.1.54661.1.1.1.1.1.1.5.0 = INTEGER: 0 +.1.3.6.1.4.1.54661.1.1.1.1.1.1.6.0 = INTEGER: 2 +.1.3.6.1.4.1.54661.1.1.1.1.1.1.7.0 = INTEGER: 0 +.1.3.6.1.4.1.54661.1.1.1.1.1.1.8.0 = INTEGER: 0 +.1.3.6.1.4.1.54661.1.1.1.1.1.1.9.0 = INTEGER: 0 +.1.3.6.1.4.1.54661.1.1.1.1.1.1.10.0 = INTEGER: 2 +.1.3.6.1.4.1.54661.1.1.1.1.1.1.11.0 = INTEGER: 2 +.1.3.6.1.4.1.54661.1.1.1.1.1.1.12.0 = INTEGER: 2 +.1.3.6.1.4.1.54661.1.1.1.1.1.1.13.0 = INTEGER: 0 +.1.3.6.1.4.1.54661.1.1.1.1.1.1.14.0 = INTEGER: 2 +.1.3.6.1.4.1.54661.1.1.1.1.1.1.15.0 = INTEGER: 0 +.1.3.6.1.4.1.54661.1.1.1.1.1.1.16.0 = INTEGER: 2 +.1.3.6.1.4.1.54661.1.1.1.1.1.1.17.0 = INTEGER: 2 +.1.3.6.1.4.1.54661.1.1.1.1.1.1.18.0 = INTEGER: 0 +.1.3.6.1.4.1.54661.1.1.1.1.1.1.19.0 = INTEGER: 0 +.1.3.6.1.4.1.54661.1.1.1.1.1.1.20.0 = INTEGER: 0 +.1.3.6.1.4.1.54661.1.1.1.1.1.1.21.0 = INTEGER: 2 +.1.3.6.1.4.1.54661.1.1.1.1.1.1.22.0 = INTEGER: 2 +.1.3.6.1.4.1.54661.1.1.1.1.1.1.23.0 = INTEGER: 2 +.1.3.6.1.4.1.54661.1.1.1.1.1.1.24.0 = INTEGER: 0 +.1.3.6.1.4.1.54661.1.1.1.1.2.1.1.0 = INTEGER: 0 +.1.3.6.1.4.1.54661.1.1.1.1.2.1.2.0 = INTEGER: 0 +.1.3.6.1.4.1.54661.1.1.1.1.2.1.3.0 = INTEGER: 0 +.1.3.6.1.4.1.54661.1.1.1.1.2.1.4.0 = INTEGER: 0 +.1.3.6.1.4.1.54661.1.1.1.1.2.1.5.0 = INTEGER: 0 +.1.3.6.1.4.1.54661.1.1.1.1.2.1.6.0 = INTEGER: 0 +.1.3.6.1.4.1.54661.1.1.1.1.2.1.7.0 = INTEGER: 0 +.1.3.6.1.4.1.54661.1.1.1.1.2.1.8.0 = INTEGER: 0 +.1.3.6.1.4.1.54661.1.1.1.1.2.1.9.0 = INTEGER: 0 +.1.3.6.1.4.1.54661.1.1.1.1.2.1.10.0 = INTEGER: 0 +.1.3.6.1.4.1.54661.1.1.1.1.2.1.11.0 = INTEGER: 0 +.1.3.6.1.4.1.54661.1.1.1.1.2.1.12.0 = INTEGER: 0 +.1.3.6.1.4.1.54661.1.1.1.1.2.1.13.0 = INTEGER: 0 +.1.3.6.1.4.1.54661.1.1.1.1.2.1.14.0 = INTEGER: 0 +.1.3.6.1.4.1.54661.1.1.1.1.2.1.15.0 = INTEGER: 0 +.1.3.6.1.4.1.54661.1.1.1.1.2.1.16.0 = INTEGER: 0 +.1.3.6.1.4.1.54661.1.1.1.1.2.1.17.0 = INTEGER: 0 +.1.3.6.1.4.1.54661.1.1.1.1.2.1.18.0 = INTEGER: 0 +.1.3.6.1.4.1.54661.1.1.1.1.2.1.19.0 = INTEGER: 0 +.1.3.6.1.4.1.54661.1.1.1.1.2.1.20.0 = INTEGER: 0 +.1.3.6.1.4.1.54661.1.1.1.1.2.1.21.0 = INTEGER: 0 +.1.3.6.1.4.1.54661.1.1.1.1.2.1.22.0 = INTEGER: 0 +.1.3.6.1.4.1.54661.1.1.1.1.2.1.23.0 = INTEGER: 0 +.1.3.6.1.4.1.54661.1.1.1.1.2.1.24.0 = INTEGER: 0 +.1.3.6.1.4.1.54661.1.1.1.1.6.1.1.0 = INTEGER: 0 +.1.3.6.1.4.1.54661.1.1.1.1.6.1.2.0 = INTEGER: 3 +.1.3.6.1.4.1.54661.1.1.1.1.6.2.1.0 = INTEGER: 0 +.1.3.6.1.4.1.54661.1.1.1.1.6.2.2.0 = INTEGER: 0 +.1.3.6.1.4.1.54661.1.1.1.1.6.2.3.0 = INTEGER: 0 +.1.3.6.1.4.1.54661.1.1.1.1.6.2.4.0 = INTEGER: 0 +.1.3.6.1.4.1.54661.1.1.1.2.1.0 = INTEGER: 1 +.1.3.6.1.4.1.54661.1.1.1.2.2.1.2.1 = INTEGER: 2006 +.1.3.6.1.4.1.54661.1.1.1.2.2.1.3.1 = INTEGER: 33 +.1.3.6.1.4.1.54661.1.1.1.2.3.0 = INTEGER: 0 +.1.3.6.1.4.1.54661.1.1.1.2.4.0 = INTEGER: 0 +.1.3.6.1.4.1.54661.1.1.1.2.5.0 = INTEGER: 0 +.1.3.6.1.4.1.54661.1.1.1.3.1.0 = INTEGER: 0