diff --git a/cloud/kubernetes/custom/api.pm b/cloud/kubernetes/custom/api.pm index 7837c5761..1c3d54566 100644 --- a/cloud/kubernetes/custom/api.pm +++ b/cloud/kubernetes/custom/api.pm @@ -74,9 +74,9 @@ sub check_options { $self->{hostname} = (defined($self->{option_results}->{hostname})) ? $self->{option_results}->{hostname} : undef; $self->{port} = (defined($self->{option_results}->{port})) ? $self->{option_results}->{port} : 443; $self->{proto} = (defined($self->{option_results}->{proto})) ? $self->{option_results}->{proto} : 'https'; - $self->{timeout} = (defined($self->{option_results}->{timeout})) ? $self->{option_results}->{timeout} : 10; + $self->{timeout} = (defined($self->{option_results}->{timeout})) && $self->{option_results}->{timeout} =~ /(\d+)/ ? $1 : 10; $self->{token} = (defined($self->{option_results}->{token})) ? $self->{option_results}->{token} : ''; - $self->{limit} = (defined($self->{option_results}->{limit})) ? $self->{option_results}->{limit} : '100'; + $self->{limit} = (defined($self->{option_results}->{limit})) && $self->{option_results}->{limit} =~ /(\d+)/ ? $1 : 100; if (!defined($self->{hostname}) || $self->{hostname} eq '') { $self->{output}->add_option_msg(short_msg => "Need to specify --hostname option."); @@ -181,6 +181,14 @@ sub request_api_paginate { return \@items; } +sub kubernetes_list_cronjobs { + my ($self, %options) = @_; + + my $response = $self->request_api_paginate(method => 'GET', url_path => '/apis/batch/v1beta1/cronjobs'); + + return $response; +} + sub kubernetes_list_daemonsets { my ($self, %options) = @_; @@ -197,6 +205,14 @@ sub kubernetes_list_deployments { return $response; } +sub kubernetes_list_events { + my ($self, %options) = @_; + + my $response = $self->request_api_paginate(method => 'GET', url_path => '/api/v1/events'); + + return $response; +} + sub kubernetes_list_ingresses { my ($self, %options) = @_; @@ -221,6 +237,14 @@ sub kubernetes_list_nodes { return $response; } +sub kubernetes_list_rcs { + my ($self, %options) = @_; + + my $response = $self->request_api_paginate(method => 'GET', url_path => '/api/v1/replicationcontrollers'); + + return $response; +} + sub kubernetes_list_replicasets { my ($self, %options) = @_; @@ -253,6 +277,14 @@ sub kubernetes_list_pods { return $response; } +sub kubernetes_list_pvs { + my ($self, %options) = @_; + + my $response = $self->request_api_paginate(method => 'GET', url_path => '/api/v1/persistentvolumes'); + + return $response; +} + 1; __END__ diff --git a/cloud/kubernetes/custom/kubectl.pm b/cloud/kubernetes/custom/kubectl.pm index 02938976f..1b793a2b0 100644 --- a/cloud/kubernetes/custom/kubectl.pm +++ b/cloud/kubernetes/custom/kubectl.pm @@ -45,7 +45,8 @@ sub new { 'proto:s' => { name => 'proto' }, 'token:s' => { name => 'token' }, 'timeout:s' => { name => 'timeout', default => 10 }, - 'config-file:s' => { name => 'config_file' }, + 'config-file:s' => { name => 'config_file', default => '~/.kube/config' }, + 'context:s' => { name => 'context' }, 'sudo' => { name => 'sudo' }, 'command:s' => { name => 'command', default => 'kubectl' }, 'command-path:s' => { name => 'command_path' }, @@ -72,12 +73,23 @@ sub check_options { my ($self, %options) = @_; $self->{config_file} = (defined($self->{option_results}->{config_file})) ? $self->{option_results}->{config_file} : ''; - $self->{timeout} = (defined($self->{option_results}->{timeout})) ? $self->{option_results}->{timeout} : 10; + $self->{context} = (defined($self->{option_results}->{context})) ? $self->{option_results}->{context} : ''; + $self->{timeout} = (defined($self->{option_results}->{timeout})) && $self->{option_results}->{timeout} =~ /(\d+)/ ? $1 : 10; if (!defined($self->{config_file}) || $self->{config_file} eq '') { $self->{output}->add_option_msg(short_msg => "Need to specify --config-file option."); $self->{output}->option_exit(); } + + if ($self->{config_file} =~ /^~/) { + centreon::plugins::misc::mymodule_load( + output => $self->{output}, + module => 'File::HomeDir', + error_msg => "Cannot load module 'File::HomeDir'." + ); + my $home = File::HomeDir->my_home; + $self->{config_file} =~ s/\~/$home/; + } if (defined($self->{option_results}->{proxyurl}) && $self->{option_results}->{proxyurl} ne '') { $ENV{HTTP_PROXY} = $self->{option_results}->{proxyurl}; @@ -126,14 +138,26 @@ sub execute { return $decoded->{items}; } +sub kubernetes_list_cronjobs { + my ($self, %options) = @_; + + my $cmd = "get cronjobs --all-namespaces --output='json' --kubeconfig='" . $self->{config_file} . "'" + . " --request-timeout='" . $self->{timeout} . "'"; + $cmd .= " --context='" . $self->{context} . "'" if (defined($self->{context}) && $self->{context} ne ''); + + my $response = $self->execute(cmd_options => $cmd); + + return $response; +} + sub kubernetes_list_daemonsets { my ($self, %options) = @_; - my $response = $self->execute( - cmd_options => "get daemonsets --all-namespaces --output='json'" - . " --kubeconfig='" . $self->{config_file} . "'" - . " --request-timeout='" . $self->{timeout} . "'" - ); + my $cmd = "get daemonsets --all-namespaces --output='json' --kubeconfig='" . $self->{config_file} . "'" + . " --request-timeout='" . $self->{timeout} . "'"; + $cmd .= " --context='" . $self->{context} . "'" if (defined($self->{context}) && $self->{context} ne ''); + + my $response = $self->execute(cmd_options => $cmd); return $response; } @@ -141,23 +165,23 @@ sub kubernetes_list_daemonsets { sub kubernetes_list_deployments { my ($self, %options) = @_; - my $response = $self->execute( - cmd_options => "get deployments --all-namespaces --output='json'" - . " --kubeconfig='" . $self->{config_file} . "'" - . " --request-timeout='" . $self->{timeout} . "'" - ); + my $cmd = "get deployments --all-namespaces --output='json' --kubeconfig='" . $self->{config_file} . "'" + . " --request-timeout='" . $self->{timeout} . "'"; + $cmd .= " --context='" . $self->{context} . "'" if (defined($self->{context}) && $self->{context} ne ''); + + my $response = $self->execute(cmd_options => $cmd); return $response; } -sub kubernetes_list_ingresses { +sub kubernetes_list_events { my ($self, %options) = @_; - my $response = $self->execute( - cmd_options => "get ingresses --all-namespaces --output='json'" - . " --kubeconfig='" . $self->{config_file} . "'" - . " --request-timeout='" . $self->{timeout} . "'" - ); + my $cmd = "get events --all-namespaces --output='json' --kubeconfig='" . $self->{config_file} . "'" + . " --request-timeout='" . $self->{timeout} . "'"; + $cmd .= " --context='" . $self->{context} . "'" if (defined($self->{context}) && $self->{context} ne ''); + + my $response = $self->execute(cmd_options => $cmd); return $response; } @@ -165,11 +189,11 @@ sub kubernetes_list_ingresses { sub kubernetes_list_namespaces { my ($self, %options) = @_; - my $response = $self->execute( - cmd_options => "get namespaces --all-namespaces --output='json'" - . " --kubeconfig='" . $self->{config_file} . "'" - . " --request-timeout='" . $self->{timeout} . "'" - ); + my $cmd = "get namespaces --all-namespaces --output='json' --kubeconfig='" . $self->{config_file} . "'" + . " --request-timeout='" . $self->{timeout} . "'"; + $cmd .= " --context='" . $self->{context} . "'" if (defined($self->{context}) && $self->{context} ne ''); + + my $response = $self->execute(cmd_options => $cmd); return $response; } @@ -177,23 +201,35 @@ sub kubernetes_list_namespaces { sub kubernetes_list_nodes { my ($self, %options) = @_; - my $response = $self->execute( - cmd_options => "get nodes --all-namespaces --output='json'" - . " --kubeconfig='" . $self->{config_file} . "'" - . " --request-timeout='" . $self->{timeout} . "'" - ); + my $cmd = "get nodes --all-namespaces --output='json' --kubeconfig='" . $self->{config_file} . "'" + . " --request-timeout='" . $self->{timeout} . "'"; + $cmd .= " --context='" . $self->{context} . "'" if (defined($self->{context}) && $self->{context} ne ''); + my $response = $self->execute(cmd_options => $cmd); + + return $response; +} + +sub kubernetes_list_rcs { + my ($self, %options) = @_; + + my $cmd = "get replicationcontroller --all-namespaces --output='json' --kubeconfig='" . $self->{config_file} . "'" + . " --request-timeout='" . $self->{timeout} . "'"; + $cmd .= " --context='" . $self->{context} . "'" if (defined($self->{context}) && $self->{context} ne ''); + + my $response = $self->execute(cmd_options => $cmd); + return $response; } sub kubernetes_list_replicasets { my ($self, %options) = @_; - my $response = $self->execute( - cmd_options => "get replicasets --all-namespaces --output='json'" - . " --kubeconfig='" . $self->{config_file} . "'" - . " --request-timeout='" . $self->{timeout} . "'" - ); + my $cmd = "get replicasets --all-namespaces --output='json' --kubeconfig='" . $self->{config_file} . "'" + . " --request-timeout='" . $self->{timeout} . "'"; + $cmd .= " --context='" . $self->{context} . "'" if (defined($self->{context}) && $self->{context} ne ''); + + my $response = $self->execute(cmd_options => $cmd); return $response; } @@ -201,11 +237,11 @@ sub kubernetes_list_replicasets { sub kubernetes_list_services { my ($self, %options) = @_; - my $response = $self->execute( - cmd_options => "get services --all-namespaces --output='json'" - . " --kubeconfig='" . $self->{config_file} . "'" - . " --request-timeout='" . $self->{timeout} . "'" - ); + my $cmd = "get services --all-namespaces --output='json' --kubeconfig='" . $self->{config_file} . "'" + . " --request-timeout='" . $self->{timeout} . "'"; + $cmd .= " --context='" . $self->{context} . "'" if (defined($self->{context}) && $self->{context} ne ''); + + my $response = $self->execute(cmd_options => $cmd); return $response; } @@ -213,11 +249,11 @@ sub kubernetes_list_services { sub kubernetes_list_statefulsets { my ($self, %options) = @_; - my $response = $self->execute( - cmd_options => "get statefulsets --all-namespaces --output='json'" - . " --kubeconfig='" . $self->{config_file} . "'" - . " --request-timeout='" . $self->{timeout} . "'" - ); + my $cmd = "get statefulsets --all-namespaces --output='json' --kubeconfig='" . $self->{config_file} . "'" + . " --request-timeout='" . $self->{timeout} . "'"; + $cmd .= " --context='" . $self->{context} . "'" if (defined($self->{context}) && $self->{context} ne ''); + + my $response = $self->execute(cmd_options => $cmd); return $response; } @@ -225,11 +261,23 @@ sub kubernetes_list_statefulsets { sub kubernetes_list_pods { my ($self, %options) = @_; - my $response = $self->execute( - cmd_options => "get pods --all-namespaces --output='json'" - . " --kubeconfig='" . $self->{config_file} . "'" - . " --request-timeout='" . $self->{timeout} . "'" - ); + my $cmd = "get pods --all-namespaces --output='json' --kubeconfig='" . $self->{config_file} . "'" + . " --request-timeout='" . $self->{timeout} . "'"; + $cmd .= " --context='" . $self->{context} . "'" if (defined($self->{context}) && $self->{context} ne ''); + + my $response = $self->execute(cmd_options => $cmd); + + return $response; +} + +sub kubernetes_list_pvs { + my ($self, %options) = @_; + + my $cmd = "get pv --all-namespaces --output='json' --kubeconfig='" . $self->{config_file} . "'" + . " --request-timeout='" . $self->{timeout} . "'"; + $cmd .= " --context='" . $self->{context} . "'" if (defined($self->{context}) && $self->{context} ne ''); + + my $response = $self->execute(cmd_options => $cmd); return $response; } @@ -254,9 +302,13 @@ Kubernetes CLI (kubectl) =item B<--config-file> -Kubernetes configuration file path +Kubernetes configuration file path (Default: '~/.kube/config'). (Example: --config-file='/root/.kube/config'). +=item B<--context> + +Context to use in configuration file. + =item B<--timeout> Set timeout in seconds (Default: 10). diff --git a/cloud/kubernetes/mode/clusterevents.pm b/cloud/kubernetes/mode/clusterevents.pm new file mode 100644 index 000000000..fb8b5c8be --- /dev/null +++ b/cloud/kubernetes/mode/clusterevents.pm @@ -0,0 +1,228 @@ +# +# Copyright 2021 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::kubernetes::mode::clusterevents; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; +use DateTime; +use centreon::plugins::misc; +use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold_ng); + +sub custom_event_calc { + my ($self, %options) = @_; + + $self->{result_values}->{type} = $options{new_datas}->{$self->{instance} . '_type'}; + $self->{result_values}->{object} = $options{new_datas}->{$self->{instance} . '_object'}; + $self->{result_values}->{message} = $options{new_datas}->{$self->{instance} . '_message'}; + $self->{result_values}->{count} = $options{new_datas}->{$self->{instance} . '_count'}; + $self->{result_values}->{first_seen_time} = $options{new_datas}->{$self->{instance} . '_first_seen'}; + $self->{result_values}->{last_seen_time} = $options{new_datas}->{$self->{instance} . '_last_seen'}; + # 2021-03-09T11:01:00Z, UTC timezone + if ($self->{result_values}->{first_seen_time} =~ /^\s*(\d+)-(\d+)-(\d+)T(\d+):(\d+):(\d+)Z/) { + my $dt = DateTime->new( + year => $1, + month => $2, + day => $3, + hour => $4, + minute => $5, + second => $6 + ); + $self->{result_values}->{first_seen} = time() - $dt->epoch; + } + if ($self->{result_values}->{last_seen_time} =~ /^\s*(\d+)-(\d+)-(\d+)T(\d+):(\d+):(\d+)Z/) { + my $dt = DateTime->new( + year => $1, + month => $2, + day => $3, + hour => $4, + minute => $5, + second => $6 + ); + $self->{result_values}->{last_seen} = time() - $dt->epoch; + } + + return 0; +} + +sub custom_event_output { + my ($self, %options) = @_; + + my $msg = sprintf("Event '%s' for object '%s' with message '%s'", + $self->{result_values}->{type}, + $self->{result_values}->{object}, + $self->{result_values}->{message} + ); + $msg .= sprintf(", Count: %s, First seen: %s ago (%s), Last seen: %s ago (%s)", + $self->{result_values}->{count}, + centreon::plugins::misc::change_seconds(value => $self->{result_values}->{first_seen}), + $self->{result_values}->{first_seen_time}, + centreon::plugins::misc::change_seconds(value => $self->{result_values}->{last_seen}), + $self->{result_values}->{last_seen_time} + ) if (defined($self->{result_values}->{count}) && $self->{result_values}->{count} ne ''); + + return $msg; +} + +sub prefix_global_output { + my ($self, %options) = @_; + + return "Number of events "; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'global', type => 0, cb_prefix_output => 'prefix_global_output', skipped_code => { -10 => 1 } }, + { name => 'events', type => 1 }, + ]; + + $self->{maps_counters}->{global} = [ + { label => 'warning', nlabel => 'events.type.warning.count', set => { + key_values => [ { name => 'warning' } ], + output_template => 'Warning : %d', + perfdatas => [ + { label => 'warning_events', template => '%d', min => 0 } + ] + } + }, + { label => 'normal', nlabel => 'events.type.normal.count', set => { + key_values => [ { name => 'normal' } ], + output_template => 'Normal : %d', + perfdatas => [ + { label => 'normal_events', template => '%d', min => 0 } + ] + } + }, + ]; + + $self->{maps_counters}->{events} = [ + { + label => 'status', + type => 2, + warning_default => '%{type} =~ /warning/i', + critical_default => '%{type} =~ /error/i', + set => { + key_values => [ + { name => 'object' }, { name => 'count' }, { name => 'first_seen' }, { name => 'last_seen' }, + { name => 'message' }, { name => 'reason' }, { name => 'type' } + ], + closure_custom_calc => $self->can('custom_event_calc'), + closure_custom_output => $self->can('custom_event_output'), + closure_custom_perfdata => sub { return 0; }, + closure_custom_threshold_check => \&catalog_status_threshold_ng + } + } + ]; +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1); + bless $self, $class; + + $options{options}->add_options(arguments => { + "filter-type:s" => { name => 'filter_type' }, + "filter-namespace:s" => { name => 'filter_namespace' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + $self->change_macros(macros => ['warning_status', 'critical_status']); +} + +sub manage_selection { + my ($self, %options) = @_; + + $self->{events} = {}; + + my $results = $options{custom}->kubernetes_list_events(); + + $self->{global} = { normal => 0, warning => 0 }; + + foreach my $event (@{$results}) { + if (defined($self->{option_results}->{filter_type}) && $self->{option_results}->{filter_type} ne '' && + $event->{type} !~ /$self->{option_results}->{filter_type}/) { + $self->{output}->output_add(long_msg => "skipping '" . $event->{type} . "': no matching filter type.", debug => 1); + next; + } + if (defined($self->{option_results}->{filter_namespace}) && $self->{option_results}->{filter_namespace} ne '' && + $event->{metadata}->{namespace} !~ /$self->{option_results}->{filter_namespace}/) { + $self->{output}->output_add(long_msg => "skipping '" . $event->{metadata}->{namespace} . "': no matching filter namespace.", debug => 1); + next; + } + + $self->{global}->{lc($event->{type})}++; + + $self->{events}->{$event->{metadata}->{uid}} = { + name => $event->{metadata}->{name}, + namespace => $event->{metadata}->{namespace}, + object => $event->{involvedObject}->{kind} . "/" . $event->{involvedObject}->{name}, + count => (defined($event->{count})) ? $event->{count} : "", + first_seen => (defined($event->{firstTimestamp})) ? $event->{firstTimestamp} : "", + last_seen => (defined($event->{lastTimestamp})) ? $event->{lastTimestamp} : "", + message => $event->{message}, + reason => $event->{reason}, + type => $event->{type} + } + } +} + +1; + +__END__ + +=head1 MODE + +Check cluster events. + +=over 8 + +=item B<--filter-type> + +Filter event type (can be a regexp). + +=item B<--filter-namespace> + +Filter namespace (can be a regexp). + +=item B<--warning-status> + +Set warning threshold for status (Default: '%{type} =~ /warning/i') +Can use special variables like: %{name}, %{namespace}, %{type}, +%{object}, %{message}, %{count}, %{first_seen}, %{last_seen}. + +=item B<--critical-status> + +Set critical threshold for status (Default: '%{type} =~ /error/i'). +Can use special variables like: %{name}, %{namespace}, %{type}, +%{object}, %{message}, %{count}, %{first_seen}, %{last_seen}. + +=back + +=cut diff --git a/cloud/kubernetes/mode/cronjobstatus.pm b/cloud/kubernetes/mode/cronjobstatus.pm new file mode 100644 index 000000000..1bb30661b --- /dev/null +++ b/cloud/kubernetes/mode/cronjobstatus.pm @@ -0,0 +1,188 @@ +# +# Copyright 2021 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::kubernetes::mode::cronjobstatus; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; +use DateTime; +use centreon::plugins::misc; +use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold); + +sub custom_status_perfdata { + my ($self, %options) = @_; + + $self->{output}->perfdata_add( + label => 'active', + nlabel => 'cronjob.jobs.active.count', + value => $self->{result_values}->{active}, + instances => $self->use_instances(extra_instance => $options{extra_instance}) ? $self->{result_values}->{name} : undef, + ); +} + +sub custom_status_output { + my ($self, %options) = @_; + + return sprintf("Jobs Active: %s, Last schedule time: %s ago (%s)", + $self->{result_values}->{active}, + centreon::plugins::misc::change_seconds(value => $self->{result_values}->{last_schedule}), + $self->{result_values}->{last_schedule_time}); +} + +sub custom_status_calc { + my ($self, %options) = @_; + + $self->{result_values}->{name} = $options{new_datas}->{$self->{instance} . '_name'}; + $self->{result_values}->{namespace} = $options{new_datas}->{$self->{instance} . '_namespace'}; + $self->{result_values}->{active} = $options{new_datas}->{$self->{instance} . '_active'}; + $self->{result_values}->{last_schedule_time} = $options{new_datas}->{$self->{instance} . '_last_schedule_time'}; + # 2021-03-09T11:01:00Z, UTC timezone + if ($self->{result_values}->{last_schedule_time} =~ /^\s*(\d+)-(\d+)-(\d+)T(\d+):(\d+):(\d+)Z/) { + my $dt = DateTime->new( + year => $1, + month => $2, + day => $3, + hour => $4, + minute => $5, + second => $6 + ); + $self->{result_values}->{last_schedule} = time() - $dt->epoch; + } + + return 0; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'cronjobs', type => 1, cb_prefix_output => 'prefix_cronjob_output', + message_multiple => 'All CronJobs status are ok', skipped_code => { -11 => 1 } }, + ]; + + $self->{maps_counters}->{cronjobs} = [ + { label => 'status', set => { + key_values => [ { name => 'active' }, { name => 'last_schedule_time' }, { name => 'name' }, + { name => 'namespace' } ], + 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 => \&catalog_status_threshold, + } + }, + ]; +} + +sub prefix_cronjob_output { + my ($self, %options) = @_; + + return "CronJob '" . $options{instance_value}->{name} . "' "; +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1); + bless $self, $class; + + $options{options}->add_options(arguments => { + "filter-name:s" => { name => 'filter_name' }, + "filter-namespace:s" => { name => 'filter_namespace' }, + "warning-status:s" => { name => 'warning_status', default => '' }, + "critical-status:s" => { name => 'critical_status', default => '' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + $self->change_macros(macros => ['warning_status', 'critical_status']); +} + +sub manage_selection { + my ($self, %options) = @_; + + $self->{cronjobs} = {}; + + my $results = $options{custom}->kubernetes_list_cronjobs(); + + foreach my $cronjob (@{$results}) { + if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' && + $cronjob->{metadata}->{name} !~ /$self->{option_results}->{filter_name}/) { + $self->{output}->output_add(long_msg => "skipping '" . $cronjob->{metadata}->{name} . "': no matching filter name.", debug => 1); + next; + } + if (defined($self->{option_results}->{filter_namespace}) && $self->{option_results}->{filter_namespace} ne '' && + $cronjob->{metadata}->{namespace} !~ /$self->{option_results}->{filter_namespace}/) { + $self->{output}->output_add(long_msg => "skipping '" . $cronjob->{metadata}->{namespace} . "': no matching filter namespace.", debug => 1); + next; + } + + $self->{cronjobs}->{$cronjob->{metadata}->{uid}} = { + name => $cronjob->{metadata}->{name}, + namespace => $cronjob->{metadata}->{namespace}, + active => (defined($cronjob->{status}->{active})) ? scalar(@{$cronjob->{status}->{active}}) : 0, + last_schedule_time => $cronjob->{status}->{lastScheduleTime} + } + } + + if (scalar(keys %{$self->{cronjobs}}) <= 0) { + $self->{output}->add_option_msg(short_msg => "No CronJobs found."); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check CronJob status. + +=over 8 + +=item B<--filter-name> + +Filter CronJob name (can be a regexp). + +=item B<--filter-namespace> + +Filter CronJob namespace (can be a regexp). + +=item B<--warning-status> + +Set warning threshold for status (Default: '') +Can used special variables like: %{name}, %{namespace}, %{active}, +%{last_schedule}. + +=item B<--critical-status> + +Set critical threshold for status (Default: ''). +Can used special variables like: %{name}, %{namespace}, %{active}, +%{last_schedule}. + +=back + +=cut diff --git a/cloud/kubernetes/mode/daemonsetstatus.pm b/cloud/kubernetes/mode/daemonsetstatus.pm index 5a8fdb36e..8591602d3 100644 --- a/cloud/kubernetes/mode/daemonsetstatus.pm +++ b/cloud/kubernetes/mode/daemonsetstatus.pm @@ -33,37 +33,37 @@ sub custom_status_perfdata { label => 'desired', nlabel => 'daemonset.pods.desired.count', value => $self->{result_values}->{desired}, - instances => $self->use_instances(extra_instance => $options{extra_instance}) ? $self->{result_values}->{display} : undef, + instances => $self->use_instances(extra_instance => $options{extra_instance}) ? $self->{result_values}->{name} : undef, ); $self->{output}->perfdata_add( label => 'current', nlabel => 'daemonset.pods.current.count', value => $self->{result_values}->{current}, - instances => $self->use_instances(extra_instance => $options{extra_instance}) ? $self->{result_values}->{display} : undef, + instances => $self->use_instances(extra_instance => $options{extra_instance}) ? $self->{result_values}->{name} : undef, ); $self->{output}->perfdata_add( label => 'available', nlabel => 'daemonset.pods.available.count', value => $self->{result_values}->{available}, - instances => $self->use_instances(extra_instance => $options{extra_instance}) ? $self->{result_values}->{display} : undef, + instances => $self->use_instances(extra_instance => $options{extra_instance}) ? $self->{result_values}->{name} : undef, ); $self->{output}->perfdata_add( label => 'up_to_date', nlabel => 'daemonset.pods.uptodate.count', value => $self->{result_values}->{up_to_date}, - instances => $self->use_instances(extra_instance => $options{extra_instance}) ? $self->{result_values}->{display} : undef, + instances => $self->use_instances(extra_instance => $options{extra_instance}) ? $self->{result_values}->{name} : undef, ); $self->{output}->perfdata_add( label => 'ready', nlabel => 'daemonset.pods.ready.count', value => $self->{result_values}->{ready}, - instances => $self->use_instances(extra_instance => $options{extra_instance}) ? $self->{result_values}->{display} : undef, + instances => $self->use_instances(extra_instance => $options{extra_instance}) ? $self->{result_values}->{name} : undef, ); $self->{output}->perfdata_add( label => 'misscheduled', nlabel => 'daemonset.pods.misscheduled.count', value => $self->{result_values}->{misscheduled}, - instances => $self->use_instances(extra_instance => $options{extra_instance}) ? $self->{result_values}->{display} : undef, + instances => $self->use_instances(extra_instance => $options{extra_instance}) ? $self->{result_values}->{name} : undef, ); } @@ -82,7 +82,8 @@ sub custom_status_output { sub custom_status_calc { my ($self, %options) = @_; - $self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_display'}; + $self->{result_values}->{name} = $options{new_datas}->{$self->{instance} . '_name'}; + $self->{result_values}->{namespace} = $options{new_datas}->{$self->{instance} . '_namespace'}; $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'}; @@ -98,13 +99,14 @@ sub set_counters { $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 } }, + 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 => 'ready' }, { name => 'misscheduled' }, { name => 'display' } ], + { name => 'available' }, { name => 'ready' }, { name => 'misscheduled' }, { name => 'name' }, + { name => 'namespace' } ], closure_custom_calc => $self->can('custom_status_calc'), closure_custom_output => $self->can('custom_status_output'), closure_custom_perfdata => $self->can('custom_status_perfdata'), @@ -117,12 +119,12 @@ sub set_counters { sub prefix_daemonset_output { my ($self, %options) = @_; - return "Daemonset '" . $options{instance_value}->{display} . "' "; + return "DaemonSet '" . $options{instance_value}->{name} . "' "; } sub new { my ($class, %options) = @_; - my $self = $class->SUPER::new(package => __PACKAGE__, %options); + my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1); bless $self, $class; $options{options}->add_options(arguments => { @@ -162,19 +164,19 @@ sub manage_selection { } $self->{daemonsets}->{$daemonset->{metadata}->{uid}} = { - display => $daemonset->{metadata}->{name}, + name => $daemonset->{metadata}->{name}, namespace => $daemonset->{metadata}->{namespace}, - desired => $daemonset->{status}->{desiredNumberScheduled}, - current => $daemonset->{status}->{currentNumberScheduled}, - up_to_date => $daemonset->{status}->{updatedNumberScheduled}, - available => $daemonset->{status}->{numberAvailable}, - ready => $daemonset->{status}->{numberReady}, - misscheduled => $daemonset->{status}->{numberMisscheduled}, + desired => (defined($daemonset->{status}->{desiredNumberScheduled})) && $daemonset->{status}->{desiredNumberScheduled} =~ /(\d+)/ ? $1 : 0, + current => (defined($daemonset->{status}->{currentNumberScheduled})) && $daemonset->{status}->{currentNumberScheduled} =~ /(\d+)/ ? $1 : 0, + up_to_date => (defined($daemonset->{status}->{updatedNumberScheduled})) && $daemonset->{status}->{updatedNumberScheduled} =~ /(\d+)/ ? $1 : 0, + available => (defined($daemonset->{status}->{numberAvailable})) && $daemonset->{status}->{numberAvailable} =~ /(\d+)/ ? $1 : 0, + ready => (defined($daemonset->{status}->{numberReady})) && $daemonset->{status}->{numberReady} =~ /(\d+)/ ? $1 : 0, + misscheduled => (defined($daemonset->{status}->{numberMisscheduled})) && $daemonset->{status}->{numberMisscheduled} =~ /(\d+)/ ? $1 : 0 } } if (scalar(keys %{$self->{daemonsets}}) <= 0) { - $self->{output}->add_option_msg(short_msg => "No daemonsets found."); + $self->{output}->add_option_msg(short_msg => "No DaemonSets found."); $self->{output}->option_exit(); } } @@ -185,29 +187,29 @@ __END__ =head1 MODE -Check daemonset status. +Check DaemonSet status. =over 8 =item B<--filter-name> -Filter daemonset name (can be a regexp). +Filter DaemonSet name (can be a regexp). =item B<--filter-namespace> -Filter daemonset namespace (can be a regexp). +Filter DaemonSet namespace (can be a regexp). =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} +Can used special variables like: %{name}, %{namespace}, %{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} +Can used special variables like: %{name}, %{namespace}, %{desired}, %{current}, +%{available}, %{unavailable}, %{up_to_date}, %{ready}, %{misscheduled}. =back diff --git a/cloud/kubernetes/mode/deploymentstatus.pm b/cloud/kubernetes/mode/deploymentstatus.pm index ddcef9cdc..3d61a407e 100644 --- a/cloud/kubernetes/mode/deploymentstatus.pm +++ b/cloud/kubernetes/mode/deploymentstatus.pm @@ -33,31 +33,31 @@ sub custom_status_perfdata { label => 'desired', nlabel => 'deployment.replicas.desired.count', value => $self->{result_values}->{desired}, - instances => $self->use_instances(extra_instance => $options{extra_instance}) ? $self->{result_values}->{display} : undef, + instances => $self->use_instances(extra_instance => $options{extra_instance}) ? $self->{result_values}->{name} : undef, ); $self->{output}->perfdata_add( label => 'current', nlabel => 'deployment.replicas.current.count', value => $self->{result_values}->{current}, - instances => $self->use_instances(extra_instance => $options{extra_instance}) ? $self->{result_values}->{display} : undef, + instances => $self->use_instances(extra_instance => $options{extra_instance}) ? $self->{result_values}->{name} : undef, ); $self->{output}->perfdata_add( label => 'available', nlabel => 'deployment.replicas.available.count', value => $self->{result_values}->{available}, - instances => $self->use_instances(extra_instance => $options{extra_instance}) ? $self->{result_values}->{display} : undef, + instances => $self->use_instances(extra_instance => $options{extra_instance}) ? $self->{result_values}->{name} : undef, ); $self->{output}->perfdata_add( label => 'ready', nlabel => 'deployment.replicas.ready.count', value => $self->{result_values}->{ready}, - instances => $self->use_instances(extra_instance => $options{extra_instance}) ? $self->{result_values}->{display} : undef, + instances => $self->use_instances(extra_instance => $options{extra_instance}) ? $self->{result_values}->{name} : undef, ); $self->{output}->perfdata_add( label => 'up_to_date', nlabel => 'deployment.replicas.uptodate.count', value => $self->{result_values}->{up_to_date}, - instances => $self->use_instances(extra_instance => $options{extra_instance}) ? $self->{result_values}->{display} : undef, + instances => $self->use_instances(extra_instance => $options{extra_instance}) ? $self->{result_values}->{name} : undef, ); } @@ -75,7 +75,8 @@ sub custom_status_output { sub custom_status_calc { my ($self, %options) = @_; - $self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_display'}; + $self->{result_values}->{name} = $options{new_datas}->{$self->{instance} . '_name'}; + $self->{result_values}->{namespace} = $options{new_datas}->{$self->{instance} . '_namespace'}; $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'}; @@ -90,13 +91,13 @@ sub set_counters { $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 } }, + 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 => 'ready' }, { name => 'display' } ], + { name => 'available' }, { name => 'ready' }, { name => 'name' }, { name => 'namespace' } ], closure_custom_calc => $self->can('custom_status_calc'), closure_custom_output => $self->can('custom_status_output'), closure_custom_perfdata => $self->can('custom_status_perfdata'), @@ -109,12 +110,12 @@ sub set_counters { sub prefix_deployment_output { my ($self, %options) = @_; - return "Deployment '" . $options{instance_value}->{display} . "' "; + return "Deployment '" . $options{instance_value}->{name} . "' "; } sub new { my ($class, %options) = @_; - my $self = $class->SUPER::new(package => __PACKAGE__, %options); + my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1); bless $self, $class; $options{options}->add_options(arguments => { @@ -154,13 +155,13 @@ sub manage_selection { } $self->{deployments}->{$deployment->{metadata}->{uid}} = { - display => $deployment->{metadata}->{name}, + name => $deployment->{metadata}->{name}, namespace => $deployment->{metadata}->{namespace}, desired => $deployment->{spec}->{replicas}, - current => $deployment->{status}->{replicas}, - ready => $deployment->{status}->{readyReplicas}, - up_to_date => $deployment->{status}->{updatedReplicas}, - available => $deployment->{status}->{availableReplicas}, + current => (defined($deployment->{status}->{replicas})) && $deployment->{status}->{replicas} =~ /(\d+)/ ? $1 : 0, + ready => (defined($deployment->{status}->{readyReplicas})) && $deployment->{status}->{readyReplicas} =~ /(\d+)/ ? $1 : 0, + up_to_date => (defined($deployment->{status}->{updatedReplicas})) && $deployment->{status}->{updatedReplicas} =~ /(\d+)/ ? $1 : 0, + available => (defined($deployment->{status}->{availableReplicas})) && $deployment->{status}->{availableReplicas} =~ /(\d+)/ ? $1 : 0 } } @@ -191,14 +192,14 @@ Filter deployment namespace (can be a regexp). =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} +Can used special variables like: %{name}, %{namespace}, %{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} +Can used special variables like: %{name}, %{namespace}, %{desired}, %{current}, +%{available}, %{unavailable}, %{up_to_date}. =back diff --git a/cloud/kubernetes/mode/nodesdiscovery.pm b/cloud/kubernetes/mode/discoverynodes.pm similarity index 98% rename from cloud/kubernetes/mode/nodesdiscovery.pm rename to cloud/kubernetes/mode/discoverynodes.pm index d561e4e1d..060305d4f 100644 --- a/cloud/kubernetes/mode/nodesdiscovery.pm +++ b/cloud/kubernetes/mode/discoverynodes.pm @@ -18,7 +18,7 @@ # limitations under the License. # -package cloud::kubernetes::mode::nodesdiscovery; +package cloud::kubernetes::mode::discoverynodes; use base qw(centreon::plugins::mode); diff --git a/cloud/kubernetes/mode/listcronjobs.pm b/cloud/kubernetes/mode/listcronjobs.pm new file mode 100644 index 000000000..74ea593c0 --- /dev/null +++ b/cloud/kubernetes/mode/listcronjobs.pm @@ -0,0 +1,128 @@ +# +# Copyright 2021 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::kubernetes::mode::listcronjobs; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $options{options}->add_options(arguments => { + "filter-name:s" => { name => 'filter_name' }, + "filter-namespace:s" => { name => 'filter_namespace' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); +} + +sub manage_selection { + my ($self, %options) = @_; + + my $results = $options{custom}->kubernetes_list_cronjobs(); + + foreach my $cronjob (@{$results}) { + if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' && + $cronjob->{metadata}->{name} !~ /$self->{option_results}->{filter_name}/) { + $self->{output}->output_add(long_msg => "skipping '" . $cronjob->{metadata}->{name} . "': no matching filter name.", debug => 1); + next; + } + if (defined($self->{option_results}->{filter_namespace}) && $self->{option_results}->{filter_namespace} ne '' && + $cronjob->{metadata}->{namespace} !~ /$self->{option_results}->{filter_namespace}/) { + $self->{output}->output_add(long_msg => "skipping '" . $cronjob->{metadata}->{namespace} . "': no matching filter namespace.", debug => 1); + next; + } + + $self->{cronjobs}->{$cronjob->{metadata}->{uid}} = { + uid => $cronjob->{metadata}->{uid}, + name => $cronjob->{metadata}->{name}, + namespace => $cronjob->{metadata}->{namespace}, + } + } +} + +sub run { + my ($self, %options) = @_; + + $self->manage_selection(%options); + foreach my $cronjob (sort keys %{$self->{cronjobs}}) { + $self->{output}->output_add(long_msg => sprintf("[uid = %s] [name = %s] [namespace = %s]", + $self->{cronjobs}->{$cronjob}->{uid}, + $self->{cronjobs}->{$cronjob}->{name}, + $self->{cronjobs}->{$cronjob}->{namespace}) + ); + } + + $self->{output}->output_add(severity => 'OK', + short_msg => 'List cronjobs:'); + $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 => ['uid', 'name', 'namespace']); +} + +sub disco_show { + my ($self, %options) = @_; + + $self->manage_selection(%options); + foreach my $cronjob (sort keys %{$self->{cronjobs}}) { + $self->{output}->add_disco_entry( + uid => $self->{cronjobs}->{$cronjob}->{uid}, + name => $self->{cronjobs}->{$cronjob}->{name}, + namespace => $self->{cronjobs}->{$cronjob}->{namespace}, + ); + } +} + +1; + +__END__ + +=head1 MODE + +List cronjobs. + +=over 8 + +=item B<--filter-name> + +Filter cronjob name (can be a regexp). + +=item B<--filter-namespace> + +Filter cronjob namespace (can be a regexp). + +=back + +=cut diff --git a/cloud/kubernetes/mode/listpersistentvolumes.pm b/cloud/kubernetes/mode/listpersistentvolumes.pm new file mode 100644 index 000000000..90dfce5f7 --- /dev/null +++ b/cloud/kubernetes/mode/listpersistentvolumes.pm @@ -0,0 +1,115 @@ +# +# Copyright 2021 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::kubernetes::mode::listpersistentvolumes; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $options{options}->add_options(arguments => { + "filter-name:s" => { name => 'filter_name' } + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); +} + +sub manage_selection { + my ($self, %options) = @_; + + my $results = $options{custom}->kubernetes_list_pvs(); + + foreach my $pv (@{$results}) { + if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' && + $pv->{metadata}->{name} !~ /$self->{option_results}->{filter_name}/) { + $self->{output}->output_add(long_msg => "skipping '" . $pv->{metadata}->{name} . "': no matching filter name.", debug => 1); + next; + } + + $self->{pvs}->{$pv->{metadata}->{uid}} = { + uid => $pv->{metadata}->{uid}, + name => $pv->{metadata}->{name} + } + } +} + +sub run { + my ($self, %options) = @_; + + $self->manage_selection(%options); + foreach my $pv (sort keys %{$self->{pvs}}) { + $self->{output}->output_add(long_msg => sprintf("[uid = %s] [name = %s]", + $self->{pvs}->{$pv}->{uid}, + $self->{pvs}->{$pv}->{name}) + ); + } + + $self->{output}->output_add(severity => 'OK', + short_msg => 'List persistent volumes:'); + $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 => ['uid', 'name']); +} + +sub disco_show { + my ($self, %options) = @_; + + $self->manage_selection(%options); + foreach my $pv (sort keys %{$self->{pvs}}) { + $self->{output}->add_disco_entry( + uid => $self->{pvs}->{$pv}->{uid}, + name => $self->{pvs}->{$pv}->{name} + ); + } +} + +1; + +__END__ + +=head1 MODE + +List persistent volumes. + +=over 8 + +=item B<--filter-name> + +Filter persistent volumes name (can be a regexp). + +=back + +=cut diff --git a/cloud/kubernetes/mode/listreplicationcontrollers.pm b/cloud/kubernetes/mode/listreplicationcontrollers.pm new file mode 100644 index 000000000..65f547801 --- /dev/null +++ b/cloud/kubernetes/mode/listreplicationcontrollers.pm @@ -0,0 +1,128 @@ +# +# Copyright 2021 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::kubernetes::mode::listreplicationcontrollers; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $options{options}->add_options(arguments => { + "filter-name:s" => { name => 'filter_name' }, + "filter-namespace:s" => { name => 'filter_namespace' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); +} + +sub manage_selection { + my ($self, %options) = @_; + + my $results = $options{custom}->kubernetes_list_rcs(); + + foreach my $rc (@{$results}) { + if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' && + $rc->{metadata}->{name} !~ /$self->{option_results}->{filter_name}/) { + $self->{output}->output_add(long_msg => "skipping '" . $rc->{metadata}->{name} . "': no matching filter name.", debug => 1); + next; + } + if (defined($self->{option_results}->{filter_namespace}) && $self->{option_results}->{filter_namespace} ne '' && + $rc->{metadata}->{namespace} !~ /$self->{option_results}->{filter_namespace}/) { + $self->{output}->output_add(long_msg => "skipping '" . $rc->{metadata}->{namespace} . "': no matching filter namespace.", debug => 1); + next; + } + + $self->{rcs}->{$rc->{metadata}->{uid}} = { + uid => $rc->{metadata}->{uid}, + name => $rc->{metadata}->{name}, + namespace => $rc->{metadata}->{namespace}, + } + } +} + +sub run { + my ($self, %options) = @_; + + $self->manage_selection(%options); + foreach my $rc (sort keys %{$self->{rcs}}) { + $self->{output}->output_add(long_msg => sprintf("[uid = %s] [name = %s] [namespace = %s]", + $self->{rcs}->{$rc}->{uid}, + $self->{rcs}->{$rc}->{name}, + $self->{rcs}->{$rc}->{namespace}) + ); + } + + $self->{output}->output_add(severity => 'OK', + short_msg => 'List replication controllers:'); + $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 => ['uid', 'name', 'namespace']); +} + +sub disco_show { + my ($self, %options) = @_; + + $self->manage_selection(%options); + foreach my $rc (sort keys %{$self->{rcs}}) { + $self->{output}->add_disco_entry( + uid => $self->{rcs}->{$rc}->{uid}, + name => $self->{rcs}->{$rc}->{name}, + namespace => $self->{rcs}->{$rc}->{namespace}, + ); + } +} + +1; + +__END__ + +=head1 MODE + +List replication controllers. + +=over 8 + +=item B<--filter-name> + +Filter replication controller name (can be a regexp). + +=item B<--filter-namespace> + +Filter replication controller namespace (can be a regexp). + +=back + +=cut diff --git a/cloud/kubernetes/mode/nodestatus.pm b/cloud/kubernetes/mode/nodestatus.pm new file mode 100644 index 000000000..73689a9d5 --- /dev/null +++ b/cloud/kubernetes/mode/nodestatus.pm @@ -0,0 +1,176 @@ +# +# Copyright 2021 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::kubernetes::mode::nodestatus; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; +use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold); + +sub custom_condition_status_output { + my ($self, %options) = @_; + + return sprintf("Status is '%s', Reason: '%s', Message: '%s'", + $self->{result_values}->{status}, + $self->{result_values}->{reason}, + $self->{result_values}->{message}); +} + +sub custom_condition_status_calc { + my ($self, %options) = @_; + + $self->{result_values}->{type} = $options{new_datas}->{$self->{instance} . '_type'}; + $self->{result_values}->{status} = $options{new_datas}->{$self->{instance} . '_status'}; + $self->{result_values}->{reason} = $options{new_datas}->{$self->{instance} . '_reason'}; + $self->{result_values}->{message} = $options{new_datas}->{$self->{instance} . '_message'}; + + return 0; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'nodes', type => 3, cb_prefix_output => 'prefix_output', cb_long_output => 'long_output', + message_multiple => 'All nodes status are ok', indent_long_output => ' ', + group => [ + { name => 'conditions', display_long => 1, cb_prefix_output => 'prefix_condition_output', + message_multiple => 'Conditions are ok', type => 1, skipped_code => { -10 => 1 } }, + ] + } + ]; + + $self->{maps_counters}->{conditions} = [ + { label => 'status', set => { + key_values => [ + { name => 'type' }, { name => 'status' }, { name => 'reason' }, { name => 'message' } + ], + closure_custom_calc => $self->can('custom_condition_status_calc'), + closure_custom_output => $self->can('custom_condition_status_output'), + closure_custom_perfdata => sub { return 0; }, + closure_custom_threshold_check => \&catalog_status_threshold, + } + }, + ]; +} + +sub prefix_output { + my ($self, %options) = @_; + + return "Node '" . $options{instance_value}->{display} . "' "; +} + +sub prefix_condition_output { + my ($self, %options) = @_; + + return "Condition '" . $options{instance_value}->{type} . "' "; +} + +sub long_output { + my ($self, %options) = @_; + + return "Checking node '" . $options{instance_value}->{display} . "'"; +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1); + bless $self, $class; + + $options{options}->add_options(arguments => { + "filter-name:s" => { name => 'filter_name' }, + "warning-status:s" => { name => 'warning_status', default => '' }, + "critical-status:s" => { + name => 'critical_status', + default => '(%{type} =~ /Ready/i && %{status} !~ /True/i) || (%{type} =~ /.*Pressure/i && %{status} !~ /False/i)' + }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + $self->change_macros(macros => ['warning_status', 'critical_status']); +} + +sub manage_selection { + my ($self, %options) = @_; + + $self->{nodes} = {}; + + my $results = $options{custom}->kubernetes_list_nodes(); + + foreach my $node (@{$results}) { + if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' && + $node->{metadata}->{name} !~ /$self->{option_results}->{filter_name}/) { + $self->{output}->output_add(long_msg => "skipping '" . $node->{metadata}->{name} . "': no matching filter name.", debug => 1); + next; + } + + $self->{nodes}->{$node->{metadata}->{uid}}->{display} = $node->{metadata}->{name}; + + foreach my $condition (@{$node->{status}->{conditions}}) { + $self->{nodes}->{$node->{metadata}->{uid}}->{conditions}->{$condition->{type}} = { + type => $condition->{type}, + status => $condition->{status}, + reason => $condition->{reason}, + message => $condition->{message} + }; + } + } + + 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<--filter-name> + +Filter node name (can be a regexp). + +=item B<--warning-status> + +Set warning threshold for status (Default: ''). +Can used special variables like: %{type}, %{status}, %{reason}, %{message}. + +=item B<--critical-status> + +Set critical threshold for status (Default: '(%{type} =~ /Ready/i && %{status} !~ /True/i) || (%{type} =~ /.*Pressure/i && %{status} !~ /False/i)'). +Can used special variables like: %{type}, %{status}, %{reason}, %{message}. + +=back + +=cut diff --git a/cloud/kubernetes/mode/nodeusage.pm b/cloud/kubernetes/mode/nodeusage.pm index 9b5916240..5bce9a911 100644 --- a/cloud/kubernetes/mode/nodeusage.pm +++ b/cloud/kubernetes/mode/nodeusage.pm @@ -177,7 +177,7 @@ sub prefix_node_output { sub new { my ($class, %options) = @_; - my $self = $class->SUPER::new(package => __PACKAGE__, %options); + my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1); bless $self, $class; $options{options}->add_options(arguments => { diff --git a/cloud/kubernetes/mode/persistentvolumestatus.pm b/cloud/kubernetes/mode/persistentvolumestatus.pm new file mode 100644 index 000000000..7893a729a --- /dev/null +++ b/cloud/kubernetes/mode/persistentvolumestatus.pm @@ -0,0 +1,145 @@ +# +# Copyright 2021 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::kubernetes::mode::persistentvolumestatus; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; +use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold); + +sub custom_status_output { + my ($self, %options) = @_; + + return sprintf("Phase is '%s'", + $self->{result_values}->{phase}); +} + +sub custom_status_calc { + my ($self, %options) = @_; + + $self->{result_values}->{name} = $options{new_datas}->{$self->{instance} . '_name'}; + $self->{result_values}->{phase} = $options{new_datas}->{$self->{instance} . '_phase'}; + + return 0; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'pvs', type => 1, cb_prefix_output => 'prefix_pv_output', + message_multiple => 'All persistent volume status are ok', skipped_code => { -11 => 1 } }, + ]; + + $self->{maps_counters}->{pvs} = [ + { label => 'status', set => { + key_values => [ { name => 'phase' }, { name => 'name' } ], + 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 => \&catalog_status_threshold, + } + }, + ]; +} + +sub prefix_pv_output { + my ($self, %options) = @_; + + return "Persistent Volume '" . $options{instance_value}->{name} . "' "; +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1); + bless $self, $class; + + $options{options}->add_options(arguments => { + "filter-name:s" => { name => 'filter_name' }, + "filter-namespace:s" => { name => 'filter_namespace' }, + "warning-status:s" => { name => 'warning_status', default => '' }, + "critical-status:s" => { name => 'critical_status', default => '%{phase} !~ /Bound|Available|Released/i' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + $self->change_macros(macros => ['warning_status', 'critical_status']); +} + +sub manage_selection { + my ($self, %options) = @_; + + $self->{pvs} = {}; + + my $results = $options{custom}->kubernetes_list_pvs(); + + foreach my $pv (@{$results}) { + if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' && + $pv->{metadata}->{name} !~ /$self->{option_results}->{filter_name}/) { + $self->{output}->output_add(long_msg => "skipping '" . $pv->{metadata}->{name} . "': no matching filter name.", debug => 1); + next; + } + + $self->{pvs}->{$pv->{metadata}->{uid}} = { + name => $pv->{metadata}->{name}, + phase => $pv->{status}->{phase} + } + } + + if (scalar(keys %{$self->{pvs}}) <= 0) { + $self->{output}->add_option_msg(short_msg => "No persistent volumes found."); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check persistent volume status. + +=over 8 + +=item B<--filter-name> + +Filter persistent volume name (can be a regexp). + +=item B<--warning-status> + +Set warning threshold for status (Default: '') +Can used special variables like: %{name}, %{phase}. + +=item B<--critical-status> + +Set critical threshold for status (Default: '%{phase} !~ /Bound|Available|Released/i'). +Can used special variables like: %{name}, %{phase}. + +=back + +=cut diff --git a/cloud/kubernetes/mode/podstatus.pm b/cloud/kubernetes/mode/podstatus.pm index ce539e9e0..64ffd93a8 100644 --- a/cloud/kubernetes/mode/podstatus.pm +++ b/cloud/kubernetes/mode/podstatus.pm @@ -36,7 +36,8 @@ sub custom_pod_status_output { sub custom_pod_status_calc { my ($self, %options) = @_; - $self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_display'}; + $self->{result_values}->{name} = $options{new_datas}->{$self->{instance} . '_name'}; + $self->{result_values}->{namespace} = $options{new_datas}->{$self->{instance} . '_namespace'}; $self->{result_values}->{status} = $options{new_datas}->{$self->{instance} . '_status'}; return 0; @@ -53,7 +54,7 @@ sub custom_container_status_output { sub custom_container_status_calc { my ($self, %options) = @_; - $self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_display'}; + $self->{result_values}->{name} = $options{new_datas}->{$self->{instance} . '_name'}; $self->{result_values}->{status} = $options{new_datas}->{$self->{instance} . '_status'}; $self->{result_values}->{state} = ($options{new_datas}->{$self->{instance} . '_state'} == 1) ? "ready" : "not ready"; @@ -77,7 +78,7 @@ sub custom_ready_perfdata { warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{thlabel}, %total_options), critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{thlabel}, %total_options), min => 0, max => $total_options{total}, - instances => $self->use_instances(extra_instance => $options{extra_instance}) ? $self->{result_values}->{display} : undef, + instances => $self->use_instances(extra_instance => $options{extra_instance}) ? $self->{result_values}->{name} : undef, ); } @@ -110,7 +111,7 @@ sub custom_ready_output { sub custom_ready_calc { my ($self, %options) = @_; - $self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_display'}; + $self->{result_values}->{name} = $options{new_datas}->{$self->{instance} . '_name'}; $self->{result_values}->{ready} = $options{new_datas}->{$self->{instance} . '_containers_ready'}; $self->{result_values}->{total} = $options{new_datas}->{$self->{instance} . '_containers_total'}; return 0 if ($self->{result_values}->{total} == 0); @@ -136,7 +137,7 @@ sub set_counters { $self->{maps_counters}->{global} = [ { label => 'containers-ready', set => { - key_values => [ { name => 'containers_total' }, { name => 'containers_ready' }, { name => 'display' } ], + key_values => [ { name => 'containers_total' }, { name => 'containers_ready' }, { name => 'name' } ], closure_custom_calc => $self->can('custom_ready_calc'), closure_custom_output => $self->can('custom_ready_output'), closure_custom_perfdata => $self->can('custom_ready_perfdata'), @@ -144,7 +145,7 @@ sub set_counters { } }, { label => 'pod-status', set => { - key_values => [ { name => 'status' } ], + key_values => [ { name => 'status' }, { name => 'name' }, { name => 'namespace' } ], closure_custom_calc => $self->can('custom_pod_status_calc'), closure_custom_output => $self->can('custom_pod_status_output'), closure_custom_perfdata => sub { return 0; }, @@ -152,11 +153,11 @@ sub set_counters { } }, { label => 'total-restarts-count', nlabel => 'restarts.total.count', set => { - key_values => [ { name => 'restarts_total' }, { name => 'display' } ], + key_values => [ { name => 'restarts_total' }, { name => 'name' } ], output_template => 'Restarts: %d', perfdatas => [ { label => 'restarts_count', value => 'restarts_total', template => '%d', - min => 0, label_extra_instance => 1, instance_use => 'display' }, + min => 0, label_extra_instance => 1, instance_use => 'name' }, ], } }, @@ -185,24 +186,24 @@ sub set_counters { sub prefix_pod_output { my ($self, %options) = @_; - return "Pod '" . $options{instance_value}->{display} . "' "; + return "Pod '" . $options{instance_value}->{name} . "' "; } sub prefix_container_output { my ($self, %options) = @_; - return "Container '" . $options{instance_value}->{display} . "' "; + return "Container '" . $options{instance_value}->{name} . "' "; } sub long_output { my ($self, %options) = @_; - return "Checking pod '" . $options{instance_value}->{display} . "'"; + return "Checking pod '" . $options{instance_value}->{name} . "'"; } sub new { my ($class, %options) = @_; - my $self = $class->SUPER::new(package => __PACKAGE__, %options); + my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1); bless $self, $class; $options{options}->add_options(arguments => { @@ -261,9 +262,10 @@ sub manage_selection { } next if ($next == 1); - $self->{pods}->{$pod->{metadata}->{uid}}->{display} = $pod->{metadata}->{name}; + $self->{pods}->{$pod->{metadata}->{uid}}->{name} = $pod->{metadata}->{name}; $self->{pods}->{$pod->{metadata}->{uid}}->{global} = { - display => $pod->{metadata}->{name}, + name => $pod->{metadata}->{name}, + namespace => $pod->{metadata}->{namespace}, status => $pod->{status}->{phase}, containers_total => scalar(@{$pod->{status}->{containerStatuses}}), containers_ready => 0, @@ -272,7 +274,7 @@ sub manage_selection { foreach my $container (@{$pod->{status}->{containerStatuses}}) { $self->{pods}->{$pod->{metadata}->{uid}}->{containers}->{$container->{name}} = { - display => $container->{name}, + name => $container->{name}, status => keys %{$container->{state}}, state => $container->{ready}, restarts => $container->{restartCount}, @@ -316,22 +318,22 @@ Example : --extra-filter='app=mynewapp' =item B<--warning-pod-status> Set warning threshold for status (Default: ''). -Can used special variables like: %{status}, %{display} +Can used special variables like: %{status}, %{name}, %{namespace}. =item B<--critical-pod-status> Set critical threshold for status (Default: '%{status} !~ /running/i'). -Can used special variables like: %{status}, %{display} +Can used special variables like: %{status}, %{name}, %{namespace}. =item B<--warning-container-status> Set warning threshold for status (Default: ''). -Can used special variables like: %{status}, %{display} +Can used special variables like: %{status}, %{name}. =item B<--critical-container-status> Set critical threshold for status (Default: '%{status} !~ /running/i || %{state} !~ /^ready$/'). -Can used special variables like: %{status}, %{state}, %{display} +Can used special variables like: %{status}, %{state}, %{name}. =item B<--warning-*> diff --git a/cloud/kubernetes/mode/replicasetstatus.pm b/cloud/kubernetes/mode/replicasetstatus.pm new file mode 100644 index 000000000..bc329f830 --- /dev/null +++ b/cloud/kubernetes/mode/replicasetstatus.pm @@ -0,0 +1,188 @@ +# +# Copyright 2021 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::kubernetes::mode::replicasetstatus; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; +use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold); + +sub custom_status_perfdata { + my ($self, %options) = @_; + + $self->{output}->perfdata_add( + label => 'desired', + nlabel => 'replicaset.replicas.desired.count', + value => $self->{result_values}->{desired}, + instances => $self->use_instances(extra_instance => $options{extra_instance}) ? $self->{result_values}->{name} : undef, + ); + $self->{output}->perfdata_add( + label => 'current', + nlabel => 'replicaset.replicas.current.count', + value => $self->{result_values}->{current}, + instances => $self->use_instances(extra_instance => $options{extra_instance}) ? $self->{result_values}->{name} : undef, + ); + $self->{output}->perfdata_add( + label => 'ready', + nlabel => 'replicaset.replicas.ready.count', + value => $self->{result_values}->{ready}, + instances => $self->use_instances(extra_instance => $options{extra_instance}) ? $self->{result_values}->{name} : undef, + ); +} + +sub custom_status_output { + my ($self, %options) = @_; + + return sprintf("Replicas Desired: %s, Current: %s, Ready: %s", + $self->{result_values}->{desired}, + $self->{result_values}->{current}, + $self->{result_values}->{ready}); +} + +sub custom_status_calc { + my ($self, %options) = @_; + + $self->{result_values}->{name} = $options{new_datas}->{$self->{instance} . '_name'}; + $self->{result_values}->{namespace} = $options{new_datas}->{$self->{instance} . '_namespace'}; + $self->{result_values}->{desired} = $options{new_datas}->{$self->{instance} . '_desired'}; + $self->{result_values}->{current} = $options{new_datas}->{$self->{instance} . '_current'}; + $self->{result_values}->{ready} = $options{new_datas}->{$self->{instance} . '_ready'}; + + return 0; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'replicasets', type => 1, cb_prefix_output => 'prefix_replicaset_output', + message_multiple => 'All ReplicaSets status are ok', skipped_code => { -11 => 1 } }, + ]; + + $self->{maps_counters}->{replicasets} = [ + { label => 'status', set => { + key_values => [ { name => 'desired' }, { name => 'current' }, + { name => 'ready' }, { name => 'name' }, { name => 'namespace' } ], + 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 => \&catalog_status_threshold, + } + }, + ]; +} + +sub prefix_replicaset_output { + my ($self, %options) = @_; + + return "ReplicaSet '" . $options{instance_value}->{name} . "' "; +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1); + bless $self, $class; + + $options{options}->add_options(arguments => { + "filter-name:s" => { name => 'filter_name' }, + "filter-namespace:s" => { name => 'filter_namespace' }, + "warning-status:s" => { name => 'warning_status', default => '' }, + "critical-status:s" => { name => 'critical_status', default => '%{ready} < %{desired}' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + $self->change_macros(macros => ['warning_status', 'critical_status']); +} + +sub manage_selection { + my ($self, %options) = @_; + + $self->{replicasets} = {}; + + my $results = $options{custom}->kubernetes_list_replicasets(); + + foreach my $replicaset (@{$results}) { + if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' && + $replicaset->{metadata}->{name} !~ /$self->{option_results}->{filter_name}/) { + $self->{output}->output_add(long_msg => "skipping '" . $replicaset->{metadata}->{name} . "': no matching filter name.", debug => 1); + next; + } + if (defined($self->{option_results}->{filter_namespace}) && $self->{option_results}->{filter_namespace} ne '' && + $replicaset->{metadata}->{namespace} !~ /$self->{option_results}->{filter_namespace}/) { + $self->{output}->output_add(long_msg => "skipping '" . $replicaset->{metadata}->{namespace} . "': no matching filter namespace.", debug => 1); + next; + } + + $self->{replicasets}->{$replicaset->{metadata}->{uid}} = { + name => $replicaset->{metadata}->{name}, + namespace => $replicaset->{metadata}->{namespace}, + desired => $replicaset->{spec}->{replicas}, + current => (defined($replicaset->{status}->{replicas})) && $replicaset->{status}->{replicas} =~ /(\d+)/ ? $1 : 0, + ready => (defined($replicaset->{status}->{readyReplicas})) && $replicaset->{status}->{readyReplicas} =~ /(\d+)/ ? $1 : 0 + } + } + + if (scalar(keys %{$self->{replicasets}}) <= 0) { + $self->{output}->add_option_msg(short_msg => "No ReplicaSets found."); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check ReplicaSet status. + +=over 8 + +=item B<--filter-name> + +Filter ReplicaSet name (can be a regexp). + +=item B<--filter-namespace> + +Filter ReplicaSet namespace (can be a regexp). + +=item B<--warning-status> + +Set warning threshold for status (Default: '') +Can used special variables like: %{name}, %{namespace}, %{desired}, %{current}, +%{ready}. + +=item B<--critical-status> + +Set critical threshold for status (Default: '%{ready} < %{desired}'). +Can used special variables like: %{name}, %{namespace}, %{desired}, %{current}, +%{ready}. + +=back + +=cut diff --git a/cloud/kubernetes/mode/replicationcontrollerstatus.pm b/cloud/kubernetes/mode/replicationcontrollerstatus.pm new file mode 100644 index 000000000..9aadf5465 --- /dev/null +++ b/cloud/kubernetes/mode/replicationcontrollerstatus.pm @@ -0,0 +1,188 @@ +# +# Copyright 2021 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::kubernetes::mode::replicationcontrollerstatus; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; +use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold); + +sub custom_status_perfdata { + my ($self, %options) = @_; + + $self->{output}->perfdata_add( + label => 'desired', + nlabel => 'replicationcontroller.replicas.desired.count', + value => $self->{result_values}->{desired}, + instances => $self->use_instances(extra_instance => $options{extra_instance}) ? $self->{result_values}->{name} : undef, + ); + $self->{output}->perfdata_add( + label => 'current', + nlabel => 'replicationcontroller.replicas.current.count', + value => $self->{result_values}->{current}, + instances => $self->use_instances(extra_instance => $options{extra_instance}) ? $self->{result_values}->{name} : undef, + ); + $self->{output}->perfdata_add( + label => 'ready', + nlabel => 'replicationcontroller.replicas.ready.count', + value => $self->{result_values}->{ready}, + instances => $self->use_instances(extra_instance => $options{extra_instance}) ? $self->{result_values}->{name} : undef, + ); +} + +sub custom_status_output { + my ($self, %options) = @_; + + return sprintf("Replicas Desired: %s, Current: %s, Ready: %s", + $self->{result_values}->{desired}, + $self->{result_values}->{current}, + $self->{result_values}->{ready}); +} + +sub custom_status_calc { + my ($self, %options) = @_; + + $self->{result_values}->{name} = $options{new_datas}->{$self->{instance} . '_name'}; + $self->{result_values}->{namespace} = $options{new_datas}->{$self->{instance} . '_namespace'}; + $self->{result_values}->{desired} = $options{new_datas}->{$self->{instance} . '_desired'}; + $self->{result_values}->{current} = $options{new_datas}->{$self->{instance} . '_current'}; + $self->{result_values}->{ready} = $options{new_datas}->{$self->{instance} . '_ready'}; + + return 0; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'rcs', type => 1, cb_prefix_output => 'prefix_rc_output', + message_multiple => 'All ReplicationControllers status are ok', skipped_code => { -11 => 1 } }, + ]; + + $self->{maps_counters}->{rcs} = [ + { label => 'status', set => { + key_values => [ { name => 'desired' }, { name => 'current' }, + { name => 'ready' }, { name => 'name' }, { name => 'namespace' } ], + 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 => \&catalog_status_threshold, + } + }, + ]; +} + +sub prefix_rc_output { + my ($self, %options) = @_; + + return "ReplicationController '" . $options{instance_value}->{name} . "' "; +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1); + bless $self, $class; + + $options{options}->add_options(arguments => { + "filter-name:s" => { name => 'filter_name' }, + "filter-namespace:s" => { name => 'filter_namespace' }, + "warning-status:s" => { name => 'warning_status', default => '' }, + "critical-status:s" => { name => 'critical_status', default => '%{ready} < %{desired}' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + $self->change_macros(macros => ['warning_status', 'critical_status']); +} + +sub manage_selection { + my ($self, %options) = @_; + + $self->{rcs} = {}; + + my $results = $options{custom}->kubernetes_list_rcs(); + + foreach my $rc (@{$results}) { + if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' && + $rc->{metadata}->{name} !~ /$self->{option_results}->{filter_name}/) { + $self->{output}->output_add(long_msg => "skipping '" . $rc->{metadata}->{name} . "': no matching filter name.", debug => 1); + next; + } + if (defined($self->{option_results}->{filter_namespace}) && $self->{option_results}->{filter_namespace} ne '' && + $rc->{metadata}->{namespace} !~ /$self->{option_results}->{filter_namespace}/) { + $self->{output}->output_add(long_msg => "skipping '" . $rc->{metadata}->{namespace} . "': no matching filter namespace.", debug => 1); + next; + } + + $self->{rcs}->{$rc->{metadata}->{uid}} = { + name => $rc->{metadata}->{name}, + namespace => $rc->{metadata}->{namespace}, + desired => $rc->{spec}->{replicas}, + current => (defined($rc->{status}->{replicas})) && $rc->{status}->{replicas} =~ /(\d+)/ ? $1 : 0, + ready => (defined($rc->{status}->{readyReplicas})) && $rc->{status}->{readyReplicas} =~ /(\d+)/ ? $1 : 0 + } + } + + if (scalar(keys %{$self->{rcs}}) <= 0) { + $self->{output}->add_option_msg(short_msg => "No ReplicationControllers found."); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check ReplicationController status. + +=over 8 + +=item B<--filter-name> + +Filter ReplicationController name (can be a regexp). + +=item B<--filter-namespace> + +Filter ReplicationController namespace (can be a regexp). + +=item B<--warning-status> + +Set warning threshold for status (Default: '') +Can used special variables like: %{name}, %{namespace}, %{desired}, %{current}, +%{ready}. + +=item B<--critical-status> + +Set critical threshold for status (Default: '%{ready} < %{desired}'). +Can used special variables like: %{name}, %{namespace}, %{desired}, %{current}, +%{ready}. + +=back + +=cut diff --git a/cloud/kubernetes/mode/statefulsetstatus.pm b/cloud/kubernetes/mode/statefulsetstatus.pm new file mode 100644 index 000000000..d2150e124 --- /dev/null +++ b/cloud/kubernetes/mode/statefulsetstatus.pm @@ -0,0 +1,197 @@ +# +# Copyright 2021 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::kubernetes::mode::statefulsetstatus; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; +use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold); + +sub custom_status_perfdata { + my ($self, %options) = @_; + + $self->{output}->perfdata_add( + label => 'desired', + nlabel => 'statefulset.replicas.desired.count', + value => $self->{result_values}->{desired}, + instances => $self->use_instances(extra_instance => $options{extra_instance}) ? $self->{result_values}->{name} : undef, + ); + $self->{output}->perfdata_add( + label => 'current', + nlabel => 'statefulset.replicas.current.count', + value => $self->{result_values}->{current}, + instances => $self->use_instances(extra_instance => $options{extra_instance}) ? $self->{result_values}->{name} : undef, + ); + $self->{output}->perfdata_add( + label => 'up_to_date', + nlabel => 'statefulset.replicas.uptodate.count', + value => $self->{result_values}->{up_to_date}, + instances => $self->use_instances(extra_instance => $options{extra_instance}) ? $self->{result_values}->{name} : undef, + ); + $self->{output}->perfdata_add( + label => 'ready', + nlabel => 'statefulset.replicas.ready.count', + value => $self->{result_values}->{ready}, + instances => $self->use_instances(extra_instance => $options{extra_instance}) ? $self->{result_values}->{name} : undef, + ); +} + +sub custom_status_output { + my ($self, %options) = @_; + + return sprintf("Replicas Desired: %s, Current: %s, Up-to-date: %s, Ready: %s", + $self->{result_values}->{desired}, + $self->{result_values}->{current}, + $self->{result_values}->{up_to_date}, + $self->{result_values}->{ready}); +} + +sub custom_status_calc { + my ($self, %options) = @_; + + $self->{result_values}->{name} = $options{new_datas}->{$self->{instance} . '_name'}; + $self->{result_values}->{namespace} = $options{new_datas}->{$self->{instance} . '_namespace'}; + $self->{result_values}->{desired} = $options{new_datas}->{$self->{instance} . '_desired'}; + $self->{result_values}->{current} = $options{new_datas}->{$self->{instance} . '_current'}; + $self->{result_values}->{up_to_date} = $options{new_datas}->{$self->{instance} . '_up_to_date'}; + $self->{result_values}->{ready} = $options{new_datas}->{$self->{instance} . '_ready'}; + + return 0; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'statefulsets', type => 1, cb_prefix_output => 'prefix_statefulset_output', + message_multiple => 'All StatefulSets status are ok', skipped_code => { -11 => 1 } }, + ]; + + $self->{maps_counters}->{statefulsets} = [ + { label => 'status', set => { + key_values => [ { name => 'desired' }, { name => 'current' }, { name => 'up_to_date' }, + { name => 'ready' }, { name => 'name' } ], + 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 => \&catalog_status_threshold, + } + }, + ]; +} + +sub prefix_statefulset_output { + my ($self, %options) = @_; + + return "StatefulSet '" . $options{instance_value}->{name} . "' "; +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1); + bless $self, $class; + + $options{options}->add_options(arguments => { + "filter-name:s" => { name => 'filter_name' }, + "filter-namespace:s" => { name => 'filter_namespace' }, + "warning-status:s" => { name => 'warning_status', default => '%{up_to_date} < %{desired}' }, + "critical-status:s" => { name => 'critical_status', default => '%{ready} < %{desired}' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + $self->change_macros(macros => ['warning_status', 'critical_status']); +} + +sub manage_selection { + my ($self, %options) = @_; + + $self->{statefulsets} = {}; + + my $results = $options{custom}->kubernetes_list_statefulsets(); + + foreach my $statefulset (@{$results}) { + if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' && + $statefulset->{metadata}->{name} !~ /$self->{option_results}->{filter_name}/) { + $self->{output}->output_add(long_msg => "skipping '" . $statefulset->{metadata}->{name} . "': no matching filter name.", debug => 1); + next; + } + if (defined($self->{option_results}->{filter_namespace}) && $self->{option_results}->{filter_namespace} ne '' && + $statefulset->{metadata}->{namespace} !~ /$self->{option_results}->{filter_namespace}/) { + $self->{output}->output_add(long_msg => "skipping '" . $statefulset->{metadata}->{namespace} . "': no matching filter namespace.", debug => 1); + next; + } + + $self->{statefulsets}->{$statefulset->{metadata}->{uid}} = { + name => $statefulset->{metadata}->{name}, + namespace => $statefulset->{metadata}->{namespace}, + desired => $statefulset->{spec}->{replicas}, + current => (defined($statefulset->{status}->{currentReplicas})) && $statefulset->{status}->{currentReplicas} =~ /(\d+)/ ? $1 : 0, + ready => (defined($statefulset->{status}->{readyReplicas})) && $statefulset->{status}->{readyReplicas} =~ /(\d+)/ ? $1 : 0, + up_to_date => (defined($statefulset->{status}->{updatedReplicas})) && $statefulset->{status}->{updatedReplicas} =~ /(\d+)/ ? $1 : 0 + } + } + + if (scalar(keys %{$self->{statefulsets}}) <= 0) { + $self->{output}->add_option_msg(short_msg => "No StatefulSets found."); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check StatefulSet status. + +=over 8 + +=item B<--filter-name> + +Filter StatefulSet name (can be a regexp). + +=item B<--filter-namespace> + +Filter StatefulSet namespace (can be a regexp). + +=item B<--warning-status> + +Set warning threshold for status (Default: '%{up_to_date} < %{desired}') +Can used special variables like: %{name}, %{namespace}, %{desired}, %{current}, +%{up_to_date}, %{ready}. + +=item B<--critical-status> + +Set critical threshold for status (Default: '%{ready} < %{desired}'). +Can used special variables like: %{name}, %{namespace}, %{desired}, %{current}, +%{up_to_date}, %{ready}. + +=back + +=cut diff --git a/cloud/kubernetes/plugin.pm b/cloud/kubernetes/plugin.pm index 08faf2e01..1114b4f3a 100644 --- a/cloud/kubernetes/plugin.pm +++ b/cloud/kubernetes/plugin.pm @@ -31,20 +31,30 @@ sub new { $self->{version} = '1.0'; %{$self->{modes}} = ( - 'daemonset-status' => 'cloud::kubernetes::mode::daemonsetstatus', - 'deployment-status' => 'cloud::kubernetes::mode::deploymentstatus', - 'list-daemonsets' => 'cloud::kubernetes::mode::listdaemonsets', - 'list-deployments' => 'cloud::kubernetes::mode::listdeployments', - 'list-ingresses' => 'cloud::kubernetes::mode::listingresses', - 'list-namespaces' => 'cloud::kubernetes::mode::listnamespaces', - 'list-nodes' => 'cloud::kubernetes::mode::listnodes', - 'list-pods' => 'cloud::kubernetes::mode::listpods', - 'list-replicasets' => 'cloud::kubernetes::mode::listreplicasets', - 'list-services' => 'cloud::kubernetes::mode::listservices', - 'list-statefulsets' => 'cloud::kubernetes::mode::liststatefulsets', - 'nodes-discovery' => 'cloud::kubernetes::mode::nodesdiscovery', - 'node-usage' => 'cloud::kubernetes::mode::nodeusage', - 'pod-status' => 'cloud::kubernetes::mode::podstatus', + 'cluster-events' => 'cloud::kubernetes::mode::clusterevents', + 'cronjob-status' => 'cloud::kubernetes::mode::cronjobstatus', + 'daemonset-status' => 'cloud::kubernetes::mode::daemonsetstatus', + 'deployment-status' => 'cloud::kubernetes::mode::deploymentstatus', + 'discovery-nodes' => 'cloud::kubernetes::mode::discoverynodes', + 'list-cronjobs' => 'cloud::kubernetes::mode::listcronjobs', + 'list-daemonsets' => 'cloud::kubernetes::mode::listdaemonsets', + 'list-deployments' => 'cloud::kubernetes::mode::listdeployments', + 'list-ingresses' => 'cloud::kubernetes::mode::listingresses', + 'list-namespaces' => 'cloud::kubernetes::mode::listnamespaces', + 'list-nodes' => 'cloud::kubernetes::mode::listnodes', + 'list-persistentvolumes' => 'cloud::kubernetes::mode::listpersistentvolumes', + 'list-pods' => 'cloud::kubernetes::mode::listpods', + 'list-replicasets' => 'cloud::kubernetes::mode::listreplicasets', + 'list-replicationcontrollers' => 'cloud::kubernetes::mode::listreplicationcontrollers', + 'list-services' => 'cloud::kubernetes::mode::listservices', + 'list-statefulsets' => 'cloud::kubernetes::mode::liststatefulsets', + 'node-status' => 'cloud::kubernetes::mode::nodestatus', + 'node-usage' => 'cloud::kubernetes::mode::nodeusage', + 'persistentvolume-status' => 'cloud::kubernetes::mode::persistentvolumestatus', + 'pod-status' => 'cloud::kubernetes::mode::podstatus', + 'replicaset-status' => 'cloud::kubernetes::mode::replicasetstatus', + 'replicationcontroller-status' => 'cloud::kubernetes::mode::replicationcontrollerstatus', + 'statefulset-status' => 'cloud::kubernetes::mode::statefulsetstatus', ); $self->{custom_modes}{api} = 'cloud::kubernetes::custom::api';