diff --git a/packaging/centreon-plugin-Cloud-Aws-Directconnect-Api/deb.json b/packaging/centreon-plugin-Cloud-Aws-Directconnect-Api/deb.json new file mode 100644 index 000000000..8133a85e5 --- /dev/null +++ b/packaging/centreon-plugin-Cloud-Aws-Directconnect-Api/deb.json @@ -0,0 +1,5 @@ +{ + "dependencies": [ + "libdatetime-perl" + ] +} diff --git a/packaging/centreon-plugin-Cloud-Aws-Directconnect-Api/pkg.json b/packaging/centreon-plugin-Cloud-Aws-Directconnect-Api/pkg.json new file mode 100644 index 000000000..4da476c43 --- /dev/null +++ b/packaging/centreon-plugin-Cloud-Aws-Directconnect-Api/pkg.json @@ -0,0 +1,10 @@ +{ + "pkg_name": "centreon-plugin-Cloud-Aws-Directconnect-Api", + "pkg_summary": "Centreon Plugin to monitor Amazon AWS Direct Connect service using Cloudwatch API", + "plugin_name": "centreon_aws_directconnect_api.pl", + "files": [ + "centreon/plugins/script_custom.pm", + "cloud/aws/custom/", + "cloud/aws/directconnect/" + ] +} diff --git a/packaging/centreon-plugin-Cloud-Aws-Directconnect-Api/rpm.json b/packaging/centreon-plugin-Cloud-Aws-Directconnect-Api/rpm.json new file mode 100644 index 000000000..e9dff7552 --- /dev/null +++ b/packaging/centreon-plugin-Cloud-Aws-Directconnect-Api/rpm.json @@ -0,0 +1,5 @@ +{ + "dependencies": [ + "perl(DateTime)" + ] +} diff --git a/src/cloud/aws/custom/awscli.pm b/src/cloud/aws/custom/awscli.pm index 51d7692fe..00559678e 100644 --- a/src/cloud/aws/custom/awscli.pm +++ b/src/cloud/aws/custom/awscli.pm @@ -914,6 +914,68 @@ sub elasticache_describe_cache_clusters { return $results; } +sub directconnect_describe_connections_set_cmd { + my ($self, %options) = @_; + + return if (defined($self->{option_results}->{command_options}) && $self->{option_results}->{command_options} ne ''); + + my $cmd_options = "directconnect describe-connections --region $self->{option_results}->{region} --output json"; + $cmd_options .= " --endpoint-url $self->{endpoint_url}" if (defined($self->{endpoint_url}) && $self->{endpoint_url} ne ''); + $cmd_options .= " --no-verify-ssl 2>/dev/null" if (defined($self->{option_results}->{skip_ssl_check})); + + return $cmd_options; +} + +sub directconnect_describe_connections { + my ($self, %options) = @_; + + my $cmd_options = $self->directconnect_describe_connections_set_cmd(%options); + my $raw_results = $self->execute(cmd_options => $cmd_options); + + my $results = {}; + foreach (@{$raw_results->{connections}}) { + $results->{ $_->{connectionId} } = { + name => $_->{connectionName}, + state => $_->{connectionState}, + bandwidth => $_->{bandwidth} + }; + } + + return $results; +} + +sub directconnect_describe_virtual_interfaces_set_cmd { + my ($self, %options) = @_; + + return if (defined($self->{option_results}->{command_options}) && $self->{option_results}->{command_options} ne ''); + + my $cmd_options = "directconnect describe-virtual-interfaces --region $self->{option_results}->{region} --output json"; + $cmd_options .= " --endpoint-url $self->{endpoint_url}" if (defined($self->{endpoint_url}) && $self->{endpoint_url} ne ''); + $cmd_options .= " --no-verify-ssl 2>/dev/null" if (defined($self->{option_results}->{skip_ssl_check})); + + return $cmd_options; +} + +sub directconnect_describe_virtual_interfaces { + my ($self, %options) = @_; + + my $cmd_options = $self->directconnect_describe_virtual_interfaces_set_cmd(%options); + my $raw_results = $self->execute(cmd_options => $cmd_options); + + my $results = {}; + foreach (@{$raw_results->{virtualInterfaces}}) { + $results->{ $_->{virtualInterfaceId} } = { + name => $_->{virtualInterfaceName}, + state => $_->{virtualInterfaceState}, + type => $_->{virtualInterfaceType}, + vlan => $_->{vlan}, + connectionId => $_->{connectionId} + }; + } + + return $results; +} + 1; __END__ diff --git a/src/cloud/aws/custom/mode.pm b/src/cloud/aws/custom/mode.pm index 14a3e5dd2..bde8085e4 100644 --- a/src/cloud/aws/custom/mode.pm +++ b/src/cloud/aws/custom/mode.pm @@ -71,18 +71,25 @@ sub custom_metric_perfdata { sub custom_metric_output { my ($self, %options) = @_; - my $msg = ''; + my $extra_unit = ''; + my $metric_label = 'value'; if (defined($self->{instance_mode}->{option_results}->{per_sec})) { - my ($value, $unit) = ($self->{instance_mode}->{metrics_mapping}->{ $self->{result_values}->{metric} }->{unit} eq 'B') ? - $self->{perfdata}->change_bytes(value => $self->{result_values}->{value_per_sec}) : - ($self->{result_values}->{value_per_sec}, $self->{instance_mode}->{metrics_mapping}->{ $self->{result_values}->{metric} }->{unit}); - $msg = sprintf("%s: %.2f %s", $self->{instance_mode}->{metrics_mapping}->{ $self->{result_values}->{metric} }->{output}, $value, $unit . '/s'); - } else { - my ($value, $unit) = ($self->{instance_mode}->{metrics_mapping}->{ $self->{result_values}->{metric} }->{unit} eq 'B') ? - $self->{perfdata}->change_bytes(value => $self->{result_values}->{value}) : - ($self->{result_values}->{value}, $self->{instance_mode}->{metrics_mapping}->{ $self->{result_values}->{metric} }->{unit}); - $msg = sprintf("%s: %.2f %s", $self->{instance_mode}->{metrics_mapping}->{ $self->{result_values}->{metric} }->{output}, $value, $unit); + $metric_label = 'value_per_sec'; + $extra_unit = '/s'; } + + my ($value, $unit); + if ($self->{instance_mode}->{metrics_mapping}->{ $self->{result_values}->{metric} }->{unit} eq 'B') { + ($value, $unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{$metric_label}); + } elsif ($self->{instance_mode}->{metrics_mapping}->{ $self->{result_values}->{metric} }->{unit} eq 'bps') { + ($value, $unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{$metric_label}, network => 1); + $extra_unit = '/s'; + } else { + ($value, $unit) = ($self->{result_values}->{$metric_label}, $self->{instance_mode}->{metrics_mapping}->{ $self->{result_values}->{metric} }->{unit}); + } + + my $msg = sprintf("%s: %.2f %s", $self->{instance_mode}->{metrics_mapping}->{ $self->{result_values}->{metric} }->{output}, $value, $unit . $extra_unit); + return $msg; } @@ -112,16 +119,16 @@ sub set_counters { $self->{maps_counters_type} = [ { name => 'metrics', type => 3, cb_prefix_output => 'prefix_metric_output', cb_long_output => 'long_output', - message_multiple => defined($data->{extra_params}->{message_mutiple}) ? $data->{extra_params}->{message_mutiple} : 'All metrics are ok', + message_multiple => defined($data->{extra_params}->{message_multiple}) ? $data->{extra_params}->{message_multiple} : 'All metrics are ok', indent_long_output => ' ', group => [ { name => 'statistics', display_long => 1, cb_prefix_output => 'prefix_statistics_output', - message_multiple => 'All metrics are ok', type => 1, skipped_code => { -10 => 1 } }, + message_multiple => 'All metrics are ok', type => 1, skipped_code => { -10 => 1 } } ] } ]; - foreach my $metric (keys %{$self->{metrics_mapping}}) { + foreach my $metric (sort keys %{$self->{metrics_mapping}}) { my $entry = { label => $self->{metrics_mapping}->{$metric}->{label}, set => { diff --git a/src/cloud/aws/custom/paws.pm b/src/cloud/aws/custom/paws.pm index 579e398a2..2a30b1b12 100644 --- a/src/cloud/aws/custom/paws.pm +++ b/src/cloud/aws/custom/paws.pm @@ -789,6 +789,56 @@ sub elasticache_describe_cache_clusters { return $results; } +sub directconnect_describe_connections { + my ($self, %options) = @_; + + my $results = {}; + eval { + my $ec = $self->{paws}->service('DirectConnect', region => $self->{option_results}->{region}); + my $connections = $ec->DescribeConnections(); + + foreach (@{$connections->{Connections}}) { + $results->{ $_->{ConnectionId} } = { { + name => $_->{ConnectionName}, + state => $_->{ConnectionState}, + bandwidth => $_->{Bandwidth} + }; + } + }; + if ($@) { + $self->{output}->add_option_msg(short_msg => "error: $@"); + $self->{output}->option_exit(); + } + + return $results; +} + +sub directconnect_describe_virtual_interfaces { + my ($self, %options) = @_; + + my $results = {}; + eval { + my $ec = $self->{paws}->service('DirectConnect', region => $self->{option_results}->{region}); + my $vi = $ec->DescribeVirtualInterfaces(); + + foreach (@{$vi->{VirtualInterfaces}}) { + $results->{ $_->{VirtualInterfaceId} } = { + name => $_->{VirtualInterfaceName}, + state => $_->{VirtualInterfaceState}, + type => $_->{VirtualInterfaceType}, + vlan => $_->{Vlan}, + connectionId => $_->{ConnectionId} + }; + } + }; + if ($@) { + $self->{output}->add_option_msg(short_msg => "error: $@"); + $self->{output}->option_exit(); + } + + return $results; +} + 1; __END__ diff --git a/src/cloud/aws/directconnect/mode/connections.pm b/src/cloud/aws/directconnect/mode/connections.pm new file mode 100644 index 000000000..f11d23263 --- /dev/null +++ b/src/cloud/aws/directconnect/mode/connections.pm @@ -0,0 +1,249 @@ +# +# Copyright 2023 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::aws::directconnect::mode::connections; + +use base qw(cloud::aws::custom::mode); + +use strict; +use warnings; +use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold_ng); + +sub get_metrics_mapping { + my ($self, %options) = @_; + + my $metrics_mapping = { + extra_params => { + message_multiple => 'All connections are ok' + }, + metrics => { + ConnectionBpsEgress => { + output => 'outbound data', + label => 'connection-egress', + nlabel => { + absolute => 'connection.egress.bitspersecond', + }, + unit => 'bps' + }, + ConnectionBpsIngress => { + output => 'inbound data', + label => 'connection-ingress', + nlabel => { + absolute => 'connection.ingress.bitspersecond', + }, + unit => 'bps' + }, + ConnectionPpsEgress => { + output => 'outbound packets data', + label => 'connection-packets-egress', + nlabel => { + absolute => 'connection.egress.packets.persecond', + }, + unit => '/s' + }, + ConnectionPpsIngress => { + output => 'inbound packet data', + label => 'connection-packets-ingress', + nlabel => { + absolute => 'connection.ingress.packets.persecond', + }, + unit => '/s' + }, + ConnectionLightLevelTx => { + output => 'outbound light level', + label => 'connection-ligh-level-outbound', + nlabel => { + absolute => 'connection.outbound.light.level.dbm', + }, + unit => 'dBm' + }, + ConnectionLightLevelRx => { + output => 'inbound light level', + label => 'connection-ligh-level-inbound', + nlabel => { + absolute => 'connection.inbound.light.level.dbm', + }, + unit => 'dBm' + } + } + }; + + return $metrics_mapping; +} + +sub custom_status_output { + my ($self, %options) = @_; + + return sprintf('state: %s [bandwidth: %s]', $self->{result_values}->{state}, $self->{result_values}->{bandwidth}); +} + +sub prefix_metric_output { + my ($self, %options) = @_; + + return "connection '" . $options{instance_value}->{display} . "' "; +} + +sub long_output { + my ($self, %options) = @_; + + return "Checking connection '" . $options{instance_value}->{display} . "' "; +} + +sub prefix_statistics_output { + my ($self, %options) = @_; + + return "statistic '" . $options{instance_value}->{display} . "' "; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->SUPER::set_counters(%options); + + unshift @{$self->{maps_counters_type}->[0]->{group}}, { + name => 'status', + type => 0, skipped_code => { -10 => 1 } + }; + + $self->{maps_counters}->{status} = [ + { label => 'status', type => 2, set => { + key_values => [ { name => 'state' }, { name => 'bandwidth' }, { name => 'connectionName' } ], + closure_custom_output => $self->can('custom_status_output'), + closure_custom_perfdata => sub { return 0; }, + closure_custom_threshold_check => \&catalog_status_threshold_ng + } + } + ]; +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1); + bless $self, $class; + + $options{options}->add_options(arguments => { + 'filter-connection-id:s' => { name => 'filter_connection_id' } + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); +} + +sub manage_selection { + my ($self, %options) = @_; + + my $connections = $options{custom}->directconnect_describe_connections(); + + foreach my $connection_id (keys %$connections) { + next if (defined($self->{option_results}->{filter_connection_id}) && $self->{option_results}->{filter_connection_id} ne '' + && $connection_id !~ /$self->{option_results}->{filter_connection_id}/); + + $self->{metrics}->{$connection_id} = { + display => $connections->{$connection_id}->{name}, + status => { + connectionName => $connections->{$connection_id}->{name}, + bandwidth => $connections->{$connection_id}->{bandwidth}, + state => $connections->{$connection_id}->{state} + }, + statistics => {} + }; + + my $cw_metrics = $options{custom}->cloudwatch_get_metrics( + namespace => 'AWS/DX', + dimensions => [ { Name => 'ConnectionId', Value => $connection_id } ], + metrics => $self->{aws_metrics}, + statistics => $self->{aws_statistics}, + timeframe => $self->{aws_timeframe}, + period => $self->{aws_period} + ); + + foreach my $metric (@{$self->{aws_metrics}}) { + foreach my $statistic (@{$self->{aws_statistics}}) { + next if (!defined($cw_metrics->{$metric}->{lc($statistic)}) && + !defined($self->{option_results}->{zeroed})); + + $self->{metrics}->{$connection_id}->{display} = $connections->{$connection_id}->{name}; + $self->{metrics}->{$connection_id}->{statistics}->{lc($statistic)}->{display} = $statistic; + $self->{metrics}->{$connection_id}->{statistics}->{lc($statistic)}->{timeframe} = $self->{aws_timeframe}; + $self->{metrics}->{$connection_id}->{statistics}->{lc($statistic)}->{$metric} = + defined($cw_metrics->{$metric}->{lc($statistic)}) ? + $cw_metrics->{$metric}->{lc($statistic)} : 0; + } + } + } + + if (scalar(keys %{$self->{metrics}}) <= 0) { + $self->{output}->add_option_msg(short_msg => 'No connection found'); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check direct connect connections. + +Example: +perl centreon_plugins.pl --plugin=cloud::aws::directconnect::plugin --custommode=paws --mode=connections --region='eu-west-1' +--filter-metric='ConnectionBpsEgress' --statistic='average' --critical-connection-egress='10Mb' --verbose + +See 'https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/viewing_metrics_with_cloudwatch.html' for more informations. + +Default statistic: 'average' / All satistics are valid. + +=over 8 + +=item B<--filter-connection-id> + +Filter connection id (can be a regexp). + +=item B<--filter-metric> + +Filter metrics (Can be: 'ConnectionBpsEgress', 'ConnectionBpsIngress', +'ConnectionPpsEgress', 'ConnectionPpsIngress', 'ConnectionLightLevelTx', 'ConnectionLightLevelRx') +(Can be a regexp). + +=item B<--warning-status> + +Set warning threshold for status. +Can used special variables like: %{state}, %{bandwidth}, %{connectionName} + +=item B<--critical-status> + +Set critical threshold for status. +Can used special variables like: %{state}, %{bandwidth}, %{connectionName} + +=item B<--warning-*> B<--critical-*> + +Thresholds. +Can be 'connection-egress', 'connection-ingress', +'connection-packets-egress', 'connection-packets-ingress', +'connection-ligh-level-outbound', 'connection-ligh-level-inbound. + +=back + +=cut diff --git a/src/cloud/aws/directconnect/mode/discovery.pm b/src/cloud/aws/directconnect/mode/discovery.pm new file mode 100644 index 000000000..9dba86ed2 --- /dev/null +++ b/src/cloud/aws/directconnect/mode/discovery.pm @@ -0,0 +1,104 @@ +# +# Copyright 2023 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::aws::directconnect::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 => { + 'prettify' => { name => 'prettify' } + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::init(%options); +} + +sub run { + my ($self, %options) = @_; + + my @disco_data; + my $disco_stats; + + $disco_stats->{start_time} = time(); + + my $connections = $options{custom}->directconnect_describe_connections(); + + foreach my $connection_id (keys %$connections) { + my %connection = (type => 'connection'); + + $connection{id} = $connection_id; + $connection{name} = $connections->{$connection_id}->{name}; + $connection{state} = $connections->{$connection_id}->{state}; + $connection{bandwidth} = $connections->{$connection_id}->{bandwidth}; + push @disco_data, \%connection; + } + + $disco_stats->{end_time} = time(); + $disco_stats->{duration} = $disco_stats->{end_time} - $disco_stats->{start_time}; + $disco_stats->{discovered_items} = @disco_data; + $disco_stats->{results} = \@disco_data; + + 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 + +AWS Direct Connect discovery. + +=over 8 + +=item B<--prettify> + +Prettify JSON output. + +=back + +=cut diff --git a/src/cloud/aws/directconnect/mode/listconnections.pm b/src/cloud/aws/directconnect/mode/listconnections.pm new file mode 100644 index 000000000..0933ea4b2 --- /dev/null +++ b/src/cloud/aws/directconnect/mode/listconnections.pm @@ -0,0 +1,103 @@ +# +# Copyright 2023 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::aws::directconnect::mode::listconnections; + +use base qw(centreon::plugins::mode); + +use strict; +use warnings; + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $options{options}->add_options(arguments => {}); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::init(%options); +} + +sub manage_selection { + my ($self, %options) = @_; + + return $options{custom}->directconnect_describe_connections(); +} + +sub run { + my ($self, %options) = @_; + + my $connections = $self->manage_selection(%options); + foreach my $connection_id (keys %$connections) { + $self->{output}->output_add( + long_msg => sprintf( + '[id: %s][name: %s][state: %s]', + $connection_id, + $connections->{$connection_id}->{name}, + $connections->{$connection_id}->{state} + ) + ); + } + + $self->{output}->output_add( + severity => 'OK', + short_msg => 'List connections:' + ); + $self->{output}->display(nolabel => 1, force_ignore_perfdata => 1, force_long_output => 1); + $self->{output}->exit(); +} + +sub disco_format { + my ($self, %options) = @_; + + $self->{output}->add_disco_format(elements => ['id', 'name', 'state']); +} + +sub disco_show { + my ($self, %options) = @_; + + my $connections = $self->manage_selection(%options); + foreach my $connection_id (keys %$connections) { + $self->{output}->add_disco_entry( + id => $connection_id, + name => $connections->{$connection_id}->{name}, + state => $connections->{$connection_id}->{state} + ); + } +} + +1; + +__END__ + +=head1 MODE + +List direct connections. + +=over 8 + +=back + +=cut diff --git a/src/cloud/aws/directconnect/mode/listvirtualinterfaces.pm b/src/cloud/aws/directconnect/mode/listvirtualinterfaces.pm new file mode 100644 index 000000000..6da2483da --- /dev/null +++ b/src/cloud/aws/directconnect/mode/listvirtualinterfaces.pm @@ -0,0 +1,114 @@ +# +# Copyright 2023 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::aws::directconnect::mode::listvirtualinterfaces; + +use base qw(centreon::plugins::mode); + +use strict; +use warnings; + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $options{options}->add_options(arguments => {}); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::init(%options); +} + +sub manage_selection { + my ($self, %options) = @_; + + my $connections = $options{custom}->directconnect_describe_connections(); + my $interfaces = $options{custom}->directconnect_describe_virtual_interfaces(); + + my $results = []; + foreach my $vid (keys %$interfaces) { + push @$results, { + connectionId => $interfaces->{$vid}->{connectionId}, + connectionName => $connections->{ $interfaces->{$vid}->{connectionId} }->{name}, + virtualInterfaceId => $vid, + virtualInterfaceName => $interfaces->{$vid}->{name}, + virtualInterfaceState => $interfaces->{$vid}->{state} + }; + } + return $results; +} + +sub run { + my ($self, %options) = @_; + + my $results = $self->manage_selection(%options); + foreach (@$results) { + $self->{output}->output_add( + long_msg => sprintf( + '[connectionId: %s][connectionName: %s][virtualInterfaceId: %s][virtualInterfaceName: %s][virtualInterfaceState: %s]', + $_->{connectionId}, + $_->{connectionName}, + $_->{virtualInterfaceId}, + $_->{virtualInterfaceName}, + $_->{virtualInterfaceState} + ) + ); + } + + $self->{output}->output_add( + severity => 'OK', + short_msg => 'List virtual interfaces:' + ); + $self->{output}->display(nolabel => 1, force_ignore_perfdata => 1, force_long_output => 1); + $self->{output}->exit(); +} + +sub disco_format { + my ($self, %options) = @_; + + $self->{output}->add_disco_format(elements => ['virtualInterfaceId', 'virtualInterfaceName', 'connectionName', 'connectionId', 'virtualInterfaceState']); +} + +sub disco_show { + my ($self, %options) = @_; + + my $results = $self->manage_selection(%options); + foreach (@$results) { + $self->{output}->add_disco_entry(%$_); + } +} + +1; + +__END__ + +=head1 MODE + +List virtual interfaces. + +=over 8 + +=back + +=cut diff --git a/src/cloud/aws/directconnect/mode/virtualinterfaces.pm b/src/cloud/aws/directconnect/mode/virtualinterfaces.pm new file mode 100644 index 000000000..e616440c8 --- /dev/null +++ b/src/cloud/aws/directconnect/mode/virtualinterfaces.pm @@ -0,0 +1,245 @@ +# +# Copyright 2023 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::aws::directconnect::mode::virtualinterfaces; + +use base qw(cloud::aws::custom::mode); + +use strict; +use warnings; +use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold_ng); + +sub get_metrics_mapping { + my ($self, %options) = @_; + + my $metrics_mapping = { + extra_params => { + message_multiple => 'All virtual interfaces are ok' + }, + metrics => { + VirtualInterfaceBpsEgress => { + output => 'outbound data', + label => 'virtual-interface-egress', + nlabel => { + absolute => 'virtual_interface.egress.bitspersecond', + }, + unit => 'bps' + }, + VirtualInterfaceBpsIngress => { + output => 'inbound data', + label => 'virtual-interface-ingress', + nlabel => { + absolute => 'virtual_interface.ingress.bitspersecond', + }, + unit => 'bps' + }, + VirtualInterfacePpsEgress => { + output => 'outbound packets data', + label => 'virtual-interface-packets-egress', + nlabel => { + absolute => 'virtual_interface.egress.packets.persecond', + }, + unit => '/s' + }, + VirtualInterfacePpsIngress => { + output => 'inbound packet data', + label => 'virtual-interface-packets-ingress', + nlabel => { + absolute => 'virtual_interface.ingress.packets.persecond', + }, + unit => '/s' + } + } + }; + + return $metrics_mapping; +} + +sub custom_status_output { + my ($self, %options) = @_; + + return sprintf('state: %s [vlan: %s, type: %s]', $self->{result_values}->{state}, $self->{result_values}->{vlan}, $self->{result_values}->{type}); +} + +sub prefix_metric_output { + my ($self, %options) = @_; + + return "connection '" . $options{instance_value}->{connectionName} . "' virtual interface '" . $options{instance_value}->{virtualInterfaceName} . "' "; +} + +sub long_output { + my ($self, %options) = @_; + + return "Checking connection '" . $options{instance_value}->{connectionName} . "' virtual interface '" . $options{instance_value}->{virtualInterfaceName} . "'"; +} + +sub prefix_statistics_output { + my ($self, %options) = @_; + + return "statistic '" . $options{instance_value}->{display} . "' "; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->SUPER::set_counters(%options); + + unshift @{$self->{maps_counters_type}->[0]->{group}}, { + name => 'status', + type => 0, skipped_code => { -10 => 1 } + }; + + $self->{maps_counters}->{status} = [ + { label => 'status', type => 2, set => { + key_values => [ { name => 'state' }, { name => 'vlan' }, { name => 'type' }, { name => 'connectionName' }, { name => 'virtualInterfaceName' } ], + closure_custom_output => $self->can('custom_status_output'), + closure_custom_perfdata => sub { return 0; }, + closure_custom_threshold_check => \&catalog_status_threshold_ng + } + } + ]; +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1); + bless $self, $class; + + $options{options}->add_options(arguments => { + 'filter-connection-id:s' => { name => 'filter_connection_id' }, + 'filter-virtual-interface-id:s' => { name => 'filter_virtual_interface_id' } + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); +} + +sub manage_selection { + my ($self, %options) = @_; + + my $connections = $options{custom}->directconnect_describe_connections(); + my $interfaces = $options{custom}->directconnect_describe_virtual_interfaces(); + + foreach my $vid (keys %$interfaces) { + next if (defined($self->{option_results}->{filter_virtual_interface_id}) && $self->{option_results}->{filter_virtual_interface_id} ne '' + && $vid !~ /$self->{option_results}->{filter_virtual_interface_id}/); + next if (defined($self->{option_results}->{filter_connection_id}) && $self->{option_results}->{filter_connection_id} ne '' + && $interfaces->{$vid}->{connectionId} !~ /$self->{option_results}->{filter_connection_id}/); + + my $key = $connections->{ $interfaces->{$vid}->{connectionId} }->{name} . $self->{output}->get_instance_perfdata_separator() . $interfaces->{$vid}->{name}; + + $self->{metrics}->{$key} = { + connectionName => $connections->{ $interfaces->{$vid}->{connectionId} }->{name}, + virtualInterfaceName => $interfaces->{$vid}->{name}, + status => { + connectionName => $connections->{ $interfaces->{$vid}->{connectionId} }->{name}, + virtualInterfaceName => $interfaces->{$vid}->{name}, + type => $interfaces->{$vid}->{type}, + vlan => $interfaces->{$vid}->{vlan}, + state => $interfaces->{$vid}->{state} + }, + statistics => {} + }; + + my $cw_metrics = $options{custom}->cloudwatch_get_metrics( + namespace => 'AWS/DX', + dimensions => [ { Name => 'ConnectionId', Value => $interfaces->{$vid}->{connectionId} }, { Name => 'VirtualInterfaceId', Value => $vid } ], + metrics => $self->{aws_metrics}, + statistics => $self->{aws_statistics}, + timeframe => $self->{aws_timeframe}, + period => $self->{aws_period} + ); + + foreach my $metric (@{$self->{aws_metrics}}) { + foreach my $statistic (@{$self->{aws_statistics}}) { + next if (!defined($cw_metrics->{$metric}->{lc($statistic)}) && + !defined($self->{option_results}->{zeroed})); + + $self->{metrics}->{$key}->{display} = $interfaces->{$vid}->{name}; + $self->{metrics}->{$key}->{statistics}->{lc($statistic)}->{display} = $statistic; + $self->{metrics}->{$key}->{statistics}->{lc($statistic)}->{timeframe} = $self->{aws_timeframe}; + $self->{metrics}->{$key}->{statistics}->{lc($statistic)}->{$metric} = + defined($cw_metrics->{$metric}->{lc($statistic)}) ? + $cw_metrics->{$metric}->{lc($statistic)} : 0; + } + } + } + + if (scalar(keys %{$self->{metrics}}) <= 0) { + $self->{output}->add_option_msg(short_msg => 'No virtual interface found'); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check direct connect virtual interfaces. + +Example: +perl centreon_plugins.pl --plugin=cloud::aws::directconnect::plugin --custommode=paws --mode=virtual-interfaces --region='eu-west-1' +--filter-metric='VirtualInterfaceBpsEgress' --statistic='average' --critical-virtual-interface-egress='10Mb' --verbose + +See 'https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/viewing_metrics_with_cloudwatch.html' for more informations. + +Default statistic: 'average' / All satistics are valid. + +=over 8 + +=item B<--filter-connection-id> + +Filter connection id (can be a regexp). + +=item B<--filter-virtual-interface-id> + +Filter virtual interface id (can be a regexp). + +=item B<--filter-metric> + +Filter metrics (Can be: 'VirtualInterfaceBpsEgress', 'VirtualInterfaceBpsIngress', +'VirtualInterfacePpsEgress', 'VirtualInterfacePpsIngress') +(Can be a regexp). + +=item B<--warning-status> + +Set warning threshold for status. +Can used special variables like: %{state}, %{vlan}, %{type}, %{virtualInterfaceId} + +=item B<--critical-status> + +Set critical threshold for status. +Can used special variables like: %{state}, %{vlan}, %{type}, %{virtualInterfaceId} + +=item B<--warning-*> B<--critical-*> + +Thresholds. +Can be 'virtual-interface-egress', 'virtual-interface-ingress', +'virtual-interface-packets-egress', 'virtual-interface-packets-ingress'. + +=back + +=cut diff --git a/src/cloud/aws/directconnect/plugin.pm b/src/cloud/aws/directconnect/plugin.pm new file mode 100644 index 000000000..2f905365d --- /dev/null +++ b/src/cloud/aws/directconnect/plugin.pm @@ -0,0 +1,53 @@ +# +# Copyright 2023 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::aws::directconnect::plugin; + +use strict; +use warnings; +use base qw(centreon::plugins::script_custom); + +sub new { + my ( $class, %options ) = @_; + my $self = $class->SUPER::new( package => __PACKAGE__, %options ); + bless $self, $class; + + $self->{modes} = { + 'connections' => 'cloud::aws::directconnect::mode::connections', + 'discovery' => 'cloud::aws::directconnect::mode::discovery', + 'list-connections' => 'cloud::aws::directconnect::mode::listconnections', + 'list-virtual-interfaces' => 'cloud::aws::directconnect::mode::listvirtualinterfaces', + 'virtual-interfaces' => 'cloud::aws::directconnect::mode::virtualinterfaces' + }; + + $self->{custom_modes}->{paws} = 'cloud::aws::custom::paws'; + $self->{custom_modes}->{awscli} = 'cloud::aws::custom::awscli'; + return $self; +} + +1; + +__END__ + +=head1 PLUGIN DESCRIPTION + +Check Amazon Direct Connect. + +=cut