diff --git a/centreon-plugins/apps/java/jvm/actuator/mode/classcount.pm b/centreon-plugins/apps/java/jvm/actuator/mode/classcount.pm new file mode 100644 index 000000000..ba5e34a19 --- /dev/null +++ b/centreon-plugins/apps/java/jvm/actuator/mode/classcount.pm @@ -0,0 +1,109 @@ +# +# Copyright 2021 Centreon (http://www.centreon.com/) +# +# Centreon is a full-fledged industry-strength solution that meets +# the needs in IT infrastructure and application monitoring for +# service performance. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +package apps::java::jvm::actuator::mode::classcount; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; +use Digest::MD5 qw(md5_hex); + +sub prefix_global_output { + my ($self, %options) = @_; + + return 'Class '; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'global', type => 0, cb_prefix_output => 'prefix_global_output', skipped_code => { -10 => 1 } } + ]; + + $self->{maps_counters}->{global} = [ + { label => 'current', nlabel => 'class.loaded.current.count', set => { + key_values => [ { name => 'current' } ], + output_template => 'current: %d', + perfdatas => [ + { template => '%d', min => 0 } + ] + } + }, + { label => 'unloaded', nlabel => 'class.unloaded.count', set => { + key_values => [ { name => 'unloaded', diff => 1 } ], + output_template => 'unloaded: %d', + perfdatas => [ + { template => '%d', min => 0 } + ] + } + } + ]; +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options, statefile => 1, force_new_perfdata => 1); + bless $self, $class; + + $options{options}->add_options(arguments => { + + }); + + return $self; +} + +sub manage_selection { + my ($self, %options) = @_; + + my $result = $options{custom}->request_api(endpoint => '/metrics/jvm.classes.unloaded'); + $self->{global} = { unloaded => $result->{measurements}->[0]->{value} }; + + $result = $options{custom}->request_api(endpoint => '/metrics/jvm.classes.loaded'); + $self->{global}->{current} = $result->{measurements}->[0]->{value}; + + $self->{cache_name} = 'jvm_actuactor_' . $self->{mode} . '_' . $options{custom}->get_connection_infos() . '_' . + (defined($self->{option_results}->{filter_counters}) ? md5_hex($self->{option_results}->{filter_counters}) : md5_hex('all')); +} + +1; + +__END__ + +=head1 MODE + +Check java class loading. + +=over 8 + +=item B<--filter-counters> + +Only display some counters (regexp can be used). +Example: --filter-counters='current' + +=item B<--warning-*> B<--critical-*> + +Thresholds. +Can be: 'unloaded', 'current'. + +=back + +=cut diff --git a/centreon-plugins/apps/java/jvm/actuator/mode/cpuload.pm b/centreon-plugins/apps/java/jvm/actuator/mode/cpuload.pm new file mode 100644 index 000000000..197f3804f --- /dev/null +++ b/centreon-plugins/apps/java/jvm/actuator/mode/cpuload.pm @@ -0,0 +1,105 @@ +# +# Copyright 2021 Centreon (http://www.centreon.com/) +# +# Centreon is a full-fledged industry-strength solution that meets +# the needs in IT infrastructure and application monitoring for +# service performance. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +package apps::java::jvm::actuator::mode::cpuload; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'global', type => 0, message_separator => ' - ', skipped_code => { -10 => 1 } } + ]; + + $self->{maps_counters}->{global} = [ + { label => 'system', nlabel => 'system.cpu.load.percentage', set => { + key_values => [ { name => 'system_load' } ], + output_template => 'system cpu load: %.2f%%', + perfdatas => [ + { template => '%.2f', min => 0, max => 100, unit => '%' } + ] + } + }, + { label => 'process', nlabel => 'process.cpu.load.percentage', set => { + key_values => [ { name => 'process_load' } ], + output_template => 'process cpu load: %.2f%%', + perfdatas => [ + { template => '%.2f', min => 0, max => 100, unit => '%' } + ] + } + } + ]; +} + + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1); + bless $self, $class; + + $options{options}->add_options(arguments => {}); + + return $self; +} + +sub manage_selection { + my ($self, %options) = @_; + + my $result = $options{custom}->request_api(endpoint => '/metrics/system.cpu.usage'); + $self->{global} = { system_load => $result->{measurements}->[0]->{value} }; + + $result = $options{custom}->request_api(endpoint => '/metrics/process.cpu.usage'); + $self->{global}->{process_load} = $result->{measurements}->[0]->{value}; +} + +1; + +__END__ + +=head1 MODE + +Check JVM SystemCpuLoad and ProcessCpuLoad (From 0 to 1 where 1 means 100% of CPU ressources are in use, here we * by 100 for convenience). +WARN : Probably not work for java -version < 7. + +=over 8 + +=item B<--warning-system> + +Threshold warning of System cpuload + +=item B<--critical-system> + +Threshold critical of System cpuload + +=item B<--warning-process> + +Threshold warning of Process cpuload + +=item B<--critical-process> + +Threshold critical of Process cpuload + +=back + +=cut diff --git a/centreon-plugins/apps/java/jvm/actuator/mode/fdusage.pm b/centreon-plugins/apps/java/jvm/actuator/mode/fdusage.pm new file mode 100644 index 000000000..f63fe94f9 --- /dev/null +++ b/centreon-plugins/apps/java/jvm/actuator/mode/fdusage.pm @@ -0,0 +1,115 @@ +# +# Copyright 2021 Centreon (http://www.centreon.com/) +# +# Centreon is a full-fledged industry-strength solution that meets +# the needs in IT infrastructure and application monitoring for +# service performance. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +package apps::java::jvm::actuator::mode::fdusage; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +sub custom_usage_output { + my ($self, %options) = @_; + + return sprintf( + "File descriptor usage total: %s used: %s (%.2f%%) free: %s (%.2f%%)", + $self->{result_values}->{total}, + $self->{result_values}->{used}, $self->{result_values}->{prct_used}, + $self->{result_values}->{free}, $self->{result_values}->{prct_free} + ); +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'global', type => 0 } + ]; + + $self->{maps_counters}->{global} = [ + { label => 'usage', nlabel => 'fd.opened.usage.count', set => { + key_values => [ { name => 'used' }, { name => 'free' }, { name => 'prct_used' }, { name => 'prct_free' }, { name => 'total' } ], + closure_custom_output => $self->can('custom_usage_output'), + perfdatas => [ + { template => '%d', min => 0, max => 'total', cast_int => 1 }, + ] + } + }, + { label => 'usage-free', display_ok => 0, nlabel => 'fd.opened.free.count', set => { + key_values => [ { name => 'free' }, { name => 'used' }, { name => 'prct_used' }, { name => 'prct_free' }, { name => 'total' } ], + closure_custom_output => $self->can('custom_usage_output'), + perfdatas => [ + { template => '%d', min => 0, max => 'total', cast_int => 1 } + ] + } + }, + { label => 'usage-prct', display_ok => 0, nlabel => 'fd.opened.usage.percentage', set => { + key_values => [ { name => 'prct_used' }, { name => 'used' }, { name => 'free' }, { name => 'prct_free' }, { name => 'total' } ], + output_template => 'Used : %.2f %%', + perfdatas => [ + { template => '%.2f', min => 0, max => 100, unit => '%' } + ] + } + } + ]; +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1); + bless $self, $class; + + $options{options}->add_options(arguments => {}); + + return $self; +} + +sub manage_selection { + my ($self, %options) = @_; + + my $result = $options{custom}->request_api(endpoint => '/metrics/process.files.open'); + $self->{global} = { used => $result->{measurements}->[0]->{value} }; + + $result = $options{custom}->request_api(endpoint => '/metrics/process.files.max'); + $self->{global}->{total} = $result->{measurements}->[0]->{value}; + $self->{global}->{free} = $self->{global}->{total} - $self->{global}->{used}; + $self->{global}->{prct_used} = $self->{global}->{used} / $self->{global}->{total} * 100; + $self->{global}->{prct_free} = 100 - $self->{global}->{prct_used}; + +} + +1; + +__END__ + +=head1 MODE + +Check number/percentage of file descriptors. + +=over 8 + +=item B<--warning-*> B<--critical-*> + +Thresholds. +Can be: 'usage', 'usage-free', 'usage-prct' (%). + +=back + +=cut diff --git a/centreon-plugins/apps/java/jvm/actuator/mode/gcusage.pm b/centreon-plugins/apps/java/jvm/actuator/mode/gcusage.pm new file mode 100644 index 000000000..c5962bcb5 --- /dev/null +++ b/centreon-plugins/apps/java/jvm/actuator/mode/gcusage.pm @@ -0,0 +1,136 @@ +# +# Copyright 2021 Centreon (http://www.centreon.com/) +# +# Centreon is a full-fledged industry-strength solution that meets +# the needs in IT infrastructure and application monitoring for +# service performance. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +package centreon::common::jvm::mode::gcusage; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; +use Digest::MD5 qw(md5_hex); + +sub prefix_gc_output { + my ($self, %options) = @_; + + return "Garbage collector '" . $options{instance_value}->{display} . "' "; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'gc', type => 1, cb_prefix_output => 'prefix_gc_output', message_multiple => 'All garbage collectors are ok' } + ]; + + $self->{maps_counters}->{gc} = [ + { label => 'time', nlabel => 'gc.collection.time.elapsed.milliseconds', set => { + key_values => [ { name => 'time', diff => 1 }, { name => 'display' } ], + output_template => 'collection time: %s ms', + perfdatas => [ + { template => '%s', unit => 'ms', min => 0, label_extra_instance => 1, instance_use => 'display' } + ] + } + }, + { label => 'count', nlabel => 'gc.collection.count', set => { + key_values => [ { name => 'count', diff => 1 }, { name => 'display' } ], + output_template => 'collection count: %s', + perfdatas => [ + { template => '%s', min => 0, label_extra_instance => 1, instance_use => 'display' } + ] + } + } + ]; +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options, statefile => 1, force_new_perfdata => 1); + bless $self, $class; + + $options{options}->add_options(arguments => { + 'filter-name:s' => { name => 'filter_name' } + }); + + return $self; +} + +sub manage_selection { + my ($self, %options) = @_; + + $self->{request} = [ + { mbean => "java.lang:type=GarbageCollector,name=*", attributes => [ { name => 'CollectionCount' }, { name => 'CollectionTime' } ] } + ]; + + $self->{gc} = {}; + my $result = $options{custom}->get_attributes(request => $self->{request}, nothing_quit => 1); + + foreach my $key (keys %$result) { + $key =~ /name=(.*?)(?:,|$)/; + my $name = $1; + + $self->{gc}->{$name} = { + display => $name, + time => $result->{$key}->{CollectionTime}, + count => $result->{$key}->{CollectionCount} + } + } + + if (scalar(keys %{$self->{gc}}) <= 0) { + $self->{output}->add_option_msg(short_msg => 'No garbage collector found.'); + $self->{output}->option_exit(); + } + + $self->{cache_name} = 'jvm_standard_' . $self->{mode} . '_' . md5_hex($options{custom}->get_connection_info()) . '_' . + (defined($self->{option_results}->{filter_counters}) ? md5_hex($self->{option_results}->{filter_counters}) : md5_hex('all')) . '_' . + (defined($self->{option_results}->{filter_name}) ? md5_hex($self->{option_results}->{filter_name}) : md5_hex('all')); +} + +1; + +__END__ + +=head1 MODE + +Check garbage collectors. + +=over 8 + +=item B<--filter-counters> + +Only display some counters (regexp can be used). +Example: --filter-counters='^count$' + +=item B<--filter-name> + +Filter garbage collector name (can be a regexp). + +=item B<--warning-*> + +Threshold warning. +Can be: 'count', 'time' (ms). + +=item B<--critical-*> + +Threshold critical. +Can be: 'count', 'time' (ms). + +=back + +=cut diff --git a/centreon-plugins/apps/java/jvm/actuator/mode/loadaverage.pm b/centreon-plugins/apps/java/jvm/actuator/mode/loadaverage.pm new file mode 100644 index 000000000..b932f5140 --- /dev/null +++ b/centreon-plugins/apps/java/jvm/actuator/mode/loadaverage.pm @@ -0,0 +1,89 @@ +# +# Copyright 2021 Centreon (http://www.centreon.com/) +# +# Centreon is a full-fledged industry-strength solution that meets +# the needs in IT infrastructure and application monitoring for +# service performance. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +package apps::java::jvm::actuator::mode::loadaverage; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'global', type => 0 } + ]; + + $self->{maps_counters}->{global} = [ + { label => 'load1', nlabel => 'system.load.1m.count', set => { + key_values => [ { name => 'load' } ], + output_template => 'System load average: %.2f (1m)', + perfdatas => [ + { template => '%.2f', min => 0 } + ] + } + } + ]; +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1); + bless $self, $class; + + $options{options}->add_options(arguments => {}); + + return $self; +} + +sub manage_selection { + my ($self, %options) = @_; + + my $result = $options{custom}->request_api(endpoint => '/metrics/system.load.average.1m'); + if ($result->{measurements}->[0]->{value} == -1) { + $self->{output}->add_option_msg(short_msg => 'System load average is not set'); + $self->{output}->option_exit(); + } + + $self->{global} = { load => $result->{measurements}->[0]->{value} }; +} + +1; + +__END__ + +=head1 MODE + +Check system load average. + +=over 8 + +=item B<--warning-load1> + +Warning threshold for loadaverage + +=item B<--critical-load1> + +Critical threshold for loadaverage + +=back + +=cut diff --git a/centreon-plugins/apps/java/jvm/actuator/mode/memory.pm b/centreon-plugins/apps/java/jvm/actuator/mode/memory.pm new file mode 100644 index 000000000..d7c0da01d --- /dev/null +++ b/centreon-plugins/apps/java/jvm/actuator/mode/memory.pm @@ -0,0 +1,198 @@ +# +# Copyright 2021 Centreon (http://www.centreon.com/) +# +# Centreon is a full-fledged industry-strength solution that meets +# the needs in IT infrastructure and application monitoring for +# service performance. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +package apps::java::jvm::actuator::mode::memory; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +sub custom_usage_perfdata { + my ($self, %options) = @_; + + my $use_th = 1; + $use_th = 0 if ($self->{instance_mode}->{option_results}->{units} eq '%' && $self->{result_values}->{max} <= 0); + + my $value_perf = $self->{result_values}->{used}; + my %total_options = (); + if ($self->{instance_mode}->{option_results}->{units} eq '%' && $self->{result_values}->{max} > 0) { + $total_options{total} = $self->{result_values}->{max}; + $total_options{cast_int} = 1; + } + + $self->{output}->perfdata_add( + nlabel => $self->{nlabel}, + unit => 'B', + value => $value_perf, + warning => $use_th == 1 ? $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{thlabel}, %total_options) : undef, + critical => $use_th == 1 ? $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{thlabel}, %total_options) : undef, + min => 0, max => $self->{result_values}->{max} > 0 ? $self->{result_values}->{max} : undef + ); +} + +sub custom_usage_threshold { + my ($self, %options) = @_; + + # Cannot use percent without total + return 'ok' if ($self->{result_values}->{max} <= 0 && $self->{instance_mode}->{option_results}->{units} eq '%'); + my ($exit, $threshold_value); + $threshold_value = $self->{result_values}->{used}; + if ($self->{instance_mode}->{option_results}->{units} eq '%') { + $threshold_value = $self->{result_values}->{prct_used}; + } + $exit = $self->{perfdata}->threshold_check( + value => $threshold_value, threshold => [ + { label => 'critical-' . $self->{thlabel}, exit_litteral => 'critical' }, + { label => 'warning-'. $self->{thlabel}, exit_litteral => 'warning' } + ] + ); + return $exit; +} + +sub custom_usage_output { + my ($self, %options) = @_; + + my $msg; + my ($total_used_value, $total_used_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{used}); + if ($self->{result_values}->{max} > 0) { + my ($total_size_value, $total_size_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{max}); + my ($total_free_value, $total_free_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{max} - $self->{result_values}->{used}); + $msg = sprintf( + "%s Total: %s Used: %s (%.2f%%) Free: %s (%.2f%%)", $self->{result_values}->{label}, + $total_size_value . " " . $total_size_unit, + $total_used_value . " " . $total_used_unit, $self->{result_values}->{prct_used}, + $total_free_value . " " . $total_free_unit, 100 - $self->{result_values}->{prct_used} + ); + } else { + $msg = sprintf( + "%s Used: %s", + $self->{result_values}->{label}, + $total_used_value . " " . $total_used_unit + ); + } + + return $msg; +} + +sub custom_usage_calc { + my ($self, %options) = @_; + + $self->{result_values}->{label} = $options{new_datas}->{$self->{label} . '_label'}; + $self->{result_values}->{max} = $options{new_datas}->{$self->{instance} . '_max'}; + $self->{result_values}->{used} = $options{new_datas}->{$self->{instance} . '_used'}; + + if ($self->{result_values}->{max} > 0) { + $self->{result_values}->{prct_used} = $self->{result_values}->{used} * 100 / $self->{result_values}->{max}; + } + + return 0; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'heap', type => 0 }, + { name => 'nonheap', type => 0 } + ]; + + $self->{maps_counters}->{heap} = [ + { label => 'heap', nlabel => 'memory.heap.usage.bytes', set => { + key_values => [ { name => 'used' }, { name => 'max' }, { name => 'label' } ], + 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') + } + }, + ]; + + $self->{maps_counters}->{nonheap} = [ + { label => 'nonheap', nlabel => 'memory.nonheap.usage.bytes', set => { + key_values => [ { name => 'used' }, { name => 'max' }, { name => 'label' } ], + 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 new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1); + bless $self, $class; + + $options{options}->add_options(arguments => { + 'units:s' => { name => 'units', default => '%' } + }); + + return $self; +} + +sub manage_selection { + my ($self, %options) = @_; + + my $result = $options{custom}->request_api(endpoint => '/metrics/jvm.memory.max', get_param => ['tag=area:heap']); + $self->{heap} = { label => 'HeapMemory', max => $result->{measurements}->[0]->{value} }; + $result = $options{custom}->request_api(endpoint => '/metrics/jvm.memory.used', get_param => ['tag=area:heap']); + $self->{heap}->{used} = $result->{measurements}->[0]->{value}; + + $result = $options{custom}->request_api(endpoint => '/metrics/jvm.memory.max', get_param => ['tag=area:nonheap']); + $self->{nonheap} = { label => 'NonHeapMemoryUsage', max => $result->{measurements}->[0]->{value} }; + $result = $options{custom}->request_api(endpoint => '/metrics/jvm.memory.used', get_param => ['tag=area:nonheap']); + $self->{nonheap}->{used} = $result->{measurements}->[0]->{value}; +} + +1; + +__END__ + +=head1 MODE + +Check Java Heap and NonHeap memory usage. + +=over 8 + +=item B<--warning-heap> + +Threshold warning of Heap memory usage + +=item B<--critical-heap> + +Threshold critical of Heap memory usage + +=item B<--warning-nonheap> + +Threshold warning of NonHeap memory usage + +=item B<--critical-nonheap> + +Threshold critical of NonHeap memory usage + +=item B<--units> + +Units of thresholds (Default: '%') ('%', 'B'). + +=back + +=cut diff --git a/centreon-plugins/apps/java/jvm/actuator/mode/memorydetailed.pm b/centreon-plugins/apps/java/jvm/actuator/mode/memorydetailed.pm new file mode 100644 index 000000000..d4581378f --- /dev/null +++ b/centreon-plugins/apps/java/jvm/actuator/mode/memorydetailed.pm @@ -0,0 +1,278 @@ +# +# Copyright 2021 Centreon (http://www.centreon.com/) +# +# Centreon is a full-fledged industry-strength solution that meets +# the needs in IT infrastructure and application monitoring for +# service performance. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +package apps::java::jvm::actuator::mode::memorydetailed; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; + +my %mapping_memory = ( + 'Eden Space' => 'eden', + 'Par Eden Space' => 'eden', + 'PS Eden Space' => 'eden', + 'Survivor Space' => 'survivor', + 'Par Survivor Space' => 'survivor', + 'PS Survivor Space' => 'survivor', + 'CMS Perm Gen' => 'permanent', + 'PS Perm Gen' => 'permanent', + 'Perm Gen' => 'permanent', + 'Metaspace' => 'permanent', + 'JIT data cache' => 'permanent', + 'Code Cache' => 'code', + 'JIT Code Cache' => 'code', + 'CMS Old Gen' => 'tenured', + 'PS Old Gen' => 'tenured', + 'Tenured Gen' => 'tenured' +); + +sub custom_usage_perfdata { + my ($self, %options) = @_; + + my $use_th = 1; + $use_th = 0 if ($self->{instance_mode}->{option_results}->{units} eq '%' && $self->{result_values}->{max} <= 0); + + my $value_perf = $self->{result_values}->{used}; + my %total_options = (); + if ($self->{instance_mode}->{option_results}->{units} eq '%' && $self->{result_values}->{max} > 0) { + $total_options{total} = $self->{result_values}->{max}; + $total_options{cast_int} = 1; + } + + $self->{output}->perfdata_add( + nlabel => $self->{nlabel}, + unit => 'B', + value => $value_perf, + warning => $use_th == 1 ? $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{thlabel}, %total_options) : undef, + critical => $use_th == 1 ? $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{thlabel}, %total_options) : undef, + min => 0, max => $self->{result_values}->{max} > 0 ? $self->{result_values}->{max} : undef + ); +} + +sub custom_usage_threshold { + my ($self, %options) = @_; + + # Cannot use percent without total + return 'ok' if ($self->{result_values}->{max} <= 0 && $self->{instance_mode}->{option_results}->{units} eq '%'); + my ($exit, $threshold_value); + $threshold_value = $self->{result_values}->{used}; + if ($self->{instance_mode}->{option_results}->{units} eq '%') { + $threshold_value = $self->{result_values}->{prct_used}; + } + $exit = $self->{perfdata}->threshold_check( + value => $threshold_value, threshold => [ + { label => 'critical-' . $self->{thlabel}, exit_litteral => 'critical' }, + { label => 'warning-'. $self->{thlabel}, exit_litteral => 'warning' } + ] + ); + return $exit; +} + +sub custom_usage_output { + my ($self, %options) = @_; + + my $msg; + my ($total_used_value, $total_used_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{used}); + if ($self->{result_values}->{max} > 0) { + my ($total_size_value, $total_size_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{max}); + my ($total_free_value, $total_free_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{max} - $self->{result_values}->{used}); + $msg = sprintf( + "Total: %s Used: %s (%.2f%%) Free: %s (%.2f%%)", + $total_size_value . " " . $total_size_unit, + $total_used_value . " " . $total_used_unit, $self->{result_values}->{prct_used}, + $total_free_value . " " . $total_free_unit, 100 - $self->{result_values}->{prct_used} + ); + } else { + $msg = sprintf("Used: %s", $total_used_value . " " . $total_used_unit); + } + return $msg; +} + +sub custom_usage_calc { + my ($self, %options) = @_; + + if ($mapping_memory{$options{new_datas}->{$self->{instance} . '_display'}} ne $self->{label}) { + return -12; + } + $self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_display'}; + $self->{result_values}->{max} = $options{new_datas}->{$self->{instance} . '_max'}; + $self->{result_values}->{used} = $options{new_datas}->{$self->{instance} . '_used'}; + if ($self->{result_values}->{max} > 0) { + $self->{result_values}->{prct_used} = $self->{result_values}->{used} * 100 / $self->{result_values}->{max}; + } + + return 0; +} + +sub prefix_mem_output { + my ($self, %options) = @_; + + return "Memory '" . $options{instance_value}->{display} . "' "; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'mem', type => 1, cb_prefix_output => 'prefix_mem_output', message_multiple => 'All memories within bounds', skipped_code => { -12 => 1 } } + ]; + + $self->{maps_counters}->{mem} = [ + { label => 'eden', nlabel => 'memory.eden.usage.bytes', set => { + key_values => [ { name => 'used' }, { name => 'max' }, { name => 'display' } ], + closure_custom_calc => $self->can('custom_usage_calc'), + closure_custom_output => $self->can('custom_usage_output'), + closure_custom_threshold_check => $self->can('custom_usage_threshold'), + closure_custom_perfdata => $self->can('custom_usage_perfdata') + } + }, + { label => 'tenured', nlabel => 'memory.tenured.usage.bytes', set => { + key_values => [ { name => 'used' }, { name => 'max' }, { name => 'display' } ], + closure_custom_calc => $self->can('custom_usage_calc'), + closure_custom_output => $self->can('custom_usage_output'), + closure_custom_threshold_check => $self->can('custom_usage_threshold'), + closure_custom_perfdata => $self->can('custom_usage_perfdata') + } + }, + { label => 'survivor', nlabel => 'memory.survivor.usage.bytes', set => { + key_values => [ { name => 'used' }, { name => 'max' }, { name => 'display' } ], + closure_custom_calc => $self->can('custom_usage_calc'), + closure_custom_output => $self->can('custom_usage_output'), + closure_custom_threshold_check => $self->can('custom_usage_threshold'), + closure_custom_perfdata => $self->can('custom_usage_perfdata') + } + }, + { label => 'permanent', nlabel => 'memory.permanent.usage.bytes', set => { + key_values => [ { name => 'used' }, { name => 'max' }, { name => 'display' } ], + closure_custom_calc => $self->can('custom_usage_calc'), + closure_custom_output => $self->can('custom_usage_output'), + closure_custom_threshold_check => $self->can('custom_usage_threshold'), + closure_custom_perfdata => $self->can('custom_usage_perfdata') + } + }, + { label => 'code', nlabel => 'memory.code.usage.bytes', set => { + key_values => [ { name => 'used' }, { name => 'max' }, { name => 'display' } ], + closure_custom_calc => $self->can('custom_usage_calc'), + closure_custom_output => $self->can('custom_usage_output'), + closure_custom_threshold_check => $self->can('custom_usage_threshold'), + closure_custom_perfdata => $self->can('custom_usage_perfdata') + } + } + ]; +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1); + bless $self, $class; + + $options{options}->add_options(arguments => { + 'units:s' => { name => 'units', default => '%' } + }); + + return $self; +} + +sub manage_selection { + my ($self, %options) = @_; + + my $result = $options{custom}->request_api(endpoint => '/metrics/jvm.memory.max'); + foreach (@{$result->{availableTags}}) { + next if ($_->{tag} ne 'id'); + foreach my $name (@{$_->{values}}) { + if (!defined($mapping_memory{$name})) { + $self->{output}->output_add(long_msg => "unknown memory: " . $name, debug => 1); + next; + } + my $max = $options{custom}->request_api(endpoint => '/metrics/jvm.memory.max', get_param => ['tag=id:' . $name]); + my $used = $options{custom}->request_api(endpoint => '/metrics/jvm.memory.used', get_param => ['tag=id:' . $name]); + $self->{mem}->{$name} = { + display => $name, + max => $max->{measurements}->[0]->{value}, + used => $used->{measurements}->[0]->{value} + }; + } + } +} + +1; + +__END__ + +=head1 MODE + +Check JVM Memory Pools : + +Eden Space (heap) (-eden) : The pool from which memory is initially allocated for most objects. +Survivor Space (heap) (-survivor) : The pool containing objects that have survived the garbage collection of the Eden space. +Tenured Generation (heap) (-tenured) : The pool containing objects that have existed for some time in the survivor space. +Permanent Generation (non-heap) (-permanent) : The pool containing all the reflective data of the virtual machine itself, such as class and method objects. +Code Cache (non-heap) (-code) : The HotSpot Java VM also includes a code cache, containing memory that is used for compilation and storage of native code. + +=over 8 + +=item B<--warning-eden> + +Threshold warning of Heap 'Eden Space' memory usage + +=item B<--critical-eden> + +Threshold critical of Heap 'Survivor Space' memory usage + +=item B<--warning-tenured> + +Threshold warning of Heap 'Tenured Generation' memory usage + +=item B<--critical-tenured> + +Threshold critical of Heap 'Tenured Generation' memory usage + +=item B<--warning-survivor> + +Threshold warning of Heap 'Survivor Space' memory usage + +=item B<--critical-survivor> + +Threshold critical of Heap 'Survivor Space' memory usage + +=item B<--warning-permanent> + +Threshold warning of NonHeap 'Permanent Generation' memory usage + +=item B<--critical-permanent> + +Threshold critical of NonHeap 'Permanent Generation' memory usage + +=item B<--warning-code> + +Threshold warning of NonHeap 'Code Cache' memory usage + +=item B<--critical-code> + +Threshold critical of NonHeap 'Code Cache' memory usage + +=item B<--units> + +Units of thresholds (Default: '%') ('%', 'B'). + +=back + +=cut diff --git a/centreon-plugins/apps/java/jvm/actuator/mode/threads.pm b/centreon-plugins/apps/java/jvm/actuator/mode/threads.pm new file mode 100644 index 000000000..7762cb312 --- /dev/null +++ b/centreon-plugins/apps/java/jvm/actuator/mode/threads.pm @@ -0,0 +1,104 @@ +# +# Copyright 2021 Centreon (http://www.centreon.com/) +# +# Centreon is a full-fledged industry-strength solution that meets +# the needs in IT infrastructure and application monitoring for +# service performance. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +package apps::java::jvm::actuator::mode::threads; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; +use Digest::MD5 qw(md5_hex); + +sub prefix_global_output { + my ($self, %options) = @_; + + return 'Threads '; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'global', type => 0, cb_prefix_output => 'prefix_global_output', skipped_code => { -10 => 1 } } + ]; + + $self->{maps_counters}->{global} = [ + { label => 'active', nlabel => 'threads.active.count', set => { + key_values => [ { name => 'active' } ], + output_template => 'active: %s', + perfdatas => [ + { template => '%s', min => 0 } + ] + } + }, + { label => 'daemon', nlabel => 'threads.daemon.count', set => { + key_values => [ { name => 'daemon' } ], + output_template => 'daemon: %s', + perfdatas => [ + { template => '%s', min => 0 } + ] + } + } + ]; +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1); + bless $self, $class; + + $options{options}->add_options(arguments => { }); + + return $self; +} + +sub manage_selection { + my ($self, %options) = @_; + + my $result = $options{custom}->request_api(endpoint => '/metrics/jvm.threads.live'); + $self->{global} = { active => $result->{measurements}->[0]->{value} }; + + $result = $options{custom}->request_api(endpoint => '/metrics/jvm.threads.daemon'); + $self->{global}->{daemon} = $result->{measurements}->[0]->{value}; +} + +1; + +__END__ + +=head1 MODE + +Check threads. + +=over 8 + +=item B<--warning-*> + +Threshold warning. +Can be: 'active', 'daemon'. + +=item B<--critical-*> + +Threshold critical. +Can be: 'active', 'daemon'. + +=back + +=cut diff --git a/centreon-plugins/apps/java/jvm/actuator/plugin.pm b/centreon-plugins/apps/java/jvm/actuator/plugin.pm new file mode 100644 index 000000000..e05fdadae --- /dev/null +++ b/centreon-plugins/apps/java/jvm/actuator/plugin.pm @@ -0,0 +1,56 @@ +# +# Copyright 2021 Centreon (http://www.centreon.com/) +# +# Centreon is a full-fledged industry-strength solution that meets +# the needs in IT infrastructure and application monitoring for +# service performance. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +package apps::java::jvm::actuator::plugin; + +use strict; +use warnings; +use base qw(centreon::plugins::script_custom); + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $self->{version} = '0.1'; + $self->{modes} = { + 'class-count' => 'apps::java::jvm::actuator::mode::classcount', + 'cpu-load' => 'apps::java::jvm::actuator::mode::cpuload', + 'fd-usage' => 'apps::java::jvm::actuator::mode::fdusage', + 'load-average' => 'apps::java::jvm::actuator::mode::loadaverage', + 'memory' => 'apps::java::jvm::actuator::mode::memory', + 'memory-detailed' => 'apps::java::jvm::actuator::mode::memorydetailed', + 'threads' => 'apps::java::jvm::actuator::mode::threads' + }; + + $self->{custom_modes}->{standard} = 'centreon::common::protocols::actuator::custom::standard'; + $self->{custom_modes}->{centreonmap} = 'centreon::common::protocols::actuator::custom::centreonmap'; + return $self; +} + +1; + +__END__ + +=head1 PLUGIN DESCRIPTION + +Check Java Virtual Machine with Actuator in HTTP. + +=cut diff --git a/centreon-plugins/centreon/common/protocols/actuator/custom/centreonmap.pm b/centreon-plugins/centreon/common/protocols/actuator/custom/centreonmap.pm new file mode 100644 index 000000000..2610a7774 --- /dev/null +++ b/centreon-plugins/centreon/common/protocols/actuator/custom/centreonmap.pm @@ -0,0 +1,298 @@ +# +# Copyright 2021 Centreon (http://www.centreon.com/) +# +# Centreon is a full-fledged industry-strength solution that meets +# the needs in IT infrastructure and application monitoring for +# service performance. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# Authors : Roman Morandell - ivertix +# + +package centreon::common::protocols::actuator::custom::centreonmap; + +use strict; +use warnings; +use centreon::plugins::http; +use centreon::plugins::statefile; +use JSON::XS; +use Digest::MD5 qw(md5_hex); + +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' }, + 'url-path:s' => { name => 'url_path' }, + 'api-username:s' => { name => 'api_username' }, + 'api-password:s' => { name => 'api_password' }, + 'client-version:s' => { name => 'client_version' }, + 'timeout:s' => { name => 'timeout' } + }); + } + $options{options}->add_help(package => __PACKAGE__, sections => 'REST API OPTIONS', once => 1); + + $self->{output} = $options{output}; + $self->{http} = centreon::plugins::http->new(%options); + $self->{cache} = centreon::plugins::statefile->new(%options); + + return $self; +} + +sub set_options { + my ($self, %options) = @_; + + $self->{option_results} = $options{option_results}; +} + +sub set_defaults {} + +sub check_options { + my ($self, %options) = @_; + + $self->{hostname} = (defined($self->{option_results}->{hostname})) ? $self->{option_results}->{hostname} : ''; + $self->{proto} = (defined($self->{option_results}->{proto})) ? $self->{option_results}->{proto} : 'http'; + $self->{port} = (defined($self->{option_results}->{port})) ? $self->{option_results}->{port} : 8080; + $self->{url_path} = (defined($self->{option_results}->{url_path})) ? $self->{option_results}->{url_path} : '/centreon-studio/api/beta'; + $self->{api_username} = (defined($self->{option_results}->{api_username})) ? $self->{option_results}->{api_username} : ''; + $self->{api_password} = (defined($self->{option_results}->{api_password})) ? $self->{option_results}->{api_password} : ''; + $self->{timeout} = (defined($self->{option_results}->{timeout})) ? $self->{option_results}->{timeout} : 30; + $self->{unknown_http_status} = (defined($self->{option_results}->{unknown_http_status})) ? $self->{option_results}->{unknown_http_status} : '%{http_code} < 200 or %{http_code} >= 300' ; + $self->{warning_http_status} = (defined($self->{option_results}->{warning_http_status})) ? $self->{option_results}->{warning_http_status} : ''; + $self->{critical_http_status} = (defined($self->{option_results}->{critical_http_status})) ? $self->{option_results}->{critical_http_status} : ''; + $self->{client_version} = (defined($self->{option_results}->{client_version})) ? $self->{option_results}->{client_version} : '21.04.0'; + + if ($self->{hostname} eq '') { + $self->{output}->add_option_msg(short_msg => 'Need to specify hostname option.'); + $self->{output}->option_exit(); + } + if ($self->{api_username} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --api-username option."); + $self->{output}->option_exit(); + } + if ($self->{api_password} eq '') { + $self->{output}->add_option_msg(short_msg => "Need to specify --api-password option."); + $self->{output}->option_exit(); + } + + $self->{cache}->check_options(option_results => $self->{option_results}); + return 0; +} + +sub get_connection_infos { + my ($self, %options) = @_; + + return $self->{hostname} . '_' . $self->{http}->get_port(); +} + +sub get_hostname { + my ($self, %options) = @_; + + return $self->{hostname}; +} + +sub get_port { + my ($self, %options) = @_; + + return $self->{port}; +} + +sub json_decode { + my ($self, %options) = @_; + + my $decoded; + eval { + $decoded = JSON::XS->new->utf8->decode($options{content}); + }; + if ($@) { + $self->{output}->add_option_msg(short_msg => "Cannot decode json response: $@"); + $self->{output}->option_exit(); + } + + return $decoded; +} + +sub build_options_for_httplib { + my ($self, %options) = @_; + + $self->{option_results}->{hostname} = $self->{hostname}; + $self->{option_results}->{port} = $self->{port}; + $self->{option_results}->{proto} = $self->{proto}; +} + +sub settings { + my ($self, %options) = @_; + + $self->build_options_for_httplib(); + $self->{http}->add_header(key => 'Accept', value => 'application/json'); + $self->{http}->add_header(key => 'X-Client-Version', value => $self->{client_version}); + $self->{http}->set_options(%{$self->{option_results}}); +} + +sub clean_session { + my ($self, %options) = @_; + + my $datas = {}; + $options{statefile}->write(data => $datas); + $self->{studio_session} = undef; +} + +sub get_session { + my ($self, %options) = @_; + + my $has_cache_file = $options{statefile}->read(statefile => 'centreonmap_session_' . md5_hex($self->{option_results}->{hostname}) . '_' . md5_hex($self->{option_results}->{api_username})); + my $studio_session = $options{statefile}->get(name => 'studio_session'); + + if ($has_cache_file == 0 || !defined($studio_session)) { + my $login = { login => $self->{api_username}, password => $self->{api_password} }; + my $post_json = JSON::XS->new->utf8->encode($login); + + my ($content) = $self->{http}->request( + method => 'POST', + url_path => $self->{url_path} . '/authentication', + header => ['Content-type: application/json'], + query_form_post => $post_json, + warning_status => '', unknown_status => '', critical_status => '' + ); + + if ($self->{http}->get_code() != 200) { + $self->{output}->add_option_msg(short_msg => "Authentication error [code: '" . $self->{http}->get_code() . "'] [message: '" . $self->{http}->get_message() . "']"); + $self->{output}->option_exit(); + } + + my $decoded = $self->json_decode(content => $content); + if (!defined($decoded->{studioSession})) { + $self->{output}->add_option_msg(short_msg => 'Cannot studio session'); + $self->{output}->option_exit(); + } + + $studio_session = $decoded->{studioSession}; + $options{statefile}->write(data => { studio_session => $studio_session }); + } + + $self->{studio_session} = $studio_session; +} + +sub request_api { + my ($self, %options) = @_; + + $self->settings(); + if (!defined($self->{studio_session})) { + $self->get_session(statefile => $self->{cache}); + } + + my $content = $self->{http}->request( + url_path => $self->{url_path} . '/actuator' . $options{endpoint}, + get_param => $options{get_param}, + header => [ + 'studio-session: ' . $self->{studio_session} + ], + warning_status => '', + unknown_status => '', + critical_status => '' + ); + + # Maybe there is an issue with the token. So we retry. + if ($self->{http}->get_code() < 200 || $self->{http}->get_code() >= 300) { + $self->clean_session(statefile => $self->{cache}); + $self->get_session(statefile => $self->{cache}); + $content = $self->{http}->request( + url_path => $self->{url_path} . '/actuator' . $options{endpoint}, + get_param => $options{get_param}, + header => [ + 'studio-session: ' . $self->{studio_session} + ], + unknown_status => $self->{unknown_http_status}, + warning_status => $self->{warning_http_status}, + critical_status => $self->{critical_http_status} + ); + } + + my $decoded = $self->json_decode(content => $content); + if (!defined($decoded)) { + $self->{output}->add_option_msg(short_msg => 'Error while retrieving data (add --debug option for detailed message)'); + $self->{output}->option_exit(); + } + + return $decoded; +} + +1; + +__END__ + +=head1 NAME + +Centreon Map API + +=head1 SYNOPSIS + +Centreon Map API + +=head1 REST API OPTIONS + +=over 8 + +=item B<--hostname> + +API hostname. + +=item B<--url-path> + +API url path (Default: '/centreon-studio/api/beta') + +=item B<--port> + +API port (Default: 8080) + +=item B<--proto> + +Specify https if needed (Default: 'http') + +=item B<--api-username> + +Set API username + +=item B<--api-password> + +Set API password + +=item B<--timeout> + +Set HTTP timeout + +=item B<--client-version> + +Set the client version (Default: '21.04.0') + +=back + +=head1 DESCRIPTION + +B. + +=cut diff --git a/centreon-plugins/centreon/common/protocols/actuator/custom/standard.pm b/centreon-plugins/centreon/common/protocols/actuator/custom/standard.pm new file mode 100644 index 000000000..4beeb1ba6 --- /dev/null +++ b/centreon-plugins/centreon/common/protocols/actuator/custom/standard.pm @@ -0,0 +1,210 @@ +# +# Copyright 2021 Centreon (http://www.centreon.com/) +# +# Centreon is a full-fledged industry-strength solution that meets +# the needs in IT infrastructure and application monitoring for +# service performance. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +package centreon::common::protocols::actuator::custom::standard; + +use strict; +use warnings; +use centreon::plugins::http; +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 => { + 'api-username:s' => { name => 'api_username' }, + 'api-password:s' => { name => 'api_password' }, + 'hostname:s' => { name => 'hostname' }, + 'port:s' => { name => 'port' }, + 'proto:s' => { name => 'proto' }, + 'timeout:s' => { name => 'timeout' }, + 'unknown-http-status:s' => { name => 'unknown_http_status' }, + 'warning-http-status:s' => { name => 'warning_http_status' }, + 'critical-http-status:s' => { name => 'critical_http_status' }, + 'url-path:s' => { name => 'url_path' } + }); + } + $options{options}->add_help(package => __PACKAGE__, sections => 'REST API OPTIONS', once => 1); + + $self->{output} = $options{output}; + $self->{http} = centreon::plugins::http->new(%options); + + return $self; +} + +sub set_options { + my ($self, %options) = @_; + + $self->{option_results} = $options{option_results}; +} + +sub set_defaults {} + +sub check_options { + my ($self, %options) = @_; + + $self->{hostname} = (defined($self->{option_results}->{hostname})) ? $self->{option_results}->{hostname} : ''; + $self->{port} = (defined($self->{option_results}->{port})) ? $self->{option_results}->{port} : 8080; + $self->{proto} = (defined($self->{option_results}->{proto})) ? $self->{option_results}->{proto} : 'http'; + $self->{timeout} = (defined($self->{option_results}->{timeout})) ? $self->{option_results}->{timeout} : 30; + $self->{api_username} = (defined($self->{option_results}->{api_username})) ? $self->{option_results}->{api_username} : ''; + $self->{api_password} = (defined($self->{option_results}->{api_password})) ? $self->{option_results}->{api_password} : ''; + $self->{unknown_http_status} = (defined($self->{option_results}->{unknown_http_status})) ? $self->{option_results}->{unknown_http_status} : '%{http_code} < 200 or %{http_code} >= 300'; + $self->{warning_http_status} = (defined($self->{option_results}->{warning_http_status})) ? $self->{option_results}->{warning_http_status} : ''; + $self->{critical_http_status} = (defined($self->{option_results}->{critical_http_status})) ? $self->{option_results}->{critical_http_status} : ''; + $self->{url_path} = (defined($self->{option_results}->{url_path})) ? $self->{option_results}->{url_path} : '/actuator'; + + if ($self->{hostname} eq '') { + $self->{output}->add_option_msg(short_msg => 'Need to specify --hostname 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}->{timeout} = $self->{timeout}; + if (defined($self->{api_username}) && $self->{api_username} ne '') { + $self->{option_results}->{credentials} = 1; + $self->{option_results}->{basic} = 1; + $self->{option_results}->{username} = $self->{api_username}; + $self->{option_results}->{password} = $self->{api_password}; + } +} + +sub settings { + my ($self, %options) = @_; + + return if (defined($self->{settings_done})); + $self->build_options_for_httplib(); + $self->{http}->add_header(key => 'Accept', value => 'application/json'); + $self->{http}->set_options(%{$self->{option_results}}); + $self->{settings_done} = 1; +} + +sub get_connection_infos { + my ($self, %options) = @_; + + return $self->{hostname} . '_' . $self->{http}->get_port(); +} + +sub get_hostname { + my ($self, %options) = @_; + + return $self->{hostname}; +} + +sub request_api { + my ($self, %options) = @_; + + $self->settings(); + my $content = $self->{http}->request( + url_path => $self->{url_path} . $options{endpoint}, + get_param => $options{get_param}, + unknown_status => $self->{unknown_http_status}, + warning_status => $self->{warning_http_status}, + critical_status => $self->{critical_http_status}, + cookies_file => '' + ); + + if (!defined($content) || $content eq '') { + $self->{output}->add_option_msg(short_msg => "API returns empty content [code: '" . $self->{http}->get_code() . "'] [message: '" . $self->{http}->get_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 response (add --debug option to display returned content)"); + $self->{output}->option_exit(); + } + + return $decoded; +} + +1; + +__END__ + +=head1 NAME + +Spring Boot Actuator Rest API + +=head1 REST API OPTIONS + +Spring Boot Actuator Rest API + +=over 8 + +=item B<--hostname> + +Hostname. + +=item B<--port> + +Port used (Default: 8080) + +=item B<--proto> + +Specify https if needed (Default: 'http') + +=item B<--api-username> + +Specify username for authentication (basic auth) + +=item B<--api-password> + +Specify password for authentication (basic auth) + +=item B<--timeout> + +Set timeout in seconds (Default: 30) + +=item B<--url-path> + +API url path (Default: '/actuator') + +=back + +=head1 DESCRIPTION + +B. + +=cut