diff --git a/apps/cisco/dnac/restapi/custom/api.pm b/apps/cisco/dnac/restapi/custom/api.pm new file mode 100644 index 000000000..d04dbe641 --- /dev/null +++ b/apps/cisco/dnac/restapi/custom/api.pm @@ -0,0 +1,278 @@ +# +# 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 apps::cisco::dnac::restapi::custom::api; + +use strict; +use warnings; +use centreon::plugins::http; +use centreon::plugins::statefile; +use JSON::XS; +use Digest::MD5 qw(md5_hex); + +sub new { + my ($class, %options) = @_; + my $self = {}; + bless $self, $class; + + if (!defined($options{output})) { + print "Class Custom: Need to specify 'output' argument.\n"; + exit 3; + } + if (!defined($options{options})) { + $options{output}->add_option_msg(short_msg => "Class Custom: Need to specify 'options' argument."); + $options{output}->option_exit(); + } + + if (!defined($options{noptions})) { + $options{options}->add_options(arguments => { + 'api-username:s' => { name => 'api_username' }, + 'api-password:s' => { name => 'api_password' }, + 'hostname:s' => { name => 'hostname' }, + 'port:s' => { name => 'port' }, + 'proto:s' => { name => 'proto' }, + 'timeout:s' => { name => 'timeout' }, + 'unknown-http-status:s' => { name => 'unknown_http_status' }, + 'warning-http-status:s' => { name => 'warning_http_status' }, + 'critical-http-status:s' => { name => 'critical_http_status' } + }); + } + $options{options}->add_help(package => __PACKAGE__, sections => 'REST API OPTIONS', once => 1); + + $self->{output} = $options{output}; + $self->{http} = centreon::plugins::http->new(%options); + $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} = (defined($self->{option_results}->{hostname})) ? $self->{option_results}->{hostname} : ''; + $self->{port} = (defined($self->{option_results}->{port})) ? $self->{option_results}->{port} : 443; + $self->{proto} = (defined($self->{option_results}->{proto})) ? $self->{option_results}->{proto} : 'https'; + $self->{timeout} = (defined($self->{option_results}->{timeout})) ? $self->{option_results}->{timeout} : 10; + $self->{unknown_http_status} = (defined($self->{option_results}->{unknown_http_status})) ? $self->{option_results}->{unknown_http_status} : '%{http_code} < 200 or %{http_code} >= 300'; + $self->{warning_http_status} = (defined($self->{option_results}->{warning_http_status})) ? $self->{option_results}->{warning_http_status} : ''; + $self->{critical_http_status} = (defined($self->{option_results}->{critical_http_status})) ? $self->{option_results}->{critical_http_status} : ''; + $self->{api_username} = (defined($self->{option_results}->{api_username})) ? $self->{option_results}->{api_username} : ''; + $self->{api_password} = (defined($self->{option_results}->{api_password})) ? $self->{option_results}->{api_password} : ''; + + if ($self->{hostname} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --hostname option."); + $self->{output}->option_exit(); + } + if ($self->{api_username} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --api-username option."); + $self->{output}->option_exit(); + } + if ($self->{api_password} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --api-password option."); + $self->{output}->option_exit(); + } + + $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 build_options_for_httplib { + my ($self, %options) = @_; + + $self->{option_results}->{hostname} = $self->{hostname}; + $self->{option_results}->{port} = $self->{port}; + $self->{option_results}->{proto} = $self->{proto}; + $self->{option_results}->{timeout} = $self->{timeout}; +} + +sub settings { + my ($self, %options) = @_; + + $self->build_options_for_httplib(); + $self->{http}->add_header(key => 'Content-Type', value => 'application/json'); + $self->{http}->add_header(key => 'Accept', value => 'application/json'); + $self->{http}->set_options(%{$self->{option_results}}); +} + +sub json_decode { + my ($self, %options) = @_; + + my $decoded; + eval { + $decoded = JSON::XS->new->utf8->decode($options{content}); + }; + if ($@) { + $self->{output}->add_option_msg(short_msg => "Cannot decode json response: $@"); + $self->{output}->option_exit(); + } + + return $decoded; +} + +sub clean_session_token { + my ($self, %options) = @_; + + my $datas = { last_timestamp => time() }; + $options{statefile}->write(data => $datas); + $self->{session_token} = undef; + $self->{http}->add_header(key => 'X-Auth-Token', value => undef); +} + +sub authenticate { + my ($self, %options) = @_; + + my $has_cache_file = $options{statefile}->read(statefile => 'cisco_dnac_' . md5_hex($self->{option_results}->{hostname}) . '_' . md5_hex($self->{option_results}->{api_username})); + my $session_token = $options{statefile}->get(name => 'session_token'); + + if ($has_cache_file == 0 || !defined($session_token)) { + my ($content) = $self->{http}->request( + method => 'POST', + url_path => '/dna/system/api/v1/auth/token', + credentials => 1, + basic => 1, + username => $self->{api_username}, + password => $self->{api_password}, + warning_status => '', + unknown_status => '', + critical_status => '' + ); + if ($self->{http}->get_code() < 200 || $self->{http}->get_code() >= 300) { + $self->{output}->add_option_msg(short_msg => "login error [code: '" . $self->{http}->get_code() . "'] [message: '" . $self->{http}->get_message() . "']"); + $self->{output}->option_exit(); + } + + my $decoded = $self->json_decode(content => $content); + if (!defined($decoded->{Token})) { + $self->{output}->add_option_msg(short_msg => 'error retrieving session_token'); + $self->{output}->option_exit(); + } + + $session_token = $decoded->{Token}; + my $datas = { last_timestamp => time(), session_token => $session_token }; + $options{statefile}->write(data => $datas); + } + + $self->{session_token} = $session_token; + $self->{http}->add_header(key => 'X-Auth-Token', value => $self->{session_token}); +} + +sub request_api { + my ($self, %options) = @_; + + $self->settings(); + if (!defined($self->{session_token})) { + $self->authenticate(statefile => $self->{cache}); + } + + my ($content) = $self->{http}->request( + url_path => '/dna/intent/api/v1' . $options{endpoint}, + get_param => $options{get_param}, + unknown_status => '', + warning_status => '', + critical_status => '' + ); + + if ($self->{http}->get_code() < 200 || $self->{http}->get_code() >= 300) { + $self->clean_session_token(statefile => $self->{cache}); + $self->authenticate(statefile => $self->{cache}); + ($content) = $self->{http}->request( + url_path => '/dna/intent/api/v1' . $options{endpoint}, + get_param => $options{get_param}, + unknown_status => $self->{unknown_http_status}, + warning_status => $self->{warning_http_status}, + critical_status => $self->{critical_http_status} + ); + } + + my $decoded = $self->json_decode(content => $content); + if (!defined($decoded)) { + $self->{output}->add_option_msg(short_msg => 'error while retrieving data (add --debug option for detailed message)'); + $self->{output}->option_exit(); + } + + return $decoded; +} + +1; + +__END__ + +=head1 NAME + +Firepower Management Center Rest API + +=head1 REST API OPTIONS + +Firepower Management Center Rest API + +=over 8 + +=item B<--hostname> + +Set hostname. + +=item B<--port> + +Port used (Default: 443) + +=item B<--proto> + +Specify https if needed (Default: 'https') + +=item B<--api-username> + +Set username. + +=item B<--api-password> + +Set password. + +=item B<--timeout> + +Set timeout in seconds (Default: 10). + +=back + +=head1 DESCRIPTION + +B. + +=cut diff --git a/apps/cisco/dnac/restapi/mode/discovery.pm b/apps/cisco/dnac/restapi/mode/discovery.pm new file mode 100644 index 000000000..a3c807cdc --- /dev/null +++ b/apps/cisco/dnac/restapi/mode/discovery.pm @@ -0,0 +1,128 @@ +# +# 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 apps::cisco::dnac::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} = 'network-device'; + } + if ($self->{option_results}->{resource_type} !~ /^network-device$/) { + $self->{output}->add_option_msg(short_msg => 'unknown resource type'); + $self->{output}->option_exit(); + } +} + +sub discovery_network_device { + my ($self, %options) = @_; + + my $devices = $options{custom}->request_api( + endpoint => '/network-device' + ); + + my $disco_data = []; + foreach my $device (@{$devices->{response}}) { + my $node = {}; + $node->{uuid} = $device->{id}; + $node->{mac_address} = $device->{macAddress}; + $node->{hostname} = $device->{hostname}; + $node->{serial} = $device->{serialNumber}; + $node->{software_type} = $device->{softwareType}; + $node->{software_version} = $device->{softwareVersion}; + $node->{role} = $device->{role}; + $node->{family} = $device->{family}; + + push @$disco_data, $node; + } + + return $disco_data; +} + +sub run { + my ($self, %options) = @_; + + my $disco_stats; + $disco_stats->{start_time} = time(); + + my $results = $self->discovery_network_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: 'network-device'). + +=back + +=cut diff --git a/apps/cisco/dnac/restapi/mode/networkdevices.pm b/apps/cisco/dnac/restapi/mode/networkdevices.pm new file mode 100644 index 000000000..fdb022456 --- /dev/null +++ b/apps/cisco/dnac/restapi/mode/networkdevices.pm @@ -0,0 +1,215 @@ +# +# 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 apps::cisco::dnac::restapi::mode::networkdevices; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +sub custom_health_output { + my ($self, %options) = @_; + + return sprintf( + '%.2f%% (%s on %s)', + $self->{result_values}->{prct}, + $self->{result_values}->{count}, + $self->{result_values}->{total} + ); +} + +sub category_long_output { + my ($self, %options) = @_; + + return "checking network category '" . $options{instance_value}->{name} . "'"; +} + +sub prefix_category_output { + my ($self, %options) = @_; + + return "Network category '" . $options{instance_value}->{name} . "' "; +} + +sub prefix_global_output { + my ($self, %options) = @_; + + return 'Network devices '; +} + +sub prefix_good_output { + my ($self, %options) = @_; + + return 'good devices: '; +} + +sub prefix_fair_output { + my ($self, %options) = @_; + + return 'fair devices: '; +} + +sub prefix_bad_output { + my ($self, %options) = @_; + + return 'bad devices: '; +} + +sub prefix_unmonitored_output { + my ($self, %options) = @_; + + return 'unmonitored devices: '; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'global', type => 0, cb_prefix_output => 'prefix_global_output', skipped_code => { -10 => 1 } }, + { name => 'categories', type => 3, cb_prefix_output => 'prefix_categorie_output', cb_long_output => 'category_long_output', indent_long_output => ' ', message_multiple => 'All network categories are ok', + group => [ + { name => 'good', type => 0, cb_prefix_output => 'prefix_good_output', skipped_code => { -10 => 1 } }, + { name => 'fair', type => 0, cb_prefix_output => 'prefix_fair_output', skipped_code => { -10 => 1 } }, + { name => 'bad', type => 0, cb_prefix_output => 'prefix_bad_output', skipped_code => { -10 => 1 } }, + { name => 'unmonitored', type => 0, cb_prefix_output => 'prefix_unmonitored_output', skipped_code => { -10 => 1 } } + ] + } + ]; + + $self->{maps_counters}->{global} = [ + { label => 'devices-total', nlabel => 'network.devices.total.count', display_ok => 0, set => { + key_values => [ { name => 'devices_total' } ], + output_template => 'total: %s', + perfdatas => [ + { template => '%s', min => 0 } + ] + } + } + ]; + + foreach (('good', 'fair', 'bad', 'unmonitored')) { + $self->{maps_counters}->{$_} = [ + { label => 'category-devices-health-' . $_ . '-usage', nlabel => 'category.network.devices.health.' . $_ . '.count', set => { + key_values => [ { name => 'count' }, { name => 'prct' }, { name => 'total' } ], + closure_custom_output => $self->can('custom_health_output'), + perfdatas => [ + { template => '%d', min => 0, max => 'total', label_extra_instance => 1 } + ] + } + }, + { label => 'category-devices-health-' . $_ . '-usage-prct', nlabel => 'category.network.devices.health.' . $_ . '.percentage', display_ok => 0, set => { + key_values => [ { name => 'count' }, { name => 'prct' }, { name => 'total' } ], + closure_custom_output => $self->can('custom_health_output'), + perfdatas => [ + { template => '%.2f', min => 0, max => 100, label_extra_instance => 1 } + ] + } + } + ]; + } +} + +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 => { + 'filter-category-name:s' => { name => 'filter_category_name' } + }); + + return $self; +} + +sub manage_selection { + my ($self, %options) = @_; + + my $networks = $options{custom}->request_api( + endpoint => '/network-health' + ); + + $self->{global} = { devices_total => 0 }; + $self->{categories} = {}; + + foreach (@{$networks->{healthDistirubution}}) { + if (defined($self->{option_results}->{filter_category_name}) && $self->{option_results}->{filter_category_name} ne '' && + $_->{category} !~ /$self->{option_results}->{filter_category_name}/) { + $self->{output}->output_add(long_msg => "skipping category '" . $_->{category} . "': no matching filter.", debug => 1); + next; + } + + $self->{categories}->{ $_->{category} } = { + name => $_->{category}, + good => { + name => $_->{category}, + total => $_->{totalCount}, + count => $_->{goodCount}, + prct => $_->{goodCount} * 100 / $_->{totalCount} + }, + fair => { + name => $_->{category}, + total => $_->{totalCount}, + count => $_->{fairCount}, + prct => $_->{fairCount} * 100 / $_->{totalCount} + }, + bad => { + name => $_->{category}, + total => $_->{totalCount}, + count => $_->{badCount}, + prct => $_->{badCount} * 100 / $_->{totalCount} + }, + unmonitored => { + name => $_->{category}, + total => $_->{totalCount}, + count => $_->{unmonCount}, + prct => $_->{unmonCount} * 100 / $_->{totalCount} + } + }; + + $self->{global}->{devices_total} += $_->{totalCount}; + } +} + +1; + +__END__ + +=head1 MODE + +Check network devices by categories. + +=over 8 + +=item B<--filter-category-name> + +Filter categories by name (Can be a regexp). + +=item B<--warning-*> B<--critical-*> + +Thresholds. +Can be: 'category-devices-health-good-usage', 'category-devices-health-good-usage-prct', +'category-devices-health-unmonitored-usage', 'category-devices-health-unmonitored-usage-prct', +'category-devices-health-fair-usage', 'category-devices-health-fair-usage-prct', +'category-devices-health-bad-usage', 'category-devices-health-bad-usage-prct', +'devices-total'. + +=back + +=cut diff --git a/apps/cisco/dnac/restapi/mode/sites.pm b/apps/cisco/dnac/restapi/mode/sites.pm new file mode 100644 index 000000000..06482ba4f --- /dev/null +++ b/apps/cisco/dnac/restapi/mode/sites.pm @@ -0,0 +1,215 @@ +# +# 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 apps::cisco::dnac::restapi::mode::sites; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; +use centreon::plugins::misc; + +sub custom_health_output { + my ($self, %options) = @_; + + return sprintf( + 'healthy %.2f%% (%s on %s)', + $self->{result_values}->{prct}, + $self->{result_values}->{count}, + $self->{result_values}->{total} + ); +} + +sub site_long_output { + my ($self, %options) = @_; + + return "checking site '" . $options{instance_value}->{name} . "'"; +} + +sub prefix_site_output { + my ($self, %options) = @_; + + return "Site '" . $options{instance_value}->{name} . "' "; +} + +sub prefix_devices_output { + my ($self, %options) = @_; + + return 'devices: '; +} + +sub prefix_clients_output { + my ($self, %options) = @_; + + return 'clients: '; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'sites', type => 3, cb_prefix_output => 'prefix_site_output', cb_long_output => 'site_long_output', indent_long_output => ' ', message_multiple => 'All sites are ok', + group => [ + { name => 'devices', type => 0, cb_prefix_output => 'prefix_devices_output', skipped_code => { -10 => 1 } }, + { name => 'clients', type => 0, cb_prefix_output => 'prefix_clients_output', skipped_code => { -10 => 1 } } + ] + } + ]; + + $self->{maps_counters}->{devices} = [ + { label => 'site-devices-healthy-usage', nlabel => 'site.network.devices.healthy.count', set => { + key_values => [ { name => 'count' }, { name => 'prct' }, { name => 'total' } ], + closure_custom_output => $self->can('custom_health_output'), + perfdatas => [ + { template => '%d', min => 0, max => 'total', label_extra_instance => 1 } + ] + } + }, + { label => 'site-devices-healthy-usage-prct', nlabel => 'site.network.devices.healthy.percentage', display_ok => 0, set => { + key_values => [ { name => 'count' }, { name => 'prct' }, { name => 'total' } ], + closure_custom_output => $self->can('custom_health_output'), + perfdatas => [ + { template => '%.2f', min => 0, max => 100, label_extra_instance => 1 } + ] + } + } + ]; + + $self->{maps_counters}->{clients} = [ + { label => 'site-clients-healthy-usage', nlabel => 'site.clients.healthy.count', set => { + key_values => [ { name => 'count' }, { name => 'prct' }, { name => 'total' } ], + closure_custom_output => $self->can('custom_health_output'), + perfdatas => [ + { template => '%d', min => 0, max => 'total', label_extra_instance => 1 } + ] + } + }, + { label => 'site-clients-healthy-usage-prct', nlabel => 'site.clients.healthy.percentage', display_ok => 0, set => { + key_values => [ { name => 'count' }, { name => 'prct' }, { name => 'total' } ], + closure_custom_output => $self->can('custom_health_output'), + perfdatas => [ + { template => '%.2f', min => 0, max => 100, label_extra_instance => 1 } + ] + } + } + ]; +} + +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 => { + 'filter-site-name:s' => { name => 'filter_site_name' }, + 'use-site-fullname' => { name => 'use_site_fullname' } + }); + + return $self; +} + +sub get_fullname { + my ($self, %options) = @_; + + return $options{name} if (!defined($options{parent_id})); + my $name = $options{name}; + foreach (@{$options{response}}) { + if ($_->{siteId} eq $options{parent_id}) { + $name = $self->get_fullname( + response => $options{response}, + name => centreon::plugins::misc::trim($_->{siteName}) . '>' . $name, + parent_id => $_->{parentSiteId} + ); + last; + } + } + + return $name; +} + +sub manage_selection { + my ($self, %options) = @_; + + my $sites = $options{custom}->request_api( + endpoint => '/site-health' + ); + + $self->{categories} = {}; + foreach (@{$sites->{response}}) { + my $site_fullname = $self->get_fullname( + response => $sites->{response}, + name => centreon::plugins::misc::trim($_->{siteName}), + parent_id => $_->{parentSiteId} + ); + my $site_name = defined($self->{option_results}->{use_site_fullname}) ? $site_fullname : centreon::plugins::misc::trim($_->{siteName}); + if (defined($self->{option_results}->{filter_site_name}) && $self->{option_results}->{filter_site_name} ne '' && + $site_name !~ /$self->{option_results}->{filter_site_name}/) { + $self->{output}->output_add(long_msg => "skipping site '" . $site_name . "': no matching filter.", debug => 1); + next; + } + + $self->{sites}->{ $site_name } = { + name => $site_name, + devices => { + name => $site_name, + total => $_->{numberOfNetworkDevice}, + count => int($_->{numberOfNetworkDevice} * $_->{healthyNetworkDevicePercentage} / 100), + prct => $_->{healthyNetworkDevicePercentage} + }, + clients => { + name => $site_name, + total => $_->{numberOfClients}, + count => int($_->{numberOfClients} * $_->{healthyClientsPercentage} / 100), + prct => $_->{healthyClientsPercentage} + } + }; + } +} + +1; + +__END__ + +=head1 MODE + +Check sites. + +=over 8 + +=item B<--filter-site-name> + +Filter sites by name (Can be a regexp). + +=item B<--use-site-fullname> + +Use site fullname (with parents name). + +=item B<--warning-*> B<--critical-*> + +Thresholds. +Can be: 'category-devices-health-good-usage', 'category-devices-health-good-usage-prct', +'category-devices-health-unmonitored-usage', 'category-devices-health-unmonitored-usage-prct', +'category-devices-health-fair-usage', 'category-devices-health-fair-usage-prct', +'category-devices-health-bad-usage', 'category-devices-health-bad-usage-prct', +'devices-total'. + +=back + +=cut diff --git a/apps/cisco/dnac/restapi/plugin.pm b/apps/cisco/dnac/restapi/plugin.pm new file mode 100644 index 000000000..9a849e667 --- /dev/null +++ b/apps/cisco/dnac/restapi/plugin.pm @@ -0,0 +1,51 @@ +# +# 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 apps::cisco::dnac::restapi::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} = '0.1'; + $self->{modes} = { + 'discovery' => 'apps::cisco::dnac::restapi::mode::discovery', + 'network-devices' => 'apps::cisco::dnac::restapi::mode::networkdevices', + 'sites' => 'apps::cisco::dnac::restapi::mode::sites' + }; + + $self->{custom_modes}->{api} = 'apps::cisco::dnac::restapi::custom::api'; + return $self; +} + +1; + +__END__ + +=head1 PLUGIN DESCRIPTION + +Check Cisco DNA Center using Rest API. + +=cut