centreon-plugins/centreon/plugins/script.pm

492 lines
14 KiB
Perl
Raw Normal View History

2013-12-13 16:14:12 +01:00
#
2021-02-08 09:55:50 +01:00
# Copyright 2021 Centreon (http://www.centreon.com/)
2015-07-21 11:51:02 +02:00
#
# 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.
#
2013-12-13 16:14:12 +01:00
package centreon::plugins::script;
use strict;
use warnings;
use centreon::plugins::output;
use centreon::plugins::misc;
use Pod::Usage;
2019-07-11 10:26:17 +02:00
my %handlers = (DIE => {}, ALRM => {});
2015-11-10 11:16:11 +01:00
2018-11-06 14:10:53 +01:00
my $global_version = '(dev)';
my $alternative_fatpacker = 0;
2013-12-13 16:14:12 +01:00
sub new {
2016-09-20 16:37:21 +02:00
my ($class) = @_;
2013-12-13 16:14:12 +01:00
my $self = {};
bless $self, $class;
$self->{options} = undef;
$self->{plugin} = undef;
$self->{help} = undef;
2015-08-28 16:08:52 +02:00
# Avoid to destroy because it keeps a ref on the object.
# A problem if we execute it multiple times in the same perl execution
# Use prepare_destroy
2019-07-11 10:26:17 +02:00
$self->set_signal_handlers();
2013-12-13 16:14:12 +01:00
return $self;
}
2015-08-28 16:08:52 +02:00
sub prepare_destroy {
2016-09-20 16:37:21 +02:00
my ($self) = @_;
2015-08-28 16:08:52 +02:00
2019-10-08 10:37:19 +02:00
%handlers = ();
2015-08-28 16:08:52 +02:00
}
2013-12-13 16:14:12 +01:00
sub set_signal_handlers {
2019-07-11 10:26:17 +02:00
my ($self) = @_;
2013-12-13 16:14:12 +01:00
$SIG{__DIE__} = \&class_handle_DIE;
$handlers{DIE}->{$self} = sub { $self->handle_DIE($_[0]) };
}
sub class_handle_DIE {
my ($msg) = @_;
foreach (keys %{$handlers{DIE}}) {
&{$handlers{DIE}->{$_}}($msg);
}
}
2019-07-11 10:26:17 +02:00
sub class_handle_ALRM {
foreach (keys %{$handlers{ALRM}}) {
&{$handlers{ALRM}->{$_}}();
}
}
2013-12-13 16:14:12 +01:00
sub handle_DIE {
my ($self, $msg) = @_;
return unless defined $^S and $^S == 0; # Ignore errors in eval
2013-12-13 16:14:12 +01:00
$self->{output}->add_option_msg(short_msg => $msg);
$self->{output}->die_exit();
}
2019-07-11 10:26:17 +02:00
sub handle_ALRM {
my ($self) = @_;
$self->{output}->add_option_msg(short_msg => 'script global timeout');
$self->{output}->option_exit();
}
sub get_global_version {
return $global_version;
}
2013-12-13 16:14:12 +01:00
sub get_plugin {
2016-09-20 16:37:21 +02:00
my ($self) = @_;
2019-12-17 11:35:12 +01:00
2013-12-13 16:14:12 +01:00
# Need to load global 'Output' and 'Options'
if ($alternative_fatpacker == 0) {
require centreon::plugins::options;
$self->{options} = centreon::plugins::options->new();
} else {
require centreon::plugins::alternative::FatPackerOptions;
$self->{options} = centreon::plugins::alternative::FatPackerOptions->new();
}
2013-12-13 16:14:12 +01:00
$self->{output} = centreon::plugins::output->new(options => $self->{options});
$self->{options}->set_output(output => $self->{output});
$self->{options}->add_options(arguments => {
2019-04-16 17:01:22 +02:00
'plugin:s' => { name => 'plugin' },
'list-plugin' => { name => 'list_plugin' },
'help' => { name => 'help' },
'ignore-warn-msg' => { name => 'ignore_warn_msg' },
'version' => { name => 'version' },
'runas:s' => { name => 'runas' },
2019-07-11 10:26:17 +02:00
'global-timeout:s' => { name => 'global_timeout' },
2019-04-16 17:01:22 +02:00
'environment:s%' => { name => 'environment' },
'convert-args:s' => { name => 'convert_args' },
});
2013-12-13 16:14:12 +01:00
$self->{options}->parse_options();
2019-07-11 10:26:17 +02:00
$self->{plugin} = $self->{options}->get_option(argument => 'plugin');
$self->{list_plugin} = $self->{options}->get_option(argument => 'list_plugin');
$self->{help} = $self->{options}->get_option(argument => 'help');
$self->{version} = $self->{options}->get_option(argument => 'version');
$self->{runas} = $self->{options}->get_option(argument => 'runas');
$self->{environment} = $self->{options}->get_option(argument => 'environment');
$self->{ignore_warn_msg} = $self->{options}->get_option(argument => 'ignore_warn_msg');
$self->{convert_args} = $self->{options}->get_option(argument => 'convert_args');
2019-12-17 11:35:12 +01:00
2019-07-11 10:26:17 +02:00
my $global_timeout = $self->{options}->get_option(argument => 'global_timeout');
if (defined($global_timeout) && $global_timeout =~ /(\d+)/) {
$SIG{ALRM} = \&class_handle_ALRM;
$handlers{ALRM}->{$self} = sub { $self->handle_ALRM() };
alarm($1);
}
2013-12-13 16:14:12 +01:00
$self->{output}->plugin(name => $self->{plugin});
$self->{output}->check_options(option_results => $self->{options}->get_options());
$self->{options}->clean();
}
sub convert_args {
my ($self) = @_;
2019-12-17 11:35:12 +01:00
if ($self->{convert_args} =~ /^(.+?),(.*)/) {
my ($search, $replace) = ($1, $2);
2017-06-01 17:57:45 +02:00
for (my $i = 0; $i <= $#ARGV; $i++) {
2017-05-10 10:22:01 +02:00
eval "\$ARGV[\$i] =~ s/$search/$replace/g";
}
}
}
2013-12-13 16:14:12 +01:00
sub display_local_help {
2016-09-20 16:37:21 +02:00
my ($self) = @_;
2013-12-13 16:14:12 +01:00
my $stdout;
if ($self->{help}) {
local *STDOUT;
open STDOUT, '>', \$stdout;
if ($alternative_fatpacker == 0) {
pod2usage(-exitval => 'NOEXIT', -input => $self->{options}->pod_where(package => __PACKAGE__));
} else {
my $pp = __PACKAGE__ . '.pm';
$pp =~ s{::}{/}g;
my $content_class = $INC{$pp}->{$pp};
open my $str_fh, '<', \$content_class;
pod2usage(-exitval => 'NOEXIT', -input => $str_fh);
close $str_fh;
}
2013-12-13 16:14:12 +01:00
}
2019-12-17 11:35:12 +01:00
2013-12-13 16:14:12 +01:00
$self->{output}->add_option_msg(long_msg => $stdout) if (defined($stdout));
}
2014-05-14 14:35:50 +02:00
sub check_directory {
my ($self, $directory) = @_;
2019-12-17 11:35:12 +01:00
2014-05-14 14:35:50 +02:00
opendir(my $dh, $directory) || return ;
while (my $filename = readdir $dh) {
$self->check_directory($directory . '/' . $filename) if ($filename !~ /^\./ && -d $directory . '/' . $filename);
2014-05-14 14:35:50 +02:00
if ($filename eq 'plugin.pm') {
my $stdout = '';
2019-12-17 11:35:12 +01:00
2014-05-14 14:35:50 +02:00
{
local *STDOUT;
open STDOUT, '>', \$stdout;
2019-12-17 11:35:12 +01:00
pod2usage(
-exitval => 'NOEXIT',
-input => $directory . "/" . $filename,
-verbose => 99,
-sections => 'PLUGIN DESCRIPTION'
);
2014-05-14 14:35:50 +02:00
}
2019-12-17 11:35:12 +01:00
$self->{plugins_result}->{$directory . '/' . $filename} = $stdout;
2014-05-14 14:35:50 +02:00
}
}
closedir $dh;
}
2016-12-08 11:41:18 +01:00
sub fatpacker_find_plugin {
my ($self) = @_;
my $plugins = [];
foreach (@INC) {
next if (ref($_) !~ /FatPacked/);
foreach my $name (keys %$_) {
if ($name =~ /plugin.pm$/) {
push @$plugins, $name;
}
}
}
2019-12-17 11:35:12 +01:00
2016-12-08 11:41:18 +01:00
return $plugins;
}
sub check_plugin_option {
my ($self) = @_;
2019-12-17 11:35:12 +01:00
2016-12-08 11:41:18 +01:00
if (defined($self->{version})) {
$self->{output}->add_option_msg(short_msg => 'Global Version: ' . $global_version);
2016-12-08 11:41:18 +01:00
$self->{output}->option_exit(nolabel => 1);
}
2019-12-17 11:35:12 +01:00
2016-12-08 11:41:18 +01:00
my $no_plugin = 1;
if ($alternative_fatpacker == 1) {
my $integrated_plugins = $self->fatpacker_find_plugin();
if (scalar(@$integrated_plugins) == 1) {
$self->{plugin} = $integrated_plugins->[0];
$no_plugin = 0;
}
}
2019-12-17 11:35:12 +01:00
2016-12-08 11:41:18 +01:00
if ($no_plugin == 1) {
$self->{output}->add_option_msg(short_msg => "Need to specify '--plugin' option.");
$self->{output}->option_exit();
}
}
2014-05-14 14:35:50 +02:00
sub display_list_plugin {
2016-09-20 16:37:21 +02:00
my ($self) = @_;
2014-05-14 14:35:50 +02:00
$self->{plugins_result} = {};
2019-08-07 17:27:47 +02:00
2016-12-08 11:41:18 +01:00
if ($alternative_fatpacker == 1) {
my $integrated_plugins = $self->fatpacker_find_plugin();
2019-12-17 11:35:12 +01:00
2019-08-07 17:27:47 +02:00
foreach my $key (sort @$integrated_plugins) {
2016-12-08 11:41:18 +01:00
# Need to load it to get the description
2019-08-07 17:27:47 +02:00
centreon::plugins::misc::mymodule_load(
output => $self->{output}, module => $key,
error_msg => 'Cannot load module --plugin.'
);
2016-12-08 11:41:18 +01:00
my $name = $key;
$name =~ s/\.pm//g;
$name =~ s/\//::/g;
$self->{output}->add_option_msg(long_msg => '-----------------');
$self->{output}->add_option_msg(long_msg => 'PLUGIN: ' . $name);
{
my $stdout = '';
local *STDOUT;
open STDOUT, '>', \$stdout;
my $content_class = $INC{$key}->{$key};
open my $str_fh, '<', \$content_class;
pod2usage(-exitval => 'NOEXIT', -input => $str_fh, -verbose => 99, -sections => 'PLUGIN DESCRIPTION');
2016-12-08 11:41:18 +01:00
close $str_fh;
$self->{output}->add_option_msg(long_msg => $stdout);
}
}
return ;
}
2019-12-17 11:35:12 +01:00
centreon::plugins::misc::mymodule_load(
output => $self->{output}, module => 'FindBin',
error_msg => "Cannot load module 'FindBin'."
);
2020-12-07 16:18:11 +01:00
my $directory = $FindBin::Bin;
if (defined($ENV{PAR_TEMP})) {
$directory = $ENV{PAR_TEMP} . '/inc/lib';
}
2014-05-14 14:35:50 +02:00
# Search file 'plugin.pm'
2020-12-07 16:18:11 +01:00
$self->check_directory($directory);
2019-08-07 17:27:47 +02:00
foreach my $key (sort keys %{$self->{plugins_result}}) {
2014-05-14 14:35:50 +02:00
my $name = $key;
2020-12-07 16:18:11 +01:00
$name =~ s/^\Q$directory\E\/(.*)\.pm/$1/;
2014-05-14 14:35:50 +02:00
$name =~ s/\//::/g;
2014-05-14 17:44:02 +02:00
$self->{plugins_result}->{$key} =~ s/^Plugin Description/DESCRIPTION/i;
2019-12-17 11:35:12 +01:00
2014-05-14 14:35:50 +02:00
$self->{output}->add_option_msg(long_msg => '-----------------');
$self->{output}->add_option_msg(long_msg => 'PLUGIN: ' . $name);
$self->{output}->add_option_msg(long_msg => $self->{plugins_result}->{$key});
}
}
sub check_relaunch_get_args {
my ($self) = @_;
my $args = ['--plugin=' . $self->{plugin}, @ARGV];
push @$args, '--ignore-warn-msg' if (defined($self->{ignore_warn_msg}));
2020-02-28 09:29:36 +01:00
push @$args, '--help' if (defined($self->{help}));
push @$args, '--global-timeout', $self->{global_timeout} if (defined($self->{global_timeout}));
foreach ((
['output_xml', 0], ['output_json', 0], ['output_openmetrics', 0],
['disco_format', 0], ['disco_show', 0], ['use_new_perfdata', 0], ['debug', 0], ['verbose', 0],
['range_perfdata', 1], ['filter_uom', 1], ['opt_exit', 1], ['filter_perfdata', 1],
['output_file', 1], ['float_precision', 1]
)) {
my $option = $self->{output}->get_option(option => $_->[0]);
if (defined($option)) {
my $option_label = $_->[0];
$option_label =~ s/_/-/g;
push @$args, "--$option_label" if ($_->[1] == 0);
push @$args, "--$option_label", $option if ($_->[1] == 1);
}
}
return $args;
}
2013-12-13 16:14:12 +01:00
sub check_relaunch {
my $self = shift;
2019-12-17 11:35:12 +01:00
centreon::plugins::misc::mymodule_load(
output => $self->{output}, module => 'FindBin',
error_msg => "Cannot load module 'FindBin'."
);
2013-12-13 16:14:12 +01:00
my $need_restart = 0;
2019-12-17 11:35:12 +01:00
my $cmd = $FindBin::Bin . '/' . $FindBin::Script;
my $args = [];
2019-12-17 11:35:12 +01:00
2013-12-13 16:14:12 +01:00
if (defined($self->{environment})) {
foreach (keys %{$self->{environment}}) {
if ($_ ne '' && (!defined($ENV{$_}) || $ENV{$_} ne $self->{environment}->{$_})) {
$ENV{$_} = $self->{environment}->{$_};
$need_restart = 1;
}
}
}
my $rebuild_args = $self->check_relaunch_get_args();
2013-12-13 16:14:12 +01:00
if (defined($self->{runas}) && $self->{runas} ne '') {
# Check if it's already me and user exist ;)
my ($name, $passwd, $uid) = getpwnam($self->{runas});
if (!defined($uid)) {
$self->{output}->add_option_msg(short_msg => "Runas user '" . $self->{runas} . "' not exist.");
$self->{output}->option_exit();
}
if ($uid != $>) {
if ($> == 0) {
unshift @$args, '-s', '/bin/bash', '-l', $self->{runas}, '-c', join(' ', $cmd, $rebuild_args);
2019-12-17 11:35:12 +01:00
$cmd = 'su';
2013-12-13 16:14:12 +01:00
} else {
unshift @$args, '-S', '-u', $self->{runas}, $cmd, @$rebuild_args;
2019-12-17 11:35:12 +01:00
$cmd = 'sudo';
2013-12-13 16:14:12 +01:00
}
$need_restart = 1;
}
}
if ($need_restart == 1) {
if (scalar(@$args) <= 0) {
unshift @$args, @$rebuild_args;
2013-12-13 16:14:12 +01:00
}
my ($lerror, $stdout, $exit_code) = centreon::plugins::misc::backtick(
command => $cmd,
arguments => $args,
timeout => 30,
wait_exit => 1
);
2013-12-13 16:14:12 +01:00
if ($exit_code <= -1000) {
if ($exit_code == -1000) {
2019-12-17 11:35:12 +01:00
$self->{output}->output_add(
severity => 'UNKNOWN',
short_msg => $stdout
);
2013-12-13 16:14:12 +01:00
}
$self->{output}->display();
$self->{output}->exit();
}
chomp $stdout;
print $stdout . "\n";
2013-12-13 16:14:12 +01:00
# We put unknown
if (!($exit_code >= 0 && $exit_code <= 4)) {
exit 3;
}
exit $exit_code;
}
}
sub run {
2016-09-20 16:37:21 +02:00
my ($self) = @_;
2013-12-13 16:14:12 +01:00
$self->get_plugin();
if (defined($self->{help}) && !defined($self->{plugin})) {
$self->display_local_help();
$self->{output}->option_exit();
}
2014-05-14 14:35:50 +02:00
if (defined($self->{list_plugin})) {
$self->display_list_plugin();
$self->{output}->option_exit();
}
$self->check_plugin_option() if (!defined($self->{plugin}) || $self->{plugin} eq '');
2014-09-30 16:50:06 +02:00
if (defined($self->{ignore_warn_msg})) {
$SIG{__WARN__} = sub {};
}
$self->convert_args() if (defined($self->{convert_args}));
2013-12-13 16:14:12 +01:00
$self->check_relaunch();
2019-12-17 11:35:12 +01:00
2016-05-02 21:06:27 +02:00
(undef, $self->{plugin}) =
centreon::plugins::misc::mymodule_load(
output => $self->{output}, module => $self->{plugin},
error_msg => 'Cannot load module --plugin.'
);
2013-12-13 16:14:12 +01:00
my $plugin = $self->{plugin}->new(options => $self->{options}, output => $self->{output});
2019-07-11 10:26:17 +02:00
$plugin->init(
help => $self->{help},
version => $self->{version}
);
2013-12-13 16:14:12 +01:00
$plugin->run();
}
1;
__END__
=head1 NAME
centreon_plugins.pl - main program to call Centreon plugins.
2013-12-13 16:14:12 +01:00
=head1 SYNOPSIS
centreon_plugins.pl [options]
=head1 OPTIONS
=over 8
=item B<--plugin>
Specify the path to the plugin.
2014-05-14 14:35:50 +02:00
=item B<--list-plugin>
Print available plugins.
2013-12-13 16:14:12 +01:00
=item B<--version>
2015-11-10 11:16:11 +01:00
Print global version.
2013-12-13 16:14:12 +01:00
=item B<--help>
Print a brief help message and exits.
2014-09-30 16:50:06 +02:00
=item B<--ignore-warn-msg>
Perl warn messages are ignored (not displayed).
2013-12-13 16:14:12 +01:00
=item B<--runas>
Run the script as a different user (prefer to use directly the good user).
2019-07-11 10:26:17 +02:00
=item B<--global-timeout>
Set script timeout.
2013-12-13 16:14:12 +01:00
=item B<--environment>
Set environment variables for the script (prefer to set it before running it for better performance).
=item B<--convert-args>
Change strings of arguments. Useful to use '!' in nrpe protocol.
2017-05-10 10:22:01 +02:00
Example: --convert-args='##,\x21'
2013-12-13 16:14:12 +01:00
=back
=head1 DESCRIPTION
B<centreon_plugins.pl> .
=cut