diff --git a/cloud/vmware/velocloud/restapi/custom/api.pm b/cloud/vmware/velocloud/restapi/custom/api.pm index 2c38cc1ec..9d747e645 100644 --- a/cloud/vmware/velocloud/restapi/custom/api.pm +++ b/cloud/vmware/velocloud/restapi/custom/api.pm @@ -24,6 +24,7 @@ use strict; use warnings; use centreon::plugins::http; use JSON::XS; +use DateTime; sub new { my ($class, %options) = @_; @@ -48,6 +49,7 @@ sub new { "password:s" => { name => 'password' }, "operator-user" => { name => 'operator_user' }, "api-path:s" => { name => 'api_path' }, + "timeframe:s" => { name => 'timeframe' }, "timeout:s" => { name => 'timeout' }, }); } @@ -220,11 +222,11 @@ sub request_api { } $self->{output}->output_add(long_msg => "URL: '" . $self->{proto} . '://' . $self->{hostname} . ':' . - $self->{port} . $options{url_path} . "'", debug => 1); + $self->{port} . $self->{api_path} . $options{path} . "'", debug => 1); my $content = $self->{http}->request( method => $options{method}, - url_path => $options{url_path}, + url_path => $self->{api_path} . $options{path}, query_form_post => $encoded_form_post, critical_status => '', warning_status => '', unknown_status => '' ); @@ -255,7 +257,7 @@ sub list_edges { my $response = $self->request_api( method => 'POST', - url_path => $self->{api_path} . '/enterprise/getEnterpriseEdges', + path => '/enterprise/getEnterpriseEdges', query_form_post => { enterpriseId => $self->{entreprise_id} } ); @@ -264,14 +266,112 @@ sub list_edges { sub list_links { my ($self, %options) = @_; - - my $response = $self->request_api( + + if (!defined($self->{entreprise_id})) { + $self->get_entreprise_id(); + } + + my $results = $self->request_api( method => 'POST', - url_path => $self->{api_path} . '/metrics/getEdgeLinkMetrics', - query_form_post => { id => $options{edge_id} } + path => '/metrics/getEdgeLinkMetrics', + query_form_post => { + enterpriseId => $self->{entreprise_id}, + edgeId => $options{edge_id}, + metrics => [ 'bytesRx' ], + } ); - - return $response; + + return $results; +} + +sub get_links_metrics { + my ($self, %options) = @_; + + if (!defined($self->{entreprise_id})) { + $self->get_entreprise_id(); + } + + my $start_time = DateTime->now->subtract(seconds => $options{timeframe})->iso8601.'Z'; + + my $results = $self->request_api( + method => 'POST', + path => '/metrics/getEdgeLinkMetrics', + query_form_post => { + enterpriseId => $self->{entreprise_id}, + edgeId => $options{edge_id}, + metrics => [ 'bytesRx', 'bytesTx', 'bestJitterMsRx', 'bestJitterMsTx', + 'bestLatencyMsRx', 'bestLatencyMsTx', 'bestLossPctRx', 'bestLossPctTx' ], + interval => { + start => $start_time + }, + } + ); + + return $results; +} + +sub get_apps_metrics { + my ($self, %options) = @_; + + my $start_time = DateTime->now->subtract(seconds => $options{timeframe})->iso8601.'Z'; + + my $results = $self->request_api( + method => 'POST', + path => '/metrics/getEdgeAppMetrics', + query_form_post => { + enterpriseId => $self->{entreprise_id}, + edgeId => $options{edge_id}, + metrics => [ 'bytesRx', 'bytesTx', 'packetsRx', 'packetsTx' ], + interval => { + start => $start_time + }, + } + ); + + return $results; +} + +sub get_links_qoe { + my ($self, %options) = @_; + + my $start_time = DateTime->now->subtract(seconds => $options{timeframe})->iso8601.'Z'; + + my $results = $self->request_api( + method => 'POST', + path => '/linkQualityEvent/getLinkQualityEvents', + query_form_post => { + enterpriseId => $self->{entreprise_id}, + edgeId => $options{edge_id}, + debug => 'false', + individualScores => 'false', + maxSamples => '15', + interval => { + start => $start_time + }, + } + ); + + return $results; +} + +sub get_categories_metrics { + my ($self, %options) = @_; + + my $start_time = DateTime->now->subtract(seconds => $options{timeframe})->iso8601.'Z'; + + my $results = $self->request_api( + method => 'POST', + path => '/metrics/getEdgeCategoryMetrics', + query_form_post => { + id => $options{edge_id}, + metrics => [ 'bytesRx', 'bytesTx', 'packetsRx', 'packetsTx' ], + interval => { + start => $start_time + }, + } + ); + + return $results; } sub DESTROY { @@ -326,6 +426,10 @@ Set if the user is an operator. API base url path (Default: '/portal/rest'). +=item B<--timeframe> + +Set timeframe in seconds (Default: 900). + =item B<--timeout> Set HTTP timeout in seconds (Default: '10'). diff --git a/cloud/vmware/velocloud/restapi/mode/applicationusage.pm b/cloud/vmware/velocloud/restapi/mode/applicationusage.pm new file mode 100644 index 000000000..33df95818 --- /dev/null +++ b/cloud/vmware/velocloud/restapi/mode/applicationusage.pm @@ -0,0 +1,204 @@ +# +# Copyright 2019 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 cloud::vmware::velocloud::restapi::mode::applicationusage; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'edges', type => 3, cb_prefix_output => 'prefix_edge_output', cb_long_output => 'long_output', + message_multiple => 'All edges applications usage are ok', indent_long_output => ' ', + group => [ + { name => 'apps', display_long => 1, cb_prefix_output => 'prefix_app_output', + message_multiple => 'All applications usage are ok', type => 1 }, + ] + } + ]; + + $self->{maps_counters}->{apps} = [ + { label => 'traffic-in', nlabel => 'application.traffic.in.bitspersecond', set => { + key_values => [ { name => 'traffic_in' }, { name => 'display' }, { name => 'id' } ], + output_change_bytes => 2, + output_template => 'Traffic In: %s %s/s', + perfdatas => [ + { value => 'traffic_in_absolute', template => '%s', + min => 0, unit => 'b/s', label_extra_instance => 1 }, + ], + } + }, + { label => 'traffic-out', nlabel => 'application.traffic.out.bitspersecond', set => { + key_values => [ { name => 'traffic_out' }, { name => 'display' }, { name => 'id' } ], + output_change_bytes => 2, + output_template => 'Traffic Out: %s %s/s', + perfdatas => [ + { value => 'traffic_out_absolute', template => '%s', + min => 0, unit => 'b/s', label_extra_instance => 1 }, + ], + } + }, + { label => 'packets-in', nlabel => 'application.packets.in.persecond', set => { + key_values => [ { name => 'packets_in' }, { name => 'display' }, { name => 'id' } ], + output_template => 'Packets In: %.2f packets/s', + perfdatas => [ + { value => 'packets_in_absolute', template => '%.2f', + min => 0, unit => 'packets/s', label_extra_instance => 1 }, + ], + } + }, + { label => 'packets-out', nlabel => 'application.packets.out.persecond', set => { + key_values => [ { name => 'packets_out' }, { name => 'display' }, { name => 'id' } ], + output_template => 'Packets Out: %.2f packets/s', + perfdatas => [ + { value => 'packets_out_absolute', template => '%.2f', + min => 0, unit => 'packets/s', label_extra_instance => 1 }, + ], + } + }, + ]; +} + +sub prefix_edge_output { + my ($self, %options) = @_; + + return "Edge '" . $options{instance_value}->{display} . "' "; +} + +sub prefix_app_output { + my ($self, %options) = @_; + + return "Application '" . $options{instance_value}->{display} . "' [Id: " . $options{instance_value}->{id} . "] "; +} + +sub long_output { + my ($self, %options) = @_; + + return "Checking edge '" . $options{instance_value}->{display} . "' [Id: " . $options{instance_value}->{id} . "] "; +} + +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-edge-name:s" => { name => 'filter_edge_name' }, + "filter-application-name:s" => { name => 'filter_application_name' }, + "warning-status:s" => { name => 'warning_status', default => '' }, + "critical-status:s" => { name => 'critical_status', default => '' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + $self->{timeframe} = defined($self->{option_results}->{timeframe}) ? $self->{option_results}->{timeframe} : 900; + + $self->change_macros(macros => ['warning_status', 'critical_status']); +} + +sub manage_selection { + my ($self, %options) = @_; + + $self->{edges} = {}; + + my $results = $options{custom}->list_edges; + + foreach my $edge (@{$results}) { + if (defined($self->{option_results}->{filter_edge_name}) && $self->{option_results}->{filter_edge_name} ne '' && + $edge->{name} !~ /$self->{option_results}->{filter_edge_name}/) { + $self->{output}->output_add(long_msg => "skipping '" . $edge->{name} . "'.", debug => 1); + next; + } + + $self->{edges}->{$edge->{name}}->{id} = $edge->{id}; + $self->{edges}->{$edge->{name}}->{display} = $edge->{name}; + + my $apps = $options{custom}->get_apps_metrics( + edge_id => $edge->{id}, + timeframe => $self->{timeframe} + ); + + foreach my $app (@{$apps}) { + if (defined($self->{option_results}->{filter_application_name}) && + $self->{option_results}->{filter_application_name} ne '' && + $app->{name} !~ /$self->{option_results}->{filter_application_name}/) { + $self->{output}->output_add(long_msg => "skipping '" . $edge->{id} . "'.", debug => 1); + next; + } + + $self->{edges}->{$edge->{name}}->{apps}->{$app->{name}} = { + id => $app->{application}, + display => $app->{name}, + traffic_out => int($app->{bytesTx} * 8 / $self->{timeframe}), + traffic_in => int($app->{bytesRx} * 8 / $self->{timeframe}), + packets_out => $app->{packetsTx} / $self->{timeframe}, + packets_in => $app->{packetsRx} / $self->{timeframe}, + }; + } + } + + if (scalar(keys %{$self->{edges}}) <= 0) { + $self->{output}->add_option_msg(short_msg => "No edge found."); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check applications usage per edges. + +=over 8 + +=item B<--filter-edge-name> + +Filter edge by name (Can be a regexp). + +=item B<--filter-application-name> + +Filter application by name (Can be a regexp). + +=item B<--warning-*> + +Threshold warning. +Can be: 'traffic-in', 'traffic-out', +'packets-in', 'packets-out'. + +=item B<--critical-*> + +Threshold critical. +Can be: 'traffic-in', 'traffic-out', +'packets-in', 'packets-out'. + +=back + +=cut diff --git a/cloud/vmware/velocloud/restapi/mode/categoryusage.pm b/cloud/vmware/velocloud/restapi/mode/categoryusage.pm new file mode 100644 index 000000000..cc56f0301 --- /dev/null +++ b/cloud/vmware/velocloud/restapi/mode/categoryusage.pm @@ -0,0 +1,204 @@ +# +# Copyright 2019 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 cloud::vmware::velocloud::restapi::mode::categoryusage; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'edges', type => 3, cb_prefix_output => 'prefix_edge_output', cb_long_output => 'long_output', + message_multiple => 'All edges categories usage are ok', indent_long_output => ' ', + group => [ + { name => 'categories', display_long => 1, cb_prefix_output => 'prefix_category_output', + message_multiple => 'All categories usage are ok', type => 1 }, + ] + } + ]; + + $self->{maps_counters}->{categories} = [ + { label => 'traffic-in', nlabel => 'category.traffic.in.bitspersecond', set => { + key_values => [ { name => 'traffic_in' }, { name => 'display' }, { name => 'id' } ], + output_change_bytes => 2, + output_template => 'Traffic In: %s %s/s', + perfdatas => [ + { value => 'traffic_in_absolute', template => '%s', + min => 0, unit => 'b/s', label_extra_instance => 1 }, + ], + } + }, + { label => 'traffic-out', nlabel => 'category.traffic.out.bitspersecond', set => { + key_values => [ { name => 'traffic_out' }, { name => 'display' }, { name => 'id' } ], + output_change_bytes => 2, + output_template => 'Traffic Out: %s %s/s', + perfdatas => [ + { value => 'traffic_out_absolute', template => '%s', + min => 0, unit => 'b/s', label_extra_instance => 1 }, + ], + } + }, + { label => 'packets-in', nlabel => 'category.packets.in.persecond', set => { + key_values => [ { name => 'packets_in' }, { name => 'display' }, { name => 'id' } ], + output_template => 'Packets In: %.2f packets/s', + perfdatas => [ + { value => 'packets_in_absolute', template => '%.2f', + min => 0, unit => 'packets/s', label_extra_instance => 1 }, + ], + } + }, + { label => 'packets-out', nlabel => 'category.packets.out.persecond', set => { + key_values => [ { name => 'packets_out' }, { name => 'display' }, { name => 'id' } ], + output_template => 'Packets Out: %.2f packets/s', + perfdatas => [ + { value => 'packets_out_absolute', template => '%.2f', + min => 0, unit => 'packets/s', label_extra_instance => 1 }, + ], + } + }, + ]; +} + +sub prefix_edge_output { + my ($self, %options) = @_; + + return "Edge '" . $options{instance_value}->{display} . "' "; +} + +sub prefix_category_output { + my ($self, %options) = @_; + + return "Category '" . $options{instance_value}->{display} . "' [Id: " . $options{instance_value}->{id} . "] "; +} + +sub long_output { + my ($self, %options) = @_; + + return "Checking edge '" . $options{instance_value}->{display} . "' [Id: " . $options{instance_value}->{id} . "] "; +} + +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-edge-name:s" => { name => 'filter_edge_name' }, + "filter-category-name:s" => { name => 'filter_category_name' }, + "warning-status:s" => { name => 'warning_status', default => '' }, + "critical-status:s" => { name => 'critical_status', default => '' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + $self->{timeframe} = defined($self->{option_results}->{timeframe}) ? $self->{option_results}->{timeframe} : 900; + + $self->change_macros(macros => ['warning_status', 'critical_status']); +} + +sub manage_selection { + my ($self, %options) = @_; + + $self->{edges} = {}; + + my $results = $options{custom}->list_edges; + + foreach my $edge (@{$results}) { + if (defined($self->{option_results}->{filter_edge_name}) && $self->{option_results}->{filter_edge_name} ne '' && + $edge->{name} !~ /$self->{option_results}->{filter_edge_name}/) { + $self->{output}->output_add(long_msg => "skipping '" . $edge->{name} . "'.", debug => 1); + next; + } + + $self->{edges}->{$edge->{name}}->{id} = $edge->{id}; + $self->{edges}->{$edge->{name}}->{display} = $edge->{name}; + + my $categories = $options{custom}->get_categories_metrics( + edge_id => $edge->{id}, + timeframe => $self->{timeframe} + ); + + foreach my $category (@{$categories}) { + if (defined($self->{option_results}->{filter_category_name}) && + $self->{option_results}->{filter_category_name} ne '' && + $category->{name} !~ /$self->{option_results}->{filter_category_name}/) { + $self->{output}->output_add(long_msg => "skipping '" . $edge->{id} . "'.", debug => 1); + next; + } + + $self->{edges}->{$edge->{name}}->{categories}->{$category->{name}} = { + id => $category->{category}, + display => $category->{name}, + traffic_out => int($category->{bytesTx} * 8 / $self->{timeframe}), + traffic_in => int($category->{bytesRx} * 8 / $self->{timeframe}), + packets_out => $category->{packetsTx} / $self->{timeframe}, + packets_in => $category->{packetsRx} / $self->{timeframe}, + }; + } + } + + if (scalar(keys %{$self->{edges}}) <= 0) { + $self->{output}->add_option_msg(short_msg => "No edge found."); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check categories usage per edges. + +=over 8 + +=item B<--filter-edge-name> + +Filter edge by name (Can be a regexp). + +=item B<--filter-category-name> + +Filter category by name (Can be a regexp). + +=item B<--warning-*> + +Threshold warning. +Can be: 'traffic-in', 'traffic-out', +'packets-in', 'packets-out'. + +=item B<--critical-*> + +Threshold critical. +Can be: 'traffic-in', 'traffic-out', +'packets-in', 'packets-out'. + +=back + +=cut diff --git a/cloud/vmware/velocloud/restapi/mode/edgeqoe.pm b/cloud/vmware/velocloud/restapi/mode/edgeqoe.pm new file mode 100644 index 000000000..797bf3932 --- /dev/null +++ b/cloud/vmware/velocloud/restapi/mode/edgeqoe.pm @@ -0,0 +1,231 @@ +# +# Copyright 2019 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 cloud::vmware::velocloud::restapi::mode::edgeqoe; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'edges', type => 3, cb_prefix_output => 'prefix_edge_output', cb_long_output => 'long_output', + message_multiple => 'All edges links QOE are ok', indent_long_output => ' ', + group => [ + { name => 'global', type => 0 }, + { name => 'links', display_long => 1, cb_prefix_output => 'prefix_link_output', + message_multiple => 'All links QOE are ok', type => 1 }, + ] + } + ]; + + $self->{maps_counters}->{global} = [ + { label => 'qoe-voice', nlabel => 'qoe.voice.count', set => { + key_values => [ { name => 'voice' } ], + output_template => 'Voice QOE: %s', + perfdatas => [ + { value => 'voice_absolute', template => '%s', + min => 0, max => 10, label_extra_instance => 1 }, + ], + } + }, + { label => 'qoe-video', nlabel => 'qoe.video.count', set => { + key_values => [ { name => 'video' } ], + output_template => 'Video QOE: %s', + perfdatas => [ + { value => 'video_absolute', template => '%s', + min => 0, max => 10, label_extra_instance => 1 }, + ], + } + }, + { label => 'qoe-transactional', nlabel => 'qoe.transactional.count', set => { + key_values => [ { name => 'transactional' } ], + output_template => 'Transactional QOE: %s', + perfdatas => [ + { value => 'transactional_absolute', template => '%s', + min => 0, max => 10, label_extra_instance => 1 }, + ], + } + }, + ]; + $self->{maps_counters}->{links} = [ + { label => 'qoe-voice', nlabel => 'link.qoe.voice.count', set => { + key_values => [ { name => 'voice' }, { name => 'display' }, { name => 'id' } ], + output_template => 'Voice QOE: %s', + perfdatas => [ + { value => 'voice_absolute', template => '%s', + min => 0, max => 10, label_extra_instance => 1 }, + ], + } + }, + { label => 'qoe-video', nlabel => 'link.qoe.video.count', set => { + key_values => [ { name => 'video' }, { name => 'display' }, { name => 'id' } ], + output_template => 'Video QOE: %s', + perfdatas => [ + { value => 'video_absolute', template => '%s', + min => 0, max => 10, label_extra_instance => 1 }, + ], + } + }, + { label => 'qoe-transactional', nlabel => 'link.qoe.transactional.count', set => { + key_values => [ { name => 'transactional' }, { name => 'display' }, { name => 'id' } ], + output_template => 'Transactional QOE: %s', + perfdatas => [ + { value => 'transactional_absolute', template => '%s', + min => 0, max => 10, label_extra_instance => 1 }, + ], + } + }, + ]; +} + +sub prefix_edge_output { + my ($self, %options) = @_; + + return "Edge '" . $options{instance_value}->{display} . "' "; +} + +sub prefix_link_output { + my ($self, %options) = @_; + + return "Link '" . $options{instance_value}->{display} . "' [Id: " . $options{instance_value}->{id} . "] "; +} + +sub long_output { + my ($self, %options) = @_; + + return "Checking edge '" . $options{instance_value}->{display} . "' [Id: " . $options{instance_value}->{id} . "] "; +} + +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-edge-name:s" => { name => 'filter_edge_name' }, + "filter-link-name:s" => { name => 'filter_link_name' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + $self->{timeframe} = defined($self->{option_results}->{timeframe}) ? $self->{option_results}->{timeframe} : 900; + + $self->change_macros(macros => ['warning_status', 'critical_status']); +} + +sub manage_selection { + my ($self, %options) = @_; + + $self->{edges} = {}; + + my $results = $options{custom}->list_edges; + + foreach my $edge (@{$results}) { + if (defined($self->{option_results}->{filter_edge_name}) && $self->{option_results}->{filter_edge_name} ne '' && + $edge->{name} !~ /$self->{option_results}->{filter_edge_name}/) { + $self->{output}->output_add(long_msg => "skipping '" . $edge->{name} . "'.", debug => 1); + next; + } + + $self->{edges}->{$edge->{name}}->{id} = $edge->{id}; + $self->{edges}->{$edge->{name}}->{display} = $edge->{name}; + + my $links = $options{custom}->list_links( + edge_id => $edge->{id} + ); + + my $qoes = $options{custom}->get_links_qoe( + edge_id => $edge->{id}, + timeframe => $self->{timeframe} + ); + + next if (ref($qoes) ne 'HASH'); + + $self->{edges}->{$edge->{name}}->{global} = { + voice => $qoes->{overallLinkQuality}->{score}->{0}, + video => $qoes->{overallLinkQuality}->{score}->{1}, + transactional => $qoes->{overallLinkQuality}->{score}->{2}, + }; + + foreach my $link (@{$links}) { + next if (!defined($qoes->{$link->{link}->{internalId}})); + + if (defined($self->{option_results}->{filter_link_name}) && $self->{option_results}->{filter_link_name} ne '' && + $link->{link}->{displayName} !~ /$self->{option_results}->{filter_link_name}/) { + $self->{output}->output_add(long_msg => "skipping '" . $edge->{id} . "'.", debug => 1); + next; + } + + $self->{edges}->{$edge->{name}}->{links}->{$link->{link}->{displayName}} = { + id => $link->{linkId}, + display => $link->{link}->{displayName}, + voice => $qoes->{$link->{link}->{internalId}}->{score}->{0}, + video => $qoes->{$link->{link}->{internalId}}->{score}->{1}, + transactional => $qoes->{$link->{link}->{internalId}}->{score}->{2}, + }; + } + } + + if (scalar(keys %{$self->{edges}}) <= 0) { + $self->{output}->add_option_msg(short_msg => "No edge found."); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check links QOE before and global QOE after VeloCloud Enhancements. + +=over 8 + +=item B<--filter-edge-name> + +Filter edge by name (Can be a regexp). + +=item B<--filter-link-name> + +Filter link by name (Can be a regexp). + +=item B<--warning-*> + +Threshold warning. +Can be: 'qoe-voice', 'qoe-video', 'qoe-transactional'. + +=item B<--critical-*> + +Threshold critical. +Can be: 'qoe-voice', 'qoe-video', 'qoe-transactional'. + +=back + +=cut diff --git a/cloud/vmware/velocloud/restapi/mode/edgestatus.pm b/cloud/vmware/velocloud/restapi/mode/edgestatus.pm index 59567e7d1..8a2b2290e 100644 --- a/cloud/vmware/velocloud/restapi/mode/edgestatus.pm +++ b/cloud/vmware/velocloud/restapi/mode/edgestatus.pm @@ -81,7 +81,6 @@ sub new { $options{options}->add_options(arguments => { "filter-name:s" => { name => 'filter_name' }, - "filter-id:s" => { name => 'filter_id' }, "warning-status:s" => { name => 'warning_status', default => '' }, "critical-status:s" => { name => 'critical_status', default => '' }, }); @@ -109,11 +108,6 @@ sub manage_selection { $self->{output}->output_add(long_msg => "skipping '" . $edge->{name} . "'.", debug => 1); next; } - if (defined($self->{option_results}->{filter_id}) && $self->{option_results}->{filter_id} ne '' && - $edge->{id} !~ /$self->{option_results}->{filter_id}/) { - $self->{output}->output_add(long_msg => "skipping '" . $edge->{id} . "'.", debug => 1); - next; - } $self->{edges}->{$edge->{id}} = { display => $edge->{name}, @@ -144,10 +138,6 @@ Check edge status. Filter edge by name (Can be a regexp). -=item B<--filter-id> - -Filter edge by id (Can be a regexp). - =item B<--warning-status> Set warning threshold for status (Default: ''). diff --git a/cloud/vmware/velocloud/restapi/mode/linkstatus.pm b/cloud/vmware/velocloud/restapi/mode/linkstatus.pm index ae9fc88a4..cf9a22e5c 100644 --- a/cloud/vmware/velocloud/restapi/mode/linkstatus.pm +++ b/cloud/vmware/velocloud/restapi/mode/linkstatus.pm @@ -25,7 +25,6 @@ use base qw(centreon::plugins::templates::counter); use strict; use warnings; use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold); -use Digest::MD5 qw(md5_hex); sub custom_status_output { my ($self, %options) = @_; @@ -37,7 +36,6 @@ sub custom_status_output { sub custom_status_calc { my ($self, %options) = @_; - $self->{result_values}->{interface} = $options{new_datas}->{$self->{instance} . '_interface'}; $self->{result_values}->{state} = $options{new_datas}->{$self->{instance} . '_state'}; $self->{result_values}->{vpn_state} = $options{new_datas}->{$self->{instance} . '_vpn_state'}; $self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_display'}; @@ -50,7 +48,7 @@ sub set_counters { $self->{maps_counters_type} = [ { name => 'edges', type => 3, cb_prefix_output => 'prefix_edge_output', cb_long_output => 'long_output', - message_multiple => 'All edges links are ok', indent_long_output => ' ', + message_multiple => 'All edges links status are ok', indent_long_output => ' ', group => [ { name => 'links', display_long => 1, cb_prefix_output => 'prefix_link_output', message_multiple => 'All links status are ok', type => 1 }, @@ -60,7 +58,7 @@ sub set_counters { $self->{maps_counters}->{links} = [ { label => 'status', set => { - key_values => [ { name => 'interface' }, { name => 'state' }, { name => 'vpn_state' }, + key_values => [ { name => 'state' }, { name => 'vpn_state' }, { name => 'display' }, { name => 'id' } ], closure_custom_calc => $self->can('custom_status_calc'), closure_custom_output => $self->can('custom_status_output'), @@ -68,80 +66,6 @@ sub set_counters { closure_custom_threshold_check => \&catalog_status_threshold, } }, - { label => 'traffic-in', nlabel => 'link.traffic.in.bitspersecond', set => { - key_values => [ { name => 'traffic_in', diff => 1 }, { name => 'id' } ], - per_second => 1, output_change_bytes => 2, - output_template => 'Traffic In: %s %s/s', - perfdatas => [ - { value => 'traffic_in_per_second', template => '%.2f', - min => 0, unit => 'b/s', label_extra_instance => 1, instance_use => 'id_absolute' }, - ], - } - }, - { label => 'traffic-out', nlabel => 'link.traffic.out.bitspersecond', set => { - key_values => [ { name => 'traffic_out', diff => 1 }, { name => 'id' } ], - per_second => 1, output_change_bytes => 2, - output_template => 'Traffic Out: %s %s/s', - perfdatas => [ - { value => 'traffic_out_per_second', template => '%.2f', - min => 0, unit => 'b/s', label_extra_instance => 1, instance_use => 'id_absolute' }, - ], - } - }, - { label => 'latency-in', nlabel => 'link.latency.in.milliseconds', set => { - key_values => [ { name => 'latency_in' }, { name => 'id' } ], - output_template => 'Latency In: %.2f ms', - perfdatas => [ - { value => 'latency_in_absolute', template => '%.2f', - min => 0, unit => 'ms', label_extra_instance => 1, instance_use => 'id_absolute' }, - ], - } - }, - { label => 'latency-out', nlabel => 'link.latency.out.milliseconds', set => { - key_values => [ { name => 'latency_out' }, { name => 'id' } ], - output_template => 'Latency Out: %.2f ms', - perfdatas => [ - { value => 'latency_out_absolute', template => '%.2f', - min => 0, unit => 'ms', label_extra_instance => 1, instance_use => 'id_absolute' }, - ], - } - }, - { label => 'jitter-in', nlabel => 'link.jitter.in.milliseconds', set => { - key_values => [ { name => 'jitter_in' }, { name => 'id' } ], - output_template => 'Jitter In: %.2f ms', - perfdatas => [ - { value => 'jitter_in_absolute', template => '%.2f', - min => 0, unit => 'ms', label_extra_instance => 1, instance_use => 'id_absolute' }, - ], - } - }, - { label => 'jitter-out', nlabel => 'link.jitter.out.milliseconds', set => { - key_values => [ { name => 'jitter_out' }, { name => 'id' } ], - output_template => 'Jitter Out: %.2f ms', - perfdatas => [ - { value => 'jitter_out_absolute', template => '%.2f', - min => 0, unit => 'ms', label_extra_instance => 1, instance_use => 'id_absolute' }, - ], - } - }, - { label => 'packet-loss-in', nlabel => 'link.packet.loss.in.percentage', set => { - key_values => [ { name => 'packet_loss_in' }, { name => 'id' } ], - output_template => 'Packet Loss In: %.2f%%', - perfdatas => [ - { value => 'packet_loss_in_absolute', template => '%.2f', - min => 0, unit => '%', label_extra_instance => 1, instance_use => 'id_absolute' }, - ], - } - }, - { label => 'packet-loss-out', nlabel => 'link.packet.loss.out.percentage', set => { - key_values => [ { name => 'packet_loss_out' }, { name => 'id' } ], - output_template => 'Packet Loss Out: %.2f%%', - perfdatas => [ - { value => 'packet_loss_out_absolute', template => '%.2f', - min => 0, unit => '%', label_extra_instance => 1, instance_use => 'id_absolute' }, - ], - } - }, ]; } @@ -165,13 +89,12 @@ sub long_output { sub new { my ($class, %options) = @_; - my $self = $class->SUPER::new(package => __PACKAGE__, %options, statefile => 1, force_new_perfdata => 1); + my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1); bless $self, $class; $options{options}->add_options(arguments => { "filter-edge-name:s" => { name => 'filter_edge_name' }, - "filter-edge-id:s" => { name => 'filter_edge_id' }, - "filter-link-id:s" => { name => 'filter_link_id' }, + "filter-link-name:s" => { name => 'filter_link_name' }, "warning-status:s" => { name => 'warning_status', default => '' }, "critical-status:s" => { name => 'critical_status', default => '' }, }); @@ -183,6 +106,8 @@ sub check_options { my ($self, %options) = @_; $self->SUPER::check_options(%options); + $self->{timeframe} = defined($self->{option_results}->{timeframe}) ? $self->{option_results}->{timeframe} : 900; + $self->change_macros(macros => ['warning_status', 'critical_status']); } @@ -191,11 +116,6 @@ sub manage_selection { $self->{edges} = {}; - $self->{cache_name} = "velocloud_" . $self->{mode} . '_' . $options{custom}->get_connection_infos() . '_' . - (defined($self->{option_results}->{filter_counters}) ? md5_hex($self->{option_results}->{filter_counters}) : md5_hex('all')) . '_' . - (defined($self->{option_results}->{filter_name}) ? md5_hex($self->{option_results}->{filter_name}) : md5_hex('all')) . '_' . - (defined($self->{option_results}->{filter_id}) ? md5_hex($self->{option_results}->{filter_id}) : md5_hex('all')); - my $results = $options{custom}->list_edges; foreach my $edge (@{$results}) { @@ -204,38 +124,27 @@ sub manage_selection { $self->{output}->output_add(long_msg => "skipping '" . $edge->{name} . "'.", debug => 1); next; } - if (defined($self->{option_results}->{filter_edge_id}) && $self->{option_results}->{filter_edge_id} ne '' && - $edge->{id} !~ /$self->{option_results}->{filter_edge_id}/) { - $self->{output}->output_add(long_msg => "skipping '" . $edge->{id} . "'.", debug => 1); - next; - } - $self->{edges}->{$edge->{id}}->{id} = $edge->{id}; - $self->{edges}->{$edge->{id}}->{display} = $edge->{name}; + $self->{edges}->{$edge->{name}}->{id} = $edge->{id}; + $self->{edges}->{$edge->{name}}->{display} = $edge->{name}; - my $links = $options{custom}->list_links(edge_id => $edge->{id}); + my $links = $options{custom}->get_links_metrics( + edge_id => $edge->{id}, + timeframe => $self->{timeframe} + ); foreach my $link (@{$links}) { - if (defined($self->{option_results}->{filter_link_id}) && $self->{option_results}->{filter_link_id} ne '' && - $link->{linkId} !~ /$self->{option_results}->{filter_link_id}/) { + if (defined($self->{option_results}->{filter_link_name}) && $self->{option_results}->{filter_link_name} ne '' && + $link->{link}->{displayName} !~ /$self->{option_results}->{filter_link_name}/) { $self->{output}->output_add(long_msg => "skipping '" . $edge->{id} . "'.", debug => 1); next; } - $self->{edges}->{$edge->{id}}->{links}->{$link->{linkId}} = { - display => $link->{link}->{displayName}, + $self->{edges}->{$edge->{name}}->{links}->{$link->{link}->{displayName}} = { id => $link->{linkId}, - interface => $link->{link}->{interface}, + display => $link->{link}->{displayName}, state => $link->{link}->{state}, vpn_state => $link->{link}->{vpnState}, - traffic_out => $link->{bytesTx} * 8, - traffic_in => $link->{bytesRx} * 8, - latency_out => $link->{bestLatencyMsTx}, - latency_in => $link->{bestLatencyMsRx}, - jitter_out => $link->{bestJitterMsTx}, - jitter_in => $link->{bestJitterMsRx}, - packet_loss_out => $link->{bestLossPctTx}, - packet_loss_in => $link->{bestLossPctRx}, }; } } @@ -252,7 +161,7 @@ __END__ =head1 MODE -Check edge links. +Check edge links status. =over 8 @@ -260,13 +169,9 @@ Check edge links. Filter edge by name (Can be a regexp). -=item B<--filter-edge-id> +=item B<--filter-link-name> -Filter edge by id (Can be a regexp). - -=item B<--filter-link-id> - -Filter link by id (Can be a regexp). +Filter link by name (Can be a regexp). =item B<--warning-status> @@ -278,16 +183,6 @@ Can used special variables like: %{state}, %{vpn_state}. Set critical threshold for status (Default: ''). Can used special variables like: %{state}, %{vpn_state}. -=item B<--warning-*> - -Threshold warning. -Can be: 'traffic-in', 'traffic-out'. - -=item B<--critical-*> - -Threshold critical. -Can be: 'traffic-in', 'traffic-out'. - =back =cut diff --git a/cloud/vmware/velocloud/restapi/mode/linkusage.pm b/cloud/vmware/velocloud/restapi/mode/linkusage.pm new file mode 100644 index 000000000..e30936685 --- /dev/null +++ b/cloud/vmware/velocloud/restapi/mode/linkusage.pm @@ -0,0 +1,243 @@ +# +# Copyright 2019 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 cloud::vmware::velocloud::restapi::mode::linkusage; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'edges', type => 3, cb_prefix_output => 'prefix_edge_output', cb_long_output => 'long_output', + message_multiple => 'All edges links usage are ok', indent_long_output => ' ', + group => [ + { name => 'links', display_long => 1, cb_prefix_output => 'prefix_link_output', + message_multiple => 'All links status are ok', type => 1 }, + ] + } + ]; + + $self->{maps_counters}->{links} = [ + { label => 'traffic-in', nlabel => 'link.traffic.in.bitspersecond', set => { + key_values => [ { name => 'traffic_in' }, { name => 'display' }, { name => 'id' } ], + output_change_bytes => 2, + output_template => 'Traffic In: %s %s/s', + perfdatas => [ + { value => 'traffic_in_absolute', template => '%s', + min => 0, unit => 'b/s', label_extra_instance => 1 }, + ], + } + }, + { label => 'traffic-out', nlabel => 'link.traffic.out.bitspersecond', set => { + key_values => [ { name => 'traffic_out' }, { name => 'display' }, { name => 'id' } ], + output_change_bytes => 2, + output_template => 'Traffic Out: %s %s/s', + perfdatas => [ + { value => 'traffic_out_absolute', template => '%s', + min => 0, unit => 'b/s', label_extra_instance => 1 }, + ], + } + }, + { label => 'latency-in', nlabel => 'link.latency.in.milliseconds', set => { + key_values => [ { name => 'latency_in' }, { name => 'display' }, { name => 'id' } ], + output_template => 'Latency In: %.2f ms', + perfdatas => [ + { value => 'latency_in_absolute', template => '%.2f', + min => 0, unit => 'ms', label_extra_instance => 1 }, + ], + } + }, + { label => 'latency-out', nlabel => 'link.latency.out.milliseconds', set => { + key_values => [ { name => 'latency_out' }, { name => 'display' }, { name => 'id' } ], + output_template => 'Latency Out: %.2f ms', + perfdatas => [ + { value => 'latency_out_absolute', template => '%.2f', + min => 0, unit => 'ms', label_extra_instance => 1 }, + ], + } + }, + { label => 'jitter-in', nlabel => 'link.jitter.in.milliseconds', set => { + key_values => [ { name => 'jitter_in' }, { name => 'display' }, { name => 'id' } ], + output_template => 'Jitter In: %.2f ms', + perfdatas => [ + { value => 'jitter_in_absolute', template => '%.2f', + min => 0, unit => 'ms', label_extra_instance => 1 }, + ], + } + }, + { label => 'jitter-out', nlabel => 'link.jitter.out.milliseconds', set => { + key_values => [ { name => 'jitter_out' }, { name => 'display' }, { name => 'id' } ], + output_template => 'Jitter Out: %.2f ms', + perfdatas => [ + { value => 'jitter_out_absolute', template => '%.2f', + min => 0, unit => 'ms', label_extra_instance => 1 }, + ], + } + }, + { label => 'packet-loss-in', nlabel => 'link.packet.loss.in.percentage', set => { + key_values => [ { name => 'packet_loss_in' }, { name => 'display' }, { name => 'id' } ], + output_template => 'Packet Loss In: %.2f%%', + perfdatas => [ + { value => 'packet_loss_in_absolute', template => '%.2f', + min => 0, max => 100, unit => '%', label_extra_instance => 1 }, + ], + } + }, + { label => 'packet-loss-out', nlabel => 'link.packet.loss.out.percentage', set => { + key_values => [ { name => 'packet_loss_out' }, { name => 'display' }, { name => 'id' } ], + output_template => 'Packet Loss Out: %.2f%%', + perfdatas => [ + { value => 'packet_loss_out_absolute', template => '%.2f', + min => 0, max => 100, unit => '%', label_extra_instance => 1 }, + ], + } + }, + ]; +} + +sub prefix_edge_output { + my ($self, %options) = @_; + + return "Edge '" . $options{instance_value}->{display} . "' "; +} + +sub prefix_link_output { + my ($self, %options) = @_; + + return "Link '" . $options{instance_value}->{display} . "' [Id: " . $options{instance_value}->{id} . "] "; +} + +sub long_output { + my ($self, %options) = @_; + + return "Checking edge '" . $options{instance_value}->{display} . "' [Id: " . $options{instance_value}->{id} . "] "; +} + +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-edge-name:s" => { name => 'filter_edge_name' }, + "filter-link-name:s" => { name => 'filter_link_name' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + $self->{timeframe} = defined($self->{option_results}->{timeframe}) ? $self->{option_results}->{timeframe} : 900; + + $self->change_macros(macros => ['warning_status', 'critical_status']); +} + +sub manage_selection { + my ($self, %options) = @_; + + $self->{edges} = {}; + + my $results = $options{custom}->list_edges; + + foreach my $edge (@{$results}) { + if (defined($self->{option_results}->{filter_edge_name}) && $self->{option_results}->{filter_edge_name} ne '' && + $edge->{name} !~ /$self->{option_results}->{filter_edge_name}/) { + $self->{output}->output_add(long_msg => "skipping '" . $edge->{name} . "'.", debug => 1); + next; + } + + $self->{edges}->{$edge->{name}}->{id} = $edge->{id}; + $self->{edges}->{$edge->{name}}->{display} = $edge->{name}; + + my $links = $options{custom}->get_links_metrics( + edge_id => $edge->{id}, + timeframe => $self->{timeframe} + ); + + foreach my $link (@{$links}) { + if (defined($self->{option_results}->{filter_link_name}) && $self->{option_results}->{filter_link_name} ne '' && + $link->{link}->{displayName} !~ /$self->{option_results}->{filter_link_name}/) { + $self->{output}->output_add(long_msg => "skipping '" . $edge->{id} . "'.", debug => 1); + next; + } + + $self->{edges}->{$edge->{name}}->{links}->{$link->{link}->{displayName}} = { + id => $link->{linkId}, + display => $link->{link}->{displayName}, + traffic_out => int($link->{bytesTx} * 8 / $self->{timeframe}), + traffic_in => int($link->{bytesRx} * 8 / $self->{timeframe}), + latency_out => $link->{bestLatencyMsTx}, + latency_in => $link->{bestLatencyMsRx}, + jitter_out => $link->{bestJitterMsTx}, + jitter_in => $link->{bestJitterMsRx}, + packet_loss_out => $link->{bestLossPctTx}, + packet_loss_in => $link->{bestLossPctRx}, + }; + } + } + + if (scalar(keys %{$self->{edges}}) <= 0) { + $self->{output}->add_option_msg(short_msg => "No edge found."); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check links usage per edges. + +=over 8 + +=item B<--filter-edge-name> + +Filter edge by name (Can be a regexp). + +=item B<--filter-link-name> + +Filter link by name (Can be a regexp). + +=item B<--warning-*> + +Threshold warning. +Can be: 'traffic-in', 'traffic-out', 'latency-in', +'latency-out', 'jitter-in', 'jitter-out', +'packet-loss-in', 'packet-loss-out'. + +=item B<--critical-*> + +Threshold critical. +Can be: 'traffic-in', 'traffic-out', 'latency-in', +'latency-out', 'jitter-in', 'jitter-out', +'packet-loss-in', 'packet-loss-out'. + +=back + +=cut diff --git a/cloud/vmware/velocloud/restapi/plugin.pm b/cloud/vmware/velocloud/restapi/plugin.pm index d7dbf9402..2089cf6fa 100644 --- a/cloud/vmware/velocloud/restapi/plugin.pm +++ b/cloud/vmware/velocloud/restapi/plugin.pm @@ -31,10 +31,14 @@ sub new { $self->{version} = '0.1'; %{$self->{modes}} = ( - 'discovery' => 'cloud::vmware::velocloud::restapi::mode::discovery', - 'edge-status' => 'cloud::vmware::velocloud::restapi::mode::edgestatus', - 'link-status' => 'cloud::vmware::velocloud::restapi::mode::linkstatus', - 'list-edges' => 'cloud::vmware::velocloud::restapi::mode::listedges', + 'application-usage' => 'cloud::vmware::velocloud::restapi::mode::applicationusage', + 'category-usage' => 'cloud::vmware::velocloud::restapi::mode::categoryusage', + 'discovery' => 'cloud::vmware::velocloud::restapi::mode::discovery', + 'edge-qoe' => 'cloud::vmware::velocloud::restapi::mode::edgeqoe', + 'edge-status' => 'cloud::vmware::velocloud::restapi::mode::edgestatus', + 'link-status' => 'cloud::vmware::velocloud::restapi::mode::linkstatus', + 'link-usage' => 'cloud::vmware::velocloud::restapi::mode::linkusage', + 'list-edges' => 'cloud::vmware::velocloud::restapi::mode::listedges', ); $self->{custom_modes}{api} = 'cloud::vmware::velocloud::restapi::custom::api';