centreon-plugins/centreon/common/protocols/jmx/custom/jolokia.pm

367 lines
12 KiB
Perl

#
# Copyright 2020 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::jmx::custom::jolokia;
use strict;
use warnings;
use JMX::Jmx4Perl;
use JMX::Jmx4Perl::Alias;
use JMX::Jmx4Perl::Request;
use JMX::Jmx4Perl::Util;
sub new {
my ($class, %options) = @_;
my $self = {};
bless $self, $class;
# $options{options} = options object
# $options{output} = output object
# $options{exit_value} = integer
# $options{noptions} = integer
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 => {
'url:s@' => { name => 'url' },
'timeout:s@' => { name => 'timeout' },
'username:s@' => { name => 'username' },
'password:s@' => { name => 'password' },
'proxy-url:s@' => { name => 'proxy_url' },
'proxy-username:s@' => { name => 'proxy_username' },
'proxy-password:s@' => { name => 'proxy_password' },
'target-url:s@' => { name => 'target_url' },
'target-username:s@' => { name => 'target_username' },
'target-password:s@' => { name => 'target_password' }
});
}
$options{options}->add_help(package => __PACKAGE__, sections => 'JOLOKIA OPTIONS', once => 1);
$self->{output} = $options{output};
$self->{jmx4perl} = undef;
return $self;
}
sub set_options {
my ($self, %options) = @_;
$self->{option_results} = $options{option_results};
}
sub set_defaults {}
sub check_options {
my ($self, %options) = @_;
foreach (('url', 'timeout', 'username', 'password', 'proxy_url', 'proxy_username',
'proxy_password', 'target_url', 'target_username', 'target_password')) {
$self->{$_} = (defined($self->{option_results}->{$_})) ? shift(@{$self->{option_results}->{$_}}) : undef;
}
$self->{connect_params} = {};
if (!defined($self->{url}) || $self->{url} eq '') {
$self->{output}->add_option_msg(short_msg => "Please set option --url.");
$self->{output}->option_exit();
}
if (defined($self->{timeout}) && $self->{timeout} =~ /^\d+$/ &&
$self->{timeout} > 0) {
$self->{timeout} = $self->{timeout};
} else {
$self->{timeout} = 30;
}
$self->{connect_params}->{url} = $self->{url};
$self->{connect_params}->{timeout} = $self->{timeout};
if (defined($self->{username}) && $self->{username} ne '') {
$self->{connect_params}->{user} = $self->{username};
$self->{connect_params}->{password} = $self->{password};
}
if (defined($self->{proxy_url}) && $self->{proxy_url} ne '') {
$self->{connect_params}->{proxy} = { url => $self->{proxy_url} };
if (defined($self->{proxy_username}) && $self->{proxy_username} ne '') {
$self->{connect_params}->{proxy}->{'proxy-user'} = $self->{proxy_username};
$self->{connect_params}->{proxy}->{'proxy-password'} = $self->{proxy_password};
}
}
if (defined($self->{target_url}) && $self->{target_url} ne '') {
$self->{connect_params}->{target} = { url => $self->{target_url}, user => undef, password => undef };
if (defined($self->{target_username}) && $self->{target_username} ne '') {
$self->{connect_params}->{target}->{user} = $self->{target_username};
$self->{connect_params}->{target}->{password} = $self->{target_password};
}
}
if (!defined($self->{url}) ||
scalar(@{$self->{option_results}->{url}}) == 0) {
return 0;
}
return 1;
}
sub get_connection_info {
my ($self, %options) = @_;
my $connection_info = $self->{url};
$connection_info .= '_' . $self->{proxy_url} if (defined($self->{proxy_url}));
return $connection_info;
}
sub connect {
my ($self, %options) = @_;
$self->{jmx4perl} = new JMX::Jmx4Perl($self->{connect_params});
}
sub _add_request {
my ($self, %options) = @_;
my $request = JMX::Jmx4Perl::Request->new(
READ, $options{object},
$options{attribute}
);
if (!$request->is_mbean_pattern($options{object})) {
$request->{path} = $options{path};
}
return $request;
}
sub check_error {
my ($self, %options) = @_;
# 500-599 an error. 400 is an attribute not present
my $status = $options{response}->status();
if ($status >= 500 ||
$status == 401 ||
$status == 403 ||
$status == 408) {
$self->{output}->add_option_msg(short_msg => "protocol issue: " . $options{response}->error_text());
$self->{output}->option_exit();
}
}
sub get_attributes {
my ($self, %options) = @_;
my $nothing_quit = defined($options{nothing_quit}) && $options{nothing_quit} == 1 ? 1 : 0;
#$options{request} = [
# { mbean => 'java.lang:name=*,type=MemoryPool', attributes => [ { name => 'CollectionUsage', path => 'committed' }, { name => 'Name', path => undef },
# { name => 'NonHeapMemoryUsagePlop', path => undef } ] },
# { mbean => 'java.lang:type=Memory', attributes => [ { name => 'NonHeapMemoryUsage' } ] },
# { mbean => 'java.lang:type=Memory', attributes => [ { name => 'HeapMemoryUsage', path => 'committed' } ] },
# { mbean => 'java.lang:type=Memory', attributes => [] },
#];
if (!defined($self->{jmx4perl})) {
$self->connect();
}
my @requests = ();
for (my $i = 0; defined($options{request}) && $i < scalar(@{$options{request}}); $i++) {
my $object = $options{request}->[$i]->{mbean};
for (my $j = 0; defined($options{request}->[$i]->{attributes}) &&
$j < scalar(@{$options{request}->[$i]->{attributes}}) ; $j++) {
push @requests, $self->_add_request(object => $object, attribute => $options{request}->[$i]->{attributes}->[$j]->{name},
path => $options{request}->[$i]->{attributes}->[$j]->{path});
}
if (!defined($options{request}->[$i]->{attributes}) || scalar(@{$options{request}->[$i]->{attributes}}) == 0) {
push @requests, $self->_add_request(object => $object, path => $options{request}->[$i]->{path});
}
}
my $response = {};
my @responses = $self->{jmx4perl}->request(@requests);
for (my $i = 0, my $pos = 0; defined($options{request}) && $i < scalar(@{$options{request}}); $i++) {
for (my $j = 0; defined($options{request}->[$i]->{attributes}) &&
defined($responses[$pos]) && $j < scalar(@{$options{request}->[$i]->{attributes}}); $j++, $pos++) {
if ($responses[$pos]->is_error()) {
$self->check_error(response => $responses[$pos]);
next;
}
my $mbean = $responses[$pos]->{request}->{mbean};
my $attribute = $responses[$pos]->{request}->{attribute};
my $value = $responses[$pos]->{value};
if ($requests[$pos]->is_mbean_pattern()) {
foreach (keys %{$responses[$pos]->{value}}) {
$response->{$_} = {} if (!defined($response->{$_}));
$response->{$_}->{$attribute} = $responses[$pos]->{value}->{$_}->{$attribute};
}
} else {
$response->{$mbean} = {} if (!defined($response->{$mbean}));
$response->{$mbean}->{$attribute} = $value;
}
}
if (!defined($options{request}->[$i]->{attributes}) || scalar(@{$options{request}->[$i]->{attributes}}) == 0) {
if ($responses[$pos]->is_error()) {
$self->check_error(response => $responses[$pos]);
} else {
my $mbean = $responses[$pos]->{request}->{mbean};
$response->{$mbean} = {} if (!defined($response->{$mbean}));
foreach (keys %{$responses[$pos]->{value}}) {
$response->{$mbean}->{$_} = $responses[$pos]->{value}->{$_};
}
}
$pos++;
}
}
if ($nothing_quit == 1 && scalar(keys %{$response}) == 0) {
$self->{output}->add_option_msg(short_msg => "JMX Request: Cant get a single value.");
$self->{output}->option_exit();
}
return $response;
}
sub list_attributes {
my ($self, %options) = @_;
my $max_depth = defined($options{max_depth}) ? $options{max_depth} : 5;
my $max_objects = defined($options{max_objects}) ? $options{max_objects} : 100;
my $max_collection_size = defined($options{max_collection_size}) ? $options{max_collection_size} : 50;
my $pattern = defined($options{mbean_pattern}) ? $options{mbean_pattern} : '*:*';
my $color = 1;
eval {
local $SIG{__DIE__} = 'IGNORE';
require Term::ANSIColor;
};
if ($@) {
$color = 0;
}
if (!defined($self->{jmx4perl})) {
$self->connect();
}
my $mbeans = $self->{jmx4perl}->search($pattern);
print "List attributes:\n";
for my $mbean (@$mbeans) {
my $request = JMX::Jmx4Perl::Request->new(
READ, $mbean, undef,
{
maxDepth => $max_depth,
maxObjects => $max_objects,
maxCollectionSize => $max_collection_size,
ignoreErrors => 1
}
);
my $response = $self->{jmx4perl}->request($request);
if ($response->is_error) {
print "ERROR: " . $response->error_text . "\n";
print JMX::Jmx4Perl::Util->dump_value($response, { format => 'DATA' });
} else {
my $values = $response->value;
if (keys %$values) {
for my $a (keys %$values) {
print Term::ANSIColor::color('red on_yellow') if ($color == 1);
print "$mbean -- $a";
print Term::ANSIColor::color('reset') if ($color == 1);
my $val = $values->{$a};
if (JMX::Jmx4Perl::Util->is_object_to_dump($val)) {
my $v = JMX::Jmx4Perl::Util->dump_value($val, { format => 'DATA' });
$v =~ s/^\s*//;
print " = " . $v;
} else {
my $scal = JMX::Jmx4Perl::Util->dump_scalar($val);
if (defined($scal)) {
print " = " . $scal . "\n";
} else {
print " = undef\n";
}
}
}
}
}
}
}
1;
__END__
=head1 NAME
JOlokia connector library
=head1 SYNOPSIS
my jolokia connector
=head1 JOLOKIA OPTIONS
=over 8
=item B<--url>
Url where the jolokia agent is deployed (required).
Example: http://localhost:8080/jolokia
=item B<--timeout>
Timeout in seconds for HTTP requests (Defaults: 30 seconds)
=item B<--username>
Credentials to use for the HTTP request
=item B<--password>
Credentials to use for the HTTP request
=item B<--proxy-url>
Optional HTTP proxy to use.
=item B<--proxy-username>
Credentials to use for the proxy
=item B<--proxy-password>
Credentials to use for the proxy
=item B<--target-url>
Target to use (if you use jolokia agent as a proxy in --url option).
=item B<--target-username>
Credentials to use for the target
=item B<--target-password>
Credentials to use for the target
=back
=head1 DESCRIPTION
B<custom>.
=cut