From 490945440b668dd9700b3ea25d5571c682ce6307 Mon Sep 17 00:00:00 2001 From: omercier Date: Thu, 20 Mar 2025 11:29:56 +0100 Subject: [PATCH 01/12] 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 b1f102ada3f6750450ef6aa7944cb4903007afe0 Mon Sep 17 00:00:00 2001 From: garnier-quentin Date: Mon, 8 Jun 2026 09:37:43 -0400 Subject: [PATCH 02/12] wip --- src/network/paloalto/api/mode/cpu.pm | 204 +++++++++++++++++++++ src/network/paloalto/api/mode/memory.pm | 177 +++++++++++++++++++ src/network/paloalto/api/mode/sessions.pm | 206 ++++++++++++++++++++++ src/network/paloalto/api/plugin.pm | 4 +- 4 files changed, 590 insertions(+), 1 deletion(-) create mode 100644 src/network/paloalto/api/mode/cpu.pm create mode 100644 src/network/paloalto/api/mode/memory.pm create mode 100644 src/network/paloalto/api/mode/sessions.pm diff --git a/src/network/paloalto/api/mode/cpu.pm b/src/network/paloalto/api/mode/cpu.pm new file mode 100644 index 0000000000..757a9240c4 --- /dev/null +++ b/src/network/paloalto/api/mode/cpu.pm @@ -0,0 +1,204 @@ +# +# 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 network::paloalto::api::mode::cpu; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; +use centreon::plugins::constants qw(:counters); +use centreon::plugins::misc qw(is_excluded); + +sub custom_perfdata { + my ($self, %options) = @_; + + $self->{output}->perfdata_add( + nlabel => $self->{nlabel}, + instances => ['dp' . $self->{result_values}->{dpNum}, 'cpu' . $self->{result_values}->{cpuNum}], + value => sprintf('%.2f', $self->{result_values}->{ $self->{key_values}->[0]->{name} }), + warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{thlabel}), + critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{thlabel}), + min => 0, + max => 100, + unit => '%' + ); +} + +sub prefix_cpu_core_output { + my ($self, %options) = @_; + + return "CPU '" . $options{instance_value}->{cpuNum} . "' "; +} + +sub long_dp_output { + my ($self, %options) = @_; + + return sprintf( + "checking data processor '%s'", + $options{instance_value}->{dpNum} + ); +} + +sub prefix_dp_output { + my ($self, %options) = @_; + + return sprintf( + "data processor '%s' ", + $options{instance_value}->{dpNum} + ); +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'dp', type => COUNTER_TYPE_MULTIPLE, cb_prefix_output => 'prefix_dp_output', cb_long_output => 'long_dp_output', + message_multiple => 'All data processors are ok', indent_long_output => ' ', + group => [ + { name => 'cpu_cores', display_long => 1, cb_prefix_output => 'prefix_cpu_core_output', message_multiple => 'All CPU cores are ok', type => COUNTER_MULTIPLE_SUBINSTANCE, sort_method => 'num' } + ] + } + ]; + + $self->{maps_counters}->{cpu_cores} = [ + { label => 'average-1m', nlabel => 'core.cpu.utilization.1m.percentage', set => { + key_values => [ { name => 'average_1m' }, { name => 'dpNum' }, { name => 'cpuNum' } ], + output_template => '%.2f %% (1m)', + closure_custom_perfdata => $self->can('custom_perfdata') + } + }, + { label => 'average-5m', nlabel => 'core.cpu.utilization.5m.percentage', set => { + key_values => [ { name => 'average_5m' }, { name => 'dpNum' }, { name => 'cpuNum' } ], + output_template => '%.2f %% (5m)', + closure_custom_perfdata => $self->can('custom_perfdata'), + } + }, + { label => 'average-15m', nlabel => 'core.cpu.utilization.15m.percentage', set => { + key_values => [ { name => 'average_15m' }, { name => 'dpNum' }, { name => 'cpuNum' } ], + output_template => '%.2f %% (15m)', + closure_custom_perfdata => $self->can('custom_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-dp-name:s' => { name => 'include_dp_name', default => '' }, + 'exclude-dp-name:s' => { name => 'exclude_dp_name', default => '' } + }); + + return $self; +} + +sub compute_cpu_average { + my ($self, %options) = @_; + + my $value = 0; + for (my $i = 0; $i < $options{sampling}; $i++) { + $value += $options{dataset}->[$i]; + } + + $value /= $options{sampling}; + + return $value; +} + +sub manage_selection { + my ($self, %options) = @_; + + my $result = $options{custom}->request_api( + type => 'op', + cmd => '', + ForceArray => ['entry'] + ); + + $self->{dp} = {}; + foreach my $dp (keys %{$result->{'resource-monitor'}->{'data-processors'}}) { + next if ($dp !~ /dp(\d+)/); + my $dp_num = $1; + + next if is_excluded($dp_num, $self->{option_results}->{include_dp_name}, $self->{option_results}->{exclude_dp_name}); + + $self->{dp}->{$dp_num} = { dpNum => $dp_num, cpu_cores => {} }; + + foreach my $core (@{$result->{'resource-monitor'}->{'data-processors'}->{$dp}->{minute}->{'cpu-load-average'}->{entry}}) { + my @datas = split(/,/, $core->{value}); + $self->{dp}->{$dp_num}->{cpu_cores}->{ $core->{coreid} } = { + dpNum => $dp_num, + cpuNum => $core->{coreid}, + average_1m => $self->compute_cpu_average(dataset => \@datas, sampling => 1), + average_5m => $self->compute_cpu_average(dataset => \@datas, sampling => 5), + average_15m => $self->compute_cpu_average(dataset => \@datas, sampling => 15) + }; + } + } +} + +1; + +__END__ + +=head1 MODE + +Check data processors. + +=over 8 + +=item B<--include-dp-name> + +Include data processor names (regexp). + +=item B<--exclude-dp-name> + +Exclude data processor names (regexp). + +=item B<--warning-average-1m> + +Warning threshold for data processor 1 minute average usage in percent. + +=item B<--critical-average-1m> + +Critical threshold for data processor 1 minute average usage in percent. + +=item B<--warning-average-5m> + +Warning threshold for data processor 5 minutes average usage in percent. + +=item B<--critical-average-5m> + +Critical threshold for data processor 5 minutes average usage in percent. + +=item B<--warning-average-15m> + +Warning threshold for data processor 15 minutes average usage in percent. + +=item B<--critical-average-15m> + +Critical threshold for data processor 15 minutes average usage in percent. + +=back + +=cut diff --git a/src/network/paloalto/api/mode/memory.pm b/src/network/paloalto/api/mode/memory.pm new file mode 100644 index 0000000000..2e2cf7789a --- /dev/null +++ b/src/network/paloalto/api/mode/memory.pm @@ -0,0 +1,177 @@ +# +# 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 network::paloalto::api::mode::memory; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; +use centreon::plugins::constants qw(:counters); + +sub custom_memory_output { + my ($self, %options) = @_; + + return sprintf( + 'Ram total: %s %s used (-%s): %s %s (%.2f%%) free: %s %s (%.2f%%) available: %s %s (%.2f%%)', + $self->{perfdata}->change_bytes(value => $self->{result_values}->{total}), + $self->{result_values}->{used_desc}, + $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}, + $self->{perfdata}->change_bytes(value => $self->{result_values}->{available}), + $self->{result_values}->{prct_available}, + + ); +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'memory', type => COUNTER_TYPE_GLOBAL, skipped_code => { NO_VALUE => 1 } } + ]; + + $self->{maps_counters}->{memory} = [ + { label => 'memory-usage', nlabel => 'memory.usage.bytes', set => { + key_values => [ { name => 'used' }, { name => 'free' }, { name => 'prct_used' }, { name => 'prct_free' }, { name => 'total' }, { name => 'used_desc' }, { name => 'available' }, { name => 'prct_available' } ], + closure_custom_output => $self->can('custom_memory_output'), + perfdatas => [ + { template => '%d', min => 0, max => 'total', unit => 'B' } + ] + } + }, + { label => 'memory-usage-free', nlabel => 'memory.free.bytes', display_ok => 0, set => { + key_values => [ { name => 'free' }, { name => 'used' }, { name => 'prct_used' }, { name => 'prct_free' }, { name => 'total' }, { name => 'used_desc' }, { name => 'available' }, { name => 'prct_available' } ], + closure_custom_output => $self->can('custom_memory_output'), + perfdatas => [ + { template => '%d', min => 0, max => 'total', unit => 'B' } + ] + } + }, + { label => 'memory-usage-prct', nlabel => 'memory.usage.percentage', display_ok => 0, set => { + key_values => [ { name => 'prct_used' }, { name => 'used' }, { name => 'free' }, { name => 'prct_free' }, { name => 'total' }, { name => 'used_desc' }, { name => 'available' }, { name => 'prct_available' } ], + closure_custom_output => $self->can('custom_memory_output'), + perfdatas => [ + { template => '%.2f', min => 0, max => 100, unit => '%' } + ] + } + }, + { label => 'memory-available', nlabel => 'memory.available.bytes', display_ok => 0, set => { + key_values => [ { name => 'available' }, { name => 'used' }, { name => 'free' }, { name => 'prct_used' }, { name => 'prct_free' }, { name => 'total' }, { name => 'used_desc' }, { name => 'prct_available' } ], + closure_custom_output => $self->can('custom_memory_output'), + perfdatas => [ + { template => '%d', min => 0, max => 'total', unit => 'B' } + ] + } + }, + { label => 'memory-available-prct', nlabel => 'memory.available.percentage', display_ok => 0, set => { + key_values => [ { name => 'prct_available' }, { name => 'prct_used' }, { name => 'used' }, { name => 'free' }, { name => 'prct_free' }, { name => 'total' }, { name => 'used_desc' }, { name => 'available' } ], + closure_custom_output => $self->can('custom_memory_output'), + perfdatas => [ + { template => '%.2f', min => 0, max => 100, unit => '%' } + ] + } + }, + { label => 'buffer', nlabel => 'memory.buffer.bytes', set => { + key_values => [ { name => 'buffer' } ], + output_template => 'buffer: %s %s', + output_change_bytes => 1, + perfdatas => [ + { template => '%d', min => 0, unit => 'B' } + ] + } + } + ]; +} + +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; +} + +sub manage_selection { + my ($self, %options) = @_; + + my $result = $options{custom}->request_api( + type => 'op', + cmd => '', + ForceArray => ['entry'] + ); + + # MiB Mem : 31855.8 total, 2491.6 free, 15135.1 used, 22848.1 buff/cache + # MiB Swap: 2.0 total, 1.9 free, 0.1 used. 16720.7 avail Mem + if ($result !~ /^.*?Mem\s*:\s*(\S+)\s+total\s*,\s*(\S+)\s+free\s*,\s*(\S+)\s+used\s*,\s*(\S+)\s+buff\/cache/mi) { + $self->{output}->add_option_msg(short_msg => 'Some memory informations missing.'); + $self->{output}->option_exit(); + } + + my $total_size = $1 * 1024 * 1024; + my $free = $2 * 1024 * 1024; + my $used = $3 * 1024 * 1024; + my $buffer_used = $4 * 1024 * 1024; + + if ($result !~ /^.*?Swap\s*:\s*(\S+)\s+total\s*,\s*(\S+)\s+free\s*,\s*(\S+)\s+used\s*.\s*(\S+)\s+avail\s+Mem/mi) { + $self->{output}->add_option_msg(short_msg => 'Some memory informations missing.'); + $self->{output}->option_exit(); + } + + my $available = $4 * 1024 * 1024; + my $used_desc = 'buffers/cache'; + + $self->{memory} = { + total => $total_size, + used => $used, + free => $free, + prct_used => $used * 100 / $total_size, + prct_free => $free * 100 / $total_size, + used_desc => $used_desc, + available => $available, + prct_available => $available * 100 / $total_size, + buffer => $buffer_used + }; +} + +1; + +__END__ + +=head1 MODE + +Check memory + +=over 8 + +=item B<--warning-*> B<--critical-*> + +Thresholds. +Can be: 'memory-usage' (B), 'memory-usage-free' (B), 'memory-usage-prct' (%), +'memory-available' (B), 'memory-available-prct' (%), 'buffer' (B). + +=back + +=cut + diff --git a/src/network/paloalto/api/mode/sessions.pm b/src/network/paloalto/api/mode/sessions.pm new file mode 100644 index 0000000000..764b9e22d0 --- /dev/null +++ b/src/network/paloalto/api/mode/sessions.pm @@ -0,0 +1,206 @@ +# +# 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 network::paloalto::api::mode::sessions; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; +use centreon::plugins::constants qw(:counters); + +sub custom_vsys_active_perfdata { + my ($self, %options) = @_; + + $self->{output}->perfdata_add( + label => $self->{label}, + nlabel => $self->{nlabel}, + instances => $self->use_instances(extra_instance => $options{extra_instance}) ? $self->{result_values}->{display} : undef, + value => $self->{result_values}->{sessions_active}, + warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{thlabel}), + critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{thlabel}), + min => 0, + max => $self->{result_values}->{sessions_max} != 0 ? $self->{result_values}->{sessions_max} : undef + ); +} + +sub custom_active_perfdata { + my ($self, %options) = @_; + + $self->{output}->perfdata_add( + label => $self->{label}, + nlabel => $self->{nlabel}, + value => $self->{result_values}->{sessions_active}, + warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{thlabel}), + critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{thlabel}), + min => 0, + max => $self->{result_values}->{sessions_max} != 0 ? $self->{result_values}->{sessions_max} : undef + ); +} + +sub custom_active_output { + my ($self, %options) = @_; + + return sprintf('active: %s (%s)', + $self->{result_values}->{sessions_active}, + $self->{result_values}->{sessions_max} != 0 ? $self->{result_values}->{sessions_max} : '-' + ); +} + +sub prefix_global_output { + my ($self, %options) = @_; + + return "Sessions "; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'global', type => COUNTER_TYPE_GLOBAL, cb_prefix_output => 'prefix_global_output', skipped_code => { NO_VALUE => 1 } } + ]; + + $self->{maps_counters}->{global} = [ + { label => 'active', nlabel => 'sessions.active.count', set => { + key_values => [ { name => 'sessions_active' }, { name => 'sessions_max' } ], + closure_custom_output => $self->can('custom_active_output'), + closure_custom_perfdata => $self->can('custom_active_perfdata') + } + }, + { label => 'active-prct', nlabel => 'sessions.active.percentage', display_ok => 0, set => { + key_values => [ { name => 'sessions_active_prct' } ], + output_template => 'active: %.2f %%', + perfdatas => [ + { template => '%.2f', unit => '%', min => 0, max => 100 } + ] + } + }, + { label => 'active-tcp', nlabel => 'sessions.active.tcp.count', set => { + key_values => [ { name => 'sessions_tcp' } ], + output_template => 'TCP: %s', + perfdatas => [ + { template => '%s', min => 0 } + ] + } + }, + { label => 'active-udp', nlabel => 'sessions.active.udp.count', set => { + key_values => [ { name => 'sessions_udp' } ], + output_template => 'UDP: %s', + perfdatas => [ + { template => '%s', min => 0 } + ] + } + }, + { label => 'active-icmp', nlabel => 'sessions.active.icmp.count', set => { + key_values => [ { name => 'sessions_icmp' } ], + output_template => 'ICMP: %s', + perfdatas => [ + { template => '%s', min => 0 } + ] + } + } + ]; +} + +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; +} + +sub manage_selection { + my ($self, %options) = @_; + + my $result = $options{custom}->request_api( + type => 'op', + cmd => '', + ForceArray => [] + ); + + $self->{global} = { + sessions_max => $result->{'num-max'}, + sessions_active => $result->{'num-active'}, + sessions_udp => $result->{'num-udp'}, + sessions_tcp => $result->{'num-tcp'}, + sessions_icmp => $result->{'num-icmp'} + }; + + $self->{global}->{sessions_active_prct} = $self->{global}->{sessions_active} * 100 / $self->{global}->{sessions_max} + if ($self->{global}->{sessions_max} != 0); +} + +1; + +__END__ + +=head1 MODE + +Check sessions. + +=over 8 + +=item B<--warning-active> + +Warning threshold for active sessions. + +=item B<--critical-active> + +Critical threshold for active sessions. + +=item B<--warning-active-prct> + +Warning threshold for active sessions in percent. + +=item B<--critical-active-prct> + +Critical threshold for for active sessions in percent. + +=item B<--warning-active-udp> + +Warning threshold for active UDP sessions. + +=item B<--critical-active-udp> + +Critical threshold for active UDP sessions. + +=item B<--warning-active-tcp> + +Warning threshold for active TCP sessions. + +=item B<--critical-active-tcp> + +Critical threshold for active TCP sessions. + +=item B<--warning-active-icmp> + +Warning threshold for active ICMP sessions. + +=item B<--critical-active-icmp> + +Critical threshold for active ICMP sessions. + +=back + +=cut diff --git a/src/network/paloalto/api/plugin.pm b/src/network/paloalto/api/plugin.pm index 99373650c5..6f404f7437 100644 --- a/src/network/paloalto/api/plugin.pm +++ b/src/network/paloalto/api/plugin.pm @@ -29,11 +29,13 @@ sub new { my $self = $class->SUPER::new(package => __PACKAGE__, %options); bless $self, $class; - $self->{version} = '1.0'; $self->{modes} = { + 'cpu' => 'network::paloalto::api::mode::cpu', 'environment' => 'network::paloalto::api::mode::environment', 'ha' => 'network::paloalto::api::mode::ha', 'licenses' => 'network::paloalto::api::mode::licenses', + 'memory' => 'network::paloalto::api::mode::memory', + 'sessions' => 'network::paloalto::api::mode::sessions', 'system' => 'network::paloalto::api::mode::system', 'ipsec' => 'network::paloalto::api::mode::ipsec' }; From 84033c97c8822849dee48712214257786d9e21d0 Mon Sep 17 00:00:00 2001 From: garnier-quentin Date: Mon, 8 Jun 2026 10:44:20 -0400 Subject: [PATCH 03/12] wip --- src/network/paloalto/api/mode/interfaces.pm | 556 ++++++++++++++++++ .../paloalto/api/mode/listinterfaces.pm | 117 ++++ src/network/paloalto/api/plugin.pm | 18 +- 3 files changed, 683 insertions(+), 8 deletions(-) create mode 100644 src/network/paloalto/api/mode/interfaces.pm create mode 100644 src/network/paloalto/api/mode/listinterfaces.pm diff --git a/src/network/paloalto/api/mode/interfaces.pm b/src/network/paloalto/api/mode/interfaces.pm new file mode 100644 index 0000000000..b4c72aa5c4 --- /dev/null +++ b/src/network/paloalto/api/mode/interfaces.pm @@ -0,0 +1,556 @@ +# +# 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 network::paloalto::api::mode::interfaces; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; +use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold_ng); +use Digest::MD5 qw(md5_hex); +use centreon::plugins::constants qw(:counters); +use centreon::plugins::misc qw(is_excluded); + + +sub custom_status_output { + my ($self, %options) = @_; + + return 'state: ' . $self->{result_values}->{state}; +} + +sub custom_traffic_perfdata { + my ($self, %options) = @_; + + my ($warning, $critical); + if ($self->{instance_mode}->{option_results}->{units_traffic} eq 'percent_delta' && defined($self->{result_values}->{speed})) { + $warning = $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{thlabel}, total => $self->{result_values}->{speed}, cast_int => 1); + $critical = $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{thlabel}, total => $self->{result_values}->{speed}, cast_int => 1); + } elsif ($self->{instance_mode}->{option_results}->{units_traffic} =~ /bps|counter/) { + $warning = $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{thlabel}); + $critical = $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{thlabel}); + } + + if ($self->{instance_mode}->{option_results}->{units_traffic} eq 'counter') { + my $nlabel = $self->{nlabel}; + $nlabel =~ s/bitspersecond/bits/; + $self->{output}->perfdata_add( + nlabel => $nlabel, + unit => 'b', + instances => $self->{result_values}->{display}, + value => $self->{result_values}->{traffic_counter}, + warning => $warning, + critical => $critical, + min => 0 + ); + } else { + $self->{output}->perfdata_add( + nlabel => $self->{nlabel}, + instances => $self->use_instances(extra_instance => $options{extra_instance}) ? $self->{result_values}->{display} : undef, + value => sprintf('%d', $self->{result_values}->{traffic_per_seconds}), + warning => $warning, + critical => $critical, + min => 0, max => $self->{result_values}->{speed} + ); + } +} + +sub custom_traffic_threshold { + my ($self, %options) = @_; + + my $exit = 'ok'; + if ($self->{instance_mode}->{option_results}->{units_traffic} eq 'percent_delta' && defined($self->{result_values}->{speed})) { + $exit = $self->{perfdata}->threshold_check(value => + $self->{result_values}->{traffic_prct}, + threshold => + [ { label => 'critical-' . $self->{thlabel}, exit_litteral => 'critical' }, + { label => 'warning-' . $self->{thlabel}, exit_litteral => 'warning' } ]); + } elsif ($self->{instance_mode}->{option_results}->{units_traffic} eq 'bps') { + $exit = $self->{perfdata}->threshold_check(value => + $self->{result_values}->{traffic_per_seconds}, + threshold => + [ { label => 'critical-' . $self->{thlabel}, exit_litteral => 'critical' }, + { label => 'warning-' . $self->{thlabel}, exit_litteral => 'warning' } ]); + } elsif ($self->{instance_mode}->{option_results}->{units_traffic} eq 'counter') { + $exit = $self->{perfdata}->threshold_check(value => + $self->{result_values}->{traffic_counter}, + threshold => + [ { label => 'critical-' . $self->{thlabel}, exit_litteral => 'critical' }, + { label => 'warning-' . $self->{thlabel}, exit_litteral => 'warning' } ]); + } + return $exit; +} + +sub custom_traffic_output { + my ($self, %options) = @_; + + my ($traffic_value, $traffic_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{traffic_per_seconds}, network => 1); + return sprintf( + 'traffic %s: %s/s (%s)', + $self->{result_values}->{label}, $traffic_value . $traffic_unit, + defined($self->{result_values}->{traffic_prct}) ? sprintf('%.2f%%', $self->{result_values}->{traffic_prct}) : '-' + ); +} +sub custom_traffic_calc { + my ($self, %options) = @_; + + $self->{result_values}->{traffic_per_seconds} = ($options{new_datas}->{$self->{instance} . '_' . $options{extra_options}->{label_ref}} + - $options{old_datas}->{$self->{instance} . '_' . $options{extra_options}{label_ref}}) + / $options{delta_time}; + $self->{result_values}->{traffic_counter} = $options{new_datas}->{ $self->{instance} . '_' . $options{extra_options}->{label_ref} }; + + $self->{result_values}->{traffic_per_seconds} = sprintf('%d', $self->{result_values}->{traffic_per_seconds}); + + if (defined($options{new_datas}->{$self->{instance} . '_speed_' . $options{extra_options}->{label_ref}}) && + $options{new_datas}->{$self->{instance} . '_speed_' . $options{extra_options}->{label_ref}} ne '' && + $options{new_datas}->{$self->{instance} . '_speed_' . $options{extra_options}->{label_ref}} > 0) { + $self->{result_values}->{traffic_prct} = $self->{result_values}->{traffic_per_seconds} * 100 / $options{new_datas}->{$self->{instance} . '_speed_' . $options{extra_options}->{label_ref}}; + $self->{result_values}->{speed} = $options{new_datas}->{$self->{instance} . '_speed_' . $options{extra_options}->{label_ref}}; + } + + $self->{result_values}->{label} = $options{extra_options}->{label_ref}; + $self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_display'}; + return 0; +} + +sub custom_errors_perfdata { + my ($self, %options) = @_; + + if ($self->{instance_mode}->{option_results}->{units_errors} =~ /percent/) { + my $nlabel = $self->{nlabel}; + $nlabel =~ s/count$/percentage/; + + $self->{output}->perfdata_add( + nlabel => $nlabel, + unit => '%', + instances => $self->use_instances(extra_instance => $options{extra_instance}) ? $self->{result_values}->{display} : undef, + value => sprintf('%.2f', $self->{result_values}->{prct}), + warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{thlabel}), + critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{thlabel}), + min => 0, + max => 100 + ); + } else { + $self->{output}->perfdata_add( + nlabel => $self->{nlabel}, + instances => $self->use_instances(extra_instance => $options{extra_instance}) ? $self->{result_values}->{display} : undef, + value => $self->{result_values}->{used}, + warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{thlabel}), + critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{thlabel}), + min => 0, + max => $self->{result_values}->{total} + ); + } +} + +sub custom_errors_threshold { + my ($self, %options) = @_; + + my $exit = 'ok'; + if ($self->{instance_mode}->{option_results}->{units_errors} =~ /percent/) { + $exit = $self->{perfdata}->threshold_check( + value => $self->{result_values}->{prct}, + threshold => [ + { label => 'critical-' . $self->{thlabel}, exit_litteral => 'critical' }, + { label => 'warning-' . $self->{thlabel}, exit_litteral => 'warning' } + ] + ); + } else { + $exit = $self->{perfdata}->threshold_check( + value => $self->{result_values}->{used}, + threshold => [ + { label => 'critical-' . $self->{thlabel}, exit_litteral => 'critical' }, + { label => 'warning-' . $self->{thlabel}, exit_litteral => 'warning' } + ] + ); + } + + return $exit; +} + +sub custom_errors_output { + my ($self, %options) = @_; + + return sprintf( + '%s: %.2f%% (%s on %s)', + $self->{result_values}->{label}, + $self->{result_values}->{prct}, + $self->{result_values}->{used}, + $self->{result_values}->{total} + ); +} + +sub custom_errors_calc { + my ($self, %options) = @_; + + my $errors = $options{new_datas}->{ $self->{instance} . '_' . $options{extra_options}->{label_ref1} . $options{extra_options}->{label_ref2} }; + my $errors_diff = $options{new_datas}->{ $self->{instance} . '_' . $options{extra_options}->{label_ref1} . $options{extra_options}->{label_ref2} } + - $options{old_datas}->{ $self->{instance} . '_' . $options{extra_options}->{label_ref1} . $options{extra_options}->{label_ref2} }; + my $total = $options{new_datas}->{$self->{instance} . '_total_' . $options{extra_options}->{label_ref1} . '_packets'}; + my $total_diff = $options{new_datas}->{$self->{instance} . '_total_' . $options{extra_options}->{label_ref1} . '_packets'} + - $options{old_datas}->{$self->{instance} . '_total_' . $options{extra_options}->{label_ref1} . '_packets'}; + + $errors_diff = sprintf('%d', $errors_diff); + $total_diff = sprintf('%d', $total_diff); + $self->{result_values}->{prct} = 0; + $self->{result_values}->{used} = $errors_diff; + $self->{result_values}->{total} = $total_diff; + if ($self->{instance_mode}->{option_results}->{units_errors} eq 'percent_delta') { + $self->{result_values}->{prct} = $errors_diff * 100 / $total_diff if ($total_diff > 0); + } elsif ($self->{instance_mode}->{option_results}->{units_errors} eq 'percent') { + $self->{result_values}->{prct} = $errors * 100 / $total if ($total > 0); + $self->{result_values}->{used} = $errors; + $self->{result_values}->{total} = $total; + } elsif ($self->{instance_mode}->{option_results}->{units_errors} eq 'delta') { + $self->{result_values}->{prct} = $errors_diff * 100 / $total_diff if ($total_diff > 0); + $self->{result_values}->{used} = $errors_diff; + } else { + $self->{result_values}->{prct} = $errors * 100 / $total if ($total > 0); + $self->{result_values}->{used} = $errors; + $self->{result_values}->{total} = $total; + } + + if (defined($options{extra_options}->{label})) { + $self->{result_values}->{label} = $options{extra_options}->{label}; + } else { + $self->{result_values}->{label} = $options{extra_options}->{label_ref2}; + } + + $self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_display'}; + return 0; +} + +sub prefix_interface_output { + my ($self, %options) = @_; + + return "Interface '" . $options{instance_value}->{display} . "' "; +} + +sub interface_long_output { + my ($self, %options) = @_; + + return sprintf( + "checking interface '%s'", + $options{instance_value}->{display} + ); +} + +sub prefix_packets_in_output { + my ($self, %options) = @_; + + return 'packets in '; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'interfaces', type => COUNTER_TYPE_MULTIPLE, cb_prefix_output => 'prefix_interface_output', cb_long_output => 'interface_long_output', + indent_long_output => ' ', message_multiple => 'All interfaces are ok', + group => [ + { name => 'status', type => COUNTER_MULTIPLE_INSTANCE, skipped_code => { NO_VALUE => 1 } }, + { name => 'traffic', type => COUNTER_MULTIPLE_INSTANCE, skipped_code => { NO_VALUE => 1 } }, + { name => 'packets_in', type => COUNTER_MULTIPLE_INSTANCE, cb_prefix_output => 'prefix_packets_in_output', skipped_code => { NO_VALUE => 1 } } + ] + } + ]; + + $self->{maps_counters}->{status} = [ + { + label => 'status', + type => COUNTER_KIND_TEXT, + critical_default => '%{state} !~ /up|N\/A/', + set => { + key_values => [ { name => 'state' }, { name => 'display' } ], + closure_custom_output => $self->can('custom_status_output'), + closure_custom_perfdata => sub { return 0; }, + closure_custom_threshold_check => \&catalog_status_threshold_ng + } + } + ]; + + $self->{maps_counters}->{traffic} = [ + { label => 'in-traffic', nlabel => 'interface.traffic.in.bitspersecond', set => { + key_values => [ { name => 'in', diff => 1 }, { name => 'speed_in' }, { name => 'display' } ], + closure_custom_calc => $self->can('custom_traffic_calc'), closure_custom_calc_extra_options => { label_ref => 'in' }, + closure_custom_output => $self->can('custom_traffic_output'), output_error_template => 'traffic in: %s', + closure_custom_perfdata => $self->can('custom_traffic_perfdata'), + closure_custom_threshold_check => $self->can('custom_traffic_threshold') + } + }, + { label => 'out-traffic', nlabel => 'interface.traffic.out.bitspersecond', set => { + key_values => [ { name => 'out', diff => 1 }, { name => 'speed_out' }, { name => 'display' } ], + closure_custom_calc => $self->can('custom_traffic_calc'), closure_custom_calc_extra_options => { label_ref => 'out' }, + closure_custom_output => $self->can('custom_traffic_output'), output_error_template => 'traffic out: %s', + closure_custom_perfdata => $self->can('custom_traffic_perfdata'), + closure_custom_threshold_check => $self->can('custom_traffic_threshold') + } + } + ]; + + $self->{maps_counters}->{packets_in} = [ + { label => 'in-error', nlabel => 'interface.packets.in.error.count', set => { + key_values => [ { name => 'inerror', diff => 1 }, { name => 'total_in_packets', diff => 1 }, { name => 'display' } ], + closure_custom_calc => $self->can('custom_errors_calc'), closure_custom_calc_extra_options => { label_ref1 => 'in', label_ref2 => 'error' }, + closure_custom_output => $self->can('custom_errors_output'), output_error_template => 'error: %s', + closure_custom_perfdata => $self->can('custom_errors_perfdata'), + closure_custom_threshold_check => $self->can('custom_errors_threshold') + } + }, + { label => 'in-drop', nlabel => 'interface.packets.in.drop.count', set => { + key_values => [ { name => 'indrop', diff => 1 }, { name => 'total_in_packets', diff => 1 }, { name => 'display' } ], + closure_custom_calc => $self->can('custom_errors_calc'), + closure_custom_calc_extra_options => { label_ref1 => 'in', label_ref2 => 'drop' }, + closure_custom_output => $self->can('custom_errors_output'), output_error_template => 'drop: %s', + closure_custom_perfdata => $self->can('custom_errors_perfdata'), + closure_custom_threshold_check => $self->can('custom_errors_threshold') + } + } + ]; +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options, statefile => 1, force_new_perfdata => 1); + bless $self, $class; + + $options{options}->add_options(arguments => { + 'include-interface-name:s' => { name => 'include_interface_name', default => '' }, + 'exclude-interface-name:s' => { name => 'exclude_interface_name', default => '' }, + 'add-status' => { name => 'add_status' }, + 'add-traffic' => { name => 'add_traffic' }, + 'add-errors' => { name => 'add_errors' }, + 'units-traffic:s' => { name => 'units_traffic', default => 'percent_delta' }, + 'units-errors:s' => { name => 'units_errors', default => 'percent_delta' }, + 'speed:s' => { name => 'speed' } + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + # If no options, we set add-status + if (!defined($self->{option_results}->{add_traffic}) && + !defined($self->{option_results}->{add_errors}) && + !defined($self->{option_results}->{add_status})) { + $self->{option_results}->{add_status} = 1; + } + + if (defined($self->{option_results}->{speed}) && $self->{option_results}->{speed} ne '') { + if ($self->{option_results}->{speed} !~ /^[0-9]+(\.[0-9]+){0,1}$/) { + $self->{output}->add_option_msg(short_msg => "Speed must be a positive number '" . $self->{option_results}->{speed} . "' (can be a float also)."); + $self->{output}->option_exit(); + } else { + $self->{option_results}->{speed} *= 1000000; + } + } + + if (defined($self->{option_results}->{add_traffic})) { + $self->{option_results}->{units_traffic} = 'percent_delta' + if (!defined($self->{option_results}->{units_traffic}) || + $self->{option_results}->{units_traffic} eq '' || + $self->{option_results}->{units_traffic} eq '%'); + if ($self->{option_results}->{units_traffic} !~ /^(?:percent|percent_delta|bps|counter)$/) { + $self->{output}->add_option_msg(short_msg => 'Wrong option --units-traffic.'); + $self->{output}->option_exit(); + } + } + + if (defined($self->{option_results}->{add_errors})) { + $self->{option_results}->{units_errors} = 'percent_delta' + if (!defined($self->{option_results}->{units_errors}) || + $self->{option_results}->{units_errors} eq '' || + $self->{option_results}->{units_errors} eq '%'); + if ($self->{option_results}->{units_errors} !~ /^(?:percent|percent_delta|delta|counter)$/) { + $self->{output}->add_option_msg(short_msg => 'Wrong option --units-errors.'); + $self->{output}->option_exit(); + } + } + + $self->{checking} = ''; + foreach ('add_status', 'add_errors', 'add_traffic') { + if (defined($self->{option_results}->{$_})) { + $self->{checking} .= $_; + } + } +} + +sub manage_selection { + my ($self, %options) = @_; + + my $result = $options{custom}->request_api( + type => 'op', + cmd => 'all', + ForceArray => ['entry'] + ); + + foreach my $interface ((@{$result->{hw}->{entry}}, @{$result->{ifnet}->{entry}})) { + next if is_excluded($interface->{name}, $self->{option_results}->{include_interface_name}, $self->{option_results}->{exclude_inteface_name}); + + my $speed_in = defined($interface->{speed}) && $interface->{speed} =~ /^([0-9]+)$/ ? $interface->{speed} * 1000000 : ''; + my $speed_out = defined($interface->{speed}) && $interface->{speed} =~ /^([0-9]+)$/ ? $interface->{speed} * 1000000 : ''; + + $self->{interfaces}->{ $interface->{name} } = { display => $interface->{name} }; + + if (defined($self->{option_results}->{add_status})) { + $self->{interfaces}->{ $interface->{name} }->{status} = { + display => $interface->{name}, + state => defined($interface->{state}) ? $interface->{state} : 'N/A', + }; + } + if (defined($self->{option_results}->{add_traffic})) { + $self->{interfaces}->{ $interface->{name} }->{traffic} = { + display => $interface->{name}, + speed_in => defined($self->{option_results}->{speed}) ? $self->{option_results}->{speed} : $speed_in, + speed_out => defined($self->{option_results}->{speed}) ? $self->{option_results}->{speed} : $speed_out + } + } + if (defined($self->{option_results}->{add_errors})) { + $self->{interfaces}->{ $interface->{name} }->{packets_in} = { + display => $interface->{name} + }; + }; + } + + if (scalar(keys %{$self->{interfaces}}) <= 0) { + $self->{output}->add_option_msg(short_msg => "No interface found."); + $self->{output}->option_exit(); + } + + $result = $options{custom}->request_api( + type => 'op', + cmd => 'all', + ForceArray => ['entry'] + ); + + foreach my $interface ((@{$result->{hw}->{entry}}, @{$result->{ifnet}->{ifnet}->{entry}})) { + next if (!defined($self->{interfaces}->{ $interface->{name} })); + + if (defined($self->{option_results}->{add_traffic})) { + $self->{interfaces}->{ $interface->{name} }->{traffic}->{in} = $interface->{ibytes}; + $self->{interfaces}->{ $interface->{name} }->{traffic}->{out} = $interface->{obytes}; + } + + if (defined($self->{option_results}->{add_errors})) { + $self->{interfaces}->{ $interface->{name} }->{packets_in}->{total_in_packets} = $interface->{ipackets}; + $self->{interfaces}->{ $interface->{name} }->{packets_in}->{inerror} = $interface->{ierrors}; + $self->{interfaces}->{ $interface->{name} }->{packets_in}->{indrop} = $interface->{idrops}; + } + } + + $self->{cache_name} = 'paloalto_' . $options{custom}->get_hostname() . '_' . $options{custom}->get_port() . $self->{mode} . '_' . + md5_hex( + (defined($self->{option_results}->{filter_counters}) ? $self->{option_results}->{filter_counters} : '') . '_' . + (defined($self->{option_results}->{include_interface_name}) ? $self->{option_results}->{include_interface_name} : '') . '_' . + (defined($self->{option_results}->{exclude_interface_name}) ? $self->{option_results}->{exclude_interface_name} : '') . '_' . + $self->{checking} + ); +} + +1; + +__END__ + +=head1 MODE + +Check interfaces. + +=over 8 + +=item B<--include-interface-name> + +Include interface names (regexp). + +=item B<--exclude-interface-name> + +Exclude interface names (regexp). + +=item B<--add-status> + +Check interface status. + +=item B<--add-traffic> + +Check interface traffic. + +=item B<--add-errors> + +Check interface errors. + +=item B<--warning-status> + +Define the conditions to match for the status to be WARNING. +You can use the following variables: C<%{state}>, C<%{display}> + +=item B<--critical-status> + +Define the conditions to match for the status to be CRITICAL (default: C<'%{state} !~ /up|N\/A/'>). +You can use the following variables: C<%{state}>, C<%{display}> + +=item B<--warning-in-drop> + +Threshold. + +=item B<--critical-in-drop> + +Threshold. + +=item B<--warning-in-error> + +Threshold. + +=item B<--critical-in-error> + +Threshold. + +=item B<--warning-in-traffic> + +Threshold. + +=item B<--critical-in-traffic> + +Threshold. + +=item B<--warning-out-traffic> + +Threshold. + +=item B<--critical-out-traffic> + +Threshold. + +=item B<--units-traffic> + +Units of thresholds for the traffic (default: C) (C, C, C). + +=item B<--units-errors> + +Units of thresholds for errors/discards (default: C) (C, C, C, C). + +=item B<--speed> + +Set interface speed (in Mb). + +=back + +=cut diff --git a/src/network/paloalto/api/mode/listinterfaces.pm b/src/network/paloalto/api/mode/listinterfaces.pm new file mode 100644 index 0000000000..3e2785841e --- /dev/null +++ b/src/network/paloalto/api/mode/listinterfaces.pm @@ -0,0 +1,117 @@ +# +# 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 network::paloalto::api::mode::listinterfaces; + +use base qw(centreon::plugins::mode); + +use strict; +use warnings; + +my @labels = ( + 'name', + 'state', + 'speed' +); + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $options{options}->add_options(arguments => {}); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::init(%options); +} + +sub manage_selection { + my ($self, %options) = @_; + + my $result = $options{custom}->request_api( + type => 'op', + cmd => 'all', + ForceArray => ['entry'] + ); + + my $results = {}; + foreach my $interface ((@{$result->{hw}->{entry}}, @{$result->{ifnet}->{entry}})) { + $results->{ $interface->{name} } = { + name => $interface->{name}, + state => defined($interface->{state}) ? $interface->{state} : 'N/A', + speed => defined($interface->{speed}) ? $interface->{speed} : '' + }; + } + + return $results; +} + +sub run { + my ($self, %options) = @_; + + my $results = $self->manage_selection(custom => $options{custom}); + foreach my $instance (sort keys %$results) { + $self->{output}->output_add(long_msg => + join('', map("[$_: " . $results->{$instance}->{$_} . ']', @labels)) + ); + } + + $self->{output}->output_add( + severity => 'OK', + short_msg => 'List interfaces:' + ); + $self->{output}->display(nolabel => 1, force_ignore_perfdata => 1, force_long_output => 1); + $self->{output}->exit(); +} + +sub disco_format { + my ($self, %options) = @_; + + $self->{output}->add_disco_format(elements => [ @labels ]); +} + +sub disco_show { + my ($self, %options) = @_; + + my $results = $self->manage_selection(custom => $options{custom}); + foreach (sort keys %$results) { + $self->{output}->add_disco_entry( + %{$results->{$_}} + ); + } +} + +1; + +__END__ + +=head1 MODE + +List interfaces. + +=over 8 + +=back + +=cut diff --git a/src/network/paloalto/api/plugin.pm b/src/network/paloalto/api/plugin.pm index 6f404f7437..681a3017dd 100644 --- a/src/network/paloalto/api/plugin.pm +++ b/src/network/paloalto/api/plugin.pm @@ -30,14 +30,16 @@ sub new { bless $self, $class; $self->{modes} = { - 'cpu' => 'network::paloalto::api::mode::cpu', - 'environment' => 'network::paloalto::api::mode::environment', - 'ha' => 'network::paloalto::api::mode::ha', - 'licenses' => 'network::paloalto::api::mode::licenses', - 'memory' => 'network::paloalto::api::mode::memory', - 'sessions' => 'network::paloalto::api::mode::sessions', - 'system' => 'network::paloalto::api::mode::system', - 'ipsec' => 'network::paloalto::api::mode::ipsec' + 'cpu' => 'network::paloalto::api::mode::cpu', + 'environment' => 'network::paloalto::api::mode::environment', + 'ha' => 'network::paloalto::api::mode::ha', + 'interfaces' => 'network::paloalto::api::mode::interfaces', + 'ipsec' => 'network::paloalto::api::mode::ipsec', + 'licenses' => 'network::paloalto::api::mode::licenses', + 'list-interfaces' => 'network::paloalto::api::mode::listinterfaces', + 'memory' => 'network::paloalto::api::mode::memory', + 'sessions' => 'network::paloalto::api::mode::sessions', + 'system' => 'network::paloalto::api::mode::system' }; $self->{custom_modes}->{api} = 'network::paloalto::api::custom::api'; From b2471a7064cccb75b5fb72c101b9e6b620cdedf0 Mon Sep 17 00:00:00 2001 From: garnier-quentin Date: Mon, 15 Jun 2026 09:04:17 -0400 Subject: [PATCH 04/12] wip --- src/centreon/plugins/backend/ssh/libssh.pm | 39 +++++ src/centreon/plugins/backend/ssh/plink.pm | 7 + src/centreon/plugins/backend/ssh/sshcli.pm | 7 + src/centreon/plugins/ssh.pm | 14 +- src/storage/veritas/nba/ssh/custom/cli.pm | 159 ++++++++++++++++++ .../veritas/nba/ssh/mode/components/disk.pm | 72 ++++++++ .../veritas/nba/ssh/mode/components/fan.pm | 72 ++++++++ .../veritas/nba/ssh/mode/components/psu.pm | 72 ++++++++ .../nba/ssh/mode/components/temperature.pm | 99 +++++++++++ src/storage/veritas/nba/ssh/mode/hardware.pm | 131 +++++++++++++++ src/storage/veritas/nba/ssh/plugin.pm | 48 ++++++ 11 files changed, 718 insertions(+), 2 deletions(-) create mode 100644 src/storage/veritas/nba/ssh/custom/cli.pm create mode 100644 src/storage/veritas/nba/ssh/mode/components/disk.pm create mode 100644 src/storage/veritas/nba/ssh/mode/components/fan.pm create mode 100644 src/storage/veritas/nba/ssh/mode/components/psu.pm create mode 100644 src/storage/veritas/nba/ssh/mode/components/temperature.pm create mode 100644 src/storage/veritas/nba/ssh/mode/hardware.pm create mode 100644 src/storage/veritas/nba/ssh/plugin.pm diff --git a/src/centreon/plugins/backend/ssh/libssh.pm b/src/centreon/plugins/backend/ssh/libssh.pm index 2c4c37145e..2d85b6b581 100644 --- a/src/centreon/plugins/backend/ssh/libssh.pm +++ b/src/centreon/plugins/backend/ssh/libssh.pm @@ -162,6 +162,45 @@ sub execute { return ($content, $exit_code); } +sub execute_scenario { + my ($self, %options) = @_; + + if (defined($options{timeout}) && $options{timeout} =~ /(\d+)/) { + $self->{ssh}->options(timeout => $options{timeout}); + } + + $self->connect(hostname => $options{hostname}); + + my $ret = $self->{ssh}->execute_scenario($options{request}); + + $self->{output}->output_add(long_msg => $ret->{stdout}, debug => 1) if (defined($ret->{stdout})); + $self->{output}->output_add(long_msg => $ret->{stderr}, debug => 1) if (defined($ret->{stderr})); + + my ($content, $exit_code); + if ($ret->{exit} == $self->{constant_cb}->(name => 'SSH_OK')) { + $content = $ret->{stdout}; + $exit_code = $ret->{exit_code}; + } elsif ($ret->{exit} == $self->{constant_cb}->(name => 'SSH_AGAIN')) { # AGAIN means timeout + $self->{output}->add_option_msg(short_msg => sprintf('command execution timeout')); + $self->{output}->option_exit(); + } else { + $self->{output}->add_option_msg(short_msg => + sprintf( + 'command execution error: %s', + $self->{ssh}->error(GetErrorSession => 1) + ) + ); + $self->{output}->option_exit(); + } + + if ($exit_code != 0 && (!defined($options{no_quit}) || $options{no_quit} != 1)) { + $self->{output}->add_option_msg(short_msg => sprintf('command execution error [exit code: %s]', $exit_code)); + $self->{output}->option_exit(); + } + + return ($content, $exit_code); +} + 1; __END__ diff --git a/src/centreon/plugins/backend/ssh/plink.pm b/src/centreon/plugins/backend/ssh/plink.pm index 21562db544..6bded3d72c 100644 --- a/src/centreon/plugins/backend/ssh/plink.pm +++ b/src/centreon/plugins/backend/ssh/plink.pm @@ -106,6 +106,13 @@ sub execute { return ($content, $exit_code); } +sub execute_scenario { + my ($self, %options) = @_; + + $self->{output}->add_option_msg(short_msg => 'Unsupported method for sshcli backend: execute_scenario'); + $self->{output}->option_exit(); +} + 1; __END__ diff --git a/src/centreon/plugins/backend/ssh/sshcli.pm b/src/centreon/plugins/backend/ssh/sshcli.pm index 7a6aadc1c9..8b73878767 100644 --- a/src/centreon/plugins/backend/ssh/sshcli.pm +++ b/src/centreon/plugins/backend/ssh/sshcli.pm @@ -105,6 +105,13 @@ sub execute { return ($content, $exit_code); } +sub execute_scenario { + my ($self, %options) = @_; + + $self->{output}->add_option_msg(short_msg => 'Unsupported method for sshcli backend: execute_scenario'); + $self->{output}->option_exit(); +} + 1; __END__ diff --git a/src/centreon/plugins/ssh.pm b/src/centreon/plugins/ssh.pm index 2d93d8c530..231e39ccdb 100644 --- a/src/centreon/plugins/ssh.pm +++ b/src/centreon/plugins/ssh.pm @@ -30,7 +30,7 @@ sub new { if (!defined($options{noptions}) || $options{noptions} != 1) { $options{options}->add_options(arguments => { - 'ssh-backend:s' => { name => 'ssh_backend', default => 'sshcli' }, + 'ssh-backend:s' => { name => 'ssh_backend' }, 'ssh-port:s' => { name => 'ssh_port' }, 'ssh-priv-key:s' => { name => 'ssh_priv_key' }, 'ssh-username:s' => { name => 'ssh_username' }, @@ -60,6 +60,9 @@ sub new { ); $self->{backend_libssh} = centreon::plugins::backend::ssh::libssh->new(%options); + $self->{default_backend} = defined($options{default_backend}) && $options{default_backend} ne '' ? + $options{default_backend} : 'sshcli'; + $self->{output} = $options{output}; return $self; } @@ -68,12 +71,13 @@ sub check_options { my ($self, %options) = @_; $self->{ssh_backend} = $options{option_results}->{ssh_backend}; + my $default_port = 22; if (defined($options{default_ssh_port}) && $options{default_ssh_port} =~ /\d+/) { $default_port = $options{default_ssh_port}; } $self->{ssh_port} = defined($options{option_results}->{ssh_port}) && $options{option_results}->{ssh_port} =~ /(\d+)/ ? $1 : $default_port; - $self->{ssh_backend} = 'sshcli' + $self->{ssh_backend} = $self->{default_backend} if (!defined($options{option_results}->{ssh_backend}) || $options{option_results}->{ssh_backend} eq ''); if (!defined($self->{'backend_' . $self->{ssh_backend}})) { $self->{output}->add_option_msg(short_msg => 'unknown ssh backend: ' . $self->{ssh_backend}); @@ -100,6 +104,12 @@ sub execute { return $self->{'backend_' . $self->{ssh_backend}}->execute(%options); } +sub execute_scenario { + my ($self, %options) = @_; + + return $self->{'backend_' . $self->{ssh_backend}}->execute_scenario(%options); +} + 1; __END__ diff --git a/src/storage/veritas/nba/ssh/custom/cli.pm b/src/storage/veritas/nba/ssh/custom/cli.pm new file mode 100644 index 0000000000..892ef32807 --- /dev/null +++ b/src/storage/veritas/nba/ssh/custom/cli.pm @@ -0,0 +1,159 @@ +# +# 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 storage::veritas::nba::ssh::custom::cli; + +use strict; +use warnings; +use centreon::plugins::ssh; +use centreon::plugins::misc; + +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; + } + if (!defined($options{options})) { + $options{output}->add_option_msg(short_msg => "Class Custom: Need to specify 'options' argument."); + $options{output}->option_exit(); + } + + if (!defined($options{noptions})) { + $options{options}->add_options(arguments => { + 'hostname:s' => { name => 'hostname' }, + 'timeout:s' => { name => 'timeout', default => 55 }, + 'command:s' => { name => 'command' }, + 'command-path:s' => { name => 'command_path' }, + 'command-options:s' => { name => 'command_options' } + }); + } + $options{options}->add_help(package => __PACKAGE__, sections => 'SSH OPTIONS', once => 1); + + $self->{output} = $options{output}; + $self->{ssh} = centreon::plugins::ssh->new(%options, default_backend => 'libssh'); + + return $self; +} + +sub set_options { + my ($self, %options) = @_; + + $self->{option_results} = $options{option_results}; +} + +sub set_defaults {} + +sub check_options { + my ($self, %options) = @_; + + if (defined($self->{option_results}->{hostname}) && $self->{option_results}->{hostname} ne '') { + $self->{ssh}->check_options(option_results => $self->{option_results}); + } + + centreon::plugins::misc::check_security_command( + output => $self->{output}, + command => $self->{option_results}->{command}, + command_options => $self->{option_results}->{command_options}, + command_path => $self->{option_results}->{command_path} + ); + + return 0; +} + +sub execute_scenario { + my ($self, %options) = @_; + + my $content; + if (defined($self->{option_results}->{hostname}) && $self->{option_results}->{hostname} ne '') { + ($content) = $self->{ssh}->execute_scenario( + hostname => $self->{option_results}->{hostname}, + request => $options{request}, + timeout => $self->{option_results}->{timeout} + ); + } else { + if (!defined($self->{option_results}->{command}) || $self->{option_results}->{command} eq '') { + $self->{output}->add_option_msg(short_msg => 'please set --hostname option for ssh connection (or --command for local)'); + $self->{output}->option_exit(); + } + + ($content) = centreon::plugins::misc::execute( + output => $self->{output}, + options => { timeout => $self->{option_results}->{timeout} }, + command => $self->{option_results}->{command}, + command_path => $self->{option_results}->{command_path}, + command_options => $self->{option_results}->{command_options} + ); + } + + $content =~ s/\x{0d}//g; # carriage return + $content =~ s/\x{08}//g; # backspace + $content =~ s/\x{1b}\x{5b}\x{30}\x{6d}//g; + $content =~ s/\x{1b}\x{5b}\x{31}\x{6d}//g; + + return $content; +} + +1; + +__END__ + +=head1 NAME + +ssh + +=head1 SYNOPSIS + +my ssh + +=head1 SSH OPTIONS + +=over 8 + +=item B<--hostname> + +Hostname to query. + +=item B<--timeout> + +Timeout in seconds for the command (default: 55). + +=item B<--command> + +Command to get information. Used it you have output in a file. + +=item B<--command-path> + +Command path. + +=item B<--command-options> + +Command options. + +=back + +=head1 DESCRIPTION + +B. + +=cut diff --git a/src/storage/veritas/nba/ssh/mode/components/disk.pm b/src/storage/veritas/nba/ssh/mode/components/disk.pm new file mode 100644 index 0000000000..5edbe0a283 --- /dev/null +++ b/src/storage/veritas/nba/ssh/mode/components/disk.pm @@ -0,0 +1,72 @@ +# +# 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 storage::veritas::nba::ssh::mode::components::disk; + +use strict; +use warnings; +use centreon::plugins::misc; + +sub load {} + +sub check { + my ($self) = @_; + + $self->{output}->output_add(long_msg => 'checking disks'); + $self->{components}->{disk} = { name => 'disk', total => 0, skip => 0 }; + return if ($self->check_filter(section => 'disk')); + + while ($self->{result} =~ /Hardware\s+monitor\s+information\s+(.*?)(?=\s+Hardware monitor information|\Z$)/msg) { + my $part = $1; + + next if ($part !~ /NetBackup\s+StorageShelf\s+(\d+)/i); + my $shelf = $1; + + while ($part =~ /^.*?Controller.*?Disk.*?\|(.*?)\|.*?\|.*?\|.*?\|.*?\|.*?\|.*?\|.*?\|(.*?)\|(.*?)\|/mig) { + my ($enclosure, $disk, $state) = (centreon::plugins::misc::trim($2), centreon::plugins::misc::trim($1), centreon::plugins::misc::trim($3)); + my $instance = 'shelf' . $shelf . '.' . $enclosure . '.' . $disk; + + next if ($self->check_filter(section => 'disk', instance => $instance)); + $self->{components}->{disk}->{total}++; + + $self->{output}->output_add( + long_msg => sprintf( + "disk '%s' shelf '%s' enclosure '%s' state is %s", + $disk, + $shelf, + $enclosure, + $state + ) + ); + my $exit = $self->get_severity(label => 'default', section => 'disk', instance => $instance, value => $state); + if (!$self->{output}->is_status(value => $exit, compare => 'ok', litteral => 1)) { + $self->{output}->output_add( + severity => $exit, + short_msg => sprintf( + "disk '%s' shelf '%s' enclosure '%s' state is %s", + $disk, $shelf, $enclosure, $state + ) + ); + } + } + } +} + +1; diff --git a/src/storage/veritas/nba/ssh/mode/components/fan.pm b/src/storage/veritas/nba/ssh/mode/components/fan.pm new file mode 100644 index 0000000000..4df64ff751 --- /dev/null +++ b/src/storage/veritas/nba/ssh/mode/components/fan.pm @@ -0,0 +1,72 @@ +# +# 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 storage::veritas::nba::ssh::mode::components::fan; + +use strict; +use warnings; +use centreon::plugins::misc; + +sub load {} + +sub check { + my ($self) = @_; + + $self->{output}->output_add(long_msg => 'checking fans'); + $self->{components}->{fan} = { name => 'fan', total => 0, skip => 0 }; + return if ($self->check_filter(section => 'fan')); + + while ($self->{result} =~ /Hardware\s+monitor\s+information\s+(.*?)(?=\s+Hardware monitor information|\Z$)/msg) { + my $part = $1; + + next if ($part !~ /StorageShelf\s+(\d+)\s+Fan\s+Information/i); + my $shelf = $1; + + while ($part =~ /^.*?Enclosure(.*?)Fan\s+(.*?)\s+\|.*?\|.*?\|.*?\|(.*?)\|/mig) { + my ($enclosure, $fan, $state) = (centreon::plugins::misc::trim($1), centreon::plugins::misc::trim($2), centreon::plugins::misc::trim($3)); + my $instance = 'shelf' . $shelf . '.' . $enclosure . '.' . $fan; + + next if ($self->check_filter(section => 'fan', instance => $instance)); + $self->{components}->{fan}->{total}++; + + $self->{output}->output_add( + long_msg => sprintf( + "fan '%s' shelf '%s' enclosure '%s' state is %s", + $fan, + $shelf, + $enclosure, + $state + ) + ); + my $exit = $self->get_severity(label => 'default', section => 'fan', instance => $instance, value => $state); + if (!$self->{output}->is_status(value => $exit, compare => 'ok', litteral => 1)) { + $self->{output}->output_add( + severity => $exit, + short_msg => sprintf( + "fan '%s' shelf '%s' enclosure '%s' state is %s", + $fan, $shelf, $enclosure, $state + ) + ); + } + } + } +} + +1; diff --git a/src/storage/veritas/nba/ssh/mode/components/psu.pm b/src/storage/veritas/nba/ssh/mode/components/psu.pm new file mode 100644 index 0000000000..0292cb4327 --- /dev/null +++ b/src/storage/veritas/nba/ssh/mode/components/psu.pm @@ -0,0 +1,72 @@ +# +# 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 storage::veritas::nba::ssh::mode::components::psu; + +use strict; +use warnings; +use centreon::plugins::misc; + +sub load {} + +sub check { + my ($self) = @_; + + $self->{output}->output_add(long_msg => 'checking power supplies'); + $self->{components}->{psu} = { name => 'psu', total => 0, skip => 0 }; + return if ($self->check_filter(section => 'psu')); + + while ($self->{result} =~ /Hardware\s+monitor\s+information\s+(.*?)(?=\s+Hardware monitor information|\Z$)/msg) { + my $part = $1; + + next if ($part !~ /StorageShelf\s+(\d+)\s+Power\s+Supply\s+Information/i); + my $shelf = $1; + + while ($part =~ /^.*?Enclosure(.*?)Power\s+Supply\s+(.*?)\s+\|.*?\|(.*?)\|/mig) { + my ($enclosure, $psu, $state) = (centreon::plugins::misc::trim($1), centreon::plugins::misc::trim($2), centreon::plugins::misc::trim($3)); + my $instance = 'shelf' . $shelf . '.' . $enclosure . '.' . $psu; + + next if ($self->check_filter(section => 'psu', instance => $instance)); + $self->{components}->{psu}->{total}++; + + $self->{output}->output_add( + long_msg => sprintf( + "power supply '%s' shelf '%s' enclosure '%s' state is %s", + $psu, + $shelf, + $enclosure, + $state + ) + ); + my $exit = $self->get_severity(label => 'default', section => 'psu', instance => $instance, value => $state); + if (!$self->{output}->is_status(value => $exit, compare => 'ok', litteral => 1)) { + $self->{output}->output_add( + severity => $exit, + short_msg => sprintf( + "power supply '%s' shelf '%s' enclosure '%s' state is %s", + $psu, $shelf, $enclosure, $state + ) + ); + } + } + } +} + +1; diff --git a/src/storage/veritas/nba/ssh/mode/components/temperature.pm b/src/storage/veritas/nba/ssh/mode/components/temperature.pm new file mode 100644 index 0000000000..608ed61cd2 --- /dev/null +++ b/src/storage/veritas/nba/ssh/mode/components/temperature.pm @@ -0,0 +1,99 @@ +# +# 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 storage::veritas::nba::ssh::mode::components::temperature; + +use strict; +use warnings; +use centreon::plugins::misc; + +sub load {} + +sub check { + my ($self) = @_; + + $self->{output}->output_add(long_msg => 'checking temperatures'); + $self->{components}->{temperature} = { name => 'temperature', total => 0, skip => 0 }; + return if ($self->check_filter(section => 'temperature')); + + while ($self->{result} =~ /Hardware\s+monitor\s+information\s+(.*?)(?=\s+Hardware monitor information|\Z$)/msg) { + my $part = $1; + + next if ($part !~ /StorageShelf\s+(\d+)\s+Temperature\s+Information/i); + my $shelf = $1; + + while ($part =~ /^.*?Enclosure(.*?)Temperature\s+(.*?)\s+\|(.*?)Degrees\s+Celsius.*?\|.*?\|(.*?)\|/mig) { + my ($enclosure, $temp, $read, $state) = (centreon::plugins::misc::trim($1), centreon::plugins::misc::trim($2), centreon::plugins::misc::trim($3), centreon::plugins::misc::trim($4)); + my $instance = 'shelf' . $shelf . '.' . $enclosure . '.' . $temp; + + next if ($self->check_filter(section => 'temperature', instance => $instance)); + $self->{components}->{temperature}->{total}++; + + $self->{output}->output_add( + long_msg => sprintf( + "temperature '%s' shelf '%s' enclosure '%s' state is %s [current: %s]", + $temp, + $shelf, + $enclosure, + $state, + $read + ) + ); + my $exit = $self->get_severity(label => 'default', section => 'temperature', instance => $instance, value => $state); + if (!$self->{output}->is_status(value => $exit, compare => 'ok', litteral => 1)) { + $self->{output}->output_add( + severity => $exit, + short_msg => sprintf( + "temperature '%s' shelf '%s' enclosure '%s' state is %s", + $temp, $shelf, $enclosure, $state + ) + ); + } + + next if ($read !~ /[0-9]+/); + + my ($exit2, $warn, $crit, $checked) = $self->get_severity_numeric(section => 'temperature', instance => $instance, value => $read); + + if (!$self->{output}->is_status(value => $exit2, compare => 'ok', litteral => 1)) { + $self->{output}->output_add( + severity => $exit2, + short_msg => sprintf( + "temperature '%s' shelf '%s' enclosure '%s' is %s degree centigrade", + $temp, + $shelf, + $enclosure, + $read + ) + ); + } + + $self->{output}->perfdata_add( + nlabel => 'hardware.temperature.celsius', + unit => 'C', + instances => ['shelf' . $shelf, $enclosure, $temp], + value => $read, + warning => $warn, + critical => $crit + ); + } + } +} + +1; diff --git a/src/storage/veritas/nba/ssh/mode/hardware.pm b/src/storage/veritas/nba/ssh/mode/hardware.pm new file mode 100644 index 0000000000..8bb578544e --- /dev/null +++ b/src/storage/veritas/nba/ssh/mode/hardware.pm @@ -0,0 +1,131 @@ +# +# 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 storage::veritas::nba::ssh::mode::hardware; + +use base qw(centreon::plugins::templates::hardware); + +use strict; +use warnings; + +sub set_system { + my ($self, %options) = @_; + + $self->{cb_hook2} = 'ssh_execute'; + + $self->{thresholds} = { + default => [ + ['ok', 'OK'], + ['.*', 'CRITICAL'] + ] + }; + + $self->{components_path} = 'storage::veritas::nba::ssh::mode::components'; + $self->{components_module} = ['disk', 'fan', 'psu', 'temperature']; +} + +sub ssh_execute { + my ($self, %options) = @_; + + ($self->{result}) = $options{custom}->execute_scenario( + request => { + interactive => 1, + rows => 800, + cols => 80, + scenario => [ + { "cmd" => "waitfor", "options" => { "Match" => 'Main_Menu>', "Timeout" => "20" } }, + { "cmd" => "put", "options" => { "String" => "Monitor\n", "Timeout" => "5" } }, + { "cmd" => "waitfor", "options" => { "Match" => 'Monitor>', "Timeout" => "5" } }, + { "cmd" => "put", "options" => { "String" => "Hardware ShowHealth StorageShelf all\n", "Timeout" => "5" } }, + { "cmd" => "waitfor", "options" => { "Match" => 'to quit', "Timeout" => "10" } }, + { "cmd" => "put", "options" => { "String" => 'f', "Timeout" => "30" } }, + { "cmd" => "waitfor", "options" => { "Match" => 'to quit', "Timeout" => "10" } }, + { "cmd" => "put", "options" => { "String" => 'q', "Timeout" => "30" } }, + { "cmd" => "waitfor", "options" => { "Match" => 'Monitor>', "Timeout" => "10" } }, + { "cmd" => "put", "options" => { "String" => "exit\n", "Timeout" => "5" } }, + { "cmd" => "close" } + ] + } + ); + + $self->{result} =~ s/\x{1b}\x{5b}\x{37}\x{6d}.*?\x{1b}\x{5b}\x{32}\x{37}\x{6d}//mg; # Press 'q' to quit... for previous page +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options, no_absent => 1, force_new_perfdata => 1); + bless $self, $class; + + $options{options}->add_options(arguments => {}); + + $self->{commands} = []; + return $self; +} + +1; + +__END__ + +=head1 MODE + +Check harware(disks, fans, power supplies and temperatures). + +=over 8 + +=item B<--component> + +Which component to check (default: '.*'). +Can be: 'disk', 'fan', 'psu', 'temperature'. + +=item B<--filter> + +Exclude the items given as a comma-separated list (example: --filter=temperature). +You can also exclude items from specific instances: --filter=C + +=item B<--no-component> + +Define the expected status if no components are found (default: critical). + +=item B<--threshold-overload> + +Use this option to override the status returned by the plugin when the status label matches a regular expression (syntax: section,[instance,]status,regexp). +Example: --threshold-overload='psu,ok,true' + +=item B<--warning> + +Set warning threshold for 'temperature' (syntax: type,regexp,threshold) +Example: --warning='temperature,.*,50' + +=item B<--critical> + +Set critical threshold for 'temperature' (syntax: type,regexp,threshold) +Example: --critical='temperature,.*,70' + +=item B<--warning-count-*> + +Define the warning threshold for the number of components of one type (replace '*' with the component type). + +=item B<--critical-count-*> + +Define the critical threshold for the number of components of one type (replace '*' with the component type). + +=back + +=cut diff --git a/src/storage/veritas/nba/ssh/plugin.pm b/src/storage/veritas/nba/ssh/plugin.pm new file mode 100644 index 0000000000..59f76389da --- /dev/null +++ b/src/storage/veritas/nba/ssh/plugin.pm @@ -0,0 +1,48 @@ +# +# 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 storage::veritas::nba::ssh::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} = { + 'hardware' => 'storage::veritas::nba::ssh::mode::hardware', + }; + + $self->{custom_modes}->{ssh} = 'storage::veritas::nba::ssh::custom::cli'; + return $self; +} + +1; + +__END__ + +=head1 PLUGIN DESCRIPTION + +Check Veritas Netbackup Appliance in SSH. + +=cut From 83fa1388c0019199186f78e555b797c86b0fff93 Mon Sep 17 00:00:00 2001 From: garnier-quentin Date: Mon, 15 Jun 2026 09:15:59 -0400 Subject: [PATCH 05/12] wip --- src/storage/veritas/nba/ssh/mode/memory.pm | 193 +++++++++++++++++++++ src/storage/veritas/nba/ssh/plugin.pm | 3 +- 2 files changed, 195 insertions(+), 1 deletion(-) create mode 100644 src/storage/veritas/nba/ssh/mode/memory.pm diff --git a/src/storage/veritas/nba/ssh/mode/memory.pm b/src/storage/veritas/nba/ssh/mode/memory.pm new file mode 100644 index 0000000000..d702cfa7c4 --- /dev/null +++ b/src/storage/veritas/nba/ssh/mode/memory.pm @@ -0,0 +1,193 @@ +# +# 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 storage::veritas::nba::ssh::mode::memory; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; +use centreon::plugins::constants qw(:counters); + +sub custom_memory_output { + my ($self, %options) = @_; + + return sprintf( + 'Ram total: %s %s used (-%s): %s %s (%.2f%%) free: %s %s (%.2f%%) available: %s %s (%.2f%%)', + $self->{perfdata}->change_bytes(value => $self->{result_values}->{total}), + $self->{result_values}->{used_desc}, + $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}, + $self->{perfdata}->change_bytes(value => $self->{result_values}->{available}), + $self->{result_values}->{prct_available}, + + ); +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'memory', type => COUNTER_TYPE_GLOBAL, skipped_code => { NO_VALUE => 1 } } + ]; + + $self->{maps_counters}->{memory} = [ + { label => 'memory-usage', nlabel => 'memory.usage.bytes', set => { + key_values => [ { name => 'used' }, { name => 'free' }, { name => 'prct_used' }, { name => 'prct_free' }, { name => 'total' }, { name => 'used_desc' }, { name => 'available' }, { name => 'prct_available' } ], + closure_custom_output => $self->can('custom_memory_output'), + perfdatas => [ + { template => '%d', min => 0, max => 'total', unit => 'B' } + ] + } + }, + { label => 'memory-usage-free', nlabel => 'memory.free.bytes', display_ok => 0, set => { + key_values => [ { name => 'free' }, { name => 'used' }, { name => 'prct_used' }, { name => 'prct_free' }, { name => 'total' }, { name => 'used_desc' }, { name => 'available' }, { name => 'prct_available' } ], + closure_custom_output => $self->can('custom_memory_output'), + perfdatas => [ + { template => '%d', min => 0, max => 'total', unit => 'B' } + ] + } + }, + { label => 'memory-usage-prct', nlabel => 'memory.usage.percentage', display_ok => 0, set => { + key_values => [ { name => 'prct_used' }, { name => 'used' }, { name => 'free' }, { name => 'prct_free' }, { name => 'total' }, { name => 'used_desc' }, { name => 'available' }, { name => 'prct_available' } ], + closure_custom_output => $self->can('custom_memory_output'), + perfdatas => [ + { template => '%.2f', min => 0, max => 100, unit => '%' } + ] + } + }, + { label => 'memory-available', nlabel => 'memory.available.bytes', display_ok => 0, set => { + key_values => [ { name => 'available' }, { name => 'used' }, { name => 'free' }, { name => 'prct_used' }, { name => 'prct_free' }, { name => 'total' }, { name => 'used_desc' }, { name => 'prct_available' } ], + closure_custom_output => $self->can('custom_memory_output'), + perfdatas => [ + { template => '%d', min => 0, max => 'total', unit => 'B' } + ] + } + }, + { label => 'memory-available-prct', nlabel => 'memory.available.percentage', display_ok => 0, set => { + key_values => [ { name => 'prct_available' }, { name => 'prct_used' }, { name => 'used' }, { name => 'free' }, { name => 'prct_free' }, { name => 'total' }, { name => 'used_desc' }, { name => 'available' } ], + closure_custom_output => $self->can('custom_memory_output'), + perfdatas => [ + { template => '%.2f', min => 0, max => 100, unit => '%' } + ] + } + }, + { label => 'buffer', nlabel => 'memory.buffer.bytes', set => { + key_values => [ { name => 'buffer' } ], + output_template => 'buffer: %s %s', + output_change_bytes => 1, + perfdatas => [ + { template => '%d', min => 0, unit => 'B' } + ] + } + }, + { label => 'shared', nlabel => 'memory.shared.bytes', set => { + key_values => [ { name => 'shared' } ], + output_template => 'shared: %s %s', + output_change_bytes => 1, + perfdatas => [ + { template => '%d', min => 0, unit => 'B' } + ] + } + } + ]; +} + +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; +} + +sub manage_selection { + my ($self, %options) = @_; + + my ($result) = $options{custom}->execute_scenario( + request => { + interactive => 1, + rows => 800, + cols => 80, + scenario => [ + { "cmd" => "waitfor", "options" => { "Match" => 'Main_Menu>', "Timeout" => "30" } }, + { "cmd" => "put", "options" => { "String" => "Monitor\n", "Timeout" => "5" } }, + { "cmd" => "waitfor", "options" => { "Match" => 'Monitor>', "Timeout" => "5" } }, + { "cmd" => "put", "options" => { "String" => "MemoryStatus\n", "Timeout" => "5" } }, + { "cmd" => "waitfor", "options" => { "Match" => 'Total:', "Timeout" => "10" } }, + { "cmd" => "close" } + ] + } + ); + + # total used free shared buff/cache available + #Mem: 262873544 122588148 3147172 142120 137138224 137563492 + #Swap: 66674684 14492760 52181924 + #Total: 329548228 137080908 55329096 + if ($result !~ /^.*?Mem\s*:\s*(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)/mi) { + $self->{output}->add_option_msg(short_msg => 'Some memory informations missing.'); + $self->{output}->option_exit(); + } + + my $total_size = $1 * 1024; + my $free = $3 * 1024; + my $used = $2 * 1024; + my $shared = $4 * 1024; + my $buffer_used = $5 * 1024; + my $available = $6 * 1024; + my $used_desc = 'buffers/cache'; + + $self->{memory} = { + total => $total_size, + used => $used, + free => $free, + prct_used => $used * 100 / $total_size, + prct_free => $free * 100 / $total_size, + used_desc => $used_desc, + available => $available, + prct_available => $available * 100 / $total_size, + buffer => $buffer_used, + shared => $shared + }; +} + +1; + +__END__ + +=head1 MODE + +Check memory + +=over 8 + +=item B<--warning-*> B<--critical-*> + +Thresholds. +Can be: 'memory-usage' (B), 'memory-usage-free' (B), 'memory-usage-prct' (%), +'memory-available' (B), 'memory-available-prct' (%), 'buffer' (B), 'shared' (B) . + +=back + +=cut \ No newline at end of file diff --git a/src/storage/veritas/nba/ssh/plugin.pm b/src/storage/veritas/nba/ssh/plugin.pm index 59f76389da..6298c9898f 100644 --- a/src/storage/veritas/nba/ssh/plugin.pm +++ b/src/storage/veritas/nba/ssh/plugin.pm @@ -30,7 +30,8 @@ sub new { bless $self, $class; $self->{modes} = { - 'hardware' => 'storage::veritas::nba::ssh::mode::hardware', + 'hardware' => 'storage::veritas::nba::ssh::mode::hardware', + 'memory' => 'storage::veritas::nba::ssh::mode::memory' }; $self->{custom_modes}->{ssh} = 'storage::veritas::nba::ssh::custom::cli'; From b23bf91474f1331a305befbe1229fe32baa20e9c Mon Sep 17 00:00:00 2001 From: garnier-quentin Date: Mon, 15 Jun 2026 09:57:49 -0400 Subject: [PATCH 06/12] wip --- .../veritas/nba/ssh/mode/liststorages.pm | 126 +++++++ src/storage/veritas/nba/ssh/mode/storage.pm | 316 ++++++++++++++++++ src/storage/veritas/nba/ssh/plugin.pm | 6 +- 3 files changed, 446 insertions(+), 2 deletions(-) create mode 100644 src/storage/veritas/nba/ssh/mode/liststorages.pm create mode 100644 src/storage/veritas/nba/ssh/mode/storage.pm diff --git a/src/storage/veritas/nba/ssh/mode/liststorages.pm b/src/storage/veritas/nba/ssh/mode/liststorages.pm new file mode 100644 index 0000000000..afed6bc95e --- /dev/null +++ b/src/storage/veritas/nba/ssh/mode/liststorages.pm @@ -0,0 +1,126 @@ +# +# 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 storage::veritas::nba::ssh::mode::liststorages; + +use base qw(centreon::plugins::mode); + +use strict; +use warnings; + +my @labels = ( + 'name', + 'status' +); + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $options{options}->add_options(arguments => {}); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::init(%options); +} + +sub manage_selection { + my ($self, %options) = @_; + + my ($result) = $options{custom}->execute_scenario( + request => { + interactive => 1, + rows => 800, + cols => 80, + scenario => [ + { "cmd" => "waitfor", "options" => { "Match" => 'Main_Menu>', "Timeout" => "30" } }, + { "cmd" => "put", "options" => { "String" => "Manage\n", "Timeout" => "5" } }, + { "cmd" => "waitfor", "options" => { "Match" => 'Manage>', "Timeout" => "5" } }, + { "cmd" => "put", "options" => { "String" => "Storage\n", "Timeout" => "5" } }, + { "cmd" => "waitfor", "options" => { "Match" => 'Storage>', "Timeout" => "5" } }, + { "cmd" => "put", "options" => { "String" => "Show ALL\n", "Timeout" => "5" } }, + { "cmd" => "waitfor", "options" => { "Match" => 'to quit|Waiting for data', "Timeout" => "20" } }, + { "cmd" => "close" } + ] + } + ); + + my $results = {}; + while ($result =~ /^(.*?)\|.*?\|.*?\|.*?\|.*?\|\s+(Optimal|Degraded|Not\s+Accessible|Not\s+Configured)/mig) { + my ($part_name, $part_status) = (centreon::plugins::misc::trim($1), $2); + $results->{ $part_name } = { + name => $part_name, + status => $part_status + }; + } + + return $results; +} + +sub run { + my ($self, %options) = @_; + + my $results = $self->manage_selection(custom => $options{custom}); + foreach my $instance (sort keys %$results) { + $self->{output}->output_add(long_msg => join('', map("[$_: " . $results->{$instance}->{$_} . ']', @labels))); + } + + $self->{output}->output_add( + severity => 'OK', + short_msg => 'List storages:' + ); + $self->{output}->display(nolabel => 1, force_ignore_perfdata => 1, force_long_output => 1); + $self->{output}->exit(); +} + +sub disco_format { + my ($self, %options) = @_; + + $self->{output}->add_disco_format(elements => [ @labels ]); +} + +sub disco_show { + my ($self, %options) = @_; + + my $results = $self->manage_selection(custom => $options{custom}); + foreach (sort keys %$results) { + $self->{output}->add_disco_entry( + %{$results->{$_}} + ); + } +} + +1; + +__END__ + +=head1 MODE + +List storages. + +=over 8 + +=back + +=cut \ No newline at end of file diff --git a/src/storage/veritas/nba/ssh/mode/storage.pm b/src/storage/veritas/nba/ssh/mode/storage.pm new file mode 100644 index 0000000000..e9d91c7e3a --- /dev/null +++ b/src/storage/veritas/nba/ssh/mode/storage.pm @@ -0,0 +1,316 @@ +# +# 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 storage::veritas::nba::ssh::mode::storage; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; +use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold_ng); +use centreon::plugins::constants qw(:counters); +use centreon::plugins::misc; + +sub custom_status_output { + my ($self, %options) = @_; + + return 'status: ' . $self->{result_values}->{status}; +} + +sub custom_space_usage_output { + my ($self, %options) = @_; + + my ($total_size_value, $total_size_unit) = $self->{perfdata}->change_bytes(value => + $self->{result_values}->{total}); + my ($total_used_value, $total_used_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{used}); + my ($total_free_value, $total_free_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{free}); + return sprintf( + 'space usage total: %s used: %s (%.2f%%) free: %s (%.2f%%)', + $total_size_value . " " . $total_size_unit, + $total_used_value . " " . $total_used_unit, $self->{result_values}->{prct_used}, + $total_free_value . " " . $total_free_unit, $self->{result_values}->{prct_free} + ); +} + +sub partition_long_output { + my ($self, %options) = @_; + + return sprintf( + "checking partition '%s'", + $options{instance_value}->{name} + ); +} + +sub prefix_storage_output { + my ($self, %options) = @_; + + return sprintf( + "partition '%s' ", + $options{instance_value}->{name} + ); +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { + name => 'partitions', + type => COUNTER_TYPE_MULTIPLE, + cb_prefix_output => 'prefix_partition_output', + cb_long_output => 'partition_long_output', + indent_long_output => ' ', + message_multiple => 'All partitions are ok', + group => + [ + { name => 'partition_status', type => COUNTER_MULTIPLE_INSTANCE }, + { name => 'partition_space', type => COUNTER_MULTIPLE_INSTANCE, skipped_code => { NO_VALUE => 1 } } + ] + } + ]; + + $self->{maps_counters}->{partition_space} = [ + { + label => 'partition-space-usage', nlabel => 'partition.space.usage.bytes', set => { + key_values => + [ + { name => 'used' }, + { name => 'free' }, + { name => 'prct_used' }, + { name => 'prct_free' }, + { name => 'total' } + ], + closure_custom_output => $self->can('custom_space_usage_output'), + perfdatas => + [ + { + template => '%d', + min => 0, + max => 'total', + unit => 'B', + cast_int => 1, + label_extra_instance => 1 + } + ] + } + }, + { + label => 'partition-space-usage-free', nlabel => 'partition.space.free.bytes', display_ok => 0, set => { + key_values => + [ + { name => 'free' }, + { name => 'used' }, + { name => 'prct_used' }, + { name => 'prct_free' }, + { name => 'total' } + ], + closure_custom_output => $self->can('custom_space_usage_output'), + perfdatas => + [ + { + template => '%d', + min => 0, + max => 'total', + unit => 'B', + cast_int => 1, + label_extra_instance => 1 + } + ] + } + }, + { + label => 'partition-space-usage-prct', nlabel => 'partition.space.usage.percentage', display_ok => 0, set => { + key_values => + [ + { name => 'prct_used' }, + { name => 'used' }, + { name => 'free' }, + { name => 'prct_free' }, + { name => 'total' } + ], + closure_custom_output => $self->can('custom_space_usage_output'), + perfdatas => + [ + { + template => '%.2f', min => 0, max => 100, unit => '%', label_extra_instance => 1 + } + ] + } + } + ]; + + $self->{maps_counters}->{partition_status} = [ + { + label => 'partition-status', type => COUNTER_KIND_TEXT, warning_default => '%{status} =~ /Degraded/i', critical_default => '%{status} =~ /Not Accessible/i', set => { + key_values => + [ + { name => 'status' }, + { name => 'partitionName' } + ], + 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-partition-name:s' => { name => 'include_partition_name', default => '' }, + 'exclude-partition-name:s' => { name => 'exclude_partition_name', default => '' } + }); + + return $self; +} + +sub manage_selection { + my ($self, %options) = @_; + + my ($result) = $options{custom}->execute_scenario( + request => { + interactive => 1, + rows => 800, + cols => 80, + scenario => [ + { "cmd" => "waitfor", "options" => { "Match" => 'Main_Menu>', "Timeout" => "30" } }, + { "cmd" => "put", "options" => { "String" => "Manage\n", "Timeout" => "5" } }, + { "cmd" => "waitfor", "options" => { "Match" => 'Manage>', "Timeout" => "5" } }, + { "cmd" => "put", "options" => { "String" => "Storage\n", "Timeout" => "5" } }, + { "cmd" => "waitfor", "options" => { "Match" => 'Storage>', "Timeout" => "5" } }, + { "cmd" => "put", "options" => { "String" => "Show ALL\n", "Timeout" => "5" } }, + { "cmd" => "waitfor", "options" => { "Match" => 'to quit|Waiting for data', "Timeout" => "20" } }, + { "cmd" => "close" } + ] + } + ); + + #------------------------------------------------------------------------------- + #Partition | Total | Available | Used | %Used | Status + #------------------------------------------------------------------------------- + #AdvancedDisk | 0 GB | 0 GB | 0 GB | 0 | Not Configured + #CDPGateway | 0 GB | 0 GB | 0 GB | 0 | Not Configured + #Configuration | 100 GB | 98.64 GB | 1.36 GB | 2 | Optimal + #MSDP | 251 TB | 80.49 TB | 170.51 TB | 68 | Optimal + #MSDP Catalog | 798 GB | 788.75 GB | 9.25 GB | 2 | Optimal + #NDMP Log | 750 GB | 634.58 GB | 115.42 GB | 16 | Optimal + #Share | 0 GB | 0 GB | 0 GB | 0 | Not Configured + #Unallocated | 18.44 TB | - | - | - | - + + while ($result =~ /^(.*?)\|.*?\|(.*?)\|(.*?)\|.*?\|\s+(Optimal|Degraded|Not\s+Accessible|Not\s+Configured)/mig) { + my ($part_name, $part_available, $part_used, $part_status) = (centreon::plugins::misc::trim($1), centreon::plugins::misc::trim($2), centreon::plugins::misc::trim($3), $4); + + next if (centreon::plugins::misc::is_excluded($part_name, $self->{option_results}->{include_partition_name}, $self->{option_results}->{exclude_partition_name})); + + $self->{partitions}->{$part_name} = { + name => $part_name, + partition_status => { + partitionName => $part_name, + status => $part_status + } + }; + + $part_used =~ /^(\S+)\s+(\S+)/; + my $part_used_bytes = centreon::plugins::misc::convert_bytes(value => $1, unit => $2); + $part_available =~ /^(\S+)\s+(\S+)/; + my $part_available_bytes = centreon::plugins::misc::convert_bytes(value => $1, unit => $2); + if (($part_used_bytes + $part_available_bytes) > 0) { + my $total = $part_used_bytes + $part_available_bytes; + $self->{partitions}->{$part_name}->{partition_space} = { + total => $total, + free => $part_available_bytes, + used => $part_used_bytes, + prct_used => ($part_used_bytes * 100) / $total, + prct_free => ($part_available_bytes * 100) / $total + }; + } + } + + if (scalar(keys %{$self->{partitions}}) <= 0) { + $self->{output}->add_option_msg(short_msg => "Couldn't get partition information"); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check storages. + +=over 8 + +=item B<--filter-counters> + +Define which counters (filtered by regular expression) should be monitored. +Can be : partition-space-usage partition-space-usage-free partition-space-usage-prct +Example: --filter-counters='partition-status' + +=item B<--include-partition-name> + +Include partition names (regexp). + +=item B<--exclude-partition-name> + +Exclude partition names (regexp). + +=item B<--warning-status> + +Define the conditions to match for the status to be WARNING (default: C<'%{status} =~ /Degraded/i'>). +You can use the following variables: C<%{status}>, C<%{partitionName}> + +=item B<--critical-status> + +Define the conditions to match for the status to be CRITICAL (default: C<'%{status} =~ /Not Accessible/i'>). +You can use the following variables: C<%{status}>, C<%{partitionName}> + +=item B<--warning-partition-space-usage> + +Warning threshold for partition space usage in bytes. + +=item B<--critical-partition-space-usage> + +Critical threshold for partition space usage in bytes. + +=item B<--warning-partition-space-usage-free> + +Warning threshold for partition free space usage in bytes. + +=item B<--critical-partition-space-usage-free> + +Critical threshold for partition free space usage in bytes. + +=item B<--warning-partition-space-usage-prct> + +Warning threshold for partition space usage in percent. + +=item B<--critical-partition-space-usage-prct> + +Critical threshold for partition space usage in percent. + +=back + +=cut diff --git a/src/storage/veritas/nba/ssh/plugin.pm b/src/storage/veritas/nba/ssh/plugin.pm index 6298c9898f..e48a148a78 100644 --- a/src/storage/veritas/nba/ssh/plugin.pm +++ b/src/storage/veritas/nba/ssh/plugin.pm @@ -30,8 +30,10 @@ sub new { bless $self, $class; $self->{modes} = { - 'hardware' => 'storage::veritas::nba::ssh::mode::hardware', - 'memory' => 'storage::veritas::nba::ssh::mode::memory' + 'hardware' => 'storage::veritas::nba::ssh::mode::hardware', + 'list-storages' => 'storage::veritas::nba::ssh::mode::liststorages', + 'memory' => 'storage::veritas::nba::ssh::mode::memory', + 'storage' => 'storage::veritas::nba::ssh::mode::storage' }; $self->{custom_modes}->{ssh} = 'storage::veritas::nba::ssh::custom::cli'; From 73475f54c041238b5be586247ab3ed8d406a9410 Mon Sep 17 00:00:00 2001 From: garnier-quentin Date: Mon, 15 Jun 2026 10:02:54 -0400 Subject: [PATCH 07/12] wip --- .../deb.json | 5 +++++ .../pkg.json | 11 +++++++++++ .../rpm.json | 5 +++++ 3 files changed, 21 insertions(+) create mode 100644 packaging/centreon-plugin-Hardware-Storage-Veritas-Nba-Ssh/deb.json create mode 100644 packaging/centreon-plugin-Hardware-Storage-Veritas-Nba-Ssh/pkg.json create mode 100644 packaging/centreon-plugin-Hardware-Storage-Veritas-Nba-Ssh/rpm.json diff --git a/packaging/centreon-plugin-Hardware-Storage-Veritas-Nba-Ssh/deb.json b/packaging/centreon-plugin-Hardware-Storage-Veritas-Nba-Ssh/deb.json new file mode 100644 index 0000000000..aa39449b2b --- /dev/null +++ b/packaging/centreon-plugin-Hardware-Storage-Veritas-Nba-Ssh/deb.json @@ -0,0 +1,5 @@ +{ + "dependencies": [ + "libssh-session-perl" + ] +} diff --git a/packaging/centreon-plugin-Hardware-Storage-Veritas-Nba-Ssh/pkg.json b/packaging/centreon-plugin-Hardware-Storage-Veritas-Nba-Ssh/pkg.json new file mode 100644 index 0000000000..ae67e827c3 --- /dev/null +++ b/packaging/centreon-plugin-Hardware-Storage-Veritas-Nba-Ssh/pkg.json @@ -0,0 +1,11 @@ +{ + "pkg_name": "centreon-plugin-Hardware-Storage-Veritas-Nba-Ssh", + "pkg_summary": "Centreon Plugin", + "plugin_name": "centreon_veritas_nba_ssh.pl", + "files": [ + "centreon/plugins/script_custom.pm", + "centreon/plugins/backend/ssh/", + "centreon/plugins/ssh.pm", + "storage/veritas/nba/ssh/" + ] +} diff --git a/packaging/centreon-plugin-Hardware-Storage-Veritas-Nba-Ssh/rpm.json b/packaging/centreon-plugin-Hardware-Storage-Veritas-Nba-Ssh/rpm.json new file mode 100644 index 0000000000..e8b0a6a432 --- /dev/null +++ b/packaging/centreon-plugin-Hardware-Storage-Veritas-Nba-Ssh/rpm.json @@ -0,0 +1,5 @@ +{ + "dependencies": [ + "perl(Libssh::Session)" + ] +} From f77187d8eec23d199ec09c176dcbbfacd6a291aa Mon Sep 17 00:00:00 2001 From: garnier-quentin Date: Mon, 15 Jun 2026 10:12:08 -0400 Subject: [PATCH 08/12] wip --- src/storage/veritas/nba/ssh/mode/hardware.pm | 6 ++++-- src/storage/veritas/nba/ssh/mode/liststorages.pm | 6 ++++-- src/storage/veritas/nba/ssh/mode/memory.pm | 6 ++++-- src/storage/veritas/nba/ssh/mode/storage.pm | 6 ++++-- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/storage/veritas/nba/ssh/mode/hardware.pm b/src/storage/veritas/nba/ssh/mode/hardware.pm index 8bb578544e..4c0f183e40 100644 --- a/src/storage/veritas/nba/ssh/mode/hardware.pm +++ b/src/storage/veritas/nba/ssh/mode/hardware.pm @@ -47,8 +47,10 @@ sub ssh_execute { ($self->{result}) = $options{custom}->execute_scenario( request => { interactive => 1, - rows => 800, - cols => 80, + pty => { + rows => 800, + cols => 80 + }, scenario => [ { "cmd" => "waitfor", "options" => { "Match" => 'Main_Menu>', "Timeout" => "20" } }, { "cmd" => "put", "options" => { "String" => "Monitor\n", "Timeout" => "5" } }, diff --git a/src/storage/veritas/nba/ssh/mode/liststorages.pm b/src/storage/veritas/nba/ssh/mode/liststorages.pm index afed6bc95e..46c444ead8 100644 --- a/src/storage/veritas/nba/ssh/mode/liststorages.pm +++ b/src/storage/veritas/nba/ssh/mode/liststorages.pm @@ -51,8 +51,10 @@ sub manage_selection { my ($result) = $options{custom}->execute_scenario( request => { interactive => 1, - rows => 800, - cols => 80, + pty => { + rows => 800, + cols => 80 + }, scenario => [ { "cmd" => "waitfor", "options" => { "Match" => 'Main_Menu>', "Timeout" => "30" } }, { "cmd" => "put", "options" => { "String" => "Manage\n", "Timeout" => "5" } }, diff --git a/src/storage/veritas/nba/ssh/mode/memory.pm b/src/storage/veritas/nba/ssh/mode/memory.pm index d702cfa7c4..1dbcb9240b 100644 --- a/src/storage/veritas/nba/ssh/mode/memory.pm +++ b/src/storage/veritas/nba/ssh/mode/memory.pm @@ -128,8 +128,10 @@ sub manage_selection { my ($result) = $options{custom}->execute_scenario( request => { interactive => 1, - rows => 800, - cols => 80, + pty => { + rows => 800, + cols => 80 + }, scenario => [ { "cmd" => "waitfor", "options" => { "Match" => 'Main_Menu>', "Timeout" => "30" } }, { "cmd" => "put", "options" => { "String" => "Monitor\n", "Timeout" => "5" } }, diff --git a/src/storage/veritas/nba/ssh/mode/storage.pm b/src/storage/veritas/nba/ssh/mode/storage.pm index e9d91c7e3a..5c109de9df 100644 --- a/src/storage/veritas/nba/ssh/mode/storage.pm +++ b/src/storage/veritas/nba/ssh/mode/storage.pm @@ -191,8 +191,10 @@ sub manage_selection { my ($result) = $options{custom}->execute_scenario( request => { interactive => 1, - rows => 800, - cols => 80, + pty => { + rows => 800, + cols => 80 + }, scenario => [ { "cmd" => "waitfor", "options" => { "Match" => 'Main_Menu>', "Timeout" => "30" } }, { "cmd" => "put", "options" => { "String" => "Manage\n", "Timeout" => "5" } }, From 22c922b486893ba4cfae42b4181ff817b2b0745f Mon Sep 17 00:00:00 2001 From: garnier-quentin Date: Mon, 15 Jun 2026 10:22:27 -0400 Subject: [PATCH 09/12] wip --- src/centreon/plugins/backend/ssh/libssh.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/centreon/plugins/backend/ssh/libssh.pm b/src/centreon/plugins/backend/ssh/libssh.pm index 2d85b6b581..56f44f3609 100644 --- a/src/centreon/plugins/backend/ssh/libssh.pm +++ b/src/centreon/plugins/backend/ssh/libssh.pm @@ -171,7 +171,7 @@ sub execute_scenario { $self->connect(hostname => $options{hostname}); - my $ret = $self->{ssh}->execute_scenario($options{request}); + my $ret = $self->{ssh}->execute_scenario(%{$options{request}}); $self->{output}->output_add(long_msg => $ret->{stdout}, debug => 1) if (defined($ret->{stdout})); $self->{output}->output_add(long_msg => $ret->{stderr}, debug => 1) if (defined($ret->{stderr})); From de25f45f744d80e46ca1b8a008b1e4fd18892b4f Mon Sep 17 00:00:00 2001 From: garnier-quentin Date: Thu, 18 Jun 2026 04:29:47 -0400 Subject: [PATCH 10/12] wip --- src/centreon/plugins/backend/ssh/libssh.pm | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/centreon/plugins/backend/ssh/libssh.pm b/src/centreon/plugins/backend/ssh/libssh.pm index 56f44f3609..a560d9f5bb 100644 --- a/src/centreon/plugins/backend/ssh/libssh.pm +++ b/src/centreon/plugins/backend/ssh/libssh.pm @@ -179,7 +179,7 @@ sub execute_scenario { my ($content, $exit_code); if ($ret->{exit} == $self->{constant_cb}->(name => 'SSH_OK')) { $content = $ret->{stdout}; - $exit_code = $ret->{exit_code}; + $exit_code = $ret->{exit}; } elsif ($ret->{exit} == $self->{constant_cb}->(name => 'SSH_AGAIN')) { # AGAIN means timeout $self->{output}->add_option_msg(short_msg => sprintf('command execution timeout')); $self->{output}->option_exit(); @@ -193,11 +193,6 @@ sub execute_scenario { $self->{output}->option_exit(); } - if ($exit_code != 0 && (!defined($options{no_quit}) || $options{no_quit} != 1)) { - $self->{output}->add_option_msg(short_msg => sprintf('command execution error [exit code: %s]', $exit_code)); - $self->{output}->option_exit(); - } - return ($content, $exit_code); } From 8e14a326ff6c274b9325925d8aa43327a7e41dd4 Mon Sep 17 00:00:00 2001 From: garnier-quentin Date: Mon, 20 Jul 2026 09:27:33 -0400 Subject: [PATCH 11/12] wip --- src/network/paloalto/api/mode/cpu.pm | 204 ------- src/network/paloalto/api/mode/interfaces.pm | 556 ------------------ .../paloalto/api/mode/listinterfaces.pm | 117 ---- src/network/paloalto/api/mode/memory.pm | 177 ------ src/network/paloalto/api/mode/sessions.pm | 206 ------- 5 files changed, 1260 deletions(-) delete mode 100644 src/network/paloalto/api/mode/cpu.pm delete mode 100644 src/network/paloalto/api/mode/interfaces.pm delete mode 100644 src/network/paloalto/api/mode/listinterfaces.pm delete mode 100644 src/network/paloalto/api/mode/memory.pm delete mode 100644 src/network/paloalto/api/mode/sessions.pm diff --git a/src/network/paloalto/api/mode/cpu.pm b/src/network/paloalto/api/mode/cpu.pm deleted file mode 100644 index 757a9240c4..0000000000 --- a/src/network/paloalto/api/mode/cpu.pm +++ /dev/null @@ -1,204 +0,0 @@ -# -# 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 network::paloalto::api::mode::cpu; - -use base qw(centreon::plugins::templates::counter); - -use strict; -use warnings; -use centreon::plugins::constants qw(:counters); -use centreon::plugins::misc qw(is_excluded); - -sub custom_perfdata { - my ($self, %options) = @_; - - $self->{output}->perfdata_add( - nlabel => $self->{nlabel}, - instances => ['dp' . $self->{result_values}->{dpNum}, 'cpu' . $self->{result_values}->{cpuNum}], - value => sprintf('%.2f', $self->{result_values}->{ $self->{key_values}->[0]->{name} }), - warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{thlabel}), - critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{thlabel}), - min => 0, - max => 100, - unit => '%' - ); -} - -sub prefix_cpu_core_output { - my ($self, %options) = @_; - - return "CPU '" . $options{instance_value}->{cpuNum} . "' "; -} - -sub long_dp_output { - my ($self, %options) = @_; - - return sprintf( - "checking data processor '%s'", - $options{instance_value}->{dpNum} - ); -} - -sub prefix_dp_output { - my ($self, %options) = @_; - - return sprintf( - "data processor '%s' ", - $options{instance_value}->{dpNum} - ); -} - -sub set_counters { - my ($self, %options) = @_; - - $self->{maps_counters_type} = [ - { name => 'dp', type => COUNTER_TYPE_MULTIPLE, cb_prefix_output => 'prefix_dp_output', cb_long_output => 'long_dp_output', - message_multiple => 'All data processors are ok', indent_long_output => ' ', - group => [ - { name => 'cpu_cores', display_long => 1, cb_prefix_output => 'prefix_cpu_core_output', message_multiple => 'All CPU cores are ok', type => COUNTER_MULTIPLE_SUBINSTANCE, sort_method => 'num' } - ] - } - ]; - - $self->{maps_counters}->{cpu_cores} = [ - { label => 'average-1m', nlabel => 'core.cpu.utilization.1m.percentage', set => { - key_values => [ { name => 'average_1m' }, { name => 'dpNum' }, { name => 'cpuNum' } ], - output_template => '%.2f %% (1m)', - closure_custom_perfdata => $self->can('custom_perfdata') - } - }, - { label => 'average-5m', nlabel => 'core.cpu.utilization.5m.percentage', set => { - key_values => [ { name => 'average_5m' }, { name => 'dpNum' }, { name => 'cpuNum' } ], - output_template => '%.2f %% (5m)', - closure_custom_perfdata => $self->can('custom_perfdata'), - } - }, - { label => 'average-15m', nlabel => 'core.cpu.utilization.15m.percentage', set => { - key_values => [ { name => 'average_15m' }, { name => 'dpNum' }, { name => 'cpuNum' } ], - output_template => '%.2f %% (15m)', - closure_custom_perfdata => $self->can('custom_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-dp-name:s' => { name => 'include_dp_name', default => '' }, - 'exclude-dp-name:s' => { name => 'exclude_dp_name', default => '' } - }); - - return $self; -} - -sub compute_cpu_average { - my ($self, %options) = @_; - - my $value = 0; - for (my $i = 0; $i < $options{sampling}; $i++) { - $value += $options{dataset}->[$i]; - } - - $value /= $options{sampling}; - - return $value; -} - -sub manage_selection { - my ($self, %options) = @_; - - my $result = $options{custom}->request_api( - type => 'op', - cmd => '', - ForceArray => ['entry'] - ); - - $self->{dp} = {}; - foreach my $dp (keys %{$result->{'resource-monitor'}->{'data-processors'}}) { - next if ($dp !~ /dp(\d+)/); - my $dp_num = $1; - - next if is_excluded($dp_num, $self->{option_results}->{include_dp_name}, $self->{option_results}->{exclude_dp_name}); - - $self->{dp}->{$dp_num} = { dpNum => $dp_num, cpu_cores => {} }; - - foreach my $core (@{$result->{'resource-monitor'}->{'data-processors'}->{$dp}->{minute}->{'cpu-load-average'}->{entry}}) { - my @datas = split(/,/, $core->{value}); - $self->{dp}->{$dp_num}->{cpu_cores}->{ $core->{coreid} } = { - dpNum => $dp_num, - cpuNum => $core->{coreid}, - average_1m => $self->compute_cpu_average(dataset => \@datas, sampling => 1), - average_5m => $self->compute_cpu_average(dataset => \@datas, sampling => 5), - average_15m => $self->compute_cpu_average(dataset => \@datas, sampling => 15) - }; - } - } -} - -1; - -__END__ - -=head1 MODE - -Check data processors. - -=over 8 - -=item B<--include-dp-name> - -Include data processor names (regexp). - -=item B<--exclude-dp-name> - -Exclude data processor names (regexp). - -=item B<--warning-average-1m> - -Warning threshold for data processor 1 minute average usage in percent. - -=item B<--critical-average-1m> - -Critical threshold for data processor 1 minute average usage in percent. - -=item B<--warning-average-5m> - -Warning threshold for data processor 5 minutes average usage in percent. - -=item B<--critical-average-5m> - -Critical threshold for data processor 5 minutes average usage in percent. - -=item B<--warning-average-15m> - -Warning threshold for data processor 15 minutes average usage in percent. - -=item B<--critical-average-15m> - -Critical threshold for data processor 15 minutes average usage in percent. - -=back - -=cut diff --git a/src/network/paloalto/api/mode/interfaces.pm b/src/network/paloalto/api/mode/interfaces.pm deleted file mode 100644 index b4c72aa5c4..0000000000 --- a/src/network/paloalto/api/mode/interfaces.pm +++ /dev/null @@ -1,556 +0,0 @@ -# -# 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 network::paloalto::api::mode::interfaces; - -use base qw(centreon::plugins::templates::counter); - -use strict; -use warnings; -use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold_ng); -use Digest::MD5 qw(md5_hex); -use centreon::plugins::constants qw(:counters); -use centreon::plugins::misc qw(is_excluded); - - -sub custom_status_output { - my ($self, %options) = @_; - - return 'state: ' . $self->{result_values}->{state}; -} - -sub custom_traffic_perfdata { - my ($self, %options) = @_; - - my ($warning, $critical); - if ($self->{instance_mode}->{option_results}->{units_traffic} eq 'percent_delta' && defined($self->{result_values}->{speed})) { - $warning = $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{thlabel}, total => $self->{result_values}->{speed}, cast_int => 1); - $critical = $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{thlabel}, total => $self->{result_values}->{speed}, cast_int => 1); - } elsif ($self->{instance_mode}->{option_results}->{units_traffic} =~ /bps|counter/) { - $warning = $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{thlabel}); - $critical = $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{thlabel}); - } - - if ($self->{instance_mode}->{option_results}->{units_traffic} eq 'counter') { - my $nlabel = $self->{nlabel}; - $nlabel =~ s/bitspersecond/bits/; - $self->{output}->perfdata_add( - nlabel => $nlabel, - unit => 'b', - instances => $self->{result_values}->{display}, - value => $self->{result_values}->{traffic_counter}, - warning => $warning, - critical => $critical, - min => 0 - ); - } else { - $self->{output}->perfdata_add( - nlabel => $self->{nlabel}, - instances => $self->use_instances(extra_instance => $options{extra_instance}) ? $self->{result_values}->{display} : undef, - value => sprintf('%d', $self->{result_values}->{traffic_per_seconds}), - warning => $warning, - critical => $critical, - min => 0, max => $self->{result_values}->{speed} - ); - } -} - -sub custom_traffic_threshold { - my ($self, %options) = @_; - - my $exit = 'ok'; - if ($self->{instance_mode}->{option_results}->{units_traffic} eq 'percent_delta' && defined($self->{result_values}->{speed})) { - $exit = $self->{perfdata}->threshold_check(value => - $self->{result_values}->{traffic_prct}, - threshold => - [ { label => 'critical-' . $self->{thlabel}, exit_litteral => 'critical' }, - { label => 'warning-' . $self->{thlabel}, exit_litteral => 'warning' } ]); - } elsif ($self->{instance_mode}->{option_results}->{units_traffic} eq 'bps') { - $exit = $self->{perfdata}->threshold_check(value => - $self->{result_values}->{traffic_per_seconds}, - threshold => - [ { label => 'critical-' . $self->{thlabel}, exit_litteral => 'critical' }, - { label => 'warning-' . $self->{thlabel}, exit_litteral => 'warning' } ]); - } elsif ($self->{instance_mode}->{option_results}->{units_traffic} eq 'counter') { - $exit = $self->{perfdata}->threshold_check(value => - $self->{result_values}->{traffic_counter}, - threshold => - [ { label => 'critical-' . $self->{thlabel}, exit_litteral => 'critical' }, - { label => 'warning-' . $self->{thlabel}, exit_litteral => 'warning' } ]); - } - return $exit; -} - -sub custom_traffic_output { - my ($self, %options) = @_; - - my ($traffic_value, $traffic_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{traffic_per_seconds}, network => 1); - return sprintf( - 'traffic %s: %s/s (%s)', - $self->{result_values}->{label}, $traffic_value . $traffic_unit, - defined($self->{result_values}->{traffic_prct}) ? sprintf('%.2f%%', $self->{result_values}->{traffic_prct}) : '-' - ); -} -sub custom_traffic_calc { - my ($self, %options) = @_; - - $self->{result_values}->{traffic_per_seconds} = ($options{new_datas}->{$self->{instance} . '_' . $options{extra_options}->{label_ref}} - - $options{old_datas}->{$self->{instance} . '_' . $options{extra_options}{label_ref}}) - / $options{delta_time}; - $self->{result_values}->{traffic_counter} = $options{new_datas}->{ $self->{instance} . '_' . $options{extra_options}->{label_ref} }; - - $self->{result_values}->{traffic_per_seconds} = sprintf('%d', $self->{result_values}->{traffic_per_seconds}); - - if (defined($options{new_datas}->{$self->{instance} . '_speed_' . $options{extra_options}->{label_ref}}) && - $options{new_datas}->{$self->{instance} . '_speed_' . $options{extra_options}->{label_ref}} ne '' && - $options{new_datas}->{$self->{instance} . '_speed_' . $options{extra_options}->{label_ref}} > 0) { - $self->{result_values}->{traffic_prct} = $self->{result_values}->{traffic_per_seconds} * 100 / $options{new_datas}->{$self->{instance} . '_speed_' . $options{extra_options}->{label_ref}}; - $self->{result_values}->{speed} = $options{new_datas}->{$self->{instance} . '_speed_' . $options{extra_options}->{label_ref}}; - } - - $self->{result_values}->{label} = $options{extra_options}->{label_ref}; - $self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_display'}; - return 0; -} - -sub custom_errors_perfdata { - my ($self, %options) = @_; - - if ($self->{instance_mode}->{option_results}->{units_errors} =~ /percent/) { - my $nlabel = $self->{nlabel}; - $nlabel =~ s/count$/percentage/; - - $self->{output}->perfdata_add( - nlabel => $nlabel, - unit => '%', - instances => $self->use_instances(extra_instance => $options{extra_instance}) ? $self->{result_values}->{display} : undef, - value => sprintf('%.2f', $self->{result_values}->{prct}), - warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{thlabel}), - critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{thlabel}), - min => 0, - max => 100 - ); - } else { - $self->{output}->perfdata_add( - nlabel => $self->{nlabel}, - instances => $self->use_instances(extra_instance => $options{extra_instance}) ? $self->{result_values}->{display} : undef, - value => $self->{result_values}->{used}, - warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{thlabel}), - critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{thlabel}), - min => 0, - max => $self->{result_values}->{total} - ); - } -} - -sub custom_errors_threshold { - my ($self, %options) = @_; - - my $exit = 'ok'; - if ($self->{instance_mode}->{option_results}->{units_errors} =~ /percent/) { - $exit = $self->{perfdata}->threshold_check( - value => $self->{result_values}->{prct}, - threshold => [ - { label => 'critical-' . $self->{thlabel}, exit_litteral => 'critical' }, - { label => 'warning-' . $self->{thlabel}, exit_litteral => 'warning' } - ] - ); - } else { - $exit = $self->{perfdata}->threshold_check( - value => $self->{result_values}->{used}, - threshold => [ - { label => 'critical-' . $self->{thlabel}, exit_litteral => 'critical' }, - { label => 'warning-' . $self->{thlabel}, exit_litteral => 'warning' } - ] - ); - } - - return $exit; -} - -sub custom_errors_output { - my ($self, %options) = @_; - - return sprintf( - '%s: %.2f%% (%s on %s)', - $self->{result_values}->{label}, - $self->{result_values}->{prct}, - $self->{result_values}->{used}, - $self->{result_values}->{total} - ); -} - -sub custom_errors_calc { - my ($self, %options) = @_; - - my $errors = $options{new_datas}->{ $self->{instance} . '_' . $options{extra_options}->{label_ref1} . $options{extra_options}->{label_ref2} }; - my $errors_diff = $options{new_datas}->{ $self->{instance} . '_' . $options{extra_options}->{label_ref1} . $options{extra_options}->{label_ref2} } - - $options{old_datas}->{ $self->{instance} . '_' . $options{extra_options}->{label_ref1} . $options{extra_options}->{label_ref2} }; - my $total = $options{new_datas}->{$self->{instance} . '_total_' . $options{extra_options}->{label_ref1} . '_packets'}; - my $total_diff = $options{new_datas}->{$self->{instance} . '_total_' . $options{extra_options}->{label_ref1} . '_packets'} - - $options{old_datas}->{$self->{instance} . '_total_' . $options{extra_options}->{label_ref1} . '_packets'}; - - $errors_diff = sprintf('%d', $errors_diff); - $total_diff = sprintf('%d', $total_diff); - $self->{result_values}->{prct} = 0; - $self->{result_values}->{used} = $errors_diff; - $self->{result_values}->{total} = $total_diff; - if ($self->{instance_mode}->{option_results}->{units_errors} eq 'percent_delta') { - $self->{result_values}->{prct} = $errors_diff * 100 / $total_diff if ($total_diff > 0); - } elsif ($self->{instance_mode}->{option_results}->{units_errors} eq 'percent') { - $self->{result_values}->{prct} = $errors * 100 / $total if ($total > 0); - $self->{result_values}->{used} = $errors; - $self->{result_values}->{total} = $total; - } elsif ($self->{instance_mode}->{option_results}->{units_errors} eq 'delta') { - $self->{result_values}->{prct} = $errors_diff * 100 / $total_diff if ($total_diff > 0); - $self->{result_values}->{used} = $errors_diff; - } else { - $self->{result_values}->{prct} = $errors * 100 / $total if ($total > 0); - $self->{result_values}->{used} = $errors; - $self->{result_values}->{total} = $total; - } - - if (defined($options{extra_options}->{label})) { - $self->{result_values}->{label} = $options{extra_options}->{label}; - } else { - $self->{result_values}->{label} = $options{extra_options}->{label_ref2}; - } - - $self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_display'}; - return 0; -} - -sub prefix_interface_output { - my ($self, %options) = @_; - - return "Interface '" . $options{instance_value}->{display} . "' "; -} - -sub interface_long_output { - my ($self, %options) = @_; - - return sprintf( - "checking interface '%s'", - $options{instance_value}->{display} - ); -} - -sub prefix_packets_in_output { - my ($self, %options) = @_; - - return 'packets in '; -} - -sub set_counters { - my ($self, %options) = @_; - - $self->{maps_counters_type} = [ - { name => 'interfaces', type => COUNTER_TYPE_MULTIPLE, cb_prefix_output => 'prefix_interface_output', cb_long_output => 'interface_long_output', - indent_long_output => ' ', message_multiple => 'All interfaces are ok', - group => [ - { name => 'status', type => COUNTER_MULTIPLE_INSTANCE, skipped_code => { NO_VALUE => 1 } }, - { name => 'traffic', type => COUNTER_MULTIPLE_INSTANCE, skipped_code => { NO_VALUE => 1 } }, - { name => 'packets_in', type => COUNTER_MULTIPLE_INSTANCE, cb_prefix_output => 'prefix_packets_in_output', skipped_code => { NO_VALUE => 1 } } - ] - } - ]; - - $self->{maps_counters}->{status} = [ - { - label => 'status', - type => COUNTER_KIND_TEXT, - critical_default => '%{state} !~ /up|N\/A/', - set => { - key_values => [ { name => 'state' }, { name => 'display' } ], - closure_custom_output => $self->can('custom_status_output'), - closure_custom_perfdata => sub { return 0; }, - closure_custom_threshold_check => \&catalog_status_threshold_ng - } - } - ]; - - $self->{maps_counters}->{traffic} = [ - { label => 'in-traffic', nlabel => 'interface.traffic.in.bitspersecond', set => { - key_values => [ { name => 'in', diff => 1 }, { name => 'speed_in' }, { name => 'display' } ], - closure_custom_calc => $self->can('custom_traffic_calc'), closure_custom_calc_extra_options => { label_ref => 'in' }, - closure_custom_output => $self->can('custom_traffic_output'), output_error_template => 'traffic in: %s', - closure_custom_perfdata => $self->can('custom_traffic_perfdata'), - closure_custom_threshold_check => $self->can('custom_traffic_threshold') - } - }, - { label => 'out-traffic', nlabel => 'interface.traffic.out.bitspersecond', set => { - key_values => [ { name => 'out', diff => 1 }, { name => 'speed_out' }, { name => 'display' } ], - closure_custom_calc => $self->can('custom_traffic_calc'), closure_custom_calc_extra_options => { label_ref => 'out' }, - closure_custom_output => $self->can('custom_traffic_output'), output_error_template => 'traffic out: %s', - closure_custom_perfdata => $self->can('custom_traffic_perfdata'), - closure_custom_threshold_check => $self->can('custom_traffic_threshold') - } - } - ]; - - $self->{maps_counters}->{packets_in} = [ - { label => 'in-error', nlabel => 'interface.packets.in.error.count', set => { - key_values => [ { name => 'inerror', diff => 1 }, { name => 'total_in_packets', diff => 1 }, { name => 'display' } ], - closure_custom_calc => $self->can('custom_errors_calc'), closure_custom_calc_extra_options => { label_ref1 => 'in', label_ref2 => 'error' }, - closure_custom_output => $self->can('custom_errors_output'), output_error_template => 'error: %s', - closure_custom_perfdata => $self->can('custom_errors_perfdata'), - closure_custom_threshold_check => $self->can('custom_errors_threshold') - } - }, - { label => 'in-drop', nlabel => 'interface.packets.in.drop.count', set => { - key_values => [ { name => 'indrop', diff => 1 }, { name => 'total_in_packets', diff => 1 }, { name => 'display' } ], - closure_custom_calc => $self->can('custom_errors_calc'), - closure_custom_calc_extra_options => { label_ref1 => 'in', label_ref2 => 'drop' }, - closure_custom_output => $self->can('custom_errors_output'), output_error_template => 'drop: %s', - closure_custom_perfdata => $self->can('custom_errors_perfdata'), - closure_custom_threshold_check => $self->can('custom_errors_threshold') - } - } - ]; -} - -sub new { - my ($class, %options) = @_; - my $self = $class->SUPER::new(package => __PACKAGE__, %options, statefile => 1, force_new_perfdata => 1); - bless $self, $class; - - $options{options}->add_options(arguments => { - 'include-interface-name:s' => { name => 'include_interface_name', default => '' }, - 'exclude-interface-name:s' => { name => 'exclude_interface_name', default => '' }, - 'add-status' => { name => 'add_status' }, - 'add-traffic' => { name => 'add_traffic' }, - 'add-errors' => { name => 'add_errors' }, - 'units-traffic:s' => { name => 'units_traffic', default => 'percent_delta' }, - 'units-errors:s' => { name => 'units_errors', default => 'percent_delta' }, - 'speed:s' => { name => 'speed' } - }); - - return $self; -} - -sub check_options { - my ($self, %options) = @_; - $self->SUPER::check_options(%options); - - # If no options, we set add-status - if (!defined($self->{option_results}->{add_traffic}) && - !defined($self->{option_results}->{add_errors}) && - !defined($self->{option_results}->{add_status})) { - $self->{option_results}->{add_status} = 1; - } - - if (defined($self->{option_results}->{speed}) && $self->{option_results}->{speed} ne '') { - if ($self->{option_results}->{speed} !~ /^[0-9]+(\.[0-9]+){0,1}$/) { - $self->{output}->add_option_msg(short_msg => "Speed must be a positive number '" . $self->{option_results}->{speed} . "' (can be a float also)."); - $self->{output}->option_exit(); - } else { - $self->{option_results}->{speed} *= 1000000; - } - } - - if (defined($self->{option_results}->{add_traffic})) { - $self->{option_results}->{units_traffic} = 'percent_delta' - if (!defined($self->{option_results}->{units_traffic}) || - $self->{option_results}->{units_traffic} eq '' || - $self->{option_results}->{units_traffic} eq '%'); - if ($self->{option_results}->{units_traffic} !~ /^(?:percent|percent_delta|bps|counter)$/) { - $self->{output}->add_option_msg(short_msg => 'Wrong option --units-traffic.'); - $self->{output}->option_exit(); - } - } - - if (defined($self->{option_results}->{add_errors})) { - $self->{option_results}->{units_errors} = 'percent_delta' - if (!defined($self->{option_results}->{units_errors}) || - $self->{option_results}->{units_errors} eq '' || - $self->{option_results}->{units_errors} eq '%'); - if ($self->{option_results}->{units_errors} !~ /^(?:percent|percent_delta|delta|counter)$/) { - $self->{output}->add_option_msg(short_msg => 'Wrong option --units-errors.'); - $self->{output}->option_exit(); - } - } - - $self->{checking} = ''; - foreach ('add_status', 'add_errors', 'add_traffic') { - if (defined($self->{option_results}->{$_})) { - $self->{checking} .= $_; - } - } -} - -sub manage_selection { - my ($self, %options) = @_; - - my $result = $options{custom}->request_api( - type => 'op', - cmd => 'all', - ForceArray => ['entry'] - ); - - foreach my $interface ((@{$result->{hw}->{entry}}, @{$result->{ifnet}->{entry}})) { - next if is_excluded($interface->{name}, $self->{option_results}->{include_interface_name}, $self->{option_results}->{exclude_inteface_name}); - - my $speed_in = defined($interface->{speed}) && $interface->{speed} =~ /^([0-9]+)$/ ? $interface->{speed} * 1000000 : ''; - my $speed_out = defined($interface->{speed}) && $interface->{speed} =~ /^([0-9]+)$/ ? $interface->{speed} * 1000000 : ''; - - $self->{interfaces}->{ $interface->{name} } = { display => $interface->{name} }; - - if (defined($self->{option_results}->{add_status})) { - $self->{interfaces}->{ $interface->{name} }->{status} = { - display => $interface->{name}, - state => defined($interface->{state}) ? $interface->{state} : 'N/A', - }; - } - if (defined($self->{option_results}->{add_traffic})) { - $self->{interfaces}->{ $interface->{name} }->{traffic} = { - display => $interface->{name}, - speed_in => defined($self->{option_results}->{speed}) ? $self->{option_results}->{speed} : $speed_in, - speed_out => defined($self->{option_results}->{speed}) ? $self->{option_results}->{speed} : $speed_out - } - } - if (defined($self->{option_results}->{add_errors})) { - $self->{interfaces}->{ $interface->{name} }->{packets_in} = { - display => $interface->{name} - }; - }; - } - - if (scalar(keys %{$self->{interfaces}}) <= 0) { - $self->{output}->add_option_msg(short_msg => "No interface found."); - $self->{output}->option_exit(); - } - - $result = $options{custom}->request_api( - type => 'op', - cmd => 'all', - ForceArray => ['entry'] - ); - - foreach my $interface ((@{$result->{hw}->{entry}}, @{$result->{ifnet}->{ifnet}->{entry}})) { - next if (!defined($self->{interfaces}->{ $interface->{name} })); - - if (defined($self->{option_results}->{add_traffic})) { - $self->{interfaces}->{ $interface->{name} }->{traffic}->{in} = $interface->{ibytes}; - $self->{interfaces}->{ $interface->{name} }->{traffic}->{out} = $interface->{obytes}; - } - - if (defined($self->{option_results}->{add_errors})) { - $self->{interfaces}->{ $interface->{name} }->{packets_in}->{total_in_packets} = $interface->{ipackets}; - $self->{interfaces}->{ $interface->{name} }->{packets_in}->{inerror} = $interface->{ierrors}; - $self->{interfaces}->{ $interface->{name} }->{packets_in}->{indrop} = $interface->{idrops}; - } - } - - $self->{cache_name} = 'paloalto_' . $options{custom}->get_hostname() . '_' . $options{custom}->get_port() . $self->{mode} . '_' . - md5_hex( - (defined($self->{option_results}->{filter_counters}) ? $self->{option_results}->{filter_counters} : '') . '_' . - (defined($self->{option_results}->{include_interface_name}) ? $self->{option_results}->{include_interface_name} : '') . '_' . - (defined($self->{option_results}->{exclude_interface_name}) ? $self->{option_results}->{exclude_interface_name} : '') . '_' . - $self->{checking} - ); -} - -1; - -__END__ - -=head1 MODE - -Check interfaces. - -=over 8 - -=item B<--include-interface-name> - -Include interface names (regexp). - -=item B<--exclude-interface-name> - -Exclude interface names (regexp). - -=item B<--add-status> - -Check interface status. - -=item B<--add-traffic> - -Check interface traffic. - -=item B<--add-errors> - -Check interface errors. - -=item B<--warning-status> - -Define the conditions to match for the status to be WARNING. -You can use the following variables: C<%{state}>, C<%{display}> - -=item B<--critical-status> - -Define the conditions to match for the status to be CRITICAL (default: C<'%{state} !~ /up|N\/A/'>). -You can use the following variables: C<%{state}>, C<%{display}> - -=item B<--warning-in-drop> - -Threshold. - -=item B<--critical-in-drop> - -Threshold. - -=item B<--warning-in-error> - -Threshold. - -=item B<--critical-in-error> - -Threshold. - -=item B<--warning-in-traffic> - -Threshold. - -=item B<--critical-in-traffic> - -Threshold. - -=item B<--warning-out-traffic> - -Threshold. - -=item B<--critical-out-traffic> - -Threshold. - -=item B<--units-traffic> - -Units of thresholds for the traffic (default: C) (C, C, C). - -=item B<--units-errors> - -Units of thresholds for errors/discards (default: C) (C, C, C, C). - -=item B<--speed> - -Set interface speed (in Mb). - -=back - -=cut diff --git a/src/network/paloalto/api/mode/listinterfaces.pm b/src/network/paloalto/api/mode/listinterfaces.pm deleted file mode 100644 index 3e2785841e..0000000000 --- a/src/network/paloalto/api/mode/listinterfaces.pm +++ /dev/null @@ -1,117 +0,0 @@ -# -# 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 network::paloalto::api::mode::listinterfaces; - -use base qw(centreon::plugins::mode); - -use strict; -use warnings; - -my @labels = ( - 'name', - 'state', - 'speed' -); - -sub new { - my ($class, %options) = @_; - my $self = $class->SUPER::new(package => __PACKAGE__, %options); - bless $self, $class; - - $options{options}->add_options(arguments => {}); - - return $self; -} - -sub check_options { - my ($self, %options) = @_; - $self->SUPER::init(%options); -} - -sub manage_selection { - my ($self, %options) = @_; - - my $result = $options{custom}->request_api( - type => 'op', - cmd => 'all', - ForceArray => ['entry'] - ); - - my $results = {}; - foreach my $interface ((@{$result->{hw}->{entry}}, @{$result->{ifnet}->{entry}})) { - $results->{ $interface->{name} } = { - name => $interface->{name}, - state => defined($interface->{state}) ? $interface->{state} : 'N/A', - speed => defined($interface->{speed}) ? $interface->{speed} : '' - }; - } - - return $results; -} - -sub run { - my ($self, %options) = @_; - - my $results = $self->manage_selection(custom => $options{custom}); - foreach my $instance (sort keys %$results) { - $self->{output}->output_add(long_msg => - join('', map("[$_: " . $results->{$instance}->{$_} . ']', @labels)) - ); - } - - $self->{output}->output_add( - severity => 'OK', - short_msg => 'List interfaces:' - ); - $self->{output}->display(nolabel => 1, force_ignore_perfdata => 1, force_long_output => 1); - $self->{output}->exit(); -} - -sub disco_format { - my ($self, %options) = @_; - - $self->{output}->add_disco_format(elements => [ @labels ]); -} - -sub disco_show { - my ($self, %options) = @_; - - my $results = $self->manage_selection(custom => $options{custom}); - foreach (sort keys %$results) { - $self->{output}->add_disco_entry( - %{$results->{$_}} - ); - } -} - -1; - -__END__ - -=head1 MODE - -List interfaces. - -=over 8 - -=back - -=cut diff --git a/src/network/paloalto/api/mode/memory.pm b/src/network/paloalto/api/mode/memory.pm deleted file mode 100644 index 2e2cf7789a..0000000000 --- a/src/network/paloalto/api/mode/memory.pm +++ /dev/null @@ -1,177 +0,0 @@ -# -# 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 network::paloalto::api::mode::memory; - -use base qw(centreon::plugins::templates::counter); - -use strict; -use warnings; -use centreon::plugins::constants qw(:counters); - -sub custom_memory_output { - my ($self, %options) = @_; - - return sprintf( - 'Ram total: %s %s used (-%s): %s %s (%.2f%%) free: %s %s (%.2f%%) available: %s %s (%.2f%%)', - $self->{perfdata}->change_bytes(value => $self->{result_values}->{total}), - $self->{result_values}->{used_desc}, - $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}, - $self->{perfdata}->change_bytes(value => $self->{result_values}->{available}), - $self->{result_values}->{prct_available}, - - ); -} - -sub set_counters { - my ($self, %options) = @_; - - $self->{maps_counters_type} = [ - { name => 'memory', type => COUNTER_TYPE_GLOBAL, skipped_code => { NO_VALUE => 1 } } - ]; - - $self->{maps_counters}->{memory} = [ - { label => 'memory-usage', nlabel => 'memory.usage.bytes', set => { - key_values => [ { name => 'used' }, { name => 'free' }, { name => 'prct_used' }, { name => 'prct_free' }, { name => 'total' }, { name => 'used_desc' }, { name => 'available' }, { name => 'prct_available' } ], - closure_custom_output => $self->can('custom_memory_output'), - perfdatas => [ - { template => '%d', min => 0, max => 'total', unit => 'B' } - ] - } - }, - { label => 'memory-usage-free', nlabel => 'memory.free.bytes', display_ok => 0, set => { - key_values => [ { name => 'free' }, { name => 'used' }, { name => 'prct_used' }, { name => 'prct_free' }, { name => 'total' }, { name => 'used_desc' }, { name => 'available' }, { name => 'prct_available' } ], - closure_custom_output => $self->can('custom_memory_output'), - perfdatas => [ - { template => '%d', min => 0, max => 'total', unit => 'B' } - ] - } - }, - { label => 'memory-usage-prct', nlabel => 'memory.usage.percentage', display_ok => 0, set => { - key_values => [ { name => 'prct_used' }, { name => 'used' }, { name => 'free' }, { name => 'prct_free' }, { name => 'total' }, { name => 'used_desc' }, { name => 'available' }, { name => 'prct_available' } ], - closure_custom_output => $self->can('custom_memory_output'), - perfdatas => [ - { template => '%.2f', min => 0, max => 100, unit => '%' } - ] - } - }, - { label => 'memory-available', nlabel => 'memory.available.bytes', display_ok => 0, set => { - key_values => [ { name => 'available' }, { name => 'used' }, { name => 'free' }, { name => 'prct_used' }, { name => 'prct_free' }, { name => 'total' }, { name => 'used_desc' }, { name => 'prct_available' } ], - closure_custom_output => $self->can('custom_memory_output'), - perfdatas => [ - { template => '%d', min => 0, max => 'total', unit => 'B' } - ] - } - }, - { label => 'memory-available-prct', nlabel => 'memory.available.percentage', display_ok => 0, set => { - key_values => [ { name => 'prct_available' }, { name => 'prct_used' }, { name => 'used' }, { name => 'free' }, { name => 'prct_free' }, { name => 'total' }, { name => 'used_desc' }, { name => 'available' } ], - closure_custom_output => $self->can('custom_memory_output'), - perfdatas => [ - { template => '%.2f', min => 0, max => 100, unit => '%' } - ] - } - }, - { label => 'buffer', nlabel => 'memory.buffer.bytes', set => { - key_values => [ { name => 'buffer' } ], - output_template => 'buffer: %s %s', - output_change_bytes => 1, - perfdatas => [ - { template => '%d', min => 0, unit => 'B' } - ] - } - } - ]; -} - -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; -} - -sub manage_selection { - my ($self, %options) = @_; - - my $result = $options{custom}->request_api( - type => 'op', - cmd => '', - ForceArray => ['entry'] - ); - - # MiB Mem : 31855.8 total, 2491.6 free, 15135.1 used, 22848.1 buff/cache - # MiB Swap: 2.0 total, 1.9 free, 0.1 used. 16720.7 avail Mem - if ($result !~ /^.*?Mem\s*:\s*(\S+)\s+total\s*,\s*(\S+)\s+free\s*,\s*(\S+)\s+used\s*,\s*(\S+)\s+buff\/cache/mi) { - $self->{output}->add_option_msg(short_msg => 'Some memory informations missing.'); - $self->{output}->option_exit(); - } - - my $total_size = $1 * 1024 * 1024; - my $free = $2 * 1024 * 1024; - my $used = $3 * 1024 * 1024; - my $buffer_used = $4 * 1024 * 1024; - - if ($result !~ /^.*?Swap\s*:\s*(\S+)\s+total\s*,\s*(\S+)\s+free\s*,\s*(\S+)\s+used\s*.\s*(\S+)\s+avail\s+Mem/mi) { - $self->{output}->add_option_msg(short_msg => 'Some memory informations missing.'); - $self->{output}->option_exit(); - } - - my $available = $4 * 1024 * 1024; - my $used_desc = 'buffers/cache'; - - $self->{memory} = { - total => $total_size, - used => $used, - free => $free, - prct_used => $used * 100 / $total_size, - prct_free => $free * 100 / $total_size, - used_desc => $used_desc, - available => $available, - prct_available => $available * 100 / $total_size, - buffer => $buffer_used - }; -} - -1; - -__END__ - -=head1 MODE - -Check memory - -=over 8 - -=item B<--warning-*> B<--critical-*> - -Thresholds. -Can be: 'memory-usage' (B), 'memory-usage-free' (B), 'memory-usage-prct' (%), -'memory-available' (B), 'memory-available-prct' (%), 'buffer' (B). - -=back - -=cut - diff --git a/src/network/paloalto/api/mode/sessions.pm b/src/network/paloalto/api/mode/sessions.pm deleted file mode 100644 index 764b9e22d0..0000000000 --- a/src/network/paloalto/api/mode/sessions.pm +++ /dev/null @@ -1,206 +0,0 @@ -# -# 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 network::paloalto::api::mode::sessions; - -use base qw(centreon::plugins::templates::counter); - -use strict; -use warnings; -use centreon::plugins::constants qw(:counters); - -sub custom_vsys_active_perfdata { - my ($self, %options) = @_; - - $self->{output}->perfdata_add( - label => $self->{label}, - nlabel => $self->{nlabel}, - instances => $self->use_instances(extra_instance => $options{extra_instance}) ? $self->{result_values}->{display} : undef, - value => $self->{result_values}->{sessions_active}, - warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{thlabel}), - critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{thlabel}), - min => 0, - max => $self->{result_values}->{sessions_max} != 0 ? $self->{result_values}->{sessions_max} : undef - ); -} - -sub custom_active_perfdata { - my ($self, %options) = @_; - - $self->{output}->perfdata_add( - label => $self->{label}, - nlabel => $self->{nlabel}, - value => $self->{result_values}->{sessions_active}, - warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{thlabel}), - critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{thlabel}), - min => 0, - max => $self->{result_values}->{sessions_max} != 0 ? $self->{result_values}->{sessions_max} : undef - ); -} - -sub custom_active_output { - my ($self, %options) = @_; - - return sprintf('active: %s (%s)', - $self->{result_values}->{sessions_active}, - $self->{result_values}->{sessions_max} != 0 ? $self->{result_values}->{sessions_max} : '-' - ); -} - -sub prefix_global_output { - my ($self, %options) = @_; - - return "Sessions "; -} - -sub set_counters { - my ($self, %options) = @_; - - $self->{maps_counters_type} = [ - { name => 'global', type => COUNTER_TYPE_GLOBAL, cb_prefix_output => 'prefix_global_output', skipped_code => { NO_VALUE => 1 } } - ]; - - $self->{maps_counters}->{global} = [ - { label => 'active', nlabel => 'sessions.active.count', set => { - key_values => [ { name => 'sessions_active' }, { name => 'sessions_max' } ], - closure_custom_output => $self->can('custom_active_output'), - closure_custom_perfdata => $self->can('custom_active_perfdata') - } - }, - { label => 'active-prct', nlabel => 'sessions.active.percentage', display_ok => 0, set => { - key_values => [ { name => 'sessions_active_prct' } ], - output_template => 'active: %.2f %%', - perfdatas => [ - { template => '%.2f', unit => '%', min => 0, max => 100 } - ] - } - }, - { label => 'active-tcp', nlabel => 'sessions.active.tcp.count', set => { - key_values => [ { name => 'sessions_tcp' } ], - output_template => 'TCP: %s', - perfdatas => [ - { template => '%s', min => 0 } - ] - } - }, - { label => 'active-udp', nlabel => 'sessions.active.udp.count', set => { - key_values => [ { name => 'sessions_udp' } ], - output_template => 'UDP: %s', - perfdatas => [ - { template => '%s', min => 0 } - ] - } - }, - { label => 'active-icmp', nlabel => 'sessions.active.icmp.count', set => { - key_values => [ { name => 'sessions_icmp' } ], - output_template => 'ICMP: %s', - perfdatas => [ - { template => '%s', min => 0 } - ] - } - } - ]; -} - -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; -} - -sub manage_selection { - my ($self, %options) = @_; - - my $result = $options{custom}->request_api( - type => 'op', - cmd => '', - ForceArray => [] - ); - - $self->{global} = { - sessions_max => $result->{'num-max'}, - sessions_active => $result->{'num-active'}, - sessions_udp => $result->{'num-udp'}, - sessions_tcp => $result->{'num-tcp'}, - sessions_icmp => $result->{'num-icmp'} - }; - - $self->{global}->{sessions_active_prct} = $self->{global}->{sessions_active} * 100 / $self->{global}->{sessions_max} - if ($self->{global}->{sessions_max} != 0); -} - -1; - -__END__ - -=head1 MODE - -Check sessions. - -=over 8 - -=item B<--warning-active> - -Warning threshold for active sessions. - -=item B<--critical-active> - -Critical threshold for active sessions. - -=item B<--warning-active-prct> - -Warning threshold for active sessions in percent. - -=item B<--critical-active-prct> - -Critical threshold for for active sessions in percent. - -=item B<--warning-active-udp> - -Warning threshold for active UDP sessions. - -=item B<--critical-active-udp> - -Critical threshold for active UDP sessions. - -=item B<--warning-active-tcp> - -Warning threshold for active TCP sessions. - -=item B<--critical-active-tcp> - -Critical threshold for active TCP sessions. - -=item B<--warning-active-icmp> - -Warning threshold for active ICMP sessions. - -=item B<--critical-active-icmp> - -Critical threshold for active ICMP sessions. - -=back - -=cut From dc70a6e1308622fd2cdda8919f26663d227cb510 Mon Sep 17 00:00:00 2001 From: garnier-quentin Date: Mon, 20 Jul 2026 09:28:11 -0400 Subject: [PATCH 12/12] wi --- src/network/paloalto/api/plugin.pm | 1 + 1 file changed, 1 insertion(+) diff --git a/src/network/paloalto/api/plugin.pm b/src/network/paloalto/api/plugin.pm index 8e299247c1..04b664ffd4 100644 --- a/src/network/paloalto/api/plugin.pm +++ b/src/network/paloalto/api/plugin.pm @@ -29,6 +29,7 @@ sub new { my $self = $class->SUPER::new(package => __PACKAGE__, %options); bless $self, $class; + $self->{version} = '1.0'; $self->{modes} = { 'environment' => 'network::paloalto::api::mode::environment', 'ha' => 'network::paloalto::api::mode::ha',