From b61565b99537ba61daa7fe58aac29cee391ea58d Mon Sep 17 00:00:00 2001 From: Colin Gagnaire Date: Fri, 22 Feb 2019 17:59:40 +0100 Subject: [PATCH] add kubernetes restapi plugin --- cloud/kubernetes/restapi/custom/api.pm | 253 ++++++++++++++ .../restapi/mode/daemonsetstatus.pm | 196 +++++++++++ .../restapi/mode/deploymentstatus.pm | 207 +++++++++++ .../kubernetes/restapi/mode/listdaemonsets.pm | 128 +++++++ .../restapi/mode/listdeployments.pm | 128 +++++++ .../kubernetes/restapi/mode/listingresses.pm | 128 +++++++ .../kubernetes/restapi/mode/listnamespaces.pm | 115 +++++++ cloud/kubernetes/restapi/mode/listnodes.pm | 115 +++++++ cloud/kubernetes/restapi/mode/listpods.pm | 137 ++++++++ .../restapi/mode/listreplicasets.pm | 128 +++++++ cloud/kubernetes/restapi/mode/listservices.pm | 128 +++++++ .../restapi/mode/liststatefulsets.pm | 128 +++++++ cloud/kubernetes/restapi/mode/podstatus.pm | 323 ++++++++++++++++++ cloud/kubernetes/restapi/plugin.pm | 66 ++++ 14 files changed, 2180 insertions(+) create mode 100644 cloud/kubernetes/restapi/custom/api.pm create mode 100644 cloud/kubernetes/restapi/mode/daemonsetstatus.pm create mode 100644 cloud/kubernetes/restapi/mode/deploymentstatus.pm create mode 100644 cloud/kubernetes/restapi/mode/listdaemonsets.pm create mode 100644 cloud/kubernetes/restapi/mode/listdeployments.pm create mode 100644 cloud/kubernetes/restapi/mode/listingresses.pm create mode 100644 cloud/kubernetes/restapi/mode/listnamespaces.pm create mode 100644 cloud/kubernetes/restapi/mode/listnodes.pm create mode 100644 cloud/kubernetes/restapi/mode/listpods.pm create mode 100644 cloud/kubernetes/restapi/mode/listreplicasets.pm create mode 100644 cloud/kubernetes/restapi/mode/listservices.pm create mode 100644 cloud/kubernetes/restapi/mode/liststatefulsets.pm create mode 100644 cloud/kubernetes/restapi/mode/podstatus.pm create mode 100644 cloud/kubernetes/restapi/plugin.pm diff --git a/cloud/kubernetes/restapi/custom/api.pm b/cloud/kubernetes/restapi/custom/api.pm new file mode 100644 index 000000000..93fdf90ad --- /dev/null +++ b/cloud/kubernetes/restapi/custom/api.pm @@ -0,0 +1,253 @@ +# +# Copyright 2019 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::restapi::custom::api; + +use strict; +use warnings; +use centreon::plugins::http; +use DateTime; +use JSON::XS; +use URI::Encode; + +sub new { + my ($class, %options) = @_; + my $self = {}; + bless $self, $class; + + if (!defined($options{output})) { + print "Class Custom: Need to specify 'output' argument.\n"; + exit 3; + } + if (!defined($options{options})) { + $options{output}->add_option_msg(short_msg => "Class Custom: Need to specify 'options' argument."); + $options{output}->option_exit(); + } + + if (!defined($options{noptions})) { + $options{options}->add_options(arguments => { + "hostname:s" => { name => 'hostname' }, + "url-path:s" => { name => 'url_path' }, + "port:s" => { name => 'port' }, + "proto:s" => { name => 'proto' }, + "token:s" => { name => 'token' }, + "proxyurl:s" => { name => 'proxyurl' }, + "timeout:s" => { name => 'timeout' }, + "ssl-opt:s@" => { name => 'ssl_opt' }, + }); + } + $options{options}->add_help(package => __PACKAGE__, sections => 'REST API OPTIONS', once => 1); + + $self->{output} = $options{output}; + $self->{mode} = $options{mode}; + $self->{http} = centreon::plugins::http->new(output => $self->{output}); + + return $self; +} + +sub set_options { + my ($self, %options) = @_; + + $self->{option_results} = $options{option_results}; +} + +sub set_defaults { + my ($self, %options) = @_; + + foreach (keys %{$options{default}}) { + if ($_ eq $self->{mode}) { + for (my $i = 0; $i < scalar(@{$options{default}->{$_}}); $i++) { + foreach my $opt (keys %{$options{default}->{$_}[$i]}) { + if (!defined($self->{option_results}->{$opt}[$i])) { + $self->{option_results}->{$opt}[$i] = $options{default}->{$_}[$i]->{$opt}; + } + } + } + } + } +} + +sub check_options { + my ($self, %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->{url_path} = (defined($self->{option_results}->{url_path})) ? $self->{option_results}->{url_path} : ''; + $self->{timeout} = (defined($self->{option_results}->{timeout})) ? $self->{option_results}->{timeout} : 10; + $self->{token} = (defined($self->{option_results}->{token})) ? $self->{option_results}->{token} : ''; + + if (!defined($self->{hostname}) || $self->{hostname} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --hostname option."); + $self->{output}->option_exit(); + } + if (!defined($self->{token}) || $self->{token} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --token option."); + $self->{output}->option_exit(); + } + + return 0; +} + +sub build_options_for_httplib { + my ($self, %options) = @_; + + $self->{option_results}->{hostname} = $self->{hostname}; + $self->{option_results}->{timeout} = $self->{timeout}; + $self->{option_results}->{port} = $self->{port}; + $self->{option_results}->{proto} = $self->{proto}; + $self->{option_results}->{url_path} = $self->{url_path}; + $self->{option_results}->{warning_status} = ''; + $self->{option_results}->{critical_status} = ''; + $self->{option_results}->{unknown_status} = ''; +} + +sub settings { + my ($self, %options) = @_; + + $self->build_options_for_httplib(); + $self->{http}->add_header(key => 'Accept', value => 'application/json'); + if (defined($self->{access_token})) { + $self->{http}->add_header(key => 'Authorization', value => 'Bearer ' . $self->{access_token}); + } + $self->{http}->set_options(%{$self->{option_results}}); +} + +sub get_connection_info { + my ($self, %options) = @_; + + return $self->{hostname} . ":" . $self->{port}; +} + +sub get_hostname { + my ($self, %options) = @_; + + return $self->{hostname}; +} + +sub get_port { + my ($self, %options) = @_; + + return $self->{port}; +} + +sub get_token { + my ($self, %options) = @_; + + return $self->{option_results}->{token}; +} + +sub request_api { + my ($self, %options) = @_; + + if (!defined($self->{access_token})) { + $self->{access_token} = $self->get_token(); + } + + $self->settings; + + $self->{output}->output_add(long_msg => "Query URL: '" . $self->{proto} . "://" . $self->{hostname} . + $self->{url_path} . $options{url_path} . "'", debug => 1); + + my $content = $self->{http}->request(url_path => $self->{url_path} . $options{url_path}); + my $response = $self->{http}->get_response(); + + if ($response->code() != 200) { + my $decoded; + eval { + $decoded = JSON::XS->new->utf8->decode($content); + }; + if ($@) { + $self->{output}->output_add(long_msg => $content, debug => 1); + $self->{output}->add_option_msg(short_msg => "Cannot decode json response: $@"); + $self->{output}->option_exit(); + } + if (defined($decoded->{code})) { + $self->{output}->output_add(long_msg => "Error message : " . $decoded->{message}, debug => 1); + $self->{output}->add_option_msg(short_msg => "API return error code '" . $decoded->{code} . "' (add --debug option for detailed message)"); + $self->{output}->option_exit(); + } else { + $self->{output}->output_add(long_msg => "Error message : " . $decoded, debug => 1); + $self->{output}->add_option_msg(short_msg => "API return error code '" . $response->code() . "' (add --debug option for detailed message)"); + $self->{output}->option_exit(); + } + } + + my $decoded; + eval { + $decoded = JSON::XS->new->utf8->decode($content); + }; + if ($@) { + $self->{output}->add_option_msg(short_msg => "Cannot decode json response: $@"); + $self->{output}->option_exit(); + } + + return $decoded; +} + +1; + +__END__ + +=head1 NAME + +Kubernetes Rest API + +=head1 SYNOPSIS + +Kubernetes Rest API custom mode + +=head1 REST API OPTIONS + +Kubernetes Rest API + +=over 8 + +=item B<--hostname> + +Kubernetes API hostname. + +=item B<--port> + +API port (Default: 443) + +=item B<--proto> + +Specify https if needed (Default: 'https') + +=item B<--proxyurl> + +Proxy URL if any + +=item B<--timeout> + +Set HTTP timeout + +=item B<--ssl-opt> + +Set SSL option (--ssl-opt="SSL_version => TLSv1" --ssl-opt="SSL_verify_mode => SSL_VERIFY_NONE"). + +=back + +=head1 DESCRIPTION + +B. + +=cut diff --git a/cloud/kubernetes/restapi/mode/daemonsetstatus.pm b/cloud/kubernetes/restapi/mode/daemonsetstatus.pm new file mode 100644 index 000000000..5cd002195 --- /dev/null +++ b/cloud/kubernetes/restapi/mode/daemonsetstatus.pm @@ -0,0 +1,196 @@ +# +# Copyright 2019 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::restapi::mode::daemonsetstatus; + +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) = @_; + + 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 => '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_output { + my ($self, %options) = @_; + + return sprintf("Pods Desired: %s, Current: %s, Available: %s, Up-to-date: %s, Ready: %s, Misscheduled: %s", + $self->{result_values}->{desired}, + $self->{result_values}->{current}, + $self->{result_values}->{available}, + $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}->{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 => '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 => \&catalog_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 => { + "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 => '%{available} < %{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->{daemonsets} = {}; + + my $results = $options{custom}->request_api(url_path => '/apis/apps/v1/daemonsets'); + + foreach my $daemonset (@{$results->{items}}) { + if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' && + $daemonset->{metadata}->{name} !~ /$self->{option_results}->{filter_name}/) { + $self->{output}->output_add(long_msg => "skipping '" . $daemonset->{metadata}->{name} . "': no matching filter name.", debug => 1); + next; + } + if (defined($self->{option_results}->{filter_namespace}) && $self->{option_results}->{filter_namespace} ne '' && + $daemonset->{metadata}->{namespace} !~ /$self->{option_results}->{filter_namespace}/) { + $self->{output}->output_add(long_msg => "skipping '" . $daemonset->{metadata}->{namespace} . "': no matching filter namespace.", debug => 1); + next; + } + + $self->{daemonsets}->{$daemonset->{metadata}->{uid}} = { + display => $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}, + } + } + + 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<--filter-name> + +Filter daemonset name (can be a regexp). + +=item B<--filter-namespace> + +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} + +=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} + +=back + +=cut diff --git a/cloud/kubernetes/restapi/mode/deploymentstatus.pm b/cloud/kubernetes/restapi/mode/deploymentstatus.pm new file mode 100644 index 000000000..45fa43a48 --- /dev/null +++ b/cloud/kubernetes/restapi/mode/deploymentstatus.pm @@ -0,0 +1,207 @@ +# +# Copyright 2019 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::restapi::mode::deploymentstatus; + +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) = @_; + + 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 => 'ready' . $extra_label, + value => $self->{result_values}->{ready}); + $self->{output}->perfdata_add(label => 'up_to_date' . $extra_label, + value => $self->{result_values}->{up_to_date}); +} + +sub custom_status_output { + my ($self, %options) = @_; + + return sprintf("Replicas Desired: %s, Current: %s, Available: %s, Ready: %s, Up-to-date: %s", + $self->{result_values}->{desired}, + $self->{result_values}->{current}, + $self->{result_values}->{available}, + $self->{result_values}->{ready}, + $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}->{ready} = $options{new_datas}->{$self->{instance} . '_ready'}; + $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 => 'ready' }, { 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 => \&catalog_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 => { + "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 => '%{available} < %{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->{deployments} = {}; + + my $results = $options{custom}->request_api(url_path => '/apis/apps/v1/deployments'); + + foreach my $deployment (@{$results->{items}}) { + if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' && + $deployment->{metadata}->{name} !~ /$self->{option_results}->{filter_name}/) { + $self->{output}->output_add(long_msg => "skipping '" . $deployment->{metadata}->{name} . "': no matching filter name.", debug => 1); + next; + } + if (defined($self->{option_results}->{filter_namespace}) && $self->{option_results}->{filter_namespace} ne '' && + $deployment->{metadata}->{namespace} !~ /$self->{option_results}->{filter_namespace}/) { + $self->{output}->output_add(long_msg => "skipping '" . $deployment->{metadata}->{namespace} . "': no matching filter namespace.", debug => 1); + next; + } + + $self->{deployments}->{$deployment->{metadata}->{uid}} = { + display => $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}, + } + } + + 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 PromQL filter, Default: 'deployment=~".*"') + +=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) + +Example : --metric-overload='metric,^my_metric_name$' + +Default : + + - 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$ + +=back + +=cut diff --git a/cloud/kubernetes/restapi/mode/listdaemonsets.pm b/cloud/kubernetes/restapi/mode/listdaemonsets.pm new file mode 100644 index 000000000..e1733f028 --- /dev/null +++ b/cloud/kubernetes/restapi/mode/listdaemonsets.pm @@ -0,0 +1,128 @@ +# +# Copyright 2019 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::restapi::mode::listdaemonsets; + +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; + + $self->{version} = '1.0'; + $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}->request_api(url_path => '/apis/apps/v1/daemonsets'); + + foreach my $daemonset (@{$results->{items}}) { + if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' && + $daemonset->{metadata}->{name} !~ /$self->{option_results}->{filter_name}/) { + $self->{output}->output_add(long_msg => "skipping '" . $daemonset->{metadata}->{name} . "': no matching filter name.", debug => 1); + next; + } + if (defined($self->{option_results}->{filter_namespace}) && $self->{option_results}->{filter_namespace} ne '' && + $daemonset->{metadata}->{namespace} !~ /$self->{option_results}->{filter_namespace}/) { + $self->{output}->output_add(long_msg => "skipping '" . $daemonset->{metadata}->{namespace} . "': no matching filter namespace.", debug => 1); + next; + } + + $self->{daemonsets}->{$daemonset->{metadata}->{uid}} = { + uid => $daemonset->{metadata}->{uid}, + name => $daemonset->{metadata}->{name}, + namespace => $daemonset->{metadata}->{namespace}, + } + } +} + +sub run { + my ($self, %options) = @_; + + $self->manage_selection(%options); + foreach my $daemonset (sort keys %{$self->{daemonsets}}) { + $self->{output}->output_add(long_msg => sprintf("[uid = %s] [name = %s] [namespace = %s]", + $self->{daemonsets}->{$daemonset}->{uid}, + $self->{daemonsets}->{$daemonset}->{name}, + $self->{daemonsets}->{$daemonset}->{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 => ['uid', 'name', 'namespace']); +} + +sub disco_show { + my ($self, %options) = @_; + + $self->manage_selection(%options); + foreach my $daemonset (sort keys %{$self->{daemonsets}}) { + $self->{output}->add_disco_entry( + uid => $self->{daemonsets}->{$daemonset}->{uid}, + name => $self->{daemonsets}->{$daemonset}->{name}, + namespace => $self->{daemonsets}->{$daemonset}->{namespace}, + ); + } +} + +1; + +__END__ + +=head1 MODE + +List daemonsets. + +=over 8 + +=item B<--filter-name> + +Filter daemonset name (can be a regexp). + +=item B<--filter-namespace> + +Filter daemonset namespace (can be a regexp). + +=back + +=cut diff --git a/cloud/kubernetes/restapi/mode/listdeployments.pm b/cloud/kubernetes/restapi/mode/listdeployments.pm new file mode 100644 index 000000000..a5eb8062e --- /dev/null +++ b/cloud/kubernetes/restapi/mode/listdeployments.pm @@ -0,0 +1,128 @@ +# +# Copyright 2019 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::restapi::mode::listdeployments; + +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; + + $self->{version} = '1.0'; + $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}->request_api(url_path => '/apis/apps/v1/deployments'); + + foreach my $deployment (@{$results->{items}}) { + if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' && + $deployment->{metadata}->{name} !~ /$self->{option_results}->{filter_name}/) { + $self->{output}->output_add(long_msg => "skipping '" . $deployment->{metadata}->{name} . "': no matching filter name.", debug => 1); + next; + } + if (defined($self->{option_results}->{filter_namespace}) && $self->{option_results}->{filter_namespace} ne '' && + $deployment->{metadata}->{namespace} !~ /$self->{option_results}->{filter_namespace}/) { + $self->{output}->output_add(long_msg => "skipping '" . $deployment->{metadata}->{namespace} . "': no matching filter namespace.", debug => 1); + next; + } + + $self->{deployments}->{$deployment->{metadata}->{uid}} = { + uid => $deployment->{metadata}->{uid}, + name => $deployment->{metadata}->{name}, + namespace => $deployment->{metadata}->{namespace}, + } + } +} + +sub run { + my ($self, %options) = @_; + + $self->manage_selection(%options); + foreach my $deployment (sort keys %{$self->{deployments}}) { + $self->{output}->output_add(long_msg => sprintf("[uid = %s] [name = %s] [namespace = %s]", + $self->{deployments}->{$deployment}->{uid}, + $self->{deployments}->{$deployment}->{name}, + $self->{deployments}->{$deployment}->{namespace})); + } + + $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 => ['uid', 'name', 'namespace']); +} + +sub disco_show { + my ($self, %options) = @_; + + $self->manage_selection(%options); + foreach my $deployment (sort keys %{$self->{deployments}}) { + $self->{output}->add_disco_entry( + uid => $self->{deployments}->{$deployment}->{uid}, + name => $self->{deployments}->{$deployment}->{name}, + namespace => $self->{deployments}->{$deployment}->{namespace}, + ); + } +} + +1; + +__END__ + +=head1 MODE + +List deployments. + +=over 8 + +=item B<--filter-name> + +Filter deployment name (can be a regexp). + +=item B<--filter-namespace> + +Filter deployment namespace (can be a regexp). + +=back + +=cut diff --git a/cloud/kubernetes/restapi/mode/listingresses.pm b/cloud/kubernetes/restapi/mode/listingresses.pm new file mode 100644 index 000000000..18b86093f --- /dev/null +++ b/cloud/kubernetes/restapi/mode/listingresses.pm @@ -0,0 +1,128 @@ +# +# Copyright 2019 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::restapi::mode::listingresses; + +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; + + $self->{version} = '1.0'; + $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}->request_api(url_path => '/apis/extensions/v1beta1/ingresses'); + + foreach my $ingress (@{$results->{items}}) { + if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' && + $ingress->{metadata}->{name} !~ /$self->{option_results}->{filter_name}/) { + $self->{output}->output_add(long_msg => "skipping '" . $ingress->{metadata}->{name} . "': no matching filter name.", debug => 1); + next; + } + if (defined($self->{option_results}->{filter_namespace}) && $self->{option_results}->{filter_namespace} ne '' && + $ingress->{metadata}->{namespace} !~ /$self->{option_results}->{filter_namespace}/) { + $self->{output}->output_add(long_msg => "skipping '" . $ingress->{metadata}->{namespace} . "': no matching filter namespace.", debug => 1); + next; + } + + $self->{ingresses}->{$ingress->{metadata}->{uid}} = { + uid => $ingress->{metadata}->{uid}, + name => $ingress->{metadata}->{name}, + namespace => $ingress->{metadata}->{namespace}, + } + } +} + +sub run { + my ($self, %options) = @_; + + $self->manage_selection(%options); + foreach my $ingress (sort keys %{$self->{ingresses}}) { + $self->{output}->output_add(long_msg => sprintf("[uid = %s] [name = %s] [namespace = %s]", + $self->{ingresses}->{$ingress}->{uid}, + $self->{ingresses}->{$ingress}->{name}, + $self->{ingresses}->{$ingress}->{namespace})); + } + + $self->{output}->output_add(severity => 'OK', + short_msg => 'List ingresses:'); + $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 $ingress (sort keys %{$self->{ingresses}}) { + $self->{output}->add_disco_entry( + uid => $self->{ingresses}->{$ingress}->{uid}, + name => $self->{ingresses}->{$ingress}->{name}, + namespace => $self->{ingresses}->{$ingress}->{namespace}, + ); + } +} + +1; + +__END__ + +=head1 MODE + +List ingresses. + +=over 8 + +=item B<--filter-name> + +Filter ingress name (can be a regexp). + +=item B<--filter-namespace> + +Filter ingress namespace (can be a regexp). + +=back + +=cut diff --git a/cloud/kubernetes/restapi/mode/listnamespaces.pm b/cloud/kubernetes/restapi/mode/listnamespaces.pm new file mode 100644 index 000000000..1bb39df9d --- /dev/null +++ b/cloud/kubernetes/restapi/mode/listnamespaces.pm @@ -0,0 +1,115 @@ +# +# Copyright 2019 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::restapi::mode::listnamespaces; + +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; + + $self->{version} = '1.0'; + $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}->request_api(url_path => '/api/v1/namespaces'); + + foreach my $namespace (@{$results->{items}}) { + if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' && + $namespace->{metadata}->{name} !~ /$self->{option_results}->{filter_name}/) { + $self->{output}->output_add(long_msg => "skipping '" . $namespace->{metadata}->{name} . "': no matching filter name.", debug => 1); + next; + } + + $self->{namespaces}->{$namespace->{metadata}->{uid}} = { + uid => $namespace->{metadata}->{uid}, + name => $namespace->{metadata}->{name}, + } + } +} + +sub run { + my ($self, %options) = @_; + + $self->manage_selection(%options); + foreach my $namespace (sort keys %{$self->{namespaces}}) { + $self->{output}->output_add(long_msg => sprintf("[uid = %s] [name = %s]", + $self->{namespaces}->{$namespace}->{uid}, + $self->{namespaces}->{$namespace}->{name})); + } + + $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 => ['uid', 'name']); +} + +sub disco_show { + my ($self, %options) = @_; + + $self->manage_selection(%options); + foreach my $namespace (sort keys %{$self->{namespaces}}) { + $self->{output}->add_disco_entry( + uid => $self->{namespaces}->{$namespace}->{uid}, + name => $self->{namespaces}->{$namespace}->{name}, + ); + } +} + +1; + +__END__ + +=head1 MODE + +List namespaces. + +=over 8 + +=item B<--filter-name> + +Filter namespace name (can be a regexp). + +=back + +=cut diff --git a/cloud/kubernetes/restapi/mode/listnodes.pm b/cloud/kubernetes/restapi/mode/listnodes.pm new file mode 100644 index 000000000..ebeda3a32 --- /dev/null +++ b/cloud/kubernetes/restapi/mode/listnodes.pm @@ -0,0 +1,115 @@ +# +# Copyright 2019 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::restapi::mode::listnodes; + +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; + + $self->{version} = '1.0'; + $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}->request_api(url_path => '/api/v1/nodes'); + + foreach my $node (@{$results->{items}}) { + 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}} = { + uid => $node->{metadata}->{uid}, + name => $node->{metadata}->{name}, + } + } +} + +sub run { + my ($self, %options) = @_; + + $self->manage_selection(%options); + foreach my $node (sort keys %{$self->{nodes}}) { + $self->{output}->output_add(long_msg => sprintf("[uid = %s] [name = %s]", + $self->{nodes}->{$node}->{uid}, + $self->{nodes}->{$node}->{name})); + } + + $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 => ['uid', 'name']); +} + +sub disco_show { + my ($self, %options) = @_; + + $self->manage_selection(%options); + foreach my $node (sort keys %{$self->{nodes}}) { + $self->{output}->add_disco_entry( + uid => $self->{nodes}->{$node}->{uid}, + name => $self->{nodes}->{$node}->{name}, + ); + } +} + +1; + +__END__ + +=head1 MODE + +List nodes. + +=over 8 + +=item B<--filter-name> + +Filter node name (can be a regexp). + +=back + +=cut diff --git a/cloud/kubernetes/restapi/mode/listpods.pm b/cloud/kubernetes/restapi/mode/listpods.pm new file mode 100644 index 000000000..ab74609c8 --- /dev/null +++ b/cloud/kubernetes/restapi/mode/listpods.pm @@ -0,0 +1,137 @@ +# +# Copyright 2019 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::restapi::mode::listpods; + +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; + + $self->{version} = '1.0'; + $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}->request_api(url_path => '/api/v1/pods'); + + foreach my $pod (@{$results->{items}}) { + if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' && + $pod->{metadata}->{name} !~ /$self->{option_results}->{filter_name}/) { + $self->{output}->output_add(long_msg => "skipping '" . $pod->{metadata}->{name} . "': no matching filter name.", debug => 1); + next; + } + if (defined($self->{option_results}->{filter_namespace}) && $self->{option_results}->{filter_namespace} ne '' && + $pod->{metadata}->{namespace} !~ /$self->{option_results}->{filter_namespace}/) { + $self->{output}->output_add(long_msg => "skipping '" . $pod->{metadata}->{namespace} . "': no matching filter namespace.", debug => 1); + next; + } + + $self->{pods}->{$pod->{metadata}->{uid}} = { + uid => $pod->{metadata}->{uid}, + name => $pod->{metadata}->{name}, + namespace => $pod->{metadata}->{namespace}, + node => $pod->{spec}->{nodeName}, + status => $pod->{status}->{phase}, + ip => $pod->{status}->{podIP}, + } + } +} + +sub run { + my ($self, %options) = @_; + + $self->manage_selection(%options); + foreach my $pod (sort keys %{$self->{pods}}) { + $self->{output}->output_add(long_msg => sprintf("[uid = %s] [name = %s] [namespace = %s] [node = %s] [status = %s] [ip = %s]", + $self->{pods}->{$pod}->{uid}, + $self->{pods}->{$pod}->{name}, + $self->{pods}->{$pod}->{namespace}, + $self->{pods}->{$pod}->{node}, + $self->{pods}->{$pod}->{status}, + $self->{pods}->{$pod}->{ip})); + } + + $self->{output}->output_add(severity => 'OK', + short_msg => 'List pods:'); + $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', 'node', 'status', 'ip']); +} + +sub disco_show { + my ($self, %options) = @_; + + $self->manage_selection(%options); + foreach my $pod (sort keys %{$self->{pods}}) { + $self->{output}->add_disco_entry( + uid => $self->{pods}->{$pod}->{uid}, + name => $self->{pods}->{$pod}->{name}, + namespace => $self->{pods}->{$pod}->{namespace}, + namespace => $self->{pods}->{$pod}->{node}, + namespace => $self->{pods}->{$pod}->{status}, + namespace => $self->{pods}->{$pod}->{ip}, + ); + } +} + +1; + +__END__ + +=head1 MODE + +List pods. + +=over 8 + +=item B<--filter-name> + +Filter pod name (can be a regexp). + +=item B<--filter-namespace> + +Filter pod namespace (can be a regexp). + +=back + +=cut diff --git a/cloud/kubernetes/restapi/mode/listreplicasets.pm b/cloud/kubernetes/restapi/mode/listreplicasets.pm new file mode 100644 index 000000000..1647d3849 --- /dev/null +++ b/cloud/kubernetes/restapi/mode/listreplicasets.pm @@ -0,0 +1,128 @@ +# +# Copyright 2019 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::restapi::mode::listreplicasets; + +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; + + $self->{version} = '1.0'; + $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}->request_api(url_path => '/apis/apps/v1/replicasets'); + + foreach my $replicaset (@{$results->{items}}) { + 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}} = { + uid => $replicaset->{metadata}->{uid}, + name => $replicaset->{metadata}->{name}, + namespace => $replicaset->{metadata}->{namespace}, + } + } +} + +sub run { + my ($self, %options) = @_; + + $self->manage_selection(%options); + foreach my $replicaset (sort keys %{$self->{replicasets}}) { + $self->{output}->output_add(long_msg => sprintf("[uid = %s] [name = %s] [namespace = %s]", + $self->{replicasets}->{$replicaset}->{uid}, + $self->{replicasets}->{$replicaset}->{name}, + $self->{replicasets}->{$replicaset}->{namespace})); + } + + $self->{output}->output_add(severity => 'OK', + short_msg => 'List replicasets:'); + $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 $replicaset (sort keys %{$self->{replicasets}}) { + $self->{output}->add_disco_entry( + uid => $self->{replicasets}->{$replicaset}->{uid}, + name => $self->{replicasets}->{$replicaset}->{name}, + namespace => $self->{replicasets}->{$replicaset}->{namespace}, + ); + } +} + +1; + +__END__ + +=head1 MODE + +List replicasets. + +=over 8 + +=item B<--filter-name> + +Filter replicaset name (can be a regexp). + +=item B<--filter-namespace> + +Filter replicaset namespace (can be a regexp). + +=back + +=cut diff --git a/cloud/kubernetes/restapi/mode/listservices.pm b/cloud/kubernetes/restapi/mode/listservices.pm new file mode 100644 index 000000000..9e6828fd7 --- /dev/null +++ b/cloud/kubernetes/restapi/mode/listservices.pm @@ -0,0 +1,128 @@ +# +# Copyright 2019 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::restapi::mode::listservices; + +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; + + $self->{version} = '1.0'; + $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}->request_api(url_path => '/api/v1/services'); + + foreach my $service (@{$results->{items}}) { + if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' && + $service->{metadata}->{name} !~ /$self->{option_results}->{filter_name}/) { + $self->{output}->output_add(long_msg => "skipping '" . $service->{metadata}->{name} . "': no matching filter name.", debug => 1); + next; + } + if (defined($self->{option_results}->{filter_namespace}) && $self->{option_results}->{filter_namespace} ne '' && + $service->{metadata}->{namespace} !~ /$self->{option_results}->{filter_namespace}/) { + $self->{output}->output_add(long_msg => "skipping '" . $service->{metadata}->{namespace} . "': no matching filter namespace.", debug => 1); + next; + } + + $self->{services}->{$service->{metadata}->{uid}} = { + uid => $service->{metadata}->{uid}, + name => $service->{metadata}->{name}, + namespace => $service->{metadata}->{namespace}, + } + } +} + +sub run { + my ($self, %options) = @_; + + $self->manage_selection(%options); + foreach my $service (sort keys %{$self->{services}}) { + $self->{output}->output_add(long_msg => sprintf("[uid = %s] [name = %s] [namespace = %s]", + $self->{services}->{$service}->{uid}, + $self->{services}->{$service}->{name}, + $self->{services}->{$service}->{namespace})); + } + + $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 => ['uid', 'name', 'namespace']); +} + +sub disco_show { + my ($self, %options) = @_; + + $self->manage_selection(%options); + foreach my $service (sort keys %{$self->{services}}) { + $self->{output}->add_disco_entry( + uid => $self->{services}->{$service}->{uid}, + name => $self->{services}->{$service}->{name}, + namespace => $self->{services}->{$service}->{namespace}, + ); + } +} + +1; + +__END__ + +=head1 MODE + +List services. + +=over 8 + +=item B<--filter-name> + +Filter service name (can be a regexp). + +=item B<--filter-namespace> + +Filter service namespace (can be a regexp). + +=back + +=cut diff --git a/cloud/kubernetes/restapi/mode/liststatefulsets.pm b/cloud/kubernetes/restapi/mode/liststatefulsets.pm new file mode 100644 index 000000000..792b1c68a --- /dev/null +++ b/cloud/kubernetes/restapi/mode/liststatefulsets.pm @@ -0,0 +1,128 @@ +# +# Copyright 2019 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::restapi::mode::liststatefulsets; + +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; + + $self->{version} = '1.0'; + $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}->request_api(url_path => '/apis/apps/v1/statefulsets'); + + foreach my $statefulset (@{$results->{items}}) { + 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}} = { + uid => $statefulset->{metadata}->{uid}, + name => $statefulset->{metadata}->{name}, + namespace => $statefulset->{metadata}->{namespace}, + } + } +} + +sub run { + my ($self, %options) = @_; + + $self->manage_selection(%options); + foreach my $statefulset (sort keys %{$self->{statefulsets}}) { + $self->{output}->output_add(long_msg => sprintf("[uid = %s] [name = %s] [namespace = %s]", + $self->{statefulsets}->{$statefulset}->{uid}, + $self->{statefulsets}->{$statefulset}->{name}, + $self->{statefulsets}->{$statefulset}->{namespace})); + } + + $self->{output}->output_add(severity => 'OK', + short_msg => 'List statefulsets:'); + $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 $statefulset (sort keys %{$self->{statefulsets}}) { + $self->{output}->add_disco_entry( + uid => $self->{statefulsets}->{$statefulset}->{uid}, + name => $self->{statefulsets}->{$statefulset}->{name}, + namespace => $self->{statefulsets}->{$statefulset}->{namespace}, + ); + } +} + +1; + +__END__ + +=head1 MODE + +List statefulsets. + +=over 8 + +=item B<--filter-name> + +Filter statefulset name (can be a regexp). + +=item B<--filter-namespace> + +Filter statefulset namespace (can be a regexp). + +=back + +=cut diff --git a/cloud/kubernetes/restapi/mode/podstatus.pm b/cloud/kubernetes/restapi/mode/podstatus.pm new file mode 100644 index 000000000..3cd27816c --- /dev/null +++ b/cloud/kubernetes/restapi/mode/podstatus.pm @@ -0,0 +1,323 @@ +# +# Copyright 2019 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::restapi::mode::podstatus; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; +use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold); + +my $instance_mode; + +sub custom_pod_status_output { + my ($self, %options) = @_; + + return sprintf("Status is '%s'", + $self->{result_values}->{status}); +} + +sub custom_pod_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'}; + + return 0; +} + +sub custom_container_status_output { + my ($self, %options) = @_; + + return sprintf("Status is '%s', State is '%s'", + $self->{result_values}->{status}, + $self->{result_values}->{state}); +} + +sub custom_container_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}->{state} = ($options{new_datas}->{$self->{instance} . '_state'} == 1) ? "ready" : "not ready"; + + return 0; +} + +sub custom_ready_perfdata { + my ($self, %options) = @_; + + my $value_perf = $self->{result_values}->{ready}; + my $extra_label = ''; + $extra_label = '_' . $self->{result_values}->{display} if (!defined($options{extra_instance}) || $options{extra_instance} != 0); + my %total_options = (); + if ($self->{result_values}->{total} > 0 && $instance_mode->{option_results}->{units} eq '%') { + $total_options{total} = $self->{result_values}->{total}; + $total_options{cast_int} = 1; + } + + $self->{output}->perfdata_add(label => 'containers_ready' . $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 => $total_options{total}); +} + +sub custom_ready_threshold { + my ($self, %options) = @_; + + my ($exit, $threshold_value); + $threshold_value = $self->{result_values}->{ready}; + if ($instance_mode->{option_results}->{units} eq '%') { + $threshold_value = $self->{result_values}->{prct_ready}; + } + $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_ready_output { + my ($self, %options) = @_; + + my $msg = sprintf("Containers Ready: %s/%s (%.2f%%)", + $self->{result_values}->{ready}, + $self->{result_values}->{total}, + $self->{result_values}->{prct_ready}); + + return $msg; +} + +sub custom_ready_calc { + my ($self, %options) = @_; + + $self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_display'}; + $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); + + $self->{result_values}->{prct_ready} = $self->{result_values}->{ready} * 100 / $self->{result_values}->{total}; + + return 0; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'pods', type => 3, cb_prefix_output => 'prefix_pod_output', cb_long_output => 'long_output', + message_multiple => 'All pods status are ok', indent_long_output => ' ', + group => [ + { name => 'global', type => 0, skipped_code => { -10 => 1 } }, + { name => 'containers', display_long => 1, cb_prefix_output => 'prefix_container_output', + message_multiple => 'All containers status are ok', type => 1, skipped_code => { -10 => 1 } }, + ] + } + ]; + + $self->{maps_counters}->{global} = [ + { label => 'containers-ready', set => { + key_values => [ { name => 'containers_total' }, { name => 'containers_ready' }, { name => 'display' } ], + closure_custom_calc => $self->can('custom_ready_calc'), + closure_custom_output => $self->can('custom_ready_output'), + closure_custom_perfdata => $self->can('custom_ready_perfdata'), + closure_custom_threshold_check => $self->can('custom_ready_threshold'), + } + }, + { label => 'pod-status', set => { + key_values => [ { name => 'status' } ], + closure_custom_calc => $self->can('custom_pod_status_calc'), + closure_custom_output => $self->can('custom_pod_status_output'), + closure_custom_perfdata => sub { return 0; }, + closure_custom_threshold_check => \&catalog_status_threshold, + } + }, + { label => 'total-restarts-count', set => { + key_values => [ { name => 'restarts_total' }, { name => 'display' } ], + output_template => 'Restarts: %d', + perfdatas => [ + { label => 'restarts_count', value => 'restarts_total_absolute', template => '%d', + min => 0, label_extra_instance => 1, instance_use => 'display_absolute' }, + ], + } + }, + ]; + $self->{maps_counters}->{containers} = [ + { label => 'container-status', set => { + key_values => [ { name => 'status' }, { name => 'state' } ], + closure_custom_calc => $self->can('custom_container_status_calc'), + closure_custom_output => $self->can('custom_container_status_output'), + closure_custom_perfdata => sub { return 0; }, + closure_custom_threshold_check => \&catalog_status_threshold, + } + }, + { label => 'restarts-count', set => { + key_values => [ { name => 'restarts' }, { name => 'perf' } ], + output_template => 'Restarts: %d', + perfdatas => [ + { label => 'restarts_count', value => 'restarts_absolute', template => '%d', + min => 0, label_extra_instance => 1, instance_use => 'perf_absolute' }, + ], + } + }, + ]; +} + +sub prefix_pod_output { + my ($self, %options) = @_; + + return "Pod '" . $options{instance_value}->{display} . "' "; +} + +sub prefix_container_output { + my ($self, %options) = @_; + + return "Container '" . $options{instance_value}->{display} . "' "; +} + +sub long_output { + my ($self, %options) = @_; + + return "Checking pod '" . $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 => { + "filter-name:s" => { name => 'filter_name' }, + "filter-namespace:s" => { name => 'filter_namespace' }, + "warning-pod-status:s" => { name => 'warning_pod_status', default => '' }, + "critical-pod-status:s" => { name => 'critical_pod_status', default => '%{status} !~ /running/i' }, + "warning-container-status:s" => { name => 'warning_container_status', default => '' }, + "critical-container-status:s" => { name => 'critical_container_status', default => '%{status} !~ /running/i || %{state} !~ /^ready$/' }, + "units:s" => { name => 'units', default => '%' }, + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + $self->change_macros(macros => ['warning_pod_status', 'critical_pod_status', + 'warning_container_status', 'critical_container_status']); + + $instance_mode = $self; +} + +sub manage_selection { + my ($self, %options) = @_; + + $self->{pods} = {}; + + my $results = $options{custom}->request_api(url_path => '/api/v1/pods'); + + foreach my $pod (@{$results->{items}}) { + if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' && + $pod->{metadata}->{name} !~ /$self->{option_results}->{filter_name}/) { + $self->{output}->output_add(long_msg => "skipping '" . $pod->{metadata}->{name} . "': no matching filter name.", debug => 1); + next; + } + if (defined($self->{option_results}->{filter_namespace}) && $self->{option_results}->{filter_namespace} ne '' && + $pod->{metadata}->{namespace} !~ /$self->{option_results}->{filter_namespace}/) { + $self->{output}->output_add(long_msg => "skipping '" . $pod->{metadata}->{namespace} . "': no matching filter namespace.", debug => 1); + next; + } + + $self->{pods}->{$pod->{metadata}->{uid}}->{display} = $pod->{metadata}->{name}; + $self->{pods}->{$pod->{metadata}->{uid}}->{global} = { + display => $pod->{metadata}->{name}, + status => $pod->{status}->{phase}, + containers_total => scalar(@{$pod->{status}->{containerStatuses}}), + containers_ready => 0, + restarts_total => 0, + }; + + foreach my $container (@{$pod->{status}->{containerStatuses}}) { + $self->{pods}->{$pod->{metadata}->{uid}}->{containers}->{$container->{name}} = { + display => $container->{name}, + status => keys %{$container->{state}}, + state => $container->{ready}, + restarts => $container->{restartCount}, + perf => $pod->{metadata}->{name} . '_' . $container->{name}, + }; + $self->{pods}->{$pod->{metadata}->{uid}}->{global}->{containers_ready}++ if ($container->{ready}); + $self->{pods}->{$pod->{metadata}->{uid}}->{global}->{restarts_total} += $container->{restartCount}; + } + } + + if (scalar(keys %{$self->{pods}}) <= 0) { + $self->{output}->add_option_msg(short_msg => "No pods found."); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check pod status. + +=over 8 + +=item B<--warning-pod-status> + +Set warning threshold for status (Default: ''). +Can used special variables like: %{status}, %{display} + +=item B<--critical-pod-status> + +Set critical threshold for status (Default: '%{status} !~ /running/i'). +Can used special variables like: %{status}, %{display} + +=item B<--warning-container-status> + +Set warning threshold for status (Default: ''). +Can used special variables like: %{status}, %{display} + +=item B<--critical-container-status> + +Set critical threshold for status (Default: '%{status} !~ /running/i || %{state} !~ /^ready$/'). +Can used special variables like: %{status}, %{state}, %{display} + +=item B<--warning-*> + +Threshold warning. +Can be: 'containers-ready', 'total-restarts-count' (count), 'restarts-count' (count). + +=item B<--critical-*> + +Threshold critical. +Can be: 'containers-ready', 'total-restarts-count' (count), 'restarts-count' (count). + +=item B<--units> + +Units of thresholds (Default: '%') ('%', 'count'). + +=back + +=cut diff --git a/cloud/kubernetes/restapi/plugin.pm b/cloud/kubernetes/restapi/plugin.pm new file mode 100644 index 000000000..b48e58861 --- /dev/null +++ b/cloud/kubernetes/restapi/plugin.pm @@ -0,0 +1,66 @@ +# +# Copyright 2019 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::restapi::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} = '1.0'; + %{$self->{modes}} = ( + 'daemonset-status' => 'cloud::kubernetes::restapi::mode::daemonsetstatus', + 'deployment-status' => 'cloud::kubernetes::restapi::mode::deploymentstatus', + 'list-daemonsets' => 'cloud::kubernetes::restapi::mode::listdaemonsets', + 'list-deployments' => 'cloud::kubernetes::restapi::mode::listdeployments', + 'list-ingresses' => 'cloud::kubernetes::restapi::mode::listingresses', + 'list-namespaces' => 'cloud::kubernetes::restapi::mode::listnamespaces', + 'list-nodes' => 'cloud::kubernetes::restapi::mode::listnodes', + 'list-pods' => 'cloud::kubernetes::restapi::mode::listpods', + 'list-replicasets' => 'cloud::kubernetes::restapi::mode::listreplicasets', + 'list-services' => 'cloud::kubernetes::restapi::mode::listservices', + 'list-statefulsets' => 'cloud::kubernetes::restapi::mode::liststatefulsets', + 'pod-status' => 'cloud::kubernetes::restapi::mode::podstatus', + ); + + $self->{custom_modes}{api} = 'cloud::kubernetes::restapi::custom::api'; + return $self; +} + +sub init { + my ( $self, %options ) = @_; + + $self->SUPER::init(%options); +} + +1; + +__END__ + +=head1 PLUGIN DESCRIPTION + +Check Kubernetes cluster using API. + +=cut