From 949dad1b201596e08615408f3b92ffb94bfaa279 Mon Sep 17 00:00:00 2001 From: cgagnaire Date: Mon, 9 Apr 2018 11:49:57 +0200 Subject: [PATCH] add aws friendly plugins --- cloud/aws/billing/mode/estimatedcharges.pm | 139 ++++++++ cloud/aws/billing/mode/listservices.pm | 120 +++++++ cloud/aws/{ => billing}/plugin.pm | 13 +- cloud/aws/cloudfront/mode/errors.pm | 181 +++++++++++ cloud/aws/cloudfront/mode/requests.pm | 223 +++++++++++++ cloud/aws/cloudfront/mode/throughput.pm | 234 ++++++++++++++ cloud/aws/cloudfront/plugin.pm | 54 ++++ .../mode/getalarms.pm} | 19 +- .../mode/getmetrics.pm} | 43 +-- .../mode/listmetrics.pm} | 23 +- cloud/aws/cloudwatch/plugin.pm | 52 +++ cloud/aws/custom/awscli.pm | 248 +++++++++++++- cloud/aws/custom/paws.pm | 171 +++++++++- cloud/aws/ebs/plugin.pm | 52 +++ cloud/aws/ec2/mode/asgstatus.pm | 257 +++++++++++++++ cloud/aws/ec2/mode/cpu.pm | 217 +++++++++++++ cloud/aws/ec2/mode/diskio.pm | 303 ++++++++++++++++++ .../mode/instancesstatus.pm} | 19 +- cloud/aws/ec2/mode/instancestypes.pm | 223 +++++++++++++ cloud/aws/ec2/mode/listasg.pm | 98 ++++++ cloud/aws/ec2/mode/listinstances.pm | 102 ++++++ cloud/aws/ec2/mode/network.pm | 303 ++++++++++++++++++ cloud/aws/ec2/mode/status.pm | 240 ++++++++++++++ cloud/aws/ec2/plugin.pm | 58 ++++ .../aws/elasticache/mode/commandsmemcached.pm | 254 +++++++++++++++ cloud/aws/elasticache/mode/commandsredis.pm | 257 +++++++++++++++ cloud/aws/elasticache/mode/connections.pm | 265 +++++++++++++++ cloud/aws/elasticache/mode/cpu.pm | 184 +++++++++++ cloud/aws/elasticache/mode/evictions.pm | 253 +++++++++++++++ cloud/aws/elasticache/mode/items.pm | 265 +++++++++++++++ cloud/aws/elasticache/mode/network.pm | 255 +++++++++++++++ cloud/aws/elasticache/mode/replication.pm | 267 +++++++++++++++ .../aws/elasticache/mode/requestsmemcached.pm | 256 +++++++++++++++ cloud/aws/elasticache/mode/requestsredis.pm | 251 +++++++++++++++ cloud/aws/elasticache/mode/usagememcached.pm | 190 +++++++++++ cloud/aws/elasticache/mode/usageredis.pm | 190 +++++++++++ cloud/aws/elasticache/plugin.pm | 61 ++++ cloud/aws/elb/mode/httpcodes.pm | 239 ++++++++++++++ cloud/aws/elb/mode/performances.pm | 234 ++++++++++++++ cloud/aws/elb/mode/queues.pm | 235 ++++++++++++++ cloud/aws/elb/mode/targetshealth.pm | 221 +++++++++++++ cloud/aws/elb/plugin.pm | 53 +++ cloud/aws/lambda/mode/invocations.pm | 193 +++++++++++ cloud/aws/lambda/plugin.pm | 50 +++ cloud/aws/rds/mode/connections.pm | 203 ++++++++++++ cloud/aws/rds/mode/cpu.pm | 215 +++++++++++++ cloud/aws/rds/mode/diskio.pm | 244 ++++++++++++++ .../mode/instancestatus.pm} | 13 +- cloud/aws/rds/mode/listclusters.pm | 100 ++++++ cloud/aws/rds/mode/listinstances.pm | 101 ++++++ cloud/aws/rds/mode/network.pm | 204 ++++++++++++ cloud/aws/rds/mode/queries.pm | 221 +++++++++++++ cloud/aws/rds/mode/transactions.pm | 215 +++++++++++++ cloud/aws/rds/mode/volume.pm | 271 ++++++++++++++++ cloud/aws/rds/plugin.pm | 59 ++++ cloud/aws/s3/mode/bucketsize.pm | 200 ++++++++++++ cloud/aws/s3/mode/objects.pm | 174 ++++++++++ cloud/aws/s3/mode/requests.pm | 180 +++++++++++ cloud/aws/s3/plugin.pm | 52 +++ 59 files changed, 9917 insertions(+), 100 deletions(-) create mode 100644 cloud/aws/billing/mode/estimatedcharges.pm create mode 100644 cloud/aws/billing/mode/listservices.pm rename cloud/aws/{ => billing}/plugin.pm (73%) create mode 100644 cloud/aws/cloudfront/mode/errors.pm create mode 100644 cloud/aws/cloudfront/mode/requests.pm create mode 100644 cloud/aws/cloudfront/mode/throughput.pm create mode 100644 cloud/aws/cloudfront/plugin.pm rename cloud/aws/{mode/cloudwatchgetalarms.pm => cloudwatch/mode/getalarms.pm} (89%) rename cloud/aws/{mode/cloudwatchgetmetrics.pm => cloudwatch/mode/getmetrics.pm} (83%) rename cloud/aws/{mode/cloudwatchlistmetrics.pm => cloudwatch/mode/listmetrics.pm} (82%) create mode 100644 cloud/aws/cloudwatch/plugin.pm create mode 100644 cloud/aws/ebs/plugin.pm create mode 100644 cloud/aws/ec2/mode/asgstatus.pm create mode 100644 cloud/aws/ec2/mode/cpu.pm create mode 100644 cloud/aws/ec2/mode/diskio.pm rename cloud/aws/{mode/ec2instancestatus.pm => ec2/mode/instancesstatus.pm} (91%) create mode 100644 cloud/aws/ec2/mode/instancestypes.pm create mode 100644 cloud/aws/ec2/mode/listasg.pm create mode 100644 cloud/aws/ec2/mode/listinstances.pm create mode 100644 cloud/aws/ec2/mode/network.pm create mode 100644 cloud/aws/ec2/mode/status.pm create mode 100644 cloud/aws/ec2/plugin.pm create mode 100644 cloud/aws/elasticache/mode/commandsmemcached.pm create mode 100644 cloud/aws/elasticache/mode/commandsredis.pm create mode 100644 cloud/aws/elasticache/mode/connections.pm create mode 100644 cloud/aws/elasticache/mode/cpu.pm create mode 100644 cloud/aws/elasticache/mode/evictions.pm create mode 100644 cloud/aws/elasticache/mode/items.pm create mode 100644 cloud/aws/elasticache/mode/network.pm create mode 100644 cloud/aws/elasticache/mode/replication.pm create mode 100644 cloud/aws/elasticache/mode/requestsmemcached.pm create mode 100644 cloud/aws/elasticache/mode/requestsredis.pm create mode 100644 cloud/aws/elasticache/mode/usagememcached.pm create mode 100644 cloud/aws/elasticache/mode/usageredis.pm create mode 100644 cloud/aws/elasticache/plugin.pm create mode 100644 cloud/aws/elb/mode/httpcodes.pm create mode 100644 cloud/aws/elb/mode/performances.pm create mode 100644 cloud/aws/elb/mode/queues.pm create mode 100644 cloud/aws/elb/mode/targetshealth.pm create mode 100644 cloud/aws/elb/plugin.pm create mode 100644 cloud/aws/lambda/mode/invocations.pm create mode 100644 cloud/aws/lambda/plugin.pm create mode 100644 cloud/aws/rds/mode/connections.pm create mode 100644 cloud/aws/rds/mode/cpu.pm create mode 100644 cloud/aws/rds/mode/diskio.pm rename cloud/aws/{mode/rdsinstancestatus.pm => rds/mode/instancestatus.pm} (93%) create mode 100644 cloud/aws/rds/mode/listclusters.pm create mode 100644 cloud/aws/rds/mode/listinstances.pm create mode 100644 cloud/aws/rds/mode/network.pm create mode 100644 cloud/aws/rds/mode/queries.pm create mode 100644 cloud/aws/rds/mode/transactions.pm create mode 100644 cloud/aws/rds/mode/volume.pm create mode 100644 cloud/aws/rds/plugin.pm create mode 100644 cloud/aws/s3/mode/bucketsize.pm create mode 100644 cloud/aws/s3/mode/objects.pm create mode 100644 cloud/aws/s3/mode/requests.pm create mode 100644 cloud/aws/s3/plugin.pm diff --git a/cloud/aws/billing/mode/estimatedcharges.pm b/cloud/aws/billing/mode/estimatedcharges.pm new file mode 100644 index 000000000..3a1ed18f4 --- /dev/null +++ b/cloud/aws/billing/mode/estimatedcharges.pm @@ -0,0 +1,139 @@ +# +# Copyright 2018 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::billing::mode::estimatedcharges; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +sub prefix_charges_output { + my ($self, %options) = @_; + + return "Service '" . $self->{option_results}->{service} . "' "; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'estimatedcharges', type => 0, cb_prefix_output => 'prefix_charges_output' }, + ]; + + $self->{maps_counters}->{estimatedcharges} = [ + { label => 'billing', set => { + key_values => [ { name => 'estimated_charges' }, { name => 'display' } ], + output_template => 'estimated charges: %.2f USD', + perfdatas => [ + { label => 'billing', value => 'estimated_charges_absolute', template => '%.2f', + unit => 'USD' }, + ], + } + }, + ]; +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $self->{version} = '1.0'; + $options{options}->add_options(arguments => + { + "service:s" => { name => 'service' }, + "currency:s" => { name => 'currency', default => 'USD' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + if (!defined($self->{option_results}->{service}) || $self->{option_results}->{service} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --service option."); + $self->{output}->option_exit(); + } + + if (!defined($self->{option_results}->{currency}) || $self->{option_results}->{currency} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --currency option."); + $self->{output}->option_exit(); + } + + $self->{aws_timeframe} = defined($self->{option_results}->{timeframe}) ? $self->{option_results}->{timeframe} : 86400; + $self->{aws_period} = defined($self->{option_results}->{period}) ? $self->{option_results}->{period} : 60; +} + +sub manage_selection { + my ($self, %options) = @_; + + my $metric_results = $options{custom}->cloudwatch_get_metrics( + region => $self->{option_results}->{region}, + namespace => 'AWS/Billing', + dimensions => [ { Name => 'ServiceName', Value => $self->{option_results}->{service} }, { Name => 'Currency', Value => $self->{option_results}->{currency} } ], + metrics => ['EstimatedCharges'], + statistics => ['Maximum'], + timeframe => $self->{aws_timeframe}, + period => $self->{aws_period}, + ); + + $self->{estimatedcharges}->{estimated_charges} = $metric_results->{'EstimatedCharges'}->{'maximum'} if defined($metric_results->{'EstimatedCharges'}->{'maximum'}); + $self->{estimatedcharges}->{display} = $self->{option_results}->{service}; + + if (scalar(keys %{$self->{estimatedcharges}}) <= 0) { + $self->{output}->add_option_msg(short_msg => 'No value.'); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check Billing estimated charges for a service. + +Example: +perl centreon_plugins.pl --plugin=cloud::aws::billing::plugin --custommode=paws --mode=estimated-charges +--region='us-east-1' --service='AWSService' --verbose + +See 'https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/billing-metricscollected.html' for more informations. + +=over 8 + +=item B<--service> + +Set the Amazon service (Required). + +=item B<--warning-billing> + +Thresholds warning. + +=item B<--critical-billing> + +Thresholds critical. + +=back + +=cut diff --git a/cloud/aws/billing/mode/listservices.pm b/cloud/aws/billing/mode/listservices.pm new file mode 100644 index 000000000..aabee3211 --- /dev/null +++ b/cloud/aws/billing/mode/listservices.pm @@ -0,0 +1,120 @@ +# +# Copyright 2018 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::billing::mode::listservices; + +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; + + $self->{version} = '1.0'; + $options{options}->add_options(arguments => + { + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::init(%options); + + $self->{aws_region} = defined($self->{option_results}->{region}) ? $self->{option_results}->{region} : 'us-east-1'; +} + +sub manage_selection { + my ($self, %options) = @_; + + $self->{dimensions} = $options{custom}->cloudwatch_list_metrics(region => $self->{aws_region}, + namespace => 'AWS/Billing'); +} + +sub run { + my ($self, %options) = @_; + + $self->manage_selection(%options); + + my %already; + foreach my $dimension (@{$self->{dimensions}}) { + my $servicename = ''; + my $currency = ''; + foreach my $name (@{$dimension->{Dimensions}}) { + $servicename = $name->{Value} if ($name->{Name} =~ m/ServiceName/ && $name->{Value} ne ''); + $currency = $name->{Value} if ($name->{Name} =~ m/Currency/ && $name->{Value} ne ''); + } + next if (defined($already{$servicename}) || $servicename eq ''); + $self->{output}->output_add(long_msg => sprintf("[ServiceName = %s][Currency = %s]", $servicename, $currency)); + $already{$servicename} = 1; + } + + $self->{output}->output_add(severity => 'OK', + short_msg => 'List services:'); + $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 => ['servicename', 'currency']); +} + +sub disco_show { + my ($self, %options) = @_; + + $self->manage_selection(%options); + + my %already; + foreach my $dimension (@{$self->{dimensions}}) { + my $servicename = ''; + my $currency = ''; + foreach my $name (@{$dimension->{Dimensions}}) { + $servicename = $name->{Value} if ($name->{Name} =~ m/ServiceName/ && $name->{Value} ne ''); + $currency = $name->{Value} if ($name->{Name} =~ m/Currency/ && $name->{Value} ne ''); + } + next if (defined($already{$servicename}) || $servicename eq ''); + $self->{output}->add_disco_entry( + servicename => $servicename, + currency => $currency, + ); + $already{$servicename} = 1; + } +} + +1; + +__END__ + +=head1 MODE + +List billed Amazon services. + +=over 8 + +=back + +=cut + diff --git a/cloud/aws/plugin.pm b/cloud/aws/billing/plugin.pm similarity index 73% rename from cloud/aws/plugin.pm rename to cloud/aws/billing/plugin.pm index 1f3068fb1..c2b9469db 100644 --- a/cloud/aws/plugin.pm +++ b/cloud/aws/billing/plugin.pm @@ -18,7 +18,7 @@ # limitations under the License. # -package cloud::aws::plugin; +package cloud::aws::billing::plugin; use strict; use warnings; @@ -31,11 +31,8 @@ sub new { $self->{version} = '0.1'; %{ $self->{modes} } = ( - 'cloudwatch-get-alarms' => 'cloud::aws::mode::cloudwatchgetalarms', - 'cloudwatch-get-metrics' => 'cloud::aws::mode::cloudwatchgetmetrics', - 'cloudwatch-list-metrics' => 'cloud::aws::mode::cloudwatchlistmetrics', - 'ec2-instance-status' => 'cloud::aws::mode::ec2instancestatus', - 'rds-instance-status' => 'cloud::aws::mode::rdsinstancestatus', + 'estimated-charges' => 'cloud::aws::billing::mode::estimatedcharges', + 'list-services' => 'cloud::aws::billing::mode::listservices', ); $self->{custom_modes}{paws} = 'cloud::aws::custom::paws'; @@ -49,6 +46,8 @@ __END__ =head1 PLUGIN DESCRIPTION -Check Amazon AWS cloud. +Check Amazon Billing. + +Works for 'us-east-1' region only. =cut diff --git a/cloud/aws/cloudfront/mode/errors.pm b/cloud/aws/cloudfront/mode/errors.pm new file mode 100644 index 000000000..8a4e09d2b --- /dev/null +++ b/cloud/aws/cloudfront/mode/errors.pm @@ -0,0 +1,181 @@ +# +# Copyright 2018 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::cloudfront::mode::errors; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +sub prefix_metric_output { + my ($self, %options) = @_; + + return "Instance '" . $options{instance_value}->{display} . "' " . $options{instance_value}->{stat} . " "; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'metric', type => 1, cb_prefix_output => 'prefix_metric_output', message_multiple => "All errors metrics are ok", skipped_code => { -10 => 1 } }, + ]; + + foreach my $statistic ('minimum', 'maximum', 'average', 'sum') { + foreach my $metric ('TotalErrorRate', '4xxErrorRate', '5xxErrorRate') { + my $entry = { label => lc($metric) . '-' . lc($statistic), set => { + key_values => [ { name => $metric . '_' . $statistic }, { name => 'display' }, { name => 'stat' } ], + output_template => $metric . ': %.2f %%', + perfdatas => [ + { label => lc($metric) . '_' . lc($statistic), value => $metric . '_' . $statistic . '_absolute', + template => '%.2f', min => 0, max => 100, unit => '%', + label_extra_instance => 1, instance_use => 'display_absolute' }, + ], + } + }; + push @{$self->{maps_counters}->{metric}}, $entry; + } + } +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $self->{version} = '1.0'; + $options{options}->add_options(arguments => + { + "id:s@" => { name => 'id' }, + "filter-metric:s" => { name => 'filter_metric' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + if (!defined($self->{option_results}->{id}) || $self->{option_results}->{id} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --id option."); + $self->{output}->option_exit(); + } + + foreach my $instance (@{$self->{option_results}->{id}}) { + if ($instance ne '') { + push @{$self->{aws_instance}}, $instance; + } + } + + $self->{aws_timeframe} = defined($self->{option_results}->{timeframe}) ? $self->{option_results}->{timeframe} : 600; + $self->{aws_period} = defined($self->{option_results}->{period}) ? $self->{option_results}->{period} : 60; + + $self->{aws_statistics} = ['Average']; + if (defined($self->{option_results}->{statistic})) { + $self->{aws_statistics} = []; + foreach my $stat (@{$self->{option_results}->{statistic}}) { + if ($stat ne '') { + push @{$self->{aws_statistics}}, ucfirst(lc($stat)); + } + } + } + + foreach my $metric ('TotalErrorRate', '4xxErrorRate', '5xxErrorRate') { + next if (defined($self->{option_results}->{filter_metric}) && $self->{option_results}->{filter_metric} ne '' + && $metric !~ /$self->{option_results}->{filter_metric}/); + + push @{$self->{aws_metrics}}, $metric; + } +} + +sub manage_selection { + my ($self, %options) = @_; + + my %metric_results; + foreach my $instance (@{$self->{aws_instance}}) { + $metric_results{$instance} = $options{custom}->cloudwatch_get_metrics( + region => $self->{option_results}->{region}, + namespace => 'AWS/CloudFront', + dimensions => [ { Name => 'Region', Value => 'Global' }, { Name => 'DistributionId', Value => $instance } ], + 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($metric_results{$instance}->{$metric}->{lc($statistic)}) && !defined($self->{option_results}->{zeroed})); + + $self->{metric}->{$instance . "_" . lc($statistic)}->{display} = $instance; + $self->{metric}->{$instance . "_" . lc($statistic)}->{stat} = lc($statistic); + $self->{metric}->{$instance . "_" . lc($statistic)}->{timeframe} = $self->{aws_timeframe}; + $self->{metric}->{$instance . "_" . lc($statistic)}->{$metric . "_" . lc($statistic)} = defined($metric_results{$instance}->{$metric}->{lc($statistic)}) ? $metric_results{$instance}->{$metric}->{lc($statistic)} : 0; + } + } + } + + if (scalar(keys %{$self->{metric}}) <= 0) { + $self->{output}->add_option_msg(short_msg => 'No metrics. Check your options or use --zeroed option to set 0 on undefined values'); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check CloudFront instances errors. + +Example: +perl centreon_plugins.pl --plugin=cloud::aws::cloudfront::plugin --custommode=paws --mode=errors --region='eu-west-1' +--id='E8T734E1AF1L4' --statistic='sum' --critical-totalerrorsrate-sum='10' --verbose + +See 'https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/cf-metricscollected.html' for more informations. + +Default statistic: 'average' / Valid statistic: 'average'. + +=over 8 + +=item B<--id> + +Set the instance id (Required) (Can be multiple). + +=item B<--filter-metric> + +Filter metrics (Can be: 'TotalErrorRate', '4xxErrorRate', '5xxErrorRate') +(Can be a regexp). + +=item B<--warning-$metric$-$statistic$> + +Thresholds warning ($metric$ can be: 'totalerrorrate', '4xxerrorrate', '5xxerrorrate', +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=item B<--critical-$metric$-$statistic$> + +Thresholds critical ($metric$ can be: 'totalerrorrate', '4xxerrorrate', '5xxerrorrate', +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=back + +=cut diff --git a/cloud/aws/cloudfront/mode/requests.pm b/cloud/aws/cloudfront/mode/requests.pm new file mode 100644 index 000000000..9ce506137 --- /dev/null +++ b/cloud/aws/cloudfront/mode/requests.pm @@ -0,0 +1,223 @@ +# +# Copyright 2018 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::cloudfront::mode::requests; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +my $instance_mode; + +sub prefix_metric_output { + my ($self, %options) = @_; + + return "Instance '" . $options{instance_value}->{display} . "' " . $options{instance_value}->{stat} . " "; +} + +sub custom_metric_calc { + my ($self, %options) = @_; + + $self->{result_values}->{timeframe} = $options{new_datas}->{$self->{instance} . '_timeframe'}; + $self->{result_values}->{value} = $options{new_datas}->{$self->{instance} . '_' . $options{extra_options}->{metric} . '_' . $options{extra_options}->{stat}}; + $self->{result_values}->{value_per_sec} = $self->{result_values}->{value} / $self->{result_values}->{timeframe}; + $self->{result_values}->{stat} = $options{extra_options}->{stat}; + $self->{result_values}->{metric} = $options{extra_options}->{metric}; + $self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_display'}; + return 0; +} + +sub custom_metric_threshold { + my ($self, %options) = @_; + + my $exit = $self->{perfdata}->threshold_check(value => defined($instance_mode->{option_results}->{per_sec}) ? $self->{result_values}->{value_per_sec} : $self->{result_values}->{value}, + threshold => [ { label => 'critical-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat}), exit_litteral => 'critical' }, + { label => 'warning-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat}), exit_litteral => 'warning' } ]); + return $exit; +} + +sub custom_metric_perfdata { + my ($self, %options) = @_; + + my $extra_label = ''; + $extra_label = '_' . lc($self->{result_values}->{display}) if (!defined($options{extra_instance}) || $options{extra_instance} != 0); + + $self->{output}->perfdata_add(label => lc($self->{result_values}->{metric}) . "_" . lc($self->{result_values}->{stat}) . $extra_label, + unit => defined($instance_mode->{option_results}->{per_sec}) ? 'requests/s' : 'requests', + value => sprintf("%.2f", defined($instance_mode->{option_results}->{per_sec}) ? $self->{result_values}->{value_per_sec} : $self->{result_values}->{value}), + warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat})), + critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat})), + ); +} + +sub custom_metric_output { + my ($self, %options) = @_; + my $msg = ""; + + if (defined($instance_mode->{option_results}->{per_sec})) { + my ($value, $unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{value_per_sec}); + $msg = $self->{result_values}->{metric} . ": " . $value . "requests/s"; + } else { + my ($value, $unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{value}); + $msg = $self->{result_values}->{metric} . ": " . $value . "requests"; + } + return $msg; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'metric', type => 1, cb_prefix_output => 'prefix_metric_output', message_multiple => "All requests metrics are ok", skipped_code => { -10 => 1 } }, + ]; + + foreach my $statistic ('minimum', 'maximum', 'average', 'sum') { + foreach my $metric ('Requests') { + my $entry = { label => lc($metric) . '-' . lc($statistic), set => { + key_values => [ { name => $metric . '_' . $statistic }, { name => 'display' }, { name => 'stat' }, { name => 'timeframe' } ], + closure_custom_calc => $self->can('custom_metric_calc'), + closure_custom_calc_extra_options => { metric => $metric, stat => $statistic }, + closure_custom_output => $self->can('custom_metric_output'), + closure_custom_perfdata => $self->can('custom_metric_perfdata'), + closure_custom_threshold_check => $self->can('custom_metric_threshold'), + } + }; + push @{$self->{maps_counters}->{metric}}, $entry; + } + } +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $self->{version} = '1.0'; + $options{options}->add_options(arguments => + { + "id:s@" => { name => 'id' }, + "per-sec" => { name => 'per_sec' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + if (!defined($self->{option_results}->{id}) || $self->{option_results}->{id} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --id option."); + $self->{output}->option_exit(); + } + + foreach my $instance (@{$self->{option_results}->{id}}) { + if ($instance ne '') { + push @{$self->{aws_instance}}, $instance; + } + } + + $self->{aws_timeframe} = defined($self->{option_results}->{timeframe}) ? $self->{option_results}->{timeframe} : 600; + $self->{aws_period} = defined($self->{option_results}->{period}) ? $self->{option_results}->{period} : 60; + + $self->{aws_statistics} = ['Sum']; + if (defined($self->{option_results}->{statistic})) { + $self->{aws_statistics} = []; + foreach my $stat (@{$self->{option_results}->{statistic}}) { + if ($stat ne '') { + push @{$self->{aws_statistics}}, ucfirst(lc($stat)); + } + } + } + + push @{$self->{aws_metrics}}, 'Requests'; + + $instance_mode = $self; +} + +sub manage_selection { + my ($self, %options) = @_; + + my %metric_results; + foreach my $instance (@{$self->{aws_instance}}) { + $metric_results{$instance} = $options{custom}->cloudwatch_get_metrics( + region => $self->{option_results}->{region}, + namespace => 'AWS/CloudFront', + dimensions => [ { Name => 'Region', Value => 'Global' }, { Name => 'DistributionId', Value => $instance } ], + 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($metric_results{$instance}->{$metric}->{lc($statistic)}) && !defined($self->{option_results}->{zeroed})); + + $self->{metric}->{$instance . "_" . lc($statistic)}->{display} = $instance; + $self->{metric}->{$instance . "_" . lc($statistic)}->{stat} = lc($statistic); + $self->{metric}->{$instance . "_" . lc($statistic)}->{timeframe} = $self->{aws_timeframe}; + $self->{metric}->{$instance . "_" . lc($statistic)}->{$metric . "_" . lc($statistic)} = defined($metric_results{$instance}->{$metric}->{lc($statistic)}) ? $metric_results{$instance}->{$metric}->{lc($statistic)} : 0; + } + } + } + + if (scalar(keys %{$self->{metric}}) <= 0) { + $self->{output}->add_option_msg(short_msg => 'No metrics. Check your options or use --zeroed option to set 0 on undefined values'); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check CloudFront instances requests. + +Example: +perl centreon_plugins.pl --plugin=cloud::aws::cloudfront::plugin --custommode=paws --mode=requests --region='eu-west-1' +--id='E8T734E1AF1L4' --statistic='sum' --critical-requests-sum='10' --verbose + +See 'https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/cf-metricscollected.html' for more informations. + +Default statistic: 'sum' / Valid statistic: 'sum'. + +=over 8 + +=item B<--id> + +Set the instance id (Required) (Can be multiple). + +=item B<--warning-$metric$-$statistic$> + +Thresholds warning ($metric$ can be: 'requests', +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=item B<--critical-$metric$-$statistic$> + +Thresholds critical ($metric$ can be: 'requests', +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=back + +=cut diff --git a/cloud/aws/cloudfront/mode/throughput.pm b/cloud/aws/cloudfront/mode/throughput.pm new file mode 100644 index 000000000..3d18b842f --- /dev/null +++ b/cloud/aws/cloudfront/mode/throughput.pm @@ -0,0 +1,234 @@ +# +# Copyright 2018 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::cloudfront::mode::throughput; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +my $instance_mode; + +sub prefix_metric_output { + my ($self, %options) = @_; + + return "Instance '" . $options{instance_value}->{display} . "' " . $options{instance_value}->{stat} . " "; +} + +sub custom_metric_calc { + my ($self, %options) = @_; + + $self->{result_values}->{timeframe} = $options{new_datas}->{$self->{instance} . '_timeframe'}; + $self->{result_values}->{value} = $options{new_datas}->{$self->{instance} . '_' . $options{extra_options}->{metric} . '_' . $options{extra_options}->{stat}}; + $self->{result_values}->{value_per_sec} = $self->{result_values}->{value} / $self->{result_values}->{timeframe}; + $self->{result_values}->{stat} = $options{extra_options}->{stat}; + $self->{result_values}->{metric} = $options{extra_options}->{metric}; + $self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_display'}; + return 0; +} + +sub custom_metric_threshold { + my ($self, %options) = @_; + + my $exit = $self->{perfdata}->threshold_check(value => defined($instance_mode->{option_results}->{per_sec}) ? $self->{result_values}->{value_per_sec} : $self->{result_values}->{value}, + threshold => [ { label => 'critical-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat}), exit_litteral => 'critical' }, + { label => 'warning-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat}), exit_litteral => 'warning' } ]); + return $exit; +} + +sub custom_metric_perfdata { + my ($self, %options) = @_; + + my $extra_label = ''; + $extra_label = '_' . lc($self->{result_values}->{display}) if (!defined($options{extra_instance}) || $options{extra_instance} != 0); + + $self->{output}->perfdata_add(label => lc($self->{result_values}->{metric}) . "_" . lc($self->{result_values}->{stat}) . $extra_label, + unit => defined($instance_mode->{option_results}->{per_sec}) ? 'B/s' : 'B', + value => sprintf("%.2f", defined($instance_mode->{option_results}->{per_sec}) ? $self->{result_values}->{value_per_sec} : $self->{result_values}->{value}), + warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat})), + critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat})), + ); +} + +sub custom_metric_output { + my ($self, %options) = @_; + my $msg = ""; + + if (defined($instance_mode->{option_results}->{per_sec})) { + my ($value, $unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{value_per_sec}); + $msg = $self->{result_values}->{metric} . ": " . $value . $unit . "/s"; + } else { + my ($value, $unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{value}); + $msg = $self->{result_values}->{metric} . ": " . $value . $unit; + } + return $msg; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'metric', type => 1, cb_prefix_output => 'prefix_metric_output', message_multiple => "All throughput metrics are ok", skipped_code => { -10 => 1 } }, + ]; + + foreach my $statistic ('minimum', 'maximum', 'average', 'sum') { + foreach my $metric ('BytesDownloaded', 'BytesUploaded') { + my $entry = { label => lc($metric) . '-' . lc($statistic), set => { + key_values => [ { name => $metric . '_' . $statistic }, { name => 'display' }, { name => 'stat' }, { name => 'timeframe' } ], + closure_custom_calc => $self->can('custom_metric_calc'), + closure_custom_calc_extra_options => { metric => $metric, stat => $statistic }, + closure_custom_output => $self->can('custom_metric_output'), + closure_custom_perfdata => $self->can('custom_metric_perfdata'), + closure_custom_threshold_check => $self->can('custom_metric_threshold'), + } + }; + push @{$self->{maps_counters}->{metric}}, $entry; + } + } +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $self->{version} = '1.0'; + $options{options}->add_options(arguments => + { + "id:s@" => { name => 'id' }, + "filter-metric:s" => { name => 'filter_metric' }, + "per-sec" => { name => 'per_sec' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + if (!defined($self->{option_results}->{id}) || $self->{option_results}->{id} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --id option."); + $self->{output}->option_exit(); + } + + foreach my $instance (@{$self->{option_results}->{id}}) { + if ($instance ne '') { + push @{$self->{aws_instance}}, $instance; + } + } + + $self->{aws_timeframe} = defined($self->{option_results}->{timeframe}) ? $self->{option_results}->{timeframe} : 600; + $self->{aws_period} = defined($self->{option_results}->{period}) ? $self->{option_results}->{period} : 60; + + $self->{aws_statistics} = ['Sum']; + if (defined($self->{option_results}->{statistic})) { + $self->{aws_statistics} = []; + foreach my $stat (@{$self->{option_results}->{statistic}}) { + if ($stat ne '') { + push @{$self->{aws_statistics}}, ucfirst(lc($stat)); + } + } + } + + foreach my $metric ('BytesDownloaded', 'BytesUploaded') { + next if (defined($self->{option_results}->{filter_metric}) && $self->{option_results}->{filter_metric} ne '' + && $metric !~ /$self->{option_results}->{filter_metric}/); + + push @{$self->{aws_metrics}}, $metric; + } + + $instance_mode = $self; +} + +sub manage_selection { + my ($self, %options) = @_; + + my %metric_results; + foreach my $instance (@{$self->{aws_instance}}) { + $metric_results{$instance} = $options{custom}->cloudwatch_get_metrics( + region => $self->{option_results}->{region}, + namespace => 'AWS/CloudFront', + dimensions => [ { Name => 'Region', Value => 'Global' }, { Name => 'DistributionId', Value => $instance } ], + 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($metric_results{$instance}->{$metric}->{lc($statistic)}) && !defined($self->{option_results}->{zeroed})); + + $self->{metric}->{$instance . "_" . lc($statistic)}->{display} = $instance; + $self->{metric}->{$instance . "_" . lc($statistic)}->{stat} = lc($statistic); + $self->{metric}->{$instance . "_" . lc($statistic)}->{timeframe} = $self->{aws_timeframe}; + $self->{metric}->{$instance . "_" . lc($statistic)}->{$metric . "_" . lc($statistic)} = defined($metric_results{$instance}->{$metric}->{lc($statistic)}) ? $metric_results{$instance}->{$metric}->{lc($statistic)} : 0; + } + } + } + + if (scalar(keys %{$self->{metric}}) <= 0) { + $self->{output}->add_option_msg(short_msg => 'No metrics. Check your options or use --zeroed option to set 0 on undefined values'); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check CloudFront instances throughput. + +Example: +perl centreon_plugins.pl --plugin=cloud::aws::cloudfront::plugin --custommode=paws --mode=throughput --region='eu-west-1' +--id='E8T734E1AF1L4' --statistic='sum' --critical-bytesdownloaded-sum='10' --verbose + +See 'https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/cf-metricscollected.html' for more informations. + +Default statistic: 'sum' / Valid statistic: 'sum'. + +=over 8 + +=item B<--id> + +Set the instance id (Required) (Can be multiple). + +=item B<--filter-metric> + +Filter metrics (Can be: 'BytesDownloaded', 'BytesUploaded') +(Can be a regexp). + +=item B<--warning-$metric$-$statistic$> + +Thresholds warning ($metric$ can be: 'bytesdownloaded', 'bytesuploaded', +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=item B<--critical-$metric$-$statistic$> + +Thresholds critical ($metric$ can be: 'bytesdownloaded', 'bytesuploaded', +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=back + +=cut diff --git a/cloud/aws/cloudfront/plugin.pm b/cloud/aws/cloudfront/plugin.pm new file mode 100644 index 000000000..334c4907b --- /dev/null +++ b/cloud/aws/cloudfront/plugin.pm @@ -0,0 +1,54 @@ +# +# Copyright 2018 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::cloudfront::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} } = ( + 'errors' => 'cloud::aws::cloudfront::mode::errors', + 'requests' => 'cloud::aws::cloudfront::mode::requests', + 'throughput' => 'cloud::aws::cloudfront::mode::throughput', + ); + + $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 CloudFront. + +Works for 'us-east-1' region only. + +=cut diff --git a/cloud/aws/mode/cloudwatchgetalarms.pm b/cloud/aws/cloudwatch/mode/getalarms.pm similarity index 89% rename from cloud/aws/mode/cloudwatchgetalarms.pm rename to cloud/aws/cloudwatch/mode/getalarms.pm index 01e8762c6..91530e3a6 100644 --- a/cloud/aws/mode/cloudwatchgetalarms.pm +++ b/cloud/aws/cloudwatch/mode/getalarms.pm @@ -18,7 +18,7 @@ # limitations under the License. # -package cloud::aws::mode::cloudwatchgetalarms; +package cloud::aws::cloudwatch::mode::getalarms; use base qw(centreon::plugins::templates::counter); @@ -103,11 +103,10 @@ sub new { $self->{version} = '1.0'; $options{options}->add_options(arguments => { - "region:s" => { name => 'region' }, - "filter-alarm-name:s" => { name => 'filter_alarm_name' }, - "warning-status:s" => { name => 'warning_status', default => '%{state_value} =~ /INSUFFICIENT_DATA/i' }, - "critical-status:s" => { name => 'critical_status', default => '%{state_value} =~ /ALARM/i' }, - "memory" => { name => 'memory' }, + "filter-alarm-name:s" => { name => 'filter_alarm_name' }, + "warning-status:s" => { name => 'warning_status', default => '%{state_value} =~ /INSUFFICIENT_DATA/i' }, + "critical-status:s" => { name => 'critical_status', default => '%{state_value} =~ /ALARM/i' }, + "memory" => { name => 'memory' }, }); centreon::plugins::misc::mymodule_load(output => $self->{output}, module => 'Date::Parse', @@ -120,10 +119,6 @@ sub check_options { my ($self, %options) = @_; $self->SUPER::check_options(%options); - if (!defined($self->{option_results}->{region}) || $self->{option_results}->{region} eq '') { - $self->{output}->add_option_msg(short_msg => "Need to specify --region option."); - $self->{output}->option_exit(); - } $instance_mode = $self; $self->change_macros(); @@ -196,10 +191,6 @@ Check cloudwatch alarms. =over 8 -=item B<--region> - -Set the region name (Required). - =item B<--filter-alarm-name> Filter by alarm name (can be a regexp). diff --git a/cloud/aws/mode/cloudwatchgetmetrics.pm b/cloud/aws/cloudwatch/mode/getmetrics.pm similarity index 83% rename from cloud/aws/mode/cloudwatchgetmetrics.pm rename to cloud/aws/cloudwatch/mode/getmetrics.pm index ceac2cd04..f255dbb54 100644 --- a/cloud/aws/mode/cloudwatchgetmetrics.pm +++ b/cloud/aws/cloudwatch/mode/getmetrics.pm @@ -18,7 +18,7 @@ # limitations under the License. # -package cloud::aws::mode::cloudwatchgetmetrics; +package cloud::aws::cloudwatch::mode::getmetrics; use base qw(centreon::plugins::templates::counter); @@ -90,13 +90,9 @@ sub new { $self->{version} = '1.0'; $options{options}->add_options(arguments => { - "region:s" => { name => 'region' }, - "namespace:s" => { name => 'namespace' }, - "dimension:s%" => { name => 'dimension' }, - "metric:s@" => { name => 'metric' }, - "statistic:s@" => { name => 'statistic' }, - "timeframe:s" => { name => 'timeframe', default => 600 }, - "period:s" => { name => 'period', default => 60 }, + "namespace:s" => { name => 'namespace' }, + "dimension:s%" => { name => 'dimension' }, + "metric:s@" => { name => 'metric' }, }); return $self; @@ -106,10 +102,6 @@ sub check_options { my ($self, %options) = @_; $self->SUPER::check_options(%options); - if (!defined($self->{option_results}->{region}) || $self->{option_results}->{region} eq '') { - $self->{output}->add_option_msg(short_msg => "Need to specify --region option."); - $self->{output}->option_exit(); - } if (!defined($self->{option_results}->{namespace}) || $self->{option_results}->{namespace} eq '') { $self->{output}->add_option_msg(short_msg => "Need to specify --namespace option."); $self->{output}->option_exit(); @@ -138,6 +130,9 @@ sub check_options { $self->{output}->add_option_msg(short_msg => "Need to specify --dimension option."); $self->{output}->option_exit(); } + + $self->{aws_timeframe} = defined($self->{option_results}->{timeframe}) ? $self->{option_results}->{timeframe} : 600; + $self->{aws_period} = defined($self->{option_results}->{period}) ? $self->{option_results}->{period} : 60; $self->{aws_statistics} = ['Average']; if (defined($self->{option_results}->{statistic})) { @@ -174,8 +169,8 @@ sub manage_selection { dimensions => $self->{aws_dimensions}, metrics => $self->{aws_metrics}, statistics => $self->{aws_statistics}, - timeframe => $self->{option_results}->{timeframe}, - period => $self->{option_results}->{period}, + timeframe => $self->{aws_timeframe}, + period => $self->{aws_period}, ); $self->{metrics} = {}; @@ -201,14 +196,12 @@ __END__ Check cloudwatch metrics (same dimension and namespace). Example: -perl centreon_plugins.pl --plugin=cloud::aws::plugin --custommode=paws --mode=cloudwatch-get-metrics --region=eu-west-1 --namespace=AWS/EC2 --dimension=InstanceId=i-01622936185e32a45 --metric=CPUUtilization --metric=CPUCreditUsage --statistic=average --statistic=max –-period=60 --timeframe=600 --warning-metric= --critical-metric= +perl centreon_plugins.pl --plugin=cloud::aws::plugin --custommode=paws --mode=cloudwatch-get-metrics --region=eu-west-1 +--namespace=AWS/EC2 --dimension=InstanceId=i-01622936185e32a45 --metric=CPUUtilization --metric=CPUCreditUsage +--statistic=average --statistic=max –-period=60 --timeframe=600 --warning-metric= --critical-metric= =over 8 -=item B<--region> - -Set the region name (Required). - =item B<--namespace> Set cloudwatch namespace (Required). @@ -221,18 +214,6 @@ Set cloudwatch dimensions (Required). Set cloudwatch metrics (Required). -=item B<--statistic> - -Set cloudwatch statistics (Default: 'average'). - -=item B<--period> - -Set period in seconds (Default: 60). - -=item B<--timeframe> - -Set timeframe in seconds (Default: 600). - =item B<--warning-metric> Threshold warning. diff --git a/cloud/aws/mode/cloudwatchlistmetrics.pm b/cloud/aws/cloudwatch/mode/listmetrics.pm similarity index 82% rename from cloud/aws/mode/cloudwatchlistmetrics.pm rename to cloud/aws/cloudwatch/mode/listmetrics.pm index dd904f2f2..102cbe07b 100644 --- a/cloud/aws/mode/cloudwatchlistmetrics.pm +++ b/cloud/aws/cloudwatch/mode/listmetrics.pm @@ -18,7 +18,7 @@ # limitations under the License. # -package cloud::aws::mode::cloudwatchlistmetrics; +package cloud::aws::cloudwatch::mode::listmetrics; use base qw(centreon::plugins::mode); @@ -33,8 +33,8 @@ sub new { $self->{version} = '1.0'; $options{options}->add_options(arguments => { - "region:s" => { name => 'region' }, - "namespace:s" => { name => 'namespace' }, + "namespace:s" => { name => 'namespace' }, + "metric:s" => { name => 'metric' }, }); return $self; @@ -43,17 +43,14 @@ sub new { sub check_options { my ($self, %options) = @_; $self->SUPER::init(%options); - - if (!defined($self->{option_results}->{region}) || $self->{option_results}->{region} eq '') { - $self->{output}->add_option_msg(short_msg => "Need to specify --region option."); - $self->{output}->option_exit(); - } } sub manage_selection { my ($self, %options) = @_; - $self->{metrics} = $options{custom}->cloudwatch_list_metrics(region => $self->{option_results}->{region}, namespace => $self->{option_results}->{namespace}); + $self->{metrics} = $options{custom}->cloudwatch_list_metrics(region => $self->{option_results}->{region}, + namespace => $self->{option_results}->{namespace}, + metric => $self->{option_results}->{metric}); } sub get_dimensions_str { @@ -113,14 +110,14 @@ List cloudwatch metrics. =over 8 -=item B<--region> - -Set the region name (Required). - =item B<--namespace> Set cloudwatch namespace. +=item B<--metric> + +Set cloudwatch metric. + =back =cut diff --git a/cloud/aws/cloudwatch/plugin.pm b/cloud/aws/cloudwatch/plugin.pm new file mode 100644 index 000000000..3aed93b17 --- /dev/null +++ b/cloud/aws/cloudwatch/plugin.pm @@ -0,0 +1,52 @@ +# +# Copyright 2018 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::cloudwatch::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} } = ( + 'get-alarms' => 'cloud::aws::cloudwatch::mode::getalarms', + 'get-metrics' => 'cloud::aws::cloudwatch::mode::getmetrics', + 'list-metrics' => 'cloud::aws::cloudwatch::mode::listmetrics', + ); + + $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 CloudWatch. + +=cut diff --git a/cloud/aws/custom/awscli.pm b/cloud/aws/custom/awscli.pm index 05b7675da..32665f115 100644 --- a/cloud/aws/custom/awscli.pm +++ b/cloud/aws/custom/awscli.pm @@ -41,17 +41,22 @@ sub new { if (!defined($options{noptions})) { $options{options}->add_options(arguments => - { - "aws-secret-key:s" => { name => 'aws_secret_key' }, - "aws-access-key:s" => { name => 'aws_access_key' }, - "timeout:s" => { name => 'timeout', default => 50 }, - "sudo" => { name => 'sudo' }, - "command:s" => { name => 'command', default => 'aws' }, - "command-path:s" => { name => 'command_path' }, - "command-options:s" => { name => 'command_options', default => '' }, + { + "aws-secret-key:s" => { name => 'aws_secret_key' }, + "aws-access-key:s" => { name => 'aws_access_key' }, + "region:s" => { name => 'region' }, + "timeframe:s" => { name => 'timeframe' }, + "period:s" => { name => 'period' }, + "statistic:s@" => { name => 'statistic' }, + "zeroed" => { name => 'zeroed' }, + "timeout:s" => { name => 'timeout', default => 50 }, + "sudo" => { name => 'sudo' }, + "command:s" => { name => 'command', default => 'aws' }, + "command-path:s" => { name => 'command_path' }, + "command-options:s" => { name => 'command_options', default => '' }, }); } - $options{options}->add_help(package => __PACKAGE__, sections => 'AWS OPTIONS', once => 1); + $options{options}->add_help(package => __PACKAGE__, sections => 'AWSCLI OPTIONS', once => 1); $self->{output} = $options{output}; $self->{mode} = $options{mode}; @@ -91,6 +96,20 @@ sub check_options { $ENV{AWS_ACCESS_KEY_ID} = $self->{option_results}->{aws_access_key}; } + if (!defined($self->{option_results}->{region}) || $self->{option_results}->{region} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --region option."); + $self->{output}->option_exit(); + } + + if (defined($self->{option_results}->{statistic})) { + foreach my $statistic (@{$self->{option_results}->{statistic}}) { + if ($statistic !~ /minimum|maximum|average|sum/) { + $self->{output}->add_option_msg(short_msg => "Statistic '" . $statistic . "' is not handled"); + $self->{output}->option_exit(); + } + } + } + return 0; } @@ -98,12 +117,13 @@ sub cloudwatch_get_metrics_set_cmd { my ($self, %options) = @_; return if (defined($self->{option_results}->{command_options}) && $self->{option_results}->{command_options} ne ''); + my $cmd_options = "cloudwatch get-metric-statistics --region $options{region} --namespace $options{namespace} --metric-name '$options{metric_name}' --start-time $options{start_time} --end-time $options{end_time} --period $options{period} --statistics " . join(' ', @{$options{statistics}}) . " --output json --dimensions"; foreach my $entry (@{$options{dimensions}}) { $cmd_options .= " 'Name=$entry->{Name},Value=$entry->{Value}'"; } - + return $cmd_options; } @@ -210,6 +230,8 @@ sub cloudwatch_list_metrics_set_cmd { return if (defined($self->{option_results}->{command_options}) && $self->{option_results}->{command_options} ne ''); my $cmd_options = "cloudwatch list-metrics --region $options{region} --output json"; + $cmd_options .= " --namespace $options{namespace}" if defined($options{namespace}); + $cmd_options .= " --metric-name $options{metric}" if defined($options{metric}); return $cmd_options; } @@ -268,12 +290,106 @@ sub ec2_get_instances_status { my $instance_results = {}; foreach (@{$list_instances->{InstanceStatuses}}) { - $instance_results->{$_->{InstanceId}} = { state => $_->{InstanceState}->{Name} }; + $instance_results->{$_->{InstanceId}} = { state => $_->{InstanceState}->{Name}, + status => => $_->{InstanceStatus}->{Status} }; } return $instance_results; } +sub ec2_list_resources_set_cmd { + my ($self, %options) = @_; + + return if (defined($self->{option_results}->{command_options}) && $self->{option_results}->{command_options} ne ''); + my $cmd_options = "ec2 describe-instances --no-dry-run --region $options{region} --output json"; + return $cmd_options; +} + +sub ec2_list_resources { + my ($self, %options) = @_; + + my $cmd_options = $self->ec2_list_resources_set_cmd(%options); + my ($response) = centreon::plugins::misc::execute( + output => $self->{output}, + options => $self->{option_results}, + sudo => $self->{option_results}->{sudo}, + command => $self->{option_results}->{command}, + command_path => $self->{option_results}->{command_path}, + command_options => $cmd_options + ); + my $list_instances; + eval { + $list_instances = JSON::XS->new->utf8->decode($response); + }; + if ($@) { + $self->{output}->add_option_msg(short_msg => "Cannot decode json response: $@"); + $self->{output}->option_exit(); + } + + my $resource_results = []; + foreach my $reservation (@{$list_instances->{Reservations}}) { + foreach my $instance (@{$reservation->{Instances}}) { + my @instance_tags; + foreach my $tag (@{$instance->{Tags}}) { + my %already = map { $_->{Name} => $_ } @{$resource_results}; + if ($tag->{Key} eq "aws:autoscaling:groupName") { + next if (defined($already{$tag->{Value}})); + push @{$resource_results}, { + Name => $tag->{Value}, + Type => 'asg', + }; + } elsif ($tag->{Key} eq "Name" && defined($tag->{Value})) { + push @instance_tags, $tag->{Value}; + } + } + push @{$resource_results}, { + Name => $instance->{InstanceId}, + Type => 'instance', + AvailabilityZone => $instance->{Placement}->{AvailabilityZone}, + InstanceType => $instance->{InstanceType}, + State => $instance->{State}->{Name}, + Tags => join(",", @instance_tags), + }; + + } + } + + return $resource_results; +} + +sub asg_get_resources_set_cmd { + my ($self, %options) = @_; + + return if (defined($self->{option_results}->{command_options}) && $self->{option_results}->{command_options} ne ''); + my $cmd_options = "autoscaling describe-auto-scaling-groups --region $options{region} --output json"; + return $cmd_options; +} + +sub asg_get_resources { + my ($self, %options) = @_; + + my $cmd_options = $self->asg_get_resources_set_cmd(%options); + my ($response) = centreon::plugins::misc::execute( + output => $self->{output}, + options => $self->{option_results}, + sudo => $self->{option_results}->{sudo}, + command => $self->{option_results}->{command}, + command_path => $self->{option_results}->{command_path}, + command_options => $cmd_options + ); + + my $autoscaling_groups; + eval { + $autoscaling_groups = JSON::XS->new->utf8->decode($response); + }; + if ($@) { + $self->{output}->add_option_msg(short_msg => "Cannot decode json response: $@"); + $self->{output}->option_exit(); + } + + return \@{$autoscaling_groups->{AutoScalingGroups}}; +} + sub rds_get_instances_status_set_cmd { my ($self, %options) = @_; @@ -311,6 +427,91 @@ sub rds_get_instances_status { return $instance_results; } +sub rds_list_instances_set_cmd { + my ($self, %options) = @_; + + return if (defined($self->{option_results}->{command_options}) && $self->{option_results}->{command_options} ne ''); + my $cmd_options = "rds describe-db-instances --region $options{region} --output json"; + return $cmd_options; +} + +sub rds_list_instances { + my ($self, %options) = @_; + + my $cmd_options = $self->rds_get_instances_status_set_cmd(%options); + my ($response) = centreon::plugins::misc::execute( + output => $self->{output}, + options => $self->{option_results}, + sudo => $self->{option_results}->{sudo}, + command => $self->{option_results}->{command}, + command_path => $self->{option_results}->{command_path}, + command_options => $cmd_options + ); + my $list_instances; + eval { + $list_instances = JSON::XS->new->utf8->decode($response); + }; + if ($@) { + $self->{output}->add_option_msg(short_msg => "Cannot decode json response: $@"); + $self->{output}->option_exit(); + } + + my $instance_results = []; + foreach my $instance (@{$list_instances->{DBInstances}}) { + push @{$instance_results}, { + Name => $instance->{DBInstanceIdentifier}, + AvailabilityZone => $instance->{AvailabilityZone}, + Engine => $instance->{Engine}, + StorageType => $instance->{StorageType}, + DBInstanceStatus => $instance->{DBInstanceStatus}, + }; + } + + return $instance_results; +} + +sub rds_list_clusters_set_cmd { + my ($self, %options) = @_; + + return if (defined($self->{option_results}->{command_options}) && $self->{option_results}->{command_options} ne ''); + my $cmd_options = "rds describe-db-clusters --region $options{region} --output json"; + return $cmd_options; +} + +sub rds_list_clusters { + my ($self, %options) = @_; + + my $cmd_options = $self->rds_list_clusters_set_cmd(%options); + my ($response) = centreon::plugins::misc::execute( + output => $self->{output}, + options => $self->{option_results}, + sudo => $self->{option_results}->{sudo}, + command => $self->{option_results}->{command}, + command_path => $self->{option_results}->{command_path}, + command_options => $cmd_options + ); + my $list_clusters; + eval { + $list_clusters = JSON::XS->new->utf8->decode($response); + }; + if ($@) { + $self->{output}->add_option_msg(short_msg => "Cannot decode json response: $@"); + $self->{output}->option_exit(); + } + + my $cluster_results = []; + foreach my $cluster (@{$list_clusters->{DBClusters}}) { + push @{$cluster_results}, { + Name => $cluster->{DBClusterIdentifier}, + DatabaseName => $cluster->{DatabaseName}, + Engine => $cluster->{Engine}, + Status => $cluster->{Status}, + }; + } + + return $cluster_results; +} + 1; __END__ @@ -323,7 +524,7 @@ Amazon AWS Amazon AWS -=head1 AWS OPTIONS +=head1 AWSCLI OPTIONS =over 8 @@ -335,9 +536,30 @@ Set AWS secret key. Set AWS access key. +=item B<--region> + +Set the region name (Required). + +=item B<--period> + +Set period in seconds. + +=item B<--timeframe> + +Set timeframe in seconds. + +=item B<--statistic> + +Set cloudwatch statistics (Can be: 'minimum', 'maximum', 'average', 'sum'). + +=item B<--zeroed> + +Set metrics value to 0 if none. Usefull when CloudWatch +does not return value when not defined. + =item B<--timeout> -Set timeout (Default: 50). +Set timeout in seconds (Default: 50). =item B<--sudo> diff --git a/cloud/aws/custom/paws.pm b/cloud/aws/custom/paws.pm index db73f93c2..2121ca2fd 100644 --- a/cloud/aws/custom/paws.pm +++ b/cloud/aws/custom/paws.pm @@ -42,11 +42,16 @@ sub new { if (!defined($options{noptions})) { $options{options}->add_options(arguments => { - "aws-secret-key:s" => { name => 'aws_secret_key' }, - "aws-access-key:s" => { name => 'aws_access_key' }, + "aws-secret-key:s" => { name => 'aws_secret_key' }, + "aws-access-key:s" => { name => 'aws_access_key' }, + "region:s" => { name => 'region' }, + "timeframe:s" => { name => 'timeframe' }, + "period:s" => { name => 'period' }, + "statistic:s@" => { name => 'statistic' }, + "zeroed" => { name => 'zeroed' }, }); } - $options{options}->add_help(package => __PACKAGE__, sections => 'AWS OPTIONS', once => 1); + $options{options}->add_help(package => __PACKAGE__, sections => 'PAWS OPTIONS', once => 1); $self->{output} = $options{output}; $self->{mode} = $options{mode}; @@ -86,6 +91,20 @@ sub check_options { $ENV{AWS_ACCESS_KEY} = $self->{option_results}->{aws_access_key}; } + if (!defined($self->{option_results}->{region}) || $self->{option_results}->{region} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --region option."); + $self->{output}->option_exit(); + } + + if (defined($self->{option_results}->{statistic})) { + foreach my $statistic (@{$self->{option_results}->{statistic}}) { + if ($statistic !~ /minimum|maximum|average|sum/) { + $self->{output}->add_option_msg(short_msg => "Statistic '" . $statistic . "' is not handled"); + $self->{output}->option_exit(); + } + } + } + return 0; } @@ -176,9 +195,10 @@ sub cloudwatch_list_metrics { my $metric_results = []; eval { my $cw = Paws->service('CloudWatch', region => $options{region}); - my %options = (); - $options{Namespace} = $options{namespace} if (defined($options{namespace})); - while ((my $list_metrics = $cw->ListMetrics(%options))) { + my %cw_options = (); + $cw_options{Namespace} = $options{namespace} if (defined($options{namespace})); + $cw_options{MetricName} = $options{metric} if (defined($options{metric})); + while ((my $list_metrics = $cw->ListMetrics(%cw_options))) { foreach (@{$list_metrics->{Metrics}}) { my $dimensions = []; foreach my $dimension (@{$_->{Dimensions}}) { @@ -192,7 +212,7 @@ sub cloudwatch_list_metrics { } last if (!defined($list_metrics->{NextToken})); - $options{NextToken} = $list_metrics->{NextToken}; + $cw_options{NextToken} = $list_metrics->{NextToken}; } }; if ($@) { @@ -210,8 +230,10 @@ sub ec2_get_instances_status { eval { my $ec2 = Paws->service('EC2', region => $options{region}); my $instances = $ec2->DescribeInstanceStatus(DryRun => 0, IncludeAllInstances => 1); + foreach (@{$instances->{InstanceStatuses}}) { - $instance_results->{$_->{InstanceId}} = { state => $_->{InstanceState}->{Name} }; + $instance_results->{$_->{InstanceId}} = { state => $_->{InstanceState}->{Name}, + status => => $_->{InstanceStatus}->{Status} }; } }; if ($@) { @@ -222,6 +244,65 @@ sub ec2_get_instances_status { return $instance_results; } +sub ec2_list_resources { + my ($self, %options) = @_; + + my $resource_results = []; + eval { + my $ec2 = Paws->service('EC2', region => $options{region}); + my $list_instances = $ec2->DescribeInstances(DryRun => 0); + + foreach my $reservation (@{$list_instances->{Reservations}}) { + foreach my $instance (@{$reservation->{Instances}}) { + my @instance_tags; + foreach my $tag (@{$instance->{Tags}}) { + my %already = map { $_->{Name} => $_ } @{$resource_results}; + if ($tag->{Key} eq "aws:autoscaling:groupName") { + next if (defined($already{$tag->{Value}})); + push @{$resource_results}, { + Name => $tag->{Value}, + Type => 'asg', + }; + } elsif (defined($tag->{Key}) && defined($tag->{Value})) { + push @instance_tags, $tag->{Key} . ":" . $tag->{Value}; + } + } + push @{$resource_results}, { + Name => $instance->{InstanceId}, + Type => 'instance', + AvailabilityZone => $instance->{Placement}->{AvailabilityZone}, + InstanceType => $instance->{InstanceType}, + State => $instance->{State}->{Name}, + Tags => join(",", @instance_tags), + }; + + } + } + }; + if ($@) { + $self->{output}->add_option_msg(short_msg => "error: $@"); + $self->{output}->option_exit(); + } + + return $resource_results; +} + +sub asg_get_resources { + my ($self, %options) = @_; + + my $autoscaling_groups = {}; + eval { + my $asg = Paws->service('AutoScaling', region => $options{region}); + $autoscaling_groups = $asg->DescribeAutoScalingGroups(); + }; + if ($@) { + $self->{output}->add_option_msg(short_msg => "error: $@"); + $self->{output}->option_exit(); + } + + return \@{$autoscaling_groups->{AutoScalingGroups}}; +} + sub rds_get_instances_status { my ($self, %options) = @_; @@ -241,6 +322,57 @@ sub rds_get_instances_status { return $instance_results; } +sub rds_list_instances { + my ($self, %options) = @_; + + my $instance_results = []; + eval { + my $rds = Paws->service('RDS', region => $options{region}); + my $list_instances = $rds->DescribeDBInstances(); + + foreach my $instance (@{$list_instances->{DBInstances}}) { + push @{$instance_results}, { + Name => $instance->{DBInstanceIdentifier}, + AvailabilityZone => $instance->{AvailabilityZone}, + Engine => $instance->{Engine}, + StorageType => $instance->{StorageType}, + DBInstanceStatus => $instance->{DBInstanceStatus}, + }; + } + }; + if ($@) { + $self->{output}->add_option_msg(short_msg => "error: $@"); + $self->{output}->option_exit(); + } + + return $instance_results; +} + +sub rds_list_clusters { + my ($self, %options) = @_; + + my $cluster_results = []; + eval { + my $rds = Paws->service('RDS', region => $options{region}); + my $list_clusters = $rds->DescribeDBClusters(); + + foreach my $cluster (@{$list_clusters->{DBClusters}}) { + push @{$cluster_results}, { + Name => $cluster->{DBClusterIdentifier}, + DatabaseName => $cluster->{DatabaseName}, + Engine => $cluster->{Engine}, + Status => $cluster->{Status}, + }; + } + }; + if ($@) { + $self->{output}->add_option_msg(short_msg => "error: $@"); + $self->{output}->option_exit(); + } + + return $cluster_results; +} + 1; __END__ @@ -253,7 +385,7 @@ Amazon AWS Amazon AWS -=head1 AWS OPTIONS +=head1 PAWS OPTIONS =over 8 @@ -265,6 +397,27 @@ Set AWS secret key. Set AWS access key. +=item B<--region> + +Set the region name (Required). + +=item B<--period> + +Set period in seconds. + +=item B<--timeframe> + +Set timeframe in seconds. + +=item B<--statistic> + +Set cloudwatch statistics (Can be: 'minimum', 'maximum', 'average', 'sum'). + +=item B<--zeroed> + +Set metrics value to 0 if none. Usefull when CloudWatch +does not return value when not defined. + =back =head1 DESCRIPTION diff --git a/cloud/aws/ebs/plugin.pm b/cloud/aws/ebs/plugin.pm new file mode 100644 index 000000000..f374546e5 --- /dev/null +++ b/cloud/aws/ebs/plugin.pm @@ -0,0 +1,52 @@ +# +# Copyright 2018 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::ebs::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} } = ( + 'volume-throughput' => 'cloud::aws::ebs::mode::volumethroughput', + 'volume-iops' => 'cloud::aws::ebs::mode::volumeiops', + 'volume-time' => 'cloud::aws::ebs::mode::volumetime', + ); + + $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 Elastic Block Store (Amazon EBS). + +=cut diff --git a/cloud/aws/ec2/mode/asgstatus.pm b/cloud/aws/ec2/mode/asgstatus.pm new file mode 100644 index 000000000..84fa660d2 --- /dev/null +++ b/cloud/aws/ec2/mode/asgstatus.pm @@ -0,0 +1,257 @@ +# +# Copyright 2018 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::ec2::mode::asgstatus; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +my $instance_mode; + +sub custom_status_threshold { + my ($self, %options) = @_; + my $status = 'ok'; + my $message; + + eval { + local $SIG{__WARN__} = sub { $message = $_[0]; }; + local $SIG{__DIE__} = sub { $message = $_[0]; }; + + my $label = $self->{label}; + if (defined($instance_mode->{option_results}->{'critical_' . $label}) && $instance_mode->{option_results}->{'critical_' . $label} ne '' && + eval "$instance_mode->{option_results}->{'critical_' . $label}") { + $status = 'critical'; + } elsif (defined($instance_mode->{option_results}->{'warning_' . $label}) && $instance_mode->{option_results}->{'warning_' . $label} ne '' && + eval "$instance_mode->{option_results}->{'warning_' . $label}") { + $status = 'warning'; + } + }; + if (defined($message)) { + $self->{output}->output_add(long_msg => 'filter status issue: ' . $message); + } + + return $status; +} + +sub custom_status_output { + my ($self, %options) = @_; + my $msg = "[Health: " . $self->{result_values}->{health} . " - Lifecycle: " . $self->{result_values}->{lifecycle} . "]"; + + return $msg; +} + +sub custom_status_calc { + my ($self, %options) = @_; + + $self->{result_values}->{health} = $options{new_datas}->{$self->{instance} . '_health'}; + $self->{result_values}->{lifecycle} = $options{new_datas}->{$self->{instance} . '_lifecycle'}; + $self->{result_values}->{asg} = $options{new_datas}->{$self->{instance} . '_asg'}; + $self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_display'}; + return 0; +} + +sub custom_asg_output { + my ($self, %options) = @_; + + my $msg = sprintf('Instance number: %s (config: min=%d max=%d)', $self->{result_values}->{count}, $self->{result_values}->{min_size}, $self->{result_values}->{max_size}); + return $msg; +} + +sub custom_asg_calc { + my ($self, %options) = @_; + + $self->{result_values}->{count} = $options{new_datas}->{$self->{instance} . '_count'}; + $self->{result_values}->{min_size} = $options{new_datas}->{$self->{instance} . '_min_size'}; + $self->{result_values}->{max_size} = $options{new_datas}->{$self->{instance} . '_max_size'}; + $self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_display'}; + + return 0; +} + +sub prefix_awsasg_output { + my ($self, %options) = @_; + + return "AutoScalingGroup '" . $options{instance_value}->{display} . "' "; +} + +sub prefix_awsinstance_output { + my ($self, %options) = @_; + + return "Instance '" . $options{instance_value}->{display} . "' "; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'aws_asg', type => 1, cb_prefix_output => 'prefix_awsasg_output', message_multiple => 'All Auto Scaling Groups are ok' }, + { name => 'aws_instances', type => 1, cb_prefix_output => 'prefix_awsinstance_output', message_multiple => 'All instances are ok' }, + ]; + + $self->{maps_counters}->{aws_asg} = [ + { label => 'count', set => { + key_values => [ { name => 'display' }, { name => 'count' }, { name => 'min_size' }, { name => 'max_size' } ], + threshold_use => 'count', + closure_custom_calc => $self->can('custom_asg_calc'), + closure_custom_output => $self->can('custom_asg_output'), + perfdatas => [ + { label => 'count', value => 'count', template => '%d', + min => 0, label_extra_instance => 1, instance_use => 'display' }, + ], + } + }, + ]; + $self->{maps_counters}->{aws_instances} = [ + { label => 'instances', set => { + key_values => [ { name => 'health' }, { name => 'lifecycle' }, { name => 'asg' }, { name => 'display' } ], + closure_custom_calc => $self->can('custom_status_calc'), + closure_custom_output => $self->can('custom_status_output'), + closure_custom_perfdata => sub { return 0; }, + closure_custom_threshold_check => $self->can('custom_status_threshold'), + } + }, + ]; + +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $self->{version} = '1.0'; + $options{options}->add_options(arguments => + { + "region:s" => { name => 'region' }, + "filter-asg:s" => { name => 'filter_asg', default => '' }, + "warning-instances:s" => { name => 'warning_instances', default => '' }, + "critical-instances:s" => { name => 'critical_instances', default => '%{health} =~ /Healthy/ && %{lifecycle} !~ /InService/' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + if (!defined($self->{option_results}->{region}) || $self->{option_results}->{region} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --region option."); + $self->{output}->option_exit(); + } + + $instance_mode = $self; + $self->change_macros(); +} + +sub change_macros { + my ($self, %options) = @_; + + foreach (('warning_instances', 'critical_instances')) { + if (defined($self->{option_results}->{$_})) { + $self->{option_results}->{$_} =~ s/%\{(.*?)\}/\$self->{result_values}->{$1}/g; + } + } +} + +sub manage_selection { + my ($self, %options) = @_; + + $self->{aws_autoscaling_groups} = {}; + + my $result = $options{custom}->asg_get_resources(region => $self->{option_results}->{region}); + + foreach my $asg (@{$result}) { + my $instance_count = 0; + + if (defined($self->{option_results}->{filter_asg}) && $self->{option_results}->{filter_asg} ne '' && + $asg->{AutoScalingGroupName} !~ /$self->{option_results}->{filter_asg}/) { + $self->{output}->output_add(long_msg => "skipping asg '" . $asg->{AutoScalingGroupName} . "': no matching filter.", debug => 1); + next; + } + + foreach my $instance (@{$asg->{Instances}}) { + $self->{aws_instances}->{$instance->{InstanceId}} = { display => $instance->{InstanceId}, + asg => $asg->{AutoScalingGroupName}, + health => $instance->{HealthStatus}, + lifecycle => $instance->{LifecycleState} }; + + $instance_count++; + } + $self->{aws_asg}->{$asg->{AutoScalingGroupName}} = { display => $asg->{AutoScalingGroupName}, + min_size => $asg->{MinSize}, + max_size => $asg->{MaxSize}, + count => $instance_count }; + } + + if (scalar(keys %{$self->{aws_instances}}) <= 0 && $self->{aws_asg} <= 0) { + $self->{output}->add_option_msg(short_msg => "Didn't check anything, are your filters correct ?"); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check EC2 Auto Scaling Groups and related instances status (number of instances within, state of each instances) + +Example: +perl centreon_plugins.pl --plugin=cloud::aws::ec2::plugin --custommode=paws --mode=asg-status --region='eu-west-1' +--critical-instances='%{health} =~ /Healthy/ && %{lifecycle} !~ /InService/' --warning-count 10 --verbose + +See 'https://docs.aws.amazon.com/autoscaling/ec2/APIReference/API_DescribeAutoScalingGroups.html' for more informations. + +=over 8 + +=item B<--filter-counters> + +Only display some counters (regexp can be used). +Possible values: asg / instances + +=item B<--filter-asg> + +Filter by autoscaling group name (can be a regexp). + +=item B<--warning-instances> + +Set warning threshold for status (Default: ''). +Can used special variables like: %{health}, %{lifecycle} + +=item B<--critical-instances> + +Set critical threshold for instances states (Default: '%{health} =~ /Healthy/ && %{lifecycle} !~ /InService/'). +Can used special variables like: %{health}, %{lifecycle} + +=item B<--warning-count> + +Threshold warning about number of instances in the autoscaling group + +=item B<--critical-count> + +Threshold critical about number of instances in the autoscaling group + +=back + +=cut diff --git a/cloud/aws/ec2/mode/cpu.pm b/cloud/aws/ec2/mode/cpu.pm new file mode 100644 index 000000000..9f8d4f2ca --- /dev/null +++ b/cloud/aws/ec2/mode/cpu.pm @@ -0,0 +1,217 @@ +# +# Copyright 2018 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::ec2::mode::cpu; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +my %map_type = ( + "instance" => "InstanceId", + "asg" => "AutoScalingGroupName", +); + +sub prefix_metric_output { + my ($self, %options) = @_; + + return ucfirst($options{instance_value}->{type}) . " '" . $options{instance_value}->{display} . "' " . $options{instance_value}->{stat} . " "; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'metric', type => 1, cb_prefix_output => 'prefix_metric_output', message_multiple => "All CPU metrics are ok", skipped_code => { -10 => 1 } }, + ]; + + foreach my $statistic ('minimum', 'maximum', 'average', 'sum') { + foreach my $metric ('CPUCreditBalance', 'CPUCreditUsage', 'CPUSurplusCreditBalance', 'CPUSurplusCreditsCharged') { + my $entry = { label => lc($metric) . '-' . lc($statistic), set => { + key_values => [ { name => $metric . '_' . $statistic }, { name => 'display' }, { name => 'type' }, { name => 'stat' } ], + output_template => $metric . ': %.2f', + perfdatas => [ + { label => lc($metric) . '_' . lc($statistic), value => $metric . '_' . $statistic . '_absolute', + template => '%.2f', label_extra_instance => 1, instance_use => 'display_absolute' }, + ], + } + }; + push @{$self->{maps_counters}->{metric}}, $entry; + } + foreach my $metric ('CPUUtilization') { + my $entry = { label => lc($metric) . '-' . lc($statistic), set => { + key_values => [ { name => $metric . '_' . $statistic }, { name => 'display' }, { name => 'type' }, { name => 'stat' } ], + output_template => $metric . ': %.2f %%', + perfdatas => [ + { label => lc($metric) . '_' . lc($statistic), value => $metric . '_' . $statistic . '_absolute', + template => '%.2f', unit => '%', label_extra_instance => 1, instance_use => 'display_absolute' }, + ], + } + }; + push @{$self->{maps_counters}->{metric}}, $entry; + } + } +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $self->{version} = '1.0'; + $options{options}->add_options(arguments => + { + "type:s" => { name => 'type' }, + "name:s@" => { name => 'name' }, + "filter-metric:s" => { name => 'filter_metric' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + if (!defined($self->{option_results}->{type}) || $self->{option_results}->{type} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --type option."); + $self->{output}->option_exit(); + } + + if ($self->{option_results}->{type} ne 'asg' && $self->{option_results}->{type} ne 'instance') { + $self->{output}->add_option_msg(short_msg => "Instance type '" . $self->{option_results}->{type} . "' is not handled for this mode"); + $self->{output}->option_exit(); + } + + if (!defined($self->{option_results}->{name}) || $self->{option_results}->{name} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --name option."); + $self->{output}->option_exit(); + } + + foreach my $instance (@{$self->{option_results}->{name}}) { + if ($instance ne '') { + push @{$self->{aws_instance}}, $instance; + } + } + + $self->{aws_timeframe} = defined($self->{option_results}->{timeframe}) ? $self->{option_results}->{timeframe} : 600; + $self->{aws_period} = defined($self->{option_results}->{period}) ? $self->{option_results}->{period} : 60; + + $self->{aws_statistics} = ['Average']; + if (defined($self->{option_results}->{statistic})) { + $self->{aws_statistics} = []; + foreach my $stat (@{$self->{option_results}->{statistic}}) { + if ($stat ne '') { + push @{$self->{aws_statistics}}, ucfirst(lc($stat)); + } + } + } + + foreach my $metric ('CPUCreditBalance', 'CPUCreditUsage', 'CPUSurplusCreditBalance', + 'CPUSurplusCreditsCharged', 'CPUUtilization') { + next if (defined($self->{option_results}->{filter_metric}) && $self->{option_results}->{filter_metric} ne '' + && $metric !~ /$self->{option_results}->{filter_metric}/); + + push @{$self->{aws_metrics}}, $metric; + } +} + +sub manage_selection { + my ($self, %options) = @_; + + my %metric_results; + foreach my $instance (@{$self->{aws_instance}}) { + $metric_results{$instance} = $options{custom}->cloudwatch_get_metrics( + region => $self->{option_results}->{region}, + namespace => 'AWS/EC2', + dimensions => [ { Name => $map_type{$self->{option_results}->{type}}, Value => $instance } ], + 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($metric_results{$instance}->{$metric}->{lc($statistic)}) && !defined($self->{option_results}->{zeroed})); + + $self->{metric}->{$instance . "_" . lc($statistic)}->{display} = $instance; + $self->{metric}->{$instance . "_" . lc($statistic)}->{type} = $self->{option_results}->{type}; + $self->{metric}->{$instance . "_" . lc($statistic)}->{stat} = lc($statistic); + $self->{metric}->{$instance . "_" . lc($statistic)}->{$metric . "_" . lc($statistic)} = defined($metric_results{$instance}->{$metric}->{lc($statistic)}) ? $metric_results{$instance}->{$metric}->{lc($statistic)} : 0; + } + } + } + + if (scalar(keys %{$self->{metric}}) <= 0) { + $self->{output}->add_option_msg(short_msg => 'No metrics. Check your options or use --zeroed option to set 0 on undefined values'); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check EC2 instances CPU metrics. + +Example: +perl centreon_plugins.pl --plugin=cloud::aws::ec2::plugin --custommode=paws --mode=cpu --region='eu-west-1' +--type='asg' --name='centreon-middleware' --filter-metric='Credit' --statistic='average' +--critical-cpucreditusage-average='10' --verbose + +See 'https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/ec2-metricscollected.html' for more informations. + +Default statistic: 'average' / All satistics are valid. + +=over 8 + +=item B<--type> + +Set the instance type (Required) (Can be: 'asg', 'instance'). + +=item B<--name> + +Set the instance name (Required) (Can be multiple). + +=item B<--filter-metric> + +Filter metrics (Can be: 'CPUCreditBalance', 'CPUCreditUsage', +'CPUSurplusCreditBalance', 'CPUSurplusCreditsCharged', 'CPUUtilization') +(Can be a regexp). + +=item B<--warning-$metric$-$statistic$> + +Thresholds warning ($metric$ can be: 'cpucreditusage', 'cpucreditbalance', +'cpusurpluscreditbalance', 'cpusurpluscreditscharged', 'cpuutilization', +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=item B<--critical-$metric$-$statistic$> + +Thresholds critical ($metric$ can be: 'cpucreditusage', 'cpucreditbalance', +'cpusurpluscreditbalance', 'cpusurpluscreditscharged', 'cpuutilization', +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=back + +=cut diff --git a/cloud/aws/ec2/mode/diskio.pm b/cloud/aws/ec2/mode/diskio.pm new file mode 100644 index 000000000..216e53c0e --- /dev/null +++ b/cloud/aws/ec2/mode/diskio.pm @@ -0,0 +1,303 @@ +# +# Copyright 2018 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::ec2::mode::diskio; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +my %map_type = ( + "instance" => "InstanceId", + "asg" => "AutoScalingGroupName", +); + +my $instance_mode; + +sub prefix_metric_output { + my ($self, %options) = @_; + + return ucfirst($options{instance_value}->{type}) . " '" . $options{instance_value}->{display} . "' " . $options{instance_value}->{stat} . " "; +} + +sub custom_metric_calc { + my ($self, %options) = @_; + + $self->{result_values}->{timeframe} = $options{new_datas}->{$self->{instance} . '_timeframe'}; + $self->{result_values}->{value} = $options{new_datas}->{$self->{instance} . '_' . $options{extra_options}->{metric} . '_' . $options{extra_options}->{stat}}; + $self->{result_values}->{value_per_sec} = $self->{result_values}->{value} / $self->{result_values}->{timeframe}; + $self->{result_values}->{stat} = $options{extra_options}->{stat}; + $self->{result_values}->{metric} = $options{extra_options}->{metric}; + $self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_display'}; + return 0; +} + +sub custom_metric_threshold { + my ($self, %options) = @_; + + my $exit = $self->{perfdata}->threshold_check(value => defined($instance_mode->{option_results}->{per_sec}) ? $self->{result_values}->{value_per_sec} : $self->{result_values}->{value}, + threshold => [ { label => 'critical-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat}), exit_litteral => 'critical' }, + { label => 'warning-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat}), exit_litteral => 'warning' } ]); + return $exit; +} + +sub custom_usage_perfdata { + my ($self, %options) = @_; + + my $extra_label = ''; + $extra_label = '_' . lc($self->{result_values}->{display}) if (!defined($options{extra_instance}) || $options{extra_instance} != 0); + + $self->{output}->perfdata_add(label => lc($self->{result_values}->{metric}) . "_" . lc($self->{result_values}->{stat}) . $extra_label, + unit => defined($instance_mode->{option_results}->{per_sec}) ? 'B/s' : 'B', + value => sprintf("%.2f", defined($instance_mode->{option_results}->{per_sec}) ? $self->{result_values}->{value_per_sec} : $self->{result_values}->{value}), + warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat})), + critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat})), + ); +} + +sub custom_usage_output { + my ($self, %options) = @_; + my $msg = ""; + + if (defined($instance_mode->{option_results}->{per_sec})) { + my ($value, $unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{value_per_sec}); + $msg = $self->{result_values}->{metric} . ": " . $value . $unit . "/s"; + } else { + my ($value, $unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{value}); + $msg = $self->{result_values}->{metric} . ": " . $value . $unit; + } + return $msg; +} + +sub custom_ops_perfdata { + my ($self, %options) = @_; + + my $extra_label = ''; + $extra_label = '_' . lc($self->{result_values}->{display}) if (!defined($options{extra_instance}) || $options{extra_instance} != 0); + + $self->{output}->perfdata_add(label => lc($self->{result_values}->{metric}) . "_" . lc($self->{result_values}->{stat}) . $extra_label, + unit => defined($instance_mode->{option_results}->{per_sec}) ? 'ops/s' : 'ops', + value => sprintf("%.2f", defined($instance_mode->{option_results}->{per_sec}) ? $self->{result_values}->{value_per_sec} : $self->{result_values}->{value}), + warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat})), + critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat})), + ); +} + +sub custom_ops_output { + my ($self, %options) = @_; + + my $msg =""; + + if (defined($instance_mode->{option_results}->{per_sec})) { + $msg = sprintf("%s: %.2f ops/s", $self->{result_values}->{metric}, $self->{result_values}->{value_per_sec}); + } else { + $msg = sprintf("%s: %.2f ops", $self->{result_values}->{metric}, $self->{result_values}->{value}); + } + + return $msg; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'metric', type => 1, cb_prefix_output => 'prefix_metric_output', message_multiple => "All disk metrics are ok", skipped_code => { -10 => 1 } }, + ]; + + foreach my $statistic ('minimum', 'maximum', 'average', 'sum') { + foreach my $metric ('DiskReadBytes', 'DiskWriteBytes') { + my $entry = { label => lc($metric) . '-' . lc($statistic), set => { + key_values => [ { name => $metric . '_' . $statistic }, { name => 'display' }, { name => 'stat' }, { name => 'timeframe' } ], + closure_custom_calc => $self->can('custom_metric_calc'), + closure_custom_calc_extra_options => { metric => $metric, stat => $statistic }, + closure_custom_output => $self->can('custom_usage_output'), + closure_custom_perfdata => $self->can('custom_usage_perfdata'), + closure_custom_threshold_check => $self->can('custom_metric_threshold'), + } + }; + push @{$self->{maps_counters}->{metric}}, $entry; + } + foreach my $metric ('DiskReadOps', 'DiskWriteOps') { + my $entry = { label => lc($metric) . '-' . lc($statistic), set => { + key_values => [ { name => $metric . '_' . $statistic }, { name => 'display' }, { name => 'stat' }, { name => 'timeframe' } ], + closure_custom_calc => $self->can('custom_metric_calc'), + closure_custom_calc_extra_options => { metric => $metric, stat => $statistic }, + closure_custom_output => $self->can('custom_ops_output'), + closure_custom_perfdata => $self->can('custom_ops_perfdata'), + closure_custom_threshold_check => $self->can('custom_metric_threshold'), + } + }; + push @{$self->{maps_counters}->{metric}}, $entry; + } + } +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $self->{version} = '1.0'; + $options{options}->add_options(arguments => + { + "type:s" => { name => 'type' }, + "name:s@" => { name => 'name' }, + "filter-metric:s" => { name => 'filter_metric' }, + "per-sec" => { name => 'per_sec' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + if (!defined($self->{option_results}->{type}) || $self->{option_results}->{type} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --type option."); + $self->{output}->option_exit(); + } + + if ($self->{option_results}->{type} ne 'asg' && $self->{option_results}->{type} ne 'instance') { + $self->{output}->add_option_msg(short_msg => "Instance type '" . $self->{option_results}->{type} . "' is not handled for this mode"); + $self->{output}->option_exit(); + } + + if (!defined($self->{option_results}->{name}) || $self->{option_results}->{name} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --name option."); + $self->{output}->option_exit(); + } + + foreach my $instance (@{$self->{option_results}->{name}}) { + if ($instance ne '') { + push @{$self->{aws_instance}}, $instance; + } + } + + $self->{aws_timeframe} = defined($self->{option_results}->{timeframe}) ? $self->{option_results}->{timeframe} : 600; + $self->{aws_period} = defined($self->{option_results}->{period}) ? $self->{option_results}->{period} : 60; + + $self->{aws_statistics} = ['Average']; + if (defined($self->{option_results}->{statistic})) { + $self->{aws_statistics} = []; + foreach my $stat (@{$self->{option_results}->{statistic}}) { + if ($stat ne '') { + push @{$self->{aws_statistics}}, ucfirst(lc($stat)); + } + } + } + + foreach my $metric ('DiskReadBytes', 'DiskWriteBytes', 'DiskReadOps', 'DiskWriteOps') { + next if (defined($self->{option_results}->{filter_metric}) && $self->{option_results}->{filter_metric} ne '' + && $metric !~ /$self->{option_results}->{filter_metric}/); + + push @{$self->{aws_metrics}}, $metric; + } + + $instance_mode = $self; +} + +sub manage_selection { + my ($self, %options) = @_; + + my %metric_results; + foreach my $instance (@{$self->{aws_instance}}) { + $metric_results{$instance} = $options{custom}->cloudwatch_get_metrics( + region => $self->{option_results}->{region}, + namespace => 'AWS/EC2', + dimensions => [ { Name => $map_type{$self->{option_results}->{type}}, Value => $instance } ], + 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($metric_results{$instance}->{$metric}->{lc($statistic)}) && !defined($self->{option_results}->{zeroed})); + + $self->{metric}->{$instance . "_" . lc($statistic)}->{display} = $instance; + $self->{metric}->{$instance . "_" . lc($statistic)}->{type} = $self->{option_results}->{type}; + $self->{metric}->{$instance . "_" . lc($statistic)}->{stat} = lc($statistic); + $self->{metric}->{$instance . "_" . lc($statistic)}->{timeframe} = $self->{aws_timeframe}; + $self->{metric}->{$instance . "_" . lc($statistic)}->{$metric . "_" . lc($statistic)} = defined($metric_results{$instance}->{$metric}->{lc($statistic)}) ? $metric_results{$instance}->{$metric}->{lc($statistic)} : 0; + } + } + } + + if (scalar(keys %{$self->{metric}}) <= 0) { + $self->{output}->add_option_msg(short_msg => 'No metrics. Check your options or use --zeroed option to set 0 on undefined values'); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check EC2 instances disk IO metrics. + +Example: +perl centreon_plugins.pl --plugin=cloud::aws::ec2::plugin --custommode=paws --mode=diskio --region='eu-west-1' +--type='asg' --name='centreon-middleware' --filter-metric='Read' --statistic='sum' --critical-diskreadops-sum='10' +--verbose + +See 'https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/ec2-metricscollected.html' for more informations. + +Default statistic: 'average' / All satistics are valid. + +=over 8 + +=item B<--type> + +Set the instance type (Required) (Can be: 'asg', 'instance'). + +=item B<--name> + +Set the instance name (Required) (Can be multiple). + +=item B<--filter-metric> + +Filter metrics (Can be: 'DiskReadBytes', 'DiskWriteBytes', +'DiskReadOps', 'DiskWriteOps') +(Can be a regexp). + +=item B<--warning-$metric$-$statistic$> + +Thresholds warning ($metric$ can be: 'diskreadbytes', 'diskwritebytes', +'diskreadops', 'diskwriteops', +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=item B<--critical-$metric$-$statistic$> + +Thresholds critical ($metric$ can be: 'diskreadbytes', 'diskwritebytes', +'diskreadops', 'diskwriteops', +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=item B<--per-sec> + +Change the data to be unit/sec. + +=back + +=cut diff --git a/cloud/aws/mode/ec2instancestatus.pm b/cloud/aws/ec2/mode/instancesstatus.pm similarity index 91% rename from cloud/aws/mode/ec2instancestatus.pm rename to cloud/aws/ec2/mode/instancesstatus.pm index 5e19ea1ec..9a97be66d 100644 --- a/cloud/aws/mode/ec2instancestatus.pm +++ b/cloud/aws/ec2/mode/instancesstatus.pm @@ -18,7 +18,7 @@ # limitations under the License. # -package cloud::aws::mode::ec2instancestatus; +package cloud::aws::ec2::mode::instancesstatus; use base qw(centreon::plugins::templates::counter); @@ -56,8 +56,7 @@ sub custom_status_threshold { sub custom_status_output { my ($self, %options) = @_; - my $msg = sprintf('state : %s', - $self->{result_values}->{health}, $self->{result_values}->{replication_health}); + my $msg = sprintf('state: %s, status: %s', $self->{result_values}->{state}, $self->{result_values}->{status}); return $msg; } @@ -65,6 +64,7 @@ sub custom_status_calc { my ($self, %options) = @_; $self->{result_values}->{state} = $options{new_datas}->{$self->{instance} . '_state'}; + $self->{result_values}->{status} = $options{new_datas}->{$self->{instance} . '_status'}; $self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_display'}; return 0; } @@ -130,9 +130,9 @@ sub set_counters { $self->{maps_counters}->{aws_instances} = [ { label => 'status', threshold => 0, set => { - key_values => [ { name => 'state' }, { name => 'display' } ], - closure_custom_calc => $self->can('custom_nas_status_calc'), - closure_custom_output => $self->can('custom_nas_status_output'), + key_values => [ { name => 'state' }, { name => 'status' }, { name => 'display' } ], + closure_custom_calc => $self->can('custom_status_calc'), + closure_custom_output => $self->can('custom_status_output'), closure_custom_perfdata => sub { return 0; }, closure_custom_threshold_check => $self->can('custom_status_threshold'), } @@ -210,6 +210,7 @@ sub manage_selection { $self->{aws_instances}->{$instance_id} = { display => $instance_id, state => $result->{$instance_id}->{state}, + status => $result->{$instance_id}->{status}, }; $self->{global}->{$result->{$instance_id}->{state}}++; } @@ -228,6 +229,12 @@ __END__ Check EC2 instances status. +Example: +perl centreon_plugins.pl --plugin=cloud::aws::ec2::plugin --custommode=paws --mode=instances-status --region='eu-west-1' +--filter-instanceid='.*' --filter-counters='^total-running$' --critical-total-running='10' --verbose + +See 'https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeInstanceStatus.html' for more informations. + =over 8 =item B<--filter-counters> diff --git a/cloud/aws/ec2/mode/instancestypes.pm b/cloud/aws/ec2/mode/instancestypes.pm new file mode 100644 index 000000000..e02d21d86 --- /dev/null +++ b/cloud/aws/ec2/mode/instancestypes.pm @@ -0,0 +1,223 @@ +# +# Copyright 2018 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::ec2::mode::instancestypes; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +my %spot_types = ( + 'general' => ['t2.nano', 't2.micro', 't2.small', 't2.medium', 't2.large', 't2.xlarge', 't2.2xlarge', 'm4.large', + 'm4.xlarge', 'm4.2xlarge', 'm4.4xlarge', 'm4.10xlarge', 'm4.16xlarge', 'm5.large', 'm5.xlarge', + 'm5.2xlarge', 'm5.4xlarge', 'm5.12xlarge', 'm5.24xlarge'], + 'compute' => ['c4.large', 'c4.xlarge', 'c4.2xlarge', 'c4.4xlarge', 'c4.8xlarge', 'c5.large', + 'c5.xlarge', 'c5.2xlarge', 'c5.4xlarge', 'c5.9xlarge', 'c5.18xlarge'], + 'memory' => ['r4.large', 'r4.xlarge', 'r4.2xlarge', 'r4.4xlarge', 'r4.8xlarge', 'r4.16xlarge', + 'x1.16xlarge', 'x1.32xlarge', 'x1e.xlarge', 'x1e.2xlarge', 'x1e.4xlarge', 'x1e.8xlarge', 'x1e.16xlarge', + 'x1e.32xlarge'], + 'storage' => ['r4.large', 'r4.xlarge', 'r4.2xlarge', 'r4.4xlarge', 'r4.8xlarge', 'r4.16xlarge', + 'x1.16xlarge', 'x1.32xlarge', 'x1e.xlarge', 'x1e.2xlarge', 'x1e.4xlarge', 'x1e.8xlarge', 'x1e.16xlarge', + 'x1e.32xlarge'], + 'accelerated' => ['f1.2xlarge', 'f1.16xlarge', 'g3.4xlarge', 'g3.8xlarge', 'g3.16xlarge', 'p2.xlarge', + 'p2.8xlarge', 'p2.16xlarge', 'p3.2xlarge', 'p3.8xlarge', 'p3.16xlarge'], +); + +sub prefix_general_output { + my ($self, %options) = @_; + + return "Spot family 'General purpose' instance types count "; +} + +sub prefix_compute_output { + my ($self, %options) = @_; + + return "Spot family 'Compute optimized' instance types count "; +} + +sub prefix_memory_output { + my ($self, %options) = @_; + + return "Spot family 'Memory optimized' instance types count "; +} + +sub prefix_storage_output { + my ($self, %options) = @_; + + return "Spot family 'Storage optimized' instance types count "; +} + +sub prefix_accelerated_output { + my ($self, %options) = @_; + + return "Spot family 'Accelerated computing' instance types count "; +} + +sub set_counters { + my ($self, %options) = @_; + + foreach my $family (keys %spot_types) { + my $counter = { name => $family, type => 0, cb_prefix_output => 'prefix_' . $family . '_output', skipped_code => { -10 => 1 } }; + + push @{$self->{maps_counters_type}}, $counter; + + $self->{maps_counters}->{$family} = []; + + foreach my $type (@{$spot_types{$family}}) { + my $entry = { label => $type, set => { + key_values => [ { name => $type } ], + output_template => $type . ": %s", + perfdatas => [ + { label => $type, value => $type . '_absolute', template => '%d', min => 0 }, + ], + } + }; + push @{$self->{maps_counters}->{$family}}, $entry; + } + } +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $self->{version} = '1.0'; + $options{options}->add_options(arguments => + { + "region:s" => { name => 'region' }, + "filter-family:s" => { name => 'filter_family' }, + "filter-type:s" => { name => 'filter_type' }, + "running" => { name => 'running' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + if (!defined($self->{option_results}->{region}) || $self->{option_results}->{region} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --region option."); + $self->{output}->option_exit(); + } +} + +sub manage_selection { + my ($self, %options) = @_; + + foreach my $family (keys %spot_types) { + if (defined($self->{option_results}->{filter_family}) && $self->{option_results}->{filter_family} ne '' && + $family !~ /$self->{option_results}->{filter_family}/) { + $self->{output}->output_add(long_msg => sprintf("skipping family '%s'", $family), debug => 1); + $self->{maps_counters}->{$family} = undef; + } else { + foreach my $type (@{$spot_types{$family}}) { + if (defined($self->{option_results}->{filter_type}) && $self->{option_results}->{filter_type} ne '' && + $type !~ /$self->{option_results}->{filter_type}/) { + next; + } + $self->{$family}->{$type} = 0; + } + } + } + + $self->{instances} = $options{custom}->ec2_list_resources(region => $self->{option_results}->{region}); + + foreach my $instance (@{$self->{instances}}) { + next if ($instance->{Type} !~ /instance/ || (defined($self->{option_results}->{running}) && $instance->{State} !~ /running/)); + if (defined($self->{option_results}->{filter_type}) && $self->{option_results}->{filter_type} ne '' && + $instance->{InstanceType} !~ /$self->{option_results}->{filter_type}/) { + $self->{output}->output_add(long_msg => sprintf("skipping type '%s'", $instance->{InstanceType}), debug => 1); + next; + } + + foreach my $family (keys %spot_types) { + $self->{$family}->{$instance->{InstanceType}}++ if (defined($self->{maps_counters}->{$family}) && map(/$instance->{InstanceType}/, @{$spot_types{$family}})); + } + } + + if (scalar(keys %{$self->{general}}) <= 0 && scalar(keys %{$self->{compute}}) <= 0 && scalar(keys %{$self->{memory}}) <= 0 && + scalar(keys %{$self->{storage}}) <= 0 && scalar(keys %{$self->{accelerated}}) <= 0) { + $self->{output}->add_option_msg(short_msg => "No result matched with applied filters."); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check EC2 instances types count. + +Example: +perl centreon_plugins.pl --plugin=cloud::aws::ec2::plugin --custommode=paws --mode=instances-types --region='eu-west-1' +--filter-family='general' --filter-type='medium' --critical-t2.medium='10' --verbose + +See 'https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-types.html' for more informations. + +=over 8 + +=item B<--filter-family> + +Filter by instance family (regexp) +(Can be: 'general', 'compute', 'memory', 'storage', 'accelerated') + +=item B<--filter-type> + +Filter by instance type (regexp) + +=item B<--warning-*> + +Threshold warning. +Can be: 't2.nano', 't2.micro', 't2.small', 't2.medium', 't2.large', 't2.xlarge', 't2.2xlarge', 'm4.large', +'m4.xlarge', 'm4.2xlarge', 'm4.4xlarge', 'm4.10xlarge', 'm4.16xlarge', 'm5.large', 'm5.xlarge', 'm5.2xlarge', +'m5.4xlarge', 'm5.12xlarge', 'm5.24xlarge', 'c4.large', 'c4.xlarge', 'c4.2xlarge', 'c4.4xlarge', 'c4.8xlarge', +'c5.large', 'c5.xlarge', 'c5.2xlarge', 'c5.4xlarge', 'c5.9xlarge', 'c5.18xlarge', 'r4.large', 'r4.xlarge', +'r4.2xlarge', 'r4.4xlarge', 'r4.8xlarge', 'r4.16xlarge', 'x1.16xlarge', 'x1.32xlarge', 'x1e.xlarge', 'x1e.2xlarge', +'x1e.4xlarge', 'x1e.8xlarge', 'x1e.16xlarge', 'x1e.32xlarge', 'r4.large', 'r4.xlarge', 'r4.2xlarge', 'r4.4xlarge', +'r4.8xlarge', 'r4.16xlarge', 'x1.16xlarge', 'x1.32xlarge', 'x1e.xlarge', 'x1e.2xlarge', 'x1e.4xlarge', 'x1e.8xlarge', +'x1e.16xlarge', 'x1e.32xlarge', 'f1.2xlarge', 'f1.16xlarge', 'g3.4xlarge', 'g3.8xlarge', 'g3.16xlarge', 'p2.xlarge', +'p2.8xlarge', 'p2.16xlarge', 'p3.2xlarge', 'p3.8xlarge', 'p3.16xlarge'. + +=item B<--critical-*> + +Threshold critical. +Can be: 't2.nano', 't2.micro', 't2.small', 't2.medium', 't2.large', 't2.xlarge', 't2.2xlarge', 'm4.large', +'m4.xlarge', 'm4.2xlarge', 'm4.4xlarge', 'm4.10xlarge', 'm4.16xlarge', 'm5.large', 'm5.xlarge', 'm5.2xlarge', +'m5.4xlarge', 'm5.12xlarge', 'm5.24xlarge', 'c4.large', 'c4.xlarge', 'c4.2xlarge', 'c4.4xlarge', 'c4.8xlarge', +'c5.large', 'c5.xlarge', 'c5.2xlarge', 'c5.4xlarge', 'c5.9xlarge', 'c5.18xlarge', 'r4.large', 'r4.xlarge', +'r4.2xlarge', 'r4.4xlarge', 'r4.8xlarge', 'r4.16xlarge', 'x1.16xlarge', 'x1.32xlarge', 'x1e.xlarge', 'x1e.2xlarge', +'x1e.4xlarge', 'x1e.8xlarge', 'x1e.16xlarge', 'x1e.32xlarge', 'r4.large', 'r4.xlarge', 'r4.2xlarge', 'r4.4xlarge', +'r4.8xlarge', 'r4.16xlarge', 'x1.16xlarge', 'x1.32xlarge', 'x1e.xlarge', 'x1e.2xlarge', 'x1e.4xlarge', 'x1e.8xlarge', +'x1e.16xlarge', 'x1e.32xlarge', 'f1.2xlarge', 'f1.16xlarge', 'g3.4xlarge', 'g3.8xlarge', 'g3.16xlarge', 'p2.xlarge', +'p2.8xlarge', 'p2.16xlarge', 'p3.2xlarge', 'p3.8xlarge', 'p3.16xlarge'. + +=item B<--running> + +Only check running instances. + +=back + +=cut diff --git a/cloud/aws/ec2/mode/listasg.pm b/cloud/aws/ec2/mode/listasg.pm new file mode 100644 index 000000000..13d1a16cf --- /dev/null +++ b/cloud/aws/ec2/mode/listasg.pm @@ -0,0 +1,98 @@ +# +# Copyright 2018 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::ec2::mode::listasg; + +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; + + $self->{version} = '1.0'; + $options{options}->add_options(arguments => + { + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::init(%options); +} + +sub manage_selection { + my ($self, %options) = @_; + + $self->{instances} = $options{custom}->ec2_list_resources(region => $self->{option_results}->{region}); +} + +sub run { + my ($self, %options) = @_; + + $self->manage_selection(%options); + foreach (@{$self->{instances}}) { + next if ($_->{Type} !~ m/asg/); + $self->{output}->output_add(long_msg => sprintf("[Name = %s]", $_->{Name})); + } + + $self->{output}->output_add(severity => 'OK', + short_msg => 'List autoscaling group:'); + $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 => ['name']); +} + +sub disco_show { + my ($self, %options) = @_; + + $self->manage_selection(%options); + foreach (@{$self->{instances}}) { + next if ($_->{Type} !~ m/asg/); + $self->{output}->add_disco_entry( + name => $_->{Name}, + ); + } +} + +1; + +__END__ + +=head1 MODE + +List EC2 autoscaling groups. + +=over 8 + +=back + +=cut + diff --git a/cloud/aws/ec2/mode/listinstances.pm b/cloud/aws/ec2/mode/listinstances.pm new file mode 100644 index 000000000..444429a9d --- /dev/null +++ b/cloud/aws/ec2/mode/listinstances.pm @@ -0,0 +1,102 @@ +# +# Copyright 2018 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::ec2::mode::listinstances; + +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; + + $self->{version} = '1.0'; + $options{options}->add_options(arguments => + { + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::init(%options); +} + +sub manage_selection { + my ($self, %options) = @_; + + $self->{instances} = $options{custom}->ec2_list_resources(region => $self->{option_results}->{region}); +} + +sub run { + my ($self, %options) = @_; + + $self->manage_selection(%options); + foreach (@{$self->{instances}}) { + next if ($_->{Type} !~ m/instance/); + $self->{output}->output_add(long_msg => sprintf("[Name = %s][AvailabilityZone = %s][InstanceType = %s][State = %s][Tags = %s]", + $_->{Name}, $_->{AvailabilityZone}, $_->{InstanceType}, $_->{State}, $_->{Tags})); + } + + $self->{output}->output_add(severity => 'OK', + short_msg => 'List instances:'); + $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 => ['name', 'availabilityzone', 'instancetype', 'state', 'tags']); +} + +sub disco_show { + my ($self, %options) = @_; + + $self->manage_selection(%options); + foreach (@{$self->{instances}}) { + next if ($_->{Type} !~ m/instance/); + $self->{output}->add_disco_entry( + name => $_->{Name}, + availabilityzone => $_->{AvailabilityZone}, + instancetype => $_->{InstanceType}, + state => $_->{State}, + tags => $_->{Tags}, + ); + } +} + +1; + +__END__ + +=head1 MODE + +List EC2 instances. + +=over 8 + +=back + +=cut diff --git a/cloud/aws/ec2/mode/network.pm b/cloud/aws/ec2/mode/network.pm new file mode 100644 index 000000000..2d9bae69a --- /dev/null +++ b/cloud/aws/ec2/mode/network.pm @@ -0,0 +1,303 @@ +# +# Copyright 2018 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::ec2::mode::network; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +my %map_type = ( + "instance" => "InstanceId", + "asg" => "AutoScalingGroupName", +); + +my $instance_mode; + +sub prefix_metric_output { + my ($self, %options) = @_; + + return ucfirst($options{instance_value}->{type}) . " '" . $options{instance_value}->{display} . "' " . $options{instance_value}->{stat} . " "; +} + +sub custom_metric_calc { + my ($self, %options) = @_; + + $self->{result_values}->{timeframe} = $options{new_datas}->{$self->{instance} . '_timeframe'}; + $self->{result_values}->{value} = $options{new_datas}->{$self->{instance} . '_' . $options{extra_options}->{metric} . '_' . $options{extra_options}->{stat}}; + $self->{result_values}->{value_per_sec} = $self->{result_values}->{value} / $self->{result_values}->{timeframe}; + $self->{result_values}->{stat} = $options{extra_options}->{stat}; + $self->{result_values}->{metric} = $options{extra_options}->{metric}; + $self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_display'}; + return 0; +} + +sub custom_metric_threshold { + my ($self, %options) = @_; + + my $exit = $self->{perfdata}->threshold_check(value => defined($instance_mode->{option_results}->{per_sec}) ? $self->{result_values}->{value_per_sec} : $self->{result_values}->{value}, + threshold => [ { label => 'critical-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat}), exit_litteral => 'critical' }, + { label => 'warning-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat}), exit_litteral => 'warning' } ]); + return $exit; +} + +sub custom_traffic_perfdata { + my ($self, %options) = @_; + + my $extra_label = ''; + $extra_label = '_' . lc($self->{result_values}->{display}) if (!defined($options{extra_instance}) || $options{extra_instance} != 0); + + $self->{output}->perfdata_add(label => lc($self->{result_values}->{metric}) . "_" . lc($self->{result_values}->{stat}) . $extra_label, + unit => defined($instance_mode->{option_results}->{per_sec}) ? 'B/s' : 'B', + value => sprintf("%.2f", defined($instance_mode->{option_results}->{per_sec}) ? $self->{result_values}->{value_per_sec} : $self->{result_values}->{value}), + warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat})), + critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat})), + ); +} + +sub custom_traffic_output { + my ($self, %options) = @_; + my $msg = ""; + + if (defined($instance_mode->{option_results}->{per_sec})) { + my ($value, $unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{value_per_sec}); + $msg = $self->{result_values}->{metric} . ": " . $value . $unit . "/s"; + } else { + my ($value, $unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{value}); + $msg = $self->{result_values}->{metric} . ": " . $value . $unit; + } + return $msg; +} + +sub custom_packets_perfdata { + my ($self, %options) = @_; + + my $extra_label = ''; + $extra_label = '_' . lc($self->{result_values}->{display}) if (!defined($options{extra_instance}) || $options{extra_instance} != 0); + + $self->{output}->perfdata_add(label => lc($self->{result_values}->{metric}) . "_" . lc($self->{result_values}->{stat}) . $extra_label, + unit => defined($instance_mode->{option_results}->{per_sec}) ? 'packets/s' : 'packets', + value => sprintf("%.2f", defined($instance_mode->{option_results}->{per_sec}) ? $self->{result_values}->{value_per_sec} : $self->{result_values}->{value}), + warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat})), + critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat})), + ); +} + +sub custom_packets_output { + my ($self, %options) = @_; + + my $msg =""; + + if (defined($instance_mode->{option_results}->{per_sec})) { + $msg = sprintf("%s: %.2f packets/s", $self->{result_values}->{metric}, $self->{result_values}->{value_per_sec}); + } else { + $msg = sprintf("%s: %.2f packets", $self->{result_values}->{metric}, $self->{result_values}->{value}); + } + + return $msg; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'metric', type => 1, cb_prefix_output => 'prefix_metric_output', message_multiple => "All network metrics are ok", skipped_code => { -10 => 1 } }, + ]; + + foreach my $statistic ('minimum', 'maximum', 'average', 'sum') { + foreach my $metric ('NetworkIn', 'NetworkOut') { + my $entry = { label => lc($metric) . '-' . lc($statistic), set => { + key_values => [ { name => $metric . '_' . $statistic }, { name => 'display' }, { name => 'stat' }, { name => 'timeframe' } ], + closure_custom_calc => $self->can('custom_metric_calc'), + closure_custom_calc_extra_options => { metric => $metric, stat => $statistic }, + closure_custom_output => $self->can('custom_traffic_output'), + closure_custom_perfdata => $self->can('custom_traffic_perfdata'), + closure_custom_threshold_check => $self->can('custom_metric_threshold'), + } + }; + push @{$self->{maps_counters}->{metric}}, $entry; + } + foreach my $metric ('NetworkPacketsIn', 'NetworkPacketsOut') { + my $entry = { label => lc($metric) . '-' . lc($statistic), set => { + key_values => [ { name => $metric . '_' . $statistic }, { name => 'display' }, { name => 'stat' }, { name => 'timeframe' } ], + closure_custom_calc => $self->can('custom_metric_calc'), + closure_custom_calc_extra_options => { metric => $metric, stat => $statistic }, + closure_custom_output => $self->can('custom_packets_output'), + closure_custom_perfdata => $self->can('custom_packets_perfdata'), + closure_custom_threshold_check => $self->can('custom_metric_threshold'), + } + }; + push @{$self->{maps_counters}->{metric}}, $entry; + } + } +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $self->{version} = '1.0'; + $options{options}->add_options(arguments => + { + "type:s" => { name => 'type' }, + "name:s@" => { name => 'name' }, + "filter-metric:s" => { name => 'filter_metric' }, + "per-sec" => { name => 'per_sec' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + if (!defined($self->{option_results}->{type}) || $self->{option_results}->{type} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --type option."); + $self->{output}->option_exit(); + } + + if ($self->{option_results}->{type} ne 'asg' && $self->{option_results}->{type} ne 'instance') { + $self->{output}->add_option_msg(short_msg => "Instance type '" . $self->{option_results}->{type} . "' is not handled for this mode"); + $self->{output}->option_exit(); + } + + if (!defined($self->{option_results}->{name}) || $self->{option_results}->{name} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --name option."); + $self->{output}->option_exit(); + } + + foreach my $instance (@{$self->{option_results}->{name}}) { + if ($instance ne '') { + push @{$self->{aws_instance}}, $instance; + } + } + + $self->{aws_timeframe} = defined($self->{option_results}->{timeframe}) ? $self->{option_results}->{timeframe} : 600; + $self->{aws_period} = defined($self->{option_results}->{period}) ? $self->{option_results}->{period} : 60; + + $self->{aws_statistics} = ['Average']; + if (defined($self->{option_results}->{statistic})) { + $self->{aws_statistics} = []; + foreach my $stat (@{$self->{option_results}->{statistic}}) { + if ($stat ne '') { + push @{$self->{aws_statistics}}, ucfirst(lc($stat)); + } + } + } + + foreach my $metric ('NetworkIn', 'NetworkOut', 'NetworkPacketsIn', 'NetworkPacketsOut') { + next if (defined($self->{option_results}->{filter_metric}) && $self->{option_results}->{filter_metric} ne '' + && $metric !~ /$self->{option_results}->{filter_metric}/); + + push @{$self->{aws_metrics}}, $metric; + } + + $instance_mode = $self; +} + +sub manage_selection { + my ($self, %options) = @_; + + my %metric_results; + foreach my $instance (@{$self->{aws_instance}}) { + $metric_results{$instance} = $options{custom}->cloudwatch_get_metrics( + region => $self->{option_results}->{region}, + namespace => 'AWS/EC2', + dimensions => [ { Name => $map_type{$self->{option_results}->{type}}, Value => $instance } ], + 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($metric_results{$instance}->{$metric}->{lc($statistic)}) && !defined($self->{option_results}->{zeroed})); + + $self->{metric}->{$instance . "_" . lc($statistic)}->{display} = $instance; + $self->{metric}->{$instance . "_" . lc($statistic)}->{type} = $self->{option_results}->{type}; + $self->{metric}->{$instance . "_" . lc($statistic)}->{stat} = lc($statistic); + $self->{metric}->{$instance . "_" . lc($statistic)}->{timeframe} = $self->{aws_timeframe}; + $self->{metric}->{$instance . "_" . lc($statistic)}->{$metric . "_" . lc($statistic)} = defined($metric_results{$instance}->{$metric}->{lc($statistic)}) ? $metric_results{$instance}->{$metric}->{lc($statistic)} : 0; + } + } + } + + if (scalar(keys %{$self->{metric}}) <= 0) { + $self->{output}->add_option_msg(short_msg => 'No metrics. Check your options or use --zeroed option to set 0 on undefined values'); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check EC2 instances network metrics. + +Example: +perl centreon_plugins.pl --plugin=cloud::aws::ec2::plugin --custommode=paws --mode=network --region='eu-west-1' +--type='asg' --name='centreon-middleware' --filter-metric='Packets' --statistic='sum' +--critical-networkpacketsout-sum='10' --verbose + +See 'https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/ec2-metricscollected.html' for more informations. + +Default statistic: 'average' / All satistics are valid. + +=over 8 + +=item B<--type> + +Set the instance type (Required) (Can be: 'asg', 'instance'). + +=item B<--name> + +Set the instance name (Required) (Can be multiple). + +=item B<--filter-metric> + +Filter metrics (Can be: 'NetworkIn', 'NetworkOut', +'NetworkPacketsIn', 'NetworkPacketsOut') +(Can be a regexp). + +=item B<--warning-$metric$-$statistic$> + +Thresholds warning ($metric$ can be: 'networkin', 'networkout', +'networkpacketsin', 'networkpacketsout', +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=item B<--critical-$metric$-$statistic$> + +Thresholds critical ($metric$ can be: 'networkin', 'networkout', +'networkpacketsin', 'networkpacketsout', +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=item B<--per-sec> + +Change the data to be unit/sec. + +=back + +=cut diff --git a/cloud/aws/ec2/mode/status.pm b/cloud/aws/ec2/mode/status.pm new file mode 100644 index 000000000..d7bec230d --- /dev/null +++ b/cloud/aws/ec2/mode/status.pm @@ -0,0 +1,240 @@ +# +# Copyright 2018 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::ec2::mode::status; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +my $instance_mode; + +my %map_type = ( + "instance" => "InstanceId", + "asg" => "AutoScalingGroupName", +); + +my %map_status = ( + 0 => 'passed', + 1 => 'failed', +); + +sub prefix_metric_output { + my ($self, %options) = @_; + + return ucfirst($options{instance_value}->{type}) . " '" . $options{instance_value}->{display} . "' "; +} + +sub custom_status_threshold { + my ($self, %options) = @_; + my $status = 'ok'; + my $message; + + eval { + local $SIG{__WARN__} = sub { $message = $_[0]; }; + local $SIG{__DIE__} = sub { $message = $_[0]; }; + + if (defined($instance_mode->{option_results}->{critical_status}) && $instance_mode->{option_results}->{critical_status} ne '' && + eval "$instance_mode->{option_results}->{critical_status}") { + $status = 'critical'; + } elsif (defined($instance_mode->{option_results}->{warning_status}) && $instance_mode->{option_results}->{warning_status} ne '' && + eval "$instance_mode->{option_results}->{warning_status}") { + $status = 'warning'; + } + }; + if (defined($message)) { + $self->{output}->output_add(long_msg => 'filter status issue: ' . $message); + } + + return $status; +} + +sub custom_status_output { + my ($self, %options) = @_; + + my $msg = $self->{result_values}->{metric} . ": " . $self->{result_values}->{status}; + return $msg; +} + +sub custom_status_calc { + my ($self, %options) = @_; + + $self->{result_values}->{status} = $map_status{$options{new_datas}->{$self->{instance} . '_' . $options{extra_options}->{metric}}}; + $self->{result_values}->{metric} = $options{extra_options}->{metric}; + return 0; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'metric', type => 1, cb_prefix_output => 'prefix_metric_output', message_multiple => "All status metrics are ok", skipped_code => { -10 => 1 } }, + ]; + + foreach my $metric ('StatusCheckFailed_Instance', 'StatusCheckFailed_System') { + my $entry = { label => lc($metric), threshold => 0, set => { + key_values => [ { name => $metric }, { name => 'display' } ], + closure_custom_calc => $self->can('custom_status_calc'), + closure_custom_calc_extra_options => { metric => $metric }, + closure_custom_output => $self->can('custom_status_output'), + closure_custom_perfdata => sub { return 0; }, + closure_custom_threshold_check => $self->can('custom_status_threshold'), + } + }; + push @{$self->{maps_counters}->{metric}}, $entry; + } +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $self->{version} = '1.0'; + $options{options}->add_options(arguments => + { + "type:s" => { name => 'type' }, + "name:s@" => { name => 'name' }, + "warning-status:s" => { name => 'warning_status', default => '' }, + "critical-status:s" => { name => 'critical_status', default => '%{status} =~ /failed/i' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + if (!defined($self->{option_results}->{type}) || $self->{option_results}->{type} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --type option."); + $self->{output}->option_exit(); + } + + if ($self->{option_results}->{type} ne 'asg' && $self->{option_results}->{type} ne 'instance') { + $self->{output}->add_option_msg(short_msg => "Instance type '" . $self->{option_results}->{type} . "' is not handled for this mode"); + $self->{output}->option_exit(); + } + + if (!defined($self->{option_results}->{name}) || $self->{option_results}->{name} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --name option."); + $self->{output}->option_exit(); + } + + foreach my $instance (@{$self->{option_results}->{name}}) { + if ($instance ne '') { + push @{$self->{aws_instance}}, $instance; + } + } + + $self->{aws_timeframe} = defined($self->{option_results}->{timeframe}) ? $self->{option_results}->{timeframe} : 90; + $self->{aws_period} = defined($self->{option_results}->{period}) ? $self->{option_results}->{period} : 60; + $self->{aws_statistics} = ['Average']; + + foreach my $metric ('StatusCheckFailed_Instance', 'StatusCheckFailed_System') { + push @{$self->{aws_metrics}}, $metric; + } + + $instance_mode = $self; + $self->change_macros(); +} + +sub change_macros { + my ($self, %options) = @_; + + foreach (('warning_status', 'critical_status')) { + if (defined($self->{option_results}->{$_})) { + $self->{option_results}->{$_} =~ s/%\{(.*?)\}/\$self->{result_values}->{$1}/g; + } + } +} + +sub manage_selection { + my ($self, %options) = @_; + + my %metric_results; + foreach my $instance (@{$self->{aws_instance}}) { + $metric_results{$instance} = $options{custom}->cloudwatch_get_metrics( + region => $self->{option_results}->{region}, + namespace => 'AWS/EC2', + dimensions => [ { Name => $map_type{$self->{option_results}->{type}}, Value => $instance } ], + metrics => $self->{aws_metrics}, + statistics => $self->{aws_statistics}, + timeframe => $self->{aws_timeframe}, + period => $self->{aws_period}, + ); + + foreach my $metric (keys $metric_results{$instance}) { + next if (!defined($metric_results{$instance}->{$metric}->{average})); + + $self->{metric}->{$instance}->{display} = $instance; + $self->{metric}->{$instance}->{type} = $self->{option_results}->{type}; + $self->{metric}->{$instance}->{$metric} = $metric_results{$instance}->{$metric}->{average}; + } + } + + if (scalar(keys %{$self->{metric}}) <= 0) { + $self->{output}->add_option_msg(short_msg => 'No metrics detected.'); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check EC2 instances status metrics. + +Example: +perl centreon_plugins.pl --plugin=cloud::aws::ec2::plugin --custommode=paws --mode=status --region='eu-west-1' +--type='asg' --name='centreon-middleware' --verbose + +See 'https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/ec2-metricscollected.html' for more informations. + +Default statistic: 'average' / Only valid statistic: 'average'. + +=over 8 + +=item B<--type> + +Set the instance type (Required) (Can be: 'asg', 'instance'). + +=item B<--name> + +Set the instance name (Required) (Can be multiple). + +=item B<--warning-status> + +Set warning threshold for status. +Can used special variables like: %{status}. +'status' can be: 'passed', 'failed'. + +=item B<--critical-status> + +Set critical threshold for status (Default: '%{status} =~ /failed/i'). +Can used special variables like: %{status}. +'status' can be: 'passed', 'failed'. + +=back + +=cut diff --git a/cloud/aws/ec2/plugin.pm b/cloud/aws/ec2/plugin.pm new file mode 100644 index 000000000..9d68c8e10 --- /dev/null +++ b/cloud/aws/ec2/plugin.pm @@ -0,0 +1,58 @@ +# +# Copyright 2018 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::ec2::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} } = ( + 'asg-status' => 'cloud::aws::ec2::mode::asgstatus', + 'cpu' => 'cloud::aws::ec2::mode::cpu', + 'diskio' => 'cloud::aws::ec2::mode::diskio', + 'instances-status' => 'cloud::aws::ec2::mode::instancesstatus', + 'instances-types' => 'cloud::aws::ec2::mode::instancestypes', + 'list-asg' => 'cloud::aws::ec2::mode::listasg', + 'list-instances' => 'cloud::aws::ec2::mode::listinstances', + 'network' => 'cloud::aws::ec2::mode::network', + 'status' => 'cloud::aws::ec2::mode::status', + ); + + $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 Elastic Compute Cloud (Amazon EC2). + +=cut diff --git a/cloud/aws/elasticache/mode/commandsmemcached.pm b/cloud/aws/elasticache/mode/commandsmemcached.pm new file mode 100644 index 000000000..e3bc1429f --- /dev/null +++ b/cloud/aws/elasticache/mode/commandsmemcached.pm @@ -0,0 +1,254 @@ +# +# Copyright 2018 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::elasticache::mode::commandsmemcached; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +my $instance_mode; + +sub prefix_metric_output { + my ($self, %options) = @_; + + my $node_id = ""; + if (defined($options{instance_value}->{node_id}) && $options{instance_value}->{node_id} ne '') { + $node_id = "[Node: $options{instance_value}->{node_id}] "; + } + + return "Cluster '" . $options{instance_value}->{display} . "' " . $node_id . $options{instance_value}->{stat} . " commands "; +} + +sub custom_metric_calc { + my ($self, %options) = @_; + + $self->{result_values}->{timeframe} = $options{new_datas}->{$self->{instance} . '_timeframe'}; + $self->{result_values}->{value} = $options{new_datas}->{$self->{instance} . '_' . $options{extra_options}->{metric} . '_' . $options{extra_options}->{stat}}; + $self->{result_values}->{value_per_sec} = $self->{result_values}->{value} / $self->{result_values}->{timeframe}; + $self->{result_values}->{stat} = $options{extra_options}->{stat}; + $self->{result_values}->{metric} = $options{extra_options}->{metric}; + $self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_display'}; + return 0; +} + +sub custom_metric_threshold { + my ($self, %options) = @_; + + my $exit = $self->{perfdata}->threshold_check(value => defined($instance_mode->{option_results}->{per_sec}) ? $self->{result_values}->{value_per_sec} : $self->{result_values}->{value}, + threshold => [ { label => 'critical-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat}), exit_litteral => 'critical' }, + { label => 'warning-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat}), exit_litteral => 'warning' } ]); + return $exit; +} + +sub custom_metric_perfdata { + my ($self, %options) = @_; + + my $extra_label = ''; + $extra_label = '_' . lc($self->{result_values}->{display}) if (!defined($options{extra_instance}) || $options{extra_instance} != 0); + + $self->{output}->perfdata_add(label => lc($self->{result_values}->{metric}) . "_" . lc($self->{result_values}->{stat}) . $extra_label, + unit => defined($instance_mode->{option_results}->{per_sec}) ? 'cmd/s' : 'cmd', + value => sprintf("%.2f", defined($instance_mode->{option_results}->{per_sec}) ? $self->{result_values}->{value_per_sec} : $self->{result_values}->{value}), + warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat})), + critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat})), + ); +} + +sub custom_metric_output { + my ($self, %options) = @_; + my $msg = ""; + + if (defined($instance_mode->{option_results}->{per_sec})) { + $msg = sprintf("%s: %.2f cmd/s", $self->{result_values}->{metric}, $self->{result_values}->{value_per_sec}); + } else { + $msg = sprintf("%s: %.2f cmd", $self->{result_values}->{metric}, $self->{result_values}->{value}); + } + return $msg; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'metric', type => 1, cb_prefix_output => 'prefix_metric_output', message_multiple => "All commands metrics are ok", skipped_code => { -10 => 1 } }, + ]; + + foreach my $statistic ('minimum', 'maximum', 'average', 'sum') { + foreach my $metric ('CmdFlush', 'CmdGet', 'CmdSet', 'CmdConfigGet', 'CmdConfigSet', 'CmdTouch') { + my $entry = { label => lc($metric) . '-' . lc($statistic), set => { + key_values => [ { name => $metric . '_' . $statistic }, { name => 'display' }, { name => 'stat' }, { name => 'timeframe' } ], + closure_custom_calc => $self->can('custom_metric_calc'), + closure_custom_calc_extra_options => { metric => $metric, stat => $statistic }, + closure_custom_output => $self->can('custom_metric_output'), + closure_custom_perfdata => $self->can('custom_metric_perfdata'), + closure_custom_threshold_check => $self->can('custom_metric_threshold'), + } + }; + push @{$self->{maps_counters}->{metric}}, $entry; + } + } +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $self->{version} = '1.0'; + $options{options}->add_options(arguments => + { + "name:s@" => { name => 'name' }, + "node-id:s" => { name => 'node_id' }, + "filter-metric:s" => { name => 'filter_metric' }, + "per-sec" => { name => 'per_sec' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + if (!defined($self->{option_results}->{name}) || $self->{option_results}->{name} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --name option."); + $self->{output}->option_exit(); + } + + foreach my $instance (@{$self->{option_results}->{name}}) { + if ($instance ne '') { + push @{$self->{aws_instance}}, $instance; + } + } + + $self->{aws_timeframe} = defined($self->{option_results}->{timeframe}) ? $self->{option_results}->{timeframe} : 600; + $self->{aws_period} = defined($self->{option_results}->{period}) ? $self->{option_results}->{period} : 60; + + $self->{aws_statistics} = ['Average']; + if (defined($self->{option_results}->{statistic})) { + $self->{aws_statistics} = []; + foreach my $stat (@{$self->{option_results}->{statistic}}) { + if ($stat ne '') { + push @{$self->{aws_statistics}}, ucfirst(lc($stat)); + } + } + } + + foreach my $metric ('CmdFlush', 'CmdGet', 'CmdSet', 'CmdConfigGet', 'CmdConfigSet', 'CmdTouch') { + next if (defined($self->{option_results}->{filter_metric}) && $self->{option_results}->{filter_metric} ne '' + && $metric !~ /$self->{option_results}->{filter_metric}/); + + push @{$self->{aws_metrics}}, $metric; + } + + $instance_mode = $self; +} + +sub manage_selection { + my ($self, %options) = @_; + + my %metric_results; + foreach my $instance (@{$self->{aws_instance}}) { + push @{$self->{aws_dimensions}}, { Name => 'CacheClusterId', Value => $instance }; + if (defined($self->{option_results}->{node_id}) && $self->{option_results}->{node_id} ne '') { + push @{$self->{aws_dimensions}}, { Name => 'CacheNodeId', Value => $self->{option_results}->{node_id} }; + } + $metric_results{$instance} = $options{custom}->cloudwatch_get_metrics( + region => $self->{option_results}->{region}, + namespace => 'AWS/ElastiCache', + dimensions => $self->{aws_dimensions}, + 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($metric_results{$instance}->{$metric}->{lc($statistic)}) && !defined($self->{option_results}->{zeroed})); + + $self->{metric}->{$instance . "_" . lc($statistic)}->{display} = $instance; + $self->{metric}->{$instance . "_" . lc($statistic)}->{stat} = lc($statistic); + $self->{metric}->{$instance . "_" . lc($statistic)}->{node_id} = $self->{option_results}->{node_id}; + $self->{metric}->{$instance . "_" . lc($statistic)}->{timeframe} = $self->{aws_timeframe}; + $self->{metric}->{$instance . "_" . lc($statistic)}->{$metric . "_" . lc($statistic)} = defined($metric_results{$instance}->{$metric}->{lc($statistic)}) ? $metric_results{$instance}->{$metric}->{lc($statistic)} : 0; + } + } + } + + if (scalar(keys %{$self->{metric}}) <= 0) { + $self->{output}->add_option_msg(short_msg => 'No metrics. Check your options or use --zeroed option to set 0 on undefined values'); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check ElastiCache cluster received commands for Memcached backends +(flush, get and set, config get, config set and touch for Memcached 1.4.14). + +Example: +perl centreon_plugins.pl --plugin=cloud::aws::elasticache::plugin --custommode=paws --mode=commands-memcached +--region='eu-west-1' --name='centreon-front' --statistic='average' --critical-cmdget-average='50' --verbose --per-sec + +See 'https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/elasticache-metricscollected.html' for more informations. + +Default statistic: 'average' / All satistics are valid. + +=over 8 + +=item B<--name> + +Set the cluster name (Required) (Can be multiple). + +=item B<--node-id> + +Set the node id (Optional). + +=item B<--filter-metric> + +Filter metrics (Can be: 'CmdFlush', 'CmdGet', 'CmdSet', 'CmdConfigGet', 'CmdConfigSet', 'CmdTouch') +(Can be a regexp). + +=item B<--warning-$metric$-$statistic$> + +Thresholds warning ($metric$ can be: 'cmdflush', 'cmdget', 'cmdset', +'cmdconfigget', 'cmdconfigset', 'cmdtouch', +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=item B<--critical-$metric$-$statistic$> + +Thresholds critical ($metric$ can be: 'cmdflush', 'cmdget', 'cmdset', +'cmdconfigget', 'cmdconfigset', 'cmdtouch', +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=item B<--per-sec> + +Change the data to be unit/sec. + +=back + +=cut diff --git a/cloud/aws/elasticache/mode/commandsredis.pm b/cloud/aws/elasticache/mode/commandsredis.pm new file mode 100644 index 000000000..db4a44e2d --- /dev/null +++ b/cloud/aws/elasticache/mode/commandsredis.pm @@ -0,0 +1,257 @@ +# +# Copyright 2018 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::elasticache::mode::commandsredis; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +my $instance_mode; + +sub prefix_metric_output { + my ($self, %options) = @_; + + my $node_id = ""; + if (defined($options{instance_value}->{node_id}) && $options{instance_value}->{node_id} ne '') { + $node_id = "[Node: $options{instance_value}->{node_id}] "; + } + + return "Cluster '" . $options{instance_value}->{display} . "' " . $node_id . $options{instance_value}->{stat} . " commands "; +} + +sub custom_metric_calc { + my ($self, %options) = @_; + + $self->{result_values}->{timeframe} = $options{new_datas}->{$self->{instance} . '_timeframe'}; + $self->{result_values}->{value} = $options{new_datas}->{$self->{instance} . '_' . $options{extra_options}->{metric} . '_' . $options{extra_options}->{stat}}; + $self->{result_values}->{value_per_sec} = $self->{result_values}->{value} / $self->{result_values}->{timeframe}; + $self->{result_values}->{stat} = $options{extra_options}->{stat}; + $self->{result_values}->{metric} = $options{extra_options}->{metric}; + $self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_display'}; + return 0; +} + +sub custom_metric_threshold { + my ($self, %options) = @_; + + my $exit = $self->{perfdata}->threshold_check(value => defined($instance_mode->{option_results}->{per_sec}) ? $self->{result_values}->{value_per_sec} : $self->{result_values}->{value}, + threshold => [ { label => 'critical-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat}), exit_litteral => 'critical' }, + { label => 'warning-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat}), exit_litteral => 'warning' } ]); + return $exit; +} + +sub custom_metric_perfdata { + my ($self, %options) = @_; + + my $extra_label = ''; + $extra_label = '_' . lc($self->{result_values}->{display}) if (!defined($options{extra_instance}) || $options{extra_instance} != 0); + + $self->{output}->perfdata_add(label => lc($self->{result_values}->{metric}) . "_" . lc($self->{result_values}->{stat}) . $extra_label, + unit => defined($instance_mode->{option_results}->{per_sec}) ? 'cmd/s' : 'cmd', + value => sprintf("%.2f", defined($instance_mode->{option_results}->{per_sec}) ? $self->{result_values}->{value_per_sec} : $self->{result_values}->{value}), + warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat})), + critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat})), + ); +} + +sub custom_metric_output { + my ($self, %options) = @_; + my $msg = ""; + + if (defined($instance_mode->{option_results}->{per_sec})) { + $msg = sprintf("%s: %.2f cmd/s", $self->{result_values}->{metric}, $self->{result_values}->{value_per_sec}); + } else { + $msg = sprintf("%s: %.2f cmd", $self->{result_values}->{metric}, $self->{result_values}->{value}); + } + return $msg; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'metric', type => 1, cb_prefix_output => 'prefix_metric_output', message_multiple => "All commands metrics are ok", skipped_code => { -10 => 1 } }, + ]; + + foreach my $statistic ('minimum', 'maximum', 'average', 'sum') { + foreach my $metric ('GetTypeCmds', 'HashBasedCmds', 'KeyBasedCmds', 'ListBasedCmds', 'SetBasedCmds', + 'SetTypeCmds', 'SortedSetBasedCmds', 'StringBasedCmds', 'HyperLogLogBasedCmds') { + my $entry = { label => lc($metric) . '-' . lc($statistic), set => { + key_values => [ { name => $metric . '_' . $statistic }, { name => 'display' }, { name => 'stat' }, { name => 'timeframe' } ], + closure_custom_calc => $self->can('custom_metric_calc'), + closure_custom_calc_extra_options => { metric => $metric, stat => $statistic }, + closure_custom_output => $self->can('custom_metric_output'), + closure_custom_perfdata => $self->can('custom_metric_perfdata'), + closure_custom_threshold_check => $self->can('custom_metric_threshold'), + } + }; + push @{$self->{maps_counters}->{metric}}, $entry; + } + } +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $self->{version} = '1.0'; + $options{options}->add_options(arguments => + { + "name:s@" => { name => 'name' }, + "node-id:s" => { name => 'node_id' }, + "filter-metric:s" => { name => 'filter_metric' }, + "per-sec" => { name => 'per_sec' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + if (!defined($self->{option_results}->{name}) || $self->{option_results}->{name} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --name option."); + $self->{output}->option_exit(); + } + + foreach my $instance (@{$self->{option_results}->{name}}) { + if ($instance ne '') { + push @{$self->{aws_instance}}, $instance; + } + } + + $self->{aws_timeframe} = defined($self->{option_results}->{timeframe}) ? $self->{option_results}->{timeframe} : 600; + $self->{aws_period} = defined($self->{option_results}->{period}) ? $self->{option_results}->{period} : 60; + + $self->{aws_statistics} = ['Average']; + if (defined($self->{option_results}->{statistic})) { + $self->{aws_statistics} = []; + foreach my $stat (@{$self->{option_results}->{statistic}}) { + if ($stat ne '') { + push @{$self->{aws_statistics}}, ucfirst(lc($stat)); + } + } + } + + foreach my $metric ('GetTypeCmds', 'HashBasedCmds', 'KeyBasedCmds', 'ListBasedCmds', 'SetBasedCmds', + 'SetTypeCmds', 'SortedSetBasedCmds', 'StringBasedCmds', 'HyperLogLogBasedCmds') { + next if (defined($self->{option_results}->{filter_metric}) && $self->{option_results}->{filter_metric} ne '' + && $metric !~ /$self->{option_results}->{filter_metric}/); + + push @{$self->{aws_metrics}}, $metric; + } + + $instance_mode = $self; +} + +sub manage_selection { + my ($self, %options) = @_; + + my %metric_results; + foreach my $instance (@{$self->{aws_instance}}) { + push @{$self->{aws_dimensions}}, { Name => 'CacheClusterId', Value => $instance }; + if (defined($self->{option_results}->{node_id}) && $self->{option_results}->{node_id} ne '') { + push @{$self->{aws_dimensions}}, { Name => 'CacheNodeId', Value => $self->{option_results}->{node_id} }; + } + $metric_results{$instance} = $options{custom}->cloudwatch_get_metrics( + region => $self->{option_results}->{region}, + namespace => 'AWS/ElastiCache', + dimensions => $self->{aws_dimensions}, + 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($metric_results{$instance}->{$metric}->{lc($statistic)}) && !defined($self->{option_results}->{zeroed})); + + $self->{metric}->{$instance . "_" . lc($statistic)}->{display} = $instance; + $self->{metric}->{$instance . "_" . lc($statistic)}->{stat} = lc($statistic); + $self->{metric}->{$instance . "_" . lc($statistic)}->{node_id} = $self->{option_results}->{node_id}; + $self->{metric}->{$instance . "_" . lc($statistic)}->{timeframe} = $self->{aws_timeframe}; + $self->{metric}->{$instance . "_" . lc($statistic)}->{$metric . "_" . lc($statistic)} = defined($metric_results{$instance}->{$metric}->{lc($statistic)}) ? $metric_results{$instance}->{$metric}->{lc($statistic)} : 0; + } + } + } + + if (scalar(keys %{$self->{metric}}) <= 0) { + $self->{output}->add_option_msg(short_msg => 'No metrics. Check your options or use --zeroed option to set 0 on undefined values'); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check ElastiCache cluster received commands for Redis backends +(get and set, hash, key, list, set, sorted set, string and hyperlog log based). + +Example: +perl centreon_plugins.pl --plugin=cloud::aws::elasticache::plugin --custommode=paws --mode=commands-redis +--region='eu-west-1' --name='centreon-front' --statistic='average' --critical-cmdget-average='50' --verbose --per-sec + +See 'https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/elasticache-metricscollected.html' for more informations. + +Default statistic: 'average' / All satistics are valid. + +=over 8 + +=item B<--name> + +Set the cluster name (Required) (Can be multiple). + +=item B<--node-id> + +Set the node id (Optional). + +=item B<--filter-metric> + +Filter metrics (Can be: 'GetTypeCmds', 'HashBasedCmds', 'KeyBasedCmds', 'ListBasedCmds', +'SetBasedCmds', 'SetTypeCmds', 'SortedSetBasedCmds', 'StringBasedCmds', 'HyperLogLogBasedCmds') +(Can be a regexp). + +=item B<--warning-$metric$-$statistic$> + +Thresholds warning ($metric$ can be: 'gettypecmds', 'hashbasedcmds', 'keybasedcmds', 'listbasedcmds', +'setbasedcmds', 'settypecmds', 'sortedsetbasedcmds', 'stringbasedcmds', 'hyperloglogbasedcmds', +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=item B<--critical-$metric$-$statistic$> + +Thresholds critical ($metric$ can be: 'gettypecmds', 'hashbasedcmds', 'keybasedcmds', 'listbasedcmds', +'setbasedcmds', 'settypecmds', 'sortedsetbasedcmds', 'stringbasedcmds' 'hyperloglogbasedcmds', +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=item B<--per-sec> + +Change the data to be unit/sec. + +=back + +=cut diff --git a/cloud/aws/elasticache/mode/connections.pm b/cloud/aws/elasticache/mode/connections.pm new file mode 100644 index 000000000..8a7c8aa40 --- /dev/null +++ b/cloud/aws/elasticache/mode/connections.pm @@ -0,0 +1,265 @@ +# +# Copyright 2018 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::elasticache::mode::connections; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +my $instance_mode; + +sub prefix_metric_output { + my ($self, %options) = @_; + + my $node_id = ""; + if (defined($options{instance_value}->{node_id}) && $options{instance_value}->{node_id} ne '') { + $node_id = "[Node: $options{instance_value}->{node_id}] "; + } + + return "Cluster '" . $options{instance_value}->{display} . "' " . $node_id . $options{instance_value}->{stat} . " "; +} + +sub custom_connection_calc { + my ($self, %options) = @_; + + $self->{result_values}->{timeframe} = $options{new_datas}->{$self->{instance} . '_timeframe'}; + $self->{result_values}->{value} = $options{new_datas}->{$self->{instance} . '_' . $options{extra_options}->{metric} . '_' . $options{extra_options}->{stat}}; + $self->{result_values}->{value_per_sec} = $self->{result_values}->{value} / $self->{result_values}->{timeframe}; + $self->{result_values}->{stat} = $options{extra_options}->{stat}; + $self->{result_values}->{metric} = $options{extra_options}->{metric}; + $self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_display'}; + return 0; +} + +sub custom_connection_threshold { + my ($self, %options) = @_; + + my $exit = $self->{perfdata}->threshold_check(value => defined($instance_mode->{option_results}->{per_sec}) ? $self->{result_values}->{value_per_sec} : $self->{result_values}->{value}, + threshold => [ { label => 'critical-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat}), exit_litteral => 'critical' }, + { label => 'warning-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat}), exit_litteral => 'warning' } ]); + return $exit; +} + +sub custom_connection_perfdata { + my ($self, %options) = @_; + + my $extra_label = ''; + $extra_label = '_' . lc($self->{result_values}->{display}) if (!defined($options{extra_instance}) || $options{extra_instance} != 0); + + $self->{output}->perfdata_add(label => lc($self->{result_values}->{metric}) . "_" . lc($self->{result_values}->{stat}) . $extra_label, + unit => defined($instance_mode->{option_results}->{per_sec}) ? 'conn/s' : 'conn', + value => sprintf("%.2f", defined($instance_mode->{option_results}->{per_sec}) ? $self->{result_values}->{value_per_sec} : $self->{result_values}->{value}), + warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat})), + critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat})), + ); +} + +sub custom_connection_output { + my ($self, %options) = @_; + my $msg = ""; + + if (defined($instance_mode->{option_results}->{per_sec})) { + $msg = sprintf("%s: %.2f connections/s", $self->{result_values}->{metric}, $self->{result_values}->{value_per_sec}); + } else { + $msg = sprintf("%s: %.2f connections", $self->{result_values}->{metric}, $self->{result_values}->{value}); + } + return $msg; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'metric', type => 1, cb_prefix_output => 'prefix_metric_output', message_multiple => "All connections metrics are ok", skipped_code => { -10 => 1 } }, + ]; + + foreach my $statistic ('minimum', 'maximum', 'average', 'sum') { + foreach my $metric ('CurrConnections') { + my $entry = { label => lc($metric) . '-' . lc($statistic), set => { + key_values => [ { name => $metric . '_' . $statistic }, { name => 'display' }, { name => 'stat' } ], + output_template => $metric . ': %d connections', + perfdatas => [ + { label => lc($metric) . '_' . lc($statistic), value => $metric . '_' . $statistic . '_absolute', + template => '%d', unit => 'conn', min => 0, label_extra_instance => 1, instance_use => 'display_absolute' }, + ], + } + }; + push @{$self->{maps_counters}->{metric}}, $entry; + } + foreach my $metric ('NewConnections') { + my $entry = { label => lc($metric) . '-' . lc($statistic), set => { + key_values => [ { name => $metric . '_' . $statistic }, { name => 'display' }, { name => 'stat' }, { name => 'timeframe' } ], + closure_custom_calc => $self->can('custom_connection_calc'), + closure_custom_calc_extra_options => { metric => $metric, stat => $statistic }, + closure_custom_output => $self->can('custom_connection_output'), + closure_custom_perfdata => $self->can('custom_connection_perfdata'), + closure_custom_threshold_check => $self->can('custom_connection_threshold'), + } + }; + push @{$self->{maps_counters}->{metric}}, $entry; + } + } +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $self->{version} = '1.0'; + $options{options}->add_options(arguments => + { + "name:s@" => { name => 'name' }, + "node-id:s" => { name => 'node_id' }, + "filter-metric:s" => { name => 'filter_metric' }, + "per-sec" => { name => 'per_sec' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + if (!defined($self->{option_results}->{name}) || $self->{option_results}->{name} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --name option."); + $self->{output}->option_exit(); + } + + foreach my $instance (@{$self->{option_results}->{name}}) { + if ($instance ne '') { + push @{$self->{aws_instance}}, $instance; + } + } + + $self->{aws_timeframe} = defined($self->{option_results}->{timeframe}) ? $self->{option_results}->{timeframe} : 600; + $self->{aws_period} = defined($self->{option_results}->{period}) ? $self->{option_results}->{period} : 60; + + $self->{aws_statistics} = ['Average']; + if (defined($self->{option_results}->{statistic})) { + $self->{aws_statistics} = []; + foreach my $stat (@{$self->{option_results}->{statistic}}) { + if ($stat ne '') { + push @{$self->{aws_statistics}}, ucfirst(lc($stat)); + } + } + } + + foreach my $metric ('CurrConnections', 'NewConnections') { + next if (defined($self->{option_results}->{filter_metric}) && $self->{option_results}->{filter_metric} ne '' + && $metric !~ /$self->{option_results}->{filter_metric}/); + + push @{$self->{aws_metrics}}, $metric; + } + + $instance_mode = $self; +} + +sub manage_selection { + my ($self, %options) = @_; + + my %metric_results; + foreach my $instance (@{$self->{aws_instance}}) { + push @{$self->{aws_dimensions}}, { Name => 'CacheClusterId', Value => $instance }; + if (defined($self->{option_results}->{node_id}) && $self->{option_results}->{node_id} ne '') { + push @{$self->{aws_dimensions}}, { Name => 'CacheNodeId', Value => $self->{option_results}->{node_id} }; + } + $metric_results{$instance} = $options{custom}->cloudwatch_get_metrics( + region => $self->{option_results}->{region}, + namespace => 'AWS/ElastiCache', + dimensions => $self->{aws_dimensions}, + 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($metric_results{$instance}->{$metric}->{lc($statistic)}) && !defined($self->{option_results}->{zeroed})); + + $self->{metric}->{$instance . "_" . lc($statistic)}->{display} = $instance; + $self->{metric}->{$instance . "_" . lc($statistic)}->{stat} = lc($statistic); + $self->{metric}->{$instance . "_" . lc($statistic)}->{node_id} = $self->{option_results}->{node_id}; + $self->{metric}->{$instance . "_" . lc($statistic)}->{timeframe} = $self->{aws_timeframe}; + $self->{metric}->{$instance . "_" . lc($statistic)}->{$metric . "_" . lc($statistic)} = defined($metric_results{$instance}->{$metric}->{lc($statistic)}) ? $metric_results{$instance}->{$metric}->{lc($statistic)} : 0; + } + } + } + + if (scalar(keys %{$self->{metric}}) <= 0) { + $self->{output}->add_option_msg(short_msg => 'No metrics. Check your options or use --zeroed option to set 0 on undefined values'); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check ElastiCache cluster connections (current and new). + +Works with Memcached and Redis backends. + +Example: +perl centreon_plugins.pl --plugin=cloud::aws::elasticache::plugin --custommode=paws --mode=connections --region='eu-west-1' +--name='centreon-front' --statistic='average' --critical-currconnections-average='20' --verbose + +See 'https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/elasticache-metricscollected.html' for more informations. + +Default statistic: 'average' / All satistics are valid. + +=over 8 + +=item B<--name> + +Set the cluster name (Required) (Can be multiple). + +=item B<--node-id> + +Set the node id (Optional). + +=item B<--filter-metric> + +Filter metrics (Can be: 'CurrConnections', 'NewConnections') +(Can be a regexp). + +=item B<--warning-$metric$-$statistic$> + +Thresholds warning ($metric$ can be: 'currconnections', 'newconnections', +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=item B<--critical-$metric$-$statistic$> + +Thresholds critical ($metric$ can be: 'currconnections', 'newconnections', +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=item B<--per-sec> + +Change the data to be unit/sec. + +=back + +=cut diff --git a/cloud/aws/elasticache/mode/cpu.pm b/cloud/aws/elasticache/mode/cpu.pm new file mode 100644 index 000000000..4d5d1794b --- /dev/null +++ b/cloud/aws/elasticache/mode/cpu.pm @@ -0,0 +1,184 @@ +# +# Copyright 2018 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::elasticache::mode::cpu; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +sub prefix_metric_output { + my ($self, %options) = @_; + + my $node_id = ""; + if (defined($options{instance_value}->{node_id}) && $options{instance_value}->{node_id} ne '') { + $node_id = "[Node: $options{instance_value}->{node_id}] "; + } + + return "Cluster '" . $options{instance_value}->{display} . "' " . $node_id . $options{instance_value}->{stat} . " "; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'metric', type => 1, cb_prefix_output => 'prefix_metric_output', message_multiple => "All CPU metrics are ok", skipped_code => { -10 => 1 } }, + ]; + + foreach my $statistic ('minimum', 'maximum', 'average', 'sum') { + foreach my $metric ('CPUUtilization') { + my $entry = { label => lc($metric) . '-' . lc($statistic), set => { + key_values => [ { name => $metric . '_' . $statistic }, { name => 'display' }, { name => 'stat' } ], + output_template => $metric . ': %.2f %%', + perfdatas => [ + { label => lc($metric) . '_' . lc($statistic), value => $metric . '_' . $statistic . '_absolute', + template => '%.2f', unit => '%', min => 0, max => 100, label_extra_instance => 1, instance_use => 'display_absolute' }, + ], + } + }; + push @{$self->{maps_counters}->{metric}}, $entry; + } + } +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $self->{version} = '1.0'; + $options{options}->add_options(arguments => + { + "region:s" => { name => 'region' }, + "name:s@" => { name => 'name' }, + "node-id:s" => { name => 'node_id' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + if (!defined($self->{option_results}->{name}) || $self->{option_results}->{name} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --name option."); + $self->{output}->option_exit(); + } + + foreach my $instance (@{$self->{option_results}->{name}}) { + if ($instance ne '') { + push @{$self->{aws_instance}}, $instance; + } + } + + $self->{aws_timeframe} = defined($self->{option_results}->{timeframe}) ? $self->{option_results}->{timeframe} : 600; + $self->{aws_period} = defined($self->{option_results}->{period}) ? $self->{option_results}->{period} : 60; + + $self->{aws_statistics} = ['Average']; + if (defined($self->{option_results}->{statistic})) { + $self->{aws_statistics} = []; + foreach my $stat (@{$self->{option_results}->{statistic}}) { + if ($stat ne '') { + push @{$self->{aws_statistics}}, ucfirst(lc($stat)); + } + } + } + + push @{$self->{aws_metrics}}, 'CPUUtilization'; +} + +sub manage_selection { + my ($self, %options) = @_; + + my %metric_results; + foreach my $instance (@{$self->{aws_instance}}) { + push @{$self->{aws_dimensions}}, { Name => 'CacheClusterId', Value => $instance }; + if (defined($self->{option_results}->{node_id}) && $self->{option_results}->{node_id} ne '') { + push @{$self->{aws_dimensions}}, { Name => 'CacheNodeId', Value => $self->{option_results}->{node_id} }; + } + $metric_results{$instance} = $options{custom}->cloudwatch_get_metrics( + region => $self->{option_results}->{region}, + namespace => 'AWS/ElastiCache', + dimensions => $self->{aws_dimensions}, + 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($metric_results{$instance}->{$metric}->{lc($statistic)}) && !defined($self->{option_results}->{zeroed})); + + $self->{metric}->{$instance . "_" . lc($statistic)}->{display} = $instance; + $self->{metric}->{$instance . "_" . lc($statistic)}->{stat} = lc($statistic); + $self->{metric}->{$instance . "_" . lc($statistic)}->{node_id} = $self->{option_results}->{node_id}; + $self->{metric}->{$instance . "_" . lc($statistic)}->{$metric . "_" . lc($statistic)} = defined($metric_results{$instance}->{$metric}->{lc($statistic)}) ? $metric_results{$instance}->{$metric}->{lc($statistic)} : 0; + } + } + } + + if (scalar(keys %{$self->{metric}}) <= 0) { + $self->{output}->add_option_msg(short_msg => 'No metrics. Check your options or use --zeroed option to set 0 on undefined values'); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check ElastiCache cluster CPU utilization. + +Works with Memcached and Redis backends. + +Example: +perl centreon_plugins.pl --plugin=cloud::aws::elasticache::plugin --custommode=paws --mode=cpu --region='eu-west-1' +--name='centreon-front' --statistic='average' --critical-cpuutilization-average='90' --verbose + +See 'https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/elasticache-metricscollected.html' for more informations. + +Default statistic: 'average' / All satistics are valid. + +=over 8 + +=item B<--name> + +Set the cluster name (Required) (Can be multiple). + +=item B<--node-id> + +Set the node id (Optional). + +=item B<--warning-cpuutilization-$statistic$> + +Thresholds warning ($statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=item B<--critical-cpuutilization-$statistic$> + +Thresholds critical ($statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=back + +=cut diff --git a/cloud/aws/elasticache/mode/evictions.pm b/cloud/aws/elasticache/mode/evictions.pm new file mode 100644 index 000000000..3a3a05700 --- /dev/null +++ b/cloud/aws/elasticache/mode/evictions.pm @@ -0,0 +1,253 @@ +# +# Copyright 2018 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::elasticache::mode::evictions; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +my $instance_mode; + +sub prefix_metric_output { + my ($self, %options) = @_; + + my $node_id = ""; + if (defined($options{instance_value}->{node_id}) && $options{instance_value}->{node_id} ne '') { + $node_id = "[Node: $options{instance_value}->{node_id}] "; + } + + return "Cluster '" . $options{instance_value}->{display} . "' " . $node_id . $options{instance_value}->{stat} . " "; +} + +sub custom_metric_calc { + my ($self, %options) = @_; + + $self->{result_values}->{timeframe} = $options{new_datas}->{$self->{instance} . '_timeframe'}; + $self->{result_values}->{value} = $options{new_datas}->{$self->{instance} . '_' . $options{extra_options}->{metric} . '_' . $options{extra_options}->{stat}}; + $self->{result_values}->{value_per_sec} = $self->{result_values}->{value} / $self->{result_values}->{timeframe}; + $self->{result_values}->{stat} = $options{extra_options}->{stat}; + $self->{result_values}->{metric} = $options{extra_options}->{metric}; + $self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_display'}; + return 0; +} + +sub custom_metric_threshold { + my ($self, %options) = @_; + + my $exit = $self->{perfdata}->threshold_check(value => defined($instance_mode->{option_results}->{per_sec}) ? $self->{result_values}->{value_per_sec} : $self->{result_values}->{value}, + threshold => [ { label => 'critical-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat}), exit_litteral => 'critical' }, + { label => 'warning-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat}), exit_litteral => 'warning' } ]); + return $exit; +} + +sub custom_metric_perfdata { + my ($self, %options) = @_; + + my $extra_label = ''; + $extra_label = '_' . lc($self->{result_values}->{display}) if (!defined($options{extra_instance}) || $options{extra_instance} != 0); + + $self->{output}->perfdata_add(label => lc($self->{result_values}->{metric}) . "_" . lc($self->{result_values}->{stat}) . $extra_label, + unit => defined($instance_mode->{option_results}->{per_sec}) ? 'evictions/s' : 'evictions', + value => sprintf("%.2f", defined($instance_mode->{option_results}->{per_sec}) ? $self->{result_values}->{value_per_sec} : $self->{result_values}->{value}), + warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat})), + critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat})), + ); +} + +sub custom_metric_output { + my ($self, %options) = @_; + my $msg = ""; + + if (defined($instance_mode->{option_results}->{per_sec})) { + $msg = sprintf("%s: %.2f evictions/s", $self->{result_values}->{metric}, $self->{result_values}->{value_per_sec}); + } else { + $msg = sprintf("%s: %.2f evictions", $self->{result_values}->{metric}, $self->{result_values}->{value}); + } + return $msg; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'metric', type => 1, cb_prefix_output => 'prefix_metric_output', message_multiple => "All evictions metrics are ok", skipped_code => { -10 => 1 } }, + ]; + + foreach my $statistic ('minimum', 'maximum', 'average', 'sum') { + foreach my $metric ('Evictions', 'Reclaimed') { + my $entry = { label => lc($metric) . '-' . lc($statistic), set => { + key_values => [ { name => $metric . '_' . $statistic }, { name => 'display' }, { name => 'stat' }, { name => 'timeframe' } ], + closure_custom_calc => $self->can('custom_metric_calc'), + closure_custom_calc_extra_options => { metric => $metric, stat => $statistic }, + closure_custom_output => $self->can('custom_metric_output'), + closure_custom_perfdata => $self->can('custom_metric_perfdata'), + closure_custom_threshold_check => $self->can('custom_metric_threshold'), + } + }; + push @{$self->{maps_counters}->{metric}}, $entry; + } + } +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $self->{version} = '1.0'; + $options{options}->add_options(arguments => + { + "name:s@" => { name => 'name' }, + "node-id:s" => { name => 'node_id' }, + "filter-metric:s" => { name => 'filter_metric' }, + "per-sec" => { name => 'per_sec' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + if (!defined($self->{option_results}->{name}) || $self->{option_results}->{name} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --name option."); + $self->{output}->option_exit(); + } + + foreach my $instance (@{$self->{option_results}->{name}}) { + if ($instance ne '') { + push @{$self->{aws_instance}}, $instance; + } + } + + $self->{aws_timeframe} = defined($self->{option_results}->{timeframe}) ? $self->{option_results}->{timeframe} : 600; + $self->{aws_period} = defined($self->{option_results}->{period}) ? $self->{option_results}->{period} : 60; + + $self->{aws_statistics} = ['Average']; + if (defined($self->{option_results}->{statistic})) { + $self->{aws_statistics} = []; + foreach my $stat (@{$self->{option_results}->{statistic}}) { + if ($stat ne '') { + push @{$self->{aws_statistics}}, ucfirst(lc($stat)); + } + } + } + + foreach my $metric ('Evictions', 'Reclaimed') { + next if (defined($self->{option_results}->{filter_metric}) && $self->{option_results}->{filter_metric} ne '' + && $metric !~ /$self->{option_results}->{filter_metric}/); + + push @{$self->{aws_metrics}}, $metric; + } + + $instance_mode = $self; +} + +sub manage_selection { + my ($self, %options) = @_; + + my %metric_results; + foreach my $instance (@{$self->{aws_instance}}) { + push @{$self->{aws_dimensions}}, { Name => 'CacheClusterId', Value => $instance }; + if (defined($self->{option_results}->{node_id}) && $self->{option_results}->{node_id} ne '') { + push @{$self->{aws_dimensions}}, { Name => 'CacheNodeId', Value => $self->{option_results}->{node_id} }; + } + $metric_results{$instance} = $options{custom}->cloudwatch_get_metrics( + region => $self->{option_results}->{region}, + namespace => 'AWS/ElastiCache', + dimensions => $self->{aws_dimensions}, + 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($metric_results{$instance}->{$metric}->{lc($statistic)}) && !defined($self->{option_results}->{zeroed})); + + $self->{metric}->{$instance . "_" . lc($statistic)}->{display} = $instance; + $self->{metric}->{$instance . "_" . lc($statistic)}->{stat} = lc($statistic); + $self->{metric}->{$instance . "_" . lc($statistic)}->{node_id} = $self->{option_results}->{node_id}; + $self->{metric}->{$instance . "_" . lc($statistic)}->{timeframe} = $self->{aws_timeframe}; + $self->{metric}->{$instance . "_" . lc($statistic)}->{$metric . "_" . lc($statistic)} = defined($metric_results{$instance}->{$metric}->{lc($statistic)}) ? $metric_results{$instance}->{$metric}->{lc($statistic)} : 0; + } + } + } + + if (scalar(keys %{$self->{metric}}) <= 0) { + $self->{output}->add_option_msg(short_msg => 'No metrics. Check your options or use --zeroed option to set 0 on undefined values'); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check ElastiCache cluster evictions to retreive space (evicted and reclaimed). + +Works with Memcached and Redis backends. + +Example: +perl centreon_plugins.pl --plugin=cloud::aws::elasticache::plugin --custommode=paws --mode=evictions --region='eu-west-1' +--name='centreon-front' --statistic='average' --critical-evictions-average='10' --verbose + +See 'https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/elasticache-metricscollected.html' for more informations. + +Default statistic: 'average' / All satistics are valid. + +=over 8 + +=item B<--name> + +Set the cluster name (Required) (Can be multiple). + +=item B<--node-id> + +Set the node id (Optional). + +=item B<--filter-metric> + +Filter metrics (Can be: 'Evictions', 'Reclaimed') +(Can be a regexp). + +=item B<--warning-$metric$-$statistic$> + +Thresholds warning ($metric$ can be: 'evictions', 'reclaimed', +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=item B<--critical-$metric$-$statistic$> + +Thresholds critical ($metric$ can be: 'evictions', 'reclaimed', +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=item B<--per-sec> + +Change the data to be unit/sec. + +=back + +=cut diff --git a/cloud/aws/elasticache/mode/items.pm b/cloud/aws/elasticache/mode/items.pm new file mode 100644 index 000000000..d92f25da9 --- /dev/null +++ b/cloud/aws/elasticache/mode/items.pm @@ -0,0 +1,265 @@ +# +# Copyright 2018 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::elasticache::mode::items; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +my $instance_mode; + +sub prefix_metric_output { + my ($self, %options) = @_; + + my $node_id = ""; + if (defined($options{instance_value}->{node_id}) && $options{instance_value}->{node_id} ne '') { + $node_id = "[Node: $options{instance_value}->{node_id}] "; + } + + return "Cluster '" . $options{instance_value}->{display} . "' " . $node_id . $options{instance_value}->{stat} . " "; +} + +sub custom_item_calc { + my ($self, %options) = @_; + + $self->{result_values}->{timeframe} = $options{new_datas}->{$self->{instance} . '_timeframe'}; + $self->{result_values}->{value} = $options{new_datas}->{$self->{instance} . '_' . $options{extra_options}->{metric} . '_' . $options{extra_options}->{stat}}; + $self->{result_values}->{value_per_sec} = $self->{result_values}->{value} / $self->{result_values}->{timeframe}; + $self->{result_values}->{stat} = $options{extra_options}->{stat}; + $self->{result_values}->{metric} = $options{extra_options}->{metric}; + $self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_display'}; + return 0; +} + +sub custom_item_threshold { + my ($self, %options) = @_; + + my $exit = $self->{perfdata}->threshold_check(value => defined($instance_mode->{option_results}->{per_sec}) ? $self->{result_values}->{value_per_sec} : $self->{result_values}->{value}, + threshold => [ { label => 'critical-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat}), exit_litteral => 'critical' }, + { label => 'warning-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat}), exit_litteral => 'warning' } ]); + return $exit; +} + +sub custom_item_perfdata { + my ($self, %options) = @_; + + my $extra_label = ''; + $extra_label = '_' . lc($self->{result_values}->{display}) if (!defined($options{extra_instance}) || $options{extra_instance} != 0); + + $self->{output}->perfdata_add(label => lc($self->{result_values}->{metric}) . "_" . lc($self->{result_values}->{stat}) . $extra_label, + unit => defined($instance_mode->{option_results}->{per_sec}) ? 'items/s' : 'items', + value => sprintf("%.2f", defined($instance_mode->{option_results}->{per_sec}) ? $self->{result_values}->{value_per_sec} : $self->{result_values}->{value}), + warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat})), + critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat})), + ); +} + +sub custom_item_output { + my ($self, %options) = @_; + my $msg = ""; + + if (defined($instance_mode->{option_results}->{per_sec})) { + $msg = sprintf("%s: %.2f items/s", $self->{result_values}->{metric}, $self->{result_values}->{value_per_sec}); + } else { + $msg = sprintf("%s: %.2f items", $self->{result_values}->{metric}, $self->{result_values}->{value}); + } + return $msg; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'metric', type => 1, cb_prefix_output => 'prefix_metric_output', message_multiple => "All items metrics are ok", skipped_code => { -10 => 1 } }, + ]; + + foreach my $statistic ('minimum', 'maximum', 'average', 'sum') { + foreach my $metric ('CurrItems') { + my $entry = { label => lc($metric) . '-' . lc($statistic), set => { + key_values => [ { name => $metric . '_' . $statistic }, { name => 'display' }, { name => 'stat' }, { name => 'timeframe' } ], + output_template => $metric . ': %d items', + perfdatas => [ + { label => lc($metric) . '_' . lc($statistic), value => $metric . '_' . $statistic . '_absolute', + template => '%d', unit => 'items', min => 0, label_extra_instance => 1, instance_use => 'display_absolute' }, + ], + } + }; + push @{$self->{maps_counters}->{metric}}, $entry; + } + foreach my $metric ('NewItems') { + my $entry = { label => lc($metric) . '-' . lc($statistic), set => { + key_values => [ { name => $metric . '_' . $statistic }, { name => 'display' }, { name => 'stat' }, { name => 'timeframe' } ], + closure_custom_calc => $self->can('custom_item_calc'), + closure_custom_calc_extra_options => { metric => $metric, stat => $statistic }, + closure_custom_output => $self->can('custom_item_output'), + closure_custom_perfdata => $self->can('custom_item_perfdata'), + closure_custom_threshold_check => $self->can('custom_item_threshold'), + } + }; + push @{$self->{maps_counters}->{metric}}, $entry; + } + } +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $self->{version} = '1.0'; + $options{options}->add_options(arguments => + { + "name:s@" => { name => 'name' }, + "node-id:s" => { name => 'node_id' }, + "filter-metric:s" => { name => 'filter_metric' }, + "per-sec" => { name => 'per_sec' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + if (!defined($self->{option_results}->{name}) || $self->{option_results}->{name} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --name option."); + $self->{output}->option_exit(); + } + + foreach my $instance (@{$self->{option_results}->{name}}) { + if ($instance ne '') { + push @{$self->{aws_instance}}, $instance; + } + } + + $self->{aws_timeframe} = defined($self->{option_results}->{timeframe}) ? $self->{option_results}->{timeframe} : 600; + $self->{aws_period} = defined($self->{option_results}->{period}) ? $self->{option_results}->{period} : 60; + + $self->{aws_statistics} = ['Average']; + if (defined($self->{option_results}->{statistic})) { + $self->{aws_statistics} = []; + foreach my $stat (@{$self->{option_results}->{statistic}}) { + if ($stat ne '') { + push @{$self->{aws_statistics}}, ucfirst(lc($stat)); + } + } + } + + foreach my $metric ('CurrItems', 'NewItems') { + next if (defined($self->{option_results}->{filter_metric}) && $self->{option_results}->{filter_metric} ne '' + && $metric !~ /$self->{option_results}->{filter_metric}/); + + push @{$self->{aws_metrics}}, $metric; + } + + $instance_mode = $self; +} + +sub manage_selection { + my ($self, %options) = @_; + + my %metric_results; + foreach my $instance (@{$self->{aws_instance}}) { + push @{$self->{aws_dimensions}}, { Name => 'CacheClusterId', Value => $instance }; + if (defined($self->{option_results}->{node_id}) && $self->{option_results}->{node_id} ne '') { + push @{$self->{aws_dimensions}}, { Name => 'CacheNodeId', Value => $self->{option_results}->{node_id} }; + } + $metric_results{$instance} = $options{custom}->cloudwatch_get_metrics( + region => $self->{option_results}->{region}, + namespace => 'AWS/ElastiCache', + dimensions => $self->{aws_dimensions}, + 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($metric_results{$instance}->{$metric}->{lc($statistic)}) && !defined($self->{option_results}->{zeroed})); + + $self->{metric}->{$instance . "_" . lc($statistic)}->{display} = $instance; + $self->{metric}->{$instance . "_" . lc($statistic)}->{stat} = lc($statistic); + $self->{metric}->{$instance . "_" . lc($statistic)}->{node_id} = $self->{option_results}->{node_id}; + $self->{metric}->{$instance . "_" . lc($statistic)}->{timeframe} = $self->{aws_timeframe}; + $self->{metric}->{$instance . "_" . lc($statistic)}->{$metric . "_" . lc($statistic)} = defined($metric_results{$instance}->{$metric}->{lc($statistic)}) ? $metric_results{$instance}->{$metric}->{lc($statistic)} : 0; + } + } + } + + if (scalar(keys %{$self->{metric}}) <= 0) { + $self->{output}->add_option_msg(short_msg => 'No metrics. Check your options or use --zeroed option to set 0 on undefined values'); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check ElastiCache cluster items number (current and new). + +Works with Memcached and Redis backends. + +Example: +perl centreon_plugins.pl --plugin=cloud::aws::elasticache::plugin --custommode=paws --mode=items --region='eu-west-1' +--name='centreon-front' --statistic='average' --critical-newitems-average='10' --verbose + +See 'https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/elasticache-metricscollected.html' for more informations. + +Default statistic: 'average' / All satistics are valid. + +=over 8 + +=item B<--name> + +Set the cluster name (Required) (Can be multiple). + +=item B<--node-id> + +Set the node id (Optional). + +=item B<--filter-metric> + +Filter metrics (Can be: 'CurrItems', 'NewItems') +(Can be a regexp). + +=item B<--warning-$metric$-$statistic$> + +Thresholds warning ($metric$ can be: 'curritems', 'newitems', +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=item B<--critical-$metric$-$statistic$> + +Thresholds critical ($metric$ can be: 'curritems', 'newitems', +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=item B<--per-sec> + +Change the data to be unit/sec. + +=back + +=cut diff --git a/cloud/aws/elasticache/mode/network.pm b/cloud/aws/elasticache/mode/network.pm new file mode 100644 index 000000000..060f0a2a6 --- /dev/null +++ b/cloud/aws/elasticache/mode/network.pm @@ -0,0 +1,255 @@ +# +# Copyright 2018 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::elasticache::mode::network; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +my $instance_mode; + +sub prefix_metric_output { + my ($self, %options) = @_; + + my $node_id = ""; + if (defined($options{instance_value}->{node_id}) && $options{instance_value}->{node_id} ne '') { + $node_id = "[Node: $options{instance_value}->{node_id}] "; + } + + return "Cluster '" . $options{instance_value}->{display} . "' " . $node_id . $options{instance_value}->{stat} . " "; +} + +sub custom_traffic_calc { + my ($self, %options) = @_; + + $self->{result_values}->{timeframe} = $options{new_datas}->{$self->{instance} . '_timeframe'}; + $self->{result_values}->{value} = $options{new_datas}->{$self->{instance} . '_' . $options{extra_options}->{metric} . '_' . $options{extra_options}->{stat}}; + $self->{result_values}->{value_per_sec} = $self->{result_values}->{value} / $self->{result_values}->{timeframe}; + $self->{result_values}->{stat} = $options{extra_options}->{stat}; + $self->{result_values}->{metric} = $options{extra_options}->{metric}; + $self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_display'}; + return 0; +} + +sub custom_traffic_threshold { + my ($self, %options) = @_; + + my $exit = $self->{perfdata}->threshold_check(value => defined($instance_mode->{option_results}->{per_sec}) ? $self->{result_values}->{value_per_sec} : $self->{result_values}->{value}, + threshold => [ { label => 'critical-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat}), exit_litteral => 'critical' }, + { label => 'warning-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat}), exit_litteral => 'warning' } ]); + return $exit; +} + +sub custom_traffic_perfdata { + my ($self, %options) = @_; + + my $extra_label = ''; + $extra_label = '_' . lc($self->{result_values}->{display}) if (!defined($options{extra_instance}) || $options{extra_instance} != 0); + + $self->{output}->perfdata_add(label => lc($self->{result_values}->{metric}) . "_" . lc($self->{result_values}->{stat}) . $extra_label, + unit => defined($instance_mode->{option_results}->{per_sec}) ? 'B/s' : 'B', + value => sprintf("%.2f", defined($instance_mode->{option_results}->{per_sec}) ? $self->{result_values}->{value_per_sec} : $self->{result_values}->{value}), + warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat})), + critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat})), + ); +} + +sub custom_traffic_output { + my ($self, %options) = @_; + my $msg = ""; + + if (defined($instance_mode->{option_results}->{per_sec})) { + my ($value, $unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{value_per_sec}); + $msg = $self->{result_values}->{metric} . ": " . $value . $unit . "/s"; + } else { + my ($value, $unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{value}); + $msg = $self->{result_values}->{metric} . ": " . $value . $unit; + } + return $msg; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'metric', type => 1, cb_prefix_output => 'prefix_metric_output', message_multiple => "All network metrics are ok", skipped_code => { -10 => 1 } }, + ]; + + foreach my $statistic ('minimum', 'maximum', 'average', 'sum') { + foreach my $metric ('NetworkBytesIn', 'NetworkBytesOut') { + my $entry = { label => lc($metric) . '-' . lc($statistic), set => { + key_values => [ { name => $metric . '_' . $statistic }, { name => 'display' }, { name => 'stat' }, { name => 'timeframe' } ], + closure_custom_calc => $self->can('custom_traffic_calc'), + closure_custom_calc_extra_options => { metric => $metric, stat => $statistic }, + closure_custom_output => $self->can('custom_traffic_output'), + closure_custom_perfdata => $self->can('custom_traffic_perfdata'), + closure_custom_threshold_check => $self->can('custom_traffic_threshold'), + } + }; + push @{$self->{maps_counters}->{metric}}, $entry; + } + } +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $self->{version} = '1.0'; + $options{options}->add_options(arguments => + { + "name:s@" => { name => 'name' }, + "node-id:s" => { name => 'node_id' }, + "filter-metric:s" => { name => 'filter_metric' }, + "per-sec" => { name => 'per_sec' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + if (!defined($self->{option_results}->{name}) || $self->{option_results}->{name} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --name option."); + $self->{output}->option_exit(); + } + + foreach my $instance (@{$self->{option_results}->{name}}) { + if ($instance ne '') { + push @{$self->{aws_instance}}, $instance; + } + } + + $self->{aws_timeframe} = defined($self->{option_results}->{timeframe}) ? $self->{option_results}->{timeframe} : 600; + $self->{aws_period} = defined($self->{option_results}->{period}) ? $self->{option_results}->{period} : 60; + + $self->{aws_statistics} = ['Average']; + if (defined($self->{option_results}->{statistic})) { + $self->{aws_statistics} = []; + foreach my $stat (@{$self->{option_results}->{statistic}}) { + if ($stat ne '') { + push @{$self->{aws_statistics}}, ucfirst(lc($stat)); + } + } + } + + foreach my $metric ('NetworkBytesIn', 'NetworkBytesOut') { + next if (defined($self->{option_results}->{filter_metric}) && $self->{option_results}->{filter_metric} ne '' + && $metric !~ /$self->{option_results}->{filter_metric}/); + + push @{$self->{aws_metrics}}, $metric; + } + + $instance_mode = $self; +} + +sub manage_selection { + my ($self, %options) = @_; + + my %metric_results; + foreach my $instance (@{$self->{aws_instance}}) { + push @{$self->{aws_dimensions}}, { Name => 'CacheClusterId', Value => $instance }; + if (defined($self->{option_results}->{node_id}) && $self->{option_results}->{node_id} ne '') { + push @{$self->{aws_dimensions}}, { Name => 'CacheNodeId', Value => $self->{option_results}->{node_id} }; + } + $metric_results{$instance} = $options{custom}->cloudwatch_get_metrics( + region => $self->{option_results}->{region}, + namespace => 'AWS/ElastiCache', + dimensions => $self->{aws_dimensions}, + 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($metric_results{$instance}->{$metric}->{lc($statistic)}) && !defined($self->{option_results}->{zeroed})); + + $self->{metric}->{$instance . "_" . lc($statistic)}->{display} = $instance; + $self->{metric}->{$instance . "_" . lc($statistic)}->{stat} = lc($statistic); + $self->{metric}->{$instance . "_" . lc($statistic)}->{node_id} = $self->{option_results}->{node_id}; + $self->{metric}->{$instance . "_" . lc($statistic)}->{timeframe} = $self->{aws_timeframe}; + $self->{metric}->{$instance . "_" . lc($statistic)}->{$metric . "_" . lc($statistic)} = defined($metric_results{$instance}->{$metric}->{lc($statistic)}) ? $metric_results{$instance}->{$metric}->{lc($statistic)} : 0; + } + } + } + + if (scalar(keys %{$self->{metric}}) <= 0) { + $self->{output}->add_option_msg(short_msg => 'No metrics. Check your options or use --zeroed option to set 0 on undefined values'); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check ElastiCache cluster network usage. + +Works with Memcached and Redis backends. + +Example: +perl centreon_plugins.pl --plugin=cloud::aws::elasticache::plugin --custommode=paws --mode=network --region='eu-west-1' +--name='centreon-front' --statistic='average' --critical-networkbytesin-average='1000' --verbose + +See 'https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/elasticache-metricscollected.html' for more informations. + +Default statistic: 'average' / All satistics are valid. + +=over 8 + +=item B<--name> + +Set the cluster name (Required) (Can be multiple). + +=item B<--node-id> + +Set the node id (Optional). + +=item B<--filter-metric> + +Filter metrics (Can be: 'NetworkBytesIn', 'NetworkBytesOut') +(Can be a regexp). + +=item B<--warning-$metric$-$statistic$> + +Thresholds warning ($metric$ can be: 'networkbytesin', 'networkbytesout', +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=item B<--critical-$metric$-$statistic$> + +Thresholds critical ($metric$ can be: 'networkbytesin', 'networkbytesout', +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=item B<--per-sec> + +Change the data to be unit/sec. + +=back + +=cut diff --git a/cloud/aws/elasticache/mode/replication.pm b/cloud/aws/elasticache/mode/replication.pm new file mode 100644 index 000000000..461d8c795 --- /dev/null +++ b/cloud/aws/elasticache/mode/replication.pm @@ -0,0 +1,267 @@ +# +# Copyright 2018 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::elasticache::mode::replication; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +my $instance_mode; + +sub prefix_metric_output { + my ($self, %options) = @_; + + my $node_id = ""; + if (defined($options{instance_value}->{node_id}) && $options{instance_value}->{node_id} ne '') { + $node_id = "[Node: $options{instance_value}->{node_id}] "; + } + + return "Cluster '" . $options{instance_value}->{display} . "' " . $node_id . $options{instance_value}->{stat} . " "; +} + +sub custom_metric_calc { + my ($self, %options) = @_; + + $self->{result_values}->{timeframe} = $options{new_datas}->{$self->{instance} . '_timeframe'}; + $self->{result_values}->{value} = $options{new_datas}->{$self->{instance} . '_' . $options{extra_options}->{metric} . '_' . $options{extra_options}->{stat}}; + $self->{result_values}->{value_per_sec} = $self->{result_values}->{value} / $self->{result_values}->{timeframe}; + $self->{result_values}->{stat} = $options{extra_options}->{stat}; + $self->{result_values}->{metric} = $options{extra_options}->{metric}; + $self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_display'}; + return 0; +} + +sub custom_metric_threshold { + my ($self, %options) = @_; + + my $exit = $self->{perfdata}->threshold_check(value => defined($instance_mode->{option_results}->{per_sec}) ? $self->{result_values}->{value_per_sec} : $self->{result_values}->{value}, + threshold => [ { label => 'critical-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat}), exit_litteral => 'critical' }, + { label => 'warning-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat}), exit_litteral => 'warning' } ]); + return $exit; +} + +sub custom_metric_perfdata { + my ($self, %options) = @_; + + my $extra_label = ''; + $extra_label = '_' . lc($self->{result_values}->{display}) if (!defined($options{extra_instance}) || $options{extra_instance} != 0); + + $self->{output}->perfdata_add(label => lc($self->{result_values}->{metric}) . "_" . lc($self->{result_values}->{stat}) . $extra_label, + unit => defined($instance_mode->{option_results}->{per_sec}) ? 'B/s' : 'B', + value => sprintf("%.2f", defined($instance_mode->{option_results}->{per_sec}) ? $self->{result_values}->{value_per_sec} : $self->{result_values}->{value}), + warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat})), + critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat})), + ); +} + +sub custom_metric_output { + my ($self, %options) = @_; + my $msg = ""; + + if (defined($instance_mode->{option_results}->{per_sec})) { + my ($value, $unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{value_per_sec}); + $msg = $self->{result_values}->{metric} . ": " . $value . $unit . "/s"; + } else { + my ($value, $unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{value}); + $msg = $self->{result_values}->{metric} . ": " . $value . $unit; + } + return $msg; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'metric', type => 1, cb_prefix_output => 'prefix_metric_output', message_multiple => "All replication metrics are ok", skipped_code => { -10 => 1 } }, + ]; + + foreach my $statistic ('minimum', 'maximum', 'average', 'sum') { + foreach my $metric ('ReplicationBytes') { + my $entry = { label => lc($metric) . '-' . lc($statistic), set => { + key_values => [ { name => $metric . '_' . $statistic }, { name => 'display' }, { name => 'stat' }, { name => 'timeframe' } ], + closure_custom_calc => $self->can('custom_metric_calc'), + closure_custom_calc_extra_options => { metric => $metric, stat => $statistic }, + closure_custom_output => $self->can('custom_metric_output'), + closure_custom_perfdata => $self->can('custom_metric_perfdata'), + closure_custom_threshold_check => $self->can('custom_metric_threshold'), + } + }; + push @{$self->{maps_counters}->{metric}}, $entry; + } + foreach my $metric ('ReplicationLag') { + my $entry = { label => lc($metric) . '-' . lc($statistic), set => { + key_values => [ { name => $metric . '_' . $statistic }, { name => 'display' }, { name => 'stat' }, { name => 'timeframe' } ], + output_template => $metric . ': %.2f s', + perfdatas => [ + { label => lc($metric) . '_' . lc($statistic), value => $metric . '_' . $statistic . '_absolute', + template => '%.2f', unit => 's', min => 0, label_extra_instance => 1, instance_use => 'display_absolute' }, + ], + } + }; + push @{$self->{maps_counters}->{metric}}, $entry; + } + } +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $self->{version} = '1.0'; + $options{options}->add_options(arguments => + { + "name:s@" => { name => 'name' }, + "node-id:s" => { name => 'node_id' }, + "filter-metric:s" => { name => 'filter_metric' }, + "per-sec" => { name => 'per_sec' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + if (!defined($self->{option_results}->{name}) || $self->{option_results}->{name} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --name option."); + $self->{output}->option_exit(); + } + + foreach my $instance (@{$self->{option_results}->{name}}) { + if ($instance ne '') { + push @{$self->{aws_instance}}, $instance; + } + } + + $self->{aws_timeframe} = defined($self->{option_results}->{timeframe}) ? $self->{option_results}->{timeframe} : 600; + $self->{aws_period} = defined($self->{option_results}->{period}) ? $self->{option_results}->{period} : 60; + + $self->{aws_statistics} = ['Average']; + if (defined($self->{option_results}->{statistic})) { + $self->{aws_statistics} = []; + foreach my $stat (@{$self->{option_results}->{statistic}}) { + if ($stat ne '') { + push @{$self->{aws_statistics}}, ucfirst(lc($stat)); + } + } + } + + foreach my $metric ('ReplicationBytes', 'ReplicationLag') { + next if (defined($self->{option_results}->{filter_metric}) && $self->{option_results}->{filter_metric} ne '' + && $metric !~ /$self->{option_results}->{filter_metric}/); + + push @{$self->{aws_metrics}}, $metric; + } + + $instance_mode = $self; +} + +sub manage_selection { + my ($self, %options) = @_; + + my %metric_results; + foreach my $instance (@{$self->{aws_instance}}) { + push @{$self->{aws_dimensions}}, { Name => 'CacheClusterId', Value => $instance }; + if (defined($self->{option_results}->{node_id}) && $self->{option_results}->{node_id} ne '') { + push @{$self->{aws_dimensions}}, { Name => 'CacheNodeId', Value => $self->{option_results}->{node_id} }; + } + $metric_results{$instance} = $options{custom}->cloudwatch_get_metrics( + region => $self->{option_results}->{region}, + namespace => 'AWS/ElastiCache', + dimensions => $self->{aws_dimensions}, + 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($metric_results{$instance}->{$metric}->{lc($statistic)}) && !defined($self->{option_results}->{zeroed})); + + $self->{metric}->{$instance . "_" . lc($statistic)}->{display} = $instance; + $self->{metric}->{$instance . "_" . lc($statistic)}->{stat} = lc($statistic); + $self->{metric}->{$instance . "_" . lc($statistic)}->{node_id} = $self->{option_results}->{node_id}; + $self->{metric}->{$instance . "_" . lc($statistic)}->{timeframe} = $self->{aws_timeframe}; + $self->{metric}->{$instance . "_" . lc($statistic)}->{$metric . "_" . lc($statistic)} = defined($metric_results{$instance}->{$metric}->{lc($statistic)}) ? $metric_results{$instance}->{$metric}->{lc($statistic)} : 0; + } + } + } + + if (scalar(keys %{$self->{metric}}) <= 0) { + $self->{output}->add_option_msg(short_msg => 'No metrics. Check your options or use --zeroed option to set 0 on undefined values'); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check ElastiCache cluster replication performances (throughput and lag). + +Works with Redis backends only. + +Example: +perl centreon_plugins.pl --plugin=cloud::aws::elasticache::plugin --custommode=paws --mode=replication +--region='eu-west-1' --name='centreon-front' --statistic='average' --critical-replicationlag-average='2' --verbose + +See 'https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/elasticache-metricscollected.html' for more informations. + +Default statistic: 'average' / All satistics are valid. + +=over 8 + +=item B<--name> + +Set the cluster name (Required) (Can be multiple). + +=item B<--node-id> + +Set the node id (Optional). + +=item B<--filter-metric> + +Filter metrics (Can be: 'ReplicationBytes', 'ReplicationLag') +(Can be a regexp). + +=item B<--warning-$metric$-$statistic$> + +Thresholds warning ($metric$ can be: 'replicationbytes', 'replicationlag', +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=item B<--critical-$metric$-$statistic$> + +Thresholds critical ($metric$ can be: 'replicationbytes', 'replicationlag', +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=item B<--per-sec> + +Change the data to be unit/sec. + +=back + +=cut diff --git a/cloud/aws/elasticache/mode/requestsmemcached.pm b/cloud/aws/elasticache/mode/requestsmemcached.pm new file mode 100644 index 000000000..4e2f7663f --- /dev/null +++ b/cloud/aws/elasticache/mode/requestsmemcached.pm @@ -0,0 +1,256 @@ +# +# Copyright 2018 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::elasticache::mode::requestsmemcached; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +my $instance_mode; + +sub prefix_metric_output { + my ($self, %options) = @_; + + my $node_id = ""; + if (defined($options{instance_value}->{node_id}) && $options{instance_value}->{node_id} ne '') { + $node_id = "[Node: $options{instance_value}->{node_id}] "; + } + + return "Cluster '" . $options{instance_value}->{display} . "' " . $node_id . $options{instance_value}->{stat} . " requests "; +} + +sub custom_metric_calc { + my ($self, %options) = @_; + + $self->{result_values}->{timeframe} = $options{new_datas}->{$self->{instance} . '_timeframe'}; + $self->{result_values}->{value} = $options{new_datas}->{$self->{instance} . '_' . $options{extra_options}->{metric} . '_' . $options{extra_options}->{stat}}; + $self->{result_values}->{value_per_sec} = $self->{result_values}->{value} / $self->{result_values}->{timeframe}; + $self->{result_values}->{stat} = $options{extra_options}->{stat}; + $self->{result_values}->{metric} = $options{extra_options}->{metric}; + $self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_display'}; + return 0; +} + +sub custom_metric_threshold { + my ($self, %options) = @_; + + my $exit = $self->{perfdata}->threshold_check(value => defined($instance_mode->{option_results}->{per_sec}) ? $self->{result_values}->{value_per_sec} : $self->{result_values}->{value}, + threshold => [ { label => 'critical-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat}), exit_litteral => 'critical' }, + { label => 'warning-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat}), exit_litteral => 'warning' } ]); + return $exit; +} + +sub custom_metric_perfdata { + my ($self, %options) = @_; + + my $extra_label = ''; + $extra_label = '_' . lc($self->{result_values}->{display}) if (!defined($options{extra_instance}) || $options{extra_instance} != 0); + + $self->{output}->perfdata_add(label => lc($self->{result_values}->{metric}) . "_" . lc($self->{result_values}->{stat}) . $extra_label, + unit => defined($instance_mode->{option_results}->{per_sec}) ? 'req/s' : 'req', + value => sprintf("%.2f", defined($instance_mode->{option_results}->{per_sec}) ? $self->{result_values}->{value_per_sec} : $self->{result_values}->{value}), + warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat})), + critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat})), + ); +} + +sub custom_metric_output { + my ($self, %options) = @_; + my $msg = ""; + + if (defined($instance_mode->{option_results}->{per_sec})) { + $msg = sprintf("%s: %.2f requests/s", $self->{result_values}->{metric}, $self->{result_values}->{value_per_sec}); + } else { + $msg = sprintf("%s: %.2f requests", $self->{result_values}->{metric}, $self->{result_values}->{value}); + } + return $msg; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'metric', type => 1, cb_prefix_output => 'prefix_metric_output', message_multiple => "All requests metrics are ok", skipped_code => { -10 => 1 } }, + ]; + + foreach my $statistic ('minimum', 'maximum', 'average', 'sum') { + foreach my $metric ('CasHits', 'CasMisses', 'DecrHits', 'DecrMisses', 'DeleteHits', 'DeleteMisses', 'GetHits', + 'GetMisses', 'IncrHits', 'IncrMisses', 'TouchHits', 'TouchMisses') { + my $entry = { label => lc($metric) . '-' . lc($statistic), set => { + key_values => [ { name => $metric . '_' . $statistic }, { name => 'display' }, { name => 'stat' }, { name => 'timeframe' } ], + closure_custom_calc => $self->can('custom_metric_calc'), + closure_custom_calc_extra_options => { metric => $metric, stat => $statistic }, + closure_custom_output => $self->can('custom_metric_output'), + closure_custom_perfdata => $self->can('custom_metric_perfdata'), + closure_custom_threshold_check => $self->can('custom_metric_threshold'), + } + }; + push @{$self->{maps_counters}->{metric}}, $entry; + } + } +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $self->{version} = '1.0'; + $options{options}->add_options(arguments => + { + "name:s@" => { name => 'name' }, + "node-id:s" => { name => 'node_id' }, + "filter-metric:s" => { name => 'filter_metric' }, + "per-sec" => { name => 'per_sec' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + if (!defined($self->{option_results}->{name}) || $self->{option_results}->{name} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --name option."); + $self->{output}->option_exit(); + } + + foreach my $instance (@{$self->{option_results}->{name}}) { + if ($instance ne '') { + push @{$self->{aws_instance}}, $instance; + } + } + + $self->{aws_timeframe} = defined($self->{option_results}->{timeframe}) ? $self->{option_results}->{timeframe} : 600; + $self->{aws_period} = defined($self->{option_results}->{period}) ? $self->{option_results}->{period} : 60; + + $self->{aws_statistics} = ['Average']; + if (defined($self->{option_results}->{statistic})) { + $self->{aws_statistics} = []; + foreach my $stat (@{$self->{option_results}->{statistic}}) { + if ($stat ne '') { + push @{$self->{aws_statistics}}, ucfirst(lc($stat)); + } + } + } + + foreach my $metric ('CasHits', 'CasMisses', 'DecrHits', 'DecrMisses', 'DeleteHits', 'DeleteMisses', + 'GetHits', 'GetMisses', 'IncrHits', 'IncrMisses', 'TouchHits', 'TouchMisses') { + next if (defined($self->{option_results}->{filter_metric}) && $self->{option_results}->{filter_metric} ne '' + && $metric !~ /$self->{option_results}->{filter_metric}/); + + push @{$self->{aws_metrics}}, $metric; + } + + $instance_mode = $self; +} + +sub manage_selection { + my ($self, %options) = @_; + + my %metric_results; + foreach my $instance (@{$self->{aws_instance}}) { + push @{$self->{aws_dimensions}}, { Name => 'CacheClusterId', Value => $instance }; + if (defined($self->{option_results}->{node_id}) && $self->{option_results}->{node_id} ne '') { + push @{$self->{aws_dimensions}}, { Name => 'CacheNodeId', Value => $self->{option_results}->{node_id} }; + } + $metric_results{$instance} = $options{custom}->cloudwatch_get_metrics( + region => $self->{option_results}->{region}, + namespace => 'AWS/ElastiCache', + dimensions => $self->{aws_dimensions}, + 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($metric_results{$instance}->{$metric}->{lc($statistic)}) && !defined($self->{option_results}->{zeroed})); + + $self->{metric}->{$instance . "_" . lc($statistic)}->{display} = $instance; + $self->{metric}->{$instance . "_" . lc($statistic)}->{stat} = lc($statistic); + $self->{metric}->{$instance . "_" . lc($statistic)}->{node_id} = $self->{option_results}->{node_id}; + $self->{metric}->{$instance . "_" . lc($statistic)}->{timeframe} = $self->{aws_timeframe}; + $self->{metric}->{$instance . "_" . lc($statistic)}->{$metric . "_" . lc($statistic)} = defined($metric_results{$instance}->{$metric}->{lc($statistic)}) ? $metric_results{$instance}->{$metric}->{lc($statistic)} : 0; + } + } + } + + if (scalar(keys %{$self->{metric}}) <= 0) { + $self->{output}->add_option_msg(short_msg => 'No metrics. Check your options or use --zeroed option to set 0 on undefined values'); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check ElastiCache cluster received requests for Memcached backends (found and not found keys). + +Example: +perl centreon_plugins.pl --plugin=cloud::aws::elasticache::plugin --custommode=paws --mode=requests-memcached +--region='eu-west-1' --name='centreon-front' --statistic='average' --critical-getmisses-average='5' --verbose + +See 'https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/elasticache-metricscollected.html' for more informations. + +Default statistic: 'average' / All satistics are valid. + +=over 8 + +=item B<--name> + +Set the cluster name (Required) (Can be multiple). + +=item B<--node-id> + +Set the node id (Optional). + +=item B<--filter-metric> + +Filter metrics (Can be: 'CasHits', 'CasMisses', 'DecrHits', 'DecrMisses', 'DeleteHits', 'DeleteMisses', +'GetHits', 'GetMisses', 'IncrHits', 'IncrMisses', 'TouchHits', 'TouchMisses') +(Can be a regexp). + +=item B<--warning-$metric$-$statistic$> + +Thresholds warning ($metric$ can be: 'cashits', 'casmisses', 'decrhits', 'decrmisses', +'deletehits', 'deletemisses', 'gethits', 'getmisses', 'incrhits', 'incrmisses', 'touchhits', 'touchmisses', +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=item B<--critical-$metric$-$statistic$> + +Thresholds critical ($metric$ can be: 'cashits', 'casmisses', 'decrhits', 'decrmisses', +'deletehits', 'deletemisses', 'gethits', 'getmisses', 'incrhits', 'incrmisses', 'touchhits', 'touchmisses', +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=item B<--per-sec> + +Change the data to be unit/sec. + +=back + +=cut diff --git a/cloud/aws/elasticache/mode/requestsredis.pm b/cloud/aws/elasticache/mode/requestsredis.pm new file mode 100644 index 000000000..b70d1c467 --- /dev/null +++ b/cloud/aws/elasticache/mode/requestsredis.pm @@ -0,0 +1,251 @@ +# +# Copyright 2018 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::elasticache::mode::requestsredis; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +my $instance_mode; + +sub prefix_metric_output { + my ($self, %options) = @_; + + my $node_id = ""; + if (defined($options{instance_value}->{node_id}) && $options{instance_value}->{node_id} ne '') { + $node_id = "[Node: $options{instance_value}->{node_id}] "; + } + + return "Cluster '" . $options{instance_value}->{display} . "' " . $node_id . $options{instance_value}->{stat} . " requests "; +} + +sub custom_metric_calc { + my ($self, %options) = @_; + + $self->{result_values}->{timeframe} = $options{new_datas}->{$self->{instance} . '_timeframe'}; + $self->{result_values}->{value} = $options{new_datas}->{$self->{instance} . '_' . $options{extra_options}->{metric} . '_' . $options{extra_options}->{stat}}; + $self->{result_values}->{value_per_sec} = $self->{result_values}->{value} / $self->{result_values}->{timeframe}; + $self->{result_values}->{stat} = $options{extra_options}->{stat}; + $self->{result_values}->{metric} = $options{extra_options}->{metric}; + $self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_display'}; + return 0; +} + +sub custom_metric_threshold { + my ($self, %options) = @_; + + my $exit = $self->{perfdata}->threshold_check(value => defined($instance_mode->{option_results}->{per_sec}) ? $self->{result_values}->{value_per_sec} : $self->{result_values}->{value}, + threshold => [ { label => 'critical-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat}), exit_litteral => 'critical' }, + { label => 'warning-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat}), exit_litteral => 'warning' } ]); + return $exit; +} + +sub custom_metric_perfdata { + my ($self, %options) = @_; + + my $extra_label = ''; + $extra_label = '_' . lc($self->{result_values}->{display}) if (!defined($options{extra_instance}) || $options{extra_instance} != 0); + + $self->{output}->perfdata_add(label => lc($self->{result_values}->{metric}) . "_" . lc($self->{result_values}->{stat}) . $extra_label, + unit => defined($instance_mode->{option_results}->{per_sec}) ? 'req/s' : 'req', + value => sprintf("%.2f", defined($instance_mode->{option_results}->{per_sec}) ? $self->{result_values}->{value_per_sec} : $self->{result_values}->{value}), + warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat})), + critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat})), + ); +} + +sub custom_metric_output { + my ($self, %options) = @_; + my $msg = ""; + + if (defined($instance_mode->{option_results}->{per_sec})) { + $msg = sprintf("%s: %.2f requests/s", $self->{result_values}->{metric}, $self->{result_values}->{value_per_sec}); + } else { + $msg = sprintf("%s: %.2f requests", $self->{result_values}->{metric}, $self->{result_values}->{value}); + } + return $msg; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'metric', type => 1, cb_prefix_output => 'prefix_metric_output', message_multiple => "All requests metrics are ok", skipped_code => { -10 => 1 } }, + ]; + + foreach my $statistic ('minimum', 'maximum', 'average', 'sum') { + foreach my $metric ('CacheHits', 'CacheMisses') { + my $entry = { label => lc($metric) . '-' . lc($statistic), set => { + key_values => [ { name => $metric . '_' . $statistic }, { name => 'display' }, { name => 'stat' }, { name => 'timeframe' } ], + closure_custom_calc => $self->can('custom_metric_calc'), + closure_custom_calc_extra_options => { metric => $metric, stat => $statistic }, + closure_custom_output => $self->can('custom_metric_output'), + closure_custom_perfdata => $self->can('custom_metric_perfdata'), + closure_custom_threshold_check => $self->can('custom_metric_threshold'), + } + }; + push @{$self->{maps_counters}->{metric}}, $entry; + } + } +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $self->{version} = '1.0'; + $options{options}->add_options(arguments => + { + "name:s@" => { name => 'name' }, + "node-id:s" => { name => 'node_id' }, + "filter-metric:s" => { name => 'filter_metric' }, + "per-sec" => { name => 'per_sec' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + if (!defined($self->{option_results}->{name}) || $self->{option_results}->{name} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --name option."); + $self->{output}->option_exit(); + } + + foreach my $instance (@{$self->{option_results}->{name}}) { + if ($instance ne '') { + push @{$self->{aws_instance}}, $instance; + } + } + + $self->{aws_timeframe} = defined($self->{option_results}->{timeframe}) ? $self->{option_results}->{timeframe} : 600; + $self->{aws_period} = defined($self->{option_results}->{period}) ? $self->{option_results}->{period} : 60; + + $self->{aws_statistics} = ['Average']; + if (defined($self->{option_results}->{statistic})) { + $self->{aws_statistics} = []; + foreach my $stat (@{$self->{option_results}->{statistic}}) { + if ($stat ne '') { + push @{$self->{aws_statistics}}, ucfirst(lc($stat)); + } + } + } + + foreach my $metric ('CacheHits', 'CacheMisses') { + next if (defined($self->{option_results}->{filter_metric}) && $self->{option_results}->{filter_metric} ne '' + && $metric !~ /$self->{option_results}->{filter_metric}/); + + push @{$self->{aws_metrics}}, $metric; + } + + $instance_mode = $self; +} + +sub manage_selection { + my ($self, %options) = @_; + + my %metric_results; + foreach my $instance (@{$self->{aws_instance}}) { + push @{$self->{aws_dimensions}}, { Name => 'CacheClusterId', Value => $instance }; + if (defined($self->{option_results}->{node_id}) && $self->{option_results}->{node_id} ne '') { + push @{$self->{aws_dimensions}}, { Name => 'CacheNodeId', Value => $self->{option_results}->{node_id} }; + } + $metric_results{$instance} = $options{custom}->cloudwatch_get_metrics( + region => $self->{option_results}->{region}, + namespace => 'AWS/ElastiCache', + dimensions => $self->{aws_dimensions}, + 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($metric_results{$instance}->{$metric}->{lc($statistic)}) && !defined($self->{option_results}->{zeroed})); + + $self->{metric}->{$instance . "_" . lc($statistic)}->{display} = $instance; + $self->{metric}->{$instance . "_" . lc($statistic)}->{stat} = lc($statistic); + $self->{metric}->{$instance . "_" . lc($statistic)}->{node_id} = $self->{option_results}->{node_id}; + $self->{metric}->{$instance . "_" . lc($statistic)}->{timeframe} = $self->{aws_timeframe}; + $self->{metric}->{$instance . "_" . lc($statistic)}->{$metric . "_" . lc($statistic)} = defined($metric_results{$instance}->{$metric}->{lc($statistic)}) ? $metric_results{$instance}->{$metric}->{lc($statistic)} : 0; + } + } + } + + if (scalar(keys %{$self->{metric}}) <= 0) { + $self->{output}->add_option_msg(short_msg => 'No metrics. Check your options or use --zeroed option to set 0 on undefined values'); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check ElastiCache cluster received requests for Redis backends (successfull and unsuccessful key lookups). + +Example: +perl centreon_plugins.pl --plugin=cloud::aws::elasticache::plugin --custommode=paws --mode=requests-redis +--region='eu-west-1' --name='centreon-front' --statistic='average' --critical-cachemisses-average='5' --verbose + +See 'https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/elasticache-metricscollected.html' for more informations. + +Default statistic: 'average' / All satistics are valid. + +=over 8 + +=item B<--name> + +Set the cluster name (Required) (Can be multiple). + +=item B<--node-id> + +Set the node id (Optional). + +=item B<--filter-metric> + +Filter metrics (Can be: 'CacheHits', 'CacheMisses') +(Can be a regexp). + +=item B<--warning-$metric$-$statistic$> + +Thresholds warning ($metric$ can be: 'cachehits', 'cachemisses', +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=item B<--critical-$metric$-$statistic$> + +Thresholds critical ($metric$ can be: 'cachehits', 'cachemisses', +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=item B<--per-sec> + +Change the data to be unit/sec. + +=back + +=cut diff --git a/cloud/aws/elasticache/mode/usagememcached.pm b/cloud/aws/elasticache/mode/usagememcached.pm new file mode 100644 index 000000000..ab85e21f2 --- /dev/null +++ b/cloud/aws/elasticache/mode/usagememcached.pm @@ -0,0 +1,190 @@ +# +# Copyright 2018 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::elasticache::mode::usagememcached; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +sub prefix_metric_output { + my ($self, %options) = @_; + + my $node_id = ""; + if (defined($options{instance_value}->{node_id}) && $options{instance_value}->{node_id} ne '') { + $node_id = "[Node: $options{instance_value}->{node_id}] "; + } + + return "Cluster '" . $options{instance_value}->{display} . "' " . $node_id . $options{instance_value}->{stat} . " "; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'metric', type => 1, cb_prefix_output => 'prefix_metric_output', message_multiple => "All usage metrics are ok", skipped_code => { -10 => 1 } }, + ]; + + foreach my $statistic ('minimum', 'maximum', 'average', 'sum') { + foreach my $metric ('BytesUsedForCacheItems') { + my $entry = { label => lc($metric) . '-' . lc($statistic), set => { + key_values => [ { name => $metric . '_' . $statistic }, { name => 'display' }, { name => 'stat' } ], + output_template => $metric . ': %d %s', + output_change_bytes => 1, + perfdatas => [ + { label => lc($metric) . '_' . lc($statistic), value => $metric . '_' . $statistic . '_absolute', + template => '%d', unit => 'B', min => 0, label_extra_instance => 1, instance_use => 'display_absolute' }, + ], + } + }; + push @{$self->{maps_counters}->{metric}}, $entry; + } + } +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $self->{version} = '1.0'; + $options{options}->add_options(arguments => + { + "name:s@" => { name => 'name' }, + "node-id:s" => { name => 'node_id' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + if (!defined($self->{option_results}->{name}) || $self->{option_results}->{name} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --name option."); + $self->{output}->option_exit(); + } + + foreach my $instance (@{$self->{option_results}->{name}}) { + if ($instance ne '') { + push @{$self->{aws_instance}}, $instance; + } + } + + $self->{aws_timeframe} = defined($self->{option_results}->{timeframe}) ? $self->{option_results}->{timeframe} : 600; + $self->{aws_period} = defined($self->{option_results}->{period}) ? $self->{option_results}->{period} : 60; + + $self->{aws_statistics} = ['Average']; + if (defined($self->{option_results}->{statistic})) { + $self->{aws_statistics} = []; + foreach my $stat (@{$self->{option_results}->{statistic}}) { + if ($stat ne '') { + push @{$self->{aws_statistics}}, ucfirst(lc($stat)); + } + } + } + + foreach my $metric ('BytesUsedForCacheItems') { + next if (defined($self->{option_results}->{filter_metric}) && $self->{option_results}->{filter_metric} ne '' + && $metric !~ /$self->{option_results}->{filter_metric}/); + + push @{$self->{aws_metrics}}, $metric; + } +} + +sub manage_selection { + my ($self, %options) = @_; + + my %metric_results; + foreach my $instance (@{$self->{aws_instance}}) { + push @{$self->{aws_dimensions}}, { Name => 'CacheClusterId', Value => $instance }; + if (defined($self->{option_results}->{node_id}) && $self->{option_results}->{node_id} ne '') { + push @{$self->{aws_dimensions}}, { Name => 'CacheNodeId', Value => $self->{option_results}->{node_id} }; + } + $metric_results{$instance} = $options{custom}->cloudwatch_get_metrics( + region => $self->{option_results}->{region}, + namespace => 'AWS/ElastiCache', + dimensions => $self->{aws_dimensions}, + 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($metric_results{$instance}->{$metric}->{lc($statistic)}) && !defined($self->{option_results}->{zeroed})); + + $self->{metric}->{$instance . "_" . lc($statistic)}->{display} = $instance; + $self->{metric}->{$instance . "_" . lc($statistic)}->{stat} = lc($statistic); + $self->{metric}->{$instance . "_" . lc($statistic)}->{node_id} = $self->{option_results}->{node_id}; + $self->{metric}->{$instance . "_" . lc($statistic)}->{$metric . "_" . lc($statistic)} = defined($metric_results{$instance}->{$metric}->{lc($statistic)}) ? $metric_results{$instance}->{$metric}->{lc($statistic)} : 0; + } + } + } + + if (scalar(keys %{$self->{metric}}) <= 0) { + $self->{output}->add_option_msg(short_msg => 'No metrics. Check your options or use --zeroed option to set 0 on undefined values'); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check ElastiCache cluster space usage for Memcached backends. + +Example: +perl centreon_plugins.pl --plugin=cloud::aws::elasticache::plugin --custommode=paws --mode=usage-memcached +--region='eu-west-1' --name='centreon-front' --statistic='average' --critical-bytesusedforcacheitems-average='1614281' +--verbose + +See 'https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/elasticache-metricscollected.html' for more informations. + +Default statistic: 'average' / All satistics are valid. + +=over 8 + +=item B<--name> + +Set the cluster name (Required) (Can be multiple). + +=item B<--node-id> + +Set the node id (Optional). + +=item B<--warning-$metric$-$statistic$> + +Thresholds warning ($metric$ can be: 'bytesusedforcacheitems', +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=item B<--critical-$metric$-$statistic$> + +Thresholds critical ($metric$ can be: 'bytesusedforcacheitems', +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=back + +=cut diff --git a/cloud/aws/elasticache/mode/usageredis.pm b/cloud/aws/elasticache/mode/usageredis.pm new file mode 100644 index 000000000..8d87cd24c --- /dev/null +++ b/cloud/aws/elasticache/mode/usageredis.pm @@ -0,0 +1,190 @@ +# +# Copyright 2018 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::elasticache::mode::usageredis; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +sub prefix_metric_output { + my ($self, %options) = @_; + + my $node_id = ""; + if (defined($options{instance_value}->{node_id}) && $options{instance_value}->{node_id} ne '') { + $node_id = "[Node: $options{instance_value}->{node_id}] "; + } + + return "Cluster '" . $options{instance_value}->{display} . "' " . $node_id . $options{instance_value}->{stat} . " "; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'metric', type => 1, cb_prefix_output => 'prefix_metric_output', message_multiple => "All usage metrics are ok", skipped_code => { -10 => 1 } }, + ]; + + foreach my $statistic ('minimum', 'maximum', 'average', 'sum') { + foreach my $metric ('BytesUsedForCache') { + my $entry = { label => lc($metric) . '-' . lc($statistic), set => { + key_values => [ { name => $metric . '_' . $statistic }, { name => 'display' }, { name => 'stat' } ], + output_template => $metric . ': %d %s', + output_change_bytes => 1, + perfdatas => [ + { label => lc($metric) . '_' . lc($statistic), value => $metric . '_' . $statistic . '_absolute', + template => '%d', unit => 'B', min => 0, label_extra_instance => 1, instance_use => 'display_absolute' }, + ], + } + }; + push @{$self->{maps_counters}->{metric}}, $entry; + } + } +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $self->{version} = '1.0'; + $options{options}->add_options(arguments => + { + "name:s@" => { name => 'name' }, + "node-id:s" => { name => 'node_id' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + if (!defined($self->{option_results}->{name}) || $self->{option_results}->{name} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --name option."); + $self->{output}->option_exit(); + } + + foreach my $instance (@{$self->{option_results}->{name}}) { + if ($instance ne '') { + push @{$self->{aws_instance}}, $instance; + } + } + + $self->{aws_timeframe} = defined($self->{option_results}->{timeframe}) ? $self->{option_results}->{timeframe} : 600; + $self->{aws_period} = defined($self->{option_results}->{period}) ? $self->{option_results}->{period} : 60; + + $self->{aws_statistics} = ['Average']; + if (defined($self->{option_results}->{statistic})) { + $self->{aws_statistics} = []; + foreach my $stat (@{$self->{option_results}->{statistic}}) { + if ($stat ne '') { + push @{$self->{aws_statistics}}, ucfirst(lc($stat)); + } + } + } + + foreach my $metric ('BytesUsedForCache') { + next if (defined($self->{option_results}->{filter_metric}) && $self->{option_results}->{filter_metric} ne '' + && $metric !~ /$self->{option_results}->{filter_metric}/); + + push @{$self->{aws_metrics}}, $metric; + } +} + +sub manage_selection { + my ($self, %options) = @_; + + my %metric_results; + foreach my $instance (@{$self->{aws_instance}}) { + push @{$self->{aws_dimensions}}, { Name => 'CacheClusterId', Value => $instance }; + if (defined($self->{option_results}->{node_id}) && $self->{option_results}->{node_id} ne '') { + push @{$self->{aws_dimensions}}, { Name => 'CacheNodeId', Value => $self->{option_results}->{node_id} }; + } + $metric_results{$instance} = $options{custom}->cloudwatch_get_metrics( + region => $self->{option_results}->{region}, + namespace => 'AWS/ElastiCache', + dimensions => $self->{aws_dimensions}, + 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($metric_results{$instance}->{$metric}->{lc($statistic)}) && !defined($self->{option_results}->{zeroed})); + + $self->{metric}->{$instance . "_" . lc($statistic)}->{display} = $instance; + $self->{metric}->{$instance . "_" . lc($statistic)}->{stat} = lc($statistic); + $self->{metric}->{$instance . "_" . lc($statistic)}->{node_id} = $self->{option_results}->{node_id}; + $self->{metric}->{$instance . "_" . lc($statistic)}->{$metric . "_" . lc($statistic)} = defined($metric_results{$instance}->{$metric}->{lc($statistic)}) ? $metric_results{$instance}->{$metric}->{lc($statistic)} : 0; + } + } + } + + if (scalar(keys %{$self->{metric}}) <= 0) { + $self->{output}->add_option_msg(short_msg => 'No metrics. Check your options or use --zeroed option to set 0 on undefined values'); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check ElastiCache cluster space usage for Redis backends. + +Example: +perl centreon_plugins.pl --plugin=cloud::aws::elasticache::plugin --custommode=paws --mode=usage-redis +--region='eu-west-1' --name='centreon-front' --statistic='average' --critical-bytesusedforcache-average='1614281' +--verbose + +See 'https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/elasticache-metricscollected.html' for more informations. + +Default statistic: 'average' / All satistics are valid. + +=over 8 + +=item B<--name> + +Set the cluster name (Required) (Can be multiple). + +=item B<--node-id> + +Set the node id (Optional). + +=item B<--warning-$metric$-$statistic$> + +Thresholds warning ($metric$ can be: 'bytesusedforcache', +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=item B<--critical-$metric$-$statistic$> + +Thresholds critical ($metric$ can be: 'bytesusedforcache', +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=back + +=cut diff --git a/cloud/aws/elasticache/plugin.pm b/cloud/aws/elasticache/plugin.pm new file mode 100644 index 000000000..e02c18997 --- /dev/null +++ b/cloud/aws/elasticache/plugin.pm @@ -0,0 +1,61 @@ +# +# Copyright 2018 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::elasticache::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} } = ( + 'commands-memcached' => 'cloud::aws::elasticache::mode::commandsmemcached', + 'commands-redis' => 'cloud::aws::elasticache::mode::commandsredis', + 'connections' => 'cloud::aws::elasticache::mode::connections', + 'cpu' => 'cloud::aws::elasticache::mode::cpu', + 'evictions' => 'cloud::aws::elasticache::mode::evictions', + 'items' => 'cloud::aws::elasticache::mode::items', + 'network' => 'cloud::aws::elasticache::mode::network', + 'replication' => 'cloud::aws::elasticache::mode::replication', + 'requests-memcached' => 'cloud::aws::elasticache::mode::requestsmemcached', + 'requests-redis' => 'cloud::aws::elasticache::mode::requestsredis', + 'usage-memcached' => 'cloud::aws::elasticache::mode::usagememcached', + 'usage-redis' => 'cloud::aws::elasticache::mode::usageredis', + ); + + $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 ElastiCache. + +=cut diff --git a/cloud/aws/elb/mode/httpcodes.pm b/cloud/aws/elb/mode/httpcodes.pm new file mode 100644 index 000000000..0193a63e6 --- /dev/null +++ b/cloud/aws/elb/mode/httpcodes.pm @@ -0,0 +1,239 @@ +# +# Copyright 2018 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::elb::mode::httpcodes; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +my %map_type = ( + "loadbalancer" => "LoadBalancerName", + "availabilityzone" => "AvailabilityZone", +); + +sub prefix_metric_output { + my ($self, %options) = @_; + + my $availability_zone = ""; + if (defined($options{instance_value}->{availability_zone}) && $options{instance_value}->{availability_zone} ne '') { + $availability_zone = "[$options{instance_value}->{availability_zone}] "; + } + + return ucfirst($options{instance_value}->{type}) . " '" . $options{instance_value}->{display} . "' " . $availability_zone . $options{instance_value}->{stat} . " "; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'metric', type => 1, cb_prefix_output => 'prefix_metric_output', message_multiple => "All http codes metrics are ok", skipped_code => { -10 => 1 } }, + ]; + + foreach my $statistic ('minimum', 'maximum', 'average', 'sum') { + foreach my $metric ('HTTPCode_Backend_2XX', 'HTTPCode_Backend_3XX', 'HTTPCode_Backend_4XX', 'HTTPCode_Backend_5XX', 'HTTPCode_ELB_4XX', 'HTTPCode_ELB_5XX') { + next if ($statistic =~ /minimum|maximum|average/); # Minimum, Maximum, and Average all return 1. + my $entry = { label => lc($metric) . '-' . lc($statistic), set => { + key_values => [ { name => $metric . '_' . $statistic }, { name => 'display' }, { name => 'type' }, { name => 'stat' } ], + output_template => $metric . ': %d', + perfdatas => [ + { label => lc($metric) . '_' . lc($statistic), value => $metric . '_' . $statistic . '_absolute', + template => '%d', label_extra_instance => 1, instance_use => 'display_absolute' }, + ], + } + }; + push @{$self->{maps_counters}->{metric}}, $entry; + } + foreach my $metric ('BackendConnectionErrors') { + my $entry = { label => lc($metric) . '-' . lc($statistic), set => { + key_values => [ { name => $metric . '_' . $statistic }, { name => 'display' }, { name => 'type' }, { name => 'stat' } ], + output_template => $metric . ': %d', + perfdatas => [ + { label => lc($metric) . '_' . lc($statistic), value => $metric . '_' . $statistic . '_absolute', + template => '%d', label_extra_instance => 1, instance_use => 'display_absolute' }, + ], + } + }; + push @{$self->{maps_counters}->{metric}}, $entry; + } + } +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $self->{version} = '1.0'; + $options{options}->add_options(arguments => + { + "type:s" => { name => 'type' }, + "name:s@" => { name => 'name' }, + "availability-zone:s" => { name => 'availability_zone' }, + "filter-metric:s" => { name => 'filter_metric' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + if (!defined($self->{option_results}->{type}) || $self->{option_results}->{type} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --type option."); + $self->{output}->option_exit(); + } + + if ($self->{option_results}->{type} ne 'loadbalancer' && $self->{option_results}->{type} ne 'availabilityzone') { + $self->{output}->add_option_msg(short_msg => "Instance type '" . $self->{option_results}->{type} . "' is not handled for this mode"); + $self->{output}->option_exit(); + } + + if ($self->{option_results}->{type} eq 'availabilityzone' && defined($self->{option_results}->{availability_zone})) { + $self->{output}->add_option_msg(short_msg => "Can't specify --availability-zone option with availabilityzone instance's type"); + $self->{output}->option_exit(); + } + + if (!defined($self->{option_results}->{name}) || $self->{option_results}->{name} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --name option."); + $self->{output}->option_exit(); + } + + foreach my $instance (@{$self->{option_results}->{name}}) { + if ($instance ne '') { + push @{$self->{aws_instance}}, $instance; + } + } + + $self->{aws_timeframe} = defined($self->{option_results}->{timeframe}) ? $self->{option_results}->{timeframe} : 600; + $self->{aws_period} = defined($self->{option_results}->{period}) ? $self->{option_results}->{period} : 60; + + $self->{aws_statistics} = ['Sum']; + if (defined($self->{option_results}->{statistic})) { + $self->{aws_statistics} = []; + foreach my $stat (@{$self->{option_results}->{statistic}}) { + if ($stat ne '') { + push @{$self->{aws_statistics}}, ucfirst(lc($stat)); + } + } + } + + foreach my $metric ('HTTPCode_Backend_2XX', 'HTTPCode_Backend_3XX', 'HTTPCode_Backend_4XX', 'HTTPCode_Backend_5XX', + 'HTTPCode_ELB_4XX', 'HTTPCode_ELB_5XX', 'BackendConnectionErrors') { + next if (defined($self->{option_results}->{filter_metric}) && $self->{option_results}->{filter_metric} ne '' + && $metric !~ /$self->{option_results}->{filter_metric}/); + + push @{$self->{aws_metrics}}, $metric; + } +} + +sub manage_selection { + my ($self, %options) = @_; + + my %metric_results; + foreach my $instance (@{$self->{aws_instance}}) { + push @{$self->{aws_dimensions}}, { Name => $map_type{$self->{option_results}->{type}}, Value => $instance }; + if (defined($self->{option_results}->{availability_zone}) && $self->{option_results}->{availability_zone} ne '') { + push @{$self->{aws_dimensions}}, { Name => 'AvailabilityZone', Value => $self->{option_results}->{availability_zone} }; + } + $metric_results{$instance} = $options{custom}->cloudwatch_get_metrics( + region => $self->{option_results}->{region}, + namespace => 'AWS/ELB', + dimensions => $self->{aws_dimensions}, + 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($metric_results{$instance}->{$metric}->{lc($statistic)}) && !defined($self->{option_results}->{zeroed})); + + $self->{metric}->{$instance . "_" . lc($statistic)}->{display} = $instance; + $self->{metric}->{$instance . "_" . lc($statistic)}->{type} = $self->{option_results}->{type}; + $self->{metric}->{$instance . "_" . lc($statistic)}->{stat} = lc($statistic); + $self->{metric}->{$instance . "_" . lc($statistic)}->{availability_zone} = $self->{option_results}->{availability_zone}; + $self->{metric}->{$instance . "_" . lc($statistic)}->{$metric . "_" . lc($statistic)} = defined($metric_results{$instance}->{$metric}->{lc($statistic)}) ? $metric_results{$instance}->{$metric}->{lc($statistic)} : 0; + } + } + } + + if (scalar(keys %{$self->{metric}}) <= 0) { + $self->{output}->add_option_msg(short_msg => 'No metrics. Check your options or use --zeroed option to set 0 on undefined values'); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check ELB http codes. + +Example: +perl centreon_plugins.pl --plugin=cloud::aws::elb::plugin --custommode=paws --mode=http-codes --region='eu-west-1' +--type='loadbalancer' --name='elb-www-fr' --critical-httpcode-backend-4xx-sum='10' --verbose + +See 'https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/elb-metricscollected.html' for more informations. + +Default statistic: 'sum' / Most usefull statistics: 'sum'. + +=over 8 + +=item B<--type> + +Set the instance type (Required) (Can be: 'loadbalancer', 'availabilityzone'). + +=item B<--name> + +Set the instance name (Required) (Can be multiple). + +=item B<--availability-zone> + +Add Availability Zone dimension (only with --type='loadbalancer'). + +=item B<--filter-metric> + +Filter metrics (Can be: 'HTTPCode_Backend_2XX', 'HTTPCode_Backend_3XX', 'HTTPCode_Backend_4XX', +'HTTPCode_Backend_5XX', 'HTTPCode_ELB_4XX', 'HTTPCode_ELB_5XX', 'BackendConnectionErrors') +(Can be a regexp). + +=item B<--warning-$metric$-$statistic$> + +Thresholds warning ($metric$ can be: 'httpcode_backend_2xx', 'httpcode_backend_3xx', +'httpcode_backend_4xx', 'httpcode_backend_5xx', 'httpcode_elb_4xx', +'httpcode_elb_5xx', 'backendconnectionerrors', +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=item B<--critical-$metric$-$statistic$> + +Thresholds critical ($metric$ can be: 'httpcode_backend_2xx', 'httpcode_backend_3xx', +'httpcode_backend_4xx', 'httpcode_backend_5xx', 'httpcode_elb_4xx', +'httpcode_elb_5xx', 'backendconnectionerrors', +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=back + +=cut diff --git a/cloud/aws/elb/mode/performances.pm b/cloud/aws/elb/mode/performances.pm new file mode 100644 index 000000000..d2a5985a3 --- /dev/null +++ b/cloud/aws/elb/mode/performances.pm @@ -0,0 +1,234 @@ +# +# Copyright 2018 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::elb::mode::performances; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +my %map_type = ( + "loadbalancer" => "LoadBalancerName", + "availabilityzone" => "AvailabilityZone", +); + +sub prefix_metric_output { + my ($self, %options) = @_; + + my $availability_zone = ""; + if (defined($options{instance_value}->{availability_zone}) && $options{instance_value}->{availability_zone} ne '') { + $availability_zone = "[$options{instance_value}->{availability_zone}] "; + } + + return ucfirst($options{instance_value}->{type}) . " '" . $options{instance_value}->{display} . "' " . $availability_zone . $options{instance_value}->{stat} . " "; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'metric', type => 1, cb_prefix_output => 'prefix_metric_output', message_multiple => "All performances metrics are ok", skipped_code => { -10 => 1 } }, + ]; + + foreach my $statistic ('minimum', 'maximum', 'average', 'sum') { + foreach my $metric ('RequestCount') { + next if ($statistic =~ /minimum|maximum|average/); # Minimum, Maximum, and Average all return 1. + my $entry = { label => lc($metric) . '-' . lc($statistic), set => { + key_values => [ { name => $metric . '_' . $statistic }, { name => 'display' }, { name => 'type' }, { name => 'stat' } ], + output_template => $metric . ': %d requests', + perfdatas => [ + { label => lc($metric) . '_' . lc($statistic), value => $metric . '_' . $statistic . '_absolute', + template => '%d', unit => 'requests', label_extra_instance => 1, instance_use => 'display_absolute' }, + ], + } + }; + push @{$self->{maps_counters}->{metric}}, $entry; + } + foreach my $metric ('Latency') { + next if ($statistic =~ /minimum|sum/); # Minimum is typically not useful + my $entry = { label => lc($metric) . '-' . lc($statistic), set => { + key_values => [ { name => $metric . '_' . $statistic }, { name => 'display' }, { name => 'type' }, { name => 'stat' } ], + output_template => $metric . ': %.2f sec', + perfdatas => [ + { label => lc($metric) . '_' . lc($statistic), value => $metric . '_' . $statistic . '_absolute', + template => '%.2f', unit => 's', label_extra_instance => 1, instance_use => 'display_absolute' }, + ], + } + }; + push @{$self->{maps_counters}->{metric}}, $entry; + } + } +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $self->{version} = '1.0'; + $options{options}->add_options(arguments => + { + "type:s" => { name => 'type' }, + "name:s@" => { name => 'name' }, + "availability-zone:s" => { name => 'availability_zone' }, + "filter-metric:s" => { name => 'filter_metric' }, + "statistic:s@" => { name => 'statistic' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + if (!defined($self->{option_results}->{type}) || $self->{option_results}->{type} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --type option."); + $self->{output}->option_exit(); + } + + if ($self->{option_results}->{type} ne 'loadbalancer' && $self->{option_results}->{type} ne 'availabilityzone') { + $self->{output}->add_option_msg(short_msg => "Instance type '" . $self->{option_results}->{type} . "' is not handled for this mode"); + $self->{output}->option_exit(); + } + + if ($self->{option_results}->{type} eq 'availabilityzone' && defined($self->{option_results}->{availability_zone})) { + $self->{output}->add_option_msg(short_msg => "Can't specify --availability-zone option with availabilityzone instance's type"); + $self->{output}->option_exit(); + } + + if (!defined($self->{option_results}->{name}) || $self->{option_results}->{name} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --name option."); + $self->{output}->option_exit(); + } + + foreach my $instance (@{$self->{option_results}->{name}}) { + if ($instance ne '') { + push @{$self->{aws_instance}}, $instance; + } + } + + $self->{aws_timeframe} = defined($self->{option_results}->{timeframe}) ? $self->{option_results}->{timeframe} : 600; + $self->{aws_period} = defined($self->{option_results}->{period}) ? $self->{option_results}->{period} : 60; + + $self->{aws_statistics} = ['Sum', 'Average']; + if (defined($self->{option_results}->{statistic})) { + $self->{aws_statistics} = []; + foreach my $stat (@{$self->{option_results}->{statistic}}) { + if ($stat ne '') { + push @{$self->{aws_statistics}}, ucfirst(lc($stat)); + } + } + } + + foreach my $metric ('RequestCount', 'Latency') { + next if (defined($self->{option_results}->{filter_metric}) && $self->{option_results}->{filter_metric} ne '' + && $metric !~ /$self->{option_results}->{filter_metric}/); + + push @{$self->{aws_metrics}}, $metric; + } +} + +sub manage_selection { + my ($self, %options) = @_; + + my %metric_results; + foreach my $instance (@{$self->{aws_instance}}) { + push @{$self->{aws_dimensions}}, { Name => $map_type{$self->{option_results}->{type}}, Value => $instance }; + if (defined($self->{option_results}->{availability_zone}) && $self->{option_results}->{availability_zone} ne '') { + push @{$self->{aws_dimensions}}, { Name => 'AvailabilityZone', Value => $self->{option_results}->{availability_zone} }; + } + $metric_results{$instance} = $options{custom}->cloudwatch_get_metrics( + region => $self->{option_results}->{region}, + namespace => 'AWS/ELB', + dimensions => $self->{aws_dimensions}, + 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($metric_results{$instance}->{$metric}->{lc($statistic)}) && !defined($self->{option_results}->{zeroed})); + + $self->{metric}->{$instance . "_" . lc($statistic)}->{display} = $instance; + $self->{metric}->{$instance . "_" . lc($statistic)}->{type} = $self->{option_results}->{type}; + $self->{metric}->{$instance . "_" . lc($statistic)}->{stat} = lc($statistic); + $self->{metric}->{$instance . "_" . lc($statistic)}->{availability_zone} = $self->{option_results}->{availability_zone}; + $self->{metric}->{$instance . "_" . lc($statistic)}->{$metric . "_" . lc($statistic)} = defined($metric_results{$instance}->{$metric}->{lc($statistic)}) ? $metric_results{$instance}->{$metric}->{lc($statistic)} : 0; + } + } + } + + if (scalar(keys %{$self->{metric}}) <= 0) { + $self->{output}->add_option_msg(short_msg => 'No metrics. Check your options or use --zeroed option to set 0 on undefined values'); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check ELB performances. + +Example: +perl centreon_plugins.pl --plugin=cloud::aws::elb::plugin --custommode=paws --mode=performances --region='eu-west-1' +--type='loadbalancer' --name='elb-www-fr' --critical-requestcount-sum='10' --verbose + +See 'https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/elb-metricscollected.html' for more informations. + +Default statistic: 'sum', 'average' / Most usefull statistics: RequestCount: 'sum', Latency: 'average'. + +=over 8 + +=item B<--type> + +Set the instance type (Required) (Can be: 'loadbalancer', 'availabilityzone'). + +=item B<--name> + +Set the instance name (Required) (Can be multiple). + +=item B<--availability-zone> + +Add Availability Zone dimension (only with --type='loadbalancer'). + +=item B<--filter-metric> + +Filter metrics (Can be: 'RequestCount', 'Latency') +(Can be a regexp). + +=item B<--warning-$metric$-$statistic$> + +Thresholds warning ($metric$ can be: 'requestcount', 'latency', +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=item B<--critical-$metric$-$statistic$> + +Thresholds critical ($metric$ can be: 'requestcount', 'latency', +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=back + +=cut diff --git a/cloud/aws/elb/mode/queues.pm b/cloud/aws/elb/mode/queues.pm new file mode 100644 index 000000000..f54afe0d3 --- /dev/null +++ b/cloud/aws/elb/mode/queues.pm @@ -0,0 +1,235 @@ +# +# Copyright 2018 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::elb::mode::queues; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +my %map_type = ( + "loadbalancer" => "LoadBalancerName", + "availabilityzone" => "AvailabilityZone", +); + +sub prefix_metric_output { + my ($self, %options) = @_; + + my $availability_zone = ""; + if (defined($options{instance_value}->{availability_zone}) && $options{instance_value}->{availability_zone} ne '') { + $availability_zone = "[$options{instance_value}->{availability_zone}] "; + } + + return ucfirst($options{instance_value}->{type}) . " '" . $options{instance_value}->{display} . "' " . $availability_zone . $options{instance_value}->{stat} . " "; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'metric', type => 1, cb_prefix_output => 'prefix_metric_output', message_multiple => "All queues metrics are ok", skipped_code => { -10 => 1 } }, + ]; + + foreach my $statistic ('minimum', 'maximum', 'average', 'sum') { + foreach my $metric ('SpilloverCount') { + next if ($statistic =~ /minimum|maximum|average/); # Average, Minimum, and Maximum are reported per load balancer node and are not typically useful. + my $entry = { label => lc($metric) . '-' . lc($statistic), set => { + key_values => [ { name => $metric . '_' . $statistic }, { name => 'display' }, { name => 'type' }, { name => 'stat' } ], + output_template => $metric . ': %d', + perfdatas => [ + { label => lc($metric) . '_' . lc($statistic), value => $metric . '_' . $statistic . '_absolute', + template => '%d', label_extra_instance => 1, instance_use => 'display_absolute' }, + ], + } + }; + push @{$self->{maps_counters}->{metric}}, $entry; + } + foreach my $metric ('SurgeQueueLength') { + next if ($statistic =~ /sum/); # Sum is not useful. + my $entry = { label => lc($metric) . '-' . lc($statistic), set => { + key_values => [ { name => $metric . '_' . $statistic }, { name => 'display' }, { name => 'type' }, { name => 'stat' } ], + output_template => $metric . ': %d', + perfdatas => [ + { label => lc($metric) . '_' . lc($statistic), value => $metric . '_' . $statistic . '_absolute', + template => '%d', label_extra_instance => 1, instance_use => 'display_absolute' }, + ], + } + }; + push @{$self->{maps_counters}->{metric}}, $entry; + } + } +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $self->{version} = '1.0'; + $options{options}->add_options(arguments => + { + "type:s" => { name => 'type' }, + "name:s@" => { name => 'name' }, + "availability-zone:s" => { name => 'availability_zone' }, + "filter-metric:s" => { name => 'filter_metric' }, + "statistic:s@" => { name => 'statistic' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + if (!defined($self->{option_results}->{type}) || $self->{option_results}->{type} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --type option."); + $self->{output}->option_exit(); + } + + if ($self->{option_results}->{type} ne 'loadbalancer' && $self->{option_results}->{type} ne 'availabilityzone') { + $self->{output}->add_option_msg(short_msg => "Instance type '" . $self->{option_results}->{type} . "' is not handled for this mode"); + $self->{output}->option_exit(); + } + + if ($self->{option_results}->{type} eq 'availabilityzone' && defined($self->{option_results}->{availability_zone})) { + $self->{output}->add_option_msg(short_msg => "Can't specify --availability-zone option with availabilityzone instance's type"); + $self->{output}->option_exit(); + } + + if (!defined($self->{option_results}->{name}) || $self->{option_results}->{name} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --name option."); + $self->{output}->option_exit(); + } + + foreach my $instance (@{$self->{option_results}->{name}}) { + if ($instance ne '') { + push @{$self->{aws_instance}}, $instance; + } + } + + $self->{aws_timeframe} = defined($self->{option_results}->{timeframe}) ? $self->{option_results}->{timeframe} : 600; + $self->{aws_period} = defined($self->{option_results}->{period}) ? $self->{option_results}->{period} : 60; + + $self->{aws_statistics} = ['Sum', 'Maximum']; + if (defined($self->{option_results}->{statistic})) { + $self->{aws_statistics} = []; + foreach my $stat (@{$self->{option_results}->{statistic}}) { + if ($stat ne '') { + push @{$self->{aws_statistics}}, ucfirst(lc($stat)); + } + } + } + + foreach my $metric ('SpilloverCount', 'SurgeQueueLength') { + next if (defined($self->{option_results}->{filter_metric}) && $self->{option_results}->{filter_metric} ne '' + && $metric !~ /$self->{option_results}->{filter_metric}/); + + push @{$self->{aws_metrics}}, $metric; + } +} + +sub manage_selection { + my ($self, %options) = @_; + + my %metric_results; + foreach my $instance (@{$self->{aws_instance}}) { + push @{$self->{aws_dimensions}}, { Name => $map_type{$self->{option_results}->{type}}, Value => $instance }; + if (defined($self->{option_results}->{availability_zone}) && $self->{option_results}->{availability_zone} ne '') { + push @{$self->{aws_dimensions}}, { Name => 'AvailabilityZone', Value => $self->{option_results}->{availability_zone} }; + } + $metric_results{$instance} = $options{custom}->cloudwatch_get_metrics( + region => $self->{option_results}->{region}, + namespace => 'AWS/ELB', + dimensions => $self->{aws_dimensions}, + 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($metric_results{$instance}->{$metric}->{lc($statistic)}) && !defined($self->{option_results}->{zeroed})); + + $self->{metric}->{$instance . "_" . lc($statistic)}->{display} = $instance; + $self->{metric}->{$instance . "_" . lc($statistic)}->{type} = $self->{option_results}->{type}; + $self->{metric}->{$instance . "_" . lc($statistic)}->{stat} = lc($statistic); + $self->{metric}->{$instance . "_" . lc($statistic)}->{availability_zone} = $self->{option_results}->{availability_zone}; + $self->{metric}->{$instance . "_" . lc($statistic)}->{$metric . "_" . lc($statistic)} = defined($metric_results{$instance}->{$metric}->{lc($statistic)}) ? $metric_results{$instance}->{$metric}->{lc($statistic)} : 0; + } + } + } + + if (scalar(keys %{$self->{metric}}) <= 0) { + $self->{output}->add_option_msg(short_msg => 'No metrics. Check your options or use --zeroed option to set 0 on undefined values'); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check ELB surge queue. + +Example: +perl centreon_plugins.pl --plugin=cloud::aws::elb::plugin --custommode=paws --mode=queues --region='eu-west-1' +--type='loadbalancer' --name='elb-www-fr' --critical-spillovercount-sum='10' --verbose + +See 'https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/elb-metricscollected.html' for more informations. + +Default statistic: 'sum', 'maximum' / Most usefull statistics: SpilloverCount: 'sum', SurgeQueueLength: 'maximum'. + +=over 8 + +=item B<--type> + +Set the instance type (Required) (Can be: 'loadbalancer', 'availabilityzone'). + +=item B<--name> + +Set the instance name (Required) (Can be multiple). + +=item B<--availability-zone> + +Add Availability Zone dimension (only with --type='loadbalancer'). + +=item B<--filter-metric> + +Filter metrics (Can be: 'SpilloverCount', 'SurgeQueueLength') +(Can be a regexp). + +=item B<--warning-$metric$-$statistic$> + +Thresholds warning ($metric$ can be: 'spillovercount', 'surgequeuelength', +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=item B<--critical-$metric$-$statistic$> + +Thresholds critical ($metric$ can be: 'spillovercount', 'surgequeuelength', +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=back + +=cut diff --git a/cloud/aws/elb/mode/targetshealth.pm b/cloud/aws/elb/mode/targetshealth.pm new file mode 100644 index 000000000..eef332af3 --- /dev/null +++ b/cloud/aws/elb/mode/targetshealth.pm @@ -0,0 +1,221 @@ +# +# Copyright 2018 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::elb::mode::targetshealth; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +my %map_type = ( + "loadbalancer" => "LoadBalancerName", + "availabilityzone" => "AvailabilityZone", +); + +sub prefix_metric_output { + my ($self, %options) = @_; + + my $availability_zone = ""; + if (defined($options{instance_value}->{availability_zone}) && $options{instance_value}->{availability_zone} ne '') { + $availability_zone = "[$options{instance_value}->{availability_zone}] "; + } + + return ucfirst($options{instance_value}->{type}) . " '" . $options{instance_value}->{display} . "' " . $availability_zone . $options{instance_value}->{stat} . " "; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'metric', type => 1, cb_prefix_output => 'prefix_metric_output', message_multiple => "All health metrics are ok", skipped_code => { -10 => 1 } }, + ]; + + foreach my $statistic ('minimum', 'maximum', 'average', 'sum') { + foreach my $metric ('HealthyHostCount', 'UnHealthyHostCount') { + my $entry = { label => lc($metric) . '-' . lc($statistic), set => { + key_values => [ { name => $metric . '_' . $statistic }, { name => 'display' }, { name => 'type' }, { name => 'stat' } ], + output_template => $metric . ': %d', + perfdatas => [ + { label => lc($metric) . '_' . lc($statistic), value => $metric . '_' . $statistic . '_absolute', + template => '%d', label_extra_instance => 1, instance_use => 'display_absolute' }, + ], + } + }; + push @{$self->{maps_counters}->{metric}}, $entry; + } + } +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $self->{version} = '1.0'; + $options{options}->add_options(arguments => + { + "type:s" => { name => 'type' }, + "name:s@" => { name => 'name' }, + "availability-zone:s" => { name => 'availability_zone' }, + "filter-metric:s" => { name => 'filter_metric' }, + "statistic:s@" => { name => 'statistic' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + if (!defined($self->{option_results}->{type}) || $self->{option_results}->{type} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --type option."); + $self->{output}->option_exit(); + } + + if ($self->{option_results}->{type} ne 'loadbalancer' && $self->{option_results}->{type} ne 'availabilityzone') { + $self->{output}->add_option_msg(short_msg => "Instance type '" . $self->{option_results}->{type} . "' is not handled for this mode"); + $self->{output}->option_exit(); + } + + if ($self->{option_results}->{type} eq 'availabilityzone' && defined($self->{option_results}->{availability_zone})) { + $self->{output}->add_option_msg(short_msg => "Can't specify --availability-zone option with availabilityzone instance's type"); + $self->{output}->option_exit(); + } + + if (!defined($self->{option_results}->{name}) || $self->{option_results}->{name} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --name option."); + $self->{output}->option_exit(); + } + + foreach my $instance (@{$self->{option_results}->{name}}) { + if ($instance ne '') { + push @{$self->{aws_instance}}, $instance; + } + } + + $self->{aws_timeframe} = defined($self->{option_results}->{timeframe}) ? $self->{option_results}->{timeframe} : 600; + $self->{aws_period} = defined($self->{option_results}->{period}) ? $self->{option_results}->{period} : 60; + + $self->{aws_statistics} = ['Average']; + if (defined($self->{option_results}->{statistic})) { + $self->{aws_statistics} = []; + foreach my $stat (@{$self->{option_results}->{statistic}}) { + if ($stat ne '') { + push @{$self->{aws_statistics}}, ucfirst(lc($stat)); + } + } + } + + foreach my $metric ('HealthyHostCount', 'UnHealthyHostCount') { + next if (defined($self->{option_results}->{filter_metric}) && $self->{option_results}->{filter_metric} ne '' + && $metric !~ /$self->{option_results}->{filter_metric}/); + + push @{$self->{aws_metrics}}, $metric; + } +} + +sub manage_selection { + my ($self, %options) = @_; + + my %metric_results; + foreach my $instance (@{$self->{aws_instance}}) { + push @{$self->{aws_dimensions}}, { Name => $map_type{$self->{option_results}->{type}}, Value => $instance }; + if (defined($self->{option_results}->{availability_zone}) && $self->{option_results}->{availability_zone} ne '') { + push @{$self->{aws_dimensions}}, { Name => 'AvailabilityZone', Value => $self->{option_results}->{availability_zone} }; + } + $metric_results{$instance} = $options{custom}->cloudwatch_get_metrics( + region => $self->{option_results}->{region}, + namespace => 'AWS/ELB', + dimensions => $self->{aws_dimensions}, + 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($metric_results{$instance}->{$metric}->{lc($statistic)}) && !defined($self->{option_results}->{zeroed})); + + $self->{metric}->{$instance . "_" . lc($statistic)}->{display} = $instance; + $self->{metric}->{$instance . "_" . lc($statistic)}->{type} = $self->{option_results}->{type}; + $self->{metric}->{$instance . "_" . lc($statistic)}->{stat} = lc($statistic); + $self->{metric}->{$instance . "_" . lc($statistic)}->{availability_zone} = $self->{option_results}->{availability_zone}; + $self->{metric}->{$instance . "_" . lc($statistic)}->{$metric . "_" . lc($statistic)} = defined($metric_results{$instance}->{$metric}->{lc($statistic)}) ? $metric_results{$instance}->{$metric}->{lc($statistic)} : 0; + } + } + } + + if (scalar(keys %{$self->{metric}}) <= 0) { + $self->{output}->add_option_msg(short_msg => 'No metrics. Check your options or use --zeroed option to set 0 on undefined values'); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check ELB instances health. + +Example: +perl centreon_plugins.pl --plugin=cloud::aws::elb::plugin --custommode=paws --mode=instancehealth --region='eu-west-1' +--type='loadbalancer' --name='elb-www-fr' --critical-healthyhostcount-average='10' --verbose + +See 'https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/elb-metricscollected.html' for more informations. + +Default statistic: 'average' / Most usefull statistics: 'average', 'minimum', 'maximum'. + +=over 8 + +=item B<--type> + +Set the instance type (Required) (Can be: 'loadbalancer', 'availabilityzone'). + +=item B<--name> + +Set the instance name (Required) (Can be multiple). + +=item B<--availability-zone> + +Add Availability Zone dimension (only with --type='loadbalancer'). + +=item B<--filter-metric> + +Filter metrics (Can be: 'HealthyHostCount', 'UnHealthyHostCount') +(Can be a regexp). + +=item B<--warning-$metric$-$statistic$> + +Thresholds warning ($metric$ can be: 'healthyhostcount', 'unhealthyhostcount', +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=item B<--critical-$metric$-$statistic$> + +Thresholds critical ($metric$ can be: 'healthyhostcount', 'unhealthyhostcount', +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=back + +=cut diff --git a/cloud/aws/elb/plugin.pm b/cloud/aws/elb/plugin.pm new file mode 100644 index 000000000..aef813f01 --- /dev/null +++ b/cloud/aws/elb/plugin.pm @@ -0,0 +1,53 @@ +# +# Copyright 2018 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::elb::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} } = ( + 'http-codes' => 'cloud::aws::elb::mode::httpcodes', + 'performances' => 'cloud::aws::elb::mode::performances', + 'queues' => 'cloud::aws::elb::mode::queues', + 'targets-health' => 'cloud::aws::elb::mode::targetshealth', + ); + + $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 Elastic Load Balancing (Amazon ELB). + +=cut diff --git a/cloud/aws/lambda/mode/invocations.pm b/cloud/aws/lambda/mode/invocations.pm new file mode 100644 index 000000000..7fdbafc6c --- /dev/null +++ b/cloud/aws/lambda/mode/invocations.pm @@ -0,0 +1,193 @@ +# +# Copyright 2018 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::lambda::mode::invocations; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +sub prefix_metric_output { + my ($self, %options) = @_; + + return "Function '" . $options{instance_value}->{display} . "' " . $options{instance_value}->{stat} . " "; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'metric', type => 1, cb_prefix_output => 'prefix_metric_output', message_multiple => "All invocations metrics are ok", skipped_code => { -10 => 1 } }, + ]; + + foreach my $statistic ('minimum', 'maximum', 'average', 'sum') { + foreach my $metric ('Invocations', 'Errors', 'Dead Letter Error', 'Throttles') { + next if ($statistic =~ /minimum|maximum|average/); + my $entry = { label => lc($metric) . '-' . lc($statistic), set => { + key_values => [ { name => $metric . '_' . $statistic }, { name => 'display' }, { name => 'stat' } ], + output_template => $metric . ': %.2f', + perfdatas => [ + { label => lc($metric) . '_' . lc($statistic), value => $metric . '_' . $statistic . '_absolute', + template => '%.2f', label_extra_instance => 1, instance_use => 'display_absolute' }, + ], + } + }; + push @{$self->{maps_counters}->{metric}}, $entry; + } + foreach my $metric ('Duration') { + next if ($statistic =~ /sum/); + my $entry = { label => lc($metric) . '-' . lc($statistic), set => { + key_values => [ { name => $metric . '_' . $statistic }, { name => 'display' }, { name => 'stat' } ], + output_template => $metric . ': %.2f ms', + perfdatas => [ + { label => lc($metric) . '_' . lc($statistic), value => $metric . '_' . $statistic . '_absolute', + template => '%.2f', unit => 'ms', label_extra_instance => 1, instance_use => 'display_absolute' }, + ], + } + }; + push @{$self->{maps_counters}->{metric}}, $entry; + } + } +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $self->{version} = '1.0'; + $options{options}->add_options(arguments => + { + "name:s@" => { name => 'name' }, + "filter-metric:s" => { name => 'filter_metric' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + if (!defined($self->{option_results}->{name}) || $self->{option_results}->{name} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --name option."); + $self->{output}->option_exit(); + } + + foreach my $instance (@{$self->{option_results}->{name}}) { + if ($instance ne '') { + push @{$self->{aws_instance}}, $instance; + } + } + + $self->{aws_timeframe} = defined($self->{option_results}->{timeframe}) ? $self->{option_results}->{timeframe} : 600; + $self->{aws_period} = defined($self->{option_results}->{period}) ? $self->{option_results}->{period} : 60; + + $self->{aws_statistics} = ['Sum', 'Average']; + if (defined($self->{option_results}->{statistic})) { + $self->{aws_statistics} = []; + foreach my $stat (@{$self->{option_results}->{statistic}}) { + if ($stat ne '') { + push @{$self->{aws_statistics}}, ucfirst(lc($stat)); + } + } + } + + foreach my $metric ('Invocations', 'Errors', 'Throttles', 'Duration') { + next if (defined($self->{option_results}->{filter_metric}) && $self->{option_results}->{filter_metric} ne '' + && $metric !~ /$self->{option_results}->{filter_metric}/); + + push @{$self->{aws_metrics}}, $metric; + } +} + +sub manage_selection { + my ($self, %options) = @_; + + my %metric_results; + foreach my $instance (@{$self->{aws_instance}}) { + $metric_results{$instance} = $options{custom}->cloudwatch_get_metrics( + region => $self->{option_results}->{region}, + namespace => 'AWS/Lambda', + dimensions => [ { Name => 'FunctionName', Value => $instance } ], + 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($metric_results{$instance}->{$metric}->{lc($statistic)}) && !defined($self->{option_results}->{zeroed})); + + $self->{metric}->{$instance . "_" . lc($statistic)}->{display} = $instance; + $self->{metric}->{$instance . "_" . lc($statistic)}->{stat} = lc($statistic); + $self->{metric}->{$instance . "_" . lc($statistic)}->{$metric . "_" . lc($statistic)} = defined($metric_results{$instance}->{$metric}->{lc($statistic)}) ? $metric_results{$instance}->{$metric}->{lc($statistic)} : 0; + } + } + } + + if (scalar(keys %{$self->{metric}}) <= 0) { + $self->{output}->add_option_msg(short_msg => 'No metrics. Check your options or use --zeroed option to set 0 on undefined values'); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check Lambda invocations metrics. + +Example: +perl centreon_plugins.pl --plugin=cloud::aws::lambda::plugin --custommode=paws --mode=invocations --region='eu-west-1' +--name='myFunction' --filter-metric='Duration' --statistic='average' --critical-duration-average='10' --verbose + +See 'https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/lam-metricscollected.html' for more informations. + +Default statistic: 'sum', 'average'. + +=over 8 + +=item B<--name> + +Set the function name (Required) (Can be multiple). + +=item B<--filter-metric> + +Filter metrics (Can be: 'Invocations', 'Errors', 'Throttles', 'Duration') +(Can be a regexp). + +=item B<--warning-$metric$-$statistic$> + +Thresholds warning ($metric$ can be: 'invocations', 'errors', 'throttles', 'duration', +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=item B<--critical-$metric$-$statistic$> + +Thresholds critical ($metric$ can be: 'invocations', 'errors', 'throttles', 'duration', +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=back + +=cut diff --git a/cloud/aws/lambda/plugin.pm b/cloud/aws/lambda/plugin.pm new file mode 100644 index 000000000..de8116362 --- /dev/null +++ b/cloud/aws/lambda/plugin.pm @@ -0,0 +1,50 @@ +# +# Copyright 2018 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::lambda::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} } = ( + 'invocations' => 'cloud::aws::lambda::mode::invocations', + ); + + $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 Lambda. + +=cut diff --git a/cloud/aws/rds/mode/connections.pm b/cloud/aws/rds/mode/connections.pm new file mode 100644 index 000000000..f618734e7 --- /dev/null +++ b/cloud/aws/rds/mode/connections.pm @@ -0,0 +1,203 @@ +# +# Copyright 2018 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::rds::mode::connections; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +my %map_type = ( + "instance" => "DBInstanceIdentifier", + "cluster" => "DBClusterIdentifier", +); + +sub prefix_metric_output { + my ($self, %options) = @_; + + return ucfirst($options{instance_value}->{type}) . " '" . $options{instance_value}->{display} . "' " . $options{instance_value}->{stat} . " "; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'metric', type => 1, cb_prefix_output => 'prefix_metric_output', message_multiple => "All database metrics are ok", skipped_code => { -10 => 1 } }, + ]; + + foreach my $statistic ('minimum', 'maximum', 'average', 'sum') { + foreach my $metric ('DatabaseConnections') { + my $entry = { label => lc($metric) . '-' . lc($statistic), set => { + key_values => [ { name => $metric . '_' . $statistic }, { name => 'display' }, { name => 'type' }, { name => 'stat' } ], + output_template => $metric . ': %d', + perfdatas => [ + { label => lc($metric) . '_' . lc($statistic), value => $metric . '_' . $statistic . '_absolute', + template => '%d', min => 0, label_extra_instance => 1, instance_use => 'display_absolute' }, + ], + } + }; + push @{$self->{maps_counters}->{metric}}, $entry; + } + } +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $self->{version} = '1.0'; + $options{options}->add_options(arguments => + { + "type:s" => { name => 'type' }, + "name:s@" => { name => 'name' }, + "filter-metric:s" => { name => 'filter_metric' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + if (!defined($self->{option_results}->{type}) || $self->{option_results}->{type} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --type option."); + $self->{output}->option_exit(); + } + + if ($self->{option_results}->{type} ne 'cluster' && $self->{option_results}->{type} ne 'instance') { + $self->{output}->add_option_msg(short_msg => "Instance type '" . $self->{option_results}->{type} . "' is not handled for this mode"); + $self->{output}->option_exit(); + } + + if (!defined($self->{option_results}->{name}) || $self->{option_results}->{name} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --name option."); + $self->{output}->option_exit(); + } + + foreach my $instance (@{$self->{option_results}->{name}}) { + if ($instance ne '') { + push @{$self->{aws_instance}}, $instance; + } + } + + $self->{aws_timeframe} = defined($self->{option_results}->{timeframe}) ? $self->{option_results}->{timeframe} : 600; + $self->{aws_period} = defined($self->{option_results}->{period}) ? $self->{option_results}->{period} : 60; + + $self->{aws_statistics} = ['Average']; + if (defined($self->{option_results}->{statistic})) { + $self->{aws_statistics} = []; + foreach my $stat (@{$self->{option_results}->{statistic}}) { + if ($stat ne '') { + push @{$self->{aws_statistics}}, ucfirst(lc($stat)); + } + } + } + + foreach my $metric ('DatabaseConnections') { + next if (defined($self->{option_results}->{filter_metric}) && $self->{option_results}->{filter_metric} ne '' + && $metric !~ /$self->{option_results}->{filter_metric}/); + + push @{$self->{aws_metrics}}, $metric; + } +} + +sub manage_selection { + my ($self, %options) = @_; + + my %metric_results; + foreach my $instance (@{$self->{aws_instance}}) { + $metric_results{$instance} = $options{custom}->cloudwatch_get_metrics( + region => $self->{option_results}->{region}, + namespace => 'AWS/RDS', + dimensions => [ { Name => $map_type{$self->{option_results}->{type}}, Value => $instance } ], + 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($metric_results{$instance}->{$metric}->{lc($statistic)}) && !defined($self->{option_results}->{zeroed})); + + $self->{metric}->{$instance . "_" . lc($statistic)}->{display} = $instance; + $self->{metric}->{$instance . "_" . lc($statistic)}->{stat} = lc($statistic); + $self->{metric}->{$instance . "_" . lc($statistic)}->{type} = $self->{option_results}->{type}; + $self->{metric}->{$instance . "_" . lc($statistic)}->{$metric . "_" . lc($statistic)} = defined($metric_results{$instance}->{$metric}->{lc($statistic)}) ? $metric_results{$instance}->{$metric}->{lc($statistic)} : 0; + } + } + } + + if (scalar(keys %{$self->{metric}}) <= 0) { + $self->{output}->add_option_msg(short_msg => 'No metrics. Check your options or use --zeroed option to set 0 on undefined values'); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check RDS instances database connections. + +Example: +perl centreon_plugins.pl --plugin=cloud::aws::rds::plugin --custommode=paws --mode=connections --region='eu-west-1' +--type='cluster' --name='centreon-db-ppd-cluster' --filter-metric='DatabaseConnections' --statistic='sum' +--critical-databaseconnections-sum='10' --verbose + +Works for the following database engines : aurora, mysql, mariadb. + +See 'https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/rds-metricscollected.html' for more informations. + +Default statistic: 'average' / All satistics are valid. + +=over 8 + +=item B<--type> + +Set the instance type (Required) (Can be: 'cluster', 'instance'). + +=item B<--name> + +Set the instance name (Required) (Can be multiple). + +=item B<--filter-metric> + +Filter metrics (Can be: 'DatabaseConnections') +(Can be a regexp). + +=item B<--warning-$metric$-$statistic$> + +Thresholds warning ($metric$ can be: 'databaseconnections' +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=item B<--critical-$metric$-$statistic$> + +Thresholds warning ($metric$ can be: 'databaseconnections' +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=back + +=cut diff --git a/cloud/aws/rds/mode/cpu.pm b/cloud/aws/rds/mode/cpu.pm new file mode 100644 index 000000000..0a297be0b --- /dev/null +++ b/cloud/aws/rds/mode/cpu.pm @@ -0,0 +1,215 @@ +# +# Copyright 2018 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::rds::mode::cpu; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +my %map_type = ( + "instance" => "DBInstanceIdentifier", + "cluster" => "DBClusterIdentifier", +); + +sub prefix_metric_output { + my ($self, %options) = @_; + + return ucfirst($options{instance_value}->{type}) . " '" . $options{instance_value}->{display} . "' " . $options{instance_value}->{stat} . " "; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'metric', type => 1, cb_prefix_output => 'prefix_metric_output', message_multiple => "All CPU metrics are ok", skipped_code => { -10 => 1 } }, + ]; + + foreach my $statistic ('minimum', 'maximum', 'average', 'sum') { + foreach my $metric ('CPUCreditBalance', 'CPUCreditUsage') { + my $entry = { label => lc($metric) . '-' . lc($statistic), set => { + key_values => [ { name => $metric . '_' . $statistic }, { name => 'display' }, { name => 'type' }, { name => 'stat' } ], + output_template => $metric . ': %.2f', + perfdatas => [ + { label => lc($metric) . '_' . lc($statistic), value => $metric . '_' . $statistic . '_absolute', + template => '%.2f', min => 0, label_extra_instance => 1, instance_use => 'display_absolute' }, + ], + } + }; + push @{$self->{maps_counters}->{metric}}, $entry; + } + foreach my $metric ('CPUUtilization') { + my $entry = { label => lc($metric) . '-' . lc($statistic), set => { + key_values => [ { name => $metric . '_' . $statistic }, { name => 'display' }, { name => 'type' }, { name => 'stat' } ], + output_template => $metric . ': %.2f %%', + perfdatas => [ + { label => lc($metric) . '_' . lc($statistic), value => $metric . '_' . $statistic . '_absolute', + template => '%.2f', unit => '%', min => 0, max => 100, label_extra_instance => 1, instance_use => 'display_absolute' }, + ], + } + }; + push @{$self->{maps_counters}->{metric}}, $entry; + } + } +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $self->{version} = '1.0'; + $options{options}->add_options(arguments => + { + "type:s" => { name => 'type' }, + "name:s@" => { name => 'name' }, + "filter-metric:s" => { name => 'filter_metric' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + if (!defined($self->{option_results}->{type}) || $self->{option_results}->{type} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --type option."); + $self->{output}->option_exit(); + } + + if ($self->{option_results}->{type} ne 'cluster' && $self->{option_results}->{type} ne 'instance') { + $self->{output}->add_option_msg(short_msg => "Instance type '" . $self->{option_results}->{type} . "' is not handled for this mode"); + $self->{output}->option_exit(); + } + + if (!defined($self->{option_results}->{name}) || $self->{option_results}->{name} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --name option."); + $self->{output}->option_exit(); + } + + $self->{aws_timeframe} = defined($self->{option_results}->{timeframe}) ? $self->{option_results}->{timeframe} : 600; + $self->{aws_period} = defined($self->{option_results}->{period}) ? $self->{option_results}->{period} : 60; + + foreach my $instance (@{$self->{option_results}->{name}}) { + if ($instance ne '') { + push @{$self->{aws_instance}}, $instance; + } + } + + $self->{aws_statistics} = ['Average']; + if (defined($self->{option_results}->{statistic})) { + $self->{aws_statistics} = []; + foreach my $stat (@{$self->{option_results}->{statistic}}) { + if ($stat ne '') { + push @{$self->{aws_statistics}}, ucfirst(lc($stat)); + } + } + } + + foreach my $metric ('CPUCreditBalance', 'CPUCreditUsage', 'CPUUtilization') { + next if (defined($self->{option_results}->{filter_metric}) && $self->{option_results}->{filter_metric} ne '' + && $metric !~ /$self->{option_results}->{filter_metric}/); + + push @{$self->{aws_metrics}}, $metric; + } +} + +sub manage_selection { + my ($self, %options) = @_; + + my %metric_results; + foreach my $instance (@{$self->{aws_instance}}) { + $metric_results{$instance} = $options{custom}->cloudwatch_get_metrics( + region => $self->{option_results}->{region}, + namespace => 'AWS/RDS', + dimensions => [ { Name => $map_type{$self->{option_results}->{type}}, Value => $instance } ], + 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($metric_results{$instance}->{$metric}->{lc($statistic)}) && !defined($self->{option_results}->{zeroed})); + + $self->{metric}->{$instance . "_" . lc($statistic)}->{display} = $instance; + $self->{metric}->{$instance . "_" . lc($statistic)}->{stat} = lc($statistic); + $self->{metric}->{$instance . "_" . lc($statistic)}->{type} = $self->{option_results}->{type}; + $self->{metric}->{$instance . "_" . lc($statistic)}->{$metric . "_" . lc($statistic)} = defined($metric_results{$instance}->{$metric}->{lc($statistic)}) ? $metric_results{$instance}->{$metric}->{lc($statistic)} : 0; + } + } + } + + if (scalar(keys %{$self->{metric}}) <= 0) { + $self->{output}->add_option_msg(short_msg => 'No metrics. Check your options or use --zeroed option to set 0 on undefined values'); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check RDS instances CPU metrics. + +Example: +perl centreon_plugins.pl --plugin=cloud::aws::rds::plugin --custommode=paws --mode=cpu --region='eu-west-1' +--type='cluster' --name='centreon-db-ppd-cluster' --filter-metric='Credit' --statistic='average' +--critical-cpucreditusage-average='10' --verbose + +Works for the following database engines : aurora, mysql, mariadb. + +See 'https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/rds-metricscollected.html' for more informations. + +Default statistic: 'average' / All satistics are valid. + +=over 8 + +=item B<--type> + +Set the instance type (Required) (Can be: 'cluster', 'instance'). + +=item B<--name> + +Set the instance name (Required) (Can be multiple). + +=item B<--filter-metric> + +Filter metrics (Can be: 'CPUCreditBalance', 'CPUCreditUsage', CPUUtilization') +(Can be a regexp). + +=item B<--warning-$metric$-$statistic$> + +Thresholds warning ($metric$ can be: 'cpucreditusage', 'cpucreditbalance', 'cpuutilization', +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=item B<--critical-$metric$-$statistic$> + +Thresholds critical ($metric$ can be: 'cpucreditusage', 'cpucreditbalance', 'cpuutilization', +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=back + +=cut diff --git a/cloud/aws/rds/mode/diskio.pm b/cloud/aws/rds/mode/diskio.pm new file mode 100644 index 000000000..0912cf047 --- /dev/null +++ b/cloud/aws/rds/mode/diskio.pm @@ -0,0 +1,244 @@ +# +# Copyright 2018 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::rds::mode::diskio; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +my %map_type = ( + "instance" => "DBInstanceIdentifier", + "cluster" => "DBClusterIdentifier", +); + +sub prefix_metric_output { + my ($self, %options) = @_; + + return ucfirst($options{instance_value}->{type}) . " '" . $options{instance_value}->{display} . "' " . $options{instance_value}->{stat} . " "; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'metric', type => 1, cb_prefix_output => 'prefix_metric_output', message_multiple => "All disk metrics are ok", skipped_code => { -10 => 1 } }, + ]; + + foreach my $statistic ('minimum', 'maximum', 'average', 'sum') { + foreach my $metric ('ReadThroughput', 'WriteThroughput') { + my $entry = { label => lc($metric) . '-' . lc($statistic), set => { + key_values => [ { name => $metric . '_' . $statistic }, { name => 'display' }, { name => 'type' }, { name => 'stat' } ], + output_template => $metric . ': %.2f %s/s', + output_change_bytes => 1, + perfdatas => [ + { label => lc($metric) . '_' . lc($statistic), value => $metric . '_' . $statistic . '_absolute', + template => '%.2f', unit => 'B/s', min => 0, label_extra_instance => 1, instance_use => 'display_absolute' }, + ], + } + }; + push @{$self->{maps_counters}->{metric}}, $entry; + } + foreach my $metric ('ReadIOPS', 'WriteIOPS') { + my $entry = { label => lc($metric) . '-' . lc($statistic), set => { + key_values => [ { name => $metric . '_' . $statistic }, { name => 'display' }, { name => 'type' }, { name => 'stat' } ], + output_template => $metric . ': %.2f iops', + perfdatas => [ + { label => lc($metric) . '_' . lc($statistic), value => $metric . '_' . $statistic . '_absolute', + template => '%.2f', unit => 'iops', min => 0, label_extra_instance => 1, instance_use => 'display_absolute' }, + ], + } + }; + push @{$self->{maps_counters}->{metric}}, $entry; + } + foreach my $metric ('ReadLatency', 'WriteLatency') { + my $entry = { label => lc($metric) . '-' . lc($statistic), set => { + key_values => [ { name => $metric . '_' . $statistic }, { name => 'display' }, { name => 'type' }, { name => 'stat' } ], + output_template => $metric . ': %.2f s', + perfdatas => [ + { label => lc($metric) . '_' . lc($statistic), value => $metric . '_' . $statistic . '_absolute', + template => '%.2f', unit => 's', min => 0, label_extra_instance => 1, instance_use => 'display_absolute' }, + ], + } + }; + push @{$self->{maps_counters}->{metric}}, $entry; + } + foreach my $metric ('DiskQueueDepth') { + my $entry = { label => lc($metric) . '-' . lc($statistic), set => { + key_values => [ { name => $metric . '_' . $statistic }, { name => 'display' }, { name => 'type' }, { name => 'stat' } ], + output_template => $metric . ': %d', + perfdatas => [ + { label => lc($metric) . '_' . lc($statistic), value => $metric . '_' . $statistic . '_absolute', + template => '%d', min => 0, label_extra_instance => 1, instance_use => 'display_absolute' }, + ], + } + }; + push @{$self->{maps_counters}->{metric}}, $entry; + } + } +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $self->{version} = '1.0'; + $options{options}->add_options(arguments => + { + "type:s" => { name => 'type' }, + "name:s@" => { name => 'name' }, + "filter-metric:s" => { name => 'filter_metric' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + if (!defined($self->{option_results}->{type}) || $self->{option_results}->{type} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --type option."); + $self->{output}->option_exit(); + } + + if ($self->{option_results}->{type} ne 'cluster' && $self->{option_results}->{type} ne 'instance') { + $self->{output}->add_option_msg(short_msg => "Instance type '" . $self->{option_results}->{type} . "' is not handled for this mode"); + $self->{output}->option_exit(); + } + + if (!defined($self->{option_results}->{name}) || $self->{option_results}->{name} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --name option."); + $self->{output}->option_exit(); + } + + foreach my $instance (@{$self->{option_results}->{name}}) { + if ($instance ne '') { + push @{$self->{aws_instance}}, $instance; + } + } + + $self->{aws_timeframe} = defined($self->{option_results}->{timeframe}) ? $self->{option_results}->{timeframe} : 600; + $self->{aws_period} = defined($self->{option_results}->{period}) ? $self->{option_results}->{period} : 60; + + $self->{aws_statistics} = ['Average']; + if (defined($self->{option_results}->{statistic})) { + $self->{aws_statistics} = []; + foreach my $stat (@{$self->{option_results}->{statistic}}) { + if ($stat ne '') { + push @{$self->{aws_statistics}}, ucfirst(lc($stat)); + } + } + } + + foreach my $metric ('ReadThroughput', 'WriteThroughput', 'ReadIOPS', 'WriteIOPS', + 'ReadLatency', 'WriteLatency', 'DiskQueueDepth') { + next if (defined($self->{option_results}->{filter_metric}) && $self->{option_results}->{filter_metric} ne '' + && $metric !~ /$self->{option_results}->{filter_metric}/); + + push @{$self->{aws_metrics}}, $metric; + } +} + +sub manage_selection { + my ($self, %options) = @_; + + my %metric_results; + foreach my $instance (@{$self->{aws_instance}}) { + $metric_results{$instance} = $options{custom}->cloudwatch_get_metrics( + region => $self->{option_results}->{region}, + namespace => 'AWS/RDS', + dimensions => [ { Name => $map_type{$self->{option_results}->{type}}, Value => $instance } ], + 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($metric_results{$instance}->{$metric}->{lc($statistic)}) && !defined($self->{option_results}->{zeroed})); + + $self->{metric}->{$instance . "_" . lc($statistic)}->{display} = $instance; + $self->{metric}->{$instance . "_" . lc($statistic)}->{stat} = lc($statistic); + $self->{metric}->{$instance . "_" . lc($statistic)}->{type} = $self->{option_results}->{type}; + $self->{metric}->{$instance . "_" . lc($statistic)}->{$metric . "_" . lc($statistic)} = defined($metric_results{$instance}->{$metric}->{lc($statistic)}) ? $metric_results{$instance}->{$metric}->{lc($statistic)} : 0; + } + } + } + + if (scalar(keys %{$self->{metric}}) <= 0) { + $self->{output}->add_option_msg(short_msg => 'No metrics. Check your options or use --zeroed option to set 0 on undefined values'); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check RDS instances disk IO metrics. + +Example: +perl centreon_plugins.pl --plugin=cloud::aws::rds::plugin --custommode=paws --mode=diskio --region='eu-west-1' +--type='cluster' --name='centreon-db-ppd-cluster' --filter-metric='Read' --statistic='sum' +--critical-readiops-sum='10' --verbose + +Works for the following database engines : mysql, mariadb. + +See 'https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/rds-metricscollected.html' for more informations. + +Default statistic: 'average' / All satistics are valid. + +=over 8 + +=item B<--type> + +Set the instance type (Required) (Can be: 'cluster', 'instance'). + +=item B<--name> + +Set the instance name (Required) (Can be multiple). + +=item B<--filter-metric> + +Filter metrics (Can be: 'ReadThroughput', 'WriteThroughput', +'ReadIOPS', 'WriteIOPS', 'ReadLatency', 'WriteLatency', 'DiskQueueDepth') +(Can be a regexp). + +=item B<--warning-$metric$-$statistic$> + +Thresholds warning ($metric$ can be: 'readthroughput', 'writethroughput', +'readiops', 'writeiops', 'readlatency', 'writelatency', 'diskqueuedepth', +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=item B<--critical-$metric$-$statistic$> + +Thresholds critical ($metric$ can be: 'readthroughput', 'writethroughput', +'readiops', 'writeiops', 'readlatency', 'writelatency', 'diskqueuedepth', +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=back + +=cut diff --git a/cloud/aws/mode/rdsinstancestatus.pm b/cloud/aws/rds/mode/instancestatus.pm similarity index 93% rename from cloud/aws/mode/rdsinstancestatus.pm rename to cloud/aws/rds/mode/instancestatus.pm index e73895c82..5ae065187 100644 --- a/cloud/aws/mode/rdsinstancestatus.pm +++ b/cloud/aws/rds/mode/instancestatus.pm @@ -18,7 +18,7 @@ # limitations under the License. # -package cloud::aws::mode::rdsinstancestatus; +package cloud::aws::rds::mode::instancestatus; use base qw(centreon::plugins::templates::counter); @@ -131,8 +131,8 @@ sub set_counters { $self->{maps_counters}->{aws_instances} = [ { label => 'status', threshold => 0, set => { key_values => [ { name => 'state' }, { name => 'display' } ], - closure_custom_calc => $self->can('custom_nas_status_calc'), - closure_custom_output => $self->can('custom_nas_status_output'), + closure_custom_calc => $self->can('custom_status_calc'), + closure_custom_output => $self->can('custom_status_output'), closure_custom_perfdata => sub { return 0; }, closure_custom_threshold_check => $self->can('custom_status_threshold'), } @@ -148,10 +148,9 @@ sub new { $self->{version} = '1.0'; $options{options}->add_options(arguments => { - "region:s" => { name => 'region' }, - "filter-instanceid:s" => { name => 'filter_instanceid' }, - "warning-status:s" => { name => 'warning_status', default => '' }, - "critical-status:s" => { name => 'critical_status', default => '' }, + "filter-instanceid:s" => { name => 'filter_instanceid' }, + "warning-status:s" => { name => 'warning_status', default => '' }, + "critical-status:s" => { name => 'critical_status', default => '' }, }); return $self; diff --git a/cloud/aws/rds/mode/listclusters.pm b/cloud/aws/rds/mode/listclusters.pm new file mode 100644 index 000000000..f7bb56778 --- /dev/null +++ b/cloud/aws/rds/mode/listclusters.pm @@ -0,0 +1,100 @@ +# +# Copyright 2018 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::rds::mode::listclusters; + +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; + + $self->{version} = '1.0'; + $options{options}->add_options(arguments => + { + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::init(%options); +} + +sub manage_selection { + my ($self, %options) = @_; + + $self->{instances} = $options{custom}->rds_list_clusters(region => $self->{option_results}->{region}); +} + +sub run { + my ($self, %options) = @_; + + $self->manage_selection(%options); + foreach (@{$self->{instances}}) { + $self->{output}->output_add(long_msg => sprintf("[Name = %s][DatabaseName = %s][Engine = %s][Status = %s]", + $_->{Name}, $_->{DatabaseName}, $_->{Engine}, $_->{Status})); + } + + $self->{output}->output_add(severity => 'OK', + short_msg => 'List cluster:'); + $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 => ['name', 'databasename', 'engine', 'status']); +} + +sub disco_show { + my ($self, %options) = @_; + + $self->manage_selection(%options); + foreach (@{$self->{instances}}) { + $self->{output}->add_disco_entry( + name => $_->{Name}, + databasename => $_->{DatabaseName}, + engine => $_->{Engine}, + status => $_->{Status}, + ); + } +} + +1; + +__END__ + +=head1 MODE + +List RDS clusters. + +=over 8 + +=back + +=cut + diff --git a/cloud/aws/rds/mode/listinstances.pm b/cloud/aws/rds/mode/listinstances.pm new file mode 100644 index 000000000..4e5aef559 --- /dev/null +++ b/cloud/aws/rds/mode/listinstances.pm @@ -0,0 +1,101 @@ +# +# Copyright 2018 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::rds::mode::listinstances; + +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; + + $self->{version} = '1.0'; + $options{options}->add_options(arguments => + { + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::init(%options); +} + +sub manage_selection { + my ($self, %options) = @_; + + $self->{instances} = $options{custom}->rds_list_instances(region => $self->{option_results}->{region}); +} + +sub run { + my ($self, %options) = @_; + + $self->manage_selection(%options); + foreach (@{$self->{instances}}) { + $self->{output}->output_add(long_msg => sprintf("[Name = %s][AvailabilityZone = %s][Engine = %s][StorageType = %s][DBInstanceStatus = %s]", + $_->{Name}, $_->{AvailabilityZone}, $_->{Engine}, $_->{StorageType}, $_->{DBInstanceStatus})); + } + + $self->{output}->output_add(severity => 'OK', + short_msg => 'List instances:'); + $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 => ['name', 'availabilityzone', 'engine', 'storagetype', 'state']); +} + +sub disco_show { + my ($self, %options) = @_; + + $self->manage_selection(%options); + foreach (@{$self->{instances}}) { + $self->{output}->add_disco_entry( + name => $_->{Name}, + availabilityzone => $_->{AvailabilityZone}, + engine => $_->{Engine}, + storagetype => $_->{StorageType}, + state => $_->{DBInstanceStatus}, + ); + } +} + +1; + +__END__ + +=head1 MODE + +List RDS instances. + +=over 8 + +=back + +=cut + diff --git a/cloud/aws/rds/mode/network.pm b/cloud/aws/rds/mode/network.pm new file mode 100644 index 000000000..efe7ab6e3 --- /dev/null +++ b/cloud/aws/rds/mode/network.pm @@ -0,0 +1,204 @@ +# +# Copyright 2018 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::rds::mode::network; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +my %map_type = ( + "instance" => "DBInstanceIdentifier", + "cluster" => "DBClusterIdentifier", +); + +sub prefix_metric_output { + my ($self, %options) = @_; + + return ucfirst($options{instance_value}->{type}) . " '" . $options{instance_value}->{display} . "' " . $options{instance_value}->{stat} . " "; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'metric', type => 1, cb_prefix_output => 'prefix_metric_output', message_multiple => "All network metrics are ok", skipped_code => { -10 => 1 } }, + ]; + + foreach my $statistic ('minimum', 'maximum', 'average', 'sum') { + foreach my $metric ('NetworkReceiveThroughput', 'NetworkTransmitThroughput') { + my $entry = { label => lc($metric) . '-' . lc($statistic), set => { + key_values => [ { name => $metric . '_' . $statistic }, { name => 'display' }, { name => 'type' }, { name => 'stat' } ], + output_template => $metric . ': %.2f %s/s', + output_change_bytes => 1, + perfdatas => [ + { label => lc($metric) . '_' . lc($statistic), value => $metric . '_' . $statistic . '_absolute', + template => '%.2f', unit => 'B/s', min => 0, label_extra_instance => 1, instance_use => 'display_absolute' }, + ], + } + }; + push @{$self->{maps_counters}->{metric}}, $entry; + } + } +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $self->{version} = '1.0'; + $options{options}->add_options(arguments => + { + "type:s" => { name => 'type' }, + "name:s@" => { name => 'name' }, + "filter-metric:s" => { name => 'filter_metric' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + if (!defined($self->{option_results}->{type}) || $self->{option_results}->{type} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --type option."); + $self->{output}->option_exit(); + } + + if ($self->{option_results}->{type} ne 'cluster' && $self->{option_results}->{type} ne 'instance') { + $self->{output}->add_option_msg(short_msg => "Instance type '" . $self->{option_results}->{type} . "' is not handled for this mode"); + $self->{output}->option_exit(); + } + + if (!defined($self->{option_results}->{name}) || $self->{option_results}->{name} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --name option."); + $self->{output}->option_exit(); + } + + foreach my $instance (@{$self->{option_results}->{name}}) { + if ($instance ne '') { + push @{$self->{aws_instance}}, $instance; + } + } + + $self->{aws_timeframe} = defined($self->{option_results}->{timeframe}) ? $self->{option_results}->{timeframe} : 600; + $self->{aws_period} = defined($self->{option_results}->{period}) ? $self->{option_results}->{period} : 60; + + $self->{aws_statistics} = ['Average']; + if (defined($self->{option_results}->{statistic})) { + $self->{aws_statistics} = []; + foreach my $stat (@{$self->{option_results}->{statistic}}) { + if ($stat ne '') { + push @{$self->{aws_statistics}}, ucfirst(lc($stat)); + } + } + } + + foreach my $metric ('NetworkReceiveThroughput', 'NetworkTransmitThroughput') { + next if (defined($self->{option_results}->{filter_metric}) && $self->{option_results}->{filter_metric} ne '' + && $metric !~ /$self->{option_results}->{filter_metric}/); + + push @{$self->{aws_metrics}}, $metric; + } +} + +sub manage_selection { + my ($self, %options) = @_; + + my %metric_results; + foreach my $instance (@{$self->{aws_instance}}) { + $metric_results{$instance} = $options{custom}->cloudwatch_get_metrics( + region => $self->{option_results}->{region}, + namespace => 'AWS/RDS', + dimensions => [ { Name => $map_type{$self->{option_results}->{type}}, Value => $instance } ], + 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($metric_results{$instance}->{$metric}->{lc($statistic)}) && !defined($self->{option_results}->{zeroed})); + + $self->{metric}->{$instance . "_" . lc($statistic)}->{display} = $instance; + $self->{metric}->{$instance . "_" . lc($statistic)}->{stat} = lc($statistic); + $self->{metric}->{$instance . "_" . lc($statistic)}->{type} = $self->{option_results}->{type}; + $self->{metric}->{$instance . "_" . lc($statistic)}->{$metric . "_" . lc($statistic)} = defined($metric_results{$instance}->{$metric}->{lc($statistic)}) ? $metric_results{$instance}->{$metric}->{lc($statistic)} : 0; + } + } + } + + if (scalar(keys %{$self->{metric}}) <= 0) { + $self->{output}->add_option_msg(short_msg => 'No metrics. Check your options or use --zeroed option to set 0 on undefined values'); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check RDS instances network metrics. + +Example: +perl centreon_plugins.pl --plugin=cloud::aws::rds::plugin --custommode=paws --mode=network --region='eu-west-1' +--type='cluster' --name='centreon-db-ppd-cluster' --filter-metric='Transmit' --statistic='sum' +--critical-networktransmitthroughput-sum='10' --verbose + +Works for the following database engines : aurora, mysql, mariadb. + +See 'https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/rds-metricscollected.html' for more informations. + +Default statistic: 'average' / All satistics are valid. + +=over 8 + +=item B<--type> + +Set the instance type (Required) (Can be: 'cluster', 'instance'). + +=item B<--name> + +Set the instance name (Required) (Can be multiple). + +=item B<--filter-metric> + +Filter metrics (Can be: 'NetworkReceiveThroughput', 'NetworkTransmitThroughput') +(Can be a regexp). + +=item B<--warning-$metric$-$statistic$> + +Thresholds warning ($metric$ can be: 'networkreceivethroughput', 'networktransmitthroughput', +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=item B<--critical-$metric$-$statistic$> + +Thresholds warning ($metric$ can be: 'networkreceivethroughput', 'networktransmitthroughput', +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=back + +=cut diff --git a/cloud/aws/rds/mode/queries.pm b/cloud/aws/rds/mode/queries.pm new file mode 100644 index 000000000..a05956220 --- /dev/null +++ b/cloud/aws/rds/mode/queries.pm @@ -0,0 +1,221 @@ +# +# Copyright 2018 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::rds::mode::queries; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +my %map_type = ( + "instance" => "DBInstanceIdentifier", + "cluster" => "DBClusterIdentifier", +); + +sub prefix_metric_output { + my ($self, %options) = @_; + + return ucfirst($options{instance_value}->{type}) . " '" . $options{instance_value}->{display} . "' " . $options{instance_value}->{stat} . " "; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'metric', type => 1, cb_prefix_output => 'prefix_metric_output', message_multiple => "All queries metrics are ok", skipped_code => { -10 => 1 } }, + ]; + + foreach my $statistic ('minimum', 'maximum', 'average', 'sum') { + foreach my $metric ('Queries', 'InsertThroughput', 'DeleteThroughput', 'SelectThroughput', 'UpdateThroughput', 'DMLThroughput', 'DDLThroughput') { + my $entry = { label => lc($metric) . '-' . lc($statistic), set => { + key_values => [ { name => $metric . '_' . $statistic }, { name => 'display' }, { name => 'type' }, { name => 'stat' } ], + output_template => $metric . ': %d queries/s', + perfdatas => [ + { label => lc($metric) . '_' . lc($statistic), value => $metric . '_' . $statistic . '_absolute', + template => '%d', unit => 'queries/s', min => 0, label_extra_instance => 1, instance_use => 'display_absolute' }, + ], + } + }; + push @{$self->{maps_counters}->{metric}}, $entry; + } + foreach my $metric ('InsertLatency', 'DeleteLatency', 'SelectLatency', 'UpdateLatency', 'DMLLatency', 'DDLLatency') { + my $entry = { label => lc($metric) . '-' . lc($statistic), set => { + key_values => [ { name => $metric . '_' . $statistic }, { name => 'display' }, { name => 'type' }, { name => 'stat' } ], + output_template => $metric . ': %.2f ms', + perfdatas => [ + { label => lc($metric) . '_' . lc($statistic), value => $metric . '_' . $statistic . '_absolute', + template => '%.2f', unit => 'ms', min => 0, label_extra_instance => 1, instance_use => 'display_absolute' }, + ], + } + }; + push @{$self->{maps_counters}->{metric}}, $entry; + } + } +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $self->{version} = '1.0'; + $options{options}->add_options(arguments => + { + "type:s" => { name => 'type' }, + "name:s@" => { name => 'name' }, + "filter-metric:s" => { name => 'filter_metric' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + if (!defined($self->{option_results}->{type}) || $self->{option_results}->{type} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --type option."); + $self->{output}->option_exit(); + } + + if ($self->{option_results}->{type} ne 'cluster' && $self->{option_results}->{type} ne 'instance') { + $self->{output}->add_option_msg(short_msg => "Instance type '" . $self->{option_results}->{type} . "' is not handled for this mode"); + $self->{output}->option_exit(); + } + + if (!defined($self->{option_results}->{name}) || $self->{option_results}->{name} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --name option."); + $self->{output}->option_exit(); + } + + foreach my $instance (@{$self->{option_results}->{name}}) { + if ($instance ne '') { + push @{$self->{aws_instance}}, $instance; + } + } + + $self->{aws_timeframe} = defined($self->{option_results}->{timeframe}) ? $self->{option_results}->{timeframe} : 600; + $self->{aws_period} = defined($self->{option_results}->{period}) ? $self->{option_results}->{period} : 60; + + $self->{aws_statistics} = ['Average']; + if (defined($self->{option_results}->{statistic})) { + $self->{aws_statistics} = []; + foreach my $stat (@{$self->{option_results}->{statistic}}) { + if ($stat ne '') { + push @{$self->{aws_statistics}}, ucfirst(lc($stat)); + } + } + } + + foreach my $metric ('Queries', 'InsertThroughput', 'DeleteThroughput', 'SelectThroughput', 'UpdateThroughput', + 'DMLThroughput', 'DDLThroughput', 'InsertLatency', 'DeleteLatency', 'SelectLatency', 'UpdateLatency', + 'DMLLatency', 'DDLLatency') { + next if (defined($self->{option_results}->{filter_metric}) && $self->{option_results}->{filter_metric} ne '' + && $metric !~ /$self->{option_results}->{filter_metric}/); + + push @{$self->{aws_metrics}}, $metric; + } +} + +sub manage_selection { + my ($self, %options) = @_; + + my %metric_results; + foreach my $instance (@{$self->{aws_instance}}) { + $metric_results{$instance} = $options{custom}->cloudwatch_get_metrics( + region => $self->{option_results}->{region}, + namespace => 'AWS/RDS', + dimensions => [ { Name => $map_type{$self->{option_results}->{type}}, Value => $instance } ], + 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($metric_results{$instance}->{$metric}->{lc($statistic)}) && !defined($self->{option_results}->{zeroed})); + + $self->{metric}->{$instance . "_" . lc($statistic)}->{display} = $instance; + $self->{metric}->{$instance . "_" . lc($statistic)}->{stat} = lc($statistic); + $self->{metric}->{$instance . "_" . lc($statistic)}->{type} = $self->{option_results}->{type}; + $self->{metric}->{$instance . "_" . lc($statistic)}->{$metric . "_" . lc($statistic)} = defined($metric_results{$instance}->{$metric}->{lc($statistic)}) ? $metric_results{$instance}->{$metric}->{lc($statistic)} : 0; + } + } + } + + if (scalar(keys %{$self->{metric}}) <= 0) { + $self->{output}->add_option_msg(short_msg => 'No metrics. Check your options or use --zeroed option to set 0 on undefined values'); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check RDS instances queries per second. + +Example: +perl centreon_plugins.pl --plugin=cloud::aws::rds::plugin --custommode=paws --mode=queries --region='eu-west-1' +--type='instance' --name='centreon-db-ppd' --filter-metric='' --statistic='average' +--critical-queries-average='10' --verbose + +Works for the following database engines : aurora. + +See 'https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/rds-metricscollected.html' for more informations. + +Default statistic: 'average' / All satistics are valid. + +=over 8 + +=item B<--type> + +Set the instance type (Required) (Can be: 'cluster', 'instance'). + +=item B<--name> + +Set the instance name (Required) (Can be multiple). + +=item B<--filter-metric> + +Filter metrics (Can be: 'Queries', 'InsertThroughput', 'DeleteThroughput', 'SelectThroughput', 'UpdateThroughput', +'DMLThroughput', 'DDLThroughput', 'InsertLatency', 'DeleteLatency', 'SelectLatency', 'UpdateLatency', +'DMLLatency', 'DDLLatency') +(Can be a regexp). + +=item B<--warning-$metric$-$statistic$> + +Thresholds warning ($metric$ can be: 'queries', 'insertthroughput', 'deletethroughput', 'selectthroughput', +'updatethroughput', 'dmlthroughput', 'ddlthroughput', 'insertlatency', 'deletelatency', 'selectlatency', +'updatelatency', 'dmllatency', 'ddllatency', $statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=item B<--critical-$metric$-$statistic$> + +Thresholds critical ($metric$ can be: 'queries', 'insertthroughput', 'deletethroughput', 'selectthroughput', +'updatethroughput', 'dmlthroughput', 'ddlthroughput', 'insertlatency', 'deletelatency', 'selectlatency', +'updatelatency', 'dmllatency', 'ddllatency', $statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=back + +=cut diff --git a/cloud/aws/rds/mode/transactions.pm b/cloud/aws/rds/mode/transactions.pm new file mode 100644 index 000000000..199d463bb --- /dev/null +++ b/cloud/aws/rds/mode/transactions.pm @@ -0,0 +1,215 @@ +# +# Copyright 2018 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::rds::mode::transactions; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +my %map_type = ( + "instance" => "DBInstanceIdentifier", + "cluster" => "DBClusterIdentifier", +); + +sub prefix_metric_output { + my ($self, %options) = @_; + + return ucfirst($options{instance_value}->{type}) . " '" . $options{instance_value}->{display} . "' " . $options{instance_value}->{stat} . " "; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'metric', type => 1, cb_prefix_output => 'prefix_metric_output', message_multiple => "All transactions metrics are ok", skipped_code => { -10 => 1 } }, + ]; + + foreach my $statistic ('minimum', 'maximum', 'average', 'sum') { + foreach my $metric ('ActiveTransactions', 'BlockedTransactions', 'CommitThroughput') { + my $entry = { label => lc($metric) . '-' . lc($statistic), set => { + key_values => [ { name => $metric . '_' . $statistic }, { name => 'display' }, { name => 'type' }, { name => 'stat' } ], + output_template => $metric . ': %d ops', + perfdatas => [ + { label => lc($metric) . '_' . lc($statistic), value => $metric . '_' . $statistic . '_absolute', + template => '%d', unit => 'ops', min => 0, label_extra_instance => 1, instance_use => 'display_absolute' }, + ], + } + }; + push @{$self->{maps_counters}->{metric}}, $entry; + } + foreach my $metric ('CommitLatency') { + my $entry = { label => lc($metric) . '-' . lc($statistic), set => { + key_values => [ { name => $metric . '_' . $statistic }, { name => 'display' }, { name => 'type' }, { name => 'stat' } ], + output_template => $metric . ': %.2f ms', + perfdatas => [ + { label => lc($metric) . '_' . lc($statistic), value => $metric . '_' . $statistic . '_absolute', + template => '%.2f', unit => 'ms', min => 0, label_extra_instance => 1, instance_use => 'display_absolute' }, + ], + } + }; + push @{$self->{maps_counters}->{metric}}, $entry; + } + } +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $self->{version} = '1.0'; + $options{options}->add_options(arguments => + { + "type:s" => { name => 'type' }, + "name:s@" => { name => 'name' }, + "filter-metric:s" => { name => 'filter_metric' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + if (!defined($self->{option_results}->{type}) || $self->{option_results}->{type} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --type option."); + $self->{output}->option_exit(); + } + + if ($self->{option_results}->{type} ne 'cluster' && $self->{option_results}->{type} ne 'instance') { + $self->{output}->add_option_msg(short_msg => "Instance type '" . $self->{option_results}->{type} . "' is not handled for this mode"); + $self->{output}->option_exit(); + } + + if (!defined($self->{option_results}->{name}) || $self->{option_results}->{name} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --name option."); + $self->{output}->option_exit(); + } + + foreach my $instance (@{$self->{option_results}->{name}}) { + if ($instance ne '') { + push @{$self->{aws_instance}}, $instance; + } + } + + $self->{aws_timeframe} = defined($self->{option_results}->{timeframe}) ? $self->{option_results}->{timeframe} : 600; + $self->{aws_period} = defined($self->{option_results}->{period}) ? $self->{option_results}->{period} : 60; + + $self->{aws_statistics} = ['Average']; + if (defined($self->{option_results}->{statistic})) { + $self->{aws_statistics} = []; + foreach my $stat (@{$self->{option_results}->{statistic}}) { + if ($stat ne '') { + push @{$self->{aws_statistics}}, ucfirst(lc($stat)); + } + } + } + + foreach my $metric ('ActiveTransactions', 'BlockedTransactions', 'CommitThroughput', 'CommitLatency') { + next if (defined($self->{option_results}->{filter_metric}) && $self->{option_results}->{filter_metric} ne '' + && $metric !~ /$self->{option_results}->{filter_metric}/); + + push @{$self->{aws_metrics}}, $metric; + } +} + +sub manage_selection { + my ($self, %options) = @_; + + my %metric_results; + foreach my $instance (@{$self->{aws_instance}}) { + $metric_results{$instance} = $options{custom}->cloudwatch_get_metrics( + region => $self->{option_results}->{region}, + namespace => 'AWS/RDS', + dimensions => [ { Name => $map_type{$self->{option_results}->{type}}, Value => $instance } ], + 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($metric_results{$instance}->{$metric}->{lc($statistic)}) && !defined($self->{option_results}->{zeroed})); + + $self->{metric}->{$instance . "_" . lc($statistic)}->{display} = $instance; + $self->{metric}->{$instance . "_" . lc($statistic)}->{stat} = lc($statistic); + $self->{metric}->{$instance . "_" . lc($statistic)}->{type} = $self->{option_results}->{type}; + $self->{metric}->{$instance . "_" . lc($statistic)}->{$metric . "_" . lc($statistic)} = defined($metric_results{$instance}->{$metric}->{lc($statistic)}) ? $metric_results{$instance}->{$metric}->{lc($statistic)} : 0; + } + } + } + + if (scalar(keys %{$self->{metric}}) <= 0) { + $self->{output}->add_option_msg(short_msg => 'No metrics. Check your options or use --zeroed option to set 0 on undefined values'); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check RDS instances transactions per second. + +Example: +perl centreon_plugins.pl --plugin=cloud::aws::rds::plugin --custommode=paws --mode=transactions --region='eu-west-1' +--type='instance' --name='centreon-db-ppd' --filter-metric='' --statistic='average' +--critical-blockedtransactions-average='1' --verbose + +Works for the following database engines : aurora. + +See 'https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/rds-metricscollected.html' for more informations. + +Default statistic: 'average' / All satistics are valid. + +=over 8 + +=item B<--type> + +Set the instance type (Required) (Can be: 'cluster', 'instance'). + +=item B<--name> + +Set the instance name (Required) (Can be multiple). + +=item B<--filter-metric> + +Filter metrics (Can be: 'ActiveTransactions', 'BlockedTransactions', 'CommitThroughput', 'CommitLatency') +(Can be a regexp). + +=item B<--warning-$metric$-$statistic$> + +Thresholds warning ($metric$ can be: 'activetransactions', 'blockedtransactions', 'committhroughput', +'commitlatency', $statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=item B<--critical-$metric$-$statistic$> + +Thresholds critical ($metric$ can be: 'activetransactions', 'blockedtransactions', 'committhroughput', +'commitlatency', $statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=back + +=cut diff --git a/cloud/aws/rds/mode/volume.pm b/cloud/aws/rds/mode/volume.pm new file mode 100644 index 000000000..5d93f5216 --- /dev/null +++ b/cloud/aws/rds/mode/volume.pm @@ -0,0 +1,271 @@ +# +# Copyright 2018 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::rds::mode::volume; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +my %map_type = ( + "cluster" => "DbClusterIdentifier", +); + + +my $instance_mode; + +sub prefix_metric_output { + my ($self, %options) = @_; + + return ucfirst($options{instance_value}->{type}) . " '" . $options{instance_value}->{display} . "' " . $options{instance_value}->{stat} . " "; +} + +sub custom_metric_calc { + my ($self, %options) = @_; + + $self->{result_values}->{timeframe} = $options{new_datas}->{$self->{instance} . '_timeframe'}; + $self->{result_values}->{value} = $options{new_datas}->{$self->{instance} . '_' . $options{extra_options}->{metric} . '_' . $options{extra_options}->{stat}}; + $self->{result_values}->{value_per_sec} = $self->{result_values}->{value} / $self->{result_values}->{timeframe}; + $self->{result_values}->{stat} = $options{extra_options}->{stat}; + $self->{result_values}->{metric} = $options{extra_options}->{metric}; + $self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_display'}; + return 0; +} + +sub custom_metric_threshold { + my ($self, %options) = @_; + + my $exit = $self->{perfdata}->threshold_check(value => defined($instance_mode->{option_results}->{per_sec}) ? $self->{result_values}->{value_per_sec} : $self->{result_values}->{value}, + threshold => [ { label => 'critical-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat}), exit_litteral => 'critical' }, + { label => 'warning-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat}), exit_litteral => 'warning' } ]); + return $exit; +} + +sub custom_ops_perfdata { + my ($self, %options) = @_; + + my $extra_label = ''; + $extra_label = '_' . lc($self->{result_values}->{display}) if (!defined($options{extra_instance}) || $options{extra_instance} != 0); + + $self->{output}->perfdata_add(label => lc($self->{result_values}->{metric}) . "_" . lc($self->{result_values}->{stat}) . $extra_label, + unit => defined($instance_mode->{option_results}->{per_sec}) ? 'ops/s' : 'ops', + value => sprintf("%.2f", defined($instance_mode->{option_results}->{per_sec}) ? $self->{result_values}->{value_per_sec} : $self->{result_values}->{value}), + warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat})), + critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . lc($self->{result_values}->{metric}) . "-" . lc($self->{result_values}->{stat})), + ); +} + +sub custom_ops_output { + my ($self, %options) = @_; + + my $msg =""; + + if (defined($instance_mode->{option_results}->{per_sec})) { + $msg = sprintf("%s: %.2f ops/s", $self->{result_values}->{metric}, $self->{result_values}->{value_per_sec}); + } else { + $msg = sprintf("%s: %.2f ops", $self->{result_values}->{metric}, $self->{result_values}->{value}); + } + + return $msg; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'metric', type => 1, cb_prefix_output => 'prefix_metric_output', message_multiple => "All volume metrics are ok", skipped_code => { -10 => 1 } }, + ]; + + foreach my $statistic ('minimum', 'maximum', 'average', 'sum') { + foreach my $metric ('VolumeBytesUsed') { + my $entry = { label => lc($metric) . '-' . lc($statistic), set => { + key_values => [ { name => $metric . '_' . $statistic }, { name => 'display' }, { name => 'type' }, { name => 'stat' }, { name => 'timeframe' } ], + output_template => $metric . ': %.2f %s', + output_change_bytes => 1, + perfdatas => [ + { label => lc($metric) . '_' . lc($statistic), value => $metric . '_' . $statistic . '_absolute', + template => '%.2f', unit => 'B', min => 0, label_extra_instance => 1, instance_use => 'display_absolute' }, + ], + } + }; + push @{$self->{maps_counters}->{metric}}, $entry; + } + foreach my $metric ('VolumeReadIOPs', 'VolumeWriteIOPs') { + my $entry = { label => lc($metric) . '-' . lc($statistic), set => { + key_values => [ { name => $metric . '_' . $statistic }, { name => 'display' }, { name => 'stat' }, { name => 'timeframe' } ], + closure_custom_calc => $self->can('custom_metric_calc'), + closure_custom_calc_extra_options => { metric => $metric, stat => $statistic }, + closure_custom_output => $self->can('custom_ops_output'), + closure_custom_perfdata => $self->can('custom_ops_perfdata'), + closure_custom_threshold_check => $self->can('custom_metric_threshold'), + } + }; + push @{$self->{maps_counters}->{metric}}, $entry; + } + } +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $self->{version} = '1.0'; + $options{options}->add_options(arguments => + { + "type:s" => { name => 'type', default => 'cluster' }, + "name:s@" => { name => 'name' }, + "filter-metric:s" => { name => 'filter_metric' }, + "per-sec" => { name => 'per_sec' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + if (!defined($self->{option_results}->{type}) || $self->{option_results}->{type} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --type option."); + $self->{output}->option_exit(); + } + + if ($self->{option_results}->{type} ne 'cluster') { + $self->{output}->add_option_msg(short_msg => "Instance type '" . $self->{option_results}->{type} . "' is not handled for this mode"); + $self->{output}->option_exit(); + } + + if (!defined($self->{option_results}->{name}) || $self->{option_results}->{name} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --name option."); + $self->{output}->option_exit(); + } + + foreach my $instance (@{$self->{option_results}->{name}}) { + if ($instance ne '') { + push @{$self->{aws_instance}}, $instance; + } + } + + $self->{aws_timeframe} = defined($self->{option_results}->{timeframe}) ? $self->{option_results}->{timeframe} : 600; + $self->{aws_period} = defined($self->{option_results}->{period}) ? $self->{option_results}->{period} : 60; + + $self->{aws_statistics} = ['Average']; + if (defined($self->{option_results}->{statistic})) { + $self->{aws_statistics} = []; + foreach my $stat (@{$self->{option_results}->{statistic}}) { + if ($stat ne '') { + push @{$self->{aws_statistics}}, ucfirst(lc($stat)); + } + } + } + + foreach my $metric ('VolumeBytesUsed', 'VolumeReadIOPs', 'VolumeWriteIOPs') { + next if (defined($self->{option_results}->{filter_metric}) && $self->{option_results}->{filter_metric} ne '' + && $metric !~ /$self->{option_results}->{filter_metric}/); + + push @{$self->{aws_metrics}}, $metric; + } + + $instance_mode = $self; +} + +sub manage_selection { + my ($self, %options) = @_; + + my %metric_results; + foreach my $instance (@{$self->{aws_instance}}) { + $metric_results{$instance} = $options{custom}->cloudwatch_get_metrics( + region => $self->{option_results}->{region}, + namespace => 'AWS/RDS', + dimensions => [ { Name => $map_type{$self->{option_results}->{type}}, Value => $instance } , { Name => 'EngineName', Value => 'aurora' } ], + 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($metric_results{$instance}->{$metric}->{lc($statistic)}) && !defined($self->{option_results}->{zeroed})); + + $self->{metric}->{$instance . "_" . lc($statistic)}->{display} = $instance; + $self->{metric}->{$instance . "_" . lc($statistic)}->{stat} = lc($statistic); + $self->{metric}->{$instance . "_" . lc($statistic)}->{type} = $self->{option_results}->{type}; + $self->{metric}->{$instance . "_" . lc($statistic)}->{timeframe} = $self->{aws_timeframe}; + $self->{metric}->{$instance . "_" . lc($statistic)}->{$metric . "_" . lc($statistic)} = defined($metric_results{$instance}->{$metric}->{lc($statistic)}) ? $metric_results{$instance}->{$metric}->{lc($statistic)} : 0; + } + } + } + + if (scalar(keys %{$self->{metric}}) <= 0) { + $self->{output}->add_option_msg(short_msg => 'No metrics. Check your options or use --zeroed option to set 0 on undefined values'); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check RDS instances volume metrics. + +Example: +perl centreon_plugins.pl --plugin=cloud::aws::rds::plugin --custommode=paws --mode=volume --region='eu-west-1' +--type='cluster' --name='centreon-db-ppd-cluster' --filter-metric='' --statistic='average' +--critical-volumebytesused-average='10' --verbose + +Works for the following database engines : aurora. + +See 'https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/rds-metricscollected.html' for more informations. + +Default statistic: 'average' / All satistics are valid. + +=over 8 + +=item B<--type> + +Set the instance type (Required) (Can be: 'cluster'). + +=item B<--name> + +Set the instance name (Required) (Can be multiple). + +=item B<--filter-metric> + +Filter metrics (Can be: 'VolumeBytesUsed', 'VolumeReadIOPs', 'VolumeWriteIOPs') +(Can be a regexp). + +=item B<--warning-$metric$-$statistic$> + +Thresholds warning ($metric$ can be: 'volumebytesused', 'volumereadiops', 'volumewriteiops', +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=item B<--critical-$metric$-$statistic$> + +Thresholds critical ($metric$ can be: 'volumebytesused', 'volumereadiops', 'volumewriteiops', +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=back + +=cut diff --git a/cloud/aws/rds/plugin.pm b/cloud/aws/rds/plugin.pm new file mode 100644 index 000000000..ed49a0688 --- /dev/null +++ b/cloud/aws/rds/plugin.pm @@ -0,0 +1,59 @@ +# +# Copyright 2018 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::rds::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} } = ( + 'connections' => 'cloud::aws::rds::mode::connections', + 'cpu' => 'cloud::aws::rds::mode::cpu', + 'diskio' => 'cloud::aws::rds::mode::diskio', + 'instance-status' => 'cloud::aws::rds::mode::instancestatus', + 'list-clusters' => 'cloud::aws::rds::mode::listclusters', + 'list-instances' => 'cloud::aws::rds::mode::listinstances', + 'network' => 'cloud::aws::rds::mode::network', + 'queries' => 'cloud::aws::rds::mode::queries', + 'transactions' => 'cloud::aws::rds::mode::transactions', + 'volume' => 'cloud::aws::rds::mode::volume', + ); + + $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 Relational Database Service (Amazon RDS). + +=cut diff --git a/cloud/aws/s3/mode/bucketsize.pm b/cloud/aws/s3/mode/bucketsize.pm new file mode 100644 index 000000000..ccbe63ebe --- /dev/null +++ b/cloud/aws/s3/mode/bucketsize.pm @@ -0,0 +1,200 @@ +# +# Copyright 2018 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::s3::mode::bucketsize; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +sub prefix_metric_output { + my ($self, %options) = @_; + + return "Bucket '" . $options{instance_value}->{display} . "' [" . ucfirst($options{instance_value}->{storage_type}) . "] " . $options{instance_value}->{stat} . " "; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'metric', type => 1, cb_prefix_output => 'prefix_metric_output', message_multiple => "All size metrics are ok", skipped_code => { -10 => 1 } }, + ]; + + foreach my $statistic ('minimum', 'maximum', 'average', 'sum') { + foreach my $metric ('BucketSizeBytes') { + foreach my $storage_type ('StandardStorage', 'StandardIAStorage', 'ReducedRedundancyStorage') { + my $entry = { label => lc($metric) . '-' . lc($storage_type) . '-' . lc($statistic), set => { + key_values => [ { name => $metric . '_' . $storage_type . '_' . $statistic }, { name => 'display' }, { name => 'storage_type' }, { name => 'stat' } ], + output_template => $metric . ': %d %s', + output_change_bytes => 1, + perfdatas => [ + { label => lc($metric) . '_' . lc($storage_type) . '_' . lc($statistic), value => $metric . '_' . $storage_type . '_' . $statistic . '_absolute', + template => '%d', unit => 'B', min => 0, label_extra_instance => 1, instance_use => 'display_absolute' }, + ], + } + }; + push @{$self->{maps_counters}->{metric}}, $entry; + } + } + } +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $self->{version} = '1.0'; + $options{options}->add_options(arguments => + { + "name:s@" => { name => 'name' }, + "storage-type:s@" => { name => 'storage_type' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + if (!defined($self->{option_results}->{name}) || $self->{option_results}->{name} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --name option."); + $self->{output}->option_exit(); + } + + foreach my $instance (@{$self->{option_results}->{name}}) { + if ($instance ne '') { + push @{$self->{aws_instance}}, $instance; + } + } + + $self->{aws_timeframe} = defined($self->{option_results}->{timeframe}) ? $self->{option_results}->{timeframe} : 172800; + $self->{aws_period} = defined($self->{option_results}->{period}) ? $self->{option_results}->{period} : 86400; + + $self->{aws_statistics} = ['Average']; + if (defined($self->{option_results}->{statistic})) { + $self->{aws_statistics} = []; + foreach my $stat (@{$self->{option_results}->{statistic}}) { + if ($stat ne '') { + push @{$self->{aws_statistics}}, ucfirst(lc($stat)); + } + } + } + + foreach my $metric ('BucketSizeBytes') { + next if (defined($self->{option_results}->{filter_metric}) && $self->{option_results}->{filter_metric} ne '' + && $metric !~ /$self->{option_results}->{filter_metric}/); + + push @{$self->{aws_metrics}}, $metric; + } + + $self->{aws_storage_type} = ['StandardStorage']; + if (defined($self->{option_results}->{storage_type})) { + $self->{aws_storage_type} = []; + foreach my $storage_type (@{$self->{option_results}->{storage_type}}) { + if ($storage_type ne '') { + push @{$self->{aws_storage_type}}, $storage_type; + } + } + } +} + +sub manage_selection { + my ($self, %options) = @_; + + my %metric_results; + foreach my $instance (@{$self->{aws_instance}}) { + foreach my $storage_type (@{$self->{aws_storage_type}}) { + $metric_results{$instance} = $options{custom}->cloudwatch_get_metrics( + region => $self->{option_results}->{region}, + namespace => 'AWS/S3', + dimensions => [ {Name => 'StorageType', Value => $storage_type }, { Name => 'BucketName', Value => $instance } ], + 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($metric_results{$instance}->{$metric}->{lc($statistic)}) && !defined($self->{option_results}->{zeroed})); + + $self->{metric}->{$instance . "_" . $storage_type . "_" . lc($statistic)}->{display} = $instance; + $self->{metric}->{$instance . "_" . $storage_type . "_" . lc($statistic)}->{storage_type} = $storage_type; + $self->{metric}->{$instance . "_" . $storage_type . "_" . lc($statistic)}->{stat} = lc($statistic); + $self->{metric}->{$instance . "_" . $storage_type . "_" . lc($statistic)}->{$metric . "_" . $storage_type . "_" . lc($statistic)} = defined($metric_results{$instance}->{$metric}->{lc($statistic)}) ? $metric_results{$instance}->{$metric}->{lc($statistic)} : 0; + } + } + } + } + + if (scalar(keys %{$self->{metric}}) <= 0) { + $self->{output}->add_option_msg(short_msg => 'No metrics. Check your options or use --zeroed option to set 0 on undefined values'); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check S3 buckets size. + +Example: +perl centreon_plugins.pl --plugin=cloud::aws::s3::plugin --custommode=paws --mode=bucket-size --region='eu-west-1' +--name='centreon-iso' --critical-bucketsizebytes-standardiastorage-average='1000' +--storage-type='StandardIAStorage' --verbose + +See 'https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/s3-metricscollected.html' for more informations. + +Default statistic: 'average' / All satistics are valid. + +=over 8 + +=item B<--name> + +Set the instance name (Required) (Can be multiple). + +=item B<--storage-type> + +Set the storage type of the bucket (Default: 'StandardStorage') +(Can be multiple: 'StandardStorage', 'StandardIAStorage', 'ReducedRedundancyStorage'). + +=item B<--warning-$metric$-$storagetype$-$statistic$> + +Thresholds warning ($metric$ can be: 'bucketsizebytes', +$storagetype$ can be: 'standardstorage', +'standardiastorage', 'reducedredundancystorage', +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=item B<--critical-$metric$-$storagetype$-$statistic$> + +Thresholds critical ($metric$ can be: 'bucketsizebytes', +$storagetype$ can be: 'standardstorage', +'standardiastorage', 'reducedredundancystorage', +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=back + +=cut diff --git a/cloud/aws/s3/mode/objects.pm b/cloud/aws/s3/mode/objects.pm new file mode 100644 index 000000000..f20569cf8 --- /dev/null +++ b/cloud/aws/s3/mode/objects.pm @@ -0,0 +1,174 @@ +# +# Copyright 2018 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::s3::mode::objects; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +sub prefix_metric_output { + my ($self, %options) = @_; + + return "Bucket '" . $options{instance_value}->{display} . "' " . $options{instance_value}->{stat} . " "; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'metric', type => 1, cb_prefix_output => 'prefix_metric_output', message_multiple => "All objects metrics are ok", skipped_code => { -10 => 1 } }, + ]; + + foreach my $statistic ('minimum', 'maximum', 'average', 'sum') { + foreach my $metric ('NumberOfObjects') { + my $entry = { label => lc($metric) . '-' . lc($statistic), set => { + key_values => [ { name => $metric . '_' . $statistic }, { name => 'display' }, { name => 'stat' } ], + output_template => $metric . ': %d objects', + perfdatas => [ + { label => lc($metric) . '_' . lc($statistic), value => $metric . '_' . $statistic . '_absolute', + template => '%d', unit => 'objects', label_extra_instance => 1, instance_use => 'display_absolute' }, + ], + } + }; + push @{$self->{maps_counters}->{metric}}, $entry; + } + } +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $self->{version} = '1.0'; + $options{options}->add_options(arguments => + { + "name:s@" => { name => 'name' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + if (!defined($self->{option_results}->{name}) || $self->{option_results}->{name} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --name option."); + $self->{output}->option_exit(); + } + + foreach my $instance (@{$self->{option_results}->{name}}) { + if ($instance ne '') { + push @{$self->{aws_instance}}, $instance; + } + } + + $self->{aws_timeframe} = defined($self->{option_results}->{timeframe}) ? $self->{option_results}->{timeframe} : 172800; + $self->{aws_period} = defined($self->{option_results}->{period}) ? $self->{option_results}->{period} : 86400; + + $self->{aws_statistics} = ['Average']; + if (defined($self->{option_results}->{statistic})) { + $self->{aws_statistics} = []; + foreach my $stat (@{$self->{option_results}->{statistic}}) { + if ($stat ne '') { + push @{$self->{aws_statistics}}, ucfirst(lc($stat)); + } + } + } + + foreach my $metric ('NumberOfObjects') { + next if (defined($self->{option_results}->{filter_metric}) && $self->{option_results}->{filter_metric} ne '' + && $metric !~ /$self->{option_results}->{filter_metric}/); + + push @{$self->{aws_metrics}}, $metric; + } +} + +sub manage_selection { + my ($self, %options) = @_; + + my %metric_results; + foreach my $instance (@{$self->{aws_instance}}) { + $metric_results{$instance} = $options{custom}->cloudwatch_get_metrics( + region => $self->{option_results}->{region}, + namespace => 'AWS/S3', + dimensions => [ {Name => 'StorageType', Value => 'AllStorageTypes' }, { Name => 'BucketName', Value => $instance } ], + 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($metric_results{$instance}->{$metric}->{lc($statistic)}) && !defined($self->{option_results}->{zeroed})); + + $self->{metric}->{$instance . "_" . lc($statistic)}->{display} = $instance; + $self->{metric}->{$instance . "_" . lc($statistic)}->{stat} = lc($statistic); + $self->{metric}->{$instance . "_" . lc($statistic)}->{type} = $self->{option_results}->{type}; + $self->{metric}->{$instance . "_" . lc($statistic)}->{$metric . "_" . lc($statistic)} = defined($metric_results{$instance}->{$metric}->{lc($statistic)}) ? $metric_results{$instance}->{$metric}->{lc($statistic)} : 0; + } + } + } + + if (scalar(keys %{$self->{metric}}) <= 0) { + $self->{output}->add_option_msg(short_msg => 'No metrics. Check your options or use --zeroed option to set 0 on undefined values'); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check S3 buckets number of objects. + +Example: +perl centreon_plugins.pl --plugin=cloud::aws::s3::plugin --custommode=paws --mode=objects --region='eu-west-1' +--name='centreon-iso' --critical-numberofobjects-average='10' --verbose + +See 'https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/s3-metricscollected.html' for more informations. + +Default statistic: 'average' / All satistics are valid. + +=over 8 + +=item B<--name> + +Set the instance name (Required) (Can be multiple). + +=item B<--warning-$metric$-$statistic$> + +Thresholds warning ($metric$ can be: 'numberofobjects', +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=item B<--critical-$metric$-$statistic$> + +Thresholds critical ($metric$ can be: 'numberofobjects', +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=back + +=cut diff --git a/cloud/aws/s3/mode/requests.pm b/cloud/aws/s3/mode/requests.pm new file mode 100644 index 000000000..ce67a94a6 --- /dev/null +++ b/cloud/aws/s3/mode/requests.pm @@ -0,0 +1,180 @@ +# +# Copyright 2018 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::s3::mode::requests; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +sub prefix_metric_output { + my ($self, %options) = @_; + + return "Bucket '" . $options{instance_value}->{display} . "' " . $options{instance_value}->{stat} . " "; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'metric', type => 1, cb_prefix_output => 'prefix_metric_output', message_multiple => "All requests metrics are ok", skipped_code => { -10 => 1 } }, + ]; + + foreach my $statistic ('minimum', 'maximum', 'average', 'sum') { + foreach my $metric ('AllRequests', 'GetRequests', 'PutRequests', 'DeleteRequests', 'HeadRequests', 'PostRequests', 'ListRequests') { + my $entry = { label => lc($metric) . '-' . lc($statistic), set => { + key_values => [ { name => $metric . '_' . $statistic }, { name => 'display' }, { name => 'stat' } ], + output_template => $metric . ': %d requests', + perfdatas => [ + { label => lc($metric) . '_' . lc($statistic), value => $metric . '_' . $statistic . '_absolute', + template => '%d', unit => 'requests', min => 0, label_extra_instance => 1, instance_use => 'display_absolute' }, + ], + } + }; + push @{$self->{maps_counters}->{metric}}, $entry; + } + } +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $self->{version} = '1.0'; + $options{options}->add_options(arguments => + { + "name:s@" => { name => 'name' }, + "filter-metric:s" => { name => 'filter_metric' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + if (!defined($self->{option_results}->{region}) || $self->{option_results}->{region} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --region option."); + $self->{output}->option_exit(); + } + + if (!defined($self->{option_results}->{name}) || $self->{option_results}->{name} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --name option."); + $self->{output}->option_exit(); + } + + foreach my $instance (@{$self->{option_results}->{name}}) { + if ($instance ne '') { + push @{$self->{aws_instance}}, $instance; + } + } + + $self->{aws_timeframe} = defined($self->{option_results}->{timeframe}) ? $self->{option_results}->{timeframe} : 600; + $self->{aws_period} = defined($self->{option_results}->{period}) ? $self->{option_results}->{period} : 60; + + $self->{aws_statistics} = ['Sum']; + + foreach my $metric ('AllRequests', 'GetRequests', 'PutRequests', 'DeleteRequests', + 'HeadRequests', 'PostRequests', 'ListRequests') { + next if (defined($self->{option_results}->{filter_metric}) && $self->{option_results}->{filter_metric} ne '' + && $metric !~ /$self->{option_results}->{filter_metric}/); + + push @{$self->{aws_metrics}}, $metric; + } +} + +sub manage_selection { + my ($self, %options) = @_; + + my %metric_results; + foreach my $instance (@{$self->{aws_instance}}) { + $metric_results{$instance} = $options{custom}->cloudwatch_get_metrics( + region => $self->{option_results}->{region}, + namespace => 'AWS/S3', + dimensions => [ { Name => 'BucketName', Value => $instance } ], + 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($metric_results{$instance}->{$metric}->{lc($statistic)}) && !defined($self->{option_results}->{zeroed})); + + $self->{metric}->{$instance . "_" . lc($statistic)}->{display} = $instance; + $self->{metric}->{$instance . "_" . lc($statistic)}->{stat} = lc($statistic); + $self->{metric}->{$instance . "_" . lc($statistic)}->{$metric . "_" . lc($statistic)} = defined($metric_results{$instance}->{$metric}->{lc($statistic)}) ? $metric_results{$instance}->{$metric}->{lc($statistic)} : 0; + } + } + } + + if (scalar(keys %{$self->{metric}}) <= 0) { + $self->{output}->add_option_msg(short_msg => 'No metrics. Check your options or use --zeroed option to set 0 on undefined values'); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check S3 buckets requests. + +Example: +perl centreon_plugins.pl --plugin=cloud::aws::s3::plugin --custommode=paws --mode=requests --region='eu-west-1' +--name='centreon-iso' --critical-allrequests-sum='5000000' --verbose + +See 'https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/s3-metricscollected.html' for more informations. + +Default statistic: 'sum' / Valid statistics: 'sum'. + +=over 8 + +=item B<--name> + +Set the instance name (Required) (Can be multiple). + +=item B<--filter-metric> + +Filter metrics (Can be: 'AllRequests', 'GetRequests', 'PutRequests', +'DeleteRequests', 'HeadRequests', 'PostRequests', 'ListRequests') +(Can be a regexp). + +=item B<--warning-$metric$-$statistic$> + +Thresholds warning ($metric$ can be: 'allrequests', 'getrequests', 'putrequests', +'deleterequests', 'headrequests', 'postrequests', 'listrequests', +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=item B<--critical-$metric$-$statistic$> + +Thresholds critical ($metric$ can be: 'allrequests', 'getrequests', 'putrequests', +'deleterequests', 'headrequests', 'postrequests', 'listrequests', +$statistic$ can be: 'minimum', 'maximum', 'average', 'sum'). + +=back + +=cut diff --git a/cloud/aws/s3/plugin.pm b/cloud/aws/s3/plugin.pm new file mode 100644 index 000000000..e9278e285 --- /dev/null +++ b/cloud/aws/s3/plugin.pm @@ -0,0 +1,52 @@ +# +# Copyright 2018 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::s3::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} } = ( + 'bucket-size' => 'cloud::aws::s3::mode::bucketsize', + 'objects' => 'cloud::aws::s3::mode::objects', + 'requests' => 'cloud::aws::s3::mode::requests', + ); + + $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 Simple Storage Service (Amazon S3). + +=cut