summaryrefslogtreecommitdiff
path: root/files/nagios/check_mysql_health
diff options
context:
space:
mode:
Diffstat (limited to 'files/nagios/check_mysql_health')
-rwxr-xr-xfiles/nagios/check_mysql_health3342
1 files changed, 0 insertions, 3342 deletions
diff --git a/files/nagios/check_mysql_health b/files/nagios/check_mysql_health
deleted file mode 100755
index f0599f2..0000000
--- a/files/nagios/check_mysql_health
+++ /dev/null
@@ -1,3342 +0,0 @@
-#! /usr/bin/perl -w
-# nagios: -epn
-
-my %ERRORS=( OK => 0, WARNING => 1, CRITICAL => 2, UNKNOWN => 3 );
-my %ERRORCODES=( 0 => 'OK', 1 => 'WARNING', 2 => 'CRITICAL', 3 => 'UNKNOWN' );
-package DBD::MySQL::Server::Instance::Innodb;
-
-use strict;
-
-our @ISA = qw(DBD::MySQL::Server::Instance);
-
-
-sub new {
- my $class = shift;
- my %params = @_;
- my $self = {
- handle => $params{handle},
- internals => undef,
- warningrange => $params{warningrange},
- criticalrange => $params{criticalrange},
- };
- bless $self, $class;
- $self->init(%params);
- return $self;
-}
-
-sub init {
- my $self = shift;
- my %params = @_;
- $self->init_nagios();
- if ($params{mode} =~ /server::instance::innodb/) {
- $self->{internals} =
- DBD::MySQL::Server::Instance::Innodb::Internals->new(%params);
- }
-}
-
-sub nagios {
- my $self = shift;
- my %params = @_;
- if ($params{mode} =~ /server::instance::innodb/) {
- $self->{internals}->nagios(%params);
- $self->merge_nagios($self->{internals});
- }
-}
-
-
-package DBD::MySQL::Server::Instance::Innodb::Internals;
-
-use strict;
-
-our @ISA = qw(DBD::MySQL::Server::Instance::Innodb);
-
-our $internals; # singleton, nur ein einziges mal instantiierbar
-
-sub new {
- my $class = shift;
- my %params = @_;
- unless ($internals) {
- $internals = {
- handle => $params{handle},
- bufferpool_hitrate => undef,
- wait_free => undef,
- log_waits => undef,
- warningrange => $params{warningrange},
- criticalrange => $params{criticalrange},
- };
- bless($internals, $class);
- $internals->init(%params);
- }
- return($internals);
-}
-
-sub init {
- my $self = shift;
- my %params = @_;
- my $dummy;
- $self->debug("enter init");
- $self->init_nagios();
- if ($params{mode} =~ /server::instance::innodb::bufferpool::hitrate/) {
- ($dummy, $self->{bufferpool_reads})
- = $self->{handle}->fetchrow_array(q{
- SHOW /*!50000 global */ STATUS LIKE 'Innodb_buffer_pool_reads'
- });
- ($dummy, $self->{bufferpool_read_requests})
- = $self->{handle}->fetchrow_array(q{
- SHOW /*!50000 global */ STATUS LIKE 'Innodb_buffer_pool_read_requests'
- });
- if (! defined $self->{bufferpool_reads}) {
- $self->add_nagios_critical("no innodb buffer pool info available");
- } else {
- $self->valdiff(\%params, qw(bufferpool_reads
- bufferpool_read_requests));
- $self->{bufferpool_hitrate_now} =
- $self->{delta_bufferpool_read_requests} > 0 ?
- 100 - (100 * $self->{delta_bufferpool_reads} /
- $self->{delta_bufferpool_read_requests}) : 100;
- $self->{bufferpool_hitrate} =
- $self->{bufferpool_read_requests} > 0 ?
- 100 - (100 * $self->{bufferpool_reads} /
- $self->{bufferpool_read_requests}) : 100;
- }
- } elsif ($params{mode} =~ /server::instance::innodb::bufferpool::waitfree/) {
- ($dummy, $self->{bufferpool_wait_free})
- = $self->{handle}->fetchrow_array(q{
- SHOW /*!50000 global */ STATUS LIKE 'Innodb_buffer_pool_wait_free'
- });
- if (! defined $self->{bufferpool_wait_free}) {
- $self->add_nagios_critical("no innodb buffer pool info available");
- } else {
- $self->valdiff(\%params, qw(bufferpool_wait_free));
- $self->{bufferpool_wait_free_rate} =
- $self->{delta_bufferpool_wait_free} / $self->{delta_timestamp};
- }
- } elsif ($params{mode} =~ /server::instance::innodb::logwaits/) {
- ($dummy, $self->{log_waits})
- = $self->{handle}->fetchrow_array(q{
- SHOW /*!50000 global */ STATUS LIKE 'Innodb_log_waits'
- });
- if (! defined $self->{log_waits}) {
- $self->add_nagios_critical("no innodb log info available");
- } else {
- $self->valdiff(\%params, qw(log_waits));
- $self->{log_waits_rate} =
- $self->{delta_log_waits} / $self->{delta_timestamp};
- }
- }
-}
-
-sub nagios {
- my $self = shift;
- my %params = @_;
- my $now = $params{lookback} ? '_now' : '';
- if (! $self->{nagios_level}) {
- if ($params{mode} =~ /server::instance::innodb::bufferpool::hitrate/) {
- my $refkey = 'bufferpool_hitrate'.($params{lookback} ? '_now' : '');
- $self->add_nagios(
- $self->check_thresholds($self->{$refkey}, "99:", "95:"),
- sprintf "innodb buffer pool hitrate at %.2f%%", $self->{$refkey});
- $self->add_perfdata(sprintf "bufferpool_hitrate=%.2f%%;%s;%s;0;100",
- $self->{bufferpool_hitrate},
- $self->{warningrange}, $self->{criticalrange});
- $self->add_perfdata(sprintf "bufferpool_hitrate_now=%.2f%%",
- $self->{bufferpool_hitrate_now});
- } elsif ($params{mode} =~ /server::instance::innodb::bufferpool::waitfree/) {
- $self->add_nagios(
- $self->check_thresholds($self->{bufferpool_wait_free_rate}, "1", "10"),
- sprintf "%ld innodb buffer pool waits in %ld seconds (%.4f/sec)",
- $self->{delta_bufferpool_wait_free}, $self->{delta_timestamp},
- $self->{bufferpool_wait_free_rate});
- $self->add_perfdata(sprintf "bufferpool_free_waits_rate=%.4f;%s;%s;0;100",
- $self->{bufferpool_wait_free_rate},
- $self->{warningrange}, $self->{criticalrange});
- } elsif ($params{mode} =~ /server::instance::innodb::logwaits/) {
- $self->add_nagios(
- $self->check_thresholds($self->{log_waits_rate}, "1", "10"),
- sprintf "%ld innodb log waits in %ld seconds (%.4f/sec)",
- $self->{delta_log_waits}, $self->{delta_timestamp},
- $self->{log_waits_rate});
- $self->add_perfdata(sprintf "innodb_log_waits_rate=%.4f;%s;%s;0;100",
- $self->{log_waits_rate},
- $self->{warningrange}, $self->{criticalrange});
- }
- }
-}
-
-
-
-
-package DBD::MySQL::Server::Instance::MyISAM;
-
-use strict;
-
-our @ISA = qw(DBD::MySQL::Server::Instance);
-
-
-sub new {
- my $class = shift;
- my %params = @_;
- my $self = {
- handle => $params{handle},
- internals => undef,
- warningrange => $params{warningrange},
- criticalrange => $params{criticalrange},
- };
- bless $self, $class;
- $self->init(%params);
- return $self;
-}
-
-sub init {
- my $self = shift;
- my %params = @_;
- $self->init_nagios();
- if ($params{mode} =~ /server::instance::myisam/) {
- $self->{internals} =
- DBD::MySQL::Server::Instance::MyISAM::Internals->new(%params);
- }
-}
-
-sub nagios {
- my $self = shift;
- my %params = @_;
- if ($params{mode} =~ /server::instance::myisam/) {
- $self->{internals}->nagios(%params);
- $self->merge_nagios($self->{internals});
- }
-}
-
-
-package DBD::MySQL::Server::Instance::MyISAM::Internals;
-
-use strict;
-
-our @ISA = qw(DBD::MySQL::Server::Instance::MyISAM);
-
-our $internals; # singleton, nur ein einziges mal instantiierbar
-
-sub new {
- my $class = shift;
- my %params = @_;
- unless ($internals) {
- $internals = {
- handle => $params{handle},
- keycache_hitrate => undef,
- warningrange => $params{warningrange},
- criticalrange => $params{criticalrange},
- };
- bless($internals, $class);
- $internals->init(%params);
- }
- return($internals);
-}
-
-sub init {
- my $self = shift;
- my %params = @_;
- my $dummy;
- $self->debug("enter init");
- $self->init_nagios();
- if ($params{mode} =~ /server::instance::myisam::keycache::hitrate/) {
- ($dummy, $self->{key_reads})
- = $self->{handle}->fetchrow_array(q{
- SHOW /*!50000 global */ STATUS LIKE 'Key_reads'
- });
- ($dummy, $self->{key_read_requests})
- = $self->{handle}->fetchrow_array(q{
- SHOW /*!50000 global */ STATUS LIKE 'Key_read_requests'
- });
- if (! defined $self->{key_read_requests}) {
- $self->add_nagios_critical("no myisam keycache info available");
- } else {
- $self->valdiff(\%params, qw(key_reads key_read_requests));
- $self->{keycache_hitrate} =
- $self->{key_read_requests} > 0 ?
- 100 - (100 * $self->{key_reads} /
- $self->{key_read_requests}) : 100;
- $self->{keycache_hitrate_now} =
- $self->{delta_key_read_requests} > 0 ?
- 100 - (100 * $self->{delta_key_reads} /
- $self->{delta_key_read_requests}) : 100;
- }
- } elsif ($params{mode} =~ /server::instance::myisam::sonstnochwas/) {
- }
-}
-
-sub nagios {
- my $self = shift;
- my %params = @_;
- if (! $self->{nagios_level}) {
- if ($params{mode} =~ /server::instance::myisam::keycache::hitrate/) {
- my $refkey = 'keycache_hitrate'.($params{lookback} ? '_now' : '');
- $self->add_nagios(
- $self->check_thresholds($self->{$refkey}, "99:", "95:"),
- sprintf "myisam keycache hitrate at %.2f%%", $self->{$refkey});
- $self->add_perfdata(sprintf "keycache_hitrate=%.2f%%;%s;%s",
- $self->{keycache_hitrate},
- $self->{warningrange}, $self->{criticalrange});
- $self->add_perfdata(sprintf "keycache_hitrate_now=%.2f%%;%s;%s",
- $self->{keycache_hitrate_now},
- $self->{warningrange}, $self->{criticalrange});
- }
- }
-}
-
-
-package DBD::MySQL::Server::Instance::Replication;
-
-use strict;
-
-our @ISA = qw(DBD::MySQL::Server::Instance);
-
-
-sub new {
- my $class = shift;
- my %params = @_;
- my $self = {
- handle => $params{handle},
- internals => undef,
- warningrange => $params{warningrange},
- criticalrange => $params{criticalrange},
- };
- bless $self, $class;
- $self->init(%params);
- return $self;
-}
-
-sub init {
- my $self = shift;
- my %params = @_;
- $self->init_nagios();
- if ($params{mode} =~ /server::instance::replication/) {
- $self->{internals} =
- DBD::MySQL::Server::Instance::Replication::Internals->new(%params);
- }
-}
-
-sub nagios {
- my $self = shift;
- my %params = @_;
- if ($params{mode} =~ /server::instance::replication/) {
- $self->{internals}->nagios(%params);
- $self->merge_nagios($self->{internals});
- }
-}
-
-
-package DBD::MySQL::Server::Instance::Replication::Internals;
-
-use strict;
-
-our @ISA = qw(DBD::MySQL::Server::Instance::Replication);
-
-our $internals; # singleton, nur ein einziges mal instantiierbar
-
-sub new {
- my $class = shift;
- my %params = @_;
- unless ($internals) {
- $internals = {
- handle => $params{handle},
- seconds_behind_master => undef,
- slave_io_running => undef,
- slave_sql_running => undef,
- warningrange => $params{warningrange},
- criticalrange => $params{criticalrange},
- };
- bless($internals, $class);
- $internals->init(%params);
- }
- return($internals);
-}
-
-sub init {
- my $self = shift;
- my %params = @_;
- $self->debug("enter init");
- $self->init_nagios();
- if ($params{mode} =~ /server::instance::replication::slavelag/) {
- # "show slave status", "Seconds_Behind_Master"
- my $slavehash = $self->{handle}->selectrow_hashref(q{
- SHOW SLAVE STATUS
- });
- if ((! defined $slavehash->{Seconds_Behind_Master}) &&
- (lc $slavehash->{Slave_IO_Running} eq 'no')) {
- $self->add_nagios_critical(
- "unable to get slave lag, because io thread is not running");
- } elsif (! defined $slavehash->{Seconds_Behind_Master}) {
- $self->add_nagios_critical(sprintf "unable to get replication info%s",
- $self->{handle}->{errstr} ? $self->{handle}->{errstr} : "");
- } else {
- $self->{seconds_behind_master} = $slavehash->{Seconds_Behind_Master};
- }
- } elsif ($params{mode} =~ /server::instance::replication::slaveiorunning/) {
- # "show slave status", "Slave_IO_Running"
- my $slavehash = $self->{handle}->selectrow_hashref(q{
- SHOW SLAVE STATUS
- });
- if (! defined $slavehash->{Slave_IO_Running}) {
- $self->add_nagios_critical(sprintf "unable to get replication info%s",
- $self->{handle}->{errstr} ? $self->{handle}->{errstr} : "");
- } else {
- $self->{slave_io_running} = $slavehash->{Slave_IO_Running};
- }
- } elsif ($params{mode} =~ /server::instance::replication::slavesqlrunning/) {
- # "show slave status", "Slave_SQL_Running"
- my $slavehash = $self->{handle}->selectrow_hashref(q{
- SHOW SLAVE STATUS
- });
- if (! defined $slavehash->{Slave_SQL_Running}) {
- $self->add_nagios_critical(sprintf "unable to get replication info%s",
- $self->{handle}->{errstr} ? $self->{handle}->{errstr} : "");
- } else {
- $self->{slave_sql_running} = $slavehash->{Slave_SQL_Running};
- }
- }
-}
-
-sub nagios {
- my $self = shift;
- my %params = @_;
- if (! $self->{nagios_level}) {
- if ($params{mode} =~ /server::instance::replication::slavelag/) {
- $self->add_nagios(
- $self->check_thresholds($self->{seconds_behind_master}, "10", "20"),
- sprintf "Slave is %d seconds behind master",
- $self->{seconds_behind_master});
- $self->add_perfdata(sprintf "slave_lag=%d;%s;%s",
- $self->{seconds_behind_master},
- $self->{warningrange}, $self->{criticalrange});
- } elsif ($params{mode} =~ /server::instance::replication::slaveiorunning/) {
- if (lc $self->{slave_io_running} eq "yes") {
- $self->add_nagios_ok("Slave io is running");
- } else {
- $self->add_nagios_critical("Slave io is not running");
- }
- } elsif ($params{mode} =~ /server::instance::replication::slavesqlrunning/) {
- if (lc $self->{slave_sql_running} eq "yes") {
- $self->add_nagios_ok("Slave sql is running");
- } else {
- $self->add_nagios_critical("Slave sql is not running");
- }
- }
- }
-}
-
-
-
-package DBD::MySQL::Server::Instance;
-
-use strict;
-
-our @ISA = qw(DBD::MySQL::Server);
-
-
-sub new {
- my $class = shift;
- my %params = @_;
- my $self = {
- handle => $params{handle},
- uptime => $params{uptime},
- warningrange => $params{warningrange},
- criticalrange => $params{criticalrange},
- threads_connected => undef,
- threads_created => undef,
- connections => undef,
- threadcache_hitrate => undef,
- querycache_hitrate => undef,
- lowmem_prunes_per_sec => undef,
- slow_queries_per_sec => undef,
- longrunners => undef,
- tablecache_hitrate => undef,
- index_usage => undef,
- engine_innodb => undef,
- engine_myisam => undef,
- replication => undef,
- };
- bless $self, $class;
- $self->init(%params);
- return $self;
-}
-
-sub init {
- my $self = shift;
- my %params = @_;
- my $dummy;
- $self->init_nagios();
- if ($params{mode} =~ /server::instance::connectedthreads/) {
- ($dummy, $self->{threads_connected}) = $self->{handle}->fetchrow_array(q{
- SHOW /*!50000 global */ STATUS LIKE 'Threads_connected'
- });
- } elsif ($params{mode} =~ /server::instance::threadcachehitrate/) {
- ($dummy, $self->{threads_created}) = $self->{handle}->fetchrow_array(q{
- SHOW /*!50000 global */ STATUS LIKE 'Threads_created'
- });
- ($dummy, $self->{connections}) = $self->{handle}->fetchrow_array(q{
- SHOW /*!50000 global */ STATUS LIKE 'Connections'
- });
- $self->valdiff(\%params, qw(threads_created connections));
- if ($self->{delta_connections} > 0) {
- $self->{threadcache_hitrate_now} =
- 100 - ($self->{delta_threads_created} * 100.0 /
- $self->{delta_connections});
- } else {
- $self->{threadcache_hitrate_now} = 100;
- }
- $self->{threadcache_hitrate} = 100 -
- ($self->{threads_created} * 100.0 / $self->{connections});
- $self->{connections_per_sec} = $self->{delta_connections} /
- $self->{delta_timestamp};
- } elsif ($params{mode} =~ /server::instance::querycachehitrate/) {
- ($dummy, $self->{com_select}) = $self->{handle}->fetchrow_array(q{
- SHOW /*!50000 global */ STATUS LIKE 'Com_select'
- });
- ($dummy, $self->{qcache_hits}) = $self->{handle}->fetchrow_array(q{
- SHOW /*!50000 global */ STATUS LIKE 'Qcache_hits'
- });
- # SHOW VARIABLES WHERE Variable_name = 'have_query_cache' for 5.x, but LIKE is compatible
- ($dummy, $self->{have_query_cache}) = $self->{handle}->fetchrow_array(q{
- SHOW VARIABLES LIKE 'have_query_cache'
- });
- # SHOW VARIABLES WHERE Variable_name = 'query_cache_size'
- ($dummy, $self->{query_cache_size}) = $self->{handle}->fetchrow_array(q{
- SHOW VARIABLES LIKE 'query_cache_size'
- });
- $self->valdiff(\%params, qw(com_select qcache_hits));
- $self->{querycache_hitrate_now} =
- ($self->{delta_com_select} + $self->{delta_qcache_hits}) > 0 ?
- 100 * $self->{delta_qcache_hits} /
- ($self->{delta_com_select} + $self->{delta_qcache_hits}) :
- 0;
- $self->{querycache_hitrate} =
- 100 * $self->{qcache_hits} / ($self->{com_select} + $self->{qcache_hits});
- $self->{selects_per_sec} =
- $self->{delta_com_select} / $self->{delta_timestamp};
- } elsif ($params{mode} =~ /server::instance::querycachelowmemprunes/) {
- ($dummy, $self->{lowmem_prunes}) = $self->{handle}->fetchrow_array(q{
- SHOW /*!50000 global */ STATUS LIKE 'Qcache_lowmem_prunes'
- });
- $self->valdiff(\%params, qw(lowmem_prunes));
- $self->{lowmem_prunes_per_sec} = $self->{delta_lowmem_prunes} /
- $self->{delta_timestamp};
- } elsif ($params{mode} =~ /server::instance::slowqueries/) {
- ($dummy, $self->{slow_queries}) = $self->{handle}->fetchrow_array(q{
- SHOW /*!50000 global */ STATUS LIKE 'Slow_queries'
- });
- $self->valdiff(\%params, qw(slow_queries));
- $self->{slow_queries_per_sec} = $self->{delta_slow_queries} /
- $self->{delta_timestamp};
- } elsif ($params{mode} =~ /server::instance::longprocs/) {
- if (DBD::MySQL::Server::return_first_server()->version_is_minimum("5.1")) {
- ($self->{longrunners}) = $self->{handle}->fetchrow_array(q{
- SELECT
- COUNT(*)
- FROM
- information_schema.processlist
- WHERE user <> 'replication'
- AND id <> CONNECTION_ID()
- AND time > 60
- AND command <> 'Sleep'
- });
- } else {
- $self->{longrunners} = 0 if ! defined $self->{longrunners};
- foreach ($self->{handle}->fetchall_array(q{
- SHOW PROCESSLIST
- })) {
- my($id, $user, $host, $db, $command, $tme, $state, $info) = @{$_};
- if (($user ne 'replication') &&
- ($tme > 60) &&
- ($command ne 'Sleep')) {
- $self->{longrunners}++;
- }
- }
- }
- } elsif ($params{mode} =~ /server::instance::tablecachehitrate/) {
- ($dummy, $self->{open_tables}) = $self->{handle}->fetchrow_array(q{
- SHOW /*!50000 global */ STATUS LIKE 'Open_tables'
- });
- ($dummy, $self->{opened_tables}) = $self->{handle}->fetchrow_array(q{
- SHOW /*!50000 global */ STATUS LIKE 'Opened_tables'
- });
- if (DBD::MySQL::Server::return_first_server()->version_is_minimum("5.1.3")) {
- # SHOW VARIABLES WHERE Variable_name = 'table_open_cache'
- ($dummy, $self->{table_cache}) = $self->{handle}->fetchrow_array(q{
- SHOW VARIABLES LIKE 'table_open_cache'
- });
- } else {
- # SHOW VARIABLES WHERE Variable_name = 'table_cache'
- ($dummy, $self->{table_cache}) = $self->{handle}->fetchrow_array(q{
- SHOW VARIABLES LIKE 'table_cache'
- });
- }
- $self->{table_cache} ||= 0;
- #$self->valdiff(\%params, qw(open_tables opened_tables table_cache));
- # _now ist hier sinnlos, da opened_tables waechst, aber open_tables wieder
- # schrumpfen kann weil tabellen geschlossen werden.
- if ($self->{opened_tables} != 0 && $self->{table_cache} != 0) {
- $self->{tablecache_hitrate} =
- 100 * $self->{open_tables} / $self->{opened_tables};
- $self->{tablecache_fillrate} =
- 100 * $self->{open_tables} / $self->{table_cache};
- } elsif ($self->{opened_tables} == 0 && $self->{table_cache} != 0) {
- $self->{tablecache_hitrate} = 100;
- $self->{tablecache_fillrate} =
- 100 * $self->{open_tables} / $self->{table_cache};
- } else {
- $self->{tablecache_hitrate} = 0;
- $self->{tablecache_fillrate} = 0;
- $self->add_nagios_critical("no table cache");
- }
- } elsif ($params{mode} =~ /server::instance::tablelockcontention/) {
- ($dummy, $self->{table_locks_waited}) = $self->{handle}->fetchrow_array(q{
- SHOW /*!50000 global */ STATUS LIKE 'Table_locks_waited'
- });
- ($dummy, $self->{table_locks_immediate}) = $self->{handle}->fetchrow_array(q{
- SHOW /*!50000 global */ STATUS LIKE 'Table_locks_immediate'
- });
- $self->valdiff(\%params, qw(table_locks_waited table_locks_immediate));
- $self->{table_lock_contention} =
- ($self->{table_locks_waited} + $self->{table_locks_immediate}) > 0 ?
- 100 * $self->{table_locks_waited} /
- ($self->{table_locks_waited} + $self->{table_locks_immediate}) :
- 100;
- $self->{table_lock_contention_now} =
- ($self->{delta_table_locks_waited} + $self->{delta_table_locks_immediate}) > 0 ?
- 100 * $self->{delta_table_locks_waited} /
- ($self->{delta_table_locks_waited} + $self->{delta_table_locks_immediate}) :
- 100;
- } elsif ($params{mode} =~ /server::instance::tableindexusage/) {
- # http://johnjacobm.wordpress.com/2007/06/
- # formula for calculating the percentage of full table scans
- ($dummy, $self->{handler_read_first}) = $self->{handle}->fetchrow_array(q{
- SHOW /*!50000 global */ STATUS LIKE 'Handler_read_first'
- });
- ($dummy, $self->{handler_read_key}) = $self->{handle}->fetchrow_array(q{
- SHOW /*!50000 global */ STATUS LIKE 'Handler_read_key'
- });
- ($dummy, $self->{handler_read_next}) = $self->{handle}->fetchrow_array(q{
- SHOW /*!50000 global */ STATUS LIKE 'Handler_read_next'
- });
- ($dummy, $self->{handler_read_prev}) = $self->{handle}->fetchrow_array(q{
- SHOW /*!50000 global */ STATUS LIKE 'Handler_read_prev'
- });
- ($dummy, $self->{handler_read_rnd}) = $self->{handle}->fetchrow_array(q{
- SHOW /*!50000 global */ STATUS LIKE 'Handler_read_rnd'
- });
- ($dummy, $self->{handler_read_rnd_next}) = $self->{handle}->fetchrow_array(q{
- SHOW /*!50000 global */ STATUS LIKE 'Handler_read_rnd_next'
- });
- $self->valdiff(\%params, qw(handler_read_first handler_read_key
- handler_read_next handler_read_prev handler_read_rnd
- handler_read_rnd_next));
- $self->{index_usage_now} = 100 - (100.0 * ($self->{delta_handler_read_rnd} +
- $self->{delta_handler_read_rnd_next}) /
- ($self->{delta_handler_read_first} +
- $self->{delta_handler_read_key} +
- $self->{delta_handler_read_next} +
- $self->{delta_handler_read_prev} +
- $self->{delta_handler_read_rnd} +
- $self->{delta_handler_read_rnd_next}));
- $self->{index_usage} = 100 - (100.0 * ($self->{handler_read_rnd} +
- $self->{handler_read_rnd_next}) /
- ($self->{handler_read_first} +
- $self->{handler_read_key} +
- $self->{handler_read_next} +
- $self->{handler_read_prev} +
- $self->{handler_read_rnd} +
- $self->{handler_read_rnd_next}));
- } elsif ($params{mode} =~ /server::instance::tabletmpondisk/) {
- ($dummy, $self->{created_tmp_tables}) = $self->{handle}->fetchrow_array(q{
- SHOW /*!50000 global */ STATUS LIKE 'Created_tmp_tables'
- });
- ($dummy, $self->{created_tmp_disk_tables}) = $self->{handle}->fetchrow_array(q{
- SHOW /*!50000 global */ STATUS LIKE 'Created_tmp_disk_tables'
- });
- $self->valdiff(\%params, qw(created_tmp_tables created_tmp_disk_tables));
- $self->{pct_tmp_on_disk} = $self->{created_tmp_tables} > 0 ?
- 100 * $self->{created_tmp_disk_tables} / $self->{created_tmp_tables} :
- 100;
- $self->{pct_tmp_on_disk_now} = $self->{delta_created_tmp_tables} > 0 ?
- 100 * $self->{delta_created_tmp_disk_tables} / $self->{delta_created_tmp_tables} :
- 100;
- } elsif ($params{mode} =~ /server::instance::openfiles/) {
- ($dummy, $self->{open_files_limit}) = $self->{handle}->fetchrow_array(q{
- SHOW VARIABLES LIKE 'open_files_limit'
- });
- ($dummy, $self->{open_files}) = $self->{handle}->fetchrow_array(q{
- SHOW /*!50000 global */ STATUS LIKE 'Open_files'
- });
- $self->{pct_open_files} = 100 * $self->{open_files} / $self->{open_files_limit};
- } elsif ($params{mode} =~ /server::instance::myisam/) {
- $self->{engine_myisam} = DBD::MySQL::Server::Instance::MyISAM->new(
- %params
- );
- } elsif ($params{mode} =~ /server::instance::innodb/) {
- $self->{engine_innodb} = DBD::MySQL::Server::Instance::Innodb->new(
- %params
- );
- } elsif ($params{mode} =~ /server::instance::replication/) {
- $self->{replication} = DBD::MySQL::Server::Instance::Replication->new(
- %params
- );
- }
-}
-
-sub nagios {
- my $self = shift;
- my %params = @_;
- if (! $self->{nagios_level}) {
- if ($params{mode} =~ /server::instance::connectedthreads/) {
- $self->add_nagios(
- $self->check_thresholds($self->{threads_connected}, 10, 20),
- sprintf "%d client connection threads", $self->{threads_connected});
- $self->add_perfdata(sprintf "threads_connected=%d;%d;%d",
- $self->{threads_connected},
- $self->{warningrange}, $self->{criticalrange});
- } elsif ($params{mode} =~ /server::instance::threadcachehitrate/) {
- my $refkey = 'threadcache_hitrate'.($params{lookback} ? '_now' : '');
- $self->add_nagios(
- $self->check_thresholds($self->{$refkey}, "90:", "80:"),
- sprintf "thread cache hitrate %.2f%%", $self->{$refkey});
- $self->add_perfdata(sprintf "thread_cache_hitrate=%.2f%%;%s;%s",
- $self->{threadcache_hitrate},
- $self->{warningrange}, $self->{criticalrange});
- $self->add_perfdata(sprintf "thread_cache_hitrate_now=%.2f%%",
- $self->{threadcache_hitrate_now});
- $self->add_perfdata(sprintf "connections_per_sec=%.2f",
- $self->{connections_per_sec});
- } elsif ($params{mode} =~ /server::instance::querycachehitrate/) {
- my $refkey = 'querycache_hitrate'.($params{lookback} ? '_now' : '');
- if ((lc $self->{have_query_cache} eq 'yes') && ($self->{query_cache_size})) {
- $self->add_nagios(
- $self->check_thresholds($self->{$refkey}, "90:", "80:"),
- sprintf "query cache hitrate %.2f%%", $self->{$refkey});
- } else {
- $self->check_thresholds($self->{$refkey}, "90:", "80:");
- $self->add_nagios_ok(
- sprintf "query cache hitrate %.2f%% (because it's turned off)",
- $self->{querycache_hitrate});
- }
- $self->add_perfdata(sprintf "qcache_hitrate=%.2f%%;%s;%s",
- $self->{querycache_hitrate},
- $self->{warningrange}, $self->{criticalrange});
- $self->add_perfdata(sprintf "qcache_hitrate_now=%.2f%%",
- $self->{querycache_hitrate_now});
- $self->add_perfdata(sprintf "selects_per_sec=%.2f",
- $self->{selects_per_sec});
- } elsif ($params{mode} =~ /server::instance::querycachelowmemprunes/) {
- $self->add_nagios(
- $self->check_thresholds($self->{lowmem_prunes_per_sec}, "1", "10"),
- sprintf "%d query cache lowmem prunes in %d seconds (%.2f/sec)",
- $self->{delta_lowmem_prunes}, $self->{delta_timestamp},
- $self->{lowmem_prunes_per_sec});
- $self->add_perfdata(sprintf "qcache_lowmem_prunes_rate=%.2f;%s;%s",
- $self->{lowmem_prunes_per_sec},
- $self->{warningrange}, $self->{criticalrange});
- } elsif ($params{mode} =~ /server::instance::slowqueries/) {
- $self->add_nagios(
- $self->check_thresholds($self->{slow_queries_per_sec}, "0.1", "1"),
- sprintf "%d slow queries in %d seconds (%.2f/sec)",
- $self->{delta_slow_queries}, $self->{delta_timestamp},
- $self->{slow_queries_per_sec});
- $self->add_perfdata(sprintf "slow_queries_rate=%.2f%%;%s;%s",
- $self->{slow_queries_per_sec},
- $self->{warningrange}, $self->{criticalrange});
- } elsif ($params{mode} =~ /server::instance::longprocs/) {
- $self->add_nagios(
- $self->check_thresholds($self->{longrunners}, 10, 20),
- sprintf "%d long running processes", $self->{longrunners});
- $self->add_perfdata(sprintf "long_running_procs=%d;%d;%d",
- $self->{longrunners},
- $self->{warningrange}, $self->{criticalrange});
- } elsif ($params{mode} =~ /server::instance::tablecachehitrate/) {
- if ($self->{tablecache_fillrate} < 95) {
- $self->add_nagios_ok(
- sprintf "table cache hitrate %.2f%%, %.2f%% filled",
- $self->{tablecache_hitrate},
- $self->{tablecache_fillrate});
- $self->check_thresholds($self->{tablecache_hitrate}, "99:", "95:");
- } else {
- $self->add_nagios(
- $self->check_thresholds($self->{tablecache_hitrate}, "99:", "95:"),
- sprintf "table cache hitrate %.2f%%", $self->{tablecache_hitrate});
- }
- $self->add_perfdata(sprintf "tablecache_hitrate=%.2f%%;%s;%s",
- $self->{tablecache_hitrate},
- $self->{warningrange}, $self->{criticalrange});
- $self->add_perfdata(sprintf "tablecache_fillrate=%.2f%%",
- $self->{tablecache_fillrate});
- } elsif ($params{mode} =~ /server::instance::tablelockcontention/) {
- my $refkey = 'table_lock_contention'.($params{lookback} ? '_now' : '');
- if ($self->{uptime} > 10800) { # MySQL Bug #30599
- $self->add_nagios(
- $self->check_thresholds($self->{$refkey}, "1", "2"),
- sprintf "table lock contention %.2f%%", $self->{$refkey});
- } else {
- $self->check_thresholds($self->{$refkey}, "1", "2");
- $self->add_nagios_ok(
- sprintf "table lock contention %.2f%% (uptime < 10800)",
- $self->{refkey});
- }
- $self->add_perfdata(sprintf "tablelock_contention=%.2f%%;%s;%s",
- $self->{table_lock_contention},
- $self->{warningrange}, $self->{criticalrange});
- $self->add_perfdata(sprintf "tablelock_contention_now=%.2f%%",
- $self->{table_lock_contention_now});
- } elsif ($params{mode} =~ /server::instance::tableindexusage/) {
- my $refkey = 'index_usage'.($params{lookback} ? '_now' : '');
- $self->add_nagios(
- $self->check_thresholds($self->{$refkey}, "90:", "80:"),
- sprintf "index usage %.2f%%", $self->{$refkey});
- $self->add_perfdata(sprintf "index_usage=%.2f%%;%s;%s",
- $self->{index_usage},
- $self->{warningrange}, $self->{criticalrange});
- $self->add_perfdata(sprintf "index_usage_now=%.2f%%",
- $self->{index_usage_now});
- } elsif ($params{mode} =~ /server::instance::tabletmpondisk/) {
- my $refkey = 'pct_tmp_on_disk'.($params{lookback} ? '_now' : '');
- $self->add_nagios(
- $self->check_thresholds($self->{$refkey}, "25", "50"),
- sprintf "%.2f%% of %d tables were created on disk",
- $self->{$refkey}, $self->{delta_created_tmp_tables});
- $self->add_perfdata(sprintf "pct_tmp_table_on_disk=%.2f%%;%s;%s",
- $self->{pct_tmp_on_disk},
- $self->{warningrange}, $self->{criticalrange});
- $self->add_perfdata(sprintf "pct_tmp_table_on_disk_now=%.2f%%",
- $self->{pct_tmp_on_disk_now});
- } elsif ($params{mode} =~ /server::instance::openfiles/) {
- $self->add_nagios(
- $self->check_thresholds($self->{pct_open_files}, 80, 95),
- sprintf "%.2f%% of the open files limit reached (%d of max. %d)",
- $self->{pct_open_files},
- $self->{open_files}, $self->{open_files_limit});
- $self->add_perfdata(sprintf "pct_open_files=%.3f%%;%.3f;%.3f",
- $self->{pct_open_files},
- $self->{warningrange},
- $self->{criticalrange});
- $self->add_perfdata(sprintf "open_files=%d;%d;%d",
- $self->{open_files},
- $self->{open_files_limit} * $self->{warningrange} / 100,
- $self->{open_files_limit} * $self->{criticalrange} / 100);
- } elsif ($params{mode} =~ /server::instance::myisam/) {
- $self->{engine_myisam}->nagios(%params);
- $self->merge_nagios($self->{engine_myisam});
- } elsif ($params{mode} =~ /server::instance::innodb/) {
- $self->{engine_innodb}->nagios(%params);
- $self->merge_nagios($self->{engine_innodb});
- } elsif ($params{mode} =~ /server::instance::replication/) {
- $self->{replication}->nagios(%params);
- $self->merge_nagios($self->{replication});
- }
- }
-}
-
-
-
-package DBD::MySQL::Server;
-
-use strict;
-use Time::HiRes;
-use IO::File;
-use File::Copy 'cp';
-use Data::Dumper;
-
-
-{
- our $verbose = 0;
- our $scream = 0; # scream if something is not implemented
- our $access = "dbi"; # how do we access the database.
- our $my_modules_dyn_dir = ""; # where we look for self-written extensions
-
- my @servers = ();
- my $initerrors = undef;
-
- sub add_server {
- push(@servers, shift);
- }
-
- sub return_servers {
- return @servers;
- }
-
- sub return_first_server() {
- return $servers[0];
- }
-
-}
-
-sub new {
- my $class = shift;
- my %params = @_;
- my $self = {
- access => $params{method} || 'dbi',
- hostname => $params{hostname},
- database => $params{database} || 'information_schema',
- port => $params{port},
- socket => $params{socket},
- username => $params{username},
- password => $params{password},
- timeout => $params{timeout},
- warningrange => $params{warningrange},
- criticalrange => $params{criticalrange},
- version => 'unknown',
- instance => undef,
- handle => undef,
- };
- bless $self, $class;
- $self->init_nagios();
- if ($self->dbconnect(%params)) {
- ($self->{dummy}, $self->{version}) = $self->{handle}->fetchrow_array(
- #q{ SHOW VARIABLES WHERE Variable_name = 'version' }
- q{ SHOW VARIABLES LIKE 'version' }
- );
- $self->{version} = (split "-", $self->{version})[0];
- ($self->{dummy}, $self->{uptime}) = $self->{handle}->fetchrow_array(
- q{ SHOW STATUS LIKE 'Uptime' }
- );
- DBD::MySQL::Server::add_server($self);
- $self->init(%params);
- }
- return $self;
-}
-
-sub init {
- my $self = shift;
- my %params = @_;
- $params{handle} = $self->{handle};
- $params{uptime} = $self->{uptime};
- if ($params{mode} =~ /^server::instance/) {
- $self->{instance} = DBD::MySQL::Server::Instance->new(%params);
- } elsif ($params{mode} =~ /^server::sql/) {
- $self->{genericsql} = $self->{handle}->fetchrow_array($params{selectname});
- if ($self->{genericsql} =~ /^\s*\d+\s*$/) {
- $self->{genericsql} = sprintf "%d", $self->{genericsql};
- } elsif ($self->{genericsql} =~ /^\s*\d*\.\d+\s*$/) {
- $self->{genericsql} = sprintf "%.2f", $self->{genericsql};
- } else {
- $self->add_nagios_unknown(sprintf "got no valid response for %s",
- $params{selectname});
- }
- } elsif ($params{mode} =~ /^server::uptime/) {
- # already set with the connection. but use minutes here
- } elsif ($params{mode} =~ /^server::connectiontime/) {
- $self->{connection_time} = $self->{tac} - $self->{tic};
- } elsif ($params{mode} =~ /^my::([^:.]+)/) {
- my $class = $1;
- my $loaderror = undef;
- substr($class, 0, 1) = uc substr($class, 0, 1);
- foreach my $libpath (split(":", $DBD::MySQL::Server::my_modules_dyn_dir)) {
- foreach my $extmod (glob $libpath."/CheckMySQLHealth*.pm") {
- eval {
- $self->trace(sprintf "loading module %s", $extmod);
- require $extmod;
- };
- if ($@) {
- $loaderror = $extmod;
- $self->trace(sprintf "failed loading module %s: %s", $extmod, $@);
- }
- }
- }
- my $obj = {
- handle => $params{handle},
- warningrange => $params{warningrange},
- criticalrange => $params{criticalrange},
- };
- bless $obj, "My$class";
- $self->{my} = $obj;
- if ($self->{my}->isa("DBD::MySQL::Server")) {
- my $dos_init = $self->can("init");
- my $dos_nagios = $self->can("nagios");
- my $my_init = $self->{my}->can("init");
- my $my_nagios = $self->{my}->can("nagios");
- if ($my_init == $dos_init) {
- $self->add_nagios_unknown(
- sprintf "Class %s needs an init() method", ref($self->{my}));
- } elsif ($my_nagios == $dos_nagios) {
- $self->add_nagios_unknown(
- sprintf "Class %s needs a nagios() method", ref($self->{my}));
- } else {
- $self->{my}->init_nagios(%params);
- $self->{my}->init(%params);
- }
- } else {
- $self->add_nagios_unknown(
- sprintf "Class %s is not a subclass of DBD::MySQL::Server%s",
- ref($self->{my}),
- $loaderror ? sprintf " (syntax error in %s?)", $loaderror : "" );
- }
- } else {
- printf "broken mode %s\n", $params{mode};
- }
-}
-
-sub dump {
- my $self = shift;
- my $message = shift || "";
- printf "%s %s\n", $message, Data::Dumper::Dumper($self);
-}
-
-sub nagios {
- my $self = shift;
- my %params = @_;
- if (! $self->{nagios_level}) {
- if ($params{mode} =~ /^server::instance/) {
- $self->{instance}->nagios(%params);
- $self->merge_nagios($self->{instance});
- } elsif ($params{mode} =~ /^server::database/) {
- $self->{database}->nagios(%params);
- $self->merge_nagios($self->{database});
- } elsif ($params{mode} =~ /^server::uptime/) {
- $self->add_nagios(
- $self->check_thresholds($self->{uptime} / 60, "10:", "5:"),
- sprintf "database is up since %d minutes", $self->{uptime} / 60);
- $self->add_perfdata(sprintf "uptime=%ds",
- $self->{uptime});
- } elsif ($params{mode} =~ /^server::connectiontime/) {
- $self->add_nagios(
- $self->check_thresholds($self->{connection_time}, 1, 5),
- sprintf "%.2f seconds to connect as %s",
- $self->{connection_time}, ($self->{username} || getpwuid($<)));
- $self->add_perfdata(sprintf "connection_time=%.4fs;%d;%d",
- $self->{connection_time},
- $self->{warningrange}, $self->{criticalrange});
- } elsif ($params{mode} =~ /^server::sql/) {
- $self->add_nagios(
- $self->check_thresholds($self->{genericsql}, 1, 5),
- sprintf "%s: %s%s",
- $params{name2} ? lc $params{name2} : lc $params{selectname},
- $self->{genericsql},
- $params{units} ? $params{units} : "");
- $self->add_perfdata(sprintf "\'%s\'=%s%s;%s;%s",
- $params{name2} ? lc $params{name2} : lc $params{selectname},
- $self->{genericsql},
- $params{units} ? $params{units} : "",
- $self->{warningrange}, $self->{criticalrange});
- } elsif ($params{mode} =~ /^my::([^:.]+)/) {
- $self->{my}->nagios(%params);
- $self->merge_nagios($self->{my});
- }
- }
-}
-
-
-sub init_nagios {
- my $self = shift;
- no strict 'refs';
- if (! ref($self)) {
- my $nagiosvar = $self."::nagios";
- my $nagioslevelvar = $self."::nagios_level";
- $$nagiosvar = {
- messages => {
- 0 => [],
- 1 => [],
- 2 => [],
- 3 => [],
- },
- perfdata => [],
- };
- $$nagioslevelvar = $ERRORS{OK},
- } else {
- $self->{nagios} = {
- messages => {
- 0 => [],
- 1 => [],
- 2 => [],
- 3 => [],
- },
- perfdata => [],
- };
- $self->{nagios_level} = $ERRORS{OK},
- }
-}
-
-sub check_thresholds {
- my $self = shift;
- my $value = shift;
- my $defaultwarningrange = shift;
- my $defaultcriticalrange = shift;
- my $level = $ERRORS{OK};
- $self->{warningrange} = defined $self->{warningrange} ?
- $self->{warningrange} : $defaultwarningrange;
- $self->{criticalrange} = defined $self->{criticalrange} ?
- $self->{criticalrange} : $defaultcriticalrange;
- if ($self->{warningrange} !~ /:/ && $self->{criticalrange} !~ /:/) {
- # warning = 10, critical = 20, warn if > 10, crit if > 20
- $level = $ERRORS{WARNING} if $value > $self->{warningrange};
- $level = $ERRORS{CRITICAL} if $value > $self->{criticalrange};
- } elsif ($self->{warningrange} =~ /([\d\.]+):/ &&
- $self->{criticalrange} =~ /([\d\.]+):/) {
- # warning = 98:, critical = 95:, warn if < 98, crit if < 95
- $self->{warningrange} =~ /([\d\.]+):/;
- $level = $ERRORS{WARNING} if $value < $1;
- $self->{criticalrange} =~ /([\d\.]+):/;
- $level = $ERRORS{CRITICAL} if $value < $1;
- }
- return $level;
- #
- # syntax error must be reported with returncode -1
- #
-}
-
-sub add_nagios {
- my $self = shift;
- my $level = shift;
- my $message = shift;
- push(@{$self->{nagios}->{messages}->{$level}}, $message);
- # recalc current level
- foreach my $llevel qw(CRITICAL WARNING UNKNOWN OK) {
- if (scalar(@{$self->{nagios}->{messages}->{$ERRORS{$llevel}}})) {
- $self->{nagios_level} = $ERRORS{$llevel};
- }
- }
-}
-
-sub add_nagios_ok {
- my $self = shift;
- my $message = shift;
- $self->add_nagios($ERRORS{OK}, $message);
-}
-
-sub add_nagios_warning {
- my $self = shift;
- my $message = shift;
- $self->add_nagios($ERRORS{WARNING}, $message);
-}
-
-sub add_nagios_critical {
- my $self = shift;
- my $message = shift;
- $self->add_nagios($ERRORS{CRITICAL}, $message);
-}
-
-sub add_nagios_unknown {
- my $self = shift;
- my $message = shift;
- $self->add_nagios($ERRORS{UNKNOWN}, $message);
-}
-
-sub add_perfdata {
- my $self = shift;
- my $data = shift;
- push(@{$self->{nagios}->{perfdata}}, $data);
-}
-
-sub merge_nagios {
- my $self = shift;
- my $child = shift;
- foreach my $level (0..3) {
- foreach (@{$child->{nagios}->{messages}->{$level}}) {
- $self->add_nagios($level, $_);
- }
- #push(@{$self->{nagios}->{messages}->{$level}},
- # @{$child->{nagios}->{messages}->{$level}});
- }
- push(@{$self->{nagios}->{perfdata}}, @{$child->{nagios}->{perfdata}});
-}
-
-
-sub calculate_result {
- my $self = shift;
- if ($ENV{NRPE_MULTILINESUPPORT} &&
- length join(" ", @{$self->{nagios}->{perfdata}}) > 200) {
- foreach my $level ("CRITICAL", "WARNING", "UNKNOWN", "OK") {
- # first the bad news
- if (scalar(@{$self->{nagios}->{messages}->{$ERRORS{$level}}})) {
- $self->{nagios_message} .=
- "\n".join("\n", @{$self->{nagios}->{messages}->{$ERRORS{$level}}});
- }
- }
- $self->{nagios_message} =~ s/^\n//g;
- $self->{perfdata} = join("\n", @{$self->{nagios}->{perfdata}});
- } else {
- foreach my $level ("CRITICAL", "WARNING", "UNKNOWN", "OK") {
- # first the bad news
- if (scalar(@{$self->{nagios}->{messages}->{$ERRORS{$level}}})) {
- $self->{nagios_message} .=
- join(", ", @{$self->{nagios}->{messages}->{$ERRORS{$level}}}).", ";
- }
- }
- $self->{nagios_message} =~ s/, $//g;
- $self->{perfdata} = join(" ", @{$self->{nagios}->{perfdata}});
- }
- foreach my $level ("OK", "UNKNOWN", "WARNING", "CRITICAL") {
- if (scalar(@{$self->{nagios}->{messages}->{$ERRORS{$level}}})) {
- $self->{nagios_level} = $ERRORS{$level};
- }
- }
-}
-
-sub debug {
- my $self = shift;
- my $msg = shift;
- if ($DBD::MySQL::Server::verbose) {
- printf "%s %s\n", $msg, ref($self);
- }
-}
-
-sub dbconnect {
- my $self = shift;
- my %params = @_;
- my $retval = undef;
- $self->{tic} = Time::HiRes::time();
- $self->{handle} = DBD::MySQL::Server::Connection->new(%params);
- if ($self->{handle}->{errstr}) {
- if ($params{mode} =~ /^server::tnsping/ &&
- $self->{handle}->{errstr} =~ /ORA-01017/) {
- $self->add_nagios($ERRORS{OK},
- sprintf "connection established to %s.", $self->{connect});
- $retval = undef;
- } elsif ($self->{handle}->{errstr} eq "alarm\n") {
- $self->add_nagios($ERRORS{CRITICAL},
- sprintf "connection could not be established within %d seconds",
- $self->{timeout});
- } else {
- $self->add_nagios($ERRORS{CRITICAL},
- sprintf "cannot connect to %s. %s",
- $self->{database}, $self->{handle}->{errstr});
- $retval = undef;
- }
- } else {
- $retval = $self->{handle};
- }
- $self->{tac} = Time::HiRes::time();
- return $retval;
-}
-
-sub trace {
- my $self = shift;
- my $format = shift;
- $self->{trace} = -f "/tmp/check_mysql_health.trace" ? 1 : 0;
- if ($self->{verbose}) {
- printf("%s: ", scalar localtime);
- printf($format, @_);
- }
- if ($self->{trace}) {
- my $logfh = new IO::File;
- $logfh->autoflush(1);
- if ($logfh->open("/tmp/check_mysql_health.trace", "a")) {
- $logfh->printf("%s: ", scalar localtime);
- $logfh->printf($format, @_);
- $logfh->printf("\n");
- $logfh->close();
- }
- }
-}
-
-sub DESTROY {
- my $self = shift;
- my $handle1 = "null";
- my $handle2 = "null";
- if (defined $self->{handle}) {
- $handle1 = ref($self->{handle});
- if (defined $self->{handle}->{handle}) {
- $handle2 = ref($self->{handle}->{handle});
- }
- }
- $self->trace(sprintf "DESTROY %s with handle %s %s", ref($self), $handle1, $handle2);
- if (ref($self) eq "DBD::MySQL::Server") {
- }
- $self->trace(sprintf "DESTROY %s exit with handle %s %s", ref($self), $handle1, $handle2);
- if (ref($self) eq "DBD::MySQL::Server") {
- #printf "humpftata\n";
- }
-}
-
-sub save_state {
- my $self = shift;
- my %params = @_;
- my $extension = "";
- mkdir $params{statefilesdir} unless -d $params{statefilesdir};
- my $statefile = sprintf "%s/%s_%s",
- $params{statefilesdir}, $params{hostname}, $params{mode};
- $extension .= $params{differenciator} ? "_".$params{differenciator} : "";
- $extension .= $params{socket} ? "_".$params{socket} : "";
- $extension .= $params{port} ? "_".$params{port} : "";
- $extension .= $params{database} ? "_".$params{database} : "";
- $extension .= $params{tablespace} ? "_".$params{tablespace} : "";
- $extension .= $params{datafile} ? "_".$params{datafile} : "";
- $extension .= $params{name} ? "_".$params{name} : "";
- $extension =~ s/\//_/g;
- $extension =~ s/\(/_/g;
- $extension =~ s/\)/_/g;
- $extension =~ s/\*/_/g;
- $extension =~ s/\s/_/g;
- $statefile .= $extension;
- $statefile = lc $statefile;
- open(STATE, ">$statefile");
- if ((ref($params{save}) eq "HASH") && exists $params{save}->{timestamp}) {
- $params{save}->{localtime} = scalar localtime $params{save}->{timestamp};
- }
- printf STATE Data::Dumper::Dumper($params{save});
- close STATE;
- $self->debug(sprintf "saved %s to %s",
- Data::Dumper::Dumper($params{save}), $statefile);
-}
-
-sub load_state {
- my $self = shift;
- my %params = @_;
- my $extension = "";
- my $statefile = sprintf "%s/%s_%s",
- $params{statefilesdir}, $params{hostname}, $params{mode};
- $extension .= $params{differenciator} ? "_".$params{differenciator} : "";
- $extension .= $params{socket} ? "_".$params{socket} : "";
- $extension .= $params{port} ? "_".$params{port} : "";
- $extension .= $params{database} ? "_".$params{database} : "";
- $extension .= $params{tablespace} ? "_".$params{tablespace} : "";
- $extension .= $params{datafile} ? "_".$params{datafile} : "";
- $extension .= $params{name} ? "_".$params{name} : "";
- $extension =~ s/\//_/g;
- $extension =~ s/\(/_/g;
- $extension =~ s/\)/_/g;
- $extension =~ s/\*/_/g;
- $extension =~ s/\s/_/g;
- $statefile .= $extension;
- $statefile = lc $statefile;
- if ( -f $statefile) {
- our $VAR1;
- eval {
- require $statefile;
- };
- if($@) {
-printf "rumms\n";
- }
- $self->debug(sprintf "load %s", Data::Dumper::Dumper($VAR1));
- return $VAR1;
- } else {
- return undef;
- }
-}
-
-sub valdiff {
- my $self = shift;
- my $pparams = shift;
- my %params = %{$pparams};
- my @keys = @_;
- my $now = time;
- my $last_values = $self->load_state(%params) || eval {
- my $empty_events = {};
- foreach (@keys) {
- $empty_events->{$_} = 0;
- }
- $empty_events->{timestamp} = 0;
- if ($params{lookback}) {
- $empty_events->{lookback_history} = {};
- }
- $empty_events;
- };
- foreach (@keys) {
- if ($params{lookback}) {
- # find a last_value in the history which fits lookback best
- # and overwrite $last_values->{$_} with historic data
- if (exists $last_values->{lookback_history}->{$_}) {
- foreach my $date (sort {$a <=> $b} keys %{$last_values->{lookback_history}->{$_}}) {
- if ($date >= ($now - $params{lookback})) {
- $last_values->{$_} = $last_values->{lookback_history}->{$_}->{$date};
- $last_values->{timestamp} = $date;
- last;
- } else {
- delete $last_values->{lookback_history}->{$_}->{$date};
- }
- }
- }
- }
- $last_values->{$_} = 0 if ! exists $last_values->{$_};
- if ($self->{$_} >= $last_values->{$_}) {
- $self->{'delta_'.$_} = $self->{$_} - $last_values->{$_};
- } else {
- # vermutlich db restart und zaehler alle auf null
- $self->{'delta_'.$_} = $self->{$_};
- }
- $self->debug(sprintf "delta_%s %f", $_, $self->{'delta_'.$_});
- }
- $self->{'delta_timestamp'} = $now - $last_values->{timestamp};
- $params{save} = eval {
- my $empty_events = {};
- foreach (@keys) {
- $empty_events->{$_} = $self->{$_};
- }
- $empty_events->{timestamp} = $now;
- if ($params{lookback}) {
- $empty_events->{lookback_history} = $last_values->{lookback_history};
- foreach (@keys) {
- $empty_events->{lookback_history}->{$_}->{$now} = $self->{$_};
- }
- }
- $empty_events;
- };
- $self->save_state(%params);
-}
-
-sub requires_version {
- my $self = shift;
- my $version = shift;
- my @instances = DBD::MySQL::Server::return_servers();
- my $instversion = $instances[0]->{version};
- if (! $self->version_is_minimum($version)) {
- $self->add_nagios($ERRORS{UNKNOWN},
- sprintf "not implemented/possible for MySQL release %s", $instversion);
- }
-}
-
-sub version_is_minimum {
- # the current version is newer or equal
- my $self = shift;
- my $version = shift;
- my $newer = 1;
- my @instances = DBD::MySQL::Server::return_servers();
- my @v1 = map { $_ eq "x" ? 0 : $_ } split(/\./, $version);
- my @v2 = split(/\./, $instances[0]->{version});
- if (scalar(@v1) > scalar(@v2)) {
- push(@v2, (0) x (scalar(@v1) - scalar(@v2)));
- } elsif (scalar(@v2) > scalar(@v1)) {
- push(@v1, (0) x (scalar(@v2) - scalar(@v1)));
- }
- foreach my $pos (0..$#v1) {
- if ($v2[$pos] > $v1[$pos]) {
- $newer = 1;
- last;
- } elsif ($v2[$pos] < $v1[$pos]) {
- $newer = 0;
- last;
- }
- }
- #printf STDERR "check if %s os minimum %s\n", join(".", @v2), join(".", @v1);
- return $newer;
-}
-
-sub instance_thread {
- my $self = shift;
- my @instances = DBD::MySQL::Server::return_servers();
- return $instances[0]->{thread};
-}
-
-sub windows_server {
- my $self = shift;
- my @instances = DBD::MySQL::Server::return_servers();
- if ($instances[0]->{os} =~ /Win/i) {
- return 1;
- } else {
- return 0;
- }
-}
-
-sub system_vartmpdir {
- my $self = shift;
- if ($^O =~ /MSWin/) {
- return $self->system_tmpdir();
- } else {
- return "/var/tmp/check_mysql_health";
- }
-}
-
-sub system_oldvartmpdir {
- my $self = shift;
- return "/tmp";
-}
-
-sub system_tmpdir {
- my $self = shift;
- if ($^O =~ /MSWin/) {
- return $ENV{TEMP} if defined $ENV{TEMP};
- return $ENV{TMP} if defined $ENV{TMP};
- return File::Spec->catfile($ENV{windir}, 'Temp')
- if defined $ENV{windir};
- return 'C:\Temp';
- } else {
- return "/tmp";
- }
-}
-
-
-package DBD::MySQL::Server::Connection;
-
-use strict;
-
-our @ISA = qw(DBD::MySQL::Server);
-
-
-sub new {
- my $class = shift;
- my %params = @_;
- my $self = {
- mode => $params{mode},
- timeout => $params{timeout},
- access => $params{method} || "dbi",
- hostname => $params{hostname},
- database => $params{database} || "information_schema",
- port => $params{port},
- socket => $params{socket},
- username => $params{username},
- password => $params{password},
- handle => undef,
- };
- bless $self, $class;
- if ($params{method} eq "dbi") {
- bless $self, "DBD::MySQL::Server::Connection::Dbi";
- } elsif ($params{method} eq "mysql") {
- bless $self, "DBD::MySQL::Server::Connection::Mysql";
- } elsif ($params{method} eq "sqlrelay") {
- bless $self, "DBD::MySQL::Server::Connection::Sqlrelay";
- }
- $self->init(%params);
- return $self;
-}
-
-
-package DBD::MySQL::Server::Connection::Dbi;
-
-use strict;
-use Net::Ping;
-
-our @ISA = qw(DBD::MySQL::Server::Connection);
-
-
-sub init {
- my $self = shift;
- my %params = @_;
- my $retval = undef;
- if ($self->{mode} =~ /^server::tnsping/) {
- if (! $self->{connect}) {
- $self->{errstr} = "Please specify a database";
- } else {
- $self->{sid} = $self->{connect};
- $self->{username} ||= time; # prefer an existing user
- $self->{password} = time;
- }
- } else {
- if (($self->{hostname} ne 'localhost') && (! $self->{username} || ! $self->{password})) {
- $self->{errstr} = "Please specify hostname, username and password";
- return undef;
- }
- $self->{dsn} = "DBI:mysql:";
- $self->{dsn} .= sprintf "database=%s", $self->{database};
- $self->{dsn} .= sprintf ";host=%s", $self->{hostname};
- $self->{dsn} .= sprintf ";port=%s", $self->{port}
- unless $self->{socket} || $self->{hostname} eq 'localhost';
- $self->{dsn} .= sprintf ";mysql_socket=%s", $self->{socket}
- if $self->{socket};
- }
- if (! exists $self->{errstr}) {
- eval {
- require DBI;
- use POSIX ':signal_h';
- local $SIG{'ALRM'} = sub {
- die "alarm\n";
- };
- my $mask = POSIX::SigSet->new( SIGALRM );
- my $action = POSIX::SigAction->new(
- sub { die "alarm\n" ; }, $mask);
- my $oldaction = POSIX::SigAction->new();
- sigaction(SIGALRM ,$action ,$oldaction );
- alarm($self->{timeout} - 1); # 1 second before the global unknown timeout
- if ($self->{handle} = DBI->connect(
- $self->{dsn},
- $self->{username},
- $self->{password},
- { RaiseError => 0, AutoCommit => 0, PrintError => 0 })) {
-# $self->{handle}->do(q{
-# ALTER SESSION SET NLS_NUMERIC_CHARACTERS=".," });
- $retval = $self;
- } else {
- $self->{errstr} = DBI::errstr();
- }
- };
- if ($@) {
- $self->{errstr} = $@;
- $retval = undef;
- }
- }
- $self->{tac} = Time::HiRes::time();
- return $retval;
-}
-
-sub selectrow_hashref {
- my $self = shift;
- my $sql = shift;
- my @arguments = @_;
- my $sth = undef;
- my $hashref = undef;
- eval {
- $self->trace(sprintf "SQL:\n%s\nARGS:\n%s\n",
- $sql, Data::Dumper::Dumper(\@arguments));
- # helm auf! jetzt wirds dreckig.
- if ($sql =~ /^\s*SHOW/) {
- $hashref = $self->{handle}->selectrow_hashref($sql);
- } else {
- $sth = $self->{handle}->prepare($sql);
- if (scalar(@arguments)) {
- $sth->execute(@arguments);
- } else {
- $sth->execute();
- }
- $hashref = $sth->selectrow_hashref();
- }
- $self->trace(sprintf "RESULT:\n%s\n",
- Data::Dumper::Dumper($hashref));
- };
- if ($@) {
- $self->debug(sprintf "bumm %s", $@);
- }
- if (-f "/tmp/check_mysql_health_simulation/".$self->{mode}) {
- my $simulation = do { local (@ARGV, $/) =
- "/tmp/check_mysql_health_simulation/".$self->{mode}; <> };
- # keine lust auf den scheiss
- }
- return $hashref;
-}
-
-sub fetchrow_array {
- my $self = shift;
- my $sql = shift;
- my @arguments = @_;
- my $sth = undef;
- my @row = ();
- eval {
- $self->trace(sprintf "SQL:\n%s\nARGS:\n%s\n",
- $sql, Data::Dumper::Dumper(\@arguments));
- $sth = $self->{handle}->prepare($sql);
- if (scalar(@arguments)) {
- $sth->execute(@arguments);
- } else {
- $sth->execute();
- }
- @row = $sth->fetchrow_array();
- $self->trace(sprintf "RESULT:\n%s\n",
- Data::Dumper::Dumper(\@row));
- };
- if ($@) {
- $self->debug(sprintf "bumm %s", $@);
- }
- if (-f "/tmp/check_mysql_health_simulation/".$self->{mode}) {
- my $simulation = do { local (@ARGV, $/) =
- "/tmp/check_mysql_health_simulation/".$self->{mode}; <> };
- @row = split(/\s+/, (split(/\n/, $simulation))[0]);
- }
- return $row[0] unless wantarray;
- return @row;
-}
-
-sub fetchall_array {
- my $self = shift;
- my $sql = shift;
- my @arguments = @_;
- my $sth = undef;
- my $rows = undef;
- eval {
- $self->trace(sprintf "SQL:\n%s\nARGS:\n%s\n",
- $sql, Data::Dumper::Dumper(\@arguments));
- $sth = $self->{handle}->prepare($sql);
- if (scalar(@arguments)) {
- $sth->execute(@arguments);
- } else {
- $sth->execute();
- }
- $rows = $sth->fetchall_arrayref();
- $self->trace(sprintf "RESULT:\n%s\n",
- Data::Dumper::Dumper($rows));
- };
- if ($@) {
- printf STDERR "bumm %s\n", $@;
- }
- if (-f "/tmp/check_mysql_health_simulation/".$self->{mode}) {
- my $simulation = do { local (@ARGV, $/) =
- "/tmp/check_mysql_health_simulation/".$self->{mode}; <> };
- @{$rows} = map { [ split(/\s+/, $_) ] } split(/\n/, $simulation);
- }
- return @{$rows};
-}
-
-sub func {
- my $self = shift;
- $self->{handle}->func(@_);
-}
-
-
-sub execute {
- my $self = shift;
- my $sql = shift;
- eval {
- my $sth = $self->{handle}->prepare($sql);
- $sth->execute();
- };
- if ($@) {
- printf STDERR "bumm %s\n", $@;
- }
-}
-
-sub errstr {
- my $self = shift;
- return $self->{errstr};
-}
-
-sub DESTROY {
- my $self = shift;
- $self->trace(sprintf "disconnecting DBD %s",
- $self->{handle} ? "with handle" : "without handle");
- $self->{handle}->disconnect() if $self->{handle};
-}
-
-package DBD::MySQL::Server::Connection::Mysql;
-
-use strict;
-use File::Temp qw/tempfile/;
-
-our @ISA = qw(DBD::MySQL::Server::Connection);
-
-
-sub init {
- my $self = shift;
- my %params = @_;
- my $retval = undef;
- $self->{loginstring} = "traditional";
- ($self->{sql_commandfile_handle}, $self->{sql_commandfile}) =
- tempfile($self->{mode}."XXXXX", SUFFIX => ".sql",
- DIR => $self->system_tmpdir() );
- close $self->{sql_commandfile_handle};
- ($self->{sql_resultfile_handle}, $self->{sql_resultfile}) =
- tempfile($self->{mode}."XXXXX", SUFFIX => ".out",
- DIR => $self->system_tmpdir() );
- close $self->{sql_resultfile_handle};
- if ($self->{mode} =~ /^server::tnsping/) {
- if (! $self->{connect}) {
- $self->{errstr} = "Please specify a database";
- } else {
- $self->{sid} = $self->{connect};
- $self->{username} ||= time; # prefer an existing user
- $self->{password} = time;
- }
- } else {
- if (! $self->{username} || ! $self->{password}) {
- $self->{errstr} = "Please specify database, username and password";
- return undef;
- } elsif (! (($self->{hostname} && $self->{port}) || $self->{socket})) {
- $self->{errstr} = "Please specify hostname and port or socket";
- return undef;
- }
- }
- if (! exists $self->{errstr}) {
- eval {
- my $mysql = '/'.'usr'.'/'.'bin'.'/'.'mysql';
- if (! -x $mysql) {
- die "nomysql\n";
- }
- if ($self->{loginstring} eq "traditional") {
- $self->{sqlplus} = sprintf "%s ", $mysql;
- $self->{sqlplus} .= sprintf "--batch --raw --skip-column-names ";
- $self->{sqlplus} .= sprintf "--database=%s ", $self->{database};
- $self->{sqlplus} .= sprintf "--host=%s ", $self->{hostname};
- $self->{sqlplus} .= sprintf "--port=%s ", $self->{port}
- unless $self->{socket} || $self->{hostname} eq "localhost";
- $self->{sqlplus} .= sprintf "--socket=%s ", $self->{socket}
- if $self->{socket};
- $self->{sqlplus} .= sprintf "--user=%s --password=%s < %s > %s",
- $self->{username}, $self->{password},
- $self->{sql_commandfile}, $self->{sql_resultfile};
- }
-
- use POSIX ':signal_h';
- local $SIG{'ALRM'} = sub {
- die "alarm\n";
- };
- my $mask = POSIX::SigSet->new( SIGALRM );
- my $action = POSIX::SigAction->new(
- sub { die "alarm\n" ; }, $mask);
- my $oldaction = POSIX::SigAction->new();
- sigaction(SIGALRM ,$action ,$oldaction );
- alarm($self->{timeout} - 1); # 1 second before the global unknown timeout
-
- my $answer = $self->fetchrow_array(
- q{ SELECT 42 FROM dual});
- die unless defined $answer and $answer == 42;
- $retval = $self;
- };
- if ($@) {
- $self->{errstr} = $@;
- $self->{errstr} =~ s/at $0 .*//g;
- chomp $self->{errstr};
- $retval = undef;
- }
- }
- $self->{tac} = Time::HiRes::time();
- return $retval;
-}
-
-sub selectrow_hashref {
- my $self = shift;
- my $sql = shift;
- my @arguments = @_;
- my $sth = undef;
- my $hashref = undef;
- foreach (@arguments) {
- # replace the ? by the parameters
- if (/^\d+$/) {
- $sql =~ s/\?/$_/;
- } else {
- $sql =~ s/\?/'$_'/;
- }
- }
- if ($sql =~ /^\s*SHOW/) {
- $sql .= '\G'; # http://dev.mysql.com/doc/refman/5.1/de/show-slave-status.html
- }
- $self->trace(sprintf "SQL (? resolved):\n%s\nARGS:\n%s\n",
- $sql, Data::Dumper::Dumper(\@arguments));
- $self->create_commandfile($sql);
- my $exit_output = `$self->{sqlplus}`;
- if ($?) {
- printf STDERR "fetchrow_array exit bumm \n";
- my $output = do { local (@ARGV, $/) = $self->{sql_resultfile}; <> };
- my @oerrs = map {
- /((ERROR \d+).*)/ ? $1 : ();
- } split(/\n/, $output);
- $self->{errstr} = join(" ", @oerrs);
- } else {
- my $output = do { local (@ARGV, $/) = $self->{sql_resultfile}; <> };
- if ($sql =~ /^\s*SHOW/) {
- map {
- if (/^\s*([\w_]+):\s*(.*)/) {
- $hashref->{$1} = $2;
- }
- } split(/\n/, $output);
- } else {
- # i dont mess around here and you shouldn't either
- }
- $self->trace(sprintf "RESULT:\n%s\n",
- Data::Dumper::Dumper($hashref));
- }
- unlink $self->{sql_commandfile};
- unlink $self->{sql_resultfile};
- return $hashref;
-}
-
-sub fetchrow_array {
- my $self = shift;
- my $sql = shift;
- my @arguments = @_;
- my $sth = undef;
- my @row = ();
- foreach (@arguments) {
- # replace the ? by the parameters
- if (/^\d+$/) {
- $sql =~ s/\?/$_/;
- } else {
- $sql =~ s/\?/'$_'/;
- }
- }
- $self->trace(sprintf "SQL (? resolved):\n%s\nARGS:\n%s\n",
- $sql, Data::Dumper::Dumper(\@arguments));
- $self->create_commandfile($sql);
- my $exit_output = `$self->{sqlplus}`;
- if ($?) {
- printf STDERR "fetchrow_array exit bumm \n";
- my $output = do { local (@ARGV, $/) = $self->{sql_resultfile}; <> };
- my @oerrs = map {
- /((ERROR \d+).*)/ ? $1 : ();
- } split(/\n/, $output);
- $self->{errstr} = join(" ", @oerrs);
- } else {
- my $output = do { local (@ARGV, $/) = $self->{sql_resultfile}; <> };
- @row = map { convert($_) }
- map { s/^\s+([\.\d]+)$/$1/g; $_ } # strip leading space from numbers
- map { s/\s+$//g; $_ } # strip trailing space
- split(/\t/, (split(/\n/, $output))[0]);
- $self->trace(sprintf "RESULT:\n%s\n",
- Data::Dumper::Dumper(\@row));
- }
- if ($@) {
- $self->debug(sprintf "bumm %s", $@);
- }
- unlink $self->{sql_commandfile};
- unlink $self->{sql_resultfile};
- return $row[0] unless wantarray;
- return @row;
-}
-
-sub fetchall_array {
- my $self = shift;
- my $sql = shift;
- my @arguments = @_;
- my $sth = undef;
- my $rows = undef;
- foreach (@arguments) {
- # replace the ? by the parameters
- if (/^\d+$/) {
- $sql =~ s/\?/$_/;
- } else {
- $sql =~ s/\?/'$_'/;
- }
- }
- $self->trace(sprintf "SQL (? resolved):\n%s\nARGS:\n%s\n",
- $sql, Data::Dumper::Dumper(\@arguments));
- $self->create_commandfile($sql);
- my $exit_output = `$self->{sqlplus}`;
- if ($?) {
- printf STDERR "fetchrow_array exit bumm %s\n", $exit_output;
- my $output = do { local (@ARGV, $/) = $self->{sql_resultfile}; <> };
- my @oerrs = map {
- /((ERROR \d+).*)/ ? $1 : ();
- } split(/\n/, $output);
- $self->{errstr} = join(" ", @oerrs);
- } else {
- my $output = do { local (@ARGV, $/) = $self->{sql_resultfile}; <> };
- my @rows = map { [
- map { convert($_) }
- map { s/^\s+([\.\d]+)$/$1/g; $_ }
- map { s/\s+$//g; $_ }
- split /\t/
- ] } grep { ! /^\d+ rows selected/ }
- grep { ! /^Elapsed: / }
- grep { ! /^\s*$/ } split(/\n/, $output);
- $rows = \@rows;
- $self->trace(sprintf "RESULT:\n%s\n",
- Data::Dumper::Dumper($rows));
- }
- if ($@) {
- $self->debug(sprintf "bumm %s", $@);
- }
- unlink $self->{sql_commandfile};
- unlink $self->{sql_resultfile};
- return @{$rows};
-}
-
-sub func {
- my $self = shift;
- my $function = shift;
- $self->{handle}->func(@_);
-}
-
-sub convert {
- my $n = shift;
- # mostly used to convert numbers in scientific notation
- if ($n =~ /^\s*\d+\s*$/) {
- return $n;
- } elsif ($n =~ /^\s*([-+]?)(\d*[\.,]*\d*)[eE]{1}([-+]?)(\d+)\s*$/) {
- my ($vor, $num, $sign, $exp) = ($1, $2, $3, $4);
- $n =~ s/E/e/g;
- $n =~ s/,/\./g;
- $num =~ s/,/\./g;
- my $sig = $sign eq '-' ? "." . ($exp - 1 + length $num) : '';
- my $dec = sprintf "%${sig}f", $n;
- $dec =~ s/\.[0]+$//g;
- return $dec;
- } elsif ($n =~ /^\s*([-+]?)(\d+)[\.,]*(\d*)\s*$/) {
- return $1.$2.".".$3;
- } elsif ($n =~ /^\s*(.*?)\s*$/) {
- return $1;
- } else {
- return $n;
- }
-}
-
-
-sub execute {
- my $self = shift;
- my $sql = shift;
- eval {
- my $sth = $self->{handle}->prepare($sql);
- $sth->execute();
- };
- if ($@) {
- printf STDERR "bumm %s\n", $@;
- }
-}
-
-sub errstr {
- my $self = shift;
- return $self->{errstr};
-}
-
-sub DESTROY {
- my $self = shift;
- $self->trace("try to clean up command and result files");
- unlink $self->{sql_commandfile} if -f $self->{sql_commandfile};
- unlink $self->{sql_resultfile} if -f $self->{sql_resultfile};
-}
-
-sub create_commandfile {
- my $self = shift;
- my $sql = shift;
- open CMDCMD, "> $self->{sql_commandfile}";
- printf CMDCMD "%s\n", $sql;
- close CMDCMD;
-}
-
-
-package DBD::MySQL::Server::Connection::Sqlrelay;
-
-use strict;
-use Net::Ping;
-
-our @ISA = qw(DBD::MySQL::Server::Connection);
-
-
-sub init {
- my $self = shift;
- my %params = @_;
- my $retval = undef;
- if ($self->{mode} =~ /^server::tnsping/) {
- if (! $self->{connect}) {
- $self->{errstr} = "Please specify a database";
- } else {
- if ($self->{connect} =~ /([\.\w]+):(\d+)/) {
- $self->{host} = $1;
- $self->{port} = $2;
- $self->{socket} = "";
- } elsif ($self->{connect} =~ /([\.\w]+):([\w\/]+)/) {
- $self->{host} = $1;
- $self->{socket} = $2;
- $self->{port} = "";
- }
- }
- } else {
- if (! $self->{hostname} || ! $self->{username} || ! $self->{password}) {
- if ($self->{hostname} && $self->{hostname} =~ /(\w+)\/(\w+)@([\.\w]+):(\d+)/) {
- $self->{username} = $1;
- $self->{password} = $2;
- $self->{hostname} = $3;
- $self->{port} = $4;
- $self->{socket} = "";
- } elsif ($self->{hostname} && $self->{hostname} =~ /(\w+)\/(\w+)@([\.\w]+):([\w\/]+)/) {
- $self->{username} = $1;
- $self->{password} = $2;
- $self->{hostname} = $3;
- $self->{socket} = $4;
- $self->{port} = "";
- } else {
- $self->{errstr} = "Please specify database, username and password";
- return undef;
- }
- } else {
- if ($self->{hostname} =~ /([\.\w]+):(\d+)/) {
- $self->{hostname} = $1;
- $self->{port} = $2;
- $self->{socket} = "";
- } elsif ($self->{hostname} =~ /([\.\w]+):([\w\/]+)/) {
- $self->{hostname} = $1;
- $self->{socket} = $2;
- $self->{port} = "";
- } else {
- $self->{errstr} = "Please specify hostname, username, password and port/socket";
- return undef;
- }
- }
- }
- if (! exists $self->{errstr}) {
- eval {
- require DBI;
- use POSIX ':signal_h';
- local $SIG{'ALRM'} = sub {
- die "alarm\n";
- };
- my $mask = POSIX::SigSet->new( SIGALRM );
- my $action = POSIX::SigAction->new(
- sub { die "alarm\n" ; }, $mask);
- my $oldaction = POSIX::SigAction->new();
- sigaction(SIGALRM ,$action ,$oldaction );
- alarm($self->{timeout} - 1); # 1 second before the global unknown timeout
- if ($self->{handle} = DBI->connect(
- sprintf("DBI:SQLRelay:host=%s;port=%d;socket=%s",
- $self->{hostname}, $self->{port}, $self->{socket}),
- $self->{username},
- $self->{password},
- { RaiseError => 1, AutoCommit => 0, PrintError => 1 })) {
- $retval = $self;
- if ($self->{mode} =~ /^server::tnsping/ && $self->{handle}->ping()) {
- # database connected. fake a "unknown user"
- $self->{errstr} = "ORA-01017";
- }
- } else {
- $self->{errstr} = DBI::errstr();
- }
- };
- if ($@) {
- $self->{errstr} = $@;
- $self->{errstr} =~ s/at [\w\/\.]+ line \d+.*//g;
- $retval = undef;
- }
- }
- $self->{tac} = Time::HiRes::time();
- return $retval;
-}
-
-sub fetchrow_array {
- my $self = shift;
- my $sql = shift;
- my @arguments = @_;
- my $sth = undef;
- my @row = ();
- $self->trace(sprintf "fetchrow_array: %s", $sql);
- eval {
- $sth = $self->{handle}->prepare($sql);
- if (scalar(@arguments)) {
- $sth->execute(@arguments);
- } else {
- $sth->execute();
- }
- @row = $sth->fetchrow_array();
- };
- if ($@) {
- $self->debug(sprintf "bumm %s", $@);
- }
- if (-f "/tmp/check_mysql_health_simulation/".$self->{mode}) {
- my $simulation = do { local (@ARGV, $/) =
- "/tmp/check_mysql_health_simulation/".$self->{mode}; <> };
- @row = split(/\s+/, (split(/\n/, $simulation))[0]);
- }
- return $row[0] unless wantarray;
- return @row;
-}
-
-sub fetchall_array {
- my $self = shift;
- my $sql = shift;
- my @arguments = @_;
- my $sth = undef;
- my $rows = undef;
- $self->trace(sprintf "fetchall_array: %s", $sql);
- eval {
- $sth = $self->{handle}->prepare($sql);
- if (scalar(@arguments)) {
- $sth->execute(@arguments);
- } else {
- $sth->execute();
- }
- $rows = $sth->fetchall_arrayref();
- };
- if ($@) {
- printf STDERR "bumm %s\n", $@;
- }
- if (-f "/tmp/check_mysql_health_simulation/".$self->{mode}) {
- my $simulation = do { local (@ARGV, $/) =
- "/tmp/check_mysql_health_simulation/".$self->{mode}; <> };
- @{$rows} = map { [ split(/\s+/, $_) ] } split(/\n/, $simulation);
- }
- return @{$rows};
-}
-
-sub func {
- my $self = shift;
- $self->{handle}->func(@_);
-}
-
-sub execute {
- my $self = shift;
- my $sql = shift;
- eval {
- my $sth = $self->{handle}->prepare($sql);
- $sth->execute();
- };
- if ($@) {
- printf STDERR "bumm %s\n", $@;
- }
-}
-
-sub DESTROY {
- my $self = shift;
- #$self->trace(sprintf "disconnecting DBD %s",
- # $self->{handle} ? "with handle" : "without handle");
- #$self->{handle}->disconnect() if $self->{handle};
-}
-
-
-
-
-package DBD::MySQL::Cluster;
-
-use strict;
-use Time::HiRes;
-use IO::File;
-use Data::Dumper;
-
-
-{
- our $verbose = 0;
- our $scream = 0; # scream if something is not implemented
- our $access = "dbi"; # how do we access the database.
- our $my_modules_dyn_dir = ""; # where we look for self-written extensions
-
- my @clusters = ();
- my $initerrors = undef;
-
- sub add_cluster {
- push(@clusters, shift);
- }
-
- sub return_clusters {
- return @clusters;
- }
-
- sub return_first_cluster() {
- return $clusters[0];
- }
-
-}
-
-sub new {
- my $class = shift;
- my %params = @_;
- my $self = {
- hostname => $params{hostname},
- port => $params{port},
- username => $params{username},
- password => $params{password},
- timeout => $params{timeout},
- warningrange => $params{warningrange},
- criticalrange => $params{criticalrange},
- version => 'unknown',
- nodes => [],
- ndbd_nodes => 0,
- ndb_mgmd_nodes => 0,
- mysqld_nodes => 0,
- };
- bless $self, $class;
- $self->init_nagios();
- if ($self->connect(%params)) {
- DBD::MySQL::Cluster::add_cluster($self);
- $self->init(%params);
- }
- return $self;
-}
-
-sub init {
- my $self = shift;
- my %params = @_;
- if ($self->{show}) {
- my $type = undef;
- foreach (split /\n/, $self->{show}) {
- if (/\[(\w+)\((\w+)\)\]\s+(\d+) node/) {
- $type = uc $2;
- } elsif (/id=(\d+)(.*)/) {
- push(@{$self->{nodes}}, DBD::MySQL::Cluster::Node->new(
- type => $type,
- id => $1,
- status => $2,
- ));
- }
- }
- } else {
- }
- if ($params{mode} =~ /^cluster::ndbdrunning/) {
- foreach my $node (@{$self->{nodes}}) {
- $node->{type} eq "NDB" && $node->{status} eq "running" && $self->{ndbd_nodes}++;
- $node->{type} eq "MGM" && $node->{status} eq "running" && $self->{ndb_mgmd_nodes}++;
- $node->{type} eq "API" && $node->{status} eq "running" && $self->{mysqld_nodes}++;
- }
- } else {
- printf "broken mode %s\n", $params{mode};
- }
-}
-
-sub dump {
- my $self = shift;
- my $message = shift || "";
- printf "%s %s\n", $message, Data::Dumper::Dumper($self);
-}
-
-sub nagios {
- my $self = shift;
- my %params = @_;
- my $dead_ndb = 0;
- my $dead_api = 0;
- if (! $self->{nagios_level}) {
- if ($params{mode} =~ /^cluster::ndbdrunning/) {
- foreach my $node (grep { $_->{type} eq "NDB"} @{$self->{nodes}}) {
- next if $params{selectname} && $params{selectname} ne $_->{id};
- if (! $node->{connected}) {
- $self->add_nagios_critical(
- sprintf "ndb node %d is not connected", $node->{id});
- $dead_ndb++;
- }
- }
- foreach my $node (grep { $_->{type} eq "API"} @{$self->{nodes}}) {
- next if $params{selectname} && $params{selectname} ne $_->{id};
- if (! $node->{connected}) {
- $self->add_nagios_critical(
- sprintf "api node %d is not connected", $node->{id});
- $dead_api++;
- }
- }
- if (! $dead_ndb) {
- $self->add_nagios_ok("all ndb nodes are connected");
- }
- if (! $dead_api) {
- $self->add_nagios_ok("all api nodes are connected");
- }
- }
- }
- $self->add_perfdata(sprintf "ndbd_nodes=%d ndb_mgmd_nodes=%d mysqld_nodes=%d",
- $self->{ndbd_nodes}, $self->{ndb_mgmd_nodes}, $self->{mysqld_nodes});
-}
-
-
-sub init_nagios {
- my $self = shift;
- no strict 'refs';
- if (! ref($self)) {
- my $nagiosvar = $self."::nagios";
- my $nagioslevelvar = $self."::nagios_level";
- $$nagiosvar = {
- messages => {
- 0 => [],
- 1 => [],
- 2 => [],
- 3 => [],
- },
- perfdata => [],
- };
- $$nagioslevelvar = $ERRORS{OK},
- } else {
- $self->{nagios} = {
- messages => {
- 0 => [],
- 1 => [],
- 2 => [],
- 3 => [],
- },
- perfdata => [],
- };
- $self->{nagios_level} = $ERRORS{OK},
- }
-}
-
-sub check_thresholds {
- my $self = shift;
- my $value = shift;
- my $defaultwarningrange = shift;
- my $defaultcriticalrange = shift;
- my $level = $ERRORS{OK};
- $self->{warningrange} = $self->{warningrange} ?
- $self->{warningrange} : $defaultwarningrange;
- $self->{criticalrange} = $self->{criticalrange} ?
- $self->{criticalrange} : $defaultcriticalrange;
- if ($self->{warningrange} !~ /:/ && $self->{criticalrange} !~ /:/) {
- # warning = 10, critical = 20, warn if > 10, crit if > 20
- $level = $ERRORS{WARNING} if $value > $self->{warningrange};
- $level = $ERRORS{CRITICAL} if $value > $self->{criticalrange};
- } elsif ($self->{warningrange} =~ /([\d\.]+):/ &&
- $self->{criticalrange} =~ /([\d\.]+):/) {
- # warning = 98:, critical = 95:, warn if < 98, crit if < 95
- $self->{warningrange} =~ /([\d\.]+):/;
- $level = $ERRORS{WARNING} if $value < $1;
- $self->{criticalrange} =~ /([\d\.]+):/;
- $level = $ERRORS{CRITICAL} if $value < $1;
- }
- return $level;
- #
- # syntax error must be reported with returncode -1
- #
-}
-
-sub add_nagios {
- my $self = shift;
- my $level = shift;
- my $message = shift;
- push(@{$self->{nagios}->{messages}->{$level}}, $message);
- # recalc current level
- foreach my $llevel qw(CRITICAL WARNING UNKNOWN OK) {
- if (scalar(@{$self->{nagios}->{messages}->{$ERRORS{$llevel}}})) {
- $self->{nagios_level} = $ERRORS{$llevel};
- }
- }
-}
-
-sub add_nagios_ok {
- my $self = shift;
- my $message = shift;
- $self->add_nagios($ERRORS{OK}, $message);
-}
-
-sub add_nagios_warning {
- my $self = shift;
- my $message = shift;
- $self->add_nagios($ERRORS{WARNING}, $message);
-}
-
-sub add_nagios_critical {
- my $self = shift;
- my $message = shift;
- $self->add_nagios($ERRORS{CRITICAL}, $message);
-}
-
-sub add_nagios_unknown {
- my $self = shift;
- my $message = shift;
- $self->add_nagios($ERRORS{UNKNOWN}, $message);
-}
-
-sub add_perfdata {
- my $self = shift;
- my $data = shift;
- push(@{$self->{nagios}->{perfdata}}, $data);
-}
-
-sub merge_nagios {
- my $self = shift;
- my $child = shift;
- foreach my $level (0..3) {
- foreach (@{$child->{nagios}->{messages}->{$level}}) {
- $self->add_nagios($level, $_);
- }
- #push(@{$self->{nagios}->{messages}->{$level}},
- # @{$child->{nagios}->{messages}->{$level}});
- }
- push(@{$self->{nagios}->{perfdata}}, @{$child->{nagios}->{perfdata}});
-}
-
-
-sub calculate_result {
- my $self = shift;
- if ($ENV{NRPE_MULTILINESUPPORT} &&
- length join(" ", @{$self->{nagios}->{perfdata}}) > 200) {
- foreach my $level ("CRITICAL", "WARNING", "UNKNOWN", "OK") {
- # first the bad news
- if (scalar(@{$self->{nagios}->{messages}->{$ERRORS{$level}}})) {
- $self->{nagios_message} .=
- "\n".join("\n", @{$self->{nagios}->{messages}->{$ERRORS{$level}}});
- }
- }
- $self->{nagios_message} =~ s/^\n//g;
- $self->{perfdata} = join("\n", @{$self->{nagios}->{perfdata}});
- } else {
- foreach my $level ("CRITICAL", "WARNING", "UNKNOWN", "OK") {
- # first the bad news
- if (scalar(@{$self->{nagios}->{messages}->{$ERRORS{$level}}})) {
- $self->{nagios_message} .=
- join(", ", @{$self->{nagios}->{messages}->{$ERRORS{$level}}}).", ";
- }
- }
- $self->{nagios_message} =~ s/, $//g;
- $self->{perfdata} = join(" ", @{$self->{nagios}->{perfdata}});
- }
- foreach my $level ("OK", "UNKNOWN", "WARNING", "CRITICAL") {
- if (scalar(@{$self->{nagios}->{messages}->{$ERRORS{$level}}})) {
- $self->{nagios_level} = $ERRORS{$level};
- }
- }
-}
-
-sub debug {
- my $self = shift;
- my $msg = shift;
- if ($DBD::MySQL::Cluster::verbose) {
- printf "%s %s\n", $msg, ref($self);
- }
-}
-
-sub connect {
- my $self = shift;
- my %params = @_;
- my $retval = undef;
- $self->{tic} = Time::HiRes::time();
- eval {
- use POSIX ':signal_h';
- local $SIG{'ALRM'} = sub {
- die "alarm\n";
- };
- my $mask = POSIX::SigSet->new( SIGALRM );
- my $action = POSIX::SigAction->new(
- sub { die "connection timeout\n" ; }, $mask);
- my $oldaction = POSIX::SigAction->new();
- sigaction(SIGALRM ,$action ,$oldaction );
- alarm($self->{timeout} - 1); # 1 second before the global unknown timeout
- my $ndb_mgm = "ndb_mgm";
- $params{hostname} = "127.0.0.1" if ! $params{hostname};
- $ndb_mgm .= sprintf " --ndb-connectstring=%s", $params{hostname}
- if $params{hostname};
- $ndb_mgm .= sprintf ":%d", $params{port}
- if $params{port};
- $self->{show} = `$ndb_mgm -e show 2>&1`;
- if ($? == -1) {
- $self->add_nagios_critical("ndb_mgm failed to execute $!");
- } elsif ($? & 127) {
- $self->add_nagios_critical("ndb_mgm failed to execute $!");
- } elsif ($? >> 8 != 0) {
- $self->add_nagios_critical("ndb_mgm unable to connect");
- } else {
- if ($self->{show} !~ /Cluster Configuration/) {
- $self->add_nagios_critical("got no cluster configuration");
- } else {
- $retval = 1;
- }
- }
- };
- if ($@) {
- $self->{errstr} = $@;
- $self->{errstr} =~ s/at $0 .*//g;
- chomp $self->{errstr};
- $self->add_nagios_critical($self->{errstr});
- $retval = undef;
- }
- $self->{tac} = Time::HiRes::time();
- return $retval;
-}
-
-sub trace {
- my $self = shift;
- my $format = shift;
- $self->{trace} = -f "/tmp/check_mysql_health.trace" ? 1 : 0;
- if ($self->{verbose}) {
- printf("%s: ", scalar localtime);
- printf($format, @_);
- }
- if ($self->{trace}) {
- my $logfh = new IO::File;
- $logfh->autoflush(1);
- if ($logfh->open("/tmp/check_mysql_health.trace", "a")) {
- $logfh->printf("%s: ", scalar localtime);
- $logfh->printf($format, @_);
- $logfh->printf("\n");
- $logfh->close();
- }
- }
-}
-
-sub DESTROY {
- my $self = shift;
- my $handle1 = "null";
- my $handle2 = "null";
- if (defined $self->{handle}) {
- $handle1 = ref($self->{handle});
- if (defined $self->{handle}->{handle}) {
- $handle2 = ref($self->{handle}->{handle});
- }
- }
- $self->trace(sprintf "DESTROY %s with handle %s %s", ref($self), $handle1, $handle2);
- if (ref($self) eq "DBD::MySQL::Cluster") {
- }
- $self->trace(sprintf "DESTROY %s exit with handle %s %s", ref($self), $handle1, $handle2);
- if (ref($self) eq "DBD::MySQL::Cluster") {
- #printf "humpftata\n";
- }
-}
-
-sub save_state {
- my $self = shift;
- my %params = @_;
- my $extension = "";
- mkdir $params{statefilesdir} unless -d $params{statefilesdir};
- my $statefile = sprintf "%s/%s_%s",
- $params{statefilesdir}, $params{hostname}, $params{mode};
- $extension .= $params{differenciator} ? "_".$params{differenciator} : "";
- $extension .= $params{socket} ? "_".$params{socket} : "";
- $extension .= $params{port} ? "_".$params{port} : "";
- $extension .= $params{database} ? "_".$params{database} : "";
- $extension .= $params{tablespace} ? "_".$params{tablespace} : "";
- $extension .= $params{datafile} ? "_".$params{datafile} : "";
- $extension .= $params{name} ? "_".$params{name} : "";
- $extension =~ s/\//_/g;
- $extension =~ s/\(/_/g;
- $extension =~ s/\)/_/g;
- $extension =~ s/\*/_/g;
- $extension =~ s/\s/_/g;
- $statefile .= $extension;
- $statefile = lc $statefile;
- open(STATE, ">$statefile");
- if ((ref($params{save}) eq "HASH") && exists $params{save}->{timestamp}) {
- $params{save}->{localtime} = scalar localtime $params{save}->{timestamp};
- }
- printf STATE Data::Dumper::Dumper($params{save});
- close STATE;
- $self->debug(sprintf "saved %s to %s",
- Data::Dumper::Dumper($params{save}), $statefile);
-}
-
-sub load_state {
- my $self = shift;
- my %params = @_;
- my $extension = "";
- my $statefile = sprintf "%s/%s_%s",
- $params{statefilesdir}, $params{hostname}, $params{mode};
- $extension .= $params{differenciator} ? "_".$params{differenciator} : "";
- $extension .= $params{socket} ? "_".$params{socket} : "";
- $extension .= $params{port} ? "_".$params{port} : "";
- $extension .= $params{database} ? "_".$params{database} : "";
- $extension .= $params{tablespace} ? "_".$params{tablespace} : "";
- $extension .= $params{datafile} ? "_".$params{datafile} : "";
- $extension .= $params{name} ? "_".$params{name} : "";
- $extension =~ s/\//_/g;
- $extension =~ s/\(/_/g;
- $extension =~ s/\)/_/g;
- $extension =~ s/\*/_/g;
- $extension =~ s/\s/_/g;
- $statefile .= $extension;
- $statefile = lc $statefile;
- if ( -f $statefile) {
- our $VAR1;
- eval {
- require $statefile;
- };
- if($@) {
-printf "rumms\n";
- }
- $self->debug(sprintf "load %s", Data::Dumper::Dumper($VAR1));
- return $VAR1;
- } else {
- return undef;
- }
-}
-
-sub valdiff {
- my $self = shift;
- my $pparams = shift;
- my %params = %{$pparams};
- my @keys = @_;
- my $last_values = $self->load_state(%params) || eval {
- my $empty_events = {};
- foreach (@keys) {
- $empty_events->{$_} = 0;
- }
- $empty_events->{timestamp} = 0;
- $empty_events;
- };
- foreach (@keys) {
- $self->{'delta_'.$_} = $self->{$_} - $last_values->{$_};
- $self->debug(sprintf "delta_%s %f", $_, $self->{'delta_'.$_});
- }
- $self->{'delta_timestamp'} = time - $last_values->{timestamp};
- $params{save} = eval {
- my $empty_events = {};
- foreach (@keys) {
- $empty_events->{$_} = $self->{$_};
- }
- $empty_events->{timestamp} = time;
- $empty_events;
- };
- $self->save_state(%params);
-}
-
-sub requires_version {
- my $self = shift;
- my $version = shift;
- my @instances = DBD::MySQL::Cluster::return_clusters();
- my $instversion = $instances[0]->{version};
- if (! $self->version_is_minimum($version)) {
- $self->add_nagios($ERRORS{UNKNOWN},
- sprintf "not implemented/possible for MySQL release %s", $instversion);
- }
-}
-
-sub version_is_minimum {
- # the current version is newer or equal
- my $self = shift;
- my $version = shift;
- my $newer = 1;
- my @instances = DBD::MySQL::Cluster::return_clusters();
- my @v1 = map { $_ eq "x" ? 0 : $_ } split(/\./, $version);
- my @v2 = split(/\./, $instances[0]->{version});
- if (scalar(@v1) > scalar(@v2)) {
- push(@v2, (0) x (scalar(@v1) - scalar(@v2)));
- } elsif (scalar(@v2) > scalar(@v1)) {
- push(@v1, (0) x (scalar(@v2) - scalar(@v1)));
- }
- foreach my $pos (0..$#v1) {
- if ($v2[$pos] > $v1[$pos]) {
- $newer = 1;
- last;
- } elsif ($v2[$pos] < $v1[$pos]) {
- $newer = 0;
- last;
- }
- }
- #printf STDERR "check if %s os minimum %s\n", join(".", @v2), join(".", @v1);
- return $newer;
-}
-
-sub instance_rac {
- my $self = shift;
- my @instances = DBD::MySQL::Cluster::return_clusters();
- return (lc $instances[0]->{parallel} eq "yes") ? 1 : 0;
-}
-
-sub instance_thread {
- my $self = shift;
- my @instances = DBD::MySQL::Cluster::return_clusters();
- return $instances[0]->{thread};
-}
-
-sub windows_cluster {
- my $self = shift;
- my @instances = DBD::MySQL::Cluster::return_clusters();
- if ($instances[0]->{os} =~ /Win/i) {
- return 1;
- } else {
- return 0;
- }
-}
-
-sub system_vartmpdir {
- my $self = shift;
- if ($^O =~ /MSWin/) {
- return $self->system_tmpdir();
- } else {
- return "/var/tmp/check_mysql_health";
- }
-}
-
-sub system_oldvartmpdir {
- my $self = shift;
- return "/tmp";
-}
-
-sub system_tmpdir {
- my $self = shift;
- if ($^O =~ /MSWin/) {
- return $ENV{TEMP} if defined $ENV{TEMP};
- return $ENV{TMP} if defined $ENV{TMP};
- return File::Spec->catfile($ENV{windir}, 'Temp')
- if defined $ENV{windir};
- return 'C:\Temp';
- } else {
- return "/tmp";
- }
-}
-
-
-package DBD::MySQL::Cluster::Node;
-
-use strict;
-
-our @ISA = qw(DBD::MySQL::Cluster);
-
-
-sub new {
- my $class = shift;
- my %params = @_;
- my $self = {
- mode => $params{mode},
- timeout => $params{timeout},
- type => $params{type},
- id => $params{id},
- status => $params{status},
- };
- bless $self, $class;
- $self->init(%params);
- if ($params{type} eq "NDB") {
- bless $self, "DBD::MySQL::Cluster::Node::NDB";
- $self->init(%params);
- }
- return $self;
-}
-
-sub init {
- my $self = shift;
- my %params = @_;
- if ($self->{status} =~ /@(\d+\.\d+\.\d+\.\d+)\s/) {
- $self->{addr} = $1;
- $self->{connected} = 1;
- } elsif ($self->{status} =~ /accepting connect from (\d+\.\d+\.\d+\.\d+)/) {
- $self->{addr} = $1;
- $self->{connected} = 0;
- }
- if ($self->{status} =~ /starting,/) {
- $self->{status} = "starting";
- } elsif ($self->{status} =~ /shutting,/) {
- $self->{status} = "shutting";
- } else {
- $self->{status} = $self->{connected} ? "running" : "dead";
- }
-}
-
-
-package DBD::MySQL::Cluster::Node::NDB;
-
-use strict;
-
-our @ISA = qw(DBD::MySQL::Cluster::Node);
-
-
-sub init {
- my $self = shift;
- my %params = @_;
- if ($self->{status} =~ /Nodegroup:\s*(\d+)/) {
- $self->{nodegroup} = $1;
- }
- $self->{master} = ($self->{status} =~ /Master\)/) ? 1 : 0;
-}
-
-
-package Extraopts;
-
-use strict;
-use File::Basename;
-use Data::Dumper;
-
-sub new {
- my $class = shift;
- my %params = @_;
- my $self = {
- file => $params{file},
- commandline => $params{commandline},
- config => {},
- section => 'default_no_section',
- };
- bless $self, $class;
- $self->prepare_file_and_section();
- $self->init();
- return $self;
-}
-
-sub prepare_file_and_section {
- my $self = shift;
- if (! defined $self->{file}) {
- # ./check_stuff --extra-opts
- $self->{section} = basename($0);
- $self->{file} = $self->get_default_file();
- } elsif ($self->{file} =~ /^[^@]+$/) {
- # ./check_stuff --extra-opts=special_opts
- $self->{section} = $self->{file};
- $self->{file} = $self->get_default_file();
- } elsif ($self->{file} =~ /^@(.*)/) {
- # ./check_stuff --extra-opts=@/etc/myconfig.ini
- $self->{section} = basename($0);
- $self->{file} = $1;
- } elsif ($self->{file} =~ /^(.*?)@(.*)/) {
- # ./check_stuff --extra-opts=special_opts@/etc/myconfig.ini
- $self->{section} = $1;
- $self->{file} = $2;
- }
-}
-
-sub get_default_file {
- my $self = shift;
- foreach my $default (qw(/etc/nagios/plugins.ini
- /usr/local/nagios/etc/plugins.ini
- /usr/local/etc/nagios/plugins.ini
- /etc/opt/nagios/plugins.ini
- /etc/nagios-plugins.ini
- /usr/local/etc/nagios-plugins.ini
- /etc/opt/nagios-plugins.ini)) {
- if (-f $default) {
- return $default;
- }
- }
- return undef;
-}
-
-sub init {
- my $self = shift;
- if (! defined $self->{file}) {
- $self->{errors} = sprintf 'no extra-opts file specified and no default file found';
- } elsif (! -f $self->{file}) {
- $self->{errors} = sprintf 'could not open %s', $self->{file};
- } else {
- my $data = do { local (@ARGV, $/) = $self->{file}; <> };
- my $in_section = 'default_no_section';
- foreach my $line (split(/\n/, $data)) {
- if ($line =~ /\[(.*)\]/) {
- $in_section = $1;
- } elsif ($line =~ /(.*)=(.*)/) {
- $self->{config}->{$in_section}->{$1} = $2;
- }
- }
- }
-}
-
-sub is_valid {
- my $self = shift;
- return ! exists $self->{errors};
-}
-
-sub overwrite {
- my $self = shift;
- my %commandline = ();
- if (scalar(keys %{$self->{config}->{default_no_section}}) > 0) {
- foreach (keys %{$self->{config}->{default_no_section}}) {
- $commandline{$_} = $self->{config}->{default_no_section}->{$_};
- }
- }
- if (exists $self->{config}->{$self->{section}}) {
- foreach (keys %{$self->{config}->{$self->{section}}}) {
- $commandline{$_} = $self->{config}->{$self->{section}}->{$_};
- }
- }
- foreach (keys %commandline) {
- if (! exists $self->{commandline}->{$_}) {
- $self->{commandline}->{$_} = $commandline{$_};
- }
- }
-}
-
-
-
-package main;
-
-use strict;
-use Getopt::Long qw(:config no_ignore_case);
-use File::Basename;
-use lib dirname($0);
-
-
-
-use vars qw ($PROGNAME $REVISION $CONTACT $TIMEOUT $STATEFILESDIR $needs_restart %commandline);
-
-$PROGNAME = "check_mysql_health";
-$REVISION = '$Revision: 2.1.3 $';
-$CONTACT = 'gerhard.lausser@consol.de';
-$TIMEOUT = 60;
-$STATEFILESDIR = '/var/run';
-$needs_restart = 0;
-
-my @modes = (
- ['server::connectiontime',
- 'connection-time', undef,
- 'Time to connect to the server' ],
- ['server::uptime',
- 'uptime', undef,
- 'Time the server is running' ],
- ['server::instance::connectedthreads',
- 'threads-connected', undef,
- 'Number of currently open connections' ],
- ['server::instance::threadcachehitrate',
- 'threadcache-hitrate', undef,
- 'Hit rate of the thread-cache' ],
- ['server::instance::replication::slavelag',
- 'slave-lag', ['replication-slave-lag'],
- 'Seconds behind master' ],
- ['server::instance::replication::slaveiorunning',
- 'slave-io-running', ['replication-slave-io-running'],
- 'Slave io running: Yes' ],
- ['server::instance::replication::slavesqlrunning',
- 'slave-sql-running', ['replication-slave-sql-running'],
- 'Slave sql running: Yes' ],
- ['server::instance::querycachehitrate',
- 'qcache-hitrate', ['querycache-hitrate'],
- 'Query cache hitrate' ],
- ['server::instance::querycachelowmemprunes',
- 'qcache-lowmem-prunes', ['querycache-lowmem-prunes'],
- 'Query cache entries pruned because of low memory' ],
- ['server::instance::myisam::keycache::hitrate',
- 'keycache-hitrate', ['myisam-keycache-hitrate'],
- 'MyISAM key cache hitrate' ],
- ['server::instance::innodb::bufferpool::hitrate',
- 'bufferpool-hitrate', ['innodb-bufferpool-hitrate'],
- 'InnoDB buffer pool hitrate' ],
- ['server::instance::innodb::bufferpool::waitfree',
- 'bufferpool-wait-free', ['innodb-bufferpool-wait-free'],
- 'InnoDB buffer pool waits for clean page available' ],
- ['server::instance::innodb::logwaits',
- 'log-waits', ['innodb-log-waits'],
- 'InnoDB log waits because of a too small log buffer' ],
- ['server::instance::tablecachehitrate',
- 'tablecache-hitrate', undef,
- 'Table cache hitrate' ],
- ['server::instance::tablelockcontention',
- 'table-lock-contention', undef,
- 'Table lock contention' ],
- ['server::instance::tableindexusage',
- 'index-usage', undef,
- 'Usage of indices' ],
- ['server::instance::tabletmpondisk',
- 'tmp-disk-tables', undef,
- 'Percent of temp tables created on disk' ],
- ['server::instance::openfiles',
- 'open-files', undef,
- 'Percent of opened files' ],
- ['server::instance::slowqueries',
- 'slow-queries', undef,
- 'Slow queries' ],
- ['server::instance::longprocs',
- 'long-running-procs', undef,
- 'long running processes' ],
- ['cluster::ndbdrunning',
- 'cluster-ndbd-running', undef,
- 'ndnd nodes are up and running' ],
- ['server::sql',
- 'sql', undef,
- 'any sql command returning a single number' ],
-);
-
-sub print_usage () {
- print <<EOUS;
- Usage:
- $PROGNAME [-v] [-t <timeout>] [[--hostname <hostname>]
- [--port <port> | --socket <socket>]
- --username <username> --password <password>] --mode <mode>
- [--method mysql]
- $PROGNAME [-h | --help]
- $PROGNAME [-V | --version]
-
- Options:
- --hostname
- the database server's hostname
- --port
- the database's port. (default: 3306)
- --socket
- the database's unix socket.
- --username
- the mysql db user
- --password
- the mysql db user's password
- --database
- the database's name. (default: information_schema)
- --warning
- the warning range
- --critical
- the critical range
- --mode
- the mode of the plugin. select one of the following keywords:
-EOUS
- my $longest = length ((reverse sort {length $a <=> length $b} map { $_->[1] } @modes)[0]);
- my $format = " %-".
- (length ((reverse sort {length $a <=> length $b} map { $_->[1] } @modes)[0])).
- "s\t(%s)\n";
- foreach (@modes) {
- printf $format, $_->[1], $_->[3];
- }
- printf "\n";
- print <<EOUS;
- --name
- the name of something that needs to be further specified,
- currently only used for sql statements
- --name2
- if name is a sql statement, this statement would appear in
- the output and the performance data. This can be ugly, so
- name2 can be used to appear instead.
- --regexp
- if this parameter is used, name will be interpreted as a
- regular expression.
- --units
- one of %, KB, MB, GB. This is used for a better output of mode=sql
- and for specifying thresholds for mode=tablespace-free
-
- In mode sql you can url-encode the statement so you will not have to mess
- around with special characters in your Nagios service definitions.
- Instead of
- --name="select count(*) from v\$session where status = 'ACTIVE'"
- you can say
- --name=select%20count%28%2A%29%20from%20v%24session%20where%20status%20%3D%20%27ACTIVE%27
- For your convenience you can call check_mysql_health with the --mode encode
- option and it will encode the standard input.
-
- You can find the full documentation at
- http://www.consol.de/opensource/nagios/check-mysql-health
-
-EOUS
-
-}
-
-sub print_help () {
- print "Copyright (c) 2009 Gerhard Lausser\n\n";
- print "\n";
- print " Check various parameters of MySQL databases \n";
- print "\n";
- print_usage();
- support();
-}
-
-
-sub print_revision ($$) {
- my $commandName = shift;
- my $pluginRevision = shift;
- $pluginRevision =~ s/^\$Revision: //;
- $pluginRevision =~ s/ \$\s*$//;
- print "$commandName ($pluginRevision)\n";
- print "This nagios plugin comes with ABSOLUTELY NO WARRANTY. You may redistribute\ncopies of this plugin under the terms of the GNU General Public License.\n";
-}
-
-sub support () {
- my $support='Send email to gerhard.lausser@consol.de if you have questions\nregarding use of this software. \nPlease include version information with all correspondence (when possible,\nuse output from the --version option of the plugin itself).\n';
- $support =~ s/@/\@/g;
- $support =~ s/\\n/\n/g;
- print $support;
-}
-
-sub contact_author ($$) {
- my $item = shift;
- my $strangepattern = shift;
- if ($commandline{verbose}) {
- printf STDERR
- "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n".
- "You found a line which is not recognized by %s\n".
- "This means, certain components of your system cannot be checked.\n".
- "Please contact the author %s and\nsend him the following output:\n\n".
- "%s /%s/\n\nThank you!\n".
- "++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n",
- $PROGNAME, $CONTACT, $item, $strangepattern;
- }
-}
-
-%commandline = ();
-my @params = (
- "timeout|t=i",
- "version|V",
- "help|h",
- "verbose|v",
- "debug|d",
- "hostname|H=s",
- "database=s",
- "port|P=s",
- "socket|S=s",
- "username|u=s",
- "password|p=s",
- "mode|m=s",
- "name=s",
- "name2=s",
- "regexp",
- "perfdata",
- "warning=s",
- "critical=s",
- "absolute|a",
- "environment|e=s%",
- "method=s",
- "runas|r=s",
- "scream",
- "shell",
- "eyecandy",
- "encode",
- "units=s",
- "lookback=i",
- "3",
- "with-mymodules-dyn-dir=s",
- "extra-opts:s");
-
-if (! GetOptions(\%commandline, @params)) {
- print_help();
- exit $ERRORS{UNKNOWN};
-}
-
-if (exists $commandline{'extra-opts'}) {
- # read the extra file and overwrite other parameters
- my $extras = Extraopts->new(file => $commandline{'extra-opts'}, commandline =>
- \%commandline);
- if (! $extras->is_valid()) {
- printf "extra-opts are not valid: %s\n", $extras->{errors};
- exit $ERRORS{UNKNOWN};
- } else {
- $extras->overwrite();
- }
-}
-
-if (exists $commandline{version}) {
- print_revision($PROGNAME, $REVISION);
- exit $ERRORS{OK};
-}
-
-if (exists $commandline{help}) {
- print_help();
- exit $ERRORS{OK};
-} elsif (! exists $commandline{mode}) {
- printf "Please select a mode\n";
- print_help();
- exit $ERRORS{OK};
-}
-
-if ($commandline{mode} eq "encode") {
- my $input = <>;
- chomp $input;
- $input =~ s/([^A-Za-z0-9])/sprintf("%%%02X", ord($1))/seg;
- printf "%s\n", $input;
- exit $ERRORS{OK};
-}
-
-if (exists $commandline{3}) {
- $ENV{NRPE_MULTILINESUPPORT} = 1;
-}
-
-if (exists $commandline{timeout}) {
- $TIMEOUT = $commandline{timeout};
-}
-
-if (exists $commandline{verbose}) {
- $DBD::MySQL::Server::verbose = exists $commandline{verbose};
-}
-
-if (exists $commandline{scream}) {
-# $DBD::MySQL::Server::hysterical = exists $commandline{scream};
-}
-
-if (exists $commandline{method}) {
- # snmp or mysql cmdline
-} else {
- $commandline{method} = "dbi";
-}
-
-if (exists $commandline{'with-mymodules-dyn-dir'}) {
- $DBD::MYSQL::Server::my_modules_dyn_dir = $commandline{'with-mymodules-dyn-dir
-'};
-} else {
- $DBD::MYSQL::Server::my_modules_dyn_dir = '/usr/local/nagios/libexec';
-}
-
-if (exists $commandline{environment}) {
- # if the desired environment variable values are different from
- # the environment of this running script, then a restart is necessary.
- # because setting $ENV does _not_ change the environment of the running script.
- foreach (keys %{$commandline{environment}}) {
- if ((! $ENV{$_}) || ($ENV{$_} ne $commandline{environment}->{$_})) {
- $needs_restart = 1;
- $ENV{$_} = $commandline{environment}->{$_};
- printf STDERR "new %s=%s forces restart\n", $_, $ENV{$_}
- if $DBD::MySQL::Server::verbose;
- }
- }
- # e.g. called with --runas dbnagio. shlib_path environment variable is stripped
- # during the sudo.
- # so the perl interpreter starts without a shlib_path. but --runas cares for
- # a --environment shlib_path=...
- # so setting the environment variable in the code above and restarting the
- # perl interpreter will help it find shared libs
-}
-
-if (exists $commandline{runas}) {
- # remove the runas parameter
- # exec sudo $0 ... the remaining parameters
- $needs_restart = 1;
- # if the calling script has a path for shared libs and there is no --environment
- # parameter then the called script surely needs the variable too.
- foreach my $important_env qw(LD_LIBRARY_PATH SHLIB_PATH
- ORACLE_HOME TNS_ADMIN ORA_NLS ORA_NLS33 ORA_NLS10) {
- if ($ENV{$important_env} && ! scalar(grep { /^$important_env=/ }
- keys %{$commandline{environment}})) {
- $commandline{environment}->{$important_env} = $ENV{$important_env};
- printf STDERR "add important --environment %s=%s\n",
- $important_env, $ENV{$important_env} if $DBD::MySQL::Server::verbose;
- }
- }
-}
-
-if ($needs_restart) {
- my @newargv = ();
- my $runas = undef;
- if (exists $commandline{runas}) {
- $runas = $commandline{runas};
- delete $commandline{runas};
- }
- foreach my $option (keys %commandline) {
- if (grep { /^$option/ && /=/ } @params) {
- if (ref ($commandline{$option}) eq "HASH") {
- foreach (keys %{$commandline{$option}}) {
- push(@newargv, sprintf "--%s", $option);
- push(@newargv, sprintf "%s=%s", $_, $commandline{$option}->{$_});
- }
- } else {
- push(@newargv, sprintf "--%s", $option);
- push(@newargv, sprintf "%s", $commandline{$option});
- }
- } else {
- push(@newargv, sprintf "--%s", $option);
- }
- }
- if ($runas) {
- exec "sudo", "-S", "-u", $runas, $0, @newargv;
- } else {
- exec $0, @newargv;
- # this makes sure that even a SHLIB or LD_LIBRARY_PATH are set correctly
- # when the perl interpreter starts. Setting them during runtime does not
- # help loading e.g. libclntsh.so
- }
- exit;
-}
-
-if (exists $commandline{shell}) {
- # forget what you see here.
- system("/bin/sh");
-}
-
-if (exists $commandline{name}) {
- # objects can be encoded like an url
- # with s/([^A-Za-z0-9])/sprintf("%%%02X", ord($1))/seg;
- if (($commandline{mode} ne "sql") ||
- (($commandline{mode} eq "sql") &&
- ($commandline{name} =~ /select%20/i))) { # protect ... like '%cac%' ... from decoding
- $commandline{name} =~ s/\%([A-Fa-f0-9]{2})/pack('C', hex($1))/seg;
- }
- if ($commandline{name} =~ /^0$/) {
- # without this, $params{selectname} would be treated like undef
- $commandline{name} = "00";
- }
-}
-
-$SIG{'ALRM'} = sub {
- printf "UNKNOWN - %s timed out after %d seconds\n", $PROGNAME, $TIMEOUT;
- exit $ERRORS{UNKNOWN};
-};
-alarm($TIMEOUT);
-
-my $nagios_level = $ERRORS{UNKNOWN};
-my $nagios_message = "";
-my $perfdata = "";
-if ($commandline{mode} =~ /^my-([^\-.]+)/) {
- my $param = $commandline{mode};
- $param =~ s/\-/::/g;
- push(@modes, [$param, $commandline{mode}, undef, 'my extension']);
-} elsif ((! grep { $commandline{mode} eq $_ } map { $_->[1] } @modes) &&
- (! grep { $commandline{mode} eq $_ } map { defined $_->[2] ? @{$_->[2]} : () } @modes)) {
- printf "UNKNOWN - mode %s\n", $commandline{mode};
- print_usage();
- exit 3;
-}
-
-$commandline{mode} = (
- map { $_->[0] }
- grep {
- ($commandline{mode} eq $_->[1]) ||
- ( defined $_->[2] && grep { $commandline{mode} eq $_ } @{$_->[2]})
- } @modes
-)[0];
-my %params = (
- timeout => $TIMEOUT,
- mode => $commandline{mode},
- method => $commandline{method} ||
- $ENV{NAGIOS__SERVICEMYSQL_METH} ||
- $ENV{NAGIOS__HOSTMYSQL_METH} || 'dbi',
- hostname => $commandline{hostname} ||
- $ENV{NAGIOS__SERVICEMYSQL_HOST} ||
- $ENV{NAGIOS__HOSTMYSQL_HOST} || 'localhost',
- database => $commandline{database} ||
- $ENV{NAGIOS__SERVICEMYSQL_DATABASE} ||
- $ENV{NAGIOS__HOSTMYSQL_DATABASE} || 'information_schema',
- port => $commandline{port} || (($commandline{mode} =~ /^cluster/) ?
- ($ENV{NAGIOS__SERVICENDBMGM_PORT} || $ENV{NAGIOS__HOSTNDBMGM_PORT} || 1186) :
- ($ENV{NAGIOS__SERVICEMYSQL_PORT} || $ENV{NAGIOS__HOSTMYSQL_PORT} || 3306)),
- socket => $commandline{socket} ||
- $ENV{NAGIOS__SERVICEMYSQL_SOCKET} ||
- $ENV{NAGIOS__HOSTMYSQL_SOCKET},
- username => $commandline{username} ||
- $ENV{NAGIOS__SERVICEMYSQL_USER} ||
- $ENV{NAGIOS__HOSTMYSQL_USER},
- password => $commandline{password} ||
- $ENV{NAGIOS__SERVICEMYSQL_PASS} ||
- $ENV{NAGIOS__HOSTMYSQL_PASS},
- warningrange => $commandline{warning},
- criticalrange => $commandline{critical},
- absolute => $commandline{absolute},
- lookback => $commandline{lookback},
- selectname => $commandline{name} || $commandline{tablespace} || $commandline{datafile},
- regexp => $commandline{regexp},
- name => $commandline{name},
- name2 => $commandline{name2} || $commandline{name},
- units => $commandline{units},
- lookback => $commandline{lookback} || 0,
- eyecandy => $commandline{eyecandy},
- statefilesdir => $STATEFILESDIR,
-);
-
-my $server = undef;
-my $cluster = undef;
-
-if ($params{mode} =~ /^(server|my)/) {
- $server = DBD::MySQL::Server->new(%params);
- $server->nagios(%params);
- $server->calculate_result();
- $nagios_message = $server->{nagios_message};
- $nagios_level = $server->{nagios_level};
- $perfdata = $server->{perfdata};
-} elsif ($params{mode} =~ /^cluster/) {
- $cluster = DBD::MySQL::Cluster->new(%params);
- $cluster->nagios(%params);
- $cluster->calculate_result();
- $nagios_message = $cluster->{nagios_message};
- $nagios_level = $cluster->{nagios_level};
- $perfdata = $cluster->{perfdata};
-}
-
-printf "%s - %s", $ERRORCODES{$nagios_level}, $nagios_message;
-printf " | %s", $perfdata if $perfdata;
-printf "\n";
-exit $nagios_level;
-
-
-__END__
-
-