add kubernetes nodes usage, add kubectl custom mode

This commit is contained in:
Colin Gagnaire 2019-04-01 23:01:49 +02:00
parent b1a4daadbb
commit 6db0612269
16 changed files with 615 additions and 86 deletions

View File

@ -18,7 +18,7 @@
# limitations under the License.
#
package cloud::kubernetes::restapi::custom::api;
package cloud::kubernetes::custom::api;
use strict;
use warnings;
@ -44,11 +44,11 @@ sub new {
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' },
"timeout:s" => { name => 'timeout' },
"config-file:s" => { name => 'config_file' },
});
}
$options{options}->add_help(package => __PACKAGE__, sections => 'REST API OPTIONS', once => 1);
@ -88,7 +88,6 @@ 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->{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} : '';
@ -111,7 +110,6 @@ sub build_options_for_httplib {
$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} = '';
@ -122,66 +120,38 @@ sub settings {
$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});
if (defined($self->{token})) {
$self->{http}->add_header(key => 'Authorization', value => 'Bearer ' . $self->{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});
$self->{output}->output_add(long_msg => "URL: '" . $self->{proto} . '://' . $self->{hostname} .
':' . $self->{port} . $options{url_path} . "'", debug => 1);
my $response = $self->{http}->request(url_path => $options{url_path});
if ($self->{http}->get_code() != 200) {
my $decoded;
eval {
$decoded = JSON::XS->new->utf8->decode($content);
$decoded = JSON::XS->new->utf8->decode($response);
};
if ($@) {
$self->{output}->output_add(long_msg => $content, debug => 1);
$self->{output}->add_option_msg(short_msg => "Cannot decode json response: $@");
$self->{output}->output_add(long_msg => $response, debug => 1);
$self->{output}->add_option_msg(short_msg => "Cannot decode json response: $response");
$self->{output}->option_exit();
}
if (defined($decoded->{code})) {
$self->{output}->output_add(long_msg => "Error message : " . $decoded->{message}, debug => 1);
$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}->output_add(long_msg => "Error message: " . $decoded, debug => 1);
$self->{output}->add_option_msg(short_msg => "API return error code '" . $self->{http}->get_code() . "' (add --debug option for detailed message)");
$self->{output}->option_exit();
}
@ -189,16 +159,89 @@ sub request_api {
my $decoded;
eval {
$decoded = JSON::XS->new->utf8->decode($content);
$decoded = JSON::XS->new->utf8->decode($response);
};
if ($@) {
$self->{output}->add_option_msg(short_msg => "Cannot decode json response: $@");
$self->{output}->output_add(long_msg => $response, debug => 1);
$self->{output}->add_option_msg(short_msg => "Cannot decode json response: $response");
$self->{output}->option_exit();
}
return $decoded;
}
sub kubernetes_list_daemonsets {
my ($self, %options) = @_;
my $response = $self->request_api(method => 'GET', url_path => '/apis/apps/v1/daemonsets');
return $response;
}
sub kubernetes_list_deployments {
my ($self, %options) = @_;
my $response = $self->request_api(method => 'GET', url_path => '/apis/apps/v1/deployments');
return $response;
}
sub kubernetes_list_ingresses {
my ($self, %options) = @_;
my $response = $self->request_api(method => 'GET', url_path => '/apis/extensions/v1beta1/ingresses');
return $response;
}
sub kubernetes_list_namespaces {
my ($self, %options) = @_;
my $response = $self->request_api(method => 'GET', url_path => '/api/v1/namespaces');
return $response;
}
sub kubernetes_list_nodes {
my ($self, %options) = @_;
my $response = $self->request_api(method => 'GET', url_path => '/api/v1/nodes');
return $response;
}
sub kubernetes_list_replicasets {
my ($self, %options) = @_;
my $response = $self->request_api(method => 'GET', url_path => '/apis/apps/v1/replicasets');
return $response;
}
sub kubernetes_list_services {
my ($self, %options) = @_;
my $response = $self->request_api(method => 'GET', url_path => '/apis/v1/services');
return $response;
}
sub kubernetes_list_statefulsets {
my ($self, %options) = @_;
my $response = $self->request_api(method => 'GET', url_path => '/apis/apps/v1/statefulsets');
return $response;
}
sub kubernetes_list_pods {
my ($self, %options) = @_;
my $response = $self->request_api(method => 'GET', url_path => '/api/v1/pods');
return $response;
}
1;
__END__

View File

@ -0,0 +1,255 @@
#
# 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::custom::kubectl;
use strict;
use warnings;
use DateTime;
use JSON::XS;
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' },
"port:s" => { name => 'port' },
"proto:s" => { name => 'proto' },
"token:s" => { name => 'token' },
"timeout:s" => { name => 'timeout', default => 10 },
"config-file:s" => { name => 'config_file' },
"sudo" => { name => 'sudo' },
"command:s" => { name => 'command', default => 'kubectl' },
"command-path:s" => { name => 'command_path' },
"command-options:s" => { name => 'command_options', default => '' },
});
}
$options{options}->add_help(package => __PACKAGE__, sections => 'CLI OPTIONS', once => 1);
$self->{output} = $options{output};
$self->{mode} = $options{mode};
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->{config_file} = (defined($self->{option_results}->{config_file})) ? $self->{option_results}->{config_file} : '';
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();
}
return 0;
}
sub execute {
my ($self, %options) = @_;
$self->{output}->output_add(long_msg => "Command line: '" . $self->{option_results}->{command} . " " . $options{cmd_options} . "'", debug => 1);
my ($response, $exit_code) = centreon::plugins::misc::execute(
output => $self->{output},
options => $self->{option_results},
sudo => $self->{option_results}->{sudo},
command => $self->{option_results}->{command},
command_path => $self->{option_results}->{command_path},
command_options => $options{cmd_options},
no_quit => 1
);
if ($exit_code != 0) {
$self->{output}->output_add(long_msg => "Error message: " . $response, debug => 1);
$self->{output}->add_option_msg(short_msg => "CLI return error code '" . $exit_code . "' (add --debug option for detailed message)");
$self->{output}->option_exit();
}
my $decoded;
eval {
$decoded = JSON::XS->new->utf8->decode($response);
};
if ($@) {
$self->{output}->output_add(long_msg => $response, debug => 1);
$self->{output}->add_option_msg(short_msg => "Cannot decode response (add --debug option to display returned content)");
$self->{output}->option_exit();
}
return $decoded;
}
sub kubernetes_list_daemonsets {
my ($self, %options) = @_;
my $response = $self->execute(cmd_options => 'get daemonsets --all-namespaces --output=json');
return $response;
}
sub kubernetes_list_deployments {
my ($self, %options) = @_;
my $response = $self->execute(cmd_options => 'get deployments --all-namespaces --output=json');
return $response;
}
sub kubernetes_list_ingresses {
my ($self, %options) = @_;
my $response = $self->execute(cmd_options => 'get ingresses --all-namespaces --output=json');
return $response;
}
sub kubernetes_list_namespaces {
my ($self, %options) = @_;
my $response = $self->execute(cmd_options => 'get namespaces --all-namespaces --output=json');
return $response;
}
sub kubernetes_list_nodes {
my ($self, %options) = @_;
my $response = $self->execute(cmd_options => 'get nodes --all-namespaces --output=json');
return $response;
}
sub kubernetes_list_replicasets {
my ($self, %options) = @_;
my $response = $self->execute(cmd_options => 'get replicasets --all-namespaces --output=json');
return $response;
}
sub kubernetes_list_services {
my ($self, %options) = @_;
my $response = $self->execute(cmd_options => 'get services --all-namespaces --output=json');
return $response;
}
sub kubernetes_list_statefulsets {
my ($self, %options) = @_;
my $response = $self->execute(cmd_options => 'get statefulsets --all-namespaces --output=json');
return $response;
}
sub kubernetes_list_pods {
my ($self, %options) = @_;
my $response = $self->execute(cmd_options => 'get pods --all-namespaces --output=json');
return $response;
}
1;
__END__
=head1 NAME
Kubernetes CLI (kubectl)
=head1 SYNOPSIS
Kubernetes CLI (kubectl) custom mode
=head1 CLI OPTIONS
Kubernetes CLI (kubectl)
=over 8
=item B<--config-file>
Kubernetes configuration file path
(Example: --config-file='/root/.kube/config').
=item B<--timeout>
Set timeout in seconds (Default: 10).
=item B<--sudo>
Use 'sudo' to execute the command.
=item B<--command>
Command to get information (Default: 'kubectl').
Can be changed if you have output in a file.
=item B<--command-path>
Command path (Default: none).
=item B<--command-options>
Command options (Default: none).
=back
=head1 DESCRIPTION
B<custom>.
=cut

View File

@ -18,7 +18,7 @@
# limitations under the License.
#
package cloud::kubernetes::restapi::mode::daemonsetstatus;
package cloud::kubernetes::mode::daemonsetstatus;
use base qw(centreon::plugins::templates::counter);
@ -129,7 +129,7 @@ sub manage_selection {
$self->{daemonsets} = {};
my $results = $options{custom}->request_api(url_path => '/apis/apps/v1/daemonsets');
my $results = $options{custom}->kubernetes_list_daemonsets();
foreach my $daemonset (@{$results->{items}}) {
if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' &&

View File

@ -18,7 +18,7 @@
# limitations under the License.
#
package cloud::kubernetes::restapi::mode::deploymentstatus;
package cloud::kubernetes::mode::deploymentstatus;
use base qw(centreon::plugins::templates::counter);
@ -125,7 +125,7 @@ sub manage_selection {
$self->{deployments} = {};
my $results = $options{custom}->request_api(url_path => '/apis/apps/v1/deployments');
my $results = $options{custom}->kubernetes_list_deployments();
foreach my $deployment (@{$results->{items}}) {
if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' &&

View File

@ -18,7 +18,7 @@
# limitations under the License.
#
package cloud::kubernetes::restapi::mode::listdaemonsets;
package cloud::kubernetes::mode::listdaemonsets;
use base qw(centreon::plugins::templates::counter);
@ -47,7 +47,7 @@ sub check_options {
sub manage_selection {
my ($self, %options) = @_;
my $results = $options{custom}->request_api(url_path => '/apis/apps/v1/daemonsets');
my $results = $options{custom}->kubernetes_list_daemonsets();
foreach my $daemonset (@{$results->{items}}) {
if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' &&

View File

@ -18,7 +18,7 @@
# limitations under the License.
#
package cloud::kubernetes::restapi::mode::listdeployments;
package cloud::kubernetes::mode::listdeployments;
use base qw(centreon::plugins::templates::counter);
@ -47,7 +47,7 @@ sub check_options {
sub manage_selection {
my ($self, %options) = @_;
my $results = $options{custom}->request_api(url_path => '/apis/apps/v1/deployments');
my $results = $options{custom}->kubernetes_list_deployments();
foreach my $deployment (@{$results->{items}}) {
if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' &&

View File

@ -18,7 +18,7 @@
# limitations under the License.
#
package cloud::kubernetes::restapi::mode::listingresses;
package cloud::kubernetes::mode::listingresses;
use base qw(centreon::plugins::templates::counter);
@ -47,7 +47,7 @@ sub check_options {
sub manage_selection {
my ($self, %options) = @_;
my $results = $options{custom}->request_api(url_path => '/apis/extensions/v1beta1/ingresses');
my $results = $options{custom}->kubernetes_list_ingresses();
foreach my $ingress (@{$results->{items}}) {
if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' &&

View File

@ -18,7 +18,7 @@
# limitations under the License.
#
package cloud::kubernetes::restapi::mode::listnamespaces;
package cloud::kubernetes::mode::listnamespaces;
use base qw(centreon::plugins::templates::counter);
@ -46,7 +46,7 @@ sub check_options {
sub manage_selection {
my ($self, %options) = @_;
my $results = $options{custom}->request_api(url_path => '/api/v1/namespaces');
my $results = $options{custom}->kubernetes_list_namespaces();
foreach my $namespace (@{$results->{items}}) {
if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' &&

View File

@ -18,7 +18,7 @@
# limitations under the License.
#
package cloud::kubernetes::restapi::mode::listnodes;
package cloud::kubernetes::mode::listnodes;
use base qw(centreon::plugins::templates::counter);
@ -46,7 +46,7 @@ sub check_options {
sub manage_selection {
my ($self, %options) = @_;
my $results = $options{custom}->request_api(url_path => '/api/v1/nodes');
my $results = $options{custom}->kubernetes_list_nodes();
foreach my $node (@{$results->{items}}) {
if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' &&

View File

@ -18,7 +18,7 @@
# limitations under the License.
#
package cloud::kubernetes::restapi::mode::listpods;
package cloud::kubernetes::mode::listpods;
use base qw(centreon::plugins::templates::counter);
@ -47,7 +47,7 @@ sub check_options {
sub manage_selection {
my ($self, %options) = @_;
my $results = $options{custom}->request_api(url_path => '/api/v1/pods');
my $results = $options{custom}->kubernetes_list_pods();
foreach my $pod (@{$results->{items}}) {
if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' &&

View File

@ -18,7 +18,7 @@
# limitations under the License.
#
package cloud::kubernetes::restapi::mode::listreplicasets;
package cloud::kubernetes::mode::listreplicasets;
use base qw(centreon::plugins::templates::counter);
@ -47,7 +47,7 @@ sub check_options {
sub manage_selection {
my ($self, %options) = @_;
my $results = $options{custom}->request_api(url_path => '/apis/apps/v1/replicasets');
my $results = $options{custom}->kubernetes_list_replicasets();
foreach my $replicaset (@{$results->{items}}) {
if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' &&

View File

@ -18,7 +18,7 @@
# limitations under the License.
#
package cloud::kubernetes::restapi::mode::listservices;
package cloud::kubernetes::mode::listservices;
use base qw(centreon::plugins::templates::counter);
@ -47,7 +47,7 @@ sub check_options {
sub manage_selection {
my ($self, %options) = @_;
my $results = $options{custom}->request_api(url_path => '/api/v1/services');
my $results = $options{custom}->kubernetes_list_services();
foreach my $service (@{$results->{items}}) {
if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' &&

View File

@ -18,7 +18,7 @@
# limitations under the License.
#
package cloud::kubernetes::restapi::mode::liststatefulsets;
package cloud::kubernetes::mode::liststatefulsets;
use base qw(centreon::plugins::templates::counter);
@ -47,7 +47,7 @@ sub check_options {
sub manage_selection {
my ($self, %options) = @_;
my $results = $options{custom}->request_api(url_path => '/apis/apps/v1/statefulsets');
my $results = $options{custom}->kubernetes_list_statefulsets();
foreach my $statefulset (@{$results->{items}}) {
if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' &&

View File

@ -0,0 +1,199 @@
#
# 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::mode::nodeusage;
use base qw(centreon::plugins::templates::counter);
use strict;
use warnings;
use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold);
sub custom_usage_perfdata {
my ($self, %options) = @_;
my $label = 'allocated_pods';
my $value_perf = $self->{result_values}->{allocated};
my $extra_label = '';
$extra_label = '_' . $self->{result_values}->{display} if (!defined($options{extra_instance}) || $options{extra_instance} != 0);
my %total_options = ();
if ($self->{instance_mode}->{option_results}->{units} eq '%') {
$total_options{total} = $self->{result_values}->{allocatable};
$total_options{cast_int} = 1;
}
$self->{output}->perfdata_add(
label => $label . $extra_label,
value => $value_perf,
warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{label}, %total_options),
critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{label}, %total_options),
min => 0, max => $self->{result_values}->{allocatable}
);
}
sub custom_usage_threshold {
my ($self, %options) = @_;
my ($exit, $threshold_value);
$threshold_value = $self->{result_values}->{allocated};
if ($self->{instance_mode}->{option_results}->{units} eq '%') {
$threshold_value = $self->{result_values}->{prct_allocated};
}
$exit = $self->{perfdata}->threshold_check(
value => $threshold_value, threshold => [ { label => 'critical-' . $self->{label}, exit_litteral => 'critical' },
{ label => 'warning-'. $self->{label}, exit_litteral => 'warning' } ]
);
return $exit;
}
sub custom_usage_output {
my ($self, %options) = @_;
my $msg = sprintf("Pods Capacity: %s, Allocatable: %s, Allocated: %s (%.2f%%)",
$self->{result_values}->{capacity},
$self->{result_values}->{allocatable},
$self->{result_values}->{allocated},
$self->{result_values}->{prct_allocated});
return $msg;
}
sub custom_usage_calc {
my ($self, %options) = @_;
$self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_display'};
$self->{result_values}->{capacity} = $options{new_datas}->{$self->{instance} . '_capacity'};
$self->{result_values}->{allocatable} = $options{new_datas}->{$self->{instance} . '_allocatable'};
$self->{result_values}->{allocated} = $options{new_datas}->{$self->{instance} . '_allocated'};
$self->{result_values}->{prct_allocated} = ($self->{result_values}->{allocatable} > 0) ? $self->{result_values}->{allocated} * 100 / $self->{result_values}->{allocatable} : 0;
return 0;
}
sub set_counters {
my ($self, %options) = @_;
$self->{maps_counters_type} = [
{ name => 'nodes', type => 1, cb_prefix_output => 'prefix_node_output',
message_multiple => 'All nodes usage are ok', skipped_code => { -11 => 1 } },
];
$self->{maps_counters}->{nodes} = [
{ label => 'allocated-pods', set => {
key_values => [ { name => 'capacity' }, { name => 'allocatable' }, { name => 'allocated' },
{ name => 'display' } ],
closure_custom_calc => $self->can('custom_usage_calc'),
closure_custom_output => $self->can('custom_usage_output'),
closure_custom_perfdata => $self->can('custom_usage_perfdata'),
closure_custom_threshold_check => $self->can('custom_usage_threshold'),
}
},
];
}
sub prefix_node_output {
my ($self, %options) = @_;
return "Node '" . $options{instance_value}->{display} . "' ";
}
sub new {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options);
bless $self, $class;
$self->{version} = '1.0';
$options{options}->add_options(arguments => {
"filter-name:s" => { name => 'filter_name' },
"units:s" => { name => 'units', 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->{nodes} = {};
my $nodes = $options{custom}->kubernetes_list_nodes();
foreach my $node (@{$nodes->{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}->{name}} = {
display => $node->{metadata}->{name},
capacity => $node->{status}->{capacity}->{pods},
allocatable => $node->{status}->{allocatable}->{pods},
}
}
if (scalar(keys %{$self->{nodes}}) <= 0) {
$self->{output}->add_option_msg(short_msg => "No nodes found.");
$self->{output}->option_exit();
}
my $pods = $options{custom}->kubernetes_list_pods();
foreach my $pod (@{$pods->{items}}) {
next if (defined($pod->{spec}->{nodeName}) && !defined($self->{nodes}->{$pod->{spec}->{nodeName}}));
$self->{nodes}->{$pod->{spec}->{nodeName}}->{allocated}++;
}
}
1;
__END__
=head1 MODE
Check node usage.
=over 8
=item B<--filter-name>
Filter node name (can be a regexp).
=item B<--warning-allocated-pods>
Threshold warning for pods allocation.
=item B<--critical-allocated-pods>
Threshold critical for pods allocation.
=item B<--units>
Units of thresholds (Default: '%') (Can be '%' or absolute).
=back
=cut

View File

@ -18,7 +18,7 @@
# limitations under the License.
#
package cloud::kubernetes::restapi::mode::podstatus;
package cloud::kubernetes::mode::podstatus;
use base qw(centreon::plugins::templates::counter);
@ -205,6 +205,7 @@ sub new {
$options{options}->add_options(arguments => {
"filter-name:s" => { name => 'filter_name' },
"filter-namespace:s" => { name => 'filter_namespace' },
"extra-filter:s@" => { name => 'extra_filter' },
"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 => '' },
@ -218,7 +219,13 @@ sub new {
sub check_options {
my ($self, %options) = @_;
$self->SUPER::check_options(%options);
$self->{extra_filter} = {};
foreach my $filter (@{$self->{option_results}->{extra_filter}}) {
next if ($filter !~ /(.*)=(.*)/);
$self->{extra_filter}->{$1} = $2;
}
$self->change_macros(macros => ['warning_pod_status', 'critical_pod_status',
'warning_container_status', 'critical_container_status']);
}
@ -228,7 +235,7 @@ sub manage_selection {
$self->{pods} = {};
my $results = $options{custom}->request_api(url_path => '/api/v1/pods');
my $results = $options{custom}->kubernetes_list_pods();
foreach my $pod (@{$results->{items}}) {
if (defined($self->{option_results}->{filter_name}) && $self->{option_results}->{filter_name} ne '' &&
@ -238,9 +245,18 @@ sub manage_selection {
}
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);
$self->{output}->output_add(long_msg => "skipping '" . $pod->{metadata}->{name} . "': no matching filter namespace.", debug => 1);
next;
}
my $next = 0;
foreach my $label (keys %{$self->{extra_filter}}) {
if (!defined($pod->{metadata}->{labels}->{$label}) || $pod->{metadata}->{labels}->{$label} !~ /$self->{extra_filter}->{$label}/) {
$self->{output}->output_add(long_msg => "skipping '" . $pod->{metadata}->{name} . "': no matching extra filter.", debug => 1);
$next = 1;
last;
}
}
next if ($next == 1);
$self->{pods}->{$pod->{metadata}->{uid}}->{display} = $pod->{metadata}->{name};
$self->{pods}->{$pod->{metadata}->{uid}}->{global} = {
@ -280,6 +296,20 @@ Check pod status.
=over 8
=item B<--filter-name>
Filter pod name (can be a regexp).
=item B<--filter-namespace>
Filter pod namespace (can be a regexp).
=item B<--extra-filter>
Add an extra filter based on labels (Can be multiple)
Example : --extra-filter='app=mynewapp'
=item B<--warning-pod-status>
Set warning threshold for status (Default: '').

View File

@ -18,7 +18,7 @@
# limitations under the License.
#
package cloud::kubernetes::restapi::plugin;
package cloud::kubernetes::plugin;
use strict;
use warnings;
@ -31,21 +31,23 @@ sub new {
$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',
'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',
'node-usage' => 'cloud::kubernetes::mode::nodeusage',
'pod-status' => 'cloud::kubernetes::mode::podstatus',
);
$self->{custom_modes}{api} = 'cloud::kubernetes::restapi::custom::api';
$self->{custom_modes}{api} = 'cloud::kubernetes::custom::api';
$self->{custom_modes}{kubectl} = 'cloud::kubernetes::custom::kubectl';
return $self;
}
@ -61,6 +63,6 @@ __END__
=head1 PLUGIN DESCRIPTION
Check Kubernetes cluster using API.
Check Kubernetes cluster using CLI (kubectl) or RestAPI.
=cut