From a04acaf3a0dc4de751e0c8c505310c76b1505723 Mon Sep 17 00:00:00 2001 From: Colin Gagnaire Date: Fri, 19 Oct 2018 09:54:33 +0200 Subject: [PATCH] add prometheus kubernetes plugin (#1181) --- .../direct/kubernetes/mode/containerstatus.pm | 267 ++++++++++++++++ .../direct/kubernetes/mode/daemonsetstatus.pm | 266 ++++++++++++++++ .../kubernetes/mode/deploymentstatus.pm | 249 +++++++++++++++ .../direct/kubernetes/mode/listcontainers.pm | 134 ++++++++ .../direct/kubernetes/mode/listdaemonsets.pm | 131 ++++++++ .../direct/kubernetes/mode/listdeployments.pm | 129 ++++++++ .../direct/kubernetes/mode/listnamespaces.pm | 129 ++++++++ .../direct/kubernetes/mode/listnodes.pm | 138 +++++++++ .../direct/kubernetes/mode/listservices.pm | 131 ++++++++ .../direct/kubernetes/mode/namespacestatus.pm | 235 ++++++++++++++ .../direct/kubernetes/mode/nodestatus.pm | 293 ++++++++++++++++++ .../prometheus/direct/kubernetes/plugin.pm | 67 ++++ 12 files changed, 2169 insertions(+) create mode 100644 centreon-plugins/cloud/prometheus/direct/kubernetes/mode/containerstatus.pm create mode 100644 centreon-plugins/cloud/prometheus/direct/kubernetes/mode/daemonsetstatus.pm create mode 100644 centreon-plugins/cloud/prometheus/direct/kubernetes/mode/deploymentstatus.pm create mode 100644 centreon-plugins/cloud/prometheus/direct/kubernetes/mode/listcontainers.pm create mode 100644 centreon-plugins/cloud/prometheus/direct/kubernetes/mode/listdaemonsets.pm create mode 100644 centreon-plugins/cloud/prometheus/direct/kubernetes/mode/listdeployments.pm create mode 100644 centreon-plugins/cloud/prometheus/direct/kubernetes/mode/listnamespaces.pm create mode 100644 centreon-plugins/cloud/prometheus/direct/kubernetes/mode/listnodes.pm create mode 100644 centreon-plugins/cloud/prometheus/direct/kubernetes/mode/listservices.pm create mode 100644 centreon-plugins/cloud/prometheus/direct/kubernetes/mode/namespacestatus.pm create mode 100644 centreon-plugins/cloud/prometheus/direct/kubernetes/mode/nodestatus.pm create mode 100644 centreon-plugins/cloud/prometheus/direct/kubernetes/plugin.pm diff --git a/centreon-plugins/cloud/prometheus/direct/kubernetes/mode/containerstatus.pm b/centreon-plugins/cloud/prometheus/direct/kubernetes/mode/containerstatus.pm new file mode 100644 index 000000000..3344929e4 --- /dev/null +++ b/centreon-plugins/cloud/prometheus/direct/kubernetes/mode/containerstatus.pm @@ -0,0 +1,267 @@ +# +# Copyright 2018 Centreon (http://www.centreon.com/) +# +# Centreon is a full-fledged industry-strength solution that meets +# the needs in IT infrastructure and application monitoring for +# service performance. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +package cloud::prometheus::direct::kubernetes::mode::containerstatus; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +my $instance_mode; + +sub custom_status_threshold { + my ($self, %options) = @_; + my $status = 'ok'; + my $message; + + eval { + local $SIG{__WARN__} = sub { $message = $_[0]; }; + local $SIG{__DIE__} = sub { $message = $_[0]; }; + + if (defined($instance_mode->{option_results}->{critical_status}) && $instance_mode->{option_results}->{critical_status} ne '' && + eval "$instance_mode->{option_results}->{critical_status}") { + $status = 'critical'; + } elsif (defined($instance_mode->{option_results}->{warning_status}) && $instance_mode->{option_results}->{warning_status} ne '' && + eval "$instance_mode->{option_results}->{warning_status}") { + $status = 'warning'; + } + }; + if (defined($message)) { + $self->{output}->output_add(long_msg => 'filter status issue: ' . $message); + } + + return $status; +} + +sub custom_status_output { + my ($self, %options) = @_; + + my $msg = sprintf("state is '%s', status is '%s'", + $self->{result_values}->{state}, + $self->{result_values}->{status}); + $msg .= " [reason: " . $self->{result_values}->{reason} . "]" if (defined($self->{result_values}->{reason}) && $self->{result_values}->{reason} ne ""); + + return $msg; +} + +sub custom_status_calc { + my ($self, %options) = @_; + + $self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_container'}; + $self->{result_values}->{pod} = $options{new_datas}->{$self->{instance} . '_pod'}; + $self->{result_values}->{status} = $options{new_datas}->{$self->{instance} . '_status'}; + $self->{result_values}->{state} = ($options{new_datas}->{$self->{instance} . '_state'} == 1) ? "ready" : "not ready"; + $self->{result_values}->{reason} = $options{new_datas}->{$self->{instance} . '_reason'}; + + return 0; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'containers', type => 1, cb_prefix_output => 'prefix_container_output', + message_multiple => 'All containers status are ok', message_separator => ' - ', + skipped_code => { -11 => 1 } }, + ]; + + $self->{maps_counters}->{containers} = [ + { label => 'status', set => { + key_values => [ { name => 'status' }, { name => 'state' }, { name => 'reason' }, { name => 'pod' }, + { name => 'container' } ], + closure_custom_calc => $self->can('custom_status_calc'), + closure_custom_output => $self->can('custom_status_output'), + closure_custom_perfdata => sub { return 0; }, + closure_custom_threshold_check => $self->can('custom_status_threshold'), + } + }, + { label => 'restarts-count', set => { + key_values => [ { name => 'restarts' }, { name => 'perf' } ], + output_template => 'Restarts count : %d', + perfdatas => [ + { label => 'restarts_count', value => 'restarts_absolute', template => '%d', + min => 0, label_extra_instance => 1, instance_use => 'perf_absolute' }, + ], + } + }, + ]; +} + +sub prefix_container_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 => '.*' }, + "pod:s" => { name => 'pod', default => '.*' }, + "warning-status:s" => { name => 'warning_status', default => '' }, + "critical-status:s" => { name => 'critical_status', default => '%{status} !~ /running/ || %{state} !~ /ready/' }, + "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} = { + 'ready' => '^kube_pod_container_status_ready$', + 'running' => '^kube_pod_container_status_running$', + 'terminated' => '^kube_pod_container_status_terminated$', + 'terminated_reason' => '^kube_pod_container_status_terminated_reason$', + 'waiting' => '^kube_pod_container_status_waiting$', + 'waiting_reason' => '^kube_pod_container_status_waiting_reason$', + 'restarts' => '^kube_pod_container_status_restarts_total$', + }; + foreach my $metric (@{$self->{option_results}->{metric_overload}}) { + next if ($metric !~ /(.*),(.*)/); + $self->{metrics}->{$1} = $2 if (defined($self->{metrics}->{$1})); + } + + $instance_mode = $self; + $self->change_macros(); +} + +sub change_macros { + my ($self, %options) = @_; + + foreach (('warning_status', 'critical_status')) { + if (defined($self->{option_results}->{$_})) { + $self->{option_results}->{$_} =~ s/%\{(.*?)\}/\$self->{result_values}->{$1}/g; + } + } +} + +sub manage_selection { + my ($self, %options) = @_; + + $self->{containers} = {}; + + my $extra_filter = ''; + foreach my $filter (@{$self->{option_results}->{extra_filter}}) { + $extra_filter .= ',' . $filter; + } + + my $results = $options{custom}->query(queries => [ 'label_replace({__name__=~"' . $self->{metrics}->{ready} . '", + container=~"' . $self->{option_results}->{container} . '", + pod=~"' . $self->{option_results}->{pod} . + '"' . $extra_filter . '}, "__name__", "ready", "", "")', + 'label_replace({__name__=~"' . $self->{metrics}->{running} . '", + container=~"' . $self->{option_results}->{container} . '", + pod=~"' . $self->{option_results}->{pod} . + '"' . $extra_filter . '}, "__name__", "running", "", "")', + 'label_replace({__name__=~"' . $self->{metrics}->{terminated} . '", + container=~"' . $self->{option_results}->{container} . '", + pod=~"' . $self->{option_results}->{pod} . + '"' . $extra_filter . '}, "__name__", "terminated", "", "")', + 'label_replace({__name__=~"' . $self->{metrics}->{terminated_reason} . '", + container=~"' . $self->{option_results}->{container} . '", + pod=~"' . $self->{option_results}->{pod} . + '"' . $extra_filter . '}, "__name__", "terminated_reason", "", "")', + 'label_replace({__name__=~"' . $self->{metrics}->{waiting} . '", + container=~"' . $self->{option_results}->{container} . '", + pod=~"' . $self->{option_results}->{pod} . + '"' . $extra_filter . '}, "__name__", "waiting", "", "")', + 'label_replace({__name__=~"' . $self->{metrics}->{waiting_reason} . '", + container=~"' . $self->{option_results}->{container} . '", + pod=~"' . $self->{option_results}->{pod} . + '"' . $extra_filter . '}, "__name__", "waiting_reason", "", "")', + 'label_replace({__name__=~"' . $self->{metrics}->{restarts} . '", + container=~"' . $self->{option_results}->{container} . '", + pod=~"' . $self->{option_results}->{pod} . + '"' . $extra_filter . '}, "__name__", "restarts", "", "")' ]); + + foreach my $metric (@{$results}) { + $self->{containers}->{$metric->{metric}->{pod} . "-" . $metric->{metric}->{container}}->{container} = $metric->{metric}->{container}; + $self->{containers}->{$metric->{metric}->{pod} . "-" . $metric->{metric}->{container}}->{pod} = $metric->{metric}->{pod}; + $self->{containers}->{$metric->{metric}->{pod} . "-" . $metric->{metric}->{container}}->{perf} = $metric->{metric}->{pod} . "_" . $metric->{metric}->{container}; + $self->{containers}->{$metric->{metric}->{pod} . "-" . $metric->{metric}->{container}}->{restarts} = ${$metric->{value}}[1] if ($metric->{metric}->{__name__} =~ /restarts/); + $self->{containers}->{$metric->{metric}->{pod} . "-" . $metric->{metric}->{container}}->{state} = ${$metric->{value}}[1] if ($metric->{metric}->{__name__} =~ /ready/); + $self->{containers}->{$metric->{metric}->{pod} . "-" . $metric->{metric}->{container}}->{status} = $metric->{metric}->{__name__} if ($metric->{metric}->{__name__} =~ /running|terminated|waiting/ && ${$metric->{value}}[1] == 1); + $self->{containers}->{$metric->{metric}->{pod} . "-" . $metric->{metric}->{container}}->{reason} = ""; + $self->{containers}->{$metric->{metric}->{pod} . "-" . $metric->{metric}->{container}}->{reason} = $metric->{metric}->{reason} if ($metric->{metric}->{__name__} =~ /reason/ && ${$metric->{value}}[1] == 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 container status. + +=over 8 + +=item B<--container> + +Filter on a specific container (Must be a regexp, Default: '.*') + +=item B<--warning-status> + +Set warning threshold for status (Default: '') +Can used special variables like: %{status}, %{state}, %{reason} + +=item B<--critical-status> + +Set critical threshold for status (Default: '%{status} !~ /running/ || %{state} !~ /ready/'). +Can used special variables like: %{status}, %{state}, %{reason} + +=item B<--warning-restarts-count> + +Threshold warning for container restarts count. + +=item B<--critical-restarts-count> + +Threshold critical for container restarts count. + +=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 'status') + +Example : --metric-overload='metric,^my_metric_name$' + +=back + +=cut diff --git a/centreon-plugins/cloud/prometheus/direct/kubernetes/mode/daemonsetstatus.pm b/centreon-plugins/cloud/prometheus/direct/kubernetes/mode/daemonsetstatus.pm new file mode 100644 index 000000000..d08815f71 --- /dev/null +++ b/centreon-plugins/cloud/prometheus/direct/kubernetes/mode/daemonsetstatus.pm @@ -0,0 +1,266 @@ +# +# 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::direct::kubernetes::mode::daemonsetstatus; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +my $instance_mode; + +sub custom_status_perfdata { + my ($self, %options) = @_; + + my $extra_label = ''; + if (!defined($options{extra_instance}) || $options{extra_instance} != 0) { + $extra_label .= '_' . $self->{result_values}->{display}; + } + + $self->{output}->perfdata_add(label => 'desired' . $extra_label, + value => $self->{result_values}->{desired}); + $self->{output}->perfdata_add(label => 'current' . $extra_label, + value => $self->{result_values}->{current}); + $self->{output}->perfdata_add(label => 'available' . $extra_label, + value => $self->{result_values}->{available}); + $self->{output}->perfdata_add(label => 'unavailable' . $extra_label, + value => $self->{result_values}->{unavailable}); + $self->{output}->perfdata_add(label => 'up_to_date' . $extra_label, + value => $self->{result_values}->{up_to_date}); + $self->{output}->perfdata_add(label => 'ready' . $extra_label, + value => $self->{result_values}->{ready}); + $self->{output}->perfdata_add(label => 'misscheduled' . $extra_label, + value => $self->{result_values}->{misscheduled}); +} + +sub custom_status_threshold { + my ($self, %options) = @_; + my $status = 'ok'; + my $message; + + eval { + local $SIG{__WARN__} = sub { $message = $_[0]; }; + local $SIG{__DIE__} = sub { $message = $_[0]; }; + + if (defined($instance_mode->{option_results}->{critical_status}) && $instance_mode->{option_results}->{critical_status} ne '' && + eval "$instance_mode->{option_results}->{critical_status}") { + $status = 'critical'; + } elsif (defined($instance_mode->{option_results}->{warning_status}) && $instance_mode->{option_results}->{warning_status} ne '' && + eval "$instance_mode->{option_results}->{warning_status}") { + $status = 'warning'; + } + }; + if (defined($message)) { + $self->{output}->output_add(long_msg => 'filter status issue: ' . $message); + } + + return $status; +} + +sub custom_status_output { + my ($self, %options) = @_; + + return sprintf("nodes desired : %s, current : %s, available : %s, unavailable : %s, up-to-date : %s, ready : %s, misscheduled : %s", + $self->{result_values}->{desired}, + $self->{result_values}->{current}, + $self->{result_values}->{available}, + $self->{result_values}->{unavailable}, + $self->{result_values}->{up_to_date}, + $self->{result_values}->{ready}, + $self->{result_values}->{misscheduled}); +} + +sub custom_status_calc { + my ($self, %options) = @_; + + $self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_display'}; + $self->{result_values}->{desired} = $options{new_datas}->{$self->{instance} . '_desired'}; + $self->{result_values}->{current} = $options{new_datas}->{$self->{instance} . '_current'}; + $self->{result_values}->{available} = $options{new_datas}->{$self->{instance} . '_available'}; + $self->{result_values}->{unavailable} = $options{new_datas}->{$self->{instance} . '_unavailable'}; + $self->{result_values}->{up_to_date} = $options{new_datas}->{$self->{instance} . '_up_to_date'}; + $self->{result_values}->{ready} = $options{new_datas}->{$self->{instance} . '_ready'}; + $self->{result_values}->{misscheduled} = $options{new_datas}->{$self->{instance} . '_misscheduled'}; + + return 0; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'daemonsets', type => 1, cb_prefix_output => 'prefix_daemonset_output', message_multiple => 'All daemonsets status are ok', skipped_code => { -11 => 1 } }, + ]; + + $self->{maps_counters}->{daemonsets} = [ + { label => 'status', set => { + key_values => [ { name => 'desired' }, { name => 'current' }, { name => 'up_to_date' }, + { name => 'available' }, { name => 'unavailable' }, { name => 'ready' }, + { name => 'misscheduled' }, { name => 'display' } ], + closure_custom_calc => $self->can('custom_status_calc'), + closure_custom_output => $self->can('custom_status_output'), + closure_custom_perfdata => $self->can('custom_status_perfdata'), + closure_custom_threshold_check => $self->can('custom_status_threshold'), + } + }, + ]; +} + +sub prefix_daemonset_output { + my ($self, %options) = @_; + + return "Daemonset '" . $options{instance_value}->{display} . "' "; +} + +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 => + { + "daemonset:s" => { name => 'daemonset', default => '.*' }, + "warning-status:s" => { name => 'warning_status', default => '%{up_to_date} < %{desired}' }, + "critical-status:s" => { name => 'critical_status', default => '%{available} < %{desired}' }, + "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} = { + 'desired' => '^kube_daemonset_status_desired_number_scheduled$', + 'current' => '^kube_daemonset_status_current_number_scheduled$', + 'available' => '^kube_daemonset_status_number_available$', + 'unavailable' => '^kube_daemonset_status_number_unavailable$', + 'up_to_date' => '^kube_daemonset_updated_number_scheduled$', + 'ready' => '^kube_daemonset_status_number_ready$', + 'misscheduled' => '^kube_daemonset_status_number_misscheduled$', + }; + foreach my $metric (@{$self->{option_results}->{metric_overload}}) { + next if ($metric !~ /(.*),(.*)/); + $self->{metrics}->{$1} = $2 if (defined($self->{metrics}->{$1})); + } + + $instance_mode = $self; + $self->change_macros(); +} + +sub change_macros { + my ($self, %options) = @_; + + foreach (('warning_status', 'critical_status')) { + if (defined($self->{option_results}->{$_})) { + $self->{option_results}->{$_} =~ s/%\{(.*?)\}/\$self->{result_values}->{$1}/g; + } + } +} + +sub manage_selection { + my ($self, %options) = @_; + + $self->{daemonsets} = {}; + + my $extra_filter = ''; + foreach my $filter (@{$self->{option_results}->{extra_filter}}) { + $extra_filter .= ',' . $filter; + } + + my $results = $options{custom}->query(queries => [ 'label_replace({__name__=~"' . $self->{metrics}->{desired} . '", + daemonset=~"' . $self->{option_results}->{daemonset} . + '"' . $extra_filter . '}, "__name__", "desired", "", "")', + 'label_replace({__name__=~"' . $self->{metrics}->{current} . '", + daemonset=~"' . $self->{option_results}->{daemonset} . + '"' . $extra_filter . '}, "__name__", "current", "", "")', + 'label_replace({__name__=~"' . $self->{metrics}->{available} . '", + daemonset=~"' . $self->{option_results}->{daemonset} . + '"' . $extra_filter . '}, "__name__", "available", "", "")', + 'label_replace({__name__=~"' . $self->{metrics}->{unavailable} . '", + daemonset=~"' . $self->{option_results}->{daemonset} . + '"' . $extra_filter . '}, "__name__", "unavailable", "", "")', + 'label_replace({__name__=~"' . $self->{metrics}->{up_to_date} . '", + daemonset=~"' . $self->{option_results}->{daemonset} . + '"' . $extra_filter . '}, "__name__", "up_to_date", "", "")', + 'label_replace({__name__=~"' . $self->{metrics}->{ready} . '", + daemonset=~"' . $self->{option_results}->{daemonset} . + '"' . $extra_filter . '}, "__name__", "ready", "", "")', + 'label_replace({__name__=~"' . $self->{metrics}->{misscheduled} . '", + daemonset=~"' . $self->{option_results}->{daemonset} . + '"' . $extra_filter . '}, "__name__", "misscheduled", "", "")' ]); + + foreach my $metric (@{$results}) { + $self->{daemonsets}->{$metric->{metric}->{daemonset}}->{display} = $metric->{metric}->{daemonset}; + $self->{daemonsets}->{$metric->{metric}->{daemonset}}->{$metric->{metric}->{__name__}} = ${$metric->{value}}[1]; + } + + if (scalar(keys %{$self->{daemonsets}}) <= 0) { + $self->{output}->add_option_msg(short_msg => "No daemonsets found."); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check daemonset status. + +=over 8 + +=item B<--daemonset> + +Filter on a specific daemonset (Must be a regexp, Default: '.*') + +=item B<--warning-status> + +Set warning threshold for status (Default: '%{up_to_date} < %{desired}') +Can used special variables like: %{display}, %{desired}, %{current}, +%{available}, %{unavailable}, %{up_to_date}, %{ready}, %{misscheduled} + +=item B<--critical-status> + +Set critical threshold for status (Default: '%{available} < %{desired}'). +Can used special variables like: %{display}, %{desired}, %{current}, +%{available}, %{unavailable}, %{up_to_date}, %{ready}, %{misscheduled} + +=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 'status') + +Example : --metric-overload='metric,^my_metric_name$' + +=back + +=cut diff --git a/centreon-plugins/cloud/prometheus/direct/kubernetes/mode/deploymentstatus.pm b/centreon-plugins/cloud/prometheus/direct/kubernetes/mode/deploymentstatus.pm new file mode 100644 index 000000000..0bef44df8 --- /dev/null +++ b/centreon-plugins/cloud/prometheus/direct/kubernetes/mode/deploymentstatus.pm @@ -0,0 +1,249 @@ +# +# 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::direct::kubernetes::mode::deploymentstatus; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +my $instance_mode; + +sub custom_status_perfdata { + my ($self, %options) = @_; + + my $extra_label = ''; + if (!defined($options{extra_instance}) || $options{extra_instance} != 0) { + $extra_label .= '_' . $self->{result_values}->{display}; + } + + $self->{output}->perfdata_add(label => 'desired' . $extra_label, + value => $self->{result_values}->{desired}); + $self->{output}->perfdata_add(label => 'current' . $extra_label, + value => $self->{result_values}->{current}); + $self->{output}->perfdata_add(label => 'available' . $extra_label, + value => $self->{result_values}->{available}); + $self->{output}->perfdata_add(label => 'unavailable' . $extra_label, + value => $self->{result_values}->{unavailable}); + $self->{output}->perfdata_add(label => 'up_to_date' . $extra_label, + value => $self->{result_values}->{up_to_date}); +} + +sub custom_status_threshold { + my ($self, %options) = @_; + my $status = 'ok'; + my $message; + + eval { + local $SIG{__WARN__} = sub { $message = $_[0]; }; + local $SIG{__DIE__} = sub { $message = $_[0]; }; + + if (defined($instance_mode->{option_results}->{critical_status}) && $instance_mode->{option_results}->{critical_status} ne '' && + eval "$instance_mode->{option_results}->{critical_status}") { + $status = 'critical'; + } elsif (defined($instance_mode->{option_results}->{warning_status}) && $instance_mode->{option_results}->{warning_status} ne '' && + eval "$instance_mode->{option_results}->{warning_status}") { + $status = 'warning'; + } + }; + if (defined($message)) { + $self->{output}->output_add(long_msg => 'filter status issue: ' . $message); + } + + return $status; +} + +sub custom_status_output { + my ($self, %options) = @_; + + return sprintf("replicas desired : %s, current : %s, available : %s, unavailable : %s, up-to-date : %s", + $self->{result_values}->{desired}, + $self->{result_values}->{current}, + $self->{result_values}->{available}, + $self->{result_values}->{unavailable}, + $self->{result_values}->{up_to_date}); +} + +sub custom_status_calc { + my ($self, %options) = @_; + + $self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_display'}; + $self->{result_values}->{desired} = $options{new_datas}->{$self->{instance} . '_desired'}; + $self->{result_values}->{current} = $options{new_datas}->{$self->{instance} . '_current'}; + $self->{result_values}->{available} = $options{new_datas}->{$self->{instance} . '_available'}; + $self->{result_values}->{unavailable} = $options{new_datas}->{$self->{instance} . '_unavailable'}; + $self->{result_values}->{up_to_date} = $options{new_datas}->{$self->{instance} . '_up_to_date'}; + + return 0; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'deployments', type => 1, cb_prefix_output => 'prefix_deployment_output', message_multiple => 'All deployments status are ok', skipped_code => { -11 => 1 } }, + ]; + + $self->{maps_counters}->{deployments} = [ + { label => 'status', set => { + key_values => [ { name => 'desired' }, { name => 'current' }, { name => 'up_to_date' }, + { name => 'available' }, { name => 'unavailable' }, { name => 'display' } ], + closure_custom_calc => $self->can('custom_status_calc'), + closure_custom_output => $self->can('custom_status_output'), + closure_custom_perfdata => $self->can('custom_status_perfdata'), + closure_custom_threshold_check => $self->can('custom_status_threshold'), + } + }, + ]; +} + +sub prefix_deployment_output { + my ($self, %options) = @_; + + return "Deployment '" . $options{instance_value}->{display} . "' "; +} + +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 => + { + "deployment:s" => { name => 'deployment', default => '.*' }, + "warning-status:s" => { name => 'warning_status', default => '%{up_to_date} < %{desired}' }, + "critical-status:s" => { name => 'critical_status', default => '%{available} < %{desired}' }, + "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} = { + 'desired' => '^kube_deployment_spec_replicas$', + 'current' => '^kube_deployment_status_replicas$', + 'available' => '^kube_deployment_status_replicas_available$', + 'unavailable' => '^kube_deployment_status_replicas_unavailable$', + 'up_to_date' => '^kube_deployment_status_replicas_updated$', + }; + foreach my $metric (@{$self->{option_results}->{metric_overload}}) { + next if ($metric !~ /(.*),(.*)/); + $self->{metrics}->{$1} = $2 if (defined($self->{metrics}->{$1})); + } + + $instance_mode = $self; + $self->change_macros(); +} + +sub change_macros { + my ($self, %options) = @_; + + foreach (('warning_status', 'critical_status')) { + if (defined($self->{option_results}->{$_})) { + $self->{option_results}->{$_} =~ s/%\{(.*?)\}/\$self->{result_values}->{$1}/g; + } + } +} + +sub manage_selection { + my ($self, %options) = @_; + + $self->{deployments} = {}; + + my $extra_filter = ''; + foreach my $filter (@{$self->{option_results}->{extra_filter}}) { + $extra_filter .= ',' . $filter; + } + + my $results = $options{custom}->query(queries => [ 'label_replace({__name__=~"' . $self->{metrics}->{desired} . '", + deployment=~"' . $self->{option_results}->{deployment} . + '"' . $extra_filter . '}, "__name__", "desired", "", "")', + 'label_replace({__name__=~"' . $self->{metrics}->{current} . '", + deployment=~"' . $self->{option_results}->{deployment} . + '"' . $extra_filter . '}, "__name__", "current", "", "")', + 'label_replace({__name__=~"' . $self->{metrics}->{available} . '", + deployment=~"' . $self->{option_results}->{deployment} . + '"' . $extra_filter . '}, "__name__", "available", "", "")', + 'label_replace({__name__=~"' . $self->{metrics}->{unavailable} . '", + deployment=~"' . $self->{option_results}->{deployment} . + '"' . $extra_filter . '}, "__name__", "unavailable", "", "")', + 'label_replace({__name__=~"' . $self->{metrics}->{up_to_date} . '", + deployment=~"' . $self->{option_results}->{deployment} . + '"' . $extra_filter . '}, "__name__", "up_to_date", "", "")' ]); + + foreach my $metric (@{$results}) { + $self->{deployments}->{$metric->{metric}->{deployment}}->{display} = $metric->{metric}->{deployment}; + $self->{deployments}->{$metric->{metric}->{deployment}}->{$metric->{metric}->{__name__}} = ${$metric->{value}}[1]; + } + + if (scalar(keys %{$self->{deployments}}) <= 0) { + $self->{output}->add_option_msg(short_msg => "No deployments found."); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check deployment status. + +=over 8 + +=item B<--deployment> + +Filter on a specific deployment (Must be a regexp, Default: '.*') + +=item B<--warning-status> + +Set warning threshold for status (Default: '%{up_to_date} < %{desired}') +Can used special variables like: %{display}, %{desired}, %{current}, +%{available}, %{unavailable}, %{up_to_date} + +=item B<--critical-status> + +Set critical threshold for status (Default: '%{available} < %{desired}'). +Can used special variables like: %{display}, %{desired}, %{current}, +%{available}, %{unavailable}, %{up_to_date} + +=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 'status') + +Example : --metric-overload='metric,^my_metric_name$' + +=back + +=cut diff --git a/centreon-plugins/cloud/prometheus/direct/kubernetes/mode/listcontainers.pm b/centreon-plugins/cloud/prometheus/direct/kubernetes/mode/listcontainers.pm new file mode 100644 index 000000000..08ada83f4 --- /dev/null +++ b/centreon-plugins/cloud/prometheus/direct/kubernetes/mode/listcontainers.pm @@ -0,0 +1,134 @@ +# +# 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::direct::kubernetes::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 => + { + "filter-name:s" => { name => 'filter_name' }, + "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} = { + 'info' => '^kube_pod_container_info$', + }; + foreach my $metric (@{$self->{option_results}->{metric_overload}}) { + next if ($metric !~ /(.*),(.*)/); + $self->{metrics}->{$1} = $2 if (defined($self->{metrics}->{$1})); + } +} + +sub manage_selection { + my ($self, %options) = @_; + + my $extra_filter = ''; + foreach my $filter (@{$self->{option_results}->{extra_filter}}) { + $extra_filter .= ',' . $filter; + } + + $self->{containers} = $options{custom}->query(queries => [ '{__name__=~"' . $self->{metrics}->{info} . '"' . $extra_filter . '}' ]); +} + +sub run { + my ($self, %options) = @_; + + $self->manage_selection(%options); + foreach my $container (@{$self->{containers}}) { + next if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' + && $container->{metric}->{container} !~ /$self->{option_results}->{filter_name}/); + $self->{output}->output_add(long_msg => sprintf("[container = %s][container_id = %s][pod = %s][image = %s]", + $container->{metric}->{container}, $container->{metric}->{container_id}, $container->{metric}->{pod}, + $container->{metric}->{image})); + } + + $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', 'container_id', 'pod', 'image']); +} + +sub disco_show { + my ($self, %options) = @_; + + $self->manage_selection(%options); + foreach my $container (@{$self->{containers}}) { + $self->{output}->add_disco_entry( + container => $container->{metric}->{container}, + container_id => $container->{metric}->{container_id}, + pod => $container->{metric}->{pod}, + image => $container->{metric}->{image}, + ); + } +} + +1; + +__END__ + +=head1 MODE + +List containers. + +=over 8 + +=item B<--filter-name> + +Filter container name (Can be a regexp). + +=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 'labels') + +Example : --metric-overload='metric,^my_metric_name$' + +=back + +=cut diff --git a/centreon-plugins/cloud/prometheus/direct/kubernetes/mode/listdaemonsets.pm b/centreon-plugins/cloud/prometheus/direct/kubernetes/mode/listdaemonsets.pm new file mode 100644 index 000000000..37755de7e --- /dev/null +++ b/centreon-plugins/cloud/prometheus/direct/kubernetes/mode/listdaemonsets.pm @@ -0,0 +1,131 @@ +# +# 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::direct::kubernetes::mode::listdaemonsets; + +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 => + { + "filter-name:s" => { name => 'filter_name' }, + "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} = { + 'created' => '^kube_daemonset_created$', + }; + foreach my $metric (@{$self->{option_results}->{metric_overload}}) { + next if ($metric !~ /(.*),(.*)/); + $self->{metrics}->{$1} = $2 if (defined($self->{metrics}->{$1})); + } +} + +sub manage_selection { + my ($self, %options) = @_; + + my $extra_filter = ''; + foreach my $filter (@{$self->{option_results}->{extra_filter}}) { + $extra_filter .= ',' . $filter; + } + + $self->{daemonsets} = $options{custom}->query(queries => [ '{__name__=~"' . $self->{metrics}->{created} . '"' . $extra_filter . '}' ]); +} + +sub run { + my ($self, %options) = @_; + + $self->manage_selection(%options); + foreach my $daemonset (@{$self->{daemonsets}}) { + next if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' + && $daemonset->{metric}->{daemonset} !~ /$self->{option_results}->{filter_name}/); + $self->{output}->output_add(long_msg => sprintf("[daemonset = %s][namespace = %s]", + $daemonset->{metric}->{daemonset}, $daemonset->{metric}->{namespace})); + } + + $self->{output}->output_add(severity => 'OK', + short_msg => 'List daemonsets:'); + $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 => ['daemonset', 'namespace']); +} + +sub disco_show { + my ($self, %options) = @_; + + $self->manage_selection(%options); + foreach my $daemonset (@{$self->{daemonsets}}) { + $self->{output}->add_disco_entry( + daemonset => $daemonset->{metric}->{daemonset}, + namespace => $daemonset->{metric}->{namespace}, + ); + } +} + +1; + +__END__ + +=head1 MODE + +List daemonsets. + +=over 8 + +=item B<--filter-name> + +Filter daemonset name (Can be a regexp). + +=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 'labels') + +Example : --metric-overload='metric,^my_metric_name$' + +=back + +=cut diff --git a/centreon-plugins/cloud/prometheus/direct/kubernetes/mode/listdeployments.pm b/centreon-plugins/cloud/prometheus/direct/kubernetes/mode/listdeployments.pm new file mode 100644 index 000000000..580920e23 --- /dev/null +++ b/centreon-plugins/cloud/prometheus/direct/kubernetes/mode/listdeployments.pm @@ -0,0 +1,129 @@ +# +# 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::direct::kubernetes::mode::listdeployments; + +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 => + { + "filter-name:s" => { name => 'filter_name' }, + "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} = { + 'labels' => '^kube_deployment_labels$', + }; + foreach my $metric (@{$self->{option_results}->{metric_overload}}) { + next if ($metric !~ /(.*),(.*)/); + $self->{metrics}->{$1} = $2 if (defined($self->{metrics}->{$1})); + } +} + +sub manage_selection { + my ($self, %options) = @_; + + my $extra_filter = ''; + foreach my $filter (@{$self->{option_results}->{extra_filter}}) { + $extra_filter .= ',' . $filter; + } + + $self->{deployments} = $options{custom}->query(queries => [ '{__name__=~"' . $self->{metrics}->{labels} . '"' . $extra_filter . '}' ]); +} + +sub run { + my ($self, %options) = @_; + + $self->manage_selection(%options); + foreach my $deployment (@{$self->{deployments}}) { + next if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' + && $deployment->{metric}->{deployment} !~ /$self->{option_results}->{filter_name}/); + $self->{output}->output_add(long_msg => sprintf("[deployment = %s]", $deployment->{metric}->{deployment})); + } + + $self->{output}->output_add(severity => 'OK', + short_msg => 'List deployments:'); + $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 => ['deployment']); +} + +sub disco_show { + my ($self, %options) = @_; + + $self->manage_selection(%options); + foreach my $deployment (@{$self->{deployments}}) { + $self->{output}->add_disco_entry( + deployment => $deployment->{metric}->{deployment}, + ); + } +} + +1; + +__END__ + +=head1 MODE + +List deployments. + +=over 8 + +=item B<--filter-name> + +Filter deployment name (Can be a regexp). + +=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 'labels') + +Example : --metric-overload='metric,^my_metric_name$' + +=back + +=cut diff --git a/centreon-plugins/cloud/prometheus/direct/kubernetes/mode/listnamespaces.pm b/centreon-plugins/cloud/prometheus/direct/kubernetes/mode/listnamespaces.pm new file mode 100644 index 000000000..ad00b254b --- /dev/null +++ b/centreon-plugins/cloud/prometheus/direct/kubernetes/mode/listnamespaces.pm @@ -0,0 +1,129 @@ +# +# 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::direct::kubernetes::mode::listnamespaces; + +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 => + { + "filter-name:s" => { name => 'filter_name' }, + "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} = { + 'labels' => '^kube_namespace_labels$', + }; + foreach my $metric (@{$self->{option_results}->{metric_overload}}) { + next if ($metric !~ /(.*),(.*)/); + $self->{metrics}->{$1} = $2 if (defined($self->{metrics}->{$1})); + } +} + +sub manage_selection { + my ($self, %options) = @_; + + my $extra_filter = ''; + foreach my $filter (@{$self->{option_results}->{extra_filter}}) { + $extra_filter .= ',' . $filter; + } + + $self->{namespaces} = $options{custom}->query(queries => [ '{__name__=~"' . $self->{metrics}->{labels} . '"' . $extra_filter . '}' ]); +} + +sub run { + my ($self, %options) = @_; + + $self->manage_selection(%options); + foreach my $namespace (@{$self->{namespaces}}) { + next if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' + && $namespace->{metric}->{namespace} !~ /$self->{option_results}->{filter_name}/); + $self->{output}->output_add(long_msg => sprintf("[namespace = %s]", $namespace->{metric}->{namespace})); + } + + $self->{output}->output_add(severity => 'OK', + short_msg => 'List namespaces:'); + $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 => ['namespace']); +} + +sub disco_show { + my ($self, %options) = @_; + + $self->manage_selection(%options); + foreach my $namespace (@{$self->{namespaces}}) { + $self->{output}->add_disco_entry( + namespace => $namespace->{metric}->{namespace}, + ); + } +} + +1; + +__END__ + +=head1 MODE + +List namespaces. + +=over 8 + +=item B<--filter-name> + +Filter namespace name (Can be a regexp). + +=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 'status') + +Example : --metric-overload='metric,^my_metric_name$' + +=back + +=cut diff --git a/centreon-plugins/cloud/prometheus/direct/kubernetes/mode/listnodes.pm b/centreon-plugins/cloud/prometheus/direct/kubernetes/mode/listnodes.pm new file mode 100644 index 000000000..da7e2b746 --- /dev/null +++ b/centreon-plugins/cloud/prometheus/direct/kubernetes/mode/listnodes.pm @@ -0,0 +1,138 @@ +# +# 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::direct::kubernetes::mode::listnodes; + +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 => + { + "filter-name:s" => { name => 'filter_name' }, + "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} = { + 'info' => '^kube_node_info$', + }; + foreach my $metric (@{$self->{option_results}->{metric_overload}}) { + next if ($metric !~ /(.*),(.*)/); + $self->{metrics}->{$1} = $2 if (defined($self->{metrics}->{$1})); + } +} + +sub manage_selection { + my ($self, %options) = @_; + + my $extra_filter = ''; + foreach my $filter (@{$self->{option_results}->{extra_filter}}) { + $extra_filter .= ',' . $filter; + } + + $self->{nodes} = $options{custom}->query(queries => [ '{__name__=~"' . $self->{metrics}->{info} . '"' . $extra_filter . '}' ]); +} + +sub run { + my ($self, %options) = @_; + + $self->manage_selection(%options); + foreach my $node (@{$self->{nodes}}) { + next if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' + && $node->{metric}->{node} !~ /$self->{option_results}->{filter_name}/); + $self->{output}->output_add(long_msg => sprintf("[node = %s][os_image = %s][kubelet_version = %s][kubeproxy_version = %s]" . + "[kernel_version = %s][container_runtime_version = %s]", + $node->{metric}->{node}, $node->{metric}->{os_image}, $node->{metric}->{kubelet_version}, + $node->{metric}->{kubeproxy_version}, $node->{metric}->{kernel_version}, $node->{metric}->{container_runtime_version})); + } + + $self->{output}->output_add(severity => 'OK', + short_msg => 'List nodes:'); + $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 => ['node', 'os_image', 'kubelet_version', 'kubeproxy_version', + 'kernel_version', 'container_runtime_version']); +} + +sub disco_show { + my ($self, %options) = @_; + + $self->manage_selection(%options); + foreach my $node (@{$self->{nodes}}) { + $self->{output}->add_disco_entry( + node => $node->{metric}->{node}, + os_image => $node->{metric}->{os_image}, + kubelet_version => $node->{metric}->{kubelet_version}, + kubeproxy_version => $node->{metric}->{kubeproxy_version}, + kernel_version => $node->{metric}->{kernel_version}, + container_runtime_version => $node->{metric}->{container_runtime_version}, + ); + } +} + +1; + +__END__ + +=head1 MODE + +List nodes. + +=over 8 + +=item B<--filter-name> + +Filter node name (Can be a regexp). + +=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 'labels') + +Example : --metric-overload='metric,^my_metric_name$' + +=back + +=cut diff --git a/centreon-plugins/cloud/prometheus/direct/kubernetes/mode/listservices.pm b/centreon-plugins/cloud/prometheus/direct/kubernetes/mode/listservices.pm new file mode 100644 index 000000000..2e71b2503 --- /dev/null +++ b/centreon-plugins/cloud/prometheus/direct/kubernetes/mode/listservices.pm @@ -0,0 +1,131 @@ +# +# 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::direct::kubernetes::mode::listservices; + +use base qw(centreon::plugins::mode); + +use strict; +use warnings; + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $self->{version} = '1.0'; + $options{options}->add_options(arguments => + { + "filter-name:s" => { name => 'filter_name' }, + "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} = { + 'info' => '^kube_service_info$', + }; + foreach my $metric (@{$self->{option_results}->{metric_overload}}) { + next if ($metric !~ /(.*),(.*)/); + $self->{metrics}->{$1} = $2 if (defined($self->{metrics}->{$1})); + } +} + +sub manage_selection { + my ($self, %options) = @_; + + my $extra_filter = ''; + foreach my $filter (@{$self->{option_results}->{extra_filter}}) { + $extra_filter .= ',' . $filter; + } + + $self->{services} = $options{custom}->query(queries => [ '{__name__=~"' . $self->{metrics}->{info} . '"' . $extra_filter . '}' ]); +} + +sub run { + my ($self, %options) = @_; + + $self->manage_selection(%options); + foreach my $service (@{$self->{services}}) { + next if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' + && $service->{metric}->{service} !~ /$self->{option_results}->{filter_name}/); + $self->{output}->output_add(long_msg => sprintf("[service = %s][cluster_ip = %s]", + $service->{metric}->{service}, $service->{metric}->{cluster_ip})); + } + + $self->{output}->output_add(severity => 'OK', + short_msg => 'List services:'); + $self->{output}->display(nolabel => 1, force_ignore_perfdata => 1, force_long_output => 1); + $self->{output}->exit(); +} + +sub disco_format { + my ($self, %options) = @_; + + $self->{output}->add_disco_format(elements => ['service', 'cluster_ip']); +} + +sub disco_show { + my ($self, %options) = @_; + + $self->manage_selection(%options); + foreach my $service (@{$self->{services}}) { + $self->{output}->add_disco_entry( + service => $service->{metric}->{service}, + cluster_ip => $service->{metric}->{cluster_ip}, + ); + } +} + +1; + +__END__ + +=head1 MODE + +List services. + +=over 8 + +=item B<--filter-name> + +Filter service name (Can be a regexp). + +=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 'labels') + +Example : --metric-overload='metric,^my_metric_name$' + +=back + +=cut diff --git a/centreon-plugins/cloud/prometheus/direct/kubernetes/mode/namespacestatus.pm b/centreon-plugins/cloud/prometheus/direct/kubernetes/mode/namespacestatus.pm new file mode 100644 index 000000000..6da617d5f --- /dev/null +++ b/centreon-plugins/cloud/prometheus/direct/kubernetes/mode/namespacestatus.pm @@ -0,0 +1,235 @@ +# +# Copyright 2018 Centreon (http://www.centreon.com/) +# +# Centreon is a full-fledged industry-strength solution that meets +# the needs in IT infrastructure and application monitoring for +# service performance. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +package cloud::prometheus::direct::kubernetes::mode::namespacestatus; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +my $instance_mode; + +sub custom_status_threshold { + my ($self, %options) = @_; + my $status = 'ok'; + my $message; + + eval { + local $SIG{__WARN__} = sub { $message = $_[0]; }; + local $SIG{__DIE__} = sub { $message = $_[0]; }; + + if (defined($instance_mode->{option_results}->{critical_status}) && $instance_mode->{option_results}->{critical_status} ne '' && + eval "$instance_mode->{option_results}->{critical_status}") { + $status = 'critical'; + } elsif (defined($instance_mode->{option_results}->{warning_status}) && $instance_mode->{option_results}->{warning_status} ne '' && + eval "$instance_mode->{option_results}->{warning_status}") { + $status = 'warning'; + } + }; + if (defined($message)) { + $self->{output}->output_add(long_msg => 'filter status issue: ' . $message); + } + + return $status; +} + +sub custom_status_output { + my ($self, %options) = @_; + + return sprintf("status phase is '%s'", $self->{result_values}->{phase}); +} + +sub custom_status_calc { + my ($self, %options) = @_; + + $self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_display'}; + $self->{result_values}->{phase} = $options{new_datas}->{$self->{instance} . '_phase'}; + + return 0; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'global', type => 0, cb_init => 'skip_global', cb_prefix_output => 'prefix_global_output' }, + { name => 'namespaces', type => 1, cb_prefix_output => 'prefix_namespace_output', message_multiple => 'All namespaces status are ok', skipped_code => { -11 => 1 } }, + ]; + + $self->{maps_counters}->{global} = [ + { label => 'active', set => { + key_values => [ { name => 'active' } ], + output_template => 'Active : %d', + perfdatas => [ + { label => 'active', value => 'active_absolute', template => '%d', + min => 0 }, + ], + } + }, + { label => 'terminating', set => { + key_values => [ { name => 'terminating' } ], + output_template => 'Terminating : %d', + perfdatas => [ + { label => 'terminating', value => 'terminating_absolute', template => '%d', + min => 0 }, + ], + } + }, + ]; + $self->{maps_counters}->{namespaces} = [ + { label => 'status', set => { + key_values => [ { name => 'phase' }, { name => 'display' } ], + closure_custom_calc => $self->can('custom_status_calc'), + closure_custom_output => $self->can('custom_status_output'), + closure_custom_perfdata => sub { return 0; }, + closure_custom_threshold_check => $self->can('custom_status_threshold'), + } + }, + ]; +} + +sub skip_global { + my ($self, %options) = @_; + + scalar(keys %{$self->{namespaces}}) > 1 ? return(0) : return(1); +} + +sub prefix_global_output { + my ($self, %options) = @_; + + return "Namespaces "; +} + +sub prefix_namespace_output { + my ($self, %options) = @_; + + return "Namespace '" . $options{instance_value}->{display} . "' "; +} + +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 => + { + "namespace:s" => { name => 'namespace', default => '.*' }, + "warning-status:s" => { name => 'warning_status' }, + "critical-status:s" => { name => 'critical_status', default => '%{phase} !~ /Active/' }, + "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} = { + 'status' => '^kube_namespace_status_phase$', + }; + foreach my $metric (@{$self->{option_results}->{metric_overload}}) { + next if ($metric !~ /(.*),(.*)/); + $self->{metrics}->{$1} = $2 if (defined($self->{metrics}->{$1})); + } + + $instance_mode = $self; + $self->change_macros(); +} + +sub change_macros { + my ($self, %options) = @_; + + foreach (('warning_status', 'critical_status')) { + if (defined($self->{option_results}->{$_})) { + $self->{option_results}->{$_} =~ s/%\{(.*?)\}/\$self->{result_values}->{$1}/g; + } + } +} + +sub manage_selection { + my ($self, %options) = @_; + + $self->{global} = { active => 0, terminating => 0 }; + $self->{namespaces} = {}; + + my $extra_filter = ''; + foreach my $filter (@{$self->{option_results}->{extra_filter}}) { + $extra_filter .= ',' . $filter; + } + + my $results = $options{custom}->query(queries => [ '{__name__=~"' . $self->{metrics}->{status} . '",namespace=~"' . $self->{option_results}->{namespace} . + '"' . $extra_filter . '}' ]); + + foreach my $metric (@{$results}) { + $self->{namespaces}->{$metric->{metric}->{namespace}}->{display} = $metric->{metric}->{namespace}; + $self->{namespaces}->{$metric->{metric}->{namespace}}->{phase} = $metric->{metric}->{phase} if (${$metric->{value}}[1] == 1); + $self->{global}->{lc($metric->{metric}->{phase})}++ if (${$metric->{value}}[1] == 1); + } + + if (scalar(keys %{$self->{namespaces}}) <= 0) { + $self->{output}->add_option_msg(short_msg => "No namespaces found."); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check namespace status phase. + +=over 8 + +=item B<--namespace> + +Filter on a specific namespace (Must be a regexp, Default: '.*') + +=item B<--warning-status> + +Set warning threshold for status (Default: '') +Can used special variables like: %{display}, %{phase}. + +=item B<--critical-status> + +Set critical threshold for status (Default: '%{phase} !~ /Active/'). +Can used special variables like: %{display}, %{phase} + +=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 'status') + +Example : --metric-overload='metric,^my_metric_name$' + +=back + +=cut diff --git a/centreon-plugins/cloud/prometheus/direct/kubernetes/mode/nodestatus.pm b/centreon-plugins/cloud/prometheus/direct/kubernetes/mode/nodestatus.pm new file mode 100644 index 000000000..0fab23031 --- /dev/null +++ b/centreon-plugins/cloud/prometheus/direct/kubernetes/mode/nodestatus.pm @@ -0,0 +1,293 @@ +# +# 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::direct::kubernetes::mode::nodestatus; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +my $instance_mode; + +sub custom_status_threshold { + my ($self, %options) = @_; + my $status = 'ok'; + my $message; + + eval { + local $SIG{__WARN__} = sub { $message = $_[0]; }; + local $SIG{__DIE__} = sub { $message = $_[0]; }; + + if (defined($instance_mode->{option_results}->{critical_status}) && $instance_mode->{option_results}->{critical_status} ne '' && + eval "$instance_mode->{option_results}->{critical_status}") { + $status = 'critical'; + } elsif (defined($instance_mode->{option_results}->{warning_status}) && $instance_mode->{option_results}->{warning_status} ne '' && + eval "$instance_mode->{option_results}->{warning_status}") { + $status = 'warning'; + } + }; + if (defined($message)) { + $self->{output}->output_add(long_msg => 'filter status issue: ' . $message); + } + + return $status; +} + +sub custom_status_output { + my ($self, %options) = @_; + + return sprintf("status is '%s', new pods schedulable : %s", + $self->{result_values}->{status}, + $self->{result_values}->{schedulable}); +} + +sub custom_status_calc { + my ($self, %options) = @_; + + $self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_display'}; + $self->{result_values}->{status} = $options{new_datas}->{$self->{instance} . '_status'}; + $self->{result_values}->{schedulable} = ($options{new_datas}->{$self->{instance} . '_unschedulable'} == 1) ? "false" : "true"; + + return 0; +} + +sub custom_usage_perfdata { + my ($self, %options) = @_; + + my $label = 'allocated_pods'; + my $value_perf = $self->{result_values}->{allocated}; + my $extra_label = ''; + $extra_label = '_' . $self->{result_values}->{display} if (!defined($options{extra_instance}) || $options{extra_instance} != 0); + my %total_options = (); + if ($instance_mode->{option_results}->{units} eq '%') { + $total_options{total} = $self->{result_values}->{capacity}; + $total_options{cast_int} = 1; + } + + $self->{output}->perfdata_add(label => $label . $extra_label, + 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}->{capacity}); +} + +sub custom_usage_threshold { + my ($self, %options) = @_; + + my ($exit, $threshold_value); + $threshold_value = $self->{result_values}->{allocated}; + if ($instance_mode->{option_results}->{units} eq '%') { + $threshold_value = $self->{result_values}->{prct_allocated}; + } + $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 = sprintf("Allocation Capacity : %s, Allocated : %s (%.2f%%)", + $self->{result_values}->{capacity}, $self->{result_values}->{allocated}, $self->{result_values}->{prct_allocated}); + return $msg; +} + +sub custom_usage_calc { + my ($self, %options) = @_; + + $self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_display'}; + $self->{result_values}->{capacity} = $options{new_datas}->{$self->{instance} . '_capacity'}; + $self->{result_values}->{allocatable} = $options{new_datas}->{$self->{instance} . '_allocatable'}; + $self->{result_values}->{allocated} = $self->{result_values}->{capacity} - $self->{result_values}->{allocatable}; + $self->{result_values}->{prct_allocated} = ($self->{result_values}->{capacity} > 0) ? $self->{result_values}->{allocated} * 100 / $self->{result_values}->{capacity} : 0; + + return 0; +} + + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'nodes', type => 1, cb_prefix_output => 'prefix_node_output', message_multiple => 'All nodes status are ok', + message_separator => ' - ', skipped_code => { -11 => 1 } }, + ]; + + $self->{maps_counters}->{nodes} = [ + { label => 'status', set => { + key_values => [ { name => 'status' }, { name => 'unschedulable' }, { name => 'display' } ], + closure_custom_calc => $self->can('custom_status_calc'), + closure_custom_output => $self->can('custom_status_output'), + closure_custom_perfdata => sub { return 0; }, + closure_custom_threshold_check => $self->can('custom_status_threshold'), + } + }, + { label => 'allocated-pods', set => { + key_values => [ { name => 'capacity' }, { name => 'allocatable' }, { name => 'display' } ], + 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_node_output { + my ($self, %options) = @_; + + return "Node '" . $options{instance_value}->{display} . "' "; +} + +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 => + { + "node:s" => { name => 'node', default => '.*' }, + "warning-status:s" => { name => 'warning_status' }, + "critical-status:s" => { name => 'critical_status', default => '%{status} !~ /Ready/ || %{schedulable} =~ /false/' }, + "extra-filter:s@" => { name => 'extra_filter' }, + "metric-overload:s@" => { name => 'metric_overload' }, + "units:s" => { name => 'units', default => '' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + $self->{metrics} = { + 'status' => '^kube_node_status_condition$', + 'unschedulable' => '^kube_node_spec_unschedulable$', + 'capacity' => '^kube_node_status_capacity_pods$', + 'allocatable' => '^kube_node_status_allocatable_pods$', + }; + foreach my $metric (@{$self->{option_results}->{metric_overload}}) { + next if ($metric !~ /(.*),(.*)/); + $self->{metrics}->{$1} = $2 if (defined($self->{metrics}->{$1})); + } + + $instance_mode = $self; + $self->change_macros(); +} + +sub change_macros { + my ($self, %options) = @_; + + foreach (('warning_status', 'critical_status')) { + if (defined($self->{option_results}->{$_})) { + $self->{option_results}->{$_} =~ s/%\{(.*?)\}/\$self->{result_values}->{$1}/g; + } + } +} + +sub manage_selection { + my ($self, %options) = @_; + + $self->{nodes} = {}; + + my $extra_filter = ''; + foreach my $filter (@{$self->{option_results}->{extra_filter}}) { + $extra_filter .= ',' . $filter; + } + + my $results = $options{custom}->query(queries => [ 'label_replace({__name__=~"' . $self->{metrics}->{status} . '", + node=~"' . $self->{option_results}->{node} . '",status="true"' . + $extra_filter . '}, "__name__", "status", "", "")', + 'label_replace({__name__=~"' . $self->{metrics}->{unschedulable} . '", + node=~"' . $self->{option_results}->{node} . + '"' . $extra_filter . '}, "__name__", "unschedulable", "", "")', + 'label_replace({__name__=~"' . $self->{metrics}->{capacity} . '", + node=~"' . $self->{option_results}->{node} . + '"' . $extra_filter . '}, "__name__", "capacity", "", "")', + 'label_replace({__name__=~"' . $self->{metrics}->{allocatable} . '", + node=~"' . $self->{option_results}->{node} . + '"' . $extra_filter . '}, "__name__", "allocatable", "", "")' ]); + + foreach my $metric (@{$results}) { + $self->{nodes}->{$metric->{metric}->{node}}->{display} = $metric->{metric}->{node}; + $self->{nodes}->{$metric->{metric}->{node}}->{$metric->{metric}->{__name__}} = ${$metric->{value}}[1]; + $self->{nodes}->{$metric->{metric}->{node}}->{$metric->{metric}->{__name__}} = $metric->{metric}->{condition} if ($metric->{metric}->{__name__} =~ /status/); + } + + if (scalar(keys %{$self->{nodes}}) <= 0) { + $self->{output}->add_option_msg(short_msg => "No nodes found."); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check node status. + +=over 8 + +=item B<--node> + +Filter on a specific node (Must be a regexp, Default: '.*') + +=item B<--warning-status> + +Set warning threshold for status (Default: '') +Can used special variables like: %{display}, %{status}, %{schedulable} + +=item B<--critical-status> + +Set critical threshold for status (Default: '%{status} !~ /Ready/ || %{schedulable} != /false/'). +Can used special variables like: %{display}, %{status}, %{schedulable} + +=item B<--warning-allocated-pods> + +Threshold warning for pods allocation. + +=item B<--critical-allocated-pods> + +Threshold critical for pods allocation. + +=item B<--units> + +Units of thresholds (Default: '') (Can be '%'). + +=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 'status') + +Example : --metric-overload='metric,^my_metric_name$' + +=back + +=cut diff --git a/centreon-plugins/cloud/prometheus/direct/kubernetes/plugin.pm b/centreon-plugins/cloud/prometheus/direct/kubernetes/plugin.pm new file mode 100644 index 000000000..1918d998b --- /dev/null +++ b/centreon-plugins/cloud/prometheus/direct/kubernetes/plugin.pm @@ -0,0 +1,67 @@ +# +# 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::direct::kubernetes::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}} = ( + 'container-status' => 'cloud::prometheus::direct::kubernetes::mode::containerstatus', + 'daemonset-status' => 'cloud::prometheus::direct::kubernetes::mode::daemonsetstatus', + 'deployment-status' => 'cloud::prometheus::direct::kubernetes::mode::deploymentstatus', + 'list-containers' => 'cloud::prometheus::direct::kubernetes::mode::listcontainers', + 'list-daemonsets' => 'cloud::prometheus::direct::kubernetes::mode::listdaemonsets', + 'list-deployments' => 'cloud::prometheus::direct::kubernetes::mode::listdeployments', + 'list-namespaces' => 'cloud::prometheus::direct::kubernetes::mode::listnamespaces', + 'list-nodes' => 'cloud::prometheus::direct::kubernetes::mode::listnodes', + 'list-services' => 'cloud::prometheus::direct::kubernetes::mode::listservices', + 'namespace-status' => 'cloud::prometheus::direct::kubernetes::mode::namespacestatus', + 'node-status' => 'cloud::prometheus::direct::kubernetes::mode::nodestatus', + ); + + $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 Kubernetes metrics through Prometheus server +using the Kubernetes kube-state-metrics add-on agent. + +=cut