From b4c08728b0771b91e4c1d85e00649404b1d21671 Mon Sep 17 00:00:00 2001 From: qgarnier Date: Fri, 5 Nov 2021 13:37:52 +0100 Subject: [PATCH] add(plugin): ibm db2 (#3232) --- .../protocols/sql/mode/connectiontime.pm | 29 +++++--- database/db2/dbi.pm | 61 ++++++++++++++- database/db2/mode/databaselogs.pm | 5 +- database/db2/mode/databaseusage.pm | 6 +- database/db2/mode/listtablespaces.pm | 4 +- database/db2/mode/tablespaces.pm | 74 +++++++++++++++---- 6 files changed, 143 insertions(+), 36 deletions(-) diff --git a/centreon/common/protocols/sql/mode/connectiontime.pm b/centreon/common/protocols/sql/mode/connectiontime.pm index d0b725a5f..7aeedf911 100644 --- a/centreon/common/protocols/sql/mode/connectiontime.pm +++ b/centreon/common/protocols/sql/mode/connectiontime.pm @@ -63,22 +63,29 @@ sub run { my ($exit, $msg_error) = $self->{sql}->connect(dontquit => 1); my $now2 = Time::HiRes::time(); $self->{sql}->disconnect(); - + if ($exit == -1) { - $self->{output}->output_add(severity => 'CRITICAL', - short_msg => $msg_error); + $self->{output}->output_add( + severity => 'CRITICAL', + short_msg => $msg_error + ); } else { my $milliseconds = $now2 - $now; $milliseconds = floor($milliseconds * 1000); my $exit_code = $self->{perfdata}->threshold_check(value => $milliseconds, threshold => [ { label => 'critical', 'exit_litteral' => 'critical' }, { label => 'warning', exit_litteral => 'warning' } ]); - $self->{output}->output_add(severity => $exit_code, - short_msg => sprintf("Connection established in %.3fs.", $milliseconds / 1000)); - $self->{output}->perfdata_add(label => 'connection_time', - value => $milliseconds, - unit => 'ms', - warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning'), - critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical'), - min => 0); + $self->{output}->output_add( + severity => $exit_code, + short_msg => sprintf("Connection established in %.3fs.", $milliseconds / 1000) + ); + $self->{output}->perfdata_add( + label => 'connection_time', + nlabel => 'connection.time.milliseconds', + value => $milliseconds, + unit => 'ms', + warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning'), + critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical'), + min => 0 + ); } $self->{output}->display(); diff --git a/database/db2/dbi.pm b/database/db2/dbi.pm index 01233ba29..19dcd2d50 100644 --- a/database/db2/dbi.pm +++ b/database/db2/dbi.pm @@ -24,9 +24,22 @@ use base qw(centreon::plugins::dbi); use strict; use warnings; +use POSIX qw(:signal_h); + +sub connect_db2 { + my ($self, %options) = @_; + + $self->{instance} = DBI->connect( + 'DBI:' . $self->{data_source}, + $self->{username}, + $self->{password}, + { RaiseError => 0, PrintError => 0, AutoCommit => 1, %{$self->{connect_options_hash}} } + ); +} sub connect { my ($self, %options) = @_; + my $dontquit = (defined($options{dontquit}) && $options{dontquit} == 1) ? 1 : 0; if ($self->{data_source} =~ /PROTOCOL=TCPIP/) { $self->{data_source} .= 'UID=' . $self->{username} . ';' @@ -34,7 +47,45 @@ sub connect { $self->{data_source} .= 'PWD=' . $self->{password} . ';' if ($self->{data_source} !~ /PWD/ && defined($self->{password})); } - $self->SUPER::connect(%options); + + # Set ENV + if (defined($self->{env})) { + foreach (keys %{$self->{env}}) { + $ENV{$_} = $self->{env}->{$_}; + } + } + + if (defined($self->{timeout})) { + my $mask = POSIX::SigSet->new(SIGALRM); + my $action = POSIX::SigAction->new( + sub { $self->handle_ALRM() }, + $mask, + ); + my $oldaction = POSIX::SigAction->new(); + sigaction(SIGALRM, $action, $oldaction); + eval { + eval { + alarm($self->{timeout}); + $self->connect_db2(); + }; + alarm(0); + }; + sigaction(SIGALRM, $oldaction); + } else { + $self->connect_db2(); + } + + if (!defined($self->{instance})) { + my $err_msg = sprintf('Cannot connect: %s', defined($DBI::errstr) ? $DBI::errstr : '(no error string)'); + if ($dontquit == 0) { + $self->{output}->add_option_msg(short_msg => $err_msg); + $self->{output}->option_exit(exit_litteral => $self->{sql_errors_exit}); + } + return (-1, $err_msg); + } + + $self->set_version(); + return 0; } sub get_dbh { @@ -43,11 +94,17 @@ sub get_dbh { return $self->{instance}; } +sub fetchrow_arrayref { + my ($self, %options) = @_; + + return $self->{statement_handle}->fetchrow_arrayref(); +} + sub get_database_name { my ($self, %options) = @_; my $dbname = 'unknown'; - $dbname = $1 if ($self->{data_source} =~ /DATABASE=([^;]*?)/i); + $dbname = $1 if ($self->{data_source} =~ /DATABASE=([^;]*)/i); $dbname = $1 if ($self->{data_source} =~ /DBI:DB2:(.*)/); $dbname =~ s/^\s+//g; $dbname =~ s/\s+$//g; diff --git a/database/db2/mode/databaselogs.pm b/database/db2/mode/databaselogs.pm index e1f3d4db1..6a9ad8bf6 100644 --- a/database/db2/mode/databaselogs.pm +++ b/database/db2/mode/databaselogs.pm @@ -18,7 +18,7 @@ # limitations under the License. # -package database::db2::mode::databaseusage; +package database::db2::mode::databaselogs; use base qw(centreon::plugins::templates::counter); @@ -33,7 +33,6 @@ sub custom_usage_output { my ($total_free_value, $total_free_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{free}); return sprintf( 'usage total: %s used: %s (%.2f%%) free: %s (%.2f%%)', - $self->{result_values}->{partition}, $total_size_value . " " . $total_size_unit, $total_used_value . " " . $total_used_unit, $self->{result_values}->{prct_used}, $total_free_value . " " . $total_free_unit, $self->{result_values}->{prct_free} @@ -77,7 +76,7 @@ sub custom_usage_prct_perfdata { nlabel => $self->{nlabel}, unit => '%', instances => [$self->{result_values}->{dbname}, $self->{result_values}->{partition}], - value => $self->{result_values}->{prct_used}, + value => sprintf('%.2f', $self->{result_values}->{prct_used}), warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{thlabel}), critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{thlabel}), min => 0, diff --git a/database/db2/mode/databaseusage.pm b/database/db2/mode/databaseusage.pm index 488e7227b..a4a473457 100644 --- a/database/db2/mode/databaseusage.pm +++ b/database/db2/mode/databaseusage.pm @@ -77,7 +77,7 @@ sub custom_usage_prct_perfdata { nlabel => $self->{nlabel}, unit => '%', instances => $self->{result_values}->{dbname}, - value => $self->{result_values}->{prct_used}, + value => sprintf('%.2f', $self->{result_values}->{prct_used}), warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{thlabel}), critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{thlabel}), min => 0, @@ -139,7 +139,7 @@ sub manage_selection { $options{sql}->connect(); my $dbh = $options{sql}->get_dbh(); - my ($snapshot_timestamp, $db_size, $db_capacity) = (0, 0, 0); + my ($snapshot_timestamp, $db_size, $db_capacity) = ('', 0, 0); my $sth = $dbh->prepare(q{ CALL SYSPROC.GET_DBSIZE_INFO(?, ?, ?, 0) }); @@ -147,7 +147,7 @@ sub manage_selection { $sth->bind_param_inout(2, \$db_size, 30, { db2_param_type=>SQL_PARAM_OUTPUT() }); $sth->bind_param_inout(3, \$db_capacity, 30, { db2_param_type=>SQL_PARAM_OUTPUT() }); $sth->execute(); - if (!defined($snapshot_timestamp) || $snapshot_timestamp == 0) { + if (!defined($snapshot_timestamp) || $snapshot_timestamp eq '') { $self->{output}->add_option_msg(short_msg => 'Cannot execute query: ' . $dbh->errstr()); $self->{output}->option_exit(); } diff --git a/database/db2/mode/listtablespaces.pm b/database/db2/mode/listtablespaces.pm index 4d264abf3..05ae9d25a 100644 --- a/database/db2/mode/listtablespaces.pm +++ b/database/db2/mode/listtablespaces.pm @@ -25,7 +25,7 @@ use base qw(centreon::plugins::mode); use strict; use warnings; -my $order = ['name', 'type', 'datype']; +my $order = ['name', 'type', 'datatype']; sub new { my ($class, %options) = @_; @@ -59,7 +59,7 @@ sub manage_selection { $tablespaces->{ $row->[0] } = { name => $row->[0], type => $row->[1] =~ /^[dD]/ ? 'dms' : 'sms', - datatype => $row->[3] + datatype => $row->[2] }; } diff --git a/database/db2/mode/tablespaces.pm b/database/db2/mode/tablespaces.pm index e28a3b1de..21d064911 100644 --- a/database/db2/mode/tablespaces.pm +++ b/database/db2/mode/tablespaces.pm @@ -43,13 +43,57 @@ sub custom_usage_output { my ($total_free_value, $total_free_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{free}); return sprintf( 'space usage total: %s used: %s (%.2f%%) free: %s (%.2f%%)', - $self->{result_values}->{partition}, $total_size_value . " " . $total_size_unit, $total_used_value . " " . $total_used_unit, $self->{result_values}->{prct_used}, $total_free_value . " " . $total_free_unit, $self->{result_values}->{prct_free} ); } +sub custom_usage_perfdata { + my ($self, %options) = @_; + + $self->{output}->perfdata_add( + nlabel => $self->{nlabel}, + unit => 'B', + instances => [$self->{result_values}->{dbname}, $self->{result_values}->{tbsname}], + value => $self->{result_values}->{used}, + warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{thlabel}), + critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{thlabel}), + min => 0, + max => $self->{result_values}->{total} + ); +} + +sub custom_usage_free_perfdata { + my ($self, %options) = @_; + + $self->{output}->perfdata_add( + nlabel => $self->{nlabel}, + unit => 'B', + instances => [$self->{result_values}->{dbname}, $self->{result_values}->{tbsname}], + value => $self->{result_values}->{free}, + warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{thlabel}), + critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{thlabel}), + min => 0, + max => $self->{result_values}->{total} + ); +} + +sub custom_usage_prct_perfdata { + my ($self, %options) = @_; + + $self->{output}->perfdata_add( + nlabel => $self->{nlabel}, + unit => '%', + instances => [$self->{result_values}->{dbname}, $self->{result_values}->{tbsname}], + value => sprintf('%.2f', $self->{result_values}->{prct_used}), + warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{thlabel}), + critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{thlabel}), + min => 0, + max => 100 + ); +} + sub prefix_tbs_output { my ($self, %options) = @_; @@ -66,7 +110,7 @@ sub set_counters { { name => 'tbs', type => 1, cb_prefix_output => 'prefix_tbs_output', message_multiple => 'All tablespaces are ok' } ]; - $self->{maps_counters}->{logs} = [ + $self->{maps_counters}->{tbs} = [ { label => 'status', type => 2, @@ -80,32 +124,29 @@ sub set_counters { }, { label => 'space-usage', nlabel => 'tablespace.space.usage.bytes', set => { key_values => [ - { name => 'used' }, { name => 'free' }, { name => 'prct_used' }, { name => 'prct_free' }, { name => 'total' } + { name => 'used' }, { name => 'free' }, { name => 'prct_used' }, { name => 'prct_free' }, { name => 'total' }, + { name => 'tbsname' }, { name => 'dbname' } ], closure_custom_output => $self->can('custom_usage_output'), - perfdatas => [ - { template => '%d', min => 0, max => 'total', cast_int => 1, label_extra_instance => 1 } - ] + closure_custom_perfdata => $self->can('custom_usage_perfdata') } }, { label => 'space-usage-free', nlabel => 'tablespace.space.free.bytes', display_ok => 0, set => { key_values => [ - { name => 'free' }, { name => 'used' }, { name => 'prct_used' }, { name => 'prct_free' }, { name => 'total' } + { name => 'free' }, { name => 'used' }, { name => 'prct_used' }, { name => 'prct_free' }, { name => 'total' }, + { name => 'tbsname' }, { name => 'dbname' } ], closure_custom_output => $self->can('custom_usage_output'), - perfdatas => [ - { template => '%d', min => 0, max => 'total', cast_int => 1, label_extra_instance => 1 } - ] + closure_custom_perfdata => $self->can('custom_usage_free_perfdata') } }, { label => 'space-usage-prct', nlabel => 'tablespace.space.usage.percentage', display_ok => 0, set => { key_values => [ - { name => 'prct_used' }, { name => 'used' }, { name => 'free' }, { name => 'prct_free' }, { name => 'total' } + { name => 'prct_used' }, { name => 'used' }, { name => 'free' }, { name => 'prct_free' }, { name => 'total' }, + { name => 'tbsname' }, { name => 'dbname' } ], closure_custom_output => $self->can('custom_usage_output'), - perfdatas => [ - { template => '%.2f', min => 0, max => 100, unit => '%', label_extra_instance => 1 } - ] + closure_custom_perfdata => $self->can('custom_usage_prct_perfdata') } } ]; @@ -189,6 +230,7 @@ sub manage_selection { }); $self->{tbs} = {}; + my $dbname = $options{sql}->get_database_name(); while (my $row = $options{sql}->fetchrow_arrayref()) { my $type = $row->[1] =~ /^[dD]/ ? 'dms' : 'sms'; @@ -198,7 +240,7 @@ sub manage_selection { next; } if (defined($self->{option_results}->{filter_type}) && $self->{option_results}->{filter_type} ne '' && - $row->[0] !~ /$self->{option_results}->{filter_type}/) { + $type !~ /$self->{option_results}->{filter_type}/) { $self->{output}->output_add(long_msg => "skipping tablespace '" . $row->[0] . "': no matching filter.", debug => 1); next; } @@ -210,7 +252,9 @@ sub manage_selection { } $self->{tbs}->{ $row->[0] } = { + dbname => $dbname, tbsname => $row->[0], + type => $type, state => $row->[2], total => $total, used => $used,