diff --git a/packaging/centreon-plugin-Network-Firewalls-Paloalto-Standard-Api/deb.json b/packaging/centreon-plugin-Network-Firewalls-Paloalto-Standard-Api/deb.json new file mode 100644 index 0000000000..439bc815cc --- /dev/null +++ b/packaging/centreon-plugin-Network-Firewalls-Paloalto-Standard-Api/deb.json @@ -0,0 +1,7 @@ +{ + "dependencies": [ + "libdatetime-perl", + "libdatetime-format-strptime-perl", + "libxml-simple-perl" + ] +} diff --git a/packaging/centreon-plugin-Network-Firewalls-Paloalto-Standard-Api/pkg.json b/packaging/centreon-plugin-Network-Firewalls-Paloalto-Standard-Api/pkg.json new file mode 100644 index 0000000000..4fa99b2092 --- /dev/null +++ b/packaging/centreon-plugin-Network-Firewalls-Paloalto-Standard-Api/pkg.json @@ -0,0 +1,9 @@ +{ + "pkg_name": "centreon-plugin-Network-Firewalls-Paloalto-Standard-Api", + "pkg_summary": "Centreon Plugin to monitor Palo Alto Networks firewalls using API XML", + "plugin_name": "centreon_paloalto_api.pl", + "files": [ + "centreon/plugins/script_custom.pm", + "network/paloalto/api/" + ] +} diff --git a/packaging/centreon-plugin-Network-Firewalls-Paloalto-Standard-Api/rpm.json b/packaging/centreon-plugin-Network-Firewalls-Paloalto-Standard-Api/rpm.json new file mode 100644 index 0000000000..34c3ea44d2 --- /dev/null +++ b/packaging/centreon-plugin-Network-Firewalls-Paloalto-Standard-Api/rpm.json @@ -0,0 +1,8 @@ +{ + "dependencies": [ + "perl(DateTime)", + "perl(DateTime::Format::Strptime)", + "perl(XML::Simple)", + "perl(URI::Escape)" + ] +} diff --git a/src/network/paloalto/api/custom/api.pm b/src/network/paloalto/api/custom/api.pm new file mode 100644 index 0000000000..0822d5d6d0 --- /dev/null +++ b/src/network/paloalto/api/custom/api.pm @@ -0,0 +1,329 @@ +# +# 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::custom::api; + +use strict; +use warnings; +use centreon::plugins::http; +use centreon::plugins::statefile; +use centreon::plugins::constants qw(:values); +use XML::Simple; +use MIME::Base64 qw(encode_base64); +use URI::Escape qw(uri_escape); +use Digest::SHA qw(sha256_hex); +use centreon::plugins::misc qw(is_empty); + +sub new { + my ($class, %options) = @_; + my $self = {}; + bless $self, $class; + + unless ($options{output}) { + print "Class Custom: Need to specify 'output' argument.\n"; + exit 3 + } + $options{output}->option_exit(short_msg => "Class Custom: Need to specify 'options' argument.") + unless $options{options}; + + unless ($options{noptions}) { + $options{options}->add_options(arguments => { + 'hostname:s' => { name => 'hostname', default => '' }, + 'port:s' => { name => 'port', default => 443 }, + 'proto:s' => { name => 'proto', default => 'https' }, + 'auth-type:s' => { name => 'auth_type', default => 'api-key' }, + 'api-key:s' => { name => 'api_key', default => '' }, + 'username:s' => { name => 'username', default => '' }, + 'password:s' => { name => 'password', default => '' }, + 'timeout:s' => { name => 'timeout', default => 30 }, + 'unknown-http-status:s' => { name => 'unknown_http_status', default => '%{http_code} < 200 or %{http_code} >= 300' }, + 'warning-http-status:s' => { name => 'warning_http_status', default => '' }, + 'critical-http-status:s' => { name => 'critical_http_status', default => '' } + }); + } + $options{options}->add_help(package => __PACKAGE__, sections => 'API OPTIONS', once => 1); + + $self->{output} = $options{output}; + $self->{http} = centreon::plugins::http->new(%options, default_backend => 'curl'); + $self->{cache} = centreon::plugins::statefile->new(%options); + + return $self; +} + +sub set_options { + my ($self, %options) = @_; + + $self->{option_results} = $options{option_results}; +} + +sub set_defaults {} + +sub check_options { + my ($self, %options) = @_; + + $self->{hostname} = $self->{option_results}->{hostname}; + $self->{port} = $self->{option_results}->{port}; + $self->{proto} = $self->{option_results}->{proto}; + $self->{auth_type} = $self->{option_results}->{auth_type}; + $self->{api_key} = $self->{option_results}->{api_key}; + $self->{username} = $self->{option_results}->{username}; + $self->{password} = $self->{option_results}->{password}; + $self->{timeout} = $self->{option_results}->{timeout}; + $self->{unknown_http_status} = $self->{option_results}->{unknown_http_status}; + $self->{warning_http_status} = $self->{option_results}->{warning_http_status}; + $self->{critical_http_status} = $self->{option_results}->{critical_http_status}; + + $self->{output}->option_exit(short_msg => "Need to specify --hostname option.") + if $self->{hostname} eq ''; + $self->{output}->option_exit(short_msg => "Unknown --auth-type value '$self->{auth_type}' (must be 'api-key' or 'basic').") + if $self->{auth_type} !~ /^(?:api-key|basic)$/; + $self->{output}->option_exit(short_msg => "With --auth-type=api-key: specify --api-key or --username/--password to auto-generate it.") + if $self->{auth_type} eq 'api-key' && $self->{api_key} eq '' && $self->{username} eq ''; + + $self->{output}->option_exit(short_msg => "Need to specify --username/--password options with --auth-type=basic.") + if $self->{auth_type} eq 'basic' && ($self->{username} eq '' || $self->{password} eq ''); + + $self->{cache}->check_options(option_results => $self->{option_results}); + + return 0; +} + +sub get_hostname { + my ($self, %options) = @_; + + return $self->{hostname}; +} + +sub get_port { + my ($self, %options) = @_; + + return $self->{port}; +} + +sub settings { + my ($self, %options) = @_; + + return if $self->{settings_done}; + $self->{option_results}->{$_} = $self->{$_} + foreach qw/hostname port proto timeout/; + $self->{http}->set_options(%{$self->{option_results}}); + $self->{settings_done} = 1; +} + +sub generate_api_key { + my ($self, %options) = @_; + + $self->{output}->output_add(long_msg => "Generating API key for user '$self->{username}'", debug => 1); + + my $content = $self->{http}->request( + url_path => '/api/', + method => 'POST', + get_param => ['type=keygen'], + query_form_post => 'user=' . uri_escape($self->{username}) . '&password=' . uri_escape($self->{password}), + header => ['Content-Type: application/x-www-form-urlencoded'], + unknown_status => '', + warning_status => '', + critical_status => '' + ); + + my $code = $self->{http}->get_code(); + $self->{output}->option_exit(short_msg => sprintf("API key generation failed [code: %s] [message: %s]", $code, $self->{http}->get_message())) + if $code < 200 || $code >= 300; + + my $result = $self->_parse_xml($content); + $self->{output}->option_exit(short_msg => "API key generation response does not contain a key.") + if is_empty($result->{key}); + + $self->{api_key} = $result->{key}; + $self->{cache}->write(data => { + updated => time(), + api_key => $self->{api_key} + }); + $self->{output}->output_add(long_msg => "API key successfully generated and cached", debug => 1); +} + +sub _load_api_key { + my ($self) = @_; + + # Use api-key if it was explicitly provided + return if $self->{api_key} ne ''; + + my $cache_name = 'paloalto_api_' . sha256_hex($self->{hostname} . '_' . $self->{username}); + my $has_cache = $self->{cache}->read(statefile => $cache_name); + + if ($has_cache != BUFFER_CREATION) { + my $cached_key = $self->{cache}->get(name => 'api_key'); + unless (is_empty($cached_key)) { + $self->{api_key} = $cached_key; + $self->{output}->output_add(long_msg => "Using cached API key", debug => 1); + return; + } + } + + $self->generate_api_key(); +} + +sub _build_auth_header { + my ($self) = @_; + + return $self->{auth_type} eq 'api-key' + ? 'X-PAN-KEY: ' . $self->{api_key} + : 'Authorization: Basic ' . encode_base64($self->{username} . ':' . $self->{password}, ''); +} + +sub _http_request { + my ($self, %options) = @_; + + return $self->{http}->request( + url_path => '/api/', + get_params => { + 'type' => $options{type}, + 'cmd' => $options{cmd} + }, + header => [ + $self->_build_auth_header(), + 'Accept: application/xml' + ], + unknown_status => $options{unknown_status} // '', + warning_status => $options{warning_status} // '', + critical_status => $options{critical_status} // '' + ); +} + +sub _parse_xml { + my ($self, $content, %options) = @_; + + $self->{output}->output_add(long_msg => "API response: $content", debug => 1); + + $self->{output}->option_exit( short_msg => "API returns empty content [code: '" . $self->{http}->get_code() . "'] [message: '" . $self->{http}->get_message() . "']") + if is_empty($content); + + $self->{output}->option_exit(short_msg => "Cannot find XML response in API reply.") + unless $content =~ /(.*<\/response>)/ms; + + my ($xml, $status) = ($1, $2); + $self->{output}->option_exit(short_msg => "API response status: $status") + unless $status eq 'success'; + + my $result; + eval { + $result = XMLin($xml, ForceArray => $options{ForceArray} // [], KeyAttr => []); + }; + $self->{output}->option_exit(short_msg => "Cannot decode XML response: $@") + if $@; + + return $result->{result}; +} + +sub request_api { + my ($self, %options) = @_; + + $self->settings(); + + $self->_load_api_key() if ($self->{auth_type} eq 'api-key'); + + # First attempt without status checking so we can intercept 401/403 + my $content = $self->_http_request(%options); + my $code = $self->{http}->get_code(); + + if ($self->{auth_type} eq 'api-key' && $code =~ /^(?:401|403)$/) { + $self->{output}->output_add(long_msg => "Got HTTP $code, regenerating API key and retrying", debug => 1); + $self->generate_api_key(); + + # Second attempt with status checking enabled + $content = $self->_http_request( + %options, + unknown_status => $self->{unknown_http_status}, + warning_status => $self->{warning_http_status}, + critical_status => $self->{critical_http_status} + ); + } elsif ($code < 200 || $code >= 300) { + $self->{output}->option_exit(short_msg => sprintf("HTTP error [code: %s] [message: %s]", $code, $self->{http}->get_message())); + } + + return $self->_parse_xml($content, %options); +} + +1; + +__END__ + +=head1 NAME + +Palo Alto XML API + +=head1 API OPTIONS + +=over 8 + +=item B<--hostname> + +Hostname or IP address of the Palo Alto device. + +=item B<--port> + +Port used (default: 443). + +=item B<--proto> + +Protocol to use: http or https (default: https). + +=item B<--auth-type> + +Authentication type: C (default) or C. + +=item B<--api-key> + +PAN-OS API key (sent as X-PAN-KEY header). Used with --auth-type=api-key. +If omitted, the key is auto-generated from --username/--password via the C +and cached locally. A 401 or 403 response also triggers automatic key regeneration. + +=item B<--username> + +Username. Required with --auth-type=basic. +Also used with --auth-type=api-key to auto-generate or regenerate the API key. + +=item B<--password> + +Password. + +=item B<--timeout> + +HTTP request timeout in seconds (default: 30). + +=item B<--unknown-http-status> + +Threshold for unknown HTTP status (default: '%{http_code} < 200 or %{http_code} >= 300'). + +=item B<--warning-http-status> + +Threshold for warning HTTP status. + +=item B<--critical-http-status> + +Threshold for critical HTTP status. + +=back + +=head1 DESCRIPTION + +B. + +=cut diff --git a/src/network/paloalto/api/mode/components/fan.pm b/src/network/paloalto/api/mode/components/fan.pm new file mode 100644 index 0000000000..a93726d6ce --- /dev/null +++ b/src/network/paloalto/api/mode/components/fan.pm @@ -0,0 +1,71 @@ +# +# 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::components::fan; + +use strict; +use warnings; +use centreon::plugins::misc qw/is_empty/; + +sub check { + my ($self) = @_; + + $self->{output}->output_add(long_msg => "Checking fans"); + $self->{components}->{fan} = { name => 'fans', total => 0, skip => 0 }; + return if $self->check_filter(section => 'fan'); + + foreach my $instance (sort keys %{$self->{data}->{fans}}) { + my $result = $self->{data}->{fans}->{$instance}; + + next if $self->check_filter(section => 'fan', instance => $instance); + next if $self->check_filter(section => 'fan', instance => $result->{description}); + $self->{components}->{fan}->{total}++; + + $self->{output}->output_add(long_msg => sprintf("Fan '%s' alarm is '%s' [instance: %s, rpm: %s]", + $result->{description}, $result->{alarm}, + $instance, $result->{rpm})); + + my $alarm_status = $self->get_severity(label => 'default', section => 'fan', value => $result->{alarm}); + $self->{output}->output_add(severity => $alarm_status, short_msg => sprintf("Fan '%s' alarm is %s", $result->{description}, $alarm_status)) + unless $self->{output}->is_status(value => $alarm_status, compare => 'ok', litteral => 1); + + unless (is_empty($result->{rpm})){ + my ($exit, $warn, $crit, $checked) = $self->get_severity_numeric( + section => 'fan', + instance => $instance, + value => $result->{rpm} + ); + $self->{output}->output_add(severity => $exit, short_msg => sprintf("Fan '%s' rpm is %s", $result->{description}, $result->{rpm})) + unless $self->{output}->is_status(value => $exit, compare => 'ok', litteral => 1); + + my $label = $result->{description} . '#hardware.fan.speed.rpm'; + $self->{output}->perfdata_add( + label => $label, + unit => 'rpm', + value => $result->{rpm}, + warning => $warn, + critical => $crit, + min => $result->{min} + ); + } + } +} + +1; diff --git a/src/network/paloalto/api/mode/components/psu.pm b/src/network/paloalto/api/mode/components/psu.pm new file mode 100644 index 0000000000..0e3a37216d --- /dev/null +++ b/src/network/paloalto/api/mode/components/psu.pm @@ -0,0 +1,51 @@ +# +# Copyright 2026-Present Centreon (http://www.centreon.com/) +# +# Centreon is a full-fledged industry-strength solution that meets +# the needs in IT infrastructure and application monitoring for +# service performance. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +package network::paloalto::api::mode::components::psu; + +use strict; +use warnings; +use centreon::plugins::misc qw/is_empty/; + +sub check { + my ($self) = @_; + + $self->{output}->output_add(long_msg => "Checking power supplies"); + $self->{components}->{psu} = { name => 'power supplies', total => 0, skip => 0 }; + return if $self->check_filter(section => 'psu'); + + foreach my $instance (sort keys %{$self->{data}->{psus}}) { + my $result = $self->{data}->{psus}->{$instance}; + + next if $self->check_filter(section => 'psu', instance => $instance); + next if $self->check_filter(section => 'psu', instance => $result->{description}); + $self->{components}->{psu}->{total}++; + + $self->{output}->output_add(long_msg => sprintf("Power supply '%s' alarm is '%s' [instance: %s, inserted: %s]", + $result->{description}, $result->{alarm}, + $instance, $result->{inserted})); + + my $alarm_status = $self->get_severity(label => 'default', section => 'psu', value => $result->{alarm}); + $self->{output}->output_add(severity => $alarm_status, short_msg => sprintf("Power supply '%s' alarm is %s", $result->{description}, $alarm_status)) + unless $self->{output}->is_status(value => $alarm_status, compare => 'ok', litteral => 1); + } +} + +1; diff --git a/src/network/paloalto/api/mode/components/temperature.pm b/src/network/paloalto/api/mode/components/temperature.pm new file mode 100644 index 0000000000..a2a49b679a --- /dev/null +++ b/src/network/paloalto/api/mode/components/temperature.pm @@ -0,0 +1,72 @@ +# +# 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::components::temperature; + +use strict; +use warnings; +use centreon::plugins::misc qw/is_empty/; + +sub check { + my ($self) = @_; + + $self->{output}->output_add(long_msg => "Checking temperatures"); + $self->{components}->{temperature} = { name => 'temperatures', total => 0, skip => 0 }; + return if $self->check_filter(section => 'temperature'); + + foreach my $instance (sort keys %{$self->{data}->{temperatures}}) { + my $result = $self->{data}->{temperatures}->{$instance}; + + next if $self->check_filter(section => 'temperature', instance => $instance); + next if $self->check_filter(section => 'temperature', instance => $result->{description}); + $self->{components}->{temperature}->{total}++; + + $self->{output}->output_add(long_msg => sprintf("Temperature '%s' alarm is '%s' [instance: %s, value: %s C]", + $result->{description}, $result->{alarm}, + $instance, $result->{value})); + + my $alarm_status = $self->get_severity(label => 'default', section => 'temperature', value => $result->{alarm}); + $self->{output}->output_add(severity => $alarm_status, short_msg => sprintf("Temperature '%s' alarm is %s", $result->{description}, $alarm_status)) + unless $self->{output}->is_status(value => $alarm_status, compare => 'ok', litteral => 1); + + unless (is_empty($result->{value})) { + my ($exit, $warn, $crit, $checked) = $self->get_severity_numeric( + section => 'temperature', + instance => $instance, + value => $result->{value} + ); + $self->{output}->output_add(severity => $exit, short_msg => sprintf("Temperature '%s' value is %s C", $result->{description}, $result->{value})) + unless $self->{output}->is_status(value => $exit, compare => 'ok', litteral => 1); + + my $label = $result->{description} . '#hardware.temperature.celsius'; + $self->{output}->perfdata_add( + label => $label, + unit => 'C', + value => $result->{value}, + warning => $warn, + critical => $crit, + min => $result->{min}, + max => $result->{max} + ); + } + } +} + +1; diff --git a/src/network/paloalto/api/mode/components/voltage.pm b/src/network/paloalto/api/mode/components/voltage.pm new file mode 100644 index 0000000000..cd372c916e --- /dev/null +++ b/src/network/paloalto/api/mode/components/voltage.pm @@ -0,0 +1,72 @@ +# +# 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::components::voltage; + +use strict; +use warnings; +use centreon::plugins::misc qw/is_empty/; + +sub check { + my ($self) = @_; + + $self->{output}->output_add(long_msg => "Checking voltages"); + $self->{components}->{voltage} = { name => 'voltages', total => 0, skip => 0 }; + return if $self->check_filter(section => 'voltage'); + + foreach my $instance (sort keys %{$self->{data}->{voltages}}) { + my $result = $self->{data}->{voltages}->{$instance}; + + next if $self->check_filter(section => 'voltage', instance => $instance); + next if $self->check_filter(section => 'voltage', instance => $result->{description}); + $self->{components}->{voltage}->{total}++; + + $self->{output}->output_add(long_msg => sprintf("Voltage '%s' alarm is '%s' [instance: %s, value: %s V]", + $result->{description}, $result->{alarm}, + $instance, $result->{value})); + + my $alarm_status = $self->get_severity(label => 'default', section => 'voltage', value => $result->{alarm}); + $self->{output}->output_add(severity => $alarm_status, short_msg => sprintf("Voltage '%s' alarm is %s", $result->{description}, $alarm_status)) + unless $self->{output}->is_status(value => $alarm_status, compare => 'ok', litteral => 1); + + unless (is_empty($result->{value})) { + my ($exit, $warn, $crit, $checked) = $self->get_severity_numeric( + section => 'voltage', + instance => $instance, + value => $result->{value} + ); + $self->{output}->output_add(severity => $exit, short_msg => sprintf("Voltage '%s' value is %s V", $result->{description}, $result->{value})) + unless $self->{output}->is_status(value => $exit, compare => 'ok', litteral => 1); + + my $label = $result->{description} . '#hardware.voltage.volt'; + $self->{output}->perfdata_add( + label => $label, + unit => 'V', + value => $result->{value}, + warning => $warn, + critical => $crit, + min => $result->{min}, + max => $result->{max} + ); + } + } +} + +1; diff --git a/src/network/paloalto/api/mode/environment.pm b/src/network/paloalto/api/mode/environment.pm new file mode 100644 index 0000000000..68e6538d7c --- /dev/null +++ b/src/network/paloalto/api/mode/environment.pm @@ -0,0 +1,199 @@ +# +# 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::environment; + +use base qw(centreon::plugins::templates::hardware); + +use strict; +use warnings; + +sub set_system { + my ($self, %options) = @_; + + $self->{regexp_threshold_numeric_check_section_option} = '^(?:temperature|fan|voltage)$'; + + $self->{cb_hook2} = 'api_execute'; + + $self->{thresholds} = { + default => [ + ['false', 'OK'], + ['.*', 'CRITICAL'] + ] + }; + + $self->{components_exec_load} = 0; + + $self->{components_path} = 'network::paloalto::api::mode::components'; + $self->{components_module} = ['temperature', 'fan', 'voltage', 'psu']; +} + +sub api_execute { + my ($self, %options) = @_; + + my $result = $options{custom}->request_api( + type => 'op', + cmd => '', + ForceArray => ['entry'] + ); + + # Structure the API response for the component checks + # Data will be organized as: $self->{data}->{component_type}->{instance} = { ... } + $self->{data} = {}; + + # Process temperature data + if (defined($result->{thermal}->{Slot1}->{entry})) { + my $entries = $result->{thermal}->{Slot1}->{entry}; + $entries = [$entries] unless ref($entries) eq 'ARRAY'; + + my $temp_idx = 0; + foreach my $entry (@$entries) { + $temp_idx++; + my $instance = "thermal_slot" . ($entry->{slot} // 1) . "_index" . $temp_idx; + $self->{data}->{temperatures}->{$instance} = { + description => $entry->{description} // "Temperature $temp_idx", + value => $entry->{DegreesC} // '', + min => $entry->{min} // '', + max => $entry->{max} // '', + alarm => $entry->{alarm} // 'False' + }; + } + } + + # Process fan data + if (defined($result->{fan}->{Slot1}->{entry})) { + my $entries = $result->{fan}->{Slot1}->{entry}; + $entries = [$entries] unless ref($entries) eq 'ARRAY'; + + my $fan_idx = 0; + foreach my $entry (@$entries) { + $fan_idx++; + my $instance = "fan_slot" . ($entry->{slot} // 1) . "_index" . $fan_idx; + $self->{data}->{fans}->{$instance} = { + description => $entry->{description} // "Fan $fan_idx", + rpm => $entry->{RPMs} // '', + min => $entry->{min} // '', + alarm => $entry->{alarm} // 'False' + }; + } + } + + # Process voltage (power) data + if (defined($result->{power}->{Slot1}->{entry})) { + my $entries = $result->{power}->{Slot1}->{entry}; + $entries = [$entries] unless ref($entries) eq 'ARRAY'; + + my $voltage_idx = 0; + foreach my $entry (@$entries) { + $voltage_idx++; + my $instance = "voltage_slot" . ($entry->{slot} // 1) . "_index" . $voltage_idx; + $self->{data}->{voltages}->{$instance} = { + description => $entry->{description} // "Voltage $voltage_idx", + value => $entry->{Volts} // '', + min => $entry->{min} // '', + max => $entry->{max} // '', + alarm => $entry->{alarm} // 'False' + }; + } + } + + # Process PSU (power supply) data + if (defined($result->{'power-supply'}->{Slot1}->{entry})) { + my $entries = $result->{'power-supply'}->{Slot1}->{entry}; + $entries = [$entries] unless ref($entries) eq 'ARRAY'; + + my $psu_idx = 0; + foreach my $entry (@$entries) { + $psu_idx++; + my $instance = "psu_slot" . ($entry->{slot} // 1) . "_index" . $psu_idx; + $self->{data}->{psus}->{$instance} = { + description => $entry->{description} // "PSU $psu_idx", + inserted => $entry->{Inserted} // 'False', + alarm => $entry->{alarm} // 'False' + }; + } + } +} + +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 => {}); + + return $self; +} + +1; + +__END__ + +=head1 MODE + +Check Palo Alto environment sensors (temperatures, fans, voltages, power supplies). + +=over 8 + +=item B<--component> + +Which component to check (default: '.*'). +Can be: 'psu', 'temperature', 'fan', 'voltage'. + +=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<--absent-problem> + +Return an error if a component is not 'present' (default is skipping). +It can be set globally or for a specific instance: --absent-problem='component_name' or --absent-problem='component_name,instance_value'. + +=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', 'fan', 'voltage' (syntax: type,regexp,threshold) +Example: --warning='temperature,.*,50' --warning='fan,.*,2500' + +=item B<--critical> + +Set critical threshold for 'temperature', 'fan', 'voltage' (syntax: type,regexp,threshold) +Example: --critical='temperature,.*,70' --critical='fan,.*,1000' + +=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/network/paloalto/api/mode/ha.pm b/src/network/paloalto/api/mode/ha.pm new file mode 100644 index 0000000000..c4182b7254 --- /dev/null +++ b/src/network/paloalto/api/mode/ha.pm @@ -0,0 +1,284 @@ +# +# 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::ha; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; +use Digest::SHA qw(sha256_hex); +use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold_ng); +use centreon::plugins::constants qw(:counters :values); + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options, statefile => 1, force_new_perfdata => 1); + bless $self, $class; + + return $self; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'ha', type => COUNTER_TYPE_GLOBAL, cb_prefix_output => 'prefix_ha_output', skipped_code => { BUFFER_CREATION() => 1 } } + ]; + + $self->{maps_counters}->{ha} = [ + { + label => 'local-state', + type => COUNTER_KIND_TEXT, + critical_default => '%{local_state} !~ /^(?:active|passive)$/', + set => { + key_values => [ { name => 'local_state' }, { name => 'local_priority' } ], + closure_custom_calc => $self->can('custom_local_state_calc'), + closure_custom_output => $self->can('output_local_state'), + closure_custom_threshold_check => \&catalog_status_threshold_ng + } + }, + { + label => 'peer-state', + type => COUNTER_KIND_TEXT, + critical_default => '%{peer_state} !~ /^(?:active|passive)$/ || %{peer_conn_status} ne "up"', + set => { + key_values => [ { name => 'peer_state' }, { name => 'peer_priority' }, { name => 'peer_conn_status' } ], + closure_custom_calc => $self->can('custom_peer_state_calc'), + closure_custom_output => $self->can('output_peer_state'), + closure_custom_threshold_check => \&catalog_status_threshold_ng + } + }, + { + label => 'state-sync', + type => COUNTER_KIND_TEXT, + critical_default => '%{state_sync} !~ /^synchronized|complete$/', + set => { + key_values => [ { name => 'state_sync' } ], + output_template => 'state sync: %s', + closure_custom_threshold_check => \&catalog_status_threshold_ng + } + }, + { + label => 'ha1-link-status', + type => COUNTER_KIND_TEXT, + critical_default => '%{ha1_status} ne "up"', + set => { + key_values => [ { name => 'ha1_status' } ], + output_template => 'HA1 link: %s', + closure_custom_threshold_check => \&catalog_status_threshold_ng + } + }, + { + label => 'ha2-link-status', + type => COUNTER_KIND_TEXT, + critical_default => '%{ha2_status} ne "up"', + set => { + key_values => [ { name => 'ha2_status' } ], + output_template => 'HA2 link: %s', + closure_custom_threshold_check => \&catalog_status_threshold_ng + } + }, + { + label => 'ha-mode', + type => COUNTER_KIND_TEXT, + set => { + key_values => [ { name => 'ha_mode' } ], + output_template => 'HA mode: %s', + closure_custom_threshold_check => \&catalog_status_threshold_ng + } + }, + { + label => 'build-compat', + type => COUNTER_KIND_TEXT, + warning_default => '%{build_compat} ne "Match"', + set => { + key_values => [ { name => 'build_compat' } ], + output_template => 'build compatibility: %s', + closure_custom_threshold_check => \&catalog_status_threshold_ng + } + } + ]; +} + +sub prefix_ha_output { + my ($self, %options) = @_; + my $model = $options{instance_value}->{platform_model} // 'HA'; + return "$model status: "; +} + +sub custom_local_state_calc { + my ($self, %options) = @_; + + # define a "local_state_last" variable for compatibility with paloalto::ssh plugin + $self->{result_values}->{local_state_last} = $options{old_datas}->{$self->{instance} . '_local_state'}; + $self->{result_values}->{local_state} = $options{new_datas}->{$self->{instance} . '_local_state'}; + $self->{result_values}->{local_priority} = $options{new_datas}->{$self->{instance} . '_local_priority'}; + if (!defined($options{old_datas}->{$self->{instance} . '_local_state'})) { + $self->{error_msg} = "buffer creation"; + return BUFFER_CREATION; + } + + return 0; +} + +sub custom_peer_state_calc { + my ($self, %options) = @_; + + # define a "peer_state_last" variable for compatibility with paloalto::ssh plugin + $self->{result_values}->{peer_state_last} = $options{old_datas}->{$self->{instance} . '_peer_state'}; + $self->{result_values}->{peer_state} = $options{new_datas}->{$self->{instance} . '_peer_state'}; + $self->{result_values}->{peer_priority} = $options{new_datas}->{$self->{instance} . '_peer_priority'}; + $self->{result_values}->{peer_conn_status} = $options{new_datas}->{$self->{instance} . '_peer_conn_status'}; + if (!defined($options{old_datas}->{$self->{instance} . '_peer_state'})) { + $self->{error_msg} = "buffer creation"; + return BUFFER_CREATION; + } + + return 0; +} + +sub output_local_state { + my ($self, %options) = @_; + return sprintf('local state: %s (priority: %s)%s', + $self->{result_values}->{local_state}, + $self->{result_values}->{local_priority}, + $self->{output}->is_verbose() ? " previous local state: ".$self->{result_values}->{local_state_last} : "" + ); +} + +sub output_peer_state { + my ($self, %options) = @_; + return sprintf('peer state: %s (priority: %s, conn: %s)%s', + $self->{result_values}->{peer_state}, + $self->{result_values}->{peer_priority}, + $self->{result_values}->{peer_conn_status}, + $self->{output}->is_verbose() ? " previous peer state: ".$self->{result_values}->{peer_state_last} : "" + ); +} + +sub manage_selection { + my ($self, %options) = @_; + + my $result = $options{custom}->request_api( + type => 'op', + cmd => '' + ); + + my $group = $result->{group} // {}; + my $local = $group->{'local-info'} // {}; + my $peer = $group->{'peer-info'} // {}; + + my $local_state = lc($local->{state} //''); + my $peer_state = lc($peer->{state} // ''); + my $ha_mode = lc($group->{mode} // ''); + my $platform_model = $local->{'platform-model'} // ''; + + $self->{ha} = { + platform_model => $platform_model, + local_state => $local_state, + local_priority => $local->{priority} // '', + peer_state => $peer_state, + peer_priority => $peer->{priority} // '', + peer_conn_status => lc($peer->{'conn-status'} // ''), + state_sync => lc($group->{'running-sync'} // ''), + ha1_status => lc($peer->{'conn-ha1'}->{'conn-status'} // ''), + ha2_status => lc($peer->{'conn-ha2'}->{'conn-status'} // ''), + ha_mode => $ha_mode, + build_compat => $local->{'build-compat'} // '' + }; + + $self->{cache_name} = "paloalto_api_" . $self->{mode} . '_' . $options{custom}->get_hostname() . '_' . + sha256_hex($self->{option_results}->{filter_counters} // 'all'); +} + +1; + +__END__ + +=head1 MODE + +Check Palo Alto High Availability (HA) status. + +=over 8 + +=item B<--warning-local-state> + +Define the conditions to match for the status to be WARNING. +You can use the following variables: %{local_state}, %{local_priority}, %{local_state_last} + +=item B<--critical-local-state> + +Define the conditions to match for the status to be CRITICAL (default: '%{local_state} !~ /^(?:active|passive)$/'). +You can use the following variables: %{local_state}, %{local_priority}, %{local_state_last} + +=item B<--warning-peer-state> + +Define the conditions to match for the status to be WARNING. +You can use the following variables: %{peer_state}, %{peer_priority}, %{peer_conn_status}, %{peer_state_last} + +=item B<--critical-peer-state> + +Define the conditions to match for the status to be CRITICAL (default: '%{peer_state} !~ /^(?:active|passive)$/ || %{peer_conn_status} ne "up"'). +You can use the following variables: %{peer_state}, %{peer_priority}, %{peer_conn_status}, %{peer_state_last} + +=item B<--warning-state-sync> + +Define the conditions to match for the status to be WARNING. +You can use the following variables: %{state_sync} + +=item B<--critical-state-sync> + +Define the conditions to match for the status to be CRITICAL (default: '%{state_sync} !~ /^synchronized|complete$/'). +You can use the following variables: %{state_sync} + +=item B<--warning-ha1-link-status> + +Define the conditions to match for the status to be WARNING. +You can use the following variables: %{ha1_status} + +=item B<--critical-ha1-link-status> + +Define the conditions to match for the status to be CRITICAL (default: '%{ha1_status} ne "up"'). +You can use the following variables: %{ha1_status} + +=item B<--warning-ha2-link-status> + +Define the conditions to match for the status to be WARNING. +You can use the following variables: %{ha2_status} + +=item B<--critical-ha2-link-status> + +Define the conditions to match for the status to be CRITICAL (default: '%{ha2_status} ne "up"'). +You can use the following variables: %{ha2_status} + +=item B<--warning-build-compat> + +Define the conditions to match for the status to be WARNING (default: '%{build_compat} ne "Match"'). +You can use the following variables: %{build_compat} + +=item B<--critical-build-compat> + +Define the conditions to match for the status to be CRITICAL. +You can use the following variables: %{build_compat} + +=back + +=cut diff --git a/src/network/paloalto/api/mode/ipsec.pm b/src/network/paloalto/api/mode/ipsec.pm new file mode 100644 index 0000000000..f12d1d2f00 --- /dev/null +++ b/src/network/paloalto/api/mode/ipsec.pm @@ -0,0 +1,185 @@ +# +# 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::ipsec; + +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 prefix_tunnel_output { + my ($self, %options) = @_; + return sprintf("tunnel '%s' ", $options{instance_value}->{name}); +} + +sub prefix_global_output { + my ($self, %options) = @_; + return 'Tunnels '; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'global', type => COUNTER_TYPE_GLOBAL, cb_prefix_output => 'prefix_global_output' }, + { name => 'tunnels', type => COUNTER_TYPE_INSTANCE, cb_prefix_output => 'prefix_tunnel_output', message_multiple => 'All tunnels are ok' } + ]; + + $self->{maps_counters}->{global} = [ + { + label => 'tunnels-count', + nlabel => 'tunnels.count', + set => { + key_values => [ { name => 'tunnels_count' } ], + output_template => 'count: %s', + perfdatas => [ + { template => '%s', min => 0 } + ] + } + } + ]; + + $self->{maps_counters}->{tunnels} = [ + { + label => 'remain-time', + nlabel => 'tunnel.remain.seconds', + set => { + key_values => [ { name => 'remain' }, { name => 'name' } ], + output_template => 'remain: %s seconds', + perfdatas => [ + { template => '%s', unit => 's', min => 0, + label_extra_instance => 1, instance_use => 'name' } + ] + } + }, + { + label => 'encryption', + type => COUNTER_KIND_TEXT, + set => { + key_values => [ { name => 'enc' }, { name => 'name' } ], + output_template => 'encryption: %s' + } + }, + { + label => 'gateway', + type => COUNTER_KIND_TEXT, + set => { + key_values => [ { name => 'gateway' }, { name => 'name' } ], + output_template => 'gateway: %s' + } + } + ]; +} + +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-tunnel-name:s' => { name => 'include_tunnel_name', default => '' }, + 'exclude-tunnel-name:s' => { name => 'exclude_tunnel_name', default => '' }, + 'include-gateway-name:s' => { name => 'include_gateway_name', default => '' }, + 'exclude-gateway-name:s' => { name => 'exclude_gateway_name', default => '' } + }); + + return $self; +} + +sub manage_selection { + my ($self, %options) = @_; + + my $result = $options{custom}->request_api( + type => 'op', + cmd => '', + ForceArray => ['entry'] + ); + + $self->{tunnels} = {}; + $self->{global} = { tunnels_count => 0 }; + + return unless ref $result->{entries} eq 'HASH'; + + foreach my $entry (@{$result->{entries}->{entry}}) { + my $name = $entry->{name} // ''; + my $gateway = $entry->{gateway} // ''; + + next if is_excluded($name, $self->{option_results}->{include_tunnel_name}, $self->{option_results}->{exclude_tunnel_name}); + next if is_excluded($gateway, $self->{option_results}->{include_gateway_name}, $self->{option_results}->{exclude_gateway_name}); + + $self->{tunnels}->{$name} = { + name => $name, + gateway => $gateway, + enc => $entry->{enc} // 'Unknown', + remain => $entry->{remain} // 0, + proto => $entry->{proto} // 'Unknown' + }; + $self->{global}->{tunnels_count}++; + } +} + +1; + +__END__ + +=head1 MODE + +Check Palo Alto IPsec VPN tunnels status and lifetime. + +=over 8 + +=item B<--include-tunnel-name> + +Include tunnel names (regexp). + +=item B<--exclude-tunnel-name> + +Exclude tunnel names (regexp). + +=item B<--include-gateway-name> + +Include gateway names (regexp). + +=item B<--exclude-gateway-name> + +Exclude gateway names (regexp). + +=item B<--warning-tunnels-count> + +Warning threshold for tunnels count. + +=item B<--critical-tunnels-count> + +Critical threshold for tunnels count. + +=item B<--warning-remain-time> + +Warning threshold for tunnel remain time in seconds. + +=item B<--critical-remain-time> + +Critical threshold for tunnel remain time in seconds. + +=back + +=cut diff --git a/src/network/paloalto/api/mode/licenses.pm b/src/network/paloalto/api/mode/licenses.pm new file mode 100644 index 0000000000..d9c4f46902 --- /dev/null +++ b/src/network/paloalto/api/mode/licenses.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::licenses; + +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 qw(is_excluded); +use DateTime; +use DateTime::Format::Strptime; + +sub custom_expiration_output { + my ($self, %options) = @_; + my $days = $self->{result_values}->{days_left}; + return 'never expire' if $days && $days == -1; + return ($days // 0) . ' days left'; +} + +sub prefix_license_output { + my ($self, %options) = @_; + return sprintf("license '%s' ", $options{instance_value}->{feature}); +} + +sub prefix_global_output { + my ($self, %options) = @_; + return 'Licenses '; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'global', type => COUNTER_TYPE_GLOBAL, cb_prefix_output => 'prefix_global_output' }, + { name => 'licenses', type => COUNTER_TYPE_INSTANCE, cb_prefix_output => 'prefix_license_output', message_multiple => 'All licenses are ok' } + ]; + + $self->{maps_counters}->{global} = [ + { + label => 'licenses-count', + nlabel => 'licenses.count', + set => { + key_values => [ { name => 'licenses_count' } ], + output_template => 'count: %s', + perfdatas => [ + { template => '%s', min => 0 } + ] + } + } + ]; + + $self->{maps_counters}->{licenses} = [ + { + label => 'status', + type => COUNTER_KIND_TEXT, + critical_default => '%{expired} =~ /yes/', + set => { + key_values => [ { name => 'expired' }, { name => 'feature' } ], + output_template => 'expired: %s', + closure_custom_threshold_check => \&catalog_status_threshold_ng + } + }, + { + label => 'expiration-days', + nlabel => 'license.empiration.days', + critical_default => '@0', + set => { + key_values => [ { name => 'days_left' }, { name => 'feature' } ], + closure_custom_output => $self->can('custom_expiration_output'), + perfdatas => [ + { template => '%s', unit => 'd', min => -1, + label_extra_instance => 1, instance_use => 'feature' } + ] + } + } + ]; +} + +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-license-name:s' => { name => 'include_license_name', default => '' }, + 'exclude-license-name:s' => { name => 'exclude_license_name', default => '' } + }); + + return $self; +} + +sub manage_selection { + my ($self, %options) = @_; + + my $result = $options{custom}->request_api( + type => 'op', + cmd => '', + ForceArray => ['entry'] + ); + + $self->{licenses} = {}; + $self->{global} = { licenses_count => 0 }; + + my $parser = DateTime::Format::Strptime->new( + pattern => '%B %d, %Y', + on_error => 'undef' + ); + + return unless defined($result->{licenses}); + + foreach my $entry (@{$result->{licenses}->{entry}}) { + my $feature = $entry->{feature} // ''; + next if is_excluded($feature, $self->{option_results}->{include_license_name}, $self->{option_results}->{exclude_license_name}); + + my $days_left = -1; + my $expires = $entry->{expires}; + + if (defined($expires) && $expires ne 'Never') { + my $exp_date = $parser->parse_datetime($expires); + if ($exp_date) { + my $now = DateTime->now(time_zone => 'UTC'); + $days_left = int(($exp_date->epoch() - $now->epoch()) / 86400); + $days_left = 0 if $days_left < 0; + } + } + $self->{licenses}->{$feature} = { + feature => $feature, + expired => lc($entry->{expired}), + days_left => $days_left + }; + $self->{global}->{licenses_count}++; + } +} + +1; + +__END__ + +=head1 MODE + +Check Palo Alto licenses status and expiration. + +=over 8 + +=item B<--include-license-name> + +Include license names (regexp). + +=item B<--exclude-license-name> + +Exclude license names (regexp). + +=item B<--unknown-status> + +Define the conditions to match for the status to be UNKNOWN. +You can use the following variables: %{expired} + +=item B<--warning-status> + +Define the conditions to match for the status to be WARNING. +You can use the following variables: %{expired} + +=item B<--critical-status> + +Define the conditions to match for the status to be CRITICAL (default: '%{expired} =~ /yes/'). +You can use the following variables: %{expired} + +=item B<--warning-expiration-days> + +Warning threshold in days before expiration. + +=item B<--critical-expiration-days> + +Critical threshold in days before expiration (default: '@0'). + +=item B<--warning-licenses-count> + +Warning threshold for licenses count. + +=item B<--critical-licenses-count> + +Critical threshold for licenses count. + +=back + +=cut diff --git a/src/network/paloalto/api/mode/system.pm b/src/network/paloalto/api/mode/system.pm new file mode 100644 index 0000000000..695b286575 --- /dev/null +++ b/src/network/paloalto/api/mode/system.pm @@ -0,0 +1,216 @@ +# +# 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::system; + +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); + +sub prefix_global_output { + my ($self, %options) = @_; + return 'System '; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'global', type => COUNTER_TYPE_GLOBAL, cb_prefix_output => 'prefix_global_output' } + ]; + + $self->{maps_counters}->{global} = [ + { + label => 'uptime', + nlabel => 'system.uptime.seconds', + set => { + key_values => [ { name => 'uptime' } ], + output_template => 'uptime: %s seconds', + perfdatas => [ + { template => '%s', unit => 's', min => 0 } + ] + } + }, + { + label => 'certificate-status', + type => COUNTER_KIND_TEXT, + critical_default => '%{cert_status} !~ /Valid/i', + set => { + key_values => [ { name => 'cert_status' } ], + output_template => 'certificate status: %s', + closure_custom_threshold_check => \&catalog_status_threshold_ng + } + }, + { + label => 'operational-mode', + type => COUNTER_KIND_TEXT, + set => { + key_values => [ { name => 'operational_mode' } ], + output_template => 'operational mode: %s', + closure_custom_threshold_check => \&catalog_status_threshold_ng + } + }, + { + label => 'software-version', + type => COUNTER_KIND_TEXT, + set => { + key_values => [ { name => 'sw_version' } ], + output_template => 'software version: %s', + closure_custom_threshold_check => \&catalog_status_threshold_ng + } + }, + { + label => 'wildfire-mode', + type => COUNTER_KIND_TEXT, + set => { + key_values => [ { name => 'wildfire_mode' } ], + output_template => 'WildFire mode: %s', + 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; + + return $self; +} + +sub manage_selection { + my ($self, %options) = @_; + + my $result = $options{custom}->request_api( + type => 'op', + cmd => '' + ); + + $self->{global} = { + uptime => 0, + cert_status => 'Unknown', + operational_mode => 'Unknown', + sw_version => 'Unknown', + wildfire_mode => 'Unknown' + }; + + return unless defined($result->{system}); + + my $system = $result->{system}; + + # Parse uptime: "X days, HH:MM:SS" format + if (defined($system->{uptime})) { + my $uptime_str = $system->{uptime}; + my $uptime_seconds = 0; + + if ($uptime_str =~ /^(\d+)\s+days?,\s+(\d+):(\d+):(\d+)$/) { + my ($days, $hours, $minutes, $seconds) = ($1, $2, $3, $4); + $uptime_seconds = $days * 86400 + $hours * 3600 + $minutes * 60 + $seconds; + } elsif ($uptime_str =~ /^(\d+):(\d+):(\d+)$/) { + my ($hours, $minutes, $seconds) = ($1, $2, $3); + $uptime_seconds = $hours * 3600 + $minutes * 60 + $seconds; + } + + $self->{global}->{uptime} = $uptime_seconds; + } + + $self->{global}->{cert_status} = $system->{'device-certificate-status'} + if $system->{'device-certificate-status'}; + + $self->{global}->{operational_mode} = $system->{'operational-mode'} + if $system->{'operational-mode'}; + + $self->{global}->{sw_version} = $system->{'sw-version'} + if $system->{'sw-version'}; + + $self->{global}->{wildfire_mode} = $system->{'wildfire-rt'} + if $system->{'wildfire-rt'}; +} + +1; + +__END__ + +=head1 MODE + +Check Palo Alto system information and status. + +=over 8 + +=item B<--warning-uptime> + +Warning threshold for uptime in seconds. + +=item B<--critical-uptime> + +Critical threshold for uptime in seconds. + +=item B<--unknown-certificate-status> + +Define the conditions to match for the status to be UNKNOWN. +You can use the following variables: %{cert_status} + +=item B<--warning-certificate-status> + +Define the conditions to match for the status to be WARNING. +You can use the following variables: %{cert_status} + +=item B<--critical-certificate-status> + +Define the conditions to match for the status to be CRITICAL (default: '%{cert_status} !~ /Valid/i'). +You can use the following variables: %{cert_status} + +=back + +=head1 AVAILABLE COUNTERS + +=over 8 + +=item B + +Total number of active system counters. + +=item B + +System uptime in seconds. + +=item B + +Device certificate status (Valid/Invalid/etc). + +=item B + +Current operational mode (normal/maintenance/etc). + +=item B + +Software version string. + +=item B + +WildFire mode status (Enabled/Disabled). + +=back + +=cut diff --git a/src/network/paloalto/api/plugin.pm b/src/network/paloalto/api/plugin.pm new file mode 100644 index 0000000000..99373650c5 --- /dev/null +++ b/src/network/paloalto/api/plugin.pm @@ -0,0 +1,53 @@ +# +# 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::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->{version} = '1.0'; + $self->{modes} = { + 'environment' => 'network::paloalto::api::mode::environment', + 'ha' => 'network::paloalto::api::mode::ha', + 'licenses' => 'network::paloalto::api::mode::licenses', + 'system' => 'network::paloalto::api::mode::system', + 'ipsec' => 'network::paloalto::api::mode::ipsec' + }; + + $self->{custom_modes}->{api} = 'network::paloalto::api::custom::api'; + return $self; +} + +1; + +__END__ + +=head1 PLUGIN DESCRIPTION + +Check Palo Alto devices using the PAN-OS XML API. + +=cut diff --git a/tests/network/paloalto/api/authent.robot b/tests/network/paloalto/api/authent.robot new file mode 100644 index 0000000000..e28f5d9240 --- /dev/null +++ b/tests/network/paloalto/api/authent.robot @@ -0,0 +1,36 @@ +*** Settings *** +Documentation Check PaloAlto authentication (api-key or basic). + +Resource ${CURDIR}${/}..${/}..${/}..${/}resources/import.resource + +Suite Setup Start Mockoon ${MOCKOON_JSON} +Suite Teardown Stop Mockoon +Test Timeout 120s + + +*** Variables *** +${MOCKOON_JSON} ${CURDIR}${/}mockoon-paloalto-api.json +${HOSTNAME} 127.0.0.1 +${APIPORT} 3000 +${CMD} ${CENTREON_PLUGINS} +... --plugin=network::paloalto::api::plugin +... --hostname=${HOSTNAME} +... --port=${APIPORT} +... --proto=http +... --mode=system + +*** Test Cases *** +paloalto-environment ${tc} + [Tags] network paloalto api environment + ${command} Catenate + ... ${CMD} + ... ${extra_options} + + Ctn Run Command And Check Result As Strings ${command} ${expected_result} + + Examples: tc extra_options expected_result -- + ... 1 ${EMPTY} UNKNOWN: With --auth-type=api-key: specify --api-key or --username/--password to auto-generate it. + ... 2 --auth-type=api-key UNKNOWN: With --auth-type=api-key: specify --api-key or --username/--password to auto-generate it. + ... 3 --auth-type=api-key --username=AA --password=BB OK: System uptime: 8552549 seconds, certificate status: Valid, operational mode: normal, software version: 10.1.12, WildFire mode: Disabled | 'system.uptime.seconds'=8552549s;;;0; + ... 4 --auth-type=basic UNKNOWN: Need to specify --username/--password options with --auth-type=basic. + ... 5 --auth-type=basic --username=AA --password=BB OK: System uptime: 8552549 seconds, certificate status: Valid, operational mode: normal, software version: 10.1.12, WildFire mode: Disabled | 'system.uptime.seconds'=8552549s;;;0; diff --git a/tests/network/paloalto/api/environment.robot b/tests/network/paloalto/api/environment.robot new file mode 100644 index 0000000000..18ad755f20 --- /dev/null +++ b/tests/network/paloalto/api/environment.robot @@ -0,0 +1,48 @@ +*** Settings *** +Documentation Check PaloAlto environment (temperatures, fans, voltages, PSUs). + +Resource ${CURDIR}${/}..${/}..${/}..${/}resources/import.resource + +Suite Setup Start Mockoon ${MOCKOON_JSON} +Suite Teardown Stop Mockoon +Test Timeout 120s + + +*** Variables *** +${MOCKOON_JSON} ${CURDIR}${/}mockoon-paloalto-api.json +${HOSTNAME} 127.0.0.1 +${APIPORT} 3000 +${CMD} ${CENTREON_PLUGINS} +... --plugin=network::paloalto::api::plugin +... --hostname=${HOSTNAME} +... --port=${APIPORT} +... --proto=http +... --mode=environment + +*** Test Cases *** +paloalto-environment ${tc} + [Tags] network paloalto api environment + ${command} Catenate + ... ${CMD} + ... --auth-type=api-key + ... --api-key=D@pAs$W@rD + ... ${extra_options} + + Ctn Run Command And Check Result As Strings ${command} ${expected_result} + + Examples: tc extra_options expected_result -- + ... 1 ${EMPTY} OK: All 20 components are ok [3/3 fans, 2/2 power supplies, 5/5 temperatures, 10/10 voltages]. | 'Temperature near CPLD (inlet)#hardware.temperature.celsius'=40.9C;;;0.0;60.0 'Temperature near Cavium (outlet)#hardware.temperature.celsius'=51.6C;;;0.0;60.0 'Temperature near Management Port (inlet)#hardware.temperature.celsius'=38.0C;;;0.0;60.0 'Temperature near Switch (midboard)#hardware.temperature.celsius'=45.0C;;;0.0;60.0 'Temperature @ Cavium Core#hardware.temperature.celsius'=53.175C;;;0.0;85.0 'Fan #1 RPM#hardware.fan.speed.rpm'=9157rpm;;;2500; 'Fan #2 RPM#hardware.fan.speed.rpm'=9557rpm;;;2500; 'Fan #3 RPM#hardware.fan.speed.rpm'=9418rpm;;;2500; '0.85V Power Rail#hardware.voltage.volt'=0.860666666667V;;;0.76;0.94 '3.3V SD Power Rail#hardware.voltage.volt'=3.332V;;;2.97;3.63 '0.9V Power Rail#hardware.voltage.volt'=0.904V;;;0.81;0.99 '1.0V Power Rail#hardware.voltage.volt'=1.006V;;;0.9;1.1 '1.1V Power Rail#hardware.voltage.volt'=1.09466666667V;;;0.99;1.21 '1.2V Power Rail#hardware.voltage.volt'=1.224V;;;1.08;1.32 '1.5V Power Rail#hardware.voltage.volt'=1.51066666667V;;;1.35;1.65 '1.8V Power Rail#hardware.voltage.volt'=1.812V;;;1.62;1.98 '2.5V Power Rail#hardware.voltage.volt'=2.504V;;;2.25;2.75 '3.3V Power Rail#hardware.voltage.volt'=3.332V;;;2.97;3.63 'hardware.fan.count'=3;;;; 'hardware.psu.count'=2;;;; 'hardware.temperature.count'=5;;;; 'hardware.voltage.count'=10;;;; + ... 2 --component=fan OK: All 3 components are ok [3/3 fans]. | 'Fan #1 RPM#hardware.fan.speed.rpm'=9157rpm;;;2500; 'Fan #2 RPM#hardware.fan.speed.rpm'=9557rpm;;;2500; 'Fan #3 RPM#hardware.fan.speed.rpm'=9418rpm;;;2500; 'hardware.fan.count'=3;;;; + ... 3 --component=fan --filter='fan,Fan #2 RPM' --filter='fan,Fan #3 RPM' OK: All 1 components are ok [1/1 fans]. | 'Fan #1 RPM#hardware.fan.speed.rpm'=9157rpm;;;2500; 'hardware.fan.count'=1;;;; + ... 4 --component=fan --warning='fan,.*,9100' WARNING: Fan 'Fan #1 RPM' rpm is 9157 - Fan 'Fan #2 RPM' rpm is 9557 - Fan 'Fan #3 RPM' rpm is 9418 | 'Fan #1 RPM#hardware.fan.speed.rpm'=9157rpm;0:9100;;2500; 'Fan #2 RPM#hardware.fan.speed.rpm'=9557rpm;0:9100;;2500; 'Fan #3 RPM#hardware.fan.speed.rpm'=9418rpm;0:9100;;2500; 'hardware.fan.count'=3;;;; + ... 5 --component=fan --critical='fan,.*,9100' CRITICAL: Fan 'Fan #1 RPM' rpm is 9157 - Fan 'Fan #2 RPM' rpm is 9557 - Fan 'Fan #3 RPM' rpm is 9418 | 'Fan #1 RPM#hardware.fan.speed.rpm'=9157rpm;;0:9100;2500; 'Fan #2 RPM#hardware.fan.speed.rpm'=9557rpm;;0:9100;2500; 'Fan #3 RPM#hardware.fan.speed.rpm'=9418rpm;;0:9100;2500; 'hardware.fan.count'=3;;;; + ... 6 --component=psu OK: All 2 components are ok [2/2 power supplies]. | 'hardware.psu.count'=2;;;; + ... 7 --component=psu --filter='psu,Supply #2' OK: All 1 components are ok [1/1 power supplies]. | 'hardware.psu.count'=1;;;; + ... 8 --component=voltage OK: All 10 components are ok [10/10 voltages]. | '0.85V Power Rail#hardware.voltage.volt'=0.860666666667V;;;0.76;0.94 '3.3V SD Power Rail#hardware.voltage.volt'=3.332V;;;2.97;3.63 '0.9V Power Rail#hardware.voltage.volt'=0.904V;;;0.81;0.99 '1.0V Power Rail#hardware.voltage.volt'=1.006V;;;0.9;1.1 '1.1V Power Rail#hardware.voltage.volt'=1.09466666667V;;;0.99;1.21 '1.2V Power Rail#hardware.voltage.volt'=1.224V;;;1.08;1.32 '1.5V Power Rail#hardware.voltage.volt'=1.51066666667V;;;1.35;1.65 '1.8V Power Rail#hardware.voltage.volt'=1.812V;;;1.62;1.98 '2.5V Power Rail#hardware.voltage.volt'=2.504V;;;2.25;2.75 '3.3V Power Rail#hardware.voltage.volt'=3.332V;;;2.97;3.63 'hardware.voltage.count'=10;;;; + ... 9 --component=voltage --filter='voltage,0' OK: All 6 components are ok [6/6 voltages]. | '1.1V Power Rail#hardware.voltage.volt'=1.09466666667V;;;0.99;1.21 '1.2V Power Rail#hardware.voltage.volt'=1.224V;;;1.08;1.32 '1.5V Power Rail#hardware.voltage.volt'=1.51066666667V;;;1.35;1.65 '1.8V Power Rail#hardware.voltage.volt'=1.812V;;;1.62;1.98 '2.5V Power Rail#hardware.voltage.volt'=2.504V;;;2.25;2.75 '3.3V Power Rail#hardware.voltage.volt'=3.332V;;;2.97;3.63 'hardware.voltage.count'=6;;;; + ... 10 --component=temperature OK: All 5 components are ok [5/5 temperatures]. | 'Temperature near CPLD (inlet)#hardware.temperature.celsius'=40.9C;;;0.0;60.0 'Temperature near Cavium (outlet)#hardware.temperature.celsius'=51.6C;;;0.0;60.0 'Temperature near Management Port (inlet)#hardware.temperature.celsius'=38.0C;;;0.0;60.0 'Temperature near Switch (midboard)#hardware.temperature.celsius'=45.0C;;;0.0;60.0 'Temperature @ Cavium Core#hardware.temperature.celsius'=53.175C;;;0.0;85.0 'hardware.temperature.count'=5;;;; + ... 11 --component=temperature --filter='temperature,Management' OK: All 4 components are ok [4/4 temperatures]. | 'Temperature near CPLD (inlet)#hardware.temperature.celsius'=40.9C;;;0.0;60.0 'Temperature near Cavium (outlet)#hardware.temperature.celsius'=51.6C;;;0.0;60.0 'Temperature near Switch (midboard)#hardware.temperature.celsius'=45.0C;;;0.0;60.0 'Temperature @ Cavium Core#hardware.temperature.celsius'=53.175C;;;0.0;85.0 'hardware.temperature.count'=4;;;; + ... 12 --component=temperature --warning='temperature,.*,45' WARNING: Temperature 'Temperature near Cavium (outlet)' value is 51.6 C - Temperature 'Temperature @ Cavium Core' value is 53.175 C | 'Temperature near CPLD (inlet)#hardware.temperature.celsius'=40.9C;0:45;;0.0;60.0 'Temperature near Cavium (outlet)#hardware.temperature.celsius'=51.6C;0:45;;0.0;60.0 'Temperature near Management Port (inlet)#hardware.temperature.celsius'=38.0C;0:45;;0.0;60.0 'Temperature near Switch (midboard)#hardware.temperature.celsius'=45.0C;0:45;;0.0;60.0 'Temperature @ Cavium Core#hardware.temperature.celsius'=53.175C;0:45;;0.0;85.0 'hardware.temperature.count'=5;;;; + ... 13 --component=temperature --critical='temperature,.*,45' CRITICAL: Temperature 'Temperature near Cavium (outlet)' value is 51.6 C - Temperature 'Temperature @ Cavium Core' value is 53.175 C | 'Temperature near CPLD (inlet)#hardware.temperature.celsius'=40.9C;;0:45;0.0;60.0 'Temperature near Cavium (outlet)#hardware.temperature.celsius'=51.6C;;0:45;0.0;60.0 'Temperature near Management Port (inlet)#hardware.temperature.celsius'=38.0C;;0:45;0.0;60.0 'Temperature near Switch (midboard)#hardware.temperature.celsius'=45.0C;;0:45;0.0;60.0 'Temperature @ Cavium Core#hardware.temperature.celsius'=53.175C;;0:45;0.0;85.0 'hardware.temperature.count'=5;;;; + ... 14 --component=voltage --warning='voltage,.*,0' WARNING: Voltage '0.85V Power Rail' value is 0.860666666667 V - Voltage '3.3V SD Power Rail' value is 3.332 V - Voltage '0.9V Power Rail' value is 0.904 V - Voltage '1.0V Power Rail' value is 1.006 V - Voltage '1.1V Power Rail' value is 1.09466666667 V - Voltage '1.2V Power Rail' value is 1.224 V - Voltage '1.5V Power Rail' value is 1.51066666667 V - Voltage '1.8V Power Rail' value is 1.812 V - Voltage '2.5V Power Rail' value is 2.504 V - Voltage '3.3V Power Rail' value is 3.332 V | '0.85V Power Rail#hardware.voltage.volt'=0.860666666667V;0:0;;0.76;0.94 '3.3V SD Power Rail#hardware.voltage.volt'=3.332V;0:0;;2.97;3.63 '0.9V Power Rail#hardware.voltage.volt'=0.904V;0:0;;0.81;0.99 '1.0V Power Rail#hardware.voltage.volt'=1.006V;0:0;;0.9;1.1 '1.1V Power Rail#hardware.voltage.volt'=1.09466666667V;0:0;;0.99;1.21 '1.2V Power Rail#hardware.voltage.volt'=1.224V;0:0;;1.08;1.32 '1.5V Power Rail#hardware.voltage.volt'=1.51066666667V;0:0;;1.35;1.65 '1.8V Power Rail#hardware.voltage.volt'=1.812V;0:0;;1.62;1.98 '2.5V Power Rail#hardware.voltage.volt'=2.504V;0:0;;2.25;2.75 '3.3V Power Rail#hardware.voltage.volt'=3.332V;0:0;;2.97;3.63 'hardware.voltage.count'=10;;;; + ... 15 --component=voltage --critical='voltage,.*,0' CRITICAL: Voltage '0.85V Power Rail' value is 0.860666666667 V - Voltage '3.3V SD Power Rail' value is 3.332 V - Voltage '0.9V Power Rail' value is 0.904 V - Voltage '1.0V Power Rail' value is 1.006 V - Voltage '1.1V Power Rail' value is 1.09466666667 V - Voltage '1.2V Power Rail' value is 1.224 V - Voltage '1.5V Power Rail' value is 1.51066666667 V - Voltage '1.8V Power Rail' value is 1.812 V - Voltage '2.5V Power Rail' value is 2.504 V - Voltage '3.3V Power Rail' value is 3.332 V | '0.85V Power Rail#hardware.voltage.volt'=0.860666666667V;;0:0;0.76;0.94 '3.3V SD Power Rail#hardware.voltage.volt'=3.332V;;0:0;2.97;3.63 '0.9V Power Rail#hardware.voltage.volt'=0.904V;;0:0;0.81;0.99 '1.0V Power Rail#hardware.voltage.volt'=1.006V;;0:0;0.9;1.1 '1.1V Power Rail#hardware.voltage.volt'=1.09466666667V;;0:0;0.99;1.21 '1.2V Power Rail#hardware.voltage.volt'=1.224V;;0:0;1.08;1.32 '1.5V Power Rail#hardware.voltage.volt'=1.51066666667V;;0:0;1.35;1.65 '1.8V Power Rail#hardware.voltage.volt'=1.812V;;0:0;1.62;1.98 '2.5V Power Rail#hardware.voltage.volt'=2.504V;;0:0;2.25;2.75 '3.3V Power Rail#hardware.voltage.volt'=3.332V;;0:0;2.97;3.63 'hardware.voltage.count'=10;;;; diff --git a/tests/network/paloalto/api/fixed_date.pm b/tests/network/paloalto/api/fixed_date.pm new file mode 100644 index 0000000000..7726d3a692 --- /dev/null +++ b/tests/network/paloalto/api/fixed_date.pm @@ -0,0 +1,10 @@ +package fixed_date; + +# Copyright 2026-Present Centreon +# Always use the same fixed date to test certificate validity + +BEGIN { + *CORE::GLOBAL::time = sub { 1738368000 }; +} + +1 diff --git a/tests/network/paloalto/api/ha.robot b/tests/network/paloalto/api/ha.robot new file mode 100644 index 0000000000..5140b34ae1 --- /dev/null +++ b/tests/network/paloalto/api/ha.robot @@ -0,0 +1,44 @@ +*** Settings *** +Documentation Check PaloAlto High Availability (HA) status. + +Resource ${CURDIR}${/}..${/}..${/}..${/}resources/import.resource + +Suite Setup Start Mockoon ${MOCKOON_JSON} +Suite Teardown Stop Mockoon +Test Timeout 120s + + +*** Variables *** +${MOCKOON_JSON} ${CURDIR}${/}mockoon-paloalto-api.json +${HOSTNAME} 127.0.0.1 +${APIPORT} 3000 +${CMD} ${CENTREON_PLUGINS} +... --plugin=network::paloalto::api::plugin +... --hostname=${HOSTNAME} +... --port=${APIPORT} +... --proto=http +... --mode=ha + +*** Test Cases *** +paloalto-ha ${tc} + [Tags] network paloalto api ha + ${command} Catenate + ... ${CMD} + ... --auth-type=api-key + ... --api-key=D@pAs$W@rD + ... ${extra_options} + + Ctn Run Command And Check Result As Strings ${command} ${expected_result} + + Examples: tc extra_options expected_result -- + ... 1 ${EMPTY} OK: PA-850 status: state sync: synchronized, HA1 link: up, HA2 link: up, HA mode: active-passive, build compatibility: Match + ... 2 --warning-peer-state='\\\%{peer_state} =~ /active/' WARNING: PA-850 status: peer state: active (priority: 100, conn: up) + ... 3 --critical-peer-state='\\\%{peer_state} =~ /active/' CRITICAL: PA-850 status: peer state: active (priority: 100, conn: up) + ... 4 --warning-state-sync='\\\%{state_sync} =~ /synchronized/' WARNING: PA-850 status: state sync: synchronized + ... 5 --critical-state-sync='\\\%{state_sync} =~ /synchronized/' CRITICAL: PA-850 status: state sync: synchronized + ... 6 --warning-ha1-link-status='\\\%{ha1_status} =~ /up/' WARNING: PA-850 status: HA1 link: up + ... 7 --critical-ha1-link-status='\\\%{ha1_status} =~ /up/' CRITICAL: PA-850 status: HA1 link: up + ... 8 --warning-ha2-link-status='\\\%{ha2_status} =~ /up/' WARNING: PA-850 status: HA2 link: up + ... 9 --critical-ha2-link-status='\\\%{ha2_status} =~ /up/' CRITICAL: PA-850 status: HA2 link: up + ... 10 --warning-build-compat='\\\%{build_compat} =~ /Match/' WARNING: PA-850 status: build compatibility: Match + ... 11 --critical-build-compat='\\\%{build_compat} =~ /Match/' CRITICAL: PA-850 status: build compatibility: Match diff --git a/tests/network/paloalto/api/ipsec.robot b/tests/network/paloalto/api/ipsec.robot new file mode 100644 index 0000000000..a88592ee11 --- /dev/null +++ b/tests/network/paloalto/api/ipsec.robot @@ -0,0 +1,43 @@ +*** Settings *** +Documentation Check PaloAlto IPsec VPN tunnels status and lifetime. + +Resource ${CURDIR}${/}..${/}..${/}..${/}resources/import.resource + +Suite Setup Start Mockoon ${MOCKOON_JSON} +Suite Teardown Stop Mockoon +Test Timeout 120s + + +*** Variables *** +${MOCKOON_JSON} ${CURDIR}${/}mockoon-paloalto-api.json +${HOSTNAME} 127.0.0.1 +${APIPORT} 3000 +${CMD} ${CENTREON_PLUGINS} +... --plugin=network::paloalto::api::plugin +... --hostname=${HOSTNAME} +... --port=${APIPORT} +... --proto=http +... --mode=ipsec + +*** Test Cases *** +paloalto-ipsec ${tc} + [Tags] network paloalto api tunnel + + ${command} Catenate + ... ${CMD} + ... --auth-type=api-key + ... --api-key=D@pAs$W@rD + ... ${extra_options} + + Ctn Run Command And Check Result As Strings ${command} ${expected_result} + + Examples: tc extra_options expected_result -- + ... 1 ${EMPTY} OK: Tunnels count: 3 - All tunnels are ok | 'tunnels.count'=3;;;0; 'Nom du tunnel 1#tunnel.remain.seconds'=1727s;;;0; 'Nom du tunnel 2#tunnel.remain.seconds'=1727s;;;0; 'Nom du tunnel 3#tunnel.remain.seconds'=1727s;;;0; + ... 2 --include-gateway-name='ateway 3' OK: Tunnels count: 1 - tunnel 'Nom du tunnel 3' remain: 1727 seconds, encryption: G256, gateway: Nom de la Gateway 3 | 'tunnels.count'=1;;;0; 'Nom du tunnel 3#tunnel.remain.seconds'=1727s;;;0; + ... 3 --exclude-gateway-name='ateway 1' OK: Tunnels count: 2 - All tunnels are ok | 'tunnels.count'=2;;;0; 'Nom du tunnel 2#tunnel.remain.seconds'=1727s;;;0; 'Nom du tunnel 3#tunnel.remain.seconds'=1727s;;;0; + ... 4 --include-tunnel-name='unnel 2' OK: Tunnels count: 1 - tunnel 'Nom du tunnel 2' remain: 1727 seconds, encryption: G256, gateway: Nom de la Gateway 2 | 'tunnels.count'=1;;;0; 'Nom du tunnel 2#tunnel.remain.seconds'=1727s;;;0; + ... 5 --exclude-tunnel-name='unnel 3' OK: Tunnels count: 2 - All tunnels are ok | 'tunnels.count'=2;;;0; 'Nom du tunnel 1#tunnel.remain.seconds'=1727s;;;0; 'Nom du tunnel 2#tunnel.remain.seconds'=1727s;;;0; + ... 6 --warning-tunnels-count=:1 WARNING: Tunnels count: 3 | 'tunnels.count'=3;0:1;;0; 'Nom du tunnel 1#tunnel.remain.seconds'=1727s;;;0; 'Nom du tunnel 2#tunnel.remain.seconds'=1727s;;;0; 'Nom du tunnel 3#tunnel.remain.seconds'=1727s;;;0; + ... 7 --critical-tunnels-count=:1 CRITICAL: Tunnels count: 3 | 'tunnels.count'=3;;0:1;0; 'Nom du tunnel 1#tunnel.remain.seconds'=1727s;;;0; 'Nom du tunnel 2#tunnel.remain.seconds'=1727s;;;0; 'Nom du tunnel 3#tunnel.remain.seconds'=1727s;;;0; + ... 8 --warning-remain-time=:1000 WARNING: tunnel 'Nom du tunnel 1' remain: 1727 seconds - tunnel 'Nom du tunnel 2' remain: 1727 seconds - tunnel 'Nom du tunnel 3' remain: 1727 seconds | 'tunnels.count'=3;;;0; 'Nom du tunnel 1#tunnel.remain.seconds'=1727s;0:1000;;0; 'Nom du tunnel 2#tunnel.remain.seconds'=1727s;0:1000;;0; 'Nom du tunnel 3#tunnel.remain.seconds'=1727s;0:1000;;0; + ... 9 --critical-remain-time=:1000 CRITICAL: tunnel 'Nom du tunnel 1' remain: 1727 seconds - tunnel 'Nom du tunnel 2' remain: 1727 seconds - tunnel 'Nom du tunnel 3' remain: 1727 seconds | 'tunnels.count'=3;;;0; 'Nom du tunnel 1#tunnel.remain.seconds'=1727s;;0:1000;0; 'Nom du tunnel 2#tunnel.remain.seconds'=1727s;;0:1000;0; 'Nom du tunnel 3#tunnel.remain.seconds'=1727s;;0:1000;0; diff --git a/tests/network/paloalto/api/licenses.robot b/tests/network/paloalto/api/licenses.robot new file mode 100644 index 0000000000..d4ea8bf163 --- /dev/null +++ b/tests/network/paloalto/api/licenses.robot @@ -0,0 +1,49 @@ +*** Settings *** +Documentation Check PaloAlto licenses status and expiration. + +Resource ${CURDIR}${/}..${/}..${/}..${/}resources/import.resource + +Suite Setup Start Mockoon ${MOCKOON_JSON} +Suite Teardown Stop Mockoon +Test Timeout 120s + + +*** Variables *** +${INJECT_PERL} -Mfixed_date -I${CURDIR} +${MOCKOON_JSON} ${CURDIR}${/}mockoon-paloalto-api.json +${HOSTNAME} 127.0.0.1 +${APIPORT} 3000 +${CMD} ${CENTREON_PLUGINS} +... --plugin=network::paloalto::api::plugin +... --hostname=${HOSTNAME} +... --port=${APIPORT} +... --proto=http +... --mode=licenses + +*** Test Cases *** +paloalto-licenses ${tc} + [Tags] network paloalto api licenses + + ${OLD_PERL5OPT}= Get Environment Variable PERL5OPT default= + Set Environment Variable PERL5OPT ${INJECT_PERL} ${OLD_PERL5OPT} + + ${command} Catenate + ... ${CMD} + ... --auth-type=api-key + ... --api-key=D@pAs$W@rD + ... ${extra_options} + + Ctn Run Command Without Connector And Check Result As Strings ${command} ${expected_result} + + Examples: tc extra_options expected_result -- + ... 1 ${EMPTY} CRITICAL: license 'Standard' expired: yes, 0 days left | 'licenses.count'=13;;;0; 'Advanced DNS Security#license.empiration.days'=185d;;@0:0;-1; 'Advanced Threat Prevention#license.empiration.days'=185d;;@0:0;-1; 'Advanced URL Filtering#license.empiration.days'=185d;;@0:0;-1; 'Advanced WildFire License#license.empiration.days'=185d;;@0:0;-1; 'DNS Security#license.empiration.days'=185d;;@0:0;-1; 'GlobalProtect Gateway#license.empiration.days'=185d;;@0:0;-1; 'GlobalProtect Portal#license.empiration.days'=-1d;;@0:0;-1; 'Logging Service#license.empiration.days'=1180d;;@0:0;-1; 'PAN-DB URL Filtering#license.empiration.days'=185d;;@0:0;-1; 'SD WAN#license.empiration.days'=185d;;@0:0;-1; 'Standard#license.empiration.days'=0d;;@0:0;-1; 'Threat Prevention#license.empiration.days'=185d;;@0:0;-1; 'WildFire License#license.empiration.days'=185d;;@0:0;-1; + ... 2 --include-license-name=Logging --warning-status='\\\%{expired}=~/no/' WARNING: license 'Logging Service' expired: no | 'licenses.count'=1;;;0; 'Logging Service#license.empiration.days'=1180d;;@0:0;-1; + ... 3 --include-license-name=Logging --critical-status='\\\%{expired}=~/no/' CRITICAL: license 'Logging Service' expired: no | 'licenses.count'=1;;;0; 'Logging Service#license.empiration.days'=1180d;;@0:0;-1; + ... 4 --include-license-name=GlobalProtect OK: Licenses count: 2 - All licenses are ok | 'licenses.count'=2;;;0; 'GlobalProtect Gateway#license.empiration.days'=185d;;@0:0;-1; 'GlobalProtect Portal#license.empiration.days'=-1d;;@0:0;-1; + ... 5 --warning-licenses-count=1000: --include-license-name=Logging WARNING: Licenses count: 1 | 'licenses.count'=1;1000:;;0; 'Logging Service#license.empiration.days'=1180d;;@0:0;-1; + ... 6 --critical-licenses-count=1000: --include-license-name=Logging CRITICAL: Licenses count: 1 | 'licenses.count'=1;;1000:;0; 'Logging Service#license.empiration.days'=1180d;;@0:0;-1; + ... 7 --include-license-name=SD OK: Licenses count: 1 - license 'SD WAN' expired: no, 185 days left | 'licenses.count'=1;;;0; 'SD WAN#license.empiration.days'=185d;;@0:0;-1; + ... 8 --include-license-name=Logging --warning-expiration-days=1000 WARNING: license 'Logging Service' 1180 days left | 'licenses.count'=1;;;0; 'Logging Service#license.empiration.days'=1180d;0:1000;@0:0;-1; + ... 9 --include-license-name=Logging --critical-expiration-days=1000 CRITICAL: license 'Logging Service' 1180 days left | 'licenses.count'=1;;;0; 'Logging Service#license.empiration.days'=1180d;;0:1000;-1; + ... 10 --include-license-name=Standard CRITICAL: license 'Standard' expired: yes, 0 days left | 'licenses.count'=1;;;0; 'Standard#license.empiration.days'=0d;;@0:0;-1; + ... 11 --include-license-name=Portal OK: Licenses count: 1 - license 'GlobalProtect Portal' expired: no, never expire | 'licenses.count'=1;;;0; 'GlobalProtect Portal#license.empiration.days'=-1d;;@0:0;-1; diff --git a/tests/network/paloalto/api/mockoon-paloalto-api.json b/tests/network/paloalto/api/mockoon-paloalto-api.json new file mode 100644 index 0000000000..c854211e63 --- /dev/null +++ b/tests/network/paloalto/api/mockoon-paloalto-api.json @@ -0,0 +1,263 @@ +{ + "uuid": "919382d8-0f30-447f-abcd-45c98e84d7fe", + "lastMigration": 33, + "name": "PaloAlto API Mock Server", + "endpointPrefix": "", + "latency": 0, + "port": 3000, + "hostname": "", + "folders": [], + "routes": [ + { + "uuid": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d", + "type": "http", + "documentation": "Generate API Key", + "method": "post", + "endpoint": "/api", + "responses": [ + { + "uuid": "b2c3d4e5-f6a7-4b8c-9d0e-1f2a3b4c5d6e", + "body": "\n \n D@pAs$W@rD\n \n", + "latency": 0, + "statusCode": 200, + "label": "keygen success", + "headers": [ + { + "key": "Content-Type", + "value": "application/xml" + } + ], + "bodyType": "INLINE", + "filePath": "", + "databucketID": "", + "sendFileAsBody": false, + "rules": [], + "rulesOperator": "OR", + "disableTemplating": false, + "fallbackTo404": false, + "default": false, + "crudKey": "id", + "callbacks": [] + } + ], + "responseMode": null, + "streamingMode": null, + "streamingInterval": 0 + }, + { + "uuid": "c3d4e5f6-a7b8-4c9d-0e1f-2a3b4c5d6e7f", + "type": "http", + "documentation": "Get HA Data", + "method": "get", + "endpoint": "/api", + "responses": [ + { + "uuid": "e5f6a7b8-c9d0-4e1f-2a3b-4c5d6e7f8a9b", + "body": "\n\n \n yes\n \n Active-Passive\n \n Mismatch\n 8868-8828\n 5.2.12\n 10.1.12\n dedicated-ha2\n 4875-5393\n no\n log-only\n 20240527.20193\n x.y.9.7/24\n configured\n PA-850\n Match\n x.y.7.10/24\n Match\n x.y.6.7/24\n f.g.h.i.j:10\n x.y.8.10/24\n Not Installed\n f.g.h.i.j:06\n 0\n 110\n 1\n passive\n 1\n 500\n Match\n Match\n Complete\n 500\n 1000\n 3000\n ethernet1/2\n 8000\n dedicated-ha1\n no\n x.y.56.7/24\n ethernet1/1\n 0\n Match\n 10000\n 0\n 8868-8828\n f.g.h.i.j:05\n 3889207\n 3\n \n auto\n 1\n \n \n ethernet\n yes\n 129-504\n Active-Passive\n Match\n Mismatch\n f.g.h.i.j:11\n Match\n \n \n 8868-8828\n 5.2.12\n 20240711.20198\n x.y.9.3\n 4875-5393\n PA-850\n x.y.7.6\n x.y.6.3\n x.y.8.6\n \n a.b.c.d.e:06\n 100\n active\n 1\n \n up\n heartbeat status\n \n User requested\n 10.1.12\n up\n a.b.c.d.e:10\n Not Installed\n x.y.56.6/24\n 1.0.3\n \n log-only\n yes\n up\n keep-alive status\n yes\n 0\n \n 8868-8828\n a.b.c.d.e:05\n \n up\n yes\n heartbeat status\n \n \n up\n yes\n keep-alive status\n \n 3889207\n \n a.b.c.d.e:11\n suspended\n yes\n 133-512\n Active-Passive\n \n up\n heartbeat status\n \n \n \n any\n yes\n \n \n \n \n up\n ethernet1/9\n \n \n up\n ethernet1/10\n \n \n all\n yes\n INSIDE Ports\n \n \n \n \n up\n ethernet1/11\n \n \n up\n ethernet1/12\n \n \n all\n yes\n OUTSIDE Ports\n \n \n \n \n \n any\n no\n \n \n \n synchronized\n yes\n \n \n", + "latency": 0, + "statusCode": 200, + "label": "HA", + "headers": [ + { + "key": "Content-Type", + "value": "application/xml" + } + ], + "bodyType": "INLINE", + "filePath": "", + "databucketID": "", + "sendFileAsBody": false, + "rules": [ + { + "target": "query", + "modifier": "cmd", + "value": "", + "invert": false, + "operator": "regex" + } + ], + "rulesOperator": "OR", + "disableTemplating": false, + "fallbackTo404": false, + "default": false, + "crudKey": "id", + "callbacks": [] + }, + { + "uuid": "7808dac1-5a12-41ca-9fba-ded37545fc73", + "body": "\n\n \n \n \n \n 1\n False\n True\n Power Supply #1 (left)\n True\n \n \n 1\n False\n True\n Power Supply #2 (right)\n True\n \n \n \n \n \n \n 1\n Temperature near CPLD (inlet)\n 0.0\n 60.0\n False\n 40.9\n \n \n 1\n Temperature near Cavium (outlet)\n 0.0\n 60.0\n False\n 51.6\n \n \n 1\n Temperature near Management Port (inlet)\n 0.0\n 60.0\n False\n 38.0\n \n \n 1\n Temperature near Switch (midboard)\n 0.0\n 60.0\n False\n 45.0\n \n \n 1\n Temperature @ Cavium Core\n 0.0\n 85.0\n False\n 53.175\n \n \n \n \n \n \n 1\n False\n Fan #1 RPM\n 9157\n 2500\n \n \n 1\n False\n Fan #2 RPM\n 9557\n 2500\n \n \n 1\n False\n Fan #3 RPM\n 9418\n 2500\n \n \n \n \n \n \n 1\n 0.85V Power Rail\n 0.76\n 0.860666666667\n False\n 0.94\n \n \n 1\n 0.9V Power Rail\n 0.81\n 0.904\n False\n 0.99\n \n \n 1\n 1.0V Power Rail\n 0.9\n 1.006\n False\n 1.1\n \n \n 1\n 1.1V Power Rail\n 0.99\n 1.09466666667\n False\n 1.21\n \n \n 1\n 1.2V Power Rail\n 1.08\n 1.224\n False\n 1.32\n \n \n 1\n 1.5V Power Rail\n 1.35\n 1.51066666667\n False\n 1.65\n \n \n 1\n 1.8V Power Rail\n 1.62\n 1.812\n False\n 1.98\n \n \n 1\n 2.5V Power Rail\n 2.25\n 2.504\n False\n 2.75\n \n \n 1\n 3.3V Power Rail\n 2.97\n 3.332\n False\n 3.63\n \n \n 1\n 3.3V SD Power Rail\n 2.97\n 3.332\n False\n 3.63\n \n \n \n \n", + "latency": 0, + "statusCode": 200, + "label": "ENVIRONMENT", + "headers": [ + { + "key": "Content-Type", + "value": "application/xml" + } + ], + "bodyType": "INLINE", + "filePath": "", + "databucketID": "", + "sendFileAsBody": false, + "rules": [ + { + "target": "query", + "modifier": "cmd", + "value": "", + "invert": false, + "operator": "regex" + } + ], + "rulesOperator": "OR", + "disableTemplating": false, + "fallbackTo404": false, + "default": false, + "crudKey": "id", + "callbacks": [] + }, + { + "uuid": "8909ebf2-6b23-52db-a0cb-3fde48656e84", + "body": "\n\n \n \n \n Advanced DNS Security\n Advanced DNS Security Subscription\n 123456789\n May 20, 2024\n August 05, 2025\n no\n \n \n \n Advanced Threat Prevention\n Advanced Threat Prevention\n 123456789\n May 20, 2024\n August 05, 2025\n no\n \n \n \n Advanced URL Filtering\n Palo Alto Networks Advanced URL License\n 123456789\n May 20, 2024\n August 05, 2025\n no\n \n \n \n Advanced WildFire License\n Access to Advanced WildFire signatures, logs, API\n 123456789\n May 20, 2024\n August 05, 2025\n no\n \n \n \n DNS Security\n Palo Alto Networks DNS Security License\n 123456789\n May 20, 2024\n August 05, 2025\n no\n I4876380\n \n \n GlobalProtect Gateway\n GlobalProtect Gateway License\n 123456789\n May 20, 2024\n August 05, 2025\n no\n \n \n \n GlobalProtect Portal\n GlobalProtect Portal License\n 123456789\n February 10, 2020\n Never\n no\n \n \n \n Logging Service\n Device Logging Service\n 123456789\n January 18, 2024\n April 26, 2028\n no\n \n <_Log_Storage_TB>1\n \n \n \n \n PAN-DB URL Filtering\n Palo Alto Networks URL Filtering License\n 123456789\n May 20, 2024\n August 05, 2025\n no\n I4287613\n \n \n SD WAN\n License to enable SD WAN feature\n 123456789\n May 20, 2024\n August 05, 2025\n no\n \n \n \n Standard\n 10 x 5 phone support; repair and replace hardware service\n 123456789\n February 25, 2021\n August 05, 2024\n yes\n \n \n \n Threat Prevention\n Threat Prevention\n 123456789\n May 20, 2024\n August 05, 2025\n no\n \n \n \n WildFire License\n WildFire signature feed, integrated WildFire logs, WildFire API\n 123456789\n May 20, 2024\n August 05, 2025\n no\n \n \n \n \n", + "latency": 0, + "statusCode": 200, + "label": "LICENSES", + "headers": [ + { + "key": "Content-Type", + "value": "application/xml" + } + ], + "bodyType": "INLINE", + "filePath": "", + "databucketID": "", + "sendFileAsBody": false, + "rules": [ + { + "target": "query", + "modifier": "cmd", + "value": "", + "invert": false, + "operator": "regex" + } + ], + "rulesOperator": "OR", + "disableTemplating": false, + "fallbackTo404": false, + "default": false, + "crudKey": "id", + "callbacks": [] + }, + { + "uuid": "3dddb89e-01f4-4048-92d2-81992c5c17b7", + "body": "\n\n \n \n Firewall_Name-01\n x.y.z.7\n unknown\n 255.255.255.0\n x.y.z.254\n no\n unknown\n fe80::x:y:z:a/64\n a:b:c:d:e\n \n 98 days, 23:42:29\n Firewall_Name-01\n 800\n PA-850\n 123456789\n non-cloud\n 10.1.12\n 5.2.12\n 129-504\n 2024/05/26 15:42:11 CEST\n 8868-8828\n 2024/07/08 23:25:41 CEST\n 4875-5393\n 2024/07/10 13:03:40 CEST\n 8868-8828\n 2024/07/08 23:25:41 CEST\n 0\n unknown\n paloaltonetworks\n 889843-893745\n 2024/07/11 14:56:58 CEST\n Disabled\n 20240527.20193\n 1695498753\n 2023-09-23 19:52:33\n 98-260\n 2023/05/23 00:41:22 CEST\n 10.1.2\n \n \n dlp-1.0.3\n \n \n 800\n off\n off\n Disabled\n normal\n Valid\n \n \n", + "latency": 0, + "statusCode": 200, + "label": "SYSTEM", + "headers": [ + { + "key": "Content-Type", + "value": "application/xml" + } + ], + "bodyType": "INLINE", + "filePath": "", + "databucketID": "", + "sendFileAsBody": false, + "rules": [ + { + "target": "query", + "modifier": "cmd", + "value": "", + "invert": false, + "operator": "regex" + } + ], + "rulesOperator": "OR", + "disableTemplating": false, + "fallbackTo404": false, + "default": false, + "crudKey": "id", + "callbacks": [] + }, + { + "uuid": "7f89e90c-80f8-4957-ac9a-26fe37fe81cd", + "body": "\n\n \n 60\n \n \n Unlimited\n 3600\n G256\n Addresse IP a.b.c.d\n Nom du tunnel 1\n ESP\n 2300285266\n 19\n 1430731122\n 1727\n 66\n \n Nom de la Gateway 1\n \n \n Unlimited\n 3600\n G256\n Addresse IP a.b.c.d\n Nom du tunnel 2\n ESP\n 2300285266\n 19\n 1430731122\n 1727\n 66\n \n Nom de la Gateway 2\n \n \n Unlimited\n 3600\n G256\n Addresse IP a.b.c.d\n Nom du tunnel 3\n ESP\n 2300285266\n 19\n 1430731122\n 1727\n 66\n \n Nom de la Gateway 3\n \n \n \n", + "latency": 0, + "statusCode": 200, + "label": "TUNNEL", + "headers": [ + { + "key": "Content-Type", + "value": "application/xml" + } + ], + "bodyType": "INLINE", + "filePath": "", + "databucketID": "", + "sendFileAsBody": false, + "rules": [ + { + "target": "query", + "modifier": "cmd", + "value": "", + "invert": false, + "operator": "regex" + } + ], + "rulesOperator": "OR", + "disableTemplating": false, + "fallbackTo404": false, + "default": false, + "crudKey": "id", + "callbacks": [] + } + ], + "responseMode": null, + "streamingMode": null, + "streamingInterval": 0 + } + ], + "rootChildren": [ + { + "type": "route", + "uuid": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d" + }, + { + "type": "route", + "uuid": "c3d4e5f6-a7b8-4c9d-0e1f-2a3b4c5d6e7f" + } + ], + "proxyMode": false, + "proxyHost": "", + "proxyRemovePrefix": false, + "tlsOptions": { + "enabled": false, + "type": "CERT", + "pfxPath": "", + "certPath": "", + "keyPath": "", + "caPath": "", + "passphrase": "" + }, + "cors": true, + "headers": [ + { + "key": "Content-Type", + "value": "application/xml" + } + ], + "proxyReqHeaders": [ + { + "key": "", + "value": "" + } + ], + "proxyResHeaders": [ + { + "key": "", + "value": "" + } + ], + "data": [], + "callbacks": [] +} \ No newline at end of file diff --git a/tests/network/paloalto/api/system.robot b/tests/network/paloalto/api/system.robot new file mode 100644 index 0000000000..79d9aef1c7 --- /dev/null +++ b/tests/network/paloalto/api/system.robot @@ -0,0 +1,47 @@ +*** Settings *** +Documentation Check PaloAlto system information and status. + +Resource ${CURDIR}${/}..${/}..${/}..${/}resources/import.resource + +Suite Setup Start Mockoon ${MOCKOON_JSON} +Suite Teardown Stop Mockoon +Test Timeout 120s + + +*** Variables *** +${MOCKOON_JSON} ${CURDIR}${/}mockoon-paloalto-api.json +${HOSTNAME} 127.0.0.1 +${APIPORT} 3000 +${CMD} ${CENTREON_PLUGINS} +... --plugin=network::paloalto::api::plugin +... --hostname=${HOSTNAME} +... --port=${APIPORT} +... --proto=http +... --mode=system + +*** Test Cases *** +paloalto-system ${tc} + [Tags] network paloalto api system + + ${command} Catenate + ... ${CMD} + ... --auth-type=api-key + ... --api-key=D@pAs$W@rD + ... ${extra_options} + + Ctn Run Command And Check Result As Strings ${command} ${expected_result} + + Examples: tc extra_options expected_result -- + ... 1 ${EMPTY} OK: System uptime: 8552549 seconds, certificate status: Valid, operational mode: normal, software version: 10.1.12, WildFire mode: Disabled | 'system.uptime.seconds'=8552549s;;;0; + ... 2 --warning-uptime=:1000 WARNING: System uptime: 8552549 seconds | 'system.uptime.seconds'=8552549s;0:1000;;0; + ... 3 --critical-uptime=:1000 CRITICAL: System uptime: 8552549 seconds | 'system.uptime.seconds'=8552549s;;0:1000;0; + ... 4 --warning-certificate-status='\\\%{cert_status} =~ /Valid/' WARNING: System certificate status: Valid | 'system.uptime.seconds'=8552549s;;;0; + ... 5 --critical-certificate-status='\\\%{cert_status} =~ /Valid/' CRITICAL: System certificate status: Valid | 'system.uptime.seconds'=8552549s;;;0; + ... 6 --warning-software-version='\\\%{sw_version} !~ /2\.0/' WARNING: System software version: 10.1.12 | 'system.uptime.seconds'=8552549s;;;0; + ... 7 --critical-software-version='\\\%{sw_version} !~ /2\.0/' CRITICAL: System software version: 10.1.12 | 'system.uptime.seconds'=8552549s;;;0; + ... 8 --warning-operational-mode='\\\%{operational_mode} =~ /normal/' WARNING: System operational mode: normal | 'system.uptime.seconds'=8552549s;;;0; + ... 9 --critical-operational-mode='\\\%{operational_mode} =~ /normal/' CRITICAL: System operational mode: normal | 'system.uptime.seconds'=8552549s;;;0; + ... 10 --warning-wildfire-mode='\\\%{wildfire_mode} =~ /disabled/i' WARNING: System WildFire mode: Disabled | 'system.uptime.seconds'=8552549s;;;0; + ... 11 --critical-wildfire-mode='\\\%{wildfire_mode} =~ /disabled/i' CRITICAL: System WildFire mode: Disabled | 'system.uptime.seconds'=8552549s;;;0; + + diff --git a/tests/resources/spellcheck/stopwords.txt b/tests/resources/spellcheck/stopwords.txt index f9a47607e4..b806b076bd 100644 --- a/tests/resources/spellcheck/stopwords.txt +++ b/tests/resources/spellcheck/stopwords.txt @@ -18,6 +18,7 @@ Alertmanager allCapacity Alletra allsteps +Alto Ansible --api-filter-orgs api.ip-label.net @@ -266,6 +267,7 @@ out-mcast out-ucast overprovisioning packetloss +Palo partiallyActive passthrough --patch-redhat @@ -407,6 +409,7 @@ WaaS --warning-cpu-utilization --warning-na --warning-total-cpu-utilization +WildFire WLAN WLC WSMAN