From 490945440b668dd9700b3ea25d5571c682ce6307 Mon Sep 17 00:00:00 2001 From: omercier Date: Thu, 20 Mar 2025 11:29:56 +0100 Subject: [PATCH 1/5] fix(ci): add missing image + fix path for tests on noble --- .github/actions/test-plugins/action.yml | 4 +++- .github/docker/testing/Dockerfile.testing-plugins-alma8 | 2 +- .github/docker/testing/Dockerfile.testing-plugins-alma9 | 2 +- .github/docker/testing/Dockerfile.testing-plugins-bookworm | 2 +- .github/docker/testing/Dockerfile.testing-plugins-bullseye | 2 +- .github/docker/testing/Dockerfile.testing-plugins-jammy | 2 +- .github/docker/testing/Dockerfile.testing-plugins-noble | 4 ++-- .github/workflows/plugins.yml | 4 ++-- 8 files changed, 12 insertions(+), 10 deletions(-) diff --git a/.github/actions/test-plugins/action.yml b/.github/actions/test-plugins/action.yml index bbcf5bfd76..ac24b7d1c6 100644 --- a/.github/actions/test-plugins/action.yml +++ b/.github/actions/test-plugins/action.yml @@ -24,4 +24,6 @@ runs: - name: Install, test and remove plugin shell: bash - run: python3 .github/scripts/test-all-plugins.py ${{ inputs.package-extension }} ${{ inputs.plugin-list }} + run: | + [[ -f /.venv/bin/activate ]] && source /.venv/bin/activate + python3 .github/scripts/test-all-plugins.py ${{ inputs.package-extension }} ${{ inputs.plugin-list }} diff --git a/.github/docker/testing/Dockerfile.testing-plugins-alma8 b/.github/docker/testing/Dockerfile.testing-plugins-alma8 index 22d2d9c07a..71abc16087 100644 --- a/.github/docker/testing/Dockerfile.testing-plugins-alma8 +++ b/.github/docker/testing/Dockerfile.testing-plugins-alma8 @@ -12,7 +12,7 @@ dnf clean all dnf install -y python3.11 python3.11-pip pip3.11 install robotframework robotframework-examples # Install snmpsim -pip3.11 install snmpsim-lextudio +pip3.11 install snmpsim # Install node curl -fsSL https://rpm.nodesource.com/setup_21.x | bash - diff --git a/.github/docker/testing/Dockerfile.testing-plugins-alma9 b/.github/docker/testing/Dockerfile.testing-plugins-alma9 index d5cead3a20..95edbe7640 100644 --- a/.github/docker/testing/Dockerfile.testing-plugins-alma9 +++ b/.github/docker/testing/Dockerfile.testing-plugins-alma9 @@ -12,7 +12,7 @@ dnf clean all dnf install -y python3.11 python3.11-pip pip3.11 install robotframework robotframework-examples # Install snmpsim -pip3.11 install snmpsim-lextudio +pip3.11 install snmpsim # Install node curl -fsSL https://rpm.nodesource.com/setup_21.x | bash - diff --git a/.github/docker/testing/Dockerfile.testing-plugins-bookworm b/.github/docker/testing/Dockerfile.testing-plugins-bookworm index f5e70048ea..48d6e00221 100644 --- a/.github/docker/testing/Dockerfile.testing-plugins-bookworm +++ b/.github/docker/testing/Dockerfile.testing-plugins-bookworm @@ -28,7 +28,7 @@ apt-get install -y python3-dev python3-pip rm -rf /usr/lib/python3.11/EXTERNALLY-MANAGED pip3 install robotframework robotframework-examples # Install snmpsim -pip3 install snmpsim-lextudio +pip3 install snmpsim # Install nodejs curl -fsSL https://deb.nodesource.com/setup_21.x | bash - &&\ diff --git a/.github/docker/testing/Dockerfile.testing-plugins-bullseye b/.github/docker/testing/Dockerfile.testing-plugins-bullseye index 171240fb7f..87700be3ac 100644 --- a/.github/docker/testing/Dockerfile.testing-plugins-bullseye +++ b/.github/docker/testing/Dockerfile.testing-plugins-bullseye @@ -27,7 +27,7 @@ apt-get update apt-get install -y python3 python3-dev python3-pip pip3 install robotframework robotframework-examples # Install snmpsim -pip3 install snmpsim-lextudio +pip3 install snmpsim # Install nodejs curl -fsSL https://deb.nodesource.com/setup_21.x | bash - &&\ diff --git a/.github/docker/testing/Dockerfile.testing-plugins-jammy b/.github/docker/testing/Dockerfile.testing-plugins-jammy index 0678ac512b..7519cd7103 100644 --- a/.github/docker/testing/Dockerfile.testing-plugins-jammy +++ b/.github/docker/testing/Dockerfile.testing-plugins-jammy @@ -27,7 +27,7 @@ apt-get update apt-get install -y python3 python3-dev python3-pip pip3 install robotframework robotframework-examples # Install snmpsim -pip3 install snmpsim-lextudio +pip3 install snmpsim # Install nodejs curl -fsSL https://deb.nodesource.com/setup_21.x | bash - &&\ diff --git a/.github/docker/testing/Dockerfile.testing-plugins-noble b/.github/docker/testing/Dockerfile.testing-plugins-noble index 77260b47ff..4b89178e3d 100644 --- a/.github/docker/testing/Dockerfile.testing-plugins-noble +++ b/.github/docker/testing/Dockerfile.testing-plugins-noble @@ -29,9 +29,9 @@ python3 -m venv .venv source .venv/bin/activate # Install Robotframework apt-get install -y python3 python3-dev python3-pip -.venv/bin/pip3 install robotframework robotframework-examples +pip3 install robotframework robotframework-examples # Install snmpsim -.venv/bin/pip3 install snmpsim-lextudio +pip3 install snmpsim # Install nodejs curl -fsSL https://deb.nodesource.com/setup_21.x | bash - &&\ diff --git a/.github/workflows/plugins.yml b/.github/workflows/plugins.yml index e4d67fe5b8..2052a609d2 100644 --- a/.github/workflows/plugins.yml +++ b/.github/workflows/plugins.yml @@ -98,7 +98,7 @@ jobs: strategy: fail-fast: false matrix: - image: [unit-tests-alma8, unit-tests-alma9, unit-tests-bullseye, unit-tests-bullseye-arm64, unit-tests-bookworm, unit-tests-jammy] + image: [unit-tests-alma8, unit-tests-alma9, unit-tests-bullseye, unit-tests-bullseye-arm64, unit-tests-bookworm, unit-tests-jammy, unit-tests-noble] include: - runner_name: ubuntu-24.04 - package_extension: rpm @@ -317,7 +317,7 @@ jobs: strategy: fail-fast: false matrix: - image: [testing-plugins-alma8, testing-plugins-alma9, testing-plugins-jammy, testing-plugins-bullseye, testing-plugins-bookworm] + image: [testing-plugins-alma8, testing-plugins-alma9, testing-plugins-jammy, testing-plugins-bullseye, testing-plugins-bookworm, testing-plugins-noble, testing-plugins-bullseye-arm64] include: - runner_name: ubuntu-24.04 - package_extension: rpm From 68e73fc9b6c545eca212847a3aa9f5cf380757bf Mon Sep 17 00:00:00 2001 From: garnier-quentin Date: Mon, 27 Jul 2026 06:19:39 -0400 Subject: [PATCH 2/5] wip --- src/apps/monitoring/prtg/api/custom/apiv1.pm | 319 +++++++++++++ src/apps/monitoring/prtg/api/mode/cache.pm | 61 +++ src/apps/monitoring/prtg/api/mode/devices.pm | 179 ++++++++ .../monitoring/prtg/api/mode/discovery.pm | 126 +++++ src/apps/monitoring/prtg/api/mode/sensors.pm | 432 ++++++++++++++++++ src/apps/monitoring/prtg/api/plugin.pm | 51 +++ 6 files changed, 1168 insertions(+) create mode 100644 src/apps/monitoring/prtg/api/custom/apiv1.pm create mode 100644 src/apps/monitoring/prtg/api/mode/cache.pm create mode 100644 src/apps/monitoring/prtg/api/mode/devices.pm create mode 100644 src/apps/monitoring/prtg/api/mode/discovery.pm create mode 100644 src/apps/monitoring/prtg/api/mode/sensors.pm create mode 100644 src/apps/monitoring/prtg/api/plugin.pm diff --git a/src/apps/monitoring/prtg/api/custom/apiv1.pm b/src/apps/monitoring/prtg/api/custom/apiv1.pm new file mode 100644 index 0000000000..d43385d2ff --- /dev/null +++ b/src/apps/monitoring/prtg/api/custom/apiv1.pm @@ -0,0 +1,319 @@ +# +# Copyright 2026-Present 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::monitoring::prtg::api::custom::apiv1; + +use strict; +use warnings; +use centreon::plugins::http; +use centreon::plugins::statefile; +use centreon::plugins::misc qw/json_decode is_empty/; +use centreon::plugins::constants qw(:messages); +use Digest::SHA qw(sha256_hex); + +sub new { + my ($class, %options) = @_; + my $self = {}; + bless $self, $class; + + if (!defined($options{output})) { + print "Class Custom: Need to specify 'output' argument.\n"; + exit 3; + } + $options{output}->option_exit(short_msg => "Class Custom: Need to specify 'options' argument.") + unless $options{options}; + + if (!defined($options{noptions})) { + $options{options}->add_options(arguments => { + 'hostname:s' => { name => 'hostname', default => '' }, + 'api-token:s' => { name => 'api_token', default => '' }, + 'port:s' => { name => 'port', default => 443 }, + 'proto:s' => { name => 'proto', default => 'https' }, + 'timeout:s' => { name => 'timeout', default => 50 }, + 'api-path:s' => { name => 'api_path', default => '/api' }, + 'unknown-http-status:s' => { name => 'unknown_http_status', default => '%{http_code} < 200 or %{http_code} >= 300' }, + 'warning-http-status:s' => { name => 'warning_http_status' }, + 'critical-http-status:s' => { name => 'critical_http_status' }, + 'cache-use' => { name => 'cache_use' }, + 'cache-lifetime:s' => { name => 'cache_lifetime', default => 1800 } + }); + } + $options{options}->add_help(package => __PACKAGE__, sections => 'API OPTIONS', once => 1); + + $self->{output} = $options{output}; + $self->{http} = centreon::plugins::http->new(%options, default_backend => 'curl'); + $self->{cache} = centreon::plugins::statefile->new(%options); + + return $self; +} + +sub set_options { + my ($self, %options) = @_; + + $self->{option_results} = $options{option_results}; +} + +sub set_defaults {} + +sub check_options { + my ($self, %options) = @_; + + $self->{$_} = $self->{option_results}->{$_} foreach qw/hostname api_token api_path port proto unknown_http_status warning_http_status critical_http_status cache_lifetime/; + + $self->{output}->option_exit(short_msg => "Need to specify --hostname option.") + if ($self->{hostname} eq ''); + + $self->{output}->option_exit(short_msg => "Need to specify --api-token option.") + if ($self->{api_token} eq ''); + + $self->{cache}->check_options(option_results => $self->{option_results}); + + return 0; +} + +sub get_connection_info { + my ($self, %options) = @_; + + return $self->{hostname} . $self->{port}; +} + +sub settings { + my ($self, %options) = @_; + + return if $self->{settings_done}; + $self->{http}->set_options(%{$self->{option_results}}); + $self->{settings_done} = 1; +} + +sub request_api { + my ($self, %options) = @_; + + my $get_param = [@{$options{get_param}}]; + push @$get_param, 'apitoken=' . $self->{api_token}; + + $self->settings(); + my ($content) = $self->{http}->request( + hostname => $self->{hostname}, + url_path => $self->{api_path} . $options{endpoint}, + get_param => $options{get_param}, + header => ['Accept: application/json'], + unknown_status => $self->{unknown_http_status}, + warning_status => $self->{warning_http_status}, + critical_status => $self->{critical_http_status} + ); + + $self->{output}->option_exit(short_msg => "API returns empty content [code: '" . $self->{http}->get_code() . "'] [message: '" . $self->{http}->get_message() . "']") + if is_empty($content); + + my $decoded = json_decode($content, output => $self->{output}, no_exit => 1); + $self->{output}->option_exit(short_msg => MSG_JSON_DECODE_ERROR) + unless $decoded; + + return $decoded; +} + +sub write_cache_file { + my ($self, %options) = @_; + + $self->{cache}->read(statefile => 'cache_prtg_' . $options{statefile} . '_' . sha256_hex($self->get_connection_info())); + $self->{cache}->write(data => { + update_time => time(), + response => $options{response} + }); +} + +sub get_cache_file_response { + my ($self, %options) = @_; + + $self->{cache}->read(statefile => 'cache_prtg_' . $options{statefile} . '_' . sha256_hex($self->get_connection_info())); + my $response = $self->{cache}->get(name => 'response'); + $self->{output}->option_exit(short_msg => 'Cache file missing') + unless $response; + + my $update_time = $self->{cache}->get(name => 'update_time'); + $self->{output}->option_exit(short_msg => 'Cache file expired') + if (time() - $self->{cache_lifetime}) > $update_time; + + return $response; +} + +sub cache_devices { + my ($self, %options) = @_; + + my $response = $self->get_devices(disable_cache => 1); + $self->write_cache_file( + statefile => 'devices', + response => $response + ); + + return $response; +} + +sub cache_sensors { + my ($self, %options) = @_; + + my $response = $self->get_sensors(disable_cache => 1); + $self->write_cache_file( + statefile => 'sensors', + response => $response + ); + + return $response; +} + +my %map_prtg_status = ( + 1 => 'unknown', + 2 => 'collecting', + 3 => 'ok', + 4 => 'warning', + 5 => 'critical', + 6 => 'noProbe', + 7 => 'pausedbyUser', + 8 => 'PausedbyDependency', + 9 => 'PausedbySchedule', + 10 => 'unusual', + 11 => 'pausedbyLicense', + 12 => 'pausedUntil', + 13 => 'downAcknowledged', + 14 => 'downPartial' +); + +sub get_devices { + my ($self, %options) = @_; + + return $self->get_cache_file_response(statefile => 'devices') + if $self->{option_results}->{cache_use} && !$options{disable_cache}; + + my $data = $self->request_api( + endpoint => '/table.json', + get_param => [ + 'content=devices', + 'columns=objid,device,host,probe,status,message,lastvalue,tags,group,active', + 'count=1000000' + ] + ); + + # PRTG device can have the same name: need to add the group + my $response = {}; + my $names = {}; + foreach (@{$data->{devices}}) { + my $name = $_->{device}; + if (defined($names->{ $_->{device} })) { + $response->{ $names->{ $_->{device} } }->{name} = $_->{device} . '-' . $response->{ $names->{ $_->{device} } }->{group}; + $name .= '-' . $_->{group}; + } + + $names->{$name} = $_->{objid}; + $response->{ $_->{objid} } = { + id => $_->{objid}, + name => $name, + address => $_->{host}, + status => $map_prtg_status{ $_->{status_raw} }, + tags => $_->{tags}, + group => $_->{group}, + active => ($_->{active} =~ /true|1/i ? 1 : 0) + }; + } + + return $response; +} + +sub get_sensors { + my ($self, %options) = @_; + + return $self->get_cache_file_response(statefile => 'sensors') + if $self->{option_results}->{cache_use} && !$options{disable_cache}; + + my $data = $self->request_api( + endpoint => '/table.json', + get_param => [ + 'content=sensors', + 'columns=objid,parentid,group,tags,device,sensor,status,lastvalue,priority,active', + 'count=1000000' + ] + ); + + my $response = {}; + foreach (@{$data->{sensors}}) { + $response->{ $_->{objid} } = { + id => $_->{objid}, + parentId => $_->{parentid}, + name => $_->{sensor}, + status => $map_prtg_status{ $_->{status_raw} }, + tags => $_->{tags}, + group => $_->{group}, + active => ($_->{active} =~ /true|1/i ? 1 : 0), + lastvalue => $_->{lastvalue}, + lastvalueRaw => $_->{lastvalue_raw} + }; + } + + return $response; +} + +1; + +__END__ + +=head1 NAME + +PRTG API v1 + +=head1 API OPTIONS + +PRTG API + +=over 8 + +=item B<--hostname> + +Define PRTG API hostname + +=item B<--api-token> + +Define API token. + +=item B<--port> + +Port used (default: 443) + +=item B<--proto> + +Define https if needed (default: 'https') + +=item B<--timeout> + +Set timeout in seconds (default: 50). + +=item B<--cache-use> + +Use the cache file (created with cache mode). + +=item B<--cache-lifetime> + +Define the cache lifetime before raising an error (default: 1800 seconds). + +=back + +=head1 DESCRIPTION + +B. + +=cut diff --git a/src/apps/monitoring/prtg/api/mode/cache.pm b/src/apps/monitoring/prtg/api/mode/cache.pm new file mode 100644 index 0000000000..c16a21ccf9 --- /dev/null +++ b/src/apps/monitoring/prtg/api/mode/cache.pm @@ -0,0 +1,61 @@ +# +# Copyright 2026-Present 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::monitoring::prtg::api::mode::cache; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $options{options}->add_options(arguments => {}); + + return $self; +} + +sub manage_selection { + my ($self, %options) = @_; + + $options{custom}->cache_devices(); + + $self->{output}->output_add( + severity => 'OK', + short_msg => 'Cache files created successfully' + ); +} + +1; + +__END__ + +=head1 MODE + +Create cache files (other modes could use it with --cache-use option). + +=over 8 + +=back + +=cut diff --git a/src/apps/monitoring/prtg/api/mode/devices.pm b/src/apps/monitoring/prtg/api/mode/devices.pm new file mode 100644 index 0000000000..978e4b0223 --- /dev/null +++ b/src/apps/monitoring/prtg/api/mode/devices.pm @@ -0,0 +1,179 @@ +# +# Copyright 2026-Present 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::monitoring::prtg::api::mode::devices; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; +use centreon::plugins::constants qw(:counters :values); +use centreon::plugins::misc qw/is_excluded/; +use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold_ng); + +sub custom_status_output { + my ($self, %options) = @_; + + return sprintf( + "status: %s", + $self->{result_values}->{status} + ); +} + +sub prefix_global_output { + my ($self, %options) = @_; + + return 'Number of devices '; +} + +sub prefix_device_output { + my ($self, %options) = @_; + + return sprintf( + "device '%s' ", + $options{instance_value}->{deviceName} + ); +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'global', type => COUNTER_TYPE_GLOBAL, cb_prefix_output => 'prefix_global_output' }, + { name => 'devices', type => COUNTER_TYPE_INSTANCE, cb_prefix_output => 'prefix_device_output', message_multiple => 'All devices are ok' } + ]; + + $self->{maps_counters}->{global} = [ + { label => 'devices-detected', display_ok => 0, nlabel => 'devices.detected.count', + unknown_default => '@0', + set => { + key_values => [ { name => 'detected' } ], + output_template => 'detected: %s', + perfdatas => [ + { template => '%s', min => 0 } + ] + } + } + ]; + + $self->{maps_counters}->{devices} = [ + { + label => 'device-status', + type => COUNTER_KIND_TEXT, + unknown_default => '%{status} =~ /unknown|unusual|noProbe|pausedbyLicense/', + warning_default => '%{status} =~ /warning/', + critical_default => '%{status} =~ /down|critical/', + set => { + key_values => [ { name => 'status' }, { name => 'deviceName' } ], + closure_custom_output => $self->can('custom_status_output'), + closure_custom_perfdata => sub { return 0; }, + closure_custom_threshold_check => \&catalog_status_threshold_ng + } + } + ]; +} + +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-device-id:s' => { name => 'include_device_id', default => '' }, + 'exclude-device-id:s' => { name => 'exclude_device_id', default => '' }, + 'include-device-name:s' => { name => 'include_device_name', default => '' }, + 'exclude-device-name:s' => { name => 'exclude_device_name', default => '' } + }); + + return $self; +} + +sub manage_selection { + my ($self, %options) = @_; + + my $devices = $options{custom}->get_devices(); + + $self->{global} = { detected => 0 }; + $self->{devices} = {}; + foreach my $dev (values %$devices) { + next if is_excluded($dev->{name}, $self->{option_results}->{include_device_name}, $self->{option_results}->{exclude_device_name}); + next if is_excluded($dev->{id}, $self->{option_results}->{include_device_id}, $self->{option_results}->{exclude_device_id}); + + $self->{devices}->{ $dev->{id} } = { + deviceName => $dev->{name}, + status => $dev->{status} + }; + + $self->{global}->{detected}++; + } +} + +1; + +__END__ + +=head1 MODE + +Check devices status. + +=over 8 + +=item B<--include-device-name> + +Include device names (regexp). + +=item B<--exclude-device-name> + +Exclude device names (regexp). + +=item B<--include-device-id> + +Include device IDs (regexp). + +=item B<--exclude-device-id> + +Exclude device IDs (regexp). + +=item B<--warning-devices-detected> + +Threshold. + +=item B<--critical-devices-detected> + +Threshold. + +=item B<--unknown-device-status> + +Define the conditions to match for the status to be UNKNOWN (default: '%{status} =~ /unknown|unusual|noProbe|pausedbyLicense/'). +You can use the following variables: %{deviceName}, %{status} + +=item B<--warning-device-status> + +Define the conditions to match for the status to be WARNING (default: '%{status} =~ /warning/'). +You can use the following variables: %{deviceName}, %{status} + +=item B<--critical-device-status> + +Define the conditions to match for the status to be CRITICAL (default: '%{status} =~ /down|critical/'). +You can use the following variables: %{deviceName}, %{status} + +=back + +=cut \ No newline at end of file diff --git a/src/apps/monitoring/prtg/api/mode/discovery.pm b/src/apps/monitoring/prtg/api/mode/discovery.pm new file mode 100644 index 0000000000..ecd4dc1fd9 --- /dev/null +++ b/src/apps/monitoring/prtg/api/mode/discovery.pm @@ -0,0 +1,126 @@ +# +# 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 apps::monitoring::prtg::api::mode::discovery; + +use base qw(centreon::plugins::mode); + +use strict; +use warnings; +use JSON::XS; + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $options{options}->add_options(arguments => { + 'resource-type:s' => { name => 'resource_type' }, + 'prettify' => { name => 'prettify' } + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::init(%options); + + if (!defined($self->{option_results}->{resource_type}) || $self->{option_results}->{resource_type} eq '') { + $self->{option_results}->{resource_type} = 'device'; + } + if ($self->{option_results}->{resource_type} !~ /^device$/) { + $self->{output}->add_option_msg(short_msg => 'unknown resource type'); + $self->{output}->option_exit(); + } +} + +sub discovery_device { + my ($self, %options) = @_; + + my $devices = $options{custom}->get_devices(); + + my $cluster = {}; + my $disco_data = []; + foreach my $dev (values %$devices) { + my $node = {}; + $node->{uuid} = $dev->{id}; + $node->{name} = $dev->{name}; + $node->{address} = $dev->{address}; + $node->{status} = $dev->{status}; + $node->{group} = $dev->{group}; + $node->{tags} = $dev->{tags}; + + push @$disco_data, $node; + } + + return $disco_data; +} + +sub run { + my ($self, %options) = @_; + + my $disco_stats; + $disco_stats->{start_time} = time(); + + my $results = []; + if ($self->{option_results}->{resource_type} eq 'device') { + $results = $self->discovery_device(custom => $options{custom}); + } + + $disco_stats->{end_time} = time(); + $disco_stats->{duration} = $disco_stats->{end_time} - $disco_stats->{start_time}; + $disco_stats->{discovered_items} = scalar(@$results); + $disco_stats->{results} = $results; + + my $encoded_data; + eval { + if (defined($self->{option_results}->{prettify})) { + $encoded_data = JSON::XS->new->utf8->pretty->encode($disco_stats); + } else { + $encoded_data = JSON::XS->new->utf8->encode($disco_stats); + } + }; + if ($@) { + $encoded_data = '{"code":"encode_error","message":"Cannot encode discovered data into JSON format"}'; + } + + $self->{output}->output_add(short_msg => $encoded_data); + $self->{output}->display(nolabel => 1, force_ignore_perfdata => 1); + $self->{output}->exit(); +} + +1; + +__END__ + +=head1 MODE + +Resources discovery. + +=over 8 + +=item B<--resource-type> + +Choose the type of resources to discover (can be: 'device'). + +=back + +=cut diff --git a/src/apps/monitoring/prtg/api/mode/sensors.pm b/src/apps/monitoring/prtg/api/mode/sensors.pm new file mode 100644 index 0000000000..7d92a44a2e --- /dev/null +++ b/src/apps/monitoring/prtg/api/mode/sensors.pm @@ -0,0 +1,432 @@ +# +# Copyright 2026-Present 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::monitoring::prtg::api::mode::sensors; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; +use centreon::plugins::constants qw(:counters :values); +use centreon::plugins::misc qw/is_excluded/; +use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold_ng); + +my $map_sensor_type = { + STORAGE => 1, # Go + PERCENT => 2, # % + MS => 3, # ms + TRAFFIC => 4, # Mbit/s + CELSIUS => 5 # u00b0C +}; + +sub custom_sensor_current_perfdata { + my ($self, %options) = @_; + + my $instances = []; + foreach (@{$self->{instance_mode}->{custom_perfdata_instances}}) { + push @$instances, $self->{result_values}->{$_}; + } + + my ($nlabel, $min, $max) = ($self->{nlabel}); + if ($self->{result_values}->{type} == $map_sensor_type->{TRAFFIC}) { + $nlabel .= '.bitspersecond'; + $min = 0; + } elsif ($self->{result_values}->{type} == $map_sensor_type->{STORAGE}) { + $nlabel .= '.bytes'; + $min = 0; + } elsif ($self->{result_values}->{type} == $map_sensor_type->{PERCENT}) { + $nlabel .= '.percent'; + $min = 0; + $max = 100; + } elsif ($self->{result_values}->{type} == $map_sensor_type->{MS}) { + $nlabel .= '.milliseconds'; + $min = 0; + } elsif ($self->{result_values}->{type} == $map_sensor_type->{CELSIUS}) { + $nlabel .= '.celsius'; + } + + $self->{output}->perfdata_add( + nlabel => $nlabel, + instances => $instances, + value => $self->{result_values}->{current}, + warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{thlabel}), + critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{thlabel}), + min => $min, + max => $max + ); +} + +sub custom_sensor_current_output { + my ($self, %options) = @_; + + if ($self->{result_values}->{type} == $map_sensor_type->{TRAFFIC}) { + my ($current_value, $current_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{current}, network => 1); + return sprintf( + 'current: %s %s/s', + $current_value, + $current_unit + ); + } elsif ($self->{result_values}->{type} == $map_sensor_type->{STORAGE}) { + my ($current_value, $current_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{current}); + return sprintf( + 'current: %s %s', + $current_value, + $current_unit + ); + } elsif ($self->{result_values}->{type} == $map_sensor_type->{PERCENT}) { + return sprintf( + 'current: %s %%', + $self->{result_values}->{current} + ); + } elsif ($self->{result_values}->{type} == $map_sensor_type->{MS}) { + return sprintf( + 'current: %s ms', + $self->{result_values}->{current} + ); + } elsif ($self->{result_values}->{type} == $map_sensor_type->{CELSIUS}) { + return sprintf( + 'current: %s C', + $self->{result_values}->{current} + ); + } +} + +sub custom_sensor_status_output { + my ($self, %options) = @_; + + return sprintf( + "status: %s", + $self->{result_values}->{sensorStatus} + ); +} + +sub prefix_global_output { + my ($self, %options) = @_; + + return 'Number of devices '; +} + +sub device_long_output { + my ($self, %options) = @_; + + return sprintf( + "checking device '%s'", + $options{instance_value}->{deviceName} + ); +} + +sub prefix_device_output { + my ($self, %options) = @_; + + return sprintf( + "device '%s' ", + $options{instance_value}->{deviceName} + ); +} + +sub prefix_sensor_output { + my ($self, %options) = @_; + + return sprintf( + "sensor '%s' ", + $options{instance_value}->{sensorName} + ); +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'global', type => COUNTER_TYPE_GLOBAL, cb_prefix_output => 'prefix_global_output' }, + { + name => 'devices', type => COUNTER_TYPE_MULTIPLE, cb_prefix_output => 'prefix_device_output', cb_long_output => 'device_long_output', indent_long_output => ' ', message_multiple => 'All devices are ok', + group => [ + { name => 'sensors', type => COUNTER_MULTIPLE_SUBINSTANCE, message_multiple => 'All sensors are ok', cb_prefix_output => 'prefix_sensor_output', display_long => 1, skipped_code => { NO_VALUE() => 1 } } + ] + } + ]; + + $self->{maps_counters}->{global} = [ + { label => 'devices-detected', display_ok => 0, nlabel => 'devices.detected.count', + unknown_default => '@0', + set => { + key_values => [ { name => 'detected' } ], + output_template => 'detected: %s', + perfdatas => [ + { template => '%s', min => 0 } + ] + } + } + ]; + + $self->{maps_counters}->{sensors} = [ + { + label => 'sensor-status', + type => COUNTER_KIND_TEXT, + unknown_default => '%{sensorStatus} =~ /unknown|unusual|noProbe|pausedbyLicense/', + warning_default => '%{sensorStatus} =~ /warning/', + critical_default => '%{sensorStatus} =~ /down|critical/', + set => { + key_values => [ + { name => 'sensorStatus' }, { name => 'deviceName' }, { name => 'sensorName' } + ], + closure_custom_output => $self->can('custom_sensor_status_output'), + closure_custom_perfdata => sub { return 0; }, + closure_custom_threshold_check => \&catalog_status_threshold_ng + } + }, + { label => 'sensor-current', nlabel => 'sensor.current', set => { + key_values => [ + { name => 'current' }, { name => 'type' }, { name => 'deviceName' }, { name => 'sensorName' } + ], + closure_custom_output => $self->can('custom_sensor_current_output'), + closure_custom_perfdata => $self->can('custom_sensor_current_perfdata') + } + } + ]; +} + +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-device-id:s' => { name => 'include_device_id', default => '' }, + 'exclude-device-id:s' => { name => 'exclude_device_id', default => '' }, + 'include-device-name:s' => { name => 'include_device_name', default => '' }, + 'exclude-device-name:s' => { name => 'exclude_device_name', default => '' }, + 'include-sensor-name:s' => { name => 'include_sensor_name', default => '' }, + 'exclude-sensor-name:s' => { name => 'exclude_sensor_name', default => '' }, + 'include-sensor-id:s' => { name => 'include_sensor_id', default => '' }, + 'exclude-sensor-id:s' => { name => 'exclude_sensor_id', default => '' }, + 'custom-perfdata-instances:s' => { name => 'custom_perfdata_instances' } + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + if (!defined($self->{option_results}->{custom_perfdata_instances}) || $self->{option_results}->{custom_perfdata_instances} eq '') { + $self->{option_results}->{custom_perfdata_instances} = '%(deviceName) %(sensorName)'; + } + + $self->{custom_perfdata_instances} = $self->custom_perfdata_instances( + option_name => '--custom-perfdata-instances', + instances => $self->{option_results}->{custom_perfdata_instances}, + labels => { deviceName => 1, sensorName => 1 } + ); +} + +sub manage_selection { + my ($self, %options) = @_; + + #my $devices = $options{custom}->get_devices(); + my $sensors = $options{custom}->get_sensors(); + + $self->{global} = { detected => 0 }; + $self->{devices} = {}; + foreach my $sensor (values %$sensors) { + #next if is_excluded($devices->{ $sensor->{parentId} }->{name}, $self->{option_results}->{include_device_name}, $self->{option_results}->{exclude_device_name}); + #next if is_excluded($devices->{ $sensor->{parentId} }->{id}, $self->{option_results}->{include_device_id}, $self->{option_results}->{exclude_device_id}); + next if is_excluded($sensor->{name}, $self->{option_results}->{include_sensor_name}, $self->{option_results}->{exclude_sensor_name}); + next if is_excluded($sensor->{id}, $self->{option_results}->{include_sensor_id}, $self->{option_results}->{exclude_sensor_id}); + + if (!defined($self->{devices}->{ $sensor->{parentId} })) { + $self->{devices}->{ $sensor->{parentId} } = { + #deviceName => $devices->{ $sensor->{parentId} }->{name}, + deviceName => $sensor->{parentId}, + sensors => {} + }; + $self->{global}->{detected}++; + } + + $self->{devices}->{ $sensor->{parentId} }->{sensors}->{ $sensor->{id} } = { + #deviceName => $devices->{ $sensor->{parentId} }->{name}, + deviceName => $sensor->{parentId}, + sensorName => $sensor->{name}, + sensorStatus => $sensor->{status}, + current => $sensor->{lastvalueRaw} + }; + + if ($sensor->{lastvalue} =~ /\s+Go/) { + $self->{devices}->{ $sensor->{parentId} }->{sensors}->{ $sensor->{id} }->{type} = $map_sensor_type->{STORAGE}; + } elsif ($sensor->{lastvalue} =~ /\s+%/) { + $self->{devices}->{ $sensor->{parentId} }->{sensors}->{ $sensor->{id} }->{type} = $map_sensor_type->{PERCENT}; + } elsif ($sensor->{lastvalue} =~ /\s+ms/) { + $self->{devices}->{ $sensor->{parentId} }->{sensors}->{ $sensor->{id} }->{type} = $map_sensor_type->{MS}; + } elsif ($sensor->{lastvalue} =~ /.*?([0-9.,]+?)\s+Mbit\/s/) { + my $value = $1; + $value =~ s/,/./g; + $self->{devices}->{ $sensor->{parentId} }->{sensors}->{ $sensor->{id} }->{current} = $value * 1000 * 1000; + $self->{devices}->{ $sensor->{parentId} }->{sensors}->{ $sensor->{id} }->{type} = $map_sensor_type->{TRAFFIC}; + } elsif ($sensor->{lastvalue} =~ /\s+.*?C$/) { + $self->{devices}->{ $sensor->{parentId} }->{sensors}->{ $sensor->{id} }->{type} = $map_sensor_type->{CELSIUS}; + } + } +} + +sub disco_format { + my ($self, %options) = @_; + + $self->{output}->add_disco_format(elements => ['deviceName', 'deviceId', 'sensorName', 'sensorId', 'sensorStatus']); +} + +sub disco_show { + my ($self, %options) = @_; + + #my $devices = $options{custom}->get_devices(); + my $sensors = $options{custom}->get_sensors(); + foreach my $sensor (values %$sensors) { + #next if is_excluded($devices->{ $sensor->{parentId} }->{name}, $self->{option_results}->{include_device_name}, $self->{option_results}->{exclude_device_name}); + #next if is_excluded($devices->{ $sensor->{parentId} }->{id}, $self->{option_results}->{include_device_id}, $self->{option_results}->{exclude_device_id}); + next if is_excluded($sensor->{name}, $self->{option_results}->{include_sensor_name}, $self->{option_results}->{exclude_sensor_name}); + next if is_excluded($sensor->{id}, $self->{option_results}->{include_sensor_id}, $self->{option_results}->{exclude_sensor_id}); + + $self->{output}->add_disco_entry( + #deviceName => $devices->{ $sensor->{parentId} }->{name}, + deviceName => $sensor->{parentId}, + deviceId => $sensor->{parentId}, + sensorName => $sensor->{name}, + sensorId => $sensor->{id}, + sensorStatus => $sensor->{status} + ); + } +} + +1; + +__END__ + +=head1 MODE + +Check sensors. + +=over 8 + +=item B<--include-device-name> + +Include device names (regexp). + +=item B<--exclude-device-name> + +Exclude device names (regexp). + +=item B<--include-device-id> + +Include device IDs (regexp). + +=item B<--exclude-device-id> + +Exclude device IDs (regexp). + +=item B<--include-sensor-name> + +Include sensor names (regexp). + +=item B<--exclude-sensor-name> + +Exclude sensor names (regexp). + +=item B<--include-sensor-id> + +Include sensor IDs (regexp). + +=item B<--exclude-sensor-id> + +Exclude sensor IDs (regexp). + +=item B<--exclude-gateway-id> + +Exclude gateway IDs (regexp). + +=item B<--custom-perfdata-instances> + +Define perfdatas instance (default: '%(deviceName) %(sensorName)') + +=item B<--unknown-sensor-status> + +Define the conditions to match for the status to be UNKNOWN (default: '%{sensorStatus} =~ /unknown|unusual|noProbe|pausedbyLicense/'). +You can use the following variables: %{deviceName}, %{sensorName}, %{sensorStatus} + +=item B<--warning-sensor-status> + +Define the conditions to match for the status to be WARNING (default: '%{sensorStatus} =~ /warning/'). +You can use the following variables: %{deviceName}, %{sensorName}, %{sensorStatus} + +=item B<--critical-sensor-status> + +Define the conditions to match for the status to be CRITICAL (default: '%{sensorStatus} =~ /down|critical/'). +You can use the following variables: %{deviceName}, %{sensorName}, %{sensorStatus} + +=item B<--warning-devices-detected> + +Threshold. + +=item B<--critical-devices-detected> + +Threshold. + +=item B<--warning-interface-traffic-in> + +Threshold. + +=item B<--critical-interface-traffic-in> + +Threshold. + +=item B<--warning-interface-traffic-out> + +Threshold. + +=item B<--critical-interface-traffic-out> + +Threshold. + +=item B<--warning-interface-jitter> + +Threshold. + +=item B<--critical-interface-jitter> + +Threshold. + +=item B<--warning-interface-latency> + +Threshold. + +=item B<--critical-interface-latency> + +Threshold. + +=item B<--warning-interface-loss> + +Threshold. + +=item B<--critical-interface-loss> + +Threshold. + +=back + +=cut diff --git a/src/apps/monitoring/prtg/api/plugin.pm b/src/apps/monitoring/prtg/api/plugin.pm new file mode 100644 index 0000000000..99f9dc9acf --- /dev/null +++ b/src/apps/monitoring/prtg/api/plugin.pm @@ -0,0 +1,51 @@ +# +# Copyright 2026-Present 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::monitoring::prtg::api::plugin; + +use strict; +use warnings; +use base qw(centreon::plugins::script_custom); + +sub new { + my ( $class, %options ) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $self->{modes} = { + 'cache' => 'apps::monitoring::prtg::api::mode::cache', + 'devices' => 'apps::monitoring::prtg::api::mode::devices', + 'discovery' => 'apps::monitoring::prtg::api::mode::discovery', + 'sensors' => 'apps::monitoring::prtg::api::mode::sensors' + }; + + $self->{custom_modes}->{apiv1} = 'apps::monitoring::prtg::api::custom::apiv1'; + return $self; +} + +1; + +__END__ + +=head1 PLUGIN DESCRIPTION + +Check PRTG using API. + +=cut From 3f3dea6beda458330fd3f117ff77c4cf294c3e93 Mon Sep 17 00:00:00 2001 From: garnier-quentin Date: Mon, 27 Jul 2026 07:57:36 -0400 Subject: [PATCH 3/5] wip --- src/apps/monitoring/prtg/api/mode/sensors.pm | 21 +++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/apps/monitoring/prtg/api/mode/sensors.pm b/src/apps/monitoring/prtg/api/mode/sensors.pm index 7d92a44a2e..ea031ab3ab 100644 --- a/src/apps/monitoring/prtg/api/mode/sensors.pm +++ b/src/apps/monitoring/prtg/api/mode/sensors.pm @@ -241,29 +241,27 @@ sub check_options { sub manage_selection { my ($self, %options) = @_; - #my $devices = $options{custom}->get_devices(); + my $devices = $options{custom}->get_devices(); my $sensors = $options{custom}->get_sensors(); $self->{global} = { detected => 0 }; $self->{devices} = {}; foreach my $sensor (values %$sensors) { - #next if is_excluded($devices->{ $sensor->{parentId} }->{name}, $self->{option_results}->{include_device_name}, $self->{option_results}->{exclude_device_name}); - #next if is_excluded($devices->{ $sensor->{parentId} }->{id}, $self->{option_results}->{include_device_id}, $self->{option_results}->{exclude_device_id}); + next if is_excluded($devices->{ $sensor->{parentId} }->{name}, $self->{option_results}->{include_device_name}, $self->{option_results}->{exclude_device_name}); + next if is_excluded($devices->{ $sensor->{parentId} }->{id}, $self->{option_results}->{include_device_id}, $self->{option_results}->{exclude_device_id}); next if is_excluded($sensor->{name}, $self->{option_results}->{include_sensor_name}, $self->{option_results}->{exclude_sensor_name}); next if is_excluded($sensor->{id}, $self->{option_results}->{include_sensor_id}, $self->{option_results}->{exclude_sensor_id}); if (!defined($self->{devices}->{ $sensor->{parentId} })) { $self->{devices}->{ $sensor->{parentId} } = { - #deviceName => $devices->{ $sensor->{parentId} }->{name}, - deviceName => $sensor->{parentId}, + deviceName => $devices->{ $sensor->{parentId} }->{name}, sensors => {} }; $self->{global}->{detected}++; } $self->{devices}->{ $sensor->{parentId} }->{sensors}->{ $sensor->{id} } = { - #deviceName => $devices->{ $sensor->{parentId} }->{name}, - deviceName => $sensor->{parentId}, + deviceName => $devices->{ $sensor->{parentId} }->{name}, sensorName => $sensor->{name}, sensorStatus => $sensor->{status}, current => $sensor->{lastvalueRaw} @@ -295,17 +293,16 @@ sub disco_format { sub disco_show { my ($self, %options) = @_; - #my $devices = $options{custom}->get_devices(); + my $devices = $options{custom}->get_devices(); my $sensors = $options{custom}->get_sensors(); foreach my $sensor (values %$sensors) { - #next if is_excluded($devices->{ $sensor->{parentId} }->{name}, $self->{option_results}->{include_device_name}, $self->{option_results}->{exclude_device_name}); - #next if is_excluded($devices->{ $sensor->{parentId} }->{id}, $self->{option_results}->{include_device_id}, $self->{option_results}->{exclude_device_id}); + next if is_excluded($devices->{ $sensor->{parentId} }->{name}, $self->{option_results}->{include_device_name}, $self->{option_results}->{exclude_device_name}); + next if is_excluded($devices->{ $sensor->{parentId} }->{id}, $self->{option_results}->{include_device_id}, $self->{option_results}->{exclude_device_id}); next if is_excluded($sensor->{name}, $self->{option_results}->{include_sensor_name}, $self->{option_results}->{exclude_sensor_name}); next if is_excluded($sensor->{id}, $self->{option_results}->{include_sensor_id}, $self->{option_results}->{exclude_sensor_id}); $self->{output}->add_disco_entry( - #deviceName => $devices->{ $sensor->{parentId} }->{name}, - deviceName => $sensor->{parentId}, + deviceName => $devices->{ $sensor->{parentId} }->{name}, deviceId => $sensor->{parentId}, sensorName => $sensor->{name}, sensorId => $sensor->{id}, From 6d73d21cf4c3679a07e2896a12a1a602d0b38fef Mon Sep 17 00:00:00 2001 From: garnier-quentin Date: Mon, 27 Jul 2026 08:08:24 -0400 Subject: [PATCH 4/5] wip --- .../deb.json | 4 ++++ .../pkg.json | 9 +++++++++ .../rpm.json | 4 ++++ src/apps/monitoring/prtg/api/custom/apiv1.pm | 2 +- 4 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 packaging/centreon-plugin-Applications-Monitoring-Prtg-Api/deb.json create mode 100644 packaging/centreon-plugin-Applications-Monitoring-Prtg-Api/pkg.json create mode 100644 packaging/centreon-plugin-Applications-Monitoring-Prtg-Api/rpm.json diff --git a/packaging/centreon-plugin-Applications-Monitoring-Prtg-Api/deb.json b/packaging/centreon-plugin-Applications-Monitoring-Prtg-Api/deb.json new file mode 100644 index 0000000000..9757fe1126 --- /dev/null +++ b/packaging/centreon-plugin-Applications-Monitoring-Prtg-Api/deb.json @@ -0,0 +1,4 @@ +{ + "dependencies": [ + ] +} diff --git a/packaging/centreon-plugin-Applications-Monitoring-Prtg-Api/pkg.json b/packaging/centreon-plugin-Applications-Monitoring-Prtg-Api/pkg.json new file mode 100644 index 0000000000..ce8962513d --- /dev/null +++ b/packaging/centreon-plugin-Applications-Monitoring-Prtg-Api/pkg.json @@ -0,0 +1,9 @@ +{ + "pkg_name": "centreon-plugin-Applications-Monitoring-Prtg-Api", + "pkg_summary": "Centreon Plugin to monitor PRTG", + "plugin_name": "centreon_monitoring_prtg_api.pl", + "files": [ + "centreon/plugins/script_custom.pm", + "apps/monitoring/prtg/api/" + ] +} diff --git a/packaging/centreon-plugin-Applications-Monitoring-Prtg-Api/rpm.json b/packaging/centreon-plugin-Applications-Monitoring-Prtg-Api/rpm.json new file mode 100644 index 0000000000..9757fe1126 --- /dev/null +++ b/packaging/centreon-plugin-Applications-Monitoring-Prtg-Api/rpm.json @@ -0,0 +1,4 @@ +{ + "dependencies": [ + ] +} diff --git a/src/apps/monitoring/prtg/api/custom/apiv1.pm b/src/apps/monitoring/prtg/api/custom/apiv1.pm index d43385d2ff..b9d45a0193 100644 --- a/src/apps/monitoring/prtg/api/custom/apiv1.pm +++ b/src/apps/monitoring/prtg/api/custom/apiv1.pm @@ -112,7 +112,7 @@ sub request_api { my ($content) = $self->{http}->request( hostname => $self->{hostname}, url_path => $self->{api_path} . $options{endpoint}, - get_param => $options{get_param}, + get_param => $get_param, header => ['Accept: application/json'], unknown_status => $self->{unknown_http_status}, warning_status => $self->{warning_http_status}, From 5c2b4c41dc3b03ff79b11e372c706a51c20c4bfd Mon Sep 17 00:00:00 2001 From: garnier-quentin Date: Mon, 27 Jul 2026 09:10:35 -0400 Subject: [PATCH 5/5] wip --- src/apps/monitoring/prtg/api/mode/cache.pm | 1 + 1 file changed, 1 insertion(+) diff --git a/src/apps/monitoring/prtg/api/mode/cache.pm b/src/apps/monitoring/prtg/api/mode/cache.pm index c16a21ccf9..125bdd1603 100644 --- a/src/apps/monitoring/prtg/api/mode/cache.pm +++ b/src/apps/monitoring/prtg/api/mode/cache.pm @@ -39,6 +39,7 @@ sub manage_selection { my ($self, %options) = @_; $options{custom}->cache_devices(); + $options{custom}->cache_sensors(); $self->{output}->output_add( severity => 'OK',