From 20fa7e96942fdeb86204dffa67c0ecbbf19dba56 Mon Sep 17 00:00:00 2001 From: qgarnier Date: Mon, 23 Nov 2020 10:34:30 +0100 Subject: [PATCH] add cisco fmc (#2364) --- .../cisco/firepower/fmc/restapi/custom/api.pm | 2 +- .../firepower/fmc/restapi/mode/devices.pm | 73 +++++++-- .../firepower/fmc/restapi/mode/discovery.pm | 138 ++++++++++++++++++ 3 files changed, 198 insertions(+), 15 deletions(-) create mode 100644 centreon-plugins/network/cisco/firepower/fmc/restapi/mode/discovery.pm diff --git a/centreon-plugins/network/cisco/firepower/fmc/restapi/custom/api.pm b/centreon-plugins/network/cisco/firepower/fmc/restapi/custom/api.pm index a6baa01c6..ac495c51d 100644 --- a/centreon-plugins/network/cisco/firepower/fmc/restapi/custom/api.pm +++ b/centreon-plugins/network/cisco/firepower/fmc/restapi/custom/api.pm @@ -201,7 +201,7 @@ sub request_api { } my ($content) = $self->{http}->request( - url_path => '/api/fmc_platform/v1' . $options{endpoint}, + url_path => '/api/' . $options{endpoint_domain} . '/v1' . $options{endpoint}, get_param => $options{get_param}, unknown_status => '', warning_status => '', diff --git a/centreon-plugins/network/cisco/firepower/fmc/restapi/mode/devices.pm b/centreon-plugins/network/cisco/firepower/fmc/restapi/mode/devices.pm index a280bc72a..010af0bfd 100644 --- a/centreon-plugins/network/cisco/firepower/fmc/restapi/mode/devices.pm +++ b/centreon-plugins/network/cisco/firepower/fmc/restapi/mode/devices.pm @@ -35,19 +35,19 @@ sub custom_device_status_output { sub domain_long_output { my ($self, %options) = @_; - return "checking domain '" . $options{instance_value}->{display} . "'"; + return "checking domain '" . $options{instance_value}->{name} . "'"; } sub prefix_domain_output { my ($self, %options) = @_; - return "Domain '" . $options{instance_value}->{display} . "' "; + return "Domain '" . $options{instance_value}->{name} . "' "; } sub prefix_device_output { my ($self, %options) = @_; - return "device '" . $options{instance_value}->{display} . "' "; + return "device '" . $options{instance_value}->{name} . "' "; } sub prefix_global_output { @@ -63,7 +63,7 @@ sub set_counters { { name => 'global', type => 0, cb_prefix_output => 'prefix_global_output', skipped_code => { -10 => 1 } }, { name => 'domains', type => 3, cb_prefix_output => 'prefix_domain_output', cb_long_output => 'domain_long_output', indent_long_output => ' ', message_multiple => 'All domains are ok', group => [ - { name => 'devices', display_long => 1, cb_prefix_output => 'prefix_device_output', message_multiple => 'All devices are ok', type => 1, skipped_code => { -10 => 1 } }, + { name => 'devices', display_long => 1, cb_prefix_output => 'prefix_device_output', message_multiple => 'devices are ok', type => 1, skipped_code => { -10 => 1 } }, ] } ]; @@ -80,7 +80,7 @@ sub set_counters { ]; foreach (('green', 'black', 'blue', 'red', 'yellow')) { push @{$self->{maps_counters}->{global}}, - { label => 'devices-status-' . $_, nlabel => 'devices.status. ' . $_ . '.count', display_ok => 0, set => { + { label => 'devices-status-' . $_, nlabel => 'devices.status.' . $_ . '.count', display_ok => 0, set => { key_values => [ { name => 'devices_' . $_ }, { name => 'devices_total' } ], output_template => $_ . ': %s', perfdatas => [ @@ -97,7 +97,7 @@ sub set_counters { warning_default => '%{status} =~ /yellow/i', critical_default => '%{status} =~ /red|black/i', set => { - key_values => [ { name => 'status' }, { name => 'display' } ], + key_values => [ { name => 'status' }, { name => 'name' } ], closure_custom_output => $self->can('custom_device_status_output'), closure_custom_perfdata => sub { return 0; }, closure_custom_threshold_check => \&catalog_status_threshold_ng @@ -123,7 +123,8 @@ sub manage_selection { my ($self, %options) = @_; my $domains = $options{custom}->request_api( - endpoint => '/info/domain', + endpoint_domain => 'fmc_platform', + endpoint => '/info/domain' ); $self->{global} = { @@ -131,14 +132,42 @@ sub manage_selection { devices_red => 0, devices_yellow => 0, devices_green => 0, devices_blue => 0 }; - $self->{devices} = {}; + $self->{domains} = {}; - if (defined($self->{option_results}->{filter_device_name}) && $self->{option_results}->{filter_device_name} ne '' && - $_->{name} !~ /$self->{option_results}->{filter_device_name}/) { - $self->{output}->output_add(long_msg => "skipping device '" . $_->{name} . "': no matching filter.", debug => 1); - next; + foreach my $domain (@{$domains->{items}}) { + if (defined($self->{option_results}->{filter_domain_name}) && $self->{option_results}->{filter_domain_name} ne '' && + $domain->{name} !~ /$self->{option_results}->{filter_domain_name}/) { + $self->{output}->output_add(long_msg => "skipping domain '" . $domain->{name} . "': no matching filter.", debug => 1); + next; + } + + $self->{domains}->{ $domain->{name} } = { + name => $domain->{name}, + devices => {} + }; + + my $devices = $options{custom}->request_api( + endpoint_domain => 'fmc_config', + endpoint => '/domain/' . $domain->{uuid} . '/devices/devicerecords', + get_param => ['expanded=true'] + ); + + foreach my $device (@{$devices->{items}}) { + if (defined($self->{option_results}->{filter_device_name}) && $self->{option_results}->{filter_device_name} ne '' && + $device->{name} !~ /$self->{option_results}->{filter_device_name}/) { + $self->{output}->output_add(long_msg => "skipping device '" . $device->{name} . "': no matching filter.", debug => 1); + next; + } + + $self->{domains}->{ $domain->{name} }->{devices}->{ $device->{name} } = { + name => $device->{name}, + status => $device->{healthStatus} + }; + $self->{global}->{'devices_' . lc($device->{name})}++ + if (defined($self->{global}->{'devices_' . lc($device->{name})})); + $self->{global}->{devices_total}++; + } } - } 1; @@ -159,10 +188,26 @@ Filter devices by domain name (Can be a regexp). Filter devices by name (Can be a regexp). +=item B<--unknown-status> + +Set unknown threshold for status. +Can used special variables like: %{status}, %{name} + +=item B<--warning-status> + +Set warning threshold for status (Default: '%{status} =~ /yellow/i'). +Can used special variables like: %{status}, %{name} + +=item B<--critical-status> + +Set critical threshold for status (Default: '%{status} =~ /red|black/i'). +Can used special variables like: %{status}, %{name} + =item B<--warning-*> B<--critical-*> Thresholds. -Can be: 'black', 'red', 'orange'. +Can be: 'devices-total', 'devices-status-green', 'devices-status-black', 'devices-status-blue', +'devices-status-red', 'devices-status-yellow'. =back diff --git a/centreon-plugins/network/cisco/firepower/fmc/restapi/mode/discovery.pm b/centreon-plugins/network/cisco/firepower/fmc/restapi/mode/discovery.pm new file mode 100644 index 000000000..d02aa583d --- /dev/null +++ b/centreon-plugins/network/cisco/firepower/fmc/restapi/mode/discovery.pm @@ -0,0 +1,138 @@ +# +# Copyright 2020 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::cisco::firepower::fmc::restapi::mode::discovery; + +use base qw(centreon::plugins::mode); + +use strict; +use warnings; +use JSON::XS; + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $options{options}->add_options(arguments => { + 'resource-type:s' => { name => 'resource_type' }, + 'prettify' => { name => 'prettify' } + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::init(%options); + + if (!defined($self->{option_results}->{resource_type}) || $self->{option_results}->{resource_type} eq '') { + $self->{option_results}->{resource_type} = 'device'; + } + if ($self->{option_results}->{resource_type} !~ /^device$/) { + $self->{output}->add_option_msg(short_msg => 'unknown resource type'); + $self->{output}->option_exit(); + } +} + +sub discovery_device { + my ($self, %options) = @_; + + my $domains = $options{custom}->request_api( + endpoint_domain => 'fmc_platform', + endpoint => '/info/domain' + ); + + my $disco_data = []; + foreach my $domain (@{$domains->{items}}) { + my $devices = $options{custom}->request_api( + endpoint_domain => 'fmc_config', + endpoint => '/domain/' . $domain->{uuid} . '/devices/devicerecords', + get_param => ['expanded=true'] + ); + + foreach my $device (@{$devices->{items}}) { + my $node = {}; + $node->{uuid} = $device->{id}; + $node->{name} = $device->{name}; + $node->{description} = $device->{description}; + $node->{health_status} = $device->{healthStatus}; + $node->{sw_version} = $device->{sw_version}; + $node->{model} = $device->{model}; + $node->{hostName} = $device->{hostName}; + $node->{domain_name} = $domain->{name}; + $node->{chassis_serial} = defined($device->{metadata}->{chassisData}->{chassisSerialNo}) ? $device->{metadata}->{chassisData}->{chassisSerialNo} : '-'; + + push @$disco_data, $node; + } + } + + return $disco_data; +} + +sub run { + my ($self, %options) = @_; + + my $disco_stats; + $disco_stats->{start_time} = time(); + + my $results = $self->discovery_device( + custom => $options{custom} + ); + + $disco_stats->{end_time} = time(); + $disco_stats->{duration} = $disco_stats->{end_time} - $disco_stats->{start_time}; + $disco_stats->{discovered_items} = scalar(@$results); + $disco_stats->{results} = $results; + + my $encoded_data; + eval { + if (defined($self->{option_results}->{prettify})) { + $encoded_data = JSON::XS->new->utf8->pretty->encode($disco_stats); + } else { + $encoded_data = JSON::XS->new->utf8->encode($disco_stats); + } + }; + if ($@) { + $encoded_data = '{"code":"encode_error","message":"Cannot encode discovered data into JSON format"}'; + } + + $self->{output}->output_add(short_msg => $encoded_data); + $self->{output}->display(nolabel => 1, force_ignore_perfdata => 1); + $self->{output}->exit(); +} + +1; + +__END__ + +=head1 MODE + +Resources discovery. + +=over 8 + +=item B<--resource-type> + +Choose the type of resources to discover (Can be: 'device'). + +=back + +=cut