From 1fd84b2802bc33c8b39e95035ead5d0f2a7cdd99 Mon Sep 17 00:00:00 2001 From: Colin Gagnaire Date: Mon, 29 Oct 2018 09:59:19 +0100 Subject: [PATCH] add prometheus cadvisor plugin (#1199) * add prometheus cadvisor plugin * change filtering --- .../prometheus/exporters/cadvisor/mode/cpu.pm | 187 +++++++++++ .../exporters/cadvisor/mode/listcontainers.pm | 155 +++++++++ .../exporters/cadvisor/mode/load.pm | 168 ++++++++++ .../exporters/cadvisor/mode/memory.pm | 301 ++++++++++++++++++ .../exporters/cadvisor/mode/storage.pm | 264 +++++++++++++++ .../exporters/cadvisor/mode/taskstate.pm | 212 ++++++++++++ cloud/prometheus/exporters/cadvisor/plugin.pm | 61 ++++ 7 files changed, 1348 insertions(+) create mode 100644 cloud/prometheus/exporters/cadvisor/mode/cpu.pm create mode 100644 cloud/prometheus/exporters/cadvisor/mode/listcontainers.pm create mode 100644 cloud/prometheus/exporters/cadvisor/mode/load.pm create mode 100644 cloud/prometheus/exporters/cadvisor/mode/memory.pm create mode 100644 cloud/prometheus/exporters/cadvisor/mode/storage.pm create mode 100644 cloud/prometheus/exporters/cadvisor/mode/taskstate.pm create mode 100644 cloud/prometheus/exporters/cadvisor/plugin.pm diff --git a/cloud/prometheus/exporters/cadvisor/mode/cpu.pm b/cloud/prometheus/exporters/cadvisor/mode/cpu.pm new file mode 100644 index 000000000..538ab66b2 --- /dev/null +++ b/cloud/prometheus/exporters/cadvisor/mode/cpu.pm @@ -0,0 +1,187 @@ +# +# 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::prometheus::exporters::cadvisor::mode::cpu; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'containers', type => 1, cb_prefix_output => 'prefix_containers_output', + message_multiple => 'All containers CPU usage are ok', skipped_code => { -10 => 1 } }, + ]; + + $self->{maps_counters}->{containers} = [ + { label => 'usage', set => { + key_values => [ { name => 'usage' }, { name => 'container' }, { name => 'pod' }, { name => 'perf' } ], + output_template => 'Usage: %.2f %%', + perfdatas => [ + { label => 'usage', value => 'usage_absolute', template => '%.2f', + min => 0, max => 100, unit => '%', + label_extra_instance => 1, instance_use => 'perf_absolute' }, + ], + } + }, + { label => 'throttled', set => { + key_values => [ { name => 'throttled' }, { name => 'container' }, { name => 'pod' }, { name => 'perf' } ], + output_template => 'Throttled: %.2f %%', + perfdatas => [ + { label => 'throttled', value => 'throttled_absolute', template => '%.2f', + min => 0, max => 100, unit => '%', + label_extra_instance => 1, instance_use => 'perf_absolute' }, + ], + } + }, + ]; +} + +sub prefix_containers_output { + my ($self, %options) = @_; + + return "Container '" . $options{instance_value}->{container} . "' [pod: " . $options{instance_value}->{pod} . "] CPU "; +} + +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 => + { + "container:s" => { name => 'container', default => 'container_name!~".*POD.*"' }, + "pod:s" => { name => 'pod', default => 'pod_name=~".*"' }, + "extra-filter:s@" => { name => 'extra_filter' }, + "metric-overload:s@" => { name => 'metric_overload' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + $self->{metrics} = { + 'throttled' => "^container_cpu_cfs_throttled_seconds_total.*", + 'usage' => "^container_cpu_usage_seconds_total.*", + }; + foreach my $metric (@{$self->{option_results}->{metric_overload}}) { + next if ($metric !~ /(.*),(.*)/); + $self->{metrics}->{$1} = $2 if (defined($self->{metrics}->{$1})); + } + + $self->{labels} = {}; + foreach my $label (('container', 'pod')) { + if ($self->{option_results}->{$label} !~ /^(\w+)[!~=]+\".*\"$/) { + $self->{output}->add_option_msg(short_msg => "Need to specify --" . $label . " option as a PromQL filter."); + $self->{output}->option_exit(); + } + $self->{labels}->{$label} = $1; + } + + $self->{extra_filter} = ''; + foreach my $filter (@{$self->{option_results}->{extra_filter}}) { + $self->{extra_filter} .= ',' . $filter; + } + + $self->{prom_timeframe} = defined($self->{option_results}->{timeframe}) ? $self->{option_results}->{timeframe} : 900; + $self->{prom_step} = defined($self->{option_results}->{step}) ? $self->{option_results}->{step} : "1m"; +} + +sub manage_selection { + my ($self, %options) = @_; + + $self->{containers} = {}; + + my $results = $options{custom}->query_range(queries => [ 'label_replace((irate({__name__=~"' . $self->{metrics}->{usage} . '",' . + 'cpu="total",' . + $self->{option_results}->{container} . ',' . + $self->{option_results}->{pod} . + $self->{extra_filter} . '}[1m])) * 100, "__name__", "usage", "", "")', + 'label_replace((irate({__name__=~"' . $self->{metrics}->{throttled} . '",' . + $self->{option_results}->{container} . ',' . + $self->{option_results}->{pod} . + $self->{extra_filter} . '}[1m])) * 100, "__name__", "throttled", "", "")' ], + timeframe => $self->{prom_timeframe}, step => $self->{prom_step}); + + foreach my $result (@{$results}) { + next if (!defined($result->{metric}->{$self->{labels}->{pod}}) || !defined($result->{metric}->{$self->{labels}->{container}})); + my $average = $options{custom}->compute(aggregation => 'average', values => $result->{values}); + $self->{containers}->{$result->{metric}->{$self->{labels}->{pod}} . "_" . $result->{metric}->{$self->{labels}->{container}}}->{container} = $result->{metric}->{$self->{labels}->{container}}; + $self->{containers}->{$result->{metric}->{$self->{labels}->{pod}} . "_" . $result->{metric}->{$self->{labels}->{container}}}->{pod} = $result->{metric}->{$self->{labels}->{pod}}; + $self->{containers}->{$result->{metric}->{$self->{labels}->{pod}} . "_" . $result->{metric}->{$self->{labels}->{container}}}->{perf} = $result->{metric}->{$self->{labels}->{pod}} . "_" . $result->{metric}->{$self->{labels}->{container}}; + $self->{containers}->{$result->{metric}->{$self->{labels}->{pod}} . "_" . $result->{metric}->{$self->{labels}->{container}}}->{$result->{metric}->{__name__}} = $average; + } + + if (scalar(keys %{$self->{containers}}) <= 0) { + $self->{output}->add_option_msg(short_msg => "No containers found."); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check containers CPU usage and throttled. + +=over 8 + +=item B<--container> + +Filter on a specific container (Must be a PromQL filter, Default: 'container_name!~".*POD.*"') + +=item B<--pod> + +Filter on a specific pod (Must be a PromQL filter, Default: 'pod_name=~".*"') + +=item B<--warning-*> + +Threshold warning. +Can be: 'usage', 'throttled'. + +=item B<--critical-*> + +Threshold critical. +Can be: 'usage', 'throttled'. + +=item B<--extra-filter> + +Add a PromQL filter (Can be multiple) + +Example : --extra-filter='name=~".*pretty.*"' + +=item B<--metric-overload> + +Overload default metrics name (Can be multiple, metric can be 'usage', 'throttled') + +Example : --metric-overload='metric,^my_metric_name$' + +=back + +=cut diff --git a/cloud/prometheus/exporters/cadvisor/mode/listcontainers.pm b/cloud/prometheus/exporters/cadvisor/mode/listcontainers.pm new file mode 100644 index 000000000..617b1f739 --- /dev/null +++ b/cloud/prometheus/exporters/cadvisor/mode/listcontainers.pm @@ -0,0 +1,155 @@ +# +# 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::prometheus::exporters::cadvisor::mode::listcontainers; + +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 => + { + "container:s" => { name => 'container', default => 'container_name!~".*POD.*"' }, + "pod:s" => { name => 'pod', default => 'pod_name=~".*"' }, + "namespace:s" => { name => 'namespace', default => 'namespace=~".*"' }, + "extra-filter:s@" => { name => 'extra_filter' }, + "metric-overload:s@" => { name => 'metric_overload' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::init(%options); + + $self->{metrics} = { + 'last_seen' => '^container_last_seen$', + }; + foreach my $metric (@{$self->{option_results}->{metric_overload}}) { + next if ($metric !~ /(.*),(.*)/); + $self->{metrics}->{$1} = $2 if (defined($self->{metrics}->{$1})); + } + + $self->{labels} = {}; + foreach my $label (('container', 'pod', 'namespace')) { + if ($self->{option_results}->{$label} !~ /^(\w+)[!~=]+\".*\"$/) { + $self->{output}->add_option_msg(short_msg => "Need to specify --" . $label . " option as a PromQL filter."); + $self->{output}->option_exit(); + } + $self->{labels}->{$label} = $1; + } + + $self->{extra_filter} = ''; + foreach my $filter (@{$self->{option_results}->{extra_filter}}) { + $self->{extra_filter} .= ',' . $filter; + } +} + +sub manage_selection { + my ($self, %options) = @_; + + $self->{containers} = $options{custom}->query(queries => [ '{__name__=~"' . $self->{metrics}->{last_seen} . '",' . + $self->{option_results}->{container} . ',' . + $self->{option_results}->{pod} . ',' . + $self->{option_results}->{namespace} . + $self->{extra_filter} . '}' ]); +} + +sub run { + my ($self, %options) = @_; + + $self->manage_selection(%options); + foreach my $container (@{$self->{containers}}) { + next if (!defined($container->{metric}->{name})); + $self->{output}->output_add(long_msg => sprintf("[container_name = %s][pod_name = %s][namespace = %s]", + $container->{metric}->{$self->{labels}->{container}}, $container->{metric}->{$self->{labels}->{pod}}, + $container->{metric}->{$self->{labels}->{namespace}})); + } + + $self->{output}->output_add(severity => 'OK', + short_msg => 'List containers:'); + $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 => ['container_name', 'pod_name', 'namespace']); +} + +sub disco_show { + my ($self, %options) = @_; + + $self->manage_selection(%options); + foreach my $container (@{$self->{containers}}) { + $self->{output}->add_disco_entry( + container_name => $container->{metric}->{$self->{labels}->{container}}, + pod_name => $container->{metric}->{$self->{labels}->{pod}}, + namespace => $container->{metric}->{$self->{labels}->{namespace}}, + ); + } +} + +1; + +__END__ + +=head1 MODE + +List containers. + +=over 8 + +=item B<--container> + +Filter on a specific container (Must be a PromQL filter, Default: 'container_name!~".*POD.*"') + +=item B<--pod> + +Filter on a specific pod (Must be a PromQL filter, Default: 'pod_name=~".*"') + +=item B<--namespace> + +Filter on a specific namespace (Must be a PromQL filter, Default: 'namespace=~".*"') + +=item B<--extra-filter> + +Add a PromQL filter (Can be multiple) + +Example : --extra-filter='name=~".*pretty.*"' + +=item B<--metric-overload> + +Overload default metrics name (Can be multiple, metric can be 'last_seen') + +Example : --metric-overload='metric,^my_metric_name$' + +=back + +=cut diff --git a/cloud/prometheus/exporters/cadvisor/mode/load.pm b/cloud/prometheus/exporters/cadvisor/mode/load.pm new file mode 100644 index 000000000..d2b0a736c --- /dev/null +++ b/cloud/prometheus/exporters/cadvisor/mode/load.pm @@ -0,0 +1,168 @@ +# +# 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::prometheus::exporters::cadvisor::mode::load; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'containers', type => 1, cb_prefix_output => 'prefix_containers_output', message_multiple => 'All containers load are ok' }, + ]; + + $self->{maps_counters}->{containers} = [ + { label => 'load', set => { + key_values => [ { name => 'load' }, { name => 'container' }, { name => 'pod' }, { name => 'perf' } ], + output_template => 'Load: %.2f', + output_change_bytes => 1, + perfdatas => [ + { label => 'load', value => 'load_absolute', template => '%.2f', + min => 0, label_extra_instance => 1, instance_use => 'perf_absolute' }, + ], + } + }, + ]; +} + +sub prefix_containers_output { + my ($self, %options) = @_; + + return "Container '" . $options{instance_value}->{container} . "' [pod: " . $options{instance_value}->{pod} . "] "; +} + +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 => + { + "container:s" => { name => 'container', default => 'container_name!~".*POD.*"' }, + "pod:s" => { name => 'pod', default => 'pod_name=~".*"' }, + "extra-filter:s@" => { name => 'extra_filter' }, + "metric-overload:s@" => { name => 'metric_overload' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + $self->{metrics} = { + 'load' => '^container_cpu_load_average_10s$', + }; + foreach my $metric (@{$self->{option_results}->{metric_overload}}) { + next if ($metric !~ /(.*),(.*)/); + $self->{metrics}->{$1} = $2 if (defined($self->{metrics}->{$1})); + } + + $self->{labels} = {}; + foreach my $label (('container', 'pod')) { + if ($self->{option_results}->{$label} !~ /^(\w+)[!~=]+\".*\"$/) { + $self->{output}->add_option_msg(short_msg => "Need to specify --" . $label . " option as a PromQL filter."); + $self->{output}->option_exit(); + } + $self->{labels}->{$label} = $1; + } + + $self->{extra_filter} = ''; + foreach my $filter (@{$self->{option_results}->{extra_filter}}) { + $self->{extra_filter} .= ',' . $filter; + } + + $self->{prom_timeframe} = defined($self->{option_results}->{timeframe}) ? $self->{option_results}->{timeframe} : 900; + $self->{prom_step} = defined($self->{option_results}->{step}) ? $self->{option_results}->{step} : "1m"; +} + +sub manage_selection { + my ($self, %options) = @_; + + $self->{containers} = {}; + + my $results = $options{custom}->query_range(queries => [ 'label_replace({__name__=~"' . $self->{metrics}->{load} . '",' . + $self->{option_results}->{container} . ',' . + $self->{option_results}->{pod} . + $self->{extra_filter} . '}, "__name__", "load", "", "")' ], + timeframe => $self->{prom_timeframe}, step => $self->{prom_step}); + + foreach my $result (@{$results}) { + next if (!defined($result->{metric}->{$self->{labels}->{pod}}) || !defined($result->{metric}->{$self->{labels}->{container}})); + my $average = $options{custom}->compute(aggregation => 'average', values => $result->{values}); + $self->{containers}->{$result->{metric}->{$self->{labels}->{pod}} . "_" . $result->{metric}->{$self->{labels}->{container}}}->{container} = $result->{metric}->{$self->{labels}->{container}}; + $self->{containers}->{$result->{metric}->{$self->{labels}->{pod}} . "_" . $result->{metric}->{$self->{labels}->{container}}}->{pod} = $result->{metric}->{$self->{labels}->{pod}}; + $self->{containers}->{$result->{metric}->{$self->{labels}->{pod}} . "_" . $result->{metric}->{$self->{labels}->{container}}}->{perf} = $result->{metric}->{$self->{labels}->{pod}} . "_" . $result->{metric}->{$self->{labels}->{container}}; + $self->{containers}->{$result->{metric}->{$self->{labels}->{pod}} . "_" . $result->{metric}->{$self->{labels}->{container}}}->{$result->{metric}->{__name__}} = $average; + } + + if (scalar(keys %{$self->{containers}}) <= 0) { + $self->{output}->add_option_msg(short_msg => "No containers found."); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check containers load. + +=over 8 + +=item B<--container> + +Filter on a specific container (Must be a PromQL filter, Default: 'container_name!~".*POD.*"') + +=item B<--pod> + +Filter on a specific pod (Must be a PromQL filter, Default: 'pod_name=~".*"') + +=item B<--warning-load> + +Threshold warning. + +=item B<--critical-load> + +Threshold critical. + +=item B<--extra-filter> + +Add a PromQL filter (Can be multiple) + +Example : --extra-filter='name=~".*pretty.*"' + +=item B<--metric-overload> + +Overload default metrics name (Can be multiple, metric can be 'load') + +Example : --metric-overload='metric,^my_metric_name$' + +=back + +=cut diff --git a/cloud/prometheus/exporters/cadvisor/mode/memory.pm b/cloud/prometheus/exporters/cadvisor/mode/memory.pm new file mode 100644 index 000000000..9c4a72c5e --- /dev/null +++ b/cloud/prometheus/exporters/cadvisor/mode/memory.pm @@ -0,0 +1,301 @@ +# +# 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::prometheus::exporters::cadvisor::mode::memory; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +my $instance_mode; + +sub custom_usage_perfdata { + my ($self, %options) = @_; + + my $label = 'used'; + my $value_perf = $self->{result_values}->{used}; + my $extra_label = ''; + $extra_label = '_' . $self->{result_values}->{perf} if (!defined($options{extra_instance}) || $options{extra_instance} != 0); + my %total_options = (); + if ($self->{result_values}->{total} > 0 && $instance_mode->{option_results}->{units} eq '%') { + $total_options{total} = $self->{result_values}->{total}; + $total_options{cast_int} = 1; + } + + $self->{output}->perfdata_add(label => $label . $extra_label, unit => 'B', + value => $value_perf, + warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{label}, %total_options), + critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{label}, %total_options), + min => 0, max => $total_options{total}); +} + +sub custom_usage_threshold { + my ($self, %options) = @_; + + return 'ok' if ($self->{result_values}->{total} <= 0 && $instance_mode->{option_results}->{units} eq '%'); + my ($exit, $threshold_value); + $threshold_value = $self->{result_values}->{used}; + if ($instance_mode->{option_results}->{units} eq '%') { + $threshold_value = $self->{result_values}->{prct_used}; + } + $exit = $self->{perfdata}->threshold_check(value => $threshold_value, threshold => [ { label => 'critical-' . $self->{label}, exit_litteral => 'critical' }, + { label => 'warning-'. $self->{label}, exit_litteral => 'warning' } ]); + return $exit; +} + +sub custom_usage_output { + my ($self, %options) = @_; + + my $msg; + my ($total_used_value, $total_used_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{used}); + if ($self->{result_values}->{total} <= 0) { + $msg = sprintf("Used: %s (unlimited)", $total_used_value . " " . $total_used_unit); + } else { + my ($total_size_value, $total_size_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{total}); + $msg = sprintf("Limits: %s, Used : %s (%.2f%%)", + $total_size_value . " " . $total_size_unit, + $total_used_value . " " . $total_used_unit, $self->{result_values}->{prct_used}); + } + + return $msg; +} + +sub custom_usage_calc { + my ($self, %options) = @_; + + $self->{result_values}->{container} = $options{new_datas}->{$self->{instance} . '_container'}; + $self->{result_values}->{pod} = $options{new_datas}->{$self->{instance} . '_pod'}; + $self->{result_values}->{perf} = $options{new_datas}->{$self->{instance} . '_perf'}; + $self->{result_values}->{total} = $options{new_datas}->{$self->{instance} . '_limits'}; + $self->{result_values}->{used} = $options{new_datas}->{$self->{instance} . '_usage'}; + return 0 if ($self->{result_values}->{total} == 0); + + $self->{result_values}->{prct_used} = $self->{result_values}->{used} * 100 / $self->{result_values}->{total}; + + return 0; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'containers', type => 1, cb_prefix_output => 'prefix_containers_output', message_multiple => 'All containers memory usage are ok' }, + ]; + + $self->{maps_counters}->{containers} = [ + { label => 'usage', set => { + key_values => [ { name => 'limits' }, { name => 'usage' }, { name => 'container' }, + { name => 'pod' }, { name => 'perf' } ], + closure_custom_calc => $self->can('custom_usage_calc'), + closure_custom_output => $self->can('custom_usage_output'), + closure_custom_perfdata => $self->can('custom_usage_perfdata'), + closure_custom_threshold_check => $self->can('custom_usage_threshold'), + } + }, + { label => 'working', set => { + key_values => [ { name => 'working' }, { name => 'container' }, { name => 'pod' }, { name => 'perf' } ], + output_template => 'Working: %.2f %s', + output_change_bytes => 1, + perfdatas => [ + { label => 'working', value => 'working_absolute', template => '%s', + min => 0, unit => 'B', label_extra_instance => 1, instance_use => 'perf_absolute' }, + ], + } + }, + { label => 'cache', set => { + key_values => [ { name => 'cache' }, { name => 'container' }, { name => 'pod' }, { name => 'perf' } ], + output_template => 'Cache: %.2f %s', + output_change_bytes => 1, + perfdatas => [ + { label => 'cache', value => 'cache_absolute', template => '%s', + min => 0, unit => 'B', label_extra_instance => 1, instance_use => 'perf_absolute' }, + ], + } + }, + { label => 'rss', set => { + key_values => [ { name => 'rss' }, { name => 'container' }, { name => 'pod' }, { name => 'perf' } ], + output_template => 'Rss: %.2f %s', + output_change_bytes => 1, + perfdatas => [ + { label => 'rss', value => 'rss_absolute', template => '%s', + min => 0, unit => 'B', label_extra_instance => 1, instance_use => 'perf_absolute' }, + ], + } + }, + { label => 'swap', set => { + key_values => [ { name => 'swap' }, { name => 'container' }, { name => 'pod' }, { name => 'perf' } ], + output_template => 'Swap: %.2f %s', + output_change_bytes => 1, + perfdatas => [ + { label => 'swap', value => 'swap_absolute', template => '%s', + min => 0, unit => 'B', label_extra_instance => 1, instance_use => 'perf_absolute' }, + ], + } + }, + ]; +} + +sub prefix_containers_output { + my ($self, %options) = @_; + + return "Container '" . $options{instance_value}->{container} . "' [pod: " . $options{instance_value}->{pod} . "] Memory "; +} + +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 => + { + "container:s" => { name => 'container', default => 'container_name!~".*POD.*"' }, + "pod:s" => { name => 'pod', default => 'pod_name=~".*"' }, + "extra-filter:s@" => { name => 'extra_filter' }, + "units:s" => { name => 'units', default => '%' }, + "metric-overload:s@" => { name => 'metric_overload' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + $self->{metrics} = { + 'limits' => "^container_spec_memory_limit_bytes.*", + 'usage' => "^container_memory_usage_bytes.*", + 'working' => "^container_memory_working_set_bytes.*", + 'cache' => "^container_memory_cache.*", + 'rss' => "^container_memory_rss.*", + 'swap' => "^container_memory_swap.*", + }; + foreach my $metric (@{$self->{option_results}->{metric_overload}}) { + next if ($metric !~ /(.*),(.*)/); + $self->{metrics}->{$1} = $2 if (defined($self->{metrics}->{$1})); + } + + $self->{labels} = {}; + foreach my $label (('container', 'pod')) { + if ($self->{option_results}->{$label} !~ /^(\w+)[!~=]+\".*\"$/) { + $self->{output}->add_option_msg(short_msg => "Need to specify --" . $label . " option as a PromQL filter."); + $self->{output}->option_exit(); + } + $self->{labels}->{$label} = $1; + } + + $self->{extra_filter} = ''; + foreach my $filter (@{$self->{option_results}->{extra_filter}}) { + $self->{extra_filter} .= ',' . $filter; + } + + $instance_mode = $self; +} + +sub manage_selection { + my ($self, %options) = @_; + + $self->{containers} = {}; + + my $results = $options{custom}->query(queries => [ 'label_replace({__name__=~"' . $self->{metrics}->{usage} . '",' . + $self->{option_results}->{container} . ',' . + $self->{option_results}->{pod} . + $self->{extra_filter} . '}, "__name__", "usage", "", "")', + 'label_replace({__name__=~"' . $self->{metrics}->{limits} . '",' . + $self->{option_results}->{container} . ',' . + $self->{option_results}->{pod} . + $self->{extra_filter} . '}, "__name__", "limits", "", "")', + 'label_replace({__name__=~"' . $self->{metrics}->{working} . '",' . + $self->{option_results}->{container} . ',' . + $self->{option_results}->{pod} . + $self->{extra_filter} . '}, "__name__", "working", "", "")', + 'label_replace({__name__=~"' . $self->{metrics}->{cache} . '",' . + $self->{option_results}->{container} . ',' . + $self->{option_results}->{pod} . + $self->{extra_filter} . '}, "__name__", "cache", "", "")', + 'label_replace({__name__=~"' . $self->{metrics}->{rss} . '",' . + $self->{option_results}->{container} . ',' . + $self->{option_results}->{pod} . + $self->{extra_filter} . '}, "__name__", "rss", "", "")', + 'label_replace({__name__=~"' . $self->{metrics}->{swap} . '",' . + $self->{option_results}->{container} . ',' . + $self->{option_results}->{pod} . + $self->{extra_filter} . '}, "__name__", "swap", "", "")' ]); + + foreach my $result (@{$results}) { + next if (!defined($result->{metric}->{$self->{labels}->{pod}}) || !defined($result->{metric}->{$self->{labels}->{container}})); + $self->{containers}->{$result->{metric}->{$self->{labels}->{pod}} . "_" . $result->{metric}->{$self->{labels}->{container}}}->{container} = $result->{metric}->{$self->{labels}->{container}}; + $self->{containers}->{$result->{metric}->{$self->{labels}->{pod}} . "_" . $result->{metric}->{$self->{labels}->{container}}}->{pod} = $result->{metric}->{$self->{labels}->{pod}}; + $self->{containers}->{$result->{metric}->{$self->{labels}->{pod}} . "_" . $result->{metric}->{$self->{labels}->{container}}}->{perf} = $result->{metric}->{$self->{labels}->{pod}} . "_" . $result->{metric}->{$self->{labels}->{container}}; + $self->{containers}->{$result->{metric}->{$self->{labels}->{pod}} . "_" . $result->{metric}->{$self->{labels}->{container}}}->{$result->{metric}->{__name__}} = ${$result->{value}}[1]; + } + + if (scalar(keys %{$self->{containers}}) <= 0) { + $self->{output}->add_option_msg(short_msg => "No containers found."); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check containers memory usage. + +=over 8 + +=item B<--container> + +Filter on a specific container (Must be a PromQL filter, Default: 'container_name!~".*POD.*"') + +=item B<--pod> + +Filter on a specific pod (Must be a PromQL filter, Default: 'pod_name=~".*"') + +=item B<--warning-*> + +Threshold warning. +Can be: 'usage', 'working', 'cache', 'rss', 'swap'. + +=item B<--critical-*> + +Threshold critical. +Can be: 'usage', 'working', 'cache', 'rss', 'swap'. + +=item B<--extra-filter> + +Add a PromQL filter (Can be multiple) + +Example : --extra-filter='name=~".*pretty.*"' + +=item B<--metric-overload> + +Overload default metrics name (Can be multiple, metric can be 'limits', +'usage', 'working', 'cache', 'rss', 'swap'.) + +Example : --metric-overload='metric,^my_metric_name$' + +=back + +=cut diff --git a/cloud/prometheus/exporters/cadvisor/mode/storage.pm b/cloud/prometheus/exporters/cadvisor/mode/storage.pm new file mode 100644 index 000000000..97be237c6 --- /dev/null +++ b/cloud/prometheus/exporters/cadvisor/mode/storage.pm @@ -0,0 +1,264 @@ +# +# 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::prometheus::exporters::cadvisor::mode::storage; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +my $instance_mode; + +sub custom_usage_perfdata { + my ($self, %options) = @_; + + my $label = 'used'; + my $value_perf = $self->{result_values}->{used}; + if (defined($instance_mode->{option_results}->{free})) { + $label = 'free'; + $value_perf = $self->{result_values}->{free}; + } + my $extra_label = ''; + $extra_label = '_' . $self->{result_values}->{perf} if (!defined($options{extra_instance}) || $options{extra_instance} != 0); + $extra_label .= '_' . $self->{result_values}->{device} if (!defined($options{extra_instance_lvl2}) || $options{extra_instance_lvl2} != 0); + my %total_options = (); + if ($instance_mode->{option_results}->{units} eq '%') { + $total_options{total} = $self->{result_values}->{total}; + $total_options{cast_int} = 1; + } + + $self->{output}->perfdata_add(label => $label . $extra_label, unit => 'B', + value => $value_perf, + warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{label}, %total_options), + critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{label}, %total_options), + min => 0, max => $self->{result_values}->{total}); +} + +sub custom_usage_threshold { + my ($self, %options) = @_; + + my ($exit, $threshold_value); + $threshold_value = $self->{result_values}->{used}; + $threshold_value = $self->{result_values}->{free} if (defined($instance_mode->{option_results}->{free})); + if ($instance_mode->{option_results}->{units} eq '%') { + $threshold_value = $self->{result_values}->{prct_used}; + $threshold_value = $self->{result_values}->{prct_free} if (defined($instance_mode->{option_results}->{free})); + } + $exit = $self->{perfdata}->threshold_check(value => $threshold_value, threshold => [ { label => 'critical-' . $self->{label}, exit_litteral => 'critical' }, { label => 'warning-'. $self->{label}, exit_litteral => 'warning' } ]); + return $exit; +} + +sub custom_usage_output { + my ($self, %options) = @_; + + my ($total_limit_value, $total_limit_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{total}); + my ($total_used_value, $total_used_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{used}); + my ($total_free_value, $total_free_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{free}); + my $msg = sprintf("Usage Limit: %s Used: %s (%.2f%%) Free: %s (%.2f%%)", + $total_limit_value . " " . $total_limit_unit, + $total_used_value . " " . $total_used_unit, $self->{result_values}->{prct_used}, + $total_free_value . " " . $total_free_unit, $self->{result_values}->{prct_free}); + return $msg; +} + +sub custom_usage_calc { + my ($self, %options) = @_; + + $self->{result_values}->{container} = $options{new_datas}->{$self->{instance} . '_container'}; + $self->{result_values}->{pod} = $options{new_datas}->{$self->{instance} . '_pod'}; + $self->{result_values}->{perf} = $options{new_datas}->{$self->{instance} . '_perf'}; + $self->{result_values}->{total} = $options{new_datas}->{$self->{instance} . '_limit'}; + $self->{result_values}->{used} = $options{new_datas}->{$self->{instance} . '_used'}; + $self->{result_values}->{free} = $self->{result_values}->{total} - $self->{result_values}->{used}; + $self->{result_values}->{prct_used} = ($self->{result_values}->{total} > 0) ? $self->{result_values}->{used} * 100 / $self->{result_values}->{total} : 0; + $self->{result_values}->{prct_free} = 100 - $self->{result_values}->{prct_used}; + + # limit to 100. Better output. + if ($self->{result_values}->{prct_used} > 100) { + $self->{result_values}->{free} = 0; + $self->{result_values}->{prct_used} = 100; + $self->{result_values}->{prct_free} = 0; + } + + return 0; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'containers', type => 3, cb_prefix_output => 'prefix_containers_output', message_multiple => 'All containers storages usage are ok', + counters => [ { name => 'storage', type => 1, cb_prefix_output => 'prefix_storage_output', message_multiple => 'All storages usage are ok' } ] }, + ]; + + $self->{maps_counters}->{storage} = [ + { label => 'usage', set => { + key_values => [ { name => 'used' }, { name => 'limit' }, { name => 'container' }, { name => 'pod' }, + { name => 'perf' } ], + closure_custom_calc => $self->can('custom_usage_calc'), + closure_custom_output => $self->can('custom_usage_output'), + closure_custom_perfdata => $self->can('custom_usage_perfdata'), + closure_custom_threshold_check => $self->can('custom_usage_threshold'), + } + }, + ]; +} + +sub prefix_storage_output { + my ($self, %options) = @_; + + return "Container '" . $options{instance_value}->{container} . "' [pod: " . $options{instance_value}->{pod} . "] Device '" . $options{instance_value}->{device} . "' "; +} + +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 => + { + "container:s" => { name => 'container', default => 'container_name!~".*POD.*"' }, + "pod:s" => { name => 'pod', default => 'pod_name=~".*"' }, + "device:s" => { name => 'device', default => 'device=~".*"' }, + "extra-filter:s@" => { name => 'extra_filter' }, + "units:s" => { name => 'units', default => '%' }, + "free" => { name => 'free' }, + "metric-overload:s@" => { name => 'metric_overload' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + $self->{metrics} = { + 'used' => "^container_fs_usage_bytes.*", + 'limit' => "^container_fs_limit_bytes.*", + }; + foreach my $metric (@{$self->{option_results}->{metric_overload}}) { + next if ($metric !~ /(.*),(.*)/); + $self->{metrics}->{$1} = $2 if (defined($self->{metrics}->{$1})); + } + + $self->{labels} = {}; + foreach my $label (('container', 'pod', 'device')) { + if ($self->{option_results}->{$label} !~ /^(\w+)[!~=]+\".*\"$/) { + $self->{output}->add_option_msg(short_msg => "Need to specify --" . $label . " option as a PromQL filter."); + $self->{output}->option_exit(); + } + $self->{labels}->{$label} = $1; + } + + $self->{extra_filter} = ''; + foreach my $filter (@{$self->{option_results}->{extra_filter}}) { + $self->{extra_filter} .= ',' . $filter; + } + + $instance_mode = $self; +} + +sub manage_selection { + my ($self, %options) = @_; + + $self->{containers} = {}; + + my $results = $options{custom}->query(queries => [ 'label_replace({__name__=~"' . $self->{metrics}->{used} . '",' . + $self->{option_results}->{container} . ',' . + $self->{option_results}->{pod} . ',' . + $self->{option_results}->{device} . + $self->{extra_filter} . '}, "__name__", "used", "", "")', + 'label_replace({__name__=~"' . $self->{metrics}->{limit} . '",' . + $self->{option_results}->{container} . ',' . + $self->{option_results}->{pod} . ',' . + $self->{option_results}->{device} . + $self->{extra_filter} . '}, "__name__", "limit", "", "")' ]); + + foreach my $result (@{$results}) { + next if (!defined($result->{metric}->{$self->{labels}->{pod}}) || !defined($result->{metric}->{$self->{labels}->{container}})); + $self->{containers}->{$result->{metric}->{$self->{labels}->{pod}} . "_" . $result->{metric}->{$self->{labels}->{container}}}->{storage}->{$result->{metric}->{$self->{labels}->{device}}}->{container} = $result->{metric}->{$self->{labels}->{container}}; + $self->{containers}->{$result->{metric}->{$self->{labels}->{pod}} . "_" . $result->{metric}->{$self->{labels}->{container}}}->{storage}->{$result->{metric}->{$self->{labels}->{device}}}->{pod} = $result->{metric}->{$self->{labels}->{pod}}; + $self->{containers}->{$result->{metric}->{$self->{labels}->{pod}} . "_" . $result->{metric}->{$self->{labels}->{container}}}->{storage}->{$result->{metric}->{$self->{labels}->{device}}}->{device} = $result->{metric}->{$self->{labels}->{device}}; + $self->{containers}->{$result->{metric}->{$self->{labels}->{pod}} . "_" . $result->{metric}->{$self->{labels}->{container}}}->{storage}->{$result->{metric}->{$self->{labels}->{device}}}->{perf} = $result->{metric}->{$self->{labels}->{pod}} . "_" . $result->{metric}->{$self->{labels}->{container}}; + $self->{containers}->{$result->{metric}->{$self->{labels}->{pod}} . "_" . $result->{metric}->{$self->{labels}->{container}}}->{storage}->{$result->{metric}->{$self->{labels}->{device}}}->{$result->{metric}->{__name__}} = ${$result->{value}}[1]; + } + + if (scalar(keys %{$self->{containers}}) <= 0) { + $self->{output}->add_option_msg(short_msg => "No containers found."); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check containers storages usage. + +=over 8 + +=item B<--container> + +Filter on a specific container (Must be a PromQL filter, Default: 'container_name!~".*POD.*"') + +=item B<--pod> + +Filter on a specific pod (Must be a PromQL filter, Default: 'pod_name=~".*"') + +=item B<--device> + +Filter on a specific device (Must be a PromQL filter, Default: 'device=~".*"') + +=item B<--units> + +Units of thresholds (Default: '%') ('%', 'B'). + +=item B<--free> + +Thresholds are on free space left. + +=item B<--warning-usage> + +Threshold warning. + +=item B<--critical-usage> + +Threshold critical. + +=item B<--extra-filter> + +Add a PromQL filter (Can be multiple) + +Example : --extra-filter='name=~".*pretty.*"' + +=item B<--metric-overload> + +Overload default metrics name (Can be multiple, metric can be 'used', 'limit') + +Example : --metric-overload='metric,^my_metric_name$' + +=back + +=cut diff --git a/cloud/prometheus/exporters/cadvisor/mode/taskstate.pm b/cloud/prometheus/exporters/cadvisor/mode/taskstate.pm new file mode 100644 index 000000000..7f060ae88 --- /dev/null +++ b/cloud/prometheus/exporters/cadvisor/mode/taskstate.pm @@ -0,0 +1,212 @@ +# +# 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::prometheus::exporters::cadvisor::mode::taskstate; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'containers', type => 1, cb_prefix_output => 'prefix_containers_output', + message_multiple => 'All containers tasks states are ok', skipped_code => { -10 => 1 } }, + ]; + + $self->{maps_counters}->{containers} = [ + { label => 'sleeping', set => { + key_values => [ { name => 'sleeping' }, { name => 'container' }, { name => 'pod' }, { name => 'perf' } ], + output_template => 'Sleeping: %d', + output_change_bytes => 1, + perfdatas => [ + { label => 'tasks_sleeping', value => 'sleeping_absolute', template => '%d', + min => 0, label_extra_instance => 1, instance_use => 'perf_absolute' }, + ], + } + }, + { label => 'running', set => { + key_values => [ { name => 'running' }, { name => 'container' }, { name => 'pod' }, { name => 'perf' } ], + output_template => 'Running: %d', + output_change_bytes => 1, + perfdatas => [ + { label => 'tasks_running', value => 'running_absolute', template => '%d', + min => 0, label_extra_instance => 1, instance_use => 'perf_absolute' }, + ], + } + }, + { label => 'stopped', set => { + key_values => [ { name => 'stopped' }, { name => 'container' }, { name => 'pod' }, { name => 'perf' } ], + output_template => 'Stopped: %d', + output_change_bytes => 1, + perfdatas => [ + { label => 'tasks_stopped', value => 'stopped_absolute', template => '%d', + min => 0, label_extra_instance => 1, instance_use => 'perf_absolute' }, + ], + } + }, + { label => 'uninterruptible', set => { + key_values => [ { name => 'uninterruptible' }, { name => 'container' }, { name => 'pod' }, { name => 'perf' } ], + output_template => 'Uninterruptible: %d', + output_change_bytes => 1, + perfdatas => [ + { label => 'tasks_uninterruptible', value => 'uninterruptible_absolute', template => '%d', + min => 0, label_extra_instance => 1, instance_use => 'perf_absolute' }, + ], + } + }, + { label => 'iowaiting', set => { + key_values => [ { name => 'iowaiting' }, { name => 'container' }, { name => 'pod' }, { name => 'perf' } ], + output_template => 'Iowaiting: %d', + output_change_bytes => 1, + perfdatas => [ + { label => 'tasks_iowaiting', value => 'iowaiting_absolute', template => '%d', + min => 0, label_extra_instance => 1, instance_use => 'perf_absolute' }, + ], + } + }, + ]; +} + +sub prefix_containers_output { + my ($self, %options) = @_; + + return "Container '" . $options{instance_value}->{container} . "' [pod: " . $options{instance_value}->{pod} . "] Tasks "; +} + +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 => + { + "container:s" => { name => 'container', default => 'container_name!~".*POD.*"' }, + "pod:s" => { name => 'pod', default => 'pod_name=~".*"' }, + "state:s" => { name => 'state', default => 'state=~".*"' }, + "extra-filter:s@" => { name => 'extra_filter' }, + "metric-overload:s@" => { name => 'metric_overload' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + $self->{metrics} = { + 'tasks_state' => '^container_tasks_state$', + }; + foreach my $metric (@{$self->{option_results}->{metric_overload}}) { + next if ($metric !~ /(.*),(.*)/); + $self->{metrics}->{$1} = $2 if (defined($self->{metrics}->{$1})); + } + + $self->{labels} = {}; + foreach my $label (('container', 'pod', 'state')) { + if ($self->{option_results}->{$label} !~ /^(\w+)[!~=]+\".*\"$/) { + $self->{output}->add_option_msg(short_msg => "Need to specify --" . $label . " option as a PromQL filter."); + $self->{output}->option_exit(); + } + $self->{labels}->{$label} = $1; + } + + $self->{extra_filter} = ''; + foreach my $filter (@{$self->{option_results}->{extra_filter}}) { + $self->{extra_filter} .= ',' . $filter; + } +} + +sub manage_selection { + my ($self, %options) = @_; + + $self->{containers} = {}; + + my $results = $options{custom}->query(queries => [ 'label_replace({__name__=~"' . $self->{metrics}->{tasks_state} . '",' . + $self->{option_results}->{container} . ',' . + $self->{option_results}->{pod} . ',' . + $self->{option_results}->{state} . + $self->{extra_filter} . '}, "__name__", "tasks_state", "", "")' ]); + + foreach my $result (@{$results}) { + next if (!defined($result->{metric}->{$self->{labels}->{pod}}) || !defined($result->{metric}->{$self->{labels}->{container}})); + $self->{containers}->{$result->{metric}->{$self->{labels}->{pod}} . "_" . $result->{metric}->{$self->{labels}->{container}}}->{container} = $result->{metric}->{$self->{labels}->{container}}; + $self->{containers}->{$result->{metric}->{$self->{labels}->{pod}} . "_" . $result->{metric}->{$self->{labels}->{container}}}->{pod} = $result->{metric}->{$self->{labels}->{pod}}; + $self->{containers}->{$result->{metric}->{$self->{labels}->{pod}} . "_" . $result->{metric}->{$self->{labels}->{container}}}->{perf} = $result->{metric}->{$self->{labels}->{pod}} . "_" . $result->{metric}->{$self->{labels}->{container}}; + $self->{containers}->{$result->{metric}->{$self->{labels}->{pod}} . "_" . $result->{metric}->{$self->{labels}->{container}}}->{$result->{metric}->{$self->{labels}->{state}}} = ${$result->{value}}[1]; + } + + if (scalar(keys %{$self->{containers}}) <= 0) { + $self->{output}->add_option_msg(short_msg => "No containers found."); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check containers number of tasks in given state. + +=over 8 + +=item B<--container> + +Filter on a specific container (Must be a PromQL filter, Default: 'container_name!~".*POD.*"') + +=item B<--pod> + +Filter on a specific pod (Must be a PromQL filter, Default: 'pod_name=~".*"') + +=item B<--state> + +Filter on a specific state (Must be a PromQL filter, Default: 'state=~".*"') + +=item B<--warning-*> + +Threshold warning. +Can be: 'sleeping', 'running', 'stopped', 'uninterruptible', 'iowaiting'. + +=item B<--critical-*> + +Threshold critical. +Can be: 'sleeping', 'running', 'stopped', 'uninterruptible', 'iowaiting'. + +=item B<--extra-filter> + +Add a PromQL filter (Can be multiple) + +Example : --extra-filter='name=~".*pretty.*"' + +=item B<--metric-overload> + +Overload default metrics name (Can be multiple, metric can be 'tasks_state') + +Example : --metric-overload='metric,^my_metric_name$' + +=back + +=cut diff --git a/cloud/prometheus/exporters/cadvisor/plugin.pm b/cloud/prometheus/exporters/cadvisor/plugin.pm new file mode 100644 index 000000000..ab3fa7fef --- /dev/null +++ b/cloud/prometheus/exporters/cadvisor/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::prometheus::exporters::cadvisor::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::prometheus::exporters::cadvisor::mode::cpu', + 'list-containers' => 'cloud::prometheus::exporters::cadvisor::mode::listcontainers', + 'load' => 'cloud::prometheus::exporters::cadvisor::mode::load', + 'memory' => 'cloud::prometheus::exporters::cadvisor::mode::memory', + 'storage' => 'cloud::prometheus::exporters::cadvisor::mode::storage', + 'task-state' => 'cloud::prometheus::exporters::cadvisor::mode::taskstate', + ); + + $self->{custom_modes}{api} = 'cloud::prometheus::restapi::custom::api'; + return $self; +} + +sub init { + my ( $self, %options ) = @_; + + $self->SUPER::init(%options); +} + + +1; + +__END__ + +=head1 PLUGIN DESCRIPTION + +Check cAdvisor metrics through Prometheus server. + +=cut