diff --git a/cloud/google/gcp/compute/computeengine/mode/cpu.pm b/cloud/google/gcp/compute/computeengine/mode/cpu.pm index e8d6f5448..aba217649 100644 --- a/cloud/google/gcp/compute/computeengine/mode/cpu.pm +++ b/cloud/google/gcp/compute/computeengine/mode/cpu.pm @@ -30,29 +30,31 @@ sub get_metrics_mapping { my $metrics_mapping = { 'instance/cpu/utilization' => { - 'output_string' => 'Cpu Utilization: %.2f', - 'perfdata' => { - 'absolute' => { - 'nlabel' => 'computeengine.cpu.utilization.percentage', - 'min' => '0', - 'max' => '100', - 'unit' => '%', - 'format' => '%.2f', - }, - }, - 'threshold' => 'utilization', - 'calc' => '* 100', - }, - 'instance/cpu/reserved_cores' => { - 'output_string' => 'Cpu Reserved Cores: %.2f', - 'perfdata' => { - 'absolute' => { - 'nlabel' => 'computeengine.cpu.cores.reserved.count', - 'format' => '%.2f', + output_string => 'cpu utilization: %.2f', + perfdata => { + absolute => { + nlabel => 'computeengine.cpu.utilization.percentage', + min => 0, + max => 100, + unit => '%', + format => '%.2f' } }, - 'threshold' => 'cores-reserved', + threshold => 'utilization', + calc => '* 100', + order => 1 }, + 'instance/cpu/reserved_cores' => { + output_string => 'cpu reserved cores: %.2f', + perfdata => { + absolute => { + nlabel => 'computeengine.cpu.reserved_cores.count', + format => '%.2f' + } + }, + threshold => 'cores-reserved', + order => 2 + } }; return $metrics_mapping; @@ -64,8 +66,12 @@ sub new { bless $self, $class; $options{options}->add_options(arguments => { - 'instance:s@' => { name => 'instance' }, - 'filter-metric:s' => { name => 'filter_metric' }, + 'dimension-name:s' => { name => 'dimension_name', default => 'metric.labels.instance_name' }, + 'dimension-operator:s' => { name => 'dimension_operator', default => 'equals' }, + 'dimension-value:s' => { name => 'dimension_value' }, + 'filter-metric:s' => { name => 'filter_metric' }, + 'timeframe:s' => { name => 'timeframe' }, + 'aggregation:s@' => { name => 'aggregation' } }); return $self; @@ -75,31 +81,12 @@ sub check_options { my ($self, %options) = @_; $self->SUPER::check_options(%options); - if (!defined($self->{option_results}->{instance})) { - $self->{output}->add_option_msg(short_msg => "Need to specify --instance ."); - $self->{output}->option_exit(); - } - - $self->{gcp_api} = "compute.googleapis.com"; - $self->{gcp_dimension} = 'metric.labels.instance_name'; - $self->{gcp_instance} = $self->{option_results}->{instance}; - $self->{gcp_timeframe} = defined($self->{option_results}->{timeframe}) ? $self->{option_results}->{timeframe} : 900; - $self->{gcp_aggregations} = ['average']; - if (defined($self->{option_results}->{aggregation})) { - $self->{gcp_aggregations} = []; - foreach my $stat (@{$self->{option_results}->{aggregation}}) { - if ($stat ne '') { - push @{$self->{gcp_aggregations}}, $stat; - } - } - } - - foreach my $metric (keys %{$self->{metrics_mapping}}) { - next if (defined($self->{option_results}->{filter_metric}) && $self->{option_results}->{filter_metric} ne '' - && $metric !~ /$self->{option_results}->{filter_metric}/); - - push @{$self->{gcp_metrics}}, $metric; - } + $self->{gcp_api} = 'compute.googleapis.com'; + $self->{gcp_dimension_name} = (!defined($self->{option_results}->{dimension_name}) || $self->{option_results}->{dimension_name} eq '') ? 'metric.labels.instance_name' : $self->{option_results}->{dimension_name}; + $self->{gcp_dimension_zeroed} = 'metric.labels.instance_name'; + $self->{gcp_instance_key} = 'metric.labels.instance_name'; + $self->{gcp_dimension_operator} = $self->{option_results}->{dimension_operator}; + $self->{gcp_dimension_value} = $self->{option_results}->{dimension_value}; } 1; @@ -113,26 +100,41 @@ Check Compute Engine instances CPU metrics. Example: perl centreon_plugins.pl --plugin=cloud::google::gcp::compute::computeengine::plugin ---custommode=api --mode=cpu --instance=mycomputeinstance --filter-metric='utilization' +--mode=cpu --dimension-value=mycomputeinstance --filter-metric='utilization' --aggregation='average' --critical-cpu-utilization-average='10' --verbose Default aggregation: 'average' / All aggregations are valid. =over 8 -=item B<--instance> +=item B<--dimension-name> -Set instance name (Required). +Set dimension name (Default: 'metric.labels.instance_name'). + +=item B<--dimension-operator> + +Set dimension operator (Default: 'equals'. Can also be: 'regexp', 'starts'). + +=item B<--dimension-value> + +Set dimension value (Required). =item B<--filter-metric> Filter metrics (Can be: 'instance/cpu/utilization', 'instance/cpu/reserved_cores') (Can be a regexp). +=item B<--timeframe> + +Set timeframe in seconds (i.e. 3600 to check last hour). + +=item B<--aggregation> + +Set monitor aggregation (Can be multiple, Can be: 'minimum', 'maximum', 'average', 'total'). + =item B<--warning-*> B<--critical-*> -Thresholds critical (Can be: 'utilization', -'cores-reserved'). +Thresholds (Can be: 'utilization', 'cores-reserved'). =back diff --git a/cloud/google/gcp/compute/computeengine/mode/diskio.pm b/cloud/google/gcp/compute/computeengine/mode/diskio.pm index 204096b2e..5c4e4147e 100644 --- a/cloud/google/gcp/compute/computeengine/mode/diskio.pm +++ b/cloud/google/gcp/compute/computeengine/mode/diskio.pm @@ -30,105 +30,111 @@ sub get_metrics_mapping { my $metrics_mapping = { 'instance/disk/read_bytes_count' => { - 'output_string' => 'Read Bytes: %.2f', - 'perfdata' => { - 'absolute' => { - 'nlabel' => 'computeengine.disk.read.volume.bytes', - 'format' => '%.2f', - 'unit' => 'B', - 'change_bytes' => 1, - }, - 'per_second' => { - 'nlabel' => 'computeengine.disk.read.volume.bytespersecond', - 'format' => '%.2f', - 'unit' => 'B/s', - 'change_bytes' => 1, + output_string => 'read: %.2f', + perfdata => { + absolute => { + nlabel => 'computeengine.disk.read.volume.bytes', + format => '%.2f', + unit => 'B', + change_bytes => 1 }, + per_second => { + nlabel => 'computeengine.disk.read.volume.bytespersecond', + format => '%.2f', + unit => 'B/s', + change_bytes => 1 + } }, - 'threshold' => 'read-volume', + threshold => 'read-volume', + order => 1 }, 'instance/disk/throttled_read_bytes_count' => { - 'output_string' => 'Throttled Read Bytes: %.2f', - 'perfdata' => { - 'absolute' => { - 'nlabel' => 'computeengine.disk.throttled.read.volume.bytes', - 'format' => '%.2f', - 'unit' => 'B', - 'change_bytes' => 1, - }, - 'per_second' => { - 'nlabel' => 'computeengine.disk.throttled.read.volume.bytespersecond', - 'format' => '%.2f', - 'unit' => 'B/s', - 'change_bytes' => 1, + output_string => 'throttled read: %.2f', + perfdata => { + absolute => { + nlabel => 'computeengine.disk.throttled.read.volume.bytes', + format => '%.2f', + unit => 'B', + change_bytes => 1 }, + per_second => { + nlabel => 'computeengine.disk.throttled.read.volume.bytespersecond', + format => '%.2f', + unit => 'B/s', + change_bytes => 1 + } }, - 'threshold' => 'throttled-read-volume', + threshold => 'throttled-read-volume', + order => 2 }, 'instance/disk/write_bytes_count' => { - 'output_string' => 'Write Bytes: %.2f', - 'perfdata' => { - 'absolute' => { - 'nlabel' => 'computeengine.disk.write.volume.bytes', - 'format' => '%.2f', - 'unit' => 'B', - 'change_bytes' => 1, - }, - 'per_second' => { - 'nlabel' => 'computeengine.disk.write.volume.bytespersecond', - 'format' => '%.2f', - 'unit' => 'B/s', - 'change_bytes' => 1, + output_string => 'write: %.2f', + perfdata => { + absolute => { + nlabel => 'computeengine.disk.write.volume.bytes', + format => '%.2f', + unit => 'B', + change_bytes => 1 }, + per_second => { + nlabel => 'computeengine.disk.write.volume.bytespersecond', + format => '%.2f', + unit => 'B/s', + change_bytes => 1 + } }, - 'threshold' => 'write-volume', + threshold => 'write-volume', + order => 3 }, 'instance/disk/throttled_write_bytes_count' => { - 'output_string' => 'Throttled Write Bytes: %.2f', - 'perfdata' => { - 'absolute' => { - 'nlabel' => 'computeengine.disk.throttled.write.volume.bytes', - 'format' => '%.2f', - 'unit' => 'B', - 'change_bytes' => 1, - }, - 'per_second' => { - 'nlabel' => 'computeengine.disk.throttled.write.volume.bytespersecond', - 'format' => '%.2f', - 'unit' => 'B/s', - 'change_bytes' => 1, + output_string => 'throttled write: %.2f', + perfdata => { + absolute => { + nlabel => 'computeengine.disk.throttled.write.volume.bytes', + format => '%.2f', + unit => 'B', + change_bytes => 1 }, + per_second => { + nlabel => 'computeengine.disk.throttled.write.volume.bytespersecond', + format => '%.2f', + unit => 'B/s', + change_bytes => 1 + } }, - 'threshold' => 'throttled-write-volume', + threshold => 'throttled-write-volume', + order => 4 }, 'instance/disk/read_ops_count' => { - 'output_string' => 'Read OPS: %.2f', - 'perfdata' => { - 'absolute' => { - 'nlabel' => 'computeengine.disk.read.ops.count', - 'format' => '%.2f', - }, - 'per_second' => { - 'nlabel' => 'computeengine.disk.read.ops.persecond', - 'format' => '%.2f', + output_string => 'read OPS: %.2f', + perfdata => { + absolute => { + nlabel => 'computeengine.disk.read.ops.count', + format => '%.2f' }, + per_second => { + nlabel => 'computeengine.disk.read.ops.persecond', + format => '%.2f' + } }, - 'threshold' => 'read-ops', + threshold => 'read-ops', + order => 5 }, 'instance/disk/write_ops_count' => { - 'output_string' => 'Write OPS: %.2f', - 'perfdata' => { - 'absolute' => { - 'nlabel' => 'computeengine.disk.write.ops.count', - 'format' => '%.2f', - }, - 'per_second' => { - 'nlabel' => 'computeengine.disk.write.ops.persecond', - 'format' => '%.2f', + output_string => 'write OPS: %.2f', + perfdata => { + absolute => { + nlabel => 'computeengine.disk.write.ops.count', + format => '%.2f' }, + per_second => { + nlabel => 'computeengine.disk.write.ops.persecond', + format => '%.2f' + } }, - 'threshold' => 'write-ops', - }, + threshold => 'write-ops', + order => 6 + } }; return $metrics_mapping; @@ -140,9 +146,13 @@ sub new { bless $self, $class; $options{options}->add_options(arguments => { - 'instance:s@' => { name => 'instance' }, - 'filter-metric:s' => { name => 'filter_metric' }, - "per-second" => { name => 'per_second' }, + 'dimension-name:s' => { name => 'dimension_name', default => 'metric.labels.instance_name' }, + 'dimension-operator:s' => { name => 'dimension_operator', default => 'equals' }, + 'dimension-value:s' => { name => 'dimension_value' }, + 'filter-metric:s' => { name => 'filter_metric' }, + "per-second" => { name => 'per_second' }, + 'timeframe:s' => { name => 'timeframe' }, + 'aggregation:s@' => { name => 'aggregation' } }); return $self; @@ -152,31 +162,12 @@ sub check_options { my ($self, %options) = @_; $self->SUPER::check_options(%options); - if (!defined($self->{option_results}->{instance})) { - $self->{output}->add_option_msg(short_msg => "Need to specify --instance ."); - $self->{output}->option_exit(); - } - - $self->{gcp_api} = "compute.googleapis.com"; - $self->{gcp_dimension} = 'metric.labels.instance_name'; - $self->{gcp_instance} = $self->{option_results}->{instance}; - $self->{gcp_timeframe} = defined($self->{option_results}->{timeframe}) ? $self->{option_results}->{timeframe} : 900; - $self->{gcp_aggregations} = ['average']; - if (defined($self->{option_results}->{aggregation})) { - $self->{gcp_aggregations} = []; - foreach my $stat (@{$self->{option_results}->{aggregation}}) { - if ($stat ne '') { - push @{$self->{gcp_aggregations}}, $stat; - } - } - } - - foreach my $metric (keys %{$self->{metrics_mapping}}) { - next if (defined($self->{option_results}->{filter_metric}) && $self->{option_results}->{filter_metric} ne '' - && $metric !~ /$self->{option_results}->{filter_metric}/); - - push @{$self->{gcp_metrics}}, $metric; - } + $self->{gcp_api} = 'compute.googleapis.com'; + $self->{gcp_dimension_name} = (!defined($self->{option_results}->{dimension_name}) || $self->{option_results}->{dimension_name} eq '') ? 'metric.labels.instance_name' : $self->{option_results}->{dimension_name}; + $self->{gcp_dimension_zeroed} = 'metric.labels.instance_name'; + $self->{gcp_instance_key} = 'metric.labels.instance_name'; + $self->{gcp_dimension_operator} = $self->{option_results}->{dimension_operator}; + $self->{gcp_dimension_value} = $self->{option_results}->{dimension_value}; } 1; @@ -190,16 +181,24 @@ Check Compute Engine instances disk IO metrics. Example: perl centreon_plugins.pl --plugin=cloud::google::gcp::compute::computeengine::plugin ---custommode=api --mode=diskio --instance=mycomputeinstance --filter-metric='throttled' +--mode=diskio --dimension-value=mycomputeinstance --filter-metric='throttled' --aggregation='average' --critical-throttled-write-volume='10' --verbose Default aggregation: 'average' / All aggregations are valid. =over 8 -=item B<--instance> +=item B<--dimension-name> -Set instance name (Required). +Set dimension name (Default: 'metric.labels.instance_name'). + +=item B<--dimension-operator> + +Set dimension operator (Default: 'equals'. Can also be: 'regexp', 'starts'). + +=item B<--dimension-value> + +Set dimension value (Required). =item B<--filter-metric> @@ -207,9 +206,17 @@ Filter metrics (Can be: 'instance/disk/read_bytes_count', 'instance/disk/throttl 'instance/disk/write_bytes_count', 'instance/disk/throttled_write_bytes_count', 'instance/disk/read_ops_count', 'instance/disk/write_ops_count') (Can be a regexp). +=item B<--timeframe> + +Set timeframe in seconds (i.e. 3600 to check last hour). + +=item B<--aggregation> + +Set monitor aggregation (Can be multiple, Can be: 'minimum', 'maximum', 'average', 'total'). + =item B<--warning-*> B<--critical-*> -Thresholds warning (Can be: 'read-volume', 'throttled-read-volume', +Thresholds (Can be: 'read-volume', 'throttled-read-volume', 'write-volume', 'throttled-write-volume', 'read-ops', 'write-ops'). =item B<--per-second> diff --git a/cloud/google/gcp/compute/computeengine/mode/network.pm b/cloud/google/gcp/compute/computeengine/mode/network.pm index 2ca69e99b..e380c1645 100644 --- a/cloud/google/gcp/compute/computeengine/mode/network.pm +++ b/cloud/google/gcp/compute/computeengine/mode/network.pm @@ -30,73 +30,77 @@ sub get_metrics_mapping { my $metrics_mapping = { 'instance/network/received_bytes_count' => { - 'output_string' => 'Received Bytes: %.2f', - 'perfdata' => { - 'absolute' => { - 'nlabel' => 'computeengine.network.received.volume.bytes', - 'format' => '%.2f', - 'unit' => 'B', - 'change_bytes' => 1, - }, - 'per_second' => { - 'nlabel' => 'computeengine.network.received.volume.bytespersecond', - 'format' => '%.2f', - 'unit' => 'B/s', - 'change_bytes' => 1, + output_string => 'received: %.2f', + perfdata => { + absolute => { + nlabel => 'computeengine.network.received.volume.bytes', + format => '%.2f', + unit => 'B', + change_bytes => 1 }, + per_second => { + nlabel => 'computeengine.network.received.volume.bytespersecond', + format => '%.2f', + unit => 'B/s', + change_bytes => 1 + } }, - 'threshold' => 'received-volume', + threshold => 'received-volume', + order => 1 }, 'instance/network/sent_bytes_count' => { - 'output_string' => 'Sent Bytes: %.2f', - 'perfdata' => { - 'absolute' => { - 'nlabel' => 'computeengine.network.sent.volume.bytes', - 'format' => '%.2f', - 'unit' => 'B', - 'change_bytes' => 1, - }, - 'per_second' => { - 'nlabel' => 'computeengine.network.sent.volume.bytespersecond', - 'format' => '%.2f', - 'unit' => 'B/s', - 'change_bytes' => 1, + output_string => 'sent: %.2f', + perfdata => { + absolute => { + nlabel => 'computeengine.network.sent.volume.bytes', + format => '%.2f', + unit => 'B', + change_bytes => 1 }, + per_second => { + nlabel => 'computeengine.network.sent.volume.bytespersecond', + format => '%.2f', + unit => 'B/s', + change_bytes => 1 + } }, - 'threshold' => 'sent-volume', + threshold => 'sent-volume', + order => 2 }, 'instance/network/received_packets_count' => { - 'output_string' => 'Received Packets: %.2f', - 'perfdata' => { - 'absolute' => { - 'nlabel' => 'computeengine.network.received.packets.count', - 'format' => '%.2f', - 'unit' => 'packets', - }, - 'per_second' => { - 'nlabel' => 'computeengine.network.received.packets.persecond', - 'format' => '%.2f', - 'unit' => 'packets/s', + output_string => 'received packets: %.2f', + perfdata => { + absolute => { + nlabel => 'computeengine.network.received.packets.count', + format => '%.2f', + unit => 'packets' }, + per_second => { + nlabel => 'computeengine.network.received.packets.persecond', + format => '%.2f', + unit => 'packets/s' + } }, - 'threshold' => 'received-packets', + threshold => 'received-packets', + order => 3 }, 'instance/network/sent_packets_count' => { - 'output_string' => 'Sent Packets: %.2f', - 'perfdata' => { - 'absolute' => { - 'nlabel' => 'computeengine.network.sent.packets.count', - 'format' => '%.2f', - 'unit' => 'packets', - }, - 'per_second' => { - 'nlabel' => 'computeengine.network.sent.packets.persecond', - 'format' => '%.2f', - 'unit' => 'packets/s', + output_string => 'sent packets: %.2f', + perfdata => { + absolute => { + nlabel => 'computeengine.network.sent.packets.count', + format => '%.2f', + unit => 'packets' }, + per_second => { + nlabel => 'computeengine.network.sent.packets.persecond', + format => '%.2f', + unit => 'packets/s' + } }, - 'threshold' => 'sent-packets', - }, + threshold => 'sent-packets', + order => 4 + } }; return $metrics_mapping; @@ -108,9 +112,13 @@ sub new { bless $self, $class; $options{options}->add_options(arguments => { - 'instance:s@' => { name => 'instance' }, - 'filter-metric:s' => { name => 'filter_metric' }, - "per-second" => { name => 'per_second' }, + 'dimension-name:s' => { name => 'dimension_name', default => 'metric.labels.instance_name' }, + 'dimension-operator:s' => { name => 'dimension_operator', default => 'equals' }, + 'dimension-value:s' => { name => 'dimension_value' }, + 'filter-metric:s' => { name => 'filter_metric' }, + "per-second" => { name => 'per_second' }, + 'timeframe:s' => { name => 'timeframe' }, + 'aggregation:s@' => { name => 'aggregation' } }); return $self; @@ -120,31 +128,12 @@ sub check_options { my ($self, %options) = @_; $self->SUPER::check_options(%options); - if (!defined($self->{option_results}->{instance})) { - $self->{output}->add_option_msg(short_msg => "Need to specify --instance ."); - $self->{output}->option_exit(); - } - - $self->{gcp_api} = "compute.googleapis.com"; - $self->{gcp_dimension} = 'metric.labels.instance_name'; - $self->{gcp_instance} = $self->{option_results}->{instance}; - $self->{gcp_timeframe} = defined($self->{option_results}->{timeframe}) ? $self->{option_results}->{timeframe} : 900; - $self->{gcp_aggregations} = ['average']; - if (defined($self->{option_results}->{aggregation})) { - $self->{gcp_aggregations} = []; - foreach my $stat (@{$self->{option_results}->{aggregation}}) { - if ($stat ne '') { - push @{$self->{gcp_aggregations}}, $stat; - } - } - } - - foreach my $metric (keys %{$self->{metrics_mapping}}) { - next if (defined($self->{option_results}->{filter_metric}) && $self->{option_results}->{filter_metric} ne '' - && $metric !~ /$self->{option_results}->{filter_metric}/); - - push @{$self->{gcp_metrics}}, $metric; - } + $self->{gcp_api} = 'compute.googleapis.com'; + $self->{gcp_dimension_name} = (!defined($self->{option_results}->{dimension_name}) || $self->{option_results}->{dimension_name} eq '') ? 'metric.labels.instance_name' : $self->{option_results}->{dimension_name}; + $self->{gcp_dimension_zeroed} = 'metric.labels.instance_name'; + $self->{gcp_instance_key} = 'metric.labels.instance_name'; + $self->{gcp_dimension_operator} = $self->{option_results}->{dimension_operator}; + $self->{gcp_dimension_value} = $self->{option_results}->{dimension_value}; } 1; @@ -158,16 +147,24 @@ Check Compute Engine instances network metrics. Example: perl centreon_plugins.pl --plugin=cloud::google::gcp::compute::computeengine::plugin ---custommode=api --mode=network --instance=mycomputeinstance --filter-metric='bytes' +--mode=network --dimension-value=mycomputeinstance --filter-metric='bytes' --aggregation='average' --critical-received-volume='10' --verbose Default aggregation: 'average' / All aggregations are valid. =over 8 -=item B<--instance> +=item B<--dimension-name> -Set instance name (Required). +Set dimension name (Default: 'metric.labels.instance_name'). + +=item B<--dimension-operator> + +Set dimension operator (Default: 'equals'. Can also be: 'regexp', 'starts'). + +=item B<--dimension-value> + +Set dimension value (Required). =item B<--filter-metric> @@ -175,9 +172,17 @@ Filter metrics (Can be: 'instance/network/received_bytes_count', 'instance/network/sent_bytes_count', 'instance/network/received_packets_count', 'instance/network/sent_packets_count') (Can be a regexp). +=item B<--timeframe> + +Set timeframe in seconds (i.e. 3600 to check last hour). + +=item B<--aggregation> + +Set monitor aggregation (Can be multiple, Can be: 'minimum', 'maximum', 'average', 'total'). + =item B<--warning-*> B<--critical-*> -Thresholds warning (Can be: 'received-volume', 'sent-volume', +Thresholds (Can be: 'received-volume', 'sent-volume', 'received-packets', 'sent-packets'). =item B<--per-second> diff --git a/cloud/google/gcp/compute/computeengine/plugin.pm b/cloud/google/gcp/compute/computeengine/plugin.pm index 00fc97261..ce2d21871 100644 --- a/cloud/google/gcp/compute/computeengine/plugin.pm +++ b/cloud/google/gcp/compute/computeengine/plugin.pm @@ -30,13 +30,13 @@ sub new { bless $self, $class; $self->{version} = '0.1'; - %{ $self->{modes} } = ( - 'cpu' => 'cloud::google::gcp::compute::computeengine::mode::cpu', - 'diskio' => 'cloud::google::gcp::compute::computeengine::mode::diskio', - 'network' => 'cloud::google::gcp::compute::computeengine::mode::network', - ); + $self->{modes} = { + 'cpu' => 'cloud::google::gcp::compute::computeengine::mode::cpu', + 'diskio' => 'cloud::google::gcp::compute::computeengine::mode::diskio', + 'network' => 'cloud::google::gcp::compute::computeengine::mode::network' + }; - $self->{custom_modes}{api} = 'cloud::google::gcp::custom::api'; + $self->{custom_modes}->{api} = 'cloud::google::gcp::custom::api'; return $self; } diff --git a/cloud/google/gcp/custom/api.pm b/cloud/google/gcp/custom/api.pm index 7d418f49c..248dc58df 100644 --- a/cloud/google/gcp/custom/api.pm +++ b/cloud/google/gcp/custom/api.pm @@ -26,7 +26,6 @@ use DateTime; use centreon::plugins::http; use centreon::plugins::statefile; use JSON::XS; -use URI::Encode; use Digest::MD5 qw(md5_hex); use JSON::WebToken; @@ -46,15 +45,12 @@ sub new { if (!defined($options{noptions})) { $options{options}->add_options(arguments => { - 'key-file:s' => { name => 'key_file' }, - 'authorization-endpoint:s' => { name => 'authorization_endpoint' }, - 'monitoring-endpoint:s' => { name => 'monitoring_endpoint' }, - 'scope-endpoint:s' => { name => 'scope_endpoint' }, - 'timeframe:s' => { name => 'timeframe' }, - 'interval:s' => { name => 'interval' }, - 'aggregation:s@' => { name => 'aggregation' }, - 'zeroed' => { name => 'zeroed' }, - 'timeout:s' => { name => 'timeout' } + 'key-file:s' => { name => 'key_file' }, + 'authorization-endpoint:s' => { name => 'authorization_endpoint' }, + 'monitoring-endpoint:s' => { name => 'monitoring_endpoint' }, + 'scope-endpoint:s' => { name => 'scope_endpoint' }, + 'zeroed' => { name => 'zeroed' }, + 'timeout:s' => { name => 'timeout' } }); } $options{options}->add_help(package => __PACKAGE__, sections => 'REST API OPTIONS', once => 1); @@ -77,18 +73,7 @@ sub set_defaults {} sub check_options { my ($self, %options) = @_; - if (defined($self->{option_results}->{aggregation})) { - foreach my $aggregation (@{$self->{option_results}->{aggregation}}) { - if ($aggregation !~ /average|maximum|minimum|total/i) { - $self->{output}->add_option_msg(short_msg => "Aggregation '" . $aggregation . "' is not handled"); - $self->{output}->option_exit(); - } - } - } - $self->{timeout} = (defined($self->{option_results}->{timeout})) ? $self->{option_results}->{timeout} : 10; - $self->{timeframe} = (defined($self->{option_results}->{timeframe})) ? $self->{option_results}->{timeframe} : undef; - $self->{step} = (defined($self->{option_results}->{step})) ? $self->{option_results}->{step} : undef; $self->{key_file} = (defined($self->{option_results}->{key_file})) ? $self->{option_results}->{key_file} : undef; $self->{authorization_endpoint} = (defined($self->{option_results}->{authorization_endpoint})) ? $self->{option_results}->{authorization_endpoint} : 'https://www.googleapis.com/oauth2/v4/token'; @@ -121,10 +106,6 @@ sub settings { $self->build_options_for_httplib(); $self->{http}->add_header(key => 'Accept', value => 'application/json'); - $self->{http}->add_header(key => 'Content-Type', value => 'application/x-www-form-urlencoded'); - if (defined($self->{access_token})) { - $self->{http}->add_header(key => 'Authorization', value => 'Bearer ' . $self->{access_token}); - } $self->{http}->set_options(%{$self->{option_results}}); } @@ -167,14 +148,16 @@ sub get_access_token { exp => $exp, iat => $iat, }, $decoded_key_file->{private_key}, 'RS256'); - - my $post_data = 'grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion=' . $jwt; - - $self->settings(); - my $content = $self->{http}->request(method => 'POST', query_form_post => $post_data, - full_url => $self->{authorization_endpoint}, - hostname => ''); + my $content = $self->{http}->request( + method => 'POST', + full_url => $self->{authorization_endpoint}, + hostname => '', + post_param => [ + 'grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer', + 'assertion=' . $jwt + ] + ); if (!defined($content) || $content eq '') { $self->{output}->add_option_msg( @@ -208,8 +191,9 @@ sub get_access_token { my $datas = { last_timestamp => time(), access_token => $decoded->{access_token}, expires_on => $exp }; $options{statefile}->write(data => $datas); } - - return $access_token; + + $self->{access_token} = $access_token; + $self->{http}->add_header(key => 'Authorization', value => 'Bearer ' . $self->{access_token}); } sub get_project_id { @@ -217,12 +201,10 @@ sub get_project_id { local $/ = undef; if (!open(FILE, "<", $self->{key_file})) { - $self->{output}->output_add( - severity => 'UNKNOWN', + $self->{output}->add_option_msg( short_msg => sprintf("Cannot read file '%s': %s", $self->{key_file}, $!) ); - $self->{output}->display(); - $self->{output}->exit(); + $self->{output}->option_exit(); } my $key_file = ; close FILE; @@ -242,13 +224,10 @@ sub get_project_id { sub request_api { my ($self, %options) = @_; - if (!defined($self->{access_token})) { - $self->{access_token} = $self->get_access_token(statefile => $self->{cache}); - } - $self->settings(); - - $self->{output}->output_add(long_msg => "URL: '" . $options{full_url} . "'", debug => 1); + if (!defined($self->{access_token})) { + $self->get_access_token(statefile => $self->{cache}); + } my $content = $self->{http}->request(%options); @@ -286,69 +265,115 @@ sub request_api { sub gcp_get_metrics_set_url { my ($self, %options) = @_; - my $uri = URI::Encode->new({encode_reserved => 1}); - my $encoded_filter = $uri->encode('metric.type = "' . $options{api} . '/' . $options{metric} . '"'); - $encoded_filter .= $uri->encode(' AND ' . $options{dimension} . ' = starts_with(' . $options{instance} . ')'); - $encoded_filter .= ' AND ' . $uri->encode(join(' AND ', @{$options{extra_filters}})) + my $filter_instance = $options{dimension_name}; + if (defined($options{dimension_operator}) && $options{dimension_operator} eq 'starts') { + $filter_instance .= ' = starts_with("' . $options{dimension_value} . '")'; + } elsif (defined($options{dimension_operator}) && $options{dimension_operator} eq 'regexp') { + $filter_instance .= ' = monitoring.regex.full_match("' . $options{dimension_value} . '")'; + } else { + $filter_instance .= ' = "' . $options{dimension_value} . '"'; + } + my $filter = 'metric.type = "' . $options{api} . '/' . $options{metric} . '" AND ' . $filter_instance; + $filter .= ' AND ' . join(' AND ', @{$options{extra_filters}}) if (defined($options{extra_filters}) && $options{extra_filters} ne ''); - my $encoded_start_time = $uri->encode($options{start_time}); - my $encoded_end_time = $uri->encode($options{end_time}); + my $get_param = [ + 'filter=' . $filter, + 'interval.startTime=' . $options{start_time}, + 'interval.endTime=' . $options{end_time} + ]; my $project_id = $self->get_project_id(); + my $url = $self->{monitoring_endpoint} . '/projects/' . $project_id . '/timeSeries/'; - my $url = $self->{monitoring_endpoint} . "/projects/" . $project_id . "/timeSeries/?filter=" . $encoded_filter . - "&interval.startTime=" . $encoded_start_time . "&interval.endTime=" . $encoded_end_time; + return ($url, $get_param); +} - return $url; +sub get_instance { + my ($self, %options) = @_; + + my $timeserie = $options{timeserie}; + foreach (@{$options{instance_key}}) { + $timeserie = $timeserie->{$_}; + } + if (ref($timeserie) !~ /ARRAY|HASH/) { + return $timeserie; + } + + return undef; } sub gcp_get_metrics { my ($self, %options) = @_; + my $start_time = DateTime->now->subtract(seconds => $options{timeframe})->iso8601() . '.000000Z'; + my $end_time = DateTime->now->iso8601() . '.000000Z'; + + my ($url, $get_param) = $self->gcp_get_metrics_set_url(%options, start_time => $start_time, end_time => $end_time); + my $response = $self->request_api( + method => 'GET', + full_url => $url, + hostname => '', + get_param => $get_param + ); + + my %aggregations = map { $_ => 1 } @{$options{aggregations}}; + my $instance_key = [split /\./, $options{instance_key}]; my $results = {}; - my $start_time = DateTime->now->subtract(seconds => $options{timeframe})->iso8601.'.000000Z'; - my $end_time = DateTime->now->iso8601.'.000000Z'; - - my $full_url = $self->gcp_get_metrics_set_url(%options, start_time => $start_time, end_time => $end_time); - my $response = $self->request_api(method => 'GET', full_url => $full_url, hostname => ''); - - my %aggregations = map {$_ => 1} @{$options{aggregations}}; - foreach my $timeserie (@{$response->{timeSeries}}) { + my $instance = $self->get_instance( + timeserie => $timeserie, + instance_key => $instance_key + ); + next if (!defined($instance)); + my $metric_name = lc($timeserie->{metric}->{type}); $metric_name =~ s/$options{api}\///; - - $results->{$metric_name} = { points => 0 }; + + if (!defined($results->{$instance})) { + $results->{$instance} = {}; + } + + my $metric_calc = { points => 0 }; foreach my $point (@{$timeserie->{points}}) { if (defined($point->{value})) { - my $value = $point->{value}->{lc($timeserie->{valueType}) . 'Value'}; + my $value = $point->{value}->{ lc($timeserie->{valueType}) . 'Value' }; if (defined($aggregations{average})) { - $results->{$metric_name}->{average} = 0 if (!defined($results->{$metric_name}->{average})); - $results->{$metric_name}->{average} += $value; - $results->{$metric_name}->{points}++; + $metric_calc->{average} = 0 if (!defined($metric_calc->{average})); + $metric_calc->{average} += $value; + $metric_calc->{points}++; } if (defined($aggregations{minimum})) { - $results->{$metric_name}->{minimum} = $value - if (!defined($results->{$metric_name}->{minimum}) || $value < $results->{$metric_name}->{minimum}); + $metric_calc->{minimum} = $value + if (!defined($metric_calc->{$metric_name}->{minimum}) || $value < $$metric_calc->{minimum}); } if (defined($aggregations{maximum})) { - $results->{$metric_name}->{maximum} = $value - if (!defined($results->{$metric_name}->{maximum}) || $value > $results->{$metric_name}->{maximum}); + $metric_calc->{maximum} = $value + if (!defined($metric_calc->{maximum}) || $value > $metric_calc->{maximum}); } if (defined($aggregations{total})) { - $results->{$metric_name}->{total} = 0 if (!defined($results->{$metric_name}->{total})); - $results->{$metric_name}->{total} += $value; - $results->{$metric_name}->{points}++; + $metric_calc->{total} = 0 if (!defined($metric_calc->{total})); + $metric_calc->{total} += $value; + $metric_calc->{points}++; } } } - if (defined($results->{$metric_name}->{average})) { - $results->{$metric_name}->{average} /= $results->{$metric_name}->{points}; + + if (defined($metric_calc->{average})) { + $metric_calc->{average} /= $metric_calc->{points}; } - $results->{resource} = $timeserie->{resource}; - $results->{labels} = $timeserie->{metric}->{labels}; + $results->{$instance}->{$metric_name} = $metric_calc; + $results->{$instance}->{resource} = $timeserie->{resource}; + $results->{$instance}->{labels} = $timeserie->{metric}->{labels}; } - - return $results, $response; + + if (defined($self->{option_results}->{zeroed}) && (!defined($options{dimension_operator}) || $options{dimension_operator} eq '' || $options{dimension_operator} eq 'equals')) { + if ($options{dimension_name} eq $options{dimension_zeroed} && !defined($results->{ $options{dimension_value} })) { + $results->{ $options{dimension_value} } = { + $options{metric} => { average => 0, minimum => 0, maximum => 0, total => 0 } + }; + } + } + + return $results; } 1; @@ -385,14 +410,6 @@ Set GCP monitoring endpoint URL (Default: 'https://monitoring.googleapis.com/v3' Set GCP scope endpoint URL (Default: 'https://www.googleapis.com/auth/monitoring.read') -=item B<--timeframe> - -Set timeframe in seconds (i.e. 3600 to check last hour). - -=item B<--aggregation> - -Set monitor aggregation (Can be multiple, Can be: 'minimum', 'maximum', 'average', 'total'). - =item B<--zeroed> Set metrics value to 0 if none. Usefull when Stackdriver diff --git a/cloud/google/gcp/custom/mode.pm b/cloud/google/gcp/custom/mode.pm index b9b57b62c..3a8378cee 100644 --- a/cloud/google/gcp/custom/mode.pm +++ b/cloud/google/gcp/custom/mode.pm @@ -34,7 +34,7 @@ sub prefix_output { sub prefix_aggregations_output { my ($self, %options) = @_; - return "Aggregation '" . $options{instance_value}->{display} . "' Metrics "; + return "aggregation '" . $options{instance_value}->{display} . "' metrics "; } sub long_output { @@ -46,8 +46,8 @@ sub long_output { sub custom_calc { my ($self, %options) = @_; - $self->{result_values}->{timeframe} = $options{new_datas}->{$self->{instance} . '_timeframe'}; - $self->{result_values}->{value}->{absolute} = $options{new_datas}->{$self->{instance} . '_' . $options{extra_options}->{metric}}; + $self->{result_values}->{timeframe} = $options{new_datas}->{ $self->{instance} . '_timeframe' }; + $self->{result_values}->{value}->{absolute} = $options{new_datas}->{ $self->{instance} . '_' . $options{extra_options}->{metric} }; $self->{result_values}->{value}->{absolute} = eval $self->{result_values}->{value}->{absolute} . $self->{instance_mode}->{metrics_mapping}->{$options{extra_options}->{metric}}->{calc} if (defined($self->{instance_mode}->{metrics_mapping}->{$options{extra_options}->{metric}}->{calc})); $self->{result_values}->{value}->{per_second} = $self->{result_values}->{value}->{absolute} / $self->{result_values}->{timeframe}; @@ -58,7 +58,7 @@ sub custom_calc { sub custom_threshold { my ($self, %options) = @_; - my $threshold = $self->{instance_mode}->{metrics_mapping}->{$self->{result_values}->{metric}}->{threshold}; + my $threshold = $self->{instance_mode}->{metrics_mapping}->{ $self->{result_values}->{metric} }->{threshold}; my $value = $self->{result_values}->{value}->{absolute}; if (defined($self->{instance_mode}->{option_results}->{per_second})) { $value = $self->{result_values}->{value}->{per_second}; @@ -76,23 +76,23 @@ sub custom_threshold { sub custom_perfdata { my ($self, %options) = @_; - my $threshold = $self->{instance_mode}->{metrics_mapping}->{$self->{result_values}->{metric}}->{threshold}; - my $options = $self->{instance_mode}->{metrics_mapping}->{$self->{result_values}->{metric}}->{perfdata}->{absolute}; + my $threshold = $self->{instance_mode}->{metrics_mapping}->{ $self->{result_values}->{metric} }->{threshold}; + my $options = $self->{instance_mode}->{metrics_mapping}->{ $self->{result_values}->{metric} }->{perfdata}->{absolute}; my $value = sprintf( - $self->{instance_mode}->{metrics_mapping}->{$self->{result_values}->{metric}}->{perfdata}->{absolute}->{format}, + $self->{instance_mode}->{metrics_mapping}->{ $self->{result_values}->{metric} }->{perfdata}->{absolute}->{format}, $self->{result_values}->{value}->{absolute} ); - if (defined($self->{instance_mode}->{option_results}->{per_second})) { + if (defined($self->{instance_mode}->{option_results}->{per_second}) && + defined($self->{instance_mode}->{metrics_mapping}->{ $self->{result_values}->{metric} }->{perfdata}->{per_second})) { $value = sprintf( - $self->{instance_mode}->{metrics_mapping}->{$self->{result_values}->{metric}}->{perfdata}->{per_second}->{format}, + $self->{instance_mode}->{metrics_mapping}->{ $self->{result_values}->{metric} }->{perfdata}->{per_second}->{format}, $self->{result_values}->{value}->{per_second} ); - $options = $self->{instance_mode}->{metrics_mapping}->{$self->{result_values}->{metric}}->{perfdata}->{per_second}; + $options = $self->{instance_mode}->{metrics_mapping}->{ $self->{result_values}->{metric} }->{perfdata}->{per_second}; } $self->{output}->perfdata_add( instances => $self->{instance}, - label => $threshold, value => $value, warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $threshold), critical => $self->{perfdata}->get_perfdata_for_output( label => 'critical-' . $threshold), @@ -110,7 +110,8 @@ sub custom_output { if (defined($self->{instance_mode}->{metrics_mapping}->{$self->{result_values}->{metric}}->{perfdata}->{absolute}->{change_bytes})) { ($value, $unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{value}->{absolute}); } - if (defined($self->{instance_mode}->{option_results}->{per_second})) { + if (defined($self->{instance_mode}->{option_results}->{per_second}) && + defined($self->{instance_mode}->{metrics_mapping}->{$self->{result_values}->{metric}}->{perfdata}->{per_second})) { $unit = $self->{instance_mode}->{metrics_mapping}->{$self->{result_values}->{metric}}->{perfdata}->{per_second}->{unit}; $value = $self->{result_values}->{value}->{per_second}; @@ -129,7 +130,7 @@ sub custom_output { sub set_counters { my ($self, %options) = @_; - $self->{metrics_mapping} = $self->get_metrics_mapping; + $self->{metrics_mapping} = $self->get_metrics_mapping(); $self->{maps_counters_type} = [ { @@ -145,14 +146,14 @@ sub set_counters { name => 'aggregations', cb_prefix_output => 'prefix_aggregations_output', display_long => 1, - message_multiple => 'All metrics are ok', + message_multiple => 'all metrics are ok', skipped_code => { -10 => 1 } - }, + } ] } ]; - foreach my $metric (keys %{$self->{metrics_mapping}}) { + foreach my $metric (sort { $self->{metrics_mapping}->{$a}->{order} <=> $self->{metrics_mapping}->{$b}->{order} } keys %{$self->{metrics_mapping}}) { my $entry = { label => $self->{metrics_mapping}->{$metric}->{threshold}, set => { @@ -161,38 +162,81 @@ sub set_counters { closure_custom_calc_extra_options => { metric => $metric }, closure_custom_output => $self->can('custom_output'), closure_custom_perfdata => $self->can('custom_perfdata'), - closure_custom_threshold_check => $self->can('custom_threshold'), + closure_custom_threshold_check => $self->can('custom_threshold') } }; push @{$self->{maps_counters}->{aggregations}}, $entry; } } +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + if (!defined($self->{option_results}->{dimension_value})) { + $self->{output}->add_option_msg(short_msg => "Need to specify --dimension-value ."); + $self->{output}->option_exit(); + } + + $self->{gcp_timeframe} = (defined($self->{option_results}->{timeframe})) ? $self->{option_results}->{timeframe} : 900; + + my $aggregations = []; + if (defined($self->{option_results}->{aggregation})) { + foreach my $aggregation (@{$self->{option_results}->{aggregation}}) { + if ($aggregation !~ /average|maximum|minimum|total/i) { + $self->{output}->add_option_msg(short_msg => "Aggregation '" . $aggregation . "' is not handled"); + $self->{output}->option_exit(); + } + + push @$aggregations, $aggregation; + } + } + $self->{gcp_aggregations} = ['average']; + if (scalar(@$aggregations) > 0) { + $self->{gcp_aggregations} = $aggregations; + } + + foreach my $metric (keys %{$self->{metrics_mapping}}) { + next if (defined($self->{option_results}->{filter_metric}) && $self->{option_results}->{filter_metric} ne '' + && $metric !~ /$self->{option_results}->{filter_metric}/); + + push @{$self->{gcp_metrics}}, $metric; + } +} + sub manage_selection { my ($self, %options) = @_; - my $metric_results; - foreach my $instance (@{$self->{gcp_instance}}) { - foreach my $metric (@{$self->{gcp_metrics}}) { - ($metric_results, undef) = $options{custom}->gcp_get_metrics( - dimension => $self->{gcp_dimension}, - instance => $instance, - metric => $metric, - api => $self->{gcp_api}, - aggregations => $self->{gcp_aggregations}, - timeframe => $self->{gcp_timeframe}, - ); - - foreach my $aggregation (@{$self->{gcp_aggregations}}) { - next if (!defined($metric_results->{$metric}->{lc($aggregation)}) && - defined($self->{option_results}->{zeroed})); + $self->{metrics} = {}; + foreach my $metric (@{$self->{gcp_metrics}}) { + my ($metric_results) = $options{custom}->gcp_get_metrics( + dimension_name => $self->{gcp_dimension_name}, + dimension_operator => $self->{gcp_dimension_operator}, + dimension_value => $self->{gcp_dimension_value}, + instance_key => $self->{gcp_instance_key}, + metric => $metric, + api => $self->{gcp_api}, + aggregations => $self->{gcp_aggregations}, + timeframe => $self->{gcp_timeframe}, + dimension_zeroed => $self->{gcp_dimension_zeroed} + ); - $self->{metrics}->{$instance}->{display} = $metric_results->{labels}->{instance_name}; - $self->{metrics}->{$instance}->{aggregations}->{lc($aggregation)}->{display} = $aggregation; - $self->{metrics}->{$instance}->{aggregations}->{lc($aggregation)}->{timeframe} = $self->{gcp_timeframe}; - $self->{metrics}->{$instance}->{aggregations}->{lc($aggregation)}->{$metric} = - defined($metric_results->{$metric}->{lc($aggregation)}) ? - $metric_results->{$metric}->{lc($aggregation)} : 0; + foreach my $instance_name (keys %$metric_results) { + foreach my $aggregation (@{$self->{gcp_aggregations}}) { + if (!defined($self->{metrics}->{$instance_name})) { + $self->{metrics}->{$instance_name} = { + display => $instance_name, + aggregations => {} + }; + } + if (!defined($self->{metrics}->{$instance_name}->{aggregations}->{lc($aggregation)})) { + $self->{metrics}->{$instance_name}->{aggregations}->{lc($aggregation)} = { + display => $aggregation, + timeframe => $self->{gcp_timeframe} + }; + } + $self->{metrics}->{$instance_name}->{aggregations}->{lc($aggregation)}->{$metric} = + defined($metric_results->{$instance_name}->{$metric}->{lc($aggregation)}) ? $metric_results->{$instance_name}->{$metric}->{lc($aggregation)} : 0 } } } diff --git a/cloud/google/gcp/database/common/mode/cpu.pm b/cloud/google/gcp/database/common/mode/cpu.pm new file mode 100644 index 000000000..47e0ed809 --- /dev/null +++ b/cloud/google/gcp/database/common/mode/cpu.pm @@ -0,0 +1,141 @@ +# +# Copyright 2020 Centreon (http://www.centreon.com/) +# +# Centreon is a full-fledged industry-strength solution that meets +# the needs in IT infrastructure and application monitoring for +# service performance. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +package cloud::google::gcp::database::common::mode::cpu; + +use base qw(cloud::google::gcp::custom::mode); + +use strict; +use warnings; + +sub get_metrics_mapping { + my ($self, %options) = @_; + + my $metrics_mapping = { + 'database/cpu/utilization' => { + output_string => 'cpu utilization: %.2f', + perfdata => { + absolute => { + nlabel => 'database.cpu.utilization.percentage', + min => 0, + max => 100, + unit => '%', + format => '%.2f' + } + }, + threshold => 'utilization', + calc => '* 100', + order => 1 + }, + 'database/cpu/reserved_cores' => { + output_string => 'cpu reserved cores: %.2f', + perfdata => { + absolute => { + nlabel => 'database.cpu.reserved_cores.count', + format => '%.2f' + } + }, + threshold => 'cores-reserved', + order => 2 + } + }; + + return $metrics_mapping; +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1); + bless $self, $class; + + $options{options}->add_options(arguments => { + 'dimension-name:s' => { name => 'dimension_name', default => 'resource.labels.database_id' }, + 'dimension-operator:s' => { name => 'dimension_operator', default => 'equals' }, + 'dimension-value:s' => { name => 'dimension_value' }, + 'filter-metric:s' => { name => 'filter_metric' }, + 'timeframe:s' => { name => 'timeframe' }, + 'aggregation:s@' => { name => 'aggregation' } + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + $self->{gcp_api} = 'cloudsql.googleapis.com'; + $self->{gcp_dimension_name} = (!defined($self->{option_results}->{dimension_name}) || $self->{option_results}->{dimension_name} eq '') ? 'resource.labels.database_id' : $self->{option_results}->{dimension_name}; + $self->{gcp_dimension_zeroed} = 'resource.labels.database_id'; + $self->{gcp_instance_key} = 'resource.labels.database_id'; + $self->{gcp_dimension_operator} = $self->{option_results}->{dimension_operator}; + $self->{gcp_dimension_value} = $self->{option_results}->{dimension_value}; +} + +1; + +__END__ + +=head1 MODE + +Check database CPU metrics. + +Example: + +perl centreon_plugins.pl --plugin=cloud::google::gcp::database::mysql::plugin +--mode=cpu --dimension-value=mydatabaseid --filter-metric='utilization' +--aggregation='average' --critical-cpu-utilization-average='10' --verbose + +Default aggregation: 'average' / All aggregations are valid. + +=over 8 + +=item B<--dimension-name> + +Set dimension name (Default: 'resource.labels.database_id'). Can be: 'resources.labels.region'. + +=item B<--dimension-operator> + +Set dimension operator (Default: 'equals'. Can also be: 'regexp', 'starts'). + +=item B<--dimension-value> + +Set dimension value (Required). + +=item B<--filter-metric> + +Filter metrics (Can be: 'database/cpu/utilization', +'database/cpu/reserved_cores') (Can be a regexp). + +=item B<--timeframe> + +Set timeframe in seconds (i.e. 3600 to check last hour). + +=item B<--aggregation> + +Set monitor aggregation (Can be multiple, Can be: 'minimum', 'maximum', 'average', 'total'). + +=item B<--warning-*> B<--critical-*> + +Thresholds (Can be: 'utilization', 'cores-reserved'). + +=back + +=cut diff --git a/cloud/google/gcp/database/common/mode/network.pm b/cloud/google/gcp/database/common/mode/network.pm new file mode 100644 index 000000000..bc46d5dca --- /dev/null +++ b/cloud/google/gcp/database/common/mode/network.pm @@ -0,0 +1,175 @@ +# +# Copyright 2020 Centreon (http://www.centreon.com/) +# +# Centreon is a full-fledged industry-strength solution that meets +# the needs in IT infrastructure and application monitoring for +# service performance. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +package cloud::google::gcp::database::common::mode::network; + +use base qw(cloud::google::gcp::custom::mode); + +use strict; +use warnings; + +sub get_metrics_mapping { + my ($self, %options) = @_; + + my $metrics_mapping = { + 'database/network/connections' => { + output_string => 'connections: %.2f', + perfdata => { + absolute => { + nlabel => 'database.network.connections.count', + format => '%.2f', + min => 0 + } + }, + threshold => 'connections', + order => 1 + }, + 'database/network/received_bytes_count' => { + output_string => 'received: %.2f', + perfdata => { + absolute => { + nlabel => 'database.network.received.volume.bytes', + format => '%.2f', + min => 0, + unit => 'B', + change_bytes => 1 + }, + per_second => { + nlabel => 'database.network.received.volume.bytespersecond', + format => '%.2f', + min => 0, + unit => 'B/s', + change_bytes => 1 + } + }, + threshold => 'received-volume', + order => 2 + }, + 'database/network/sent_bytes_count' => { + output_string => 'sent: %.2f', + perfdata => { + absolute => { + nlabel => 'database.network.sent.volume.bytes', + format => '%.2f', + min => 0, + unit => 'B', + change_bytes => 1 + }, + per_second => { + nlabel => 'database.network.sent.volume.bytespersecond', + format => '%.2f', + min => 0, + unit => 'B/s', + change_bytes => 1 + } + }, + threshold => 'sent-volume', + order => 3 + } + }; + + return $metrics_mapping; +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1); + bless $self, $class; + + $options{options}->add_options(arguments => { + 'dimension-name:s' => { name => 'dimension_name', default => 'resource.labels.database_id' }, + 'dimension-operator:s' => { name => 'dimension_operator', default => 'equals' }, + 'dimension-value:s' => { name => 'dimension_value' }, + 'filter-metric:s' => { name => 'filter_metric' }, + "per-second" => { name => 'per_second' }, + 'timeframe:s' => { name => 'timeframe' }, + 'aggregation:s@' => { name => 'aggregation' } + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + $self->{gcp_api} = 'cloudsql.googleapis.com'; + $self->{gcp_dimension_name} = (!defined($self->{option_results}->{dimension_name}) || $self->{option_results}->{dimension_name} eq '') ? 'resource.labels.database_id' : $self->{option_results}->{dimension_name}; + $self->{gcp_dimension_zeroed} = 'resource.labels.database_id'; + $self->{gcp_instance_key} = 'resource.labels.database_id'; + $self->{gcp_dimension_operator} = $self->{option_results}->{dimension_operator}; + $self->{gcp_dimension_value} = $self->{option_results}->{dimension_value}; +} + +1; + +__END__ + +=head1 MODE + +Check database instances network metrics. + +Example: + +perl centreon_plugins.pl --plugin=cloud::google::gcp::database::mysql::plugin +--mode=network --dimension-value=mydatabaseid --filter-metric='bytes' +--aggregation='average' --critical-received-volume='10' --verbose + +Default aggregation: 'average' / All aggregations are valid. + +=over 8 + +=item B<--dimension-name> + +Set dimension name (Default: 'resource.labels.database_id'). Can be: 'resources.labels.region'. + +=item B<--dimension-operator> + +Set dimension operator (Default: 'equals'. Can also be: 'regexp', 'starts'). + +=item B<--dimension-value> + +Set dimension value (Required). + +=item B<--filter-metric> + +Filter metrics (Can be: 'database/network/received_bytes_count', +'database/network/sent_bytes_count', 'database/network/connections') (Can be a regexp). + +=item B<--timeframe> + +Set timeframe in seconds (i.e. 3600 to check last hour). + +=item B<--aggregation> + +Set monitor aggregation (Can be multiple, Can be: 'minimum', 'maximum', 'average', 'total'). + +=item B<--warning-*> B<--critical-*> + +Thresholds (Can be: 'received-volume', 'sent-volume', +'connections'). + +=item B<--per-second> + +Change the data to be unit/sec. + +=back + +=cut diff --git a/cloud/google/gcp/database/common/mode/storage.pm b/cloud/google/gcp/database/common/mode/storage.pm new file mode 100644 index 000000000..1c1eaf5fc --- /dev/null +++ b/cloud/google/gcp/database/common/mode/storage.pm @@ -0,0 +1,163 @@ +# +# Copyright 2020 Centreon (http://www.centreon.com/) +# +# Centreon is a full-fledged industry-strength solution that meets +# the needs in IT infrastructure and application monitoring for +# service performance. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +package cloud::google::gcp::database::common::mode::storage; + +use base qw(cloud::google::gcp::custom::mode); + +use strict; +use warnings; + +sub get_metrics_mapping { + my ($self, %options) = @_; + + my $metrics_mapping = { + 'database/disk/bytes_used' => { + output_string => 'disk space usage: %.2f', + perfdata => { + absolute => { + nlabel => 'database.space.usage.bytes', + format => '%d', + unit => 'B', + change_bytes => 1 + } + }, + threshold => 'space-usage', + order => 1 + }, + 'database/disk/read_ops_count' => { + output_string => 'disk read IO operations: %.2f', + perfdata => { + absolute => { + nlabel => 'database.disk.read.io.operations.count', + format => '%.2f' + }, + per_second => { + nlabel => 'database.disk.read.io.operations.persecond', + format => '%.2f' + } + }, + threshold => 'read-operations', + order => 2 + }, + 'database/disk/write_ops_count' => { + output_string => 'disk write IO operations: %.2f', + perfdata => { + absolute => { + nlabel => 'database.disk.write.io.operations.count', + format => '%.2f' + }, + per_second => { + nlabel => 'database.disk.write.io.operations.persecond', + format => '%.2f' + } + }, + threshold => 'write-operations', + order => 3 + } + }; + + return $metrics_mapping; +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1); + bless $self, $class; + + $options{options}->add_options(arguments => { + 'dimension-name:s' => { name => 'dimension_name', default => 'resource.labels.database_id' }, + 'dimension-operator:s' => { name => 'dimension_operator', default => 'equals' }, + 'dimension-value:s' => { name => 'dimension_value' }, + 'filter-metric:s' => { name => 'filter_metric' }, + "per-second" => { name => 'per_second' }, + 'timeframe:s' => { name => 'timeframe' }, + 'aggregation:s@' => { name => 'aggregation' } + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + $self->{gcp_api} = 'cloudsql.googleapis.com'; + $self->{gcp_dimension_name} = (!defined($self->{option_results}->{dimension_name}) || $self->{option_results}->{dimension_name} eq '') ? 'resource.labels.database_id' : $self->{option_results}->{dimension_name}; + $self->{gcp_dimension_zeroed} = 'resource.labels.database_id'; + $self->{gcp_instance_key} = 'resource.labels.database_id'; + $self->{gcp_dimension_operator} = $self->{option_results}->{dimension_operator}; + $self->{gcp_dimension_value} = $self->{option_results}->{dimension_value}; +} + +1; + +__END__ + +=head1 MODE + +Check database storage metrics. + +Example: + +perl centreon_plugins.pl --plugin=cloud::google::gcp::database::mysql::plugin +--mode=diskio --dimension-value=mydatabaseid --filter-metric='space' +--aggregation='average' --verbose + +Default aggregation: 'average' / All aggregations are valid. + +=over 8 + +=item B<--dimension-name> + +Set dimension name (Default: 'resource.labels.database_id'). Can be: 'resources.labels.region'. + +=item B<--dimension-operator> + +Set dimension operator (Default: 'equals'. Can also be: 'regexp', 'starts'). + +=item B<--dimension-value> + +Set dimension value (Required). + +=item B<--filter-metric> + +Filter metrics (Can be: 'database/disk/bytes_used', +'database/disk/read_ops_count', 'databse/disk/write_ops_count') (Can be a regexp). + +=item B<--timeframe> + +Set timeframe in seconds (i.e. 3600 to check last hour). + +=item B<--aggregation> + +Set monitor aggregation (Can be multiple, Can be: 'minimum', 'maximum', 'average', 'total'). + +=item B<--warning-*> B<--critical-*> + +Thresholds (Can be: 'space-usage', 'read-operations', 'write-operations'). + +=item B<--per-second> + +Change the data to be unit/sec. + +=back + +=cut diff --git a/cloud/google/gcp/database/mysql/mode/innodb.pm b/cloud/google/gcp/database/mysql/mode/innodb.pm new file mode 100644 index 000000000..9b5cd1a3b --- /dev/null +++ b/cloud/google/gcp/database/mysql/mode/innodb.pm @@ -0,0 +1,189 @@ +# +# Copyright 2020 Centreon (http://www.centreon.com/) +# +# Centreon is a full-fledged industry-strength solution that meets +# the needs in IT infrastructure and application monitoring for +# service performance. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +package cloud::google::gcp::database::mysql::mode::innodb; + +use base qw(cloud::google::gcp::custom::mode); + +use strict; +use warnings; + +sub get_metrics_mapping { + my ($self, %options) = @_; + + my $metrics_mapping = { + 'database/mysql/innodb_data_fsyncs' => { + output_string => 'fsync calls: %.2f', + perfdata => { + absolute => { + nlabel => 'database.mysql.innodb.data_fsyncs.count', + format => '%.2f', + min => 0 + }, + per_second => { + nlabel => 'database.mysql.innodb.data_fsyncs.persecond', + format => '%.2f', + min => 0 + } + }, + threshold => 'fsyncs-calls', + order => 1 + }, + 'database/mysql/innodb_os_log_fsyncs' => { + output_string => 'fsync calls to the log file: %.2f', + perfdata => { + absolute => { + nlabel => 'database.mysql.innodb.os_log_fsyncs.count', + format => '%.2f', + min => 0 + }, + per_second => { + nlabel => 'database.mysql.innodb.os_log_fsyncs.persecond', + format => '%.2f', + min => 0 + } + }, + threshold => 'fsync-calls-logfile', + order => 2 + }, + 'database/mysql/innodb_pages_read' => { + output_string => 'pages read: %.2f', + perfdata => { + absolute => { + nlabel => 'database.mysql.innodb.pages_read.count', + format => '%.2f', + min => 0 + }, + per_second => { + nlabel => 'database.mysql.innodb.pages_read.persecond', + format => '%.2f', + min => 0 + } + }, + threshold => 'pages-read', + order => 3 + }, + 'database/mysql/innodb_pages_written' => { + output_string => 'pages written: %.2f', + perfdata => { + absolute => { + nlabel => 'database.mysql.innodb.pages_written.count', + format => '%.2f', + min => 0 + }, + per_second => { + nlabel => 'database.mysql.innodb.pages_written.persecond', + format => '%.2f', + min => 0 + } + }, + threshold => 'pages-written', + order => 4 + } + }; + + return $metrics_mapping; +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1); + bless $self, $class; + + $options{options}->add_options(arguments => { + 'dimension-name:s' => { name => 'dimension_name', default => 'resource.labels.database_id' }, + 'dimension-operator:s' => { name => 'dimension_operator', default => 'equals' }, + 'dimension-value:s' => { name => 'dimension_value' }, + 'filter-metric:s' => { name => 'filter_metric' }, + "per-second" => { name => 'per_second' }, + 'timeframe:s' => { name => 'timeframe' }, + 'aggregation:s@' => { name => 'aggregation' } + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + $self->{gcp_api} = 'cloudsql.googleapis.com'; + $self->{gcp_dimension_name} = (!defined($self->{option_results}->{dimension_name}) || $self->{option_results}->{dimension_name} eq '') ? 'resource.labels.database_id' : $self->{option_results}->{dimension_name}; + $self->{gcp_dimension_zeroed} = 'resource.labels.database_id'; + $self->{gcp_instance_key} = 'resource.labels.database_id'; + $self->{gcp_dimension_operator} = $self->{option_results}->{dimension_operator}; + $self->{gcp_dimension_value} = $self->{option_results}->{dimension_value}; +} + +1; + +__END__ + +=head1 MODE + +Check mysql innodb metrics. + +Example: + +perl centreon_plugins.pl --plugin=cloud::google::gcp::database::mysql::plugin +--mode=diskio --dimension-value=mydatabaseid --filter-metric='queries' +--aggregation='average' --verbose + +Default aggregation: 'average' / All aggregations are valid. + +=over 8 + +=item B<--dimension-name> + +Set dimension name (Default: 'resource.labels.database_id'). Can be: 'resources.labels.region'. + +=item B<--dimension-operator> + +Set dimension operator (Default: 'equals'. Can also be: 'regexp', 'starts'). + +=item B<--dimension-value> + +Set dimension value (Required). + +=item B<--filter-metric> + +Filter metrics (Can be: 'database/mysql/innodb_data_fsyncs', 'database/mysql/innodb_os_log_fsyncs', +'database/mysql/innodb_pages_read', 'database/mysql/innodb_pages_write') (Can be a regexp). + +=item B<--timeframe> + +Set timeframe in seconds (i.e. 3600 to check last hour). + +=item B<--aggregation> + +Set monitor aggregation (Can be multiple, Can be: 'minimum', 'maximum', 'average', 'total'). + +=item B<--warning-*> B<--critical-*> + +Thresholds (Can be: 'fsyncs-calls', 'fsync-calls-logfile', +'pages-read', 'pages-written'). + +=item B<--per-second> + +Change the data to be unit/sec. + +=back + +=cut diff --git a/cloud/google/gcp/database/mysql/mode/queries.pm b/cloud/google/gcp/database/mysql/mode/queries.pm new file mode 100644 index 000000000..6588863c0 --- /dev/null +++ b/cloud/google/gcp/database/mysql/mode/queries.pm @@ -0,0 +1,153 @@ +# +# Copyright 2020 Centreon (http://www.centreon.com/) +# +# Centreon is a full-fledged industry-strength solution that meets +# the needs in IT infrastructure and application monitoring for +# service performance. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +package cloud::google::gcp::database::mysql::mode::queries; + +use base qw(cloud::google::gcp::custom::mode); + +use strict; +use warnings; + +sub get_metrics_mapping { + my ($self, %options) = @_; + + my $metrics_mapping = { + 'database/mysql/questions' => { + output_string => 'questions: %.2f', + perfdata => { + absolute => { + nlabel => 'database.mysql.questions.count', + format => '%.2f', + min => 0 + }, + per_second => { + nlabel => 'database.mysql.questions.persecond', + format => '%.2f', + min => 0 + } + }, + threshold => 'questions', + order => 1 + }, + 'database/mysql/queries' => { + output_string => 'queries: %.2f', + perfdata => { + absolute => { + nlabel => 'database.mysql.queries.count', + format => '%.2f', + min => 0 + }, + per_second => { + nlabel => 'database.mysql.queries.persecond', + format => '%.2f', + min => 0 + } + }, + threshold => 'queries', + order => 2 + } + }; + + return $metrics_mapping; +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1); + bless $self, $class; + + $options{options}->add_options(arguments => { + 'dimension-name:s' => { name => 'dimension_name', default => 'resource.labels.database_id' }, + 'dimension-operator:s' => { name => 'dimension_operator', default => 'equals' }, + 'dimension-value:s' => { name => 'dimension_value' }, + 'filter-metric:s' => { name => 'filter_metric' }, + "per-second" => { name => 'per_second' }, + 'timeframe:s' => { name => 'timeframe' }, + 'aggregation:s@' => { name => 'aggregation' } + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + $self->{gcp_api} = 'cloudsql.googleapis.com'; + $self->{gcp_dimension_name} = (!defined($self->{option_results}->{dimension_name}) || $self->{option_results}->{dimension_name} eq '') ? 'resource.labels.database_id' : $self->{option_results}->{dimension_name}; + $self->{gcp_dimension_zeroed} = 'resource.labels.database_id'; + $self->{gcp_instance_key} = 'resource.labels.database_id'; + $self->{gcp_dimension_operator} = $self->{option_results}->{dimension_operator}; + $self->{gcp_dimension_value} = $self->{option_results}->{dimension_value}; +} + +1; + +__END__ + +=head1 MODE + +Check mysql queries metrics. + +Example: + +perl centreon_plugins.pl --plugin=cloud::google::gcp::database::mysql::plugin +--mode=diskio --dimension-value=mydatabaseid --filter-metric='queries' +--aggregation='average' --verbose + +Default aggregation: 'average' / All aggregations are valid. + +=over 8 + +=item B<--dimension-name> + +Set dimension name (Default: 'resource.labels.database_id'). Can be: 'resources.labels.region'. + +=item B<--dimension-operator> + +Set dimension operator (Default: 'equals'. Can also be: 'regexp', 'starts'). + +=item B<--dimension-value> + +Set dimension value (Required). + +=item B<--filter-metric> + +Filter metrics (Can be: 'database/mysql/questions', 'database/mysql/queries') (Can be a regexp). + +=item B<--timeframe> + +Set timeframe in seconds (i.e. 3600 to check last hour). + +=item B<--aggregation> + +Set monitor aggregation (Can be multiple, Can be: 'minimum', 'maximum', 'average', 'total'). + +=item B<--warning-*> B<--critical-*> + +Thresholds (Can be: 'queries', 'questions'). + +=item B<--per-second> + +Change the data to be unit/sec. + +=back + +=cut diff --git a/cloud/google/gcp/database/mysql/plugin.pm b/cloud/google/gcp/database/mysql/plugin.pm new file mode 100644 index 000000000..8fb7b8f8e --- /dev/null +++ b/cloud/google/gcp/database/mysql/plugin.pm @@ -0,0 +1,53 @@ +# +# Copyright 2020 Centreon (http://www.centreon.com/) +# +# Centreon is a full-fledged industry-strength solution that meets +# the needs in IT infrastructure and application monitoring for +# service performance. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +package cloud::google::gcp::database::mysql::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} = { + 'cpu' => 'cloud::google::gcp::database::common::mode::cpu', + 'innodb' => 'cloud::google::gcp::database::mysql::mode::innodb', + 'network' => 'cloud::google::gcp::database::common::mode::network', + 'queries' => 'cloud::google::gcp::database::mysql::mode::queries', + 'storage' => 'cloud::google::gcp::database::common::mode::storage' + }; + + $self->{custom_modes}->{api} = 'cloud::google::gcp::custom::api'; + return $self; +} + +1; + +__END__ + +=head1 PLUGIN DESCRIPTION + +Check Google Cloud Platform MySQL. + +=cut diff --git a/cloud/google/gcp/management/stackdriver/mode/getmetrics.pm b/cloud/google/gcp/management/stackdriver/mode/getmetrics.pm index 4252bfb39..53d2d09d0 100644 --- a/cloud/google/gcp/management/stackdriver/mode/getmetrics.pm +++ b/cloud/google/gcp/management/stackdriver/mode/getmetrics.pm @@ -24,7 +24,6 @@ use base qw(centreon::plugins::templates::counter); use strict; use warnings; -use Data::Dumper; sub custom_metric_perfdata { my ($self, %options) = @_; @@ -33,7 +32,7 @@ sub custom_metric_perfdata { label => $self->{result_values}->{perf_label}, value => $self->{result_values}->{value}, warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-metric'), - critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-metric'), + critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-metric') ); } @@ -42,16 +41,18 @@ sub custom_metric_threshold { my $exit = $self->{perfdata}->threshold_check( value => $self->{result_values}->{value}, - threshold => [ { label => 'critical-metric', exit_litteral => 'critical' }, - { label => 'warning-metric', exit_litteral => 'warning' } ]); + threshold => [ + { label => 'critical-metric', exit_litteral => 'critical' }, + { label => 'warning-metric', exit_litteral => 'warning' } + ] + ); return $exit; } sub custom_metric_output { my ($self, %options) = @_; - my $msg = "Metric '" . $self->{result_values}->{label} . "' of resource '" . $self->{result_values}->{display} . "' value is " . $self->{result_values}->{value}; - return $msg; + return "Metric '" . $self->{result_values}->{label} . "' of resource '" . $self->{result_values}->{display} . "' value is " . $self->{result_values}->{value}; } sub custom_metric_calc { @@ -69,17 +70,19 @@ sub set_counters { my ($self, %options) = @_; $self->{maps_counters_type} = [ - { name => 'metrics', type => 0 }, + { name => 'metrics', type => 1 } ]; $self->{maps_counters}->{metrics} = [ { label => 'metric', set => { - key_values => [ { name => 'value' }, { name => 'label' }, { name => 'aggregation' }, - { name => 'perf_label' }, { name => 'display' } ], + key_values => [ + { name => 'label' }, { name => 'value' }, { name => 'aggregation' }, + { name => 'perf_label' }, { name => 'display' } + ], closure_custom_calc => $self->can('custom_metric_calc'), 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'), + closure_custom_threshold_check => $self->can('custom_metric_threshold') } } ]; @@ -89,15 +92,18 @@ sub new { my ($class, %options) = @_; my $self = $class->SUPER::new(package => __PACKAGE__, %options); bless $self, $class; - + $options{options}->add_options(arguments => { - "dimension:s" => { name => 'dimension' }, - "instance:s" => { name => 'instance' }, - "metric:s" => { name => 'metric' }, - "api:s" => { name => 'api' }, - "extra-filter:s@" => { name => 'extra_filter' }, + 'dimension-name:s' => { name => 'dimension_name' }, + 'dimension-operator:s' => { name => 'dimension_operator', default => 'equals' }, + 'dimension-value:s' => { name => 'dimension_value' }, + 'instance-key:s' => { name => 'instance_key' }, + 'metric:s' => { name => 'metric' }, + 'api:s' => { name => 'api' }, + 'extra-filter:s@' => { name => 'extra_filter' }, + 'aggregation:s@' => { name => 'aggregation' } }); - + return $self; } @@ -105,12 +111,12 @@ sub check_options { my ($self, %options) = @_; $self->SUPER::check_options(%options); - if (!defined($self->{option_results}->{dimension})) { - $self->{output}->add_option_msg(short_msg => "Need to specify --dimension ."); + if (!defined($self->{option_results}->{dimension_name}) || $self->{option_results}->{dimension_name} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --dimension-name ."); $self->{output}->option_exit(); } - if (!defined($self->{option_results}->{instance})) { - $self->{output}->add_option_msg(short_msg => "Need to specify --instance ."); + if (!defined($self->{option_results}->{dimension_value}) || $self->{option_results}->{dimension_value} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --dimension-value ."); $self->{output}->option_exit(); } if (!defined($self->{option_results}->{metric})) { @@ -122,8 +128,11 @@ sub check_options { $self->{output}->option_exit(); } - $self->{gcp_dimension} = $self->{option_results}->{dimension}; - $self->{gcp_instance} = $self->{option_results}->{instance}; + $self->{gcp_dimension_name} = $self->{option_results}->{dimension_name}; + $self->{gcp_dimension_operator} = $self->{option_results}->{dimension_operator}; + $self->{gcp_dimension_value} = $self->{option_results}->{dimension_value}; + $self->{gcp_instance_key} = defined($self->{option_results}->{instance_key}) && $self->{option_results}->{instance_key} ne '' ? + $self->{option_results}->{instance_key} : $self->{option_results}->{dimension_name}; $self->{gcp_metric} = $self->{option_results}->{metric}; $self->{gcp_api} = $self->{option_results}->{api}; $self->{gcp_timeframe} = defined($self->{option_results}->{timeframe}) ? $self->{option_results}->{timeframe} : 600; @@ -136,47 +145,52 @@ sub check_options { } } } - - $self->{gcp_aggregation} = ['average']; + + my $aggregations = []; if (defined($self->{option_results}->{aggregation})) { - $self->{gcp_aggregation} = []; foreach my $aggregation (@{$self->{option_results}->{aggregation}}) { if ($aggregation ne '') { - push @{$self->{gcp_aggregation}}, lc($aggregation); + push @$aggregations, lc($aggregation); } } } + $self->{gcp_aggregations} = ['average']; + if (scalar(@$aggregations) > 0) { + $self->{gcp_aggregations} = @$aggregations; + } } sub manage_selection { my ($self, %options) = @_; + my $results = $options{custom}->gcp_get_metrics( + dimension_name => $self->{gcp_dimension_name}, + dimension_operator => $self->{gcp_dimension_operator}, + dimension_value => $self->{gcp_dimension_value}, + instance_key => $self->{gcp_instance_key}, + metric => $self->{gcp_metric}, + api => $self->{gcp_api}, + extra_filters => $self->{gcp_extra_filters}, + aggregations => $self->{gcp_aggregations}, + timeframe => $self->{gcp_timeframe} + ); + $self->{metrics} = {}; - - my ($results, $raw_results) = $options{custom}->gcp_get_metrics( - dimension => $self->{gcp_dimension}, - instance => $self->{gcp_instance}, - metric => $self->{gcp_metric}, - api => $self->{gcp_api}, - extra_filters => $self->{gcp_extra_filters}, - aggregations => $self->{gcp_aggregation}, - timeframe => $self->{gcp_timeframe}, - ); - - foreach my $label (keys %{$results}) { - foreach my $aggregation (('minimum', 'maximum', 'average', 'total')) { - next if (!defined($results->{$label}->{$aggregation})); - $self->{metrics} = { - display => $self->{gcp_instance}, - label => $label, - aggregation => $aggregation, - value => $results->{$label}->{$aggregation}, - perf_label => $label . '_' . $aggregation, - }; + foreach my $instance_name (keys %$results) { + foreach my $label (keys %{$results->{$instance_name}}) { + foreach my $aggregation (@{$self->{gcp_aggregations}}) { + next if (!defined($results->{$instance_name}->{$label}->{$aggregation})); + + $self->{metrics}->{ $label . '_' . $aggregation } = { + display => $instance_name, + label => $label, + aggregation => $aggregation, + value => $results->{$instance_name}->{$label}->{$aggregation}, + perf_label => $label . '_' . $aggregation + }; + } } - } - - $self->{output}->output_add(long_msg => sprintf("Raw data:\n%s", Dumper($raw_results)), debug => 1); + } } 1; @@ -190,8 +204,8 @@ Check GCP metrics. Example: perl centreon_plugins.pl --plugin=cloud::google::gcp::management::stackdriver::plugin ---custommode=api --mode=get-metrics --api='compute.googleapis.com' --dimension='metric.labels.instance_name' ---metric='instance/cpu/utilization' --instance=mycomputeinstance --aggregation=average +--custommode=api --mode=get-metrics --api='compute.googleapis.com' --metric='instance/cpu/utilization' +--dimension-name='metric.labels.instance_name' --dimension-operator=equals --dimension-value=mycomputeinstance --aggregation=average --timeframe=600 --warning-metric= --critical-metric= =over 8 @@ -204,13 +218,21 @@ Set GCP API (Required). Set stackdriver metric (Required). -=item B<--dimension> +=item B<--dimension-name> -Set dimension primary filter (Required). +Set dimension name (Required). -=item B<--instance> +=item B<--dimension-operator> -Set instance name (Required). +Set dimension operator (Default: 'equals'. Can also be: 'regexp', 'starts'). + +=item B<--dimension-value> + +Set dimension value (Required). + +=item B<--instance-key> + +Set instance key (By default, --dimension-name option is used). =item B<--warning-metric> diff --git a/cloud/google/gcp/management/stackdriver/plugin.pm b/cloud/google/gcp/management/stackdriver/plugin.pm index 9e8f06dc3..01b9da33d 100644 --- a/cloud/google/gcp/management/stackdriver/plugin.pm +++ b/cloud/google/gcp/management/stackdriver/plugin.pm @@ -30,11 +30,11 @@ sub new { bless $self, $class; $self->{version} = '1.0'; - %{$self->{modes}} = ( - 'get-metrics' => 'cloud::google::gcp::management::stackdriver::mode::getmetrics', - ); + $self->{modes} = { + 'get-metrics' => 'cloud::google::gcp::management::stackdriver::mode::getmetrics' + }; - $self->{custom_modes}{api} = 'cloud::google::gcp::custom::api'; + $self->{custom_modes}->{api} = 'cloud::google::gcp::custom::api'; return $self; } diff --git a/cloud/google/gcp/storage/mode/bucket.pm b/cloud/google/gcp/storage/mode/bucket.pm new file mode 100644 index 000000000..642fd62f5 --- /dev/null +++ b/cloud/google/gcp/storage/mode/bucket.pm @@ -0,0 +1,174 @@ +# +# Copyright 2020 Centreon (http://www.centreon.com/) +# +# Centreon is a full-fledged industry-strength solution that meets +# the needs in IT infrastructure and application monitoring for +# service performance. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +package cloud::google::gcp::storage::mode::bucket; + +use base qw(cloud::google::gcp::custom::mode); + +use strict; +use warnings; + +sub get_metrics_mapping { + my ($self, %options) = @_; + + my $metrics_mapping = { + 'storage/object_count' => { + output_string => 'objects: %.2f', + perfdata => { + absolute => { + nlabel => 'storage.bucket.objects.count', + format => '%.2f', + min => 0 + } + }, + threshold => 'bucket-objects', + order => 1 + }, + 'network/received_bytes_count' => { + output_string => 'received: %.2f', + perfdata => { + absolute => { + nlabel => 'storage.network.received.volume.bytes', + format => '%.2f', + min => 0, + unit => 'B', + change_bytes => 1 + }, + per_second => { + nlabel => 'storage.network.received.volume.bytespersecond', + format => '%.2f', + min => 0, + unit => 'B/s', + change_bytes => 1 + } + }, + threshold => 'received-volume', + order => 2 + }, + 'network/sent_bytes_count' => { + output_string => 'sent: %.2f', + perfdata => { + absolute => { + nlabel => 'storage.network.sent.volume.bytes', + format => '%.2f', + min => 0, + unit => 'B', + change_bytes => 1 + }, + per_second => { + nlabel => 'storage.network.sent.volume.bytespersecond', + format => '%.2f', + min => 0, + unit => 'B/s', + change_bytes => 1 + } + }, + threshold => 'sent-volume', + order => 3 + } + }; + + return $metrics_mapping; +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1); + bless $self, $class; + + $options{options}->add_options(arguments => { + 'dimension-name:s' => { name => 'dimension_name', default => 'resource.labels.bucket_name' }, + 'dimension-operator:s' => { name => 'dimension_operator', default => 'equals' }, + 'dimension-value:s' => { name => 'dimension_value' }, + 'filter-metric:s' => { name => 'filter_metric' }, + "per-second" => { name => 'per_second' }, + 'timeframe:s' => { name => 'timeframe' }, + 'aggregation:s@' => { name => 'aggregation' } + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + $self->{gcp_api} = 'storage.googleapis.com'; + $self->{gcp_dimension_name} = (!defined($self->{option_results}->{dimension_name}) || $self->{option_results}->{dimension_name} eq '') ? 'resource.labels.bucket_name' : $self->{option_results}->{dimension_name}; + $self->{gcp_dimension_zeroed} = 'resource.labels.bucket_name'; + $self->{gcp_instance_key} = 'resource.labels.bucket_name'; + $self->{gcp_dimension_operator} = $self->{option_results}->{dimension_operator}; + $self->{gcp_dimension_value} = $self->{option_results}->{dimension_value}; +} + +1; + +__END__ + +=head1 MODE + +Check storage network metrics. + +Example: + +perl centreon_plugins.pl --plugin=cloud::google::gcp::storage::plugin +--mode=network --dimension-value=mydatabaseid --filter-metric='sent' +--aggregation='average' --critical-received-volume='10' --verbose + +Default aggregation: 'average' / All aggregations are valid. + +=over 8 + +=item B<--dimension-name> + +Set dimension name (Default: 'resource.labels.bucket_name'). Can be: 'resources.labels.location'. + +=item B<--dimension-operator> + +Set dimension operator (Default: 'equals'. Can also be: 'regexp', 'starts'). + +=item B<--dimension-value> + +Set dimension value (Required). + +=item B<--filter-metric> + +Filter metrics (Can be: 'storage/object_count', 'network/received_bytes_count', +'network/sent_bytes_count') (Can be a regexp). + +=item B<--timeframe> + +Set timeframe in seconds (i.e. 3600 to check last hour). + +=item B<--aggregation> + +Set monitor aggregation (Can be multiple, Can be: 'minimum', 'maximum', 'average', 'total'). + +=item B<--warning-*> B<--critical-*> + +Thresholds (Can be: 'bucket-objects', 'received-volume', 'sent-volume'). + +=item B<--per-second> + +Change the data to be unit/sec. + +=back + +=cut diff --git a/cloud/google/gcp/storage/plugin.pm b/cloud/google/gcp/storage/plugin.pm new file mode 100644 index 000000000..5117752aa --- /dev/null +++ b/cloud/google/gcp/storage/plugin.pm @@ -0,0 +1,49 @@ +# +# Copyright 2020 Centreon (http://www.centreon.com/) +# +# Centreon is a full-fledged industry-strength solution that meets +# the needs in IT infrastructure and application monitoring for +# service performance. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +package cloud::google::gcp::storage::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' => 'cloud::google::gcp::storage::mode::bucket' + }; + + $self->{custom_modes}->{api} = 'cloud::google::gcp::custom::api'; + return $self; +} + +1; + +__END__ + +=head1 PLUGIN DESCRIPTION + +Check Google Cloud Platform Storage. + +=cut