├── NEWS ├── rel-eng ├── packages │ ├── check_mssql_health │ └── .readme ├── tito.props └── releasers.conf ├── AUTHORS ├── TODO ├── .gitmodules ├── plugins-scripts ├── Classes │ ├── APS │ │ ├── DBI.pm │ │ ├── Sqsh.pm │ │ ├── SqlRelay.pm │ │ └── Component │ │ │ ├── ComponentSubsystem.pm │ │ │ ├── AlertSubsystem.pm │ │ │ └── DiskSubsystem.pm │ ├── ASE │ │ ├── DBI.pm │ │ ├── Sqsh.pm │ │ ├── SqlRelay.pm │ │ └── Component │ │ │ └── DatabaseSubsystem.pm │ ├── MSSQL │ │ ├── DBI.pm │ │ ├── Sqsh.pm │ │ ├── SqlRelay.pm │ │ └── Component │ │ │ ├── MemorypoolSubsystem.pm │ │ │ ├── MemorypoolSubsystem │ │ │ ├── Lock.pm │ │ │ └── Buffercache.pm │ │ │ ├── AvailabilitygroupSubsystem.pm │ │ │ └── JobSubsystem.pm │ ├── APS.pm │ ├── Sybase │ │ ├── SqlRelay.pm │ │ ├── DBI.pm │ │ └── Sqsh.pm │ ├── ASE.pm │ ├── Device.pm │ ├── Sybase.pm │ └── MSSQL.pm ├── subst.in ├── Makefile.am └── check_mssql_health.pl ├── Makefile.am ├── FORMULA ├── t └── Makefile.am ├── doc └── Makefile.am ├── check_mssql_health.spec ├── contrib ├── delete_user.sql ├── create_user.sql └── README.formula ├── configure.ac ├── acinclude.m4 ├── README ├── README.md ├── missing ├── INSTALL ├── ChangeLog ├── install-sh └── COPYING /NEWS: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /rel-eng/packages/check_mssql_health: -------------------------------------------------------------------------------- 1 | 1.5.10-1 / 2 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Gerhard Lausser 2 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | --database is important 2 | 3 | examine sys.dm_os_volume_stats 4 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "GLPlugin"] 2 | path = GLPlugin 3 | url = https://github.com/lausser/GLPlugin.git 4 | -------------------------------------------------------------------------------- /plugins-scripts/Classes/APS/DBI.pm: -------------------------------------------------------------------------------- 1 | package Classes::APS::DBI; 2 | our @ISA = qw(Classes::APS Classes::Sybase::DBI); 3 | use strict; 4 | -------------------------------------------------------------------------------- /plugins-scripts/Classes/APS/Sqsh.pm: -------------------------------------------------------------------------------- 1 | package Classes::APS::Sqsh; 2 | our @ISA = qw(Classes::APS Classes::Sybase::Sqsh); 3 | use strict; 4 | -------------------------------------------------------------------------------- /plugins-scripts/Classes/ASE/DBI.pm: -------------------------------------------------------------------------------- 1 | package Classes::ASE::DBI; 2 | our @ISA = qw(Classes::ASE Classes::Sybase::DBI); 3 | use strict; 4 | -------------------------------------------------------------------------------- /plugins-scripts/Classes/ASE/Sqsh.pm: -------------------------------------------------------------------------------- 1 | package Classes::ASE::Sqsh; 2 | our @ISA = qw(Classes::ASE Classes::Sybase::Sqsh); 3 | use strict; 4 | -------------------------------------------------------------------------------- /plugins-scripts/Classes/MSSQL/DBI.pm: -------------------------------------------------------------------------------- 1 | package Classes::MSSQL::DBI; 2 | our @ISA = qw(Classes::MSSQL Classes::Sybase::DBI); 3 | use strict; 4 | -------------------------------------------------------------------------------- /plugins-scripts/Classes/MSSQL/Sqsh.pm: -------------------------------------------------------------------------------- 1 | package Classes::MSSQL::Sqsh; 2 | our @ISA = qw(Classes::MSSQL Classes::Sybase::Sqsh); 3 | use strict; 4 | -------------------------------------------------------------------------------- /plugins-scripts/Classes/APS/SqlRelay.pm: -------------------------------------------------------------------------------- 1 | package Classes::APS::Sqlrelay; 2 | our @ISA = qw(Classes::APS Classes::Sybase::Sqlrelay); 3 | use strict; 4 | -------------------------------------------------------------------------------- /plugins-scripts/Classes/ASE/SqlRelay.pm: -------------------------------------------------------------------------------- 1 | package Classes::ASE::Sqlrelay; 2 | our @ISA = qw(Classes::ASE Classes::Sybase::Sqlrelay); 3 | use strict; 4 | -------------------------------------------------------------------------------- /plugins-scripts/Classes/MSSQL/SqlRelay.pm: -------------------------------------------------------------------------------- 1 | package Classes::MSSQL::Sqlrelay; 2 | our @ISA = qw(Classes::MSSQL Classes::Sybase::Sqlrelay); 3 | use strict; 4 | -------------------------------------------------------------------------------- /rel-eng/packages/.readme: -------------------------------------------------------------------------------- 1 | the rel-eng/packages directory contains metadata files 2 | named after their packages. Each file has the latest tagged 3 | version and the project's relative directory. 4 | -------------------------------------------------------------------------------- /rel-eng/tito.props: -------------------------------------------------------------------------------- 1 | [globalconfig] 2 | default_builder = tito.builder.Builder 3 | default_tagger = tito.tagger.VersionTagger 4 | changelog_do_not_remove_cherrypick = 0 5 | changelog_format = %s (%ae) 6 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | ## Process this file with automake to produce Makefile.in 2 | 3 | SUBDIRS = plugins-scripts 4 | DOS2UNIX=$(shell which dos2unix || which fromdos) 5 | 6 | dist-hook: 7 | rm -f t/var/tmp/* 8 | rm -f t/var/adm/* 9 | find $(distdir) -type f -exec $(DOS2UNIX) {} >/dev/null 2>&1 \; 10 | make 11 | 12 | -------------------------------------------------------------------------------- /FORMULA: -------------------------------------------------------------------------------- 1 | datafile io 2 | http://media.wiley.com/product_data/excerpt/57/04701274/0470127457.pdf 3 | http://sqlserveradvisor.blogspot.com/2009/02/microsoft-included-fnvirtualfilestats.html 4 | 5 | http://www.databasejournal.com/features/mssql/article.php/3796551/SQL-Server-Database-File-IO-Report.htm 6 | select database id file id 7 | 8 | dbo.sysperfinfo bei sql server2000 und jeztz dm_os_perrformance_counters in 2005 9 | http://www.mssqltips.com/tip.asp?tip=1039 10 | 11 | WMI from linux 12 | http://forums.cacti.net/about29392.html 13 | -------------------------------------------------------------------------------- /t/Makefile.am: -------------------------------------------------------------------------------- 1 | ## 2 | ## Process this file with automake to produce Makefile.in 3 | ## 4 | 5 | AUTOMAKE_OPTIONS = 1.3 no-dependencies 6 | 7 | #all: tests 8 | 9 | TEST_VERBOSE=0 10 | TEST_TYPE=test_$(LINKTYPE) 11 | TEST_FILE = test.pl 12 | TEST_FILES = *.t 13 | TESTDB_SW = -d 14 | 15 | #EXTRA_DIST = *.t bin var etc 16 | EXTRA_DIST = *.t 17 | 18 | tests: 19 | $(PERL) "-MExtUtils::Command::MM" "-e" "test_harness($(TEST_VERBOSE))" $(TEST_FILES) 20 | # PERL_DL_NONLAZY=1 $(FULLPERLRUN) "-MExtUtils::Command::MM" "-e" "test_harness($(TEST_VERBOSE), '$(INST_LIB)', '$(INST_ARCHLIB)')" $(TEST_FILES) 21 | 22 | -------------------------------------------------------------------------------- /doc/Makefile.am: -------------------------------------------------------------------------------- 1 | PLUGIN=check_mssql_health 2 | 3 | docs: dedoc endoc 4 | $(RM) $(PLUGIN).html 5 | printf "\n\n" >> $(PLUGIN).html 6 | cat $(PLUGIN).de.html >> $(PLUGIN).html 7 | printf "\n\n" >> $(PLUGIN).html 8 | cat $(PLUGIN).en.html >> $(PLUGIN).html 9 | printf "\n\n" >> $(PLUGIN).html 10 | sed -ri '/col width/d' $(PLUGIN).html 11 | sed -ri 's/$$/\r/' $(PLUGIN).html 12 | 13 | dedoc: 14 | asciidoc --unsafe --no-header-footer -a max-width=800 $(PLUGIN).de.txt 15 | 16 | endoc: 17 | asciidoc --unsafe --no-header-footer -a max-width=800 $(PLUGIN).en.txt 18 | 19 | clean: 20 | $(RM) $(PLUGIN).html 21 | $(RM) $(PLUGIN).en.html 22 | $(RM) $(PLUGIN).de.html 23 | -------------------------------------------------------------------------------- /check_mssql_health.spec: -------------------------------------------------------------------------------- 1 | %define debug_package %{nil} 2 | 3 | Summary: Nagios plugins to check the status of MS-SQL Servers 4 | Name: check_mssql_health 5 | Version: 1.5.10 6 | Release: 1%{?dist} 7 | License: GPLv2+ 8 | Group: Applications/System 9 | URL: http://labs.consol.de/lang/en/nagios/check_mssql_health/ 10 | Source0: http://labs.consol.de/download/shinken-nagios-plugins/check_mssql_health-%{version}.tar.gz 11 | Requires: perl-Nagios-Plugin 12 | Requires: perl-DBD-Sybase 13 | BuildRequires: automake 14 | BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) 15 | 16 | 17 | %description 18 | check_mssql_health is a plugin, which is used to monitor different parameters of a MS SQL server. 19 | 20 | %prep 21 | %setup -T -b0 22 | 23 | %build 24 | aclocal 25 | autoconf 26 | automake 27 | ./configure --libexecdir=%{_libdir}/nagios/plugins/ --libdir=%{_libdir} 28 | make 29 | 30 | 31 | %install 32 | make install DESTDIR="%{buildroot}" 33 | 34 | %clean 35 | rm -rf %{buildroot} 36 | 37 | %files 38 | %defattr(-,root,root,-) 39 | %doc README COPYING 40 | %{_libdir}/nagios/plugins/check_mssql_health 41 | 42 | %changelog 43 | * Thu Aug 16 2012 Pall Sigurdsson 1.5.10-1 44 | - Initial packaging 45 | -------------------------------------------------------------------------------- /plugins-scripts/Classes/MSSQL/Component/MemorypoolSubsystem.pm: -------------------------------------------------------------------------------- 1 | package Classes::MSSQL::Component::MemorypoolSubsystem; 2 | our @ISA = qw(Monitoring::GLPlugin::DB::Item); 3 | use strict; 4 | 5 | sub init { 6 | my $self = shift; 7 | my $sql = undef; 8 | if ($self->mode =~ /server::memorypool::lock/) { 9 | my $columns = ['name']; 10 | my @locks = $self->get_instance_names('SQLServer:Locks'); 11 | @locks = map { 12 | "'".$_."'"; 13 | } map { 14 | s/\s*$//g; $_; 15 | } map { 16 | $_->[0]; 17 | } @locks; 18 | $sql = join(" UNION ALL ", map { "SELECT ".$_ } @locks); 19 | $self->get_db_tables([ 20 | ['locks', $sql, 'Classes::MSSQL::Component::MemorypoolSubsystem::Lock', sub { my $o = shift; $self->filter_name($o->{name}) }, $columns], 21 | ]); 22 | } elsif ($self->mode =~ /server::memorypool::buffercache/) { 23 | $self->analyze_and_check_buffercache_subsystem("Classes::MSSQL::Component::MemorypoolSubsystem::Buffercache"); 24 | } 25 | } 26 | 27 | sub check { 28 | my $self = shift; 29 | $self->add_info('checking memorypools'); 30 | if ($self->mode =~ /server::memorypool::lock::listlocks$/) { 31 | foreach (@{$self->{locks}}) { 32 | printf "%s\n", $_->{name}; 33 | } 34 | $self->add_ok("have fun"); 35 | } else { 36 | $self->SUPER::check(); 37 | } 38 | } 39 | 40 | -------------------------------------------------------------------------------- /contrib/delete_user.sql: -------------------------------------------------------------------------------- 1 | declare @dbname varchar(255) 2 | declare @check_mssql_health_USER varchar(255) 3 | declare @check_mssql_health_ROLE varchar(255) 4 | 5 | SET @check_mssql_health_USER = '"[Servername|Domainname]\Username"' 6 | SET @check_mssql_health_ROLE = 'Rolename' 7 | 8 | declare dblist cursor for 9 | select name from sysdatabases WHERE name NOT IN ('master', 'tempdb', 'msdb') open dblist 10 | fetch next from dblist into @dbname 11 | while @@fetch_status = 0 begin 12 | EXEC ('USE ' + @dbname + ' print ''Revoke permissions in the db '' + ''"'' + DB_NAME() + ''"''') 13 | EXEC ('USE ' + @dbname + ' EXEC sp_droprolemember ' + @check_mssql_health_ROLE + ' , ' + @check_mssql_health_USER) 14 | EXEC ('USE ' + @dbname + ' DROP USER ' + @check_mssql_health_USER) 15 | EXEC ('USE ' + @dbname + ' REVOKE VIEW DEFINITION TO ' + @check_mssql_health_ROLE) 16 | EXEC ('USE ' + @dbname + ' REVOKE VIEW DATABASE STATE TO ' + @check_mssql_health_ROLE) 17 | EXEC ('USE ' + @dbname + ' REVOKE EXECUTE TO ' + @check_mssql_health_ROLE) 18 | EXEC ('USE ' + @dbname + ' DROP ROLE ' + @check_mssql_health_ROLE) 19 | EXEC ('USE ' + @dbname + ' print ''Permissions in the db '' + ''"'' + DB_NAME() + ''" revoked.''') 20 | fetch next from dblist into @dbname 21 | end 22 | close dblist 23 | deallocate dblist 24 | 25 | PRINT '' 26 | PRINT 'drop Nagios plugin user ' + @check_mssql_health_USER 27 | EXEC ('USE MASTER REVOKE VIEW SERVER STATE TO ' + @check_mssql_health_USER) 28 | EXEC ('DROP LOGIN ' + @check_mssql_health_USER) 29 | PRINT 'User ' + @check_mssql_health_USER + ' dropped.' 30 | 31 | -------------------------------------------------------------------------------- /plugins-scripts/subst.in: -------------------------------------------------------------------------------- 1 | #!/usr/bin/awk 2 | 3 | function which(c,path) { 4 | cmd = "test -x " c; 5 | 6 | if (system(cmd)==0) { 7 | return c; 8 | } 9 | 10 | sub(/\/.*\//,"",c); 11 | for (dir in path) { 12 | cmd = "test -x " path[dir] "/" c; 13 | if (system(cmd)==0) { 14 | return path[dir] "/" c; 15 | } 16 | } 17 | 18 | 19 | return c; 20 | } 21 | 22 | # used to replace "use lib utils.pm" with "use lib @libexecdir" 23 | # 24 | function led() { 25 | led1 = "@libexecdir@"; 26 | led2 = "@exec_prefix@"; 27 | led3 = "@prefix@"; 28 | if ( match(led1, /^\$\{exec_prefix\}/ ) != 0 ) { 29 | return "\"" led3 "/libexec\" " ; 30 | 31 | } 32 | return "\"" led1 "\"" ; 33 | } 34 | 35 | BEGIN { 36 | split(ENVIRON["PATH"] ":/sbin:/usr/sbin",path,/:/); 37 | 38 | } 39 | 40 | # scripting language (first line) 41 | 42 | /^#! ?\/.*\/python/ {sub(/^#! ?\/.*\/python/,"#! @PYTHON@");} 43 | /^#! ?\/.*\/perl/ {sub(/^#! ?\/.*\/perl/,"#! @PERL@");} 44 | /^#! ?\/.*\/[a-z]{0,2}awk/ {sub(/^#! ?\/.*\/[a-z]{0,2}awk/,"#! @AWK@");} 45 | /^#! ?\/.*\/sh/ {sub(/^#! ?\/.*\/sh/,"#! @SHELL@");} 46 | 47 | # add to libexecdir to INC for perl utils.pm 48 | /^use/ { if (/lib/) { if (/utils.pm|"."/ ) {sub(/utils.pm|"."/,led() )} } } 49 | 50 | 51 | # Replace the placeholders with the values from configure 52 | /#PERL#/ {sub(/#PERL#/,"@PERL@");} 53 | /#GZIP#/ {sub(/#GZIP#/,"@GZIP@");} 54 | /#STATEFILES_DIR#/ {sub(/#STATEFILES_DIR#/,"@STATEFILES_DIR@");} 55 | /#PACKAGE_VERSION#/ {sub(/#PACKAGE_VERSION#/,"@PACKAGE_VERSION@");} 56 | /#MYMODULES_DYN_DIR#/ {sub(/#MYMODULES_DYN_DIR#/,"@MYMODULES_DYN_DIR@");} 57 | 58 | { 59 | print; 60 | } 61 | 62 | -------------------------------------------------------------------------------- /plugins-scripts/Classes/APS.pm: -------------------------------------------------------------------------------- 1 | package Classes::APS; 2 | our @ISA = qw(Classes::Sybase); 3 | 4 | use strict; 5 | use Time::HiRes; 6 | use IO::File; 7 | use File::Copy 'cp'; 8 | use Data::Dumper; 9 | our $AUTOLOAD; 10 | 11 | 12 | sub init { 13 | my $self = shift; 14 | $self->set_variable("dbuser", $self->fetchrow_array( 15 | q{ SELECT SYSTEM_USER } 16 | )); 17 | if ($self->mode =~ /^server::aps::component/) { 18 | $self->analyze_and_check_component_subsystem("Classes::APS::Component::ComponentSubsystem"); 19 | } elsif ($self->mode =~ /^server::aps::alert/) { 20 | $self->analyze_and_check_alert_subsystem("Classes::APS::Component::AlertSubsystem"); 21 | } elsif ($self->mode =~ /^server::aps::disk/) { 22 | $self->analyze_and_check_alert_subsystem("Classes::APS::Component::DiskSubsystem"); 23 | } else { 24 | $self->no_such_mode(); 25 | } 26 | } 27 | 28 | sub has_threshold_table { 29 | my $self = shift; 30 | if (! exists $self->{has_threshold_table}) { 31 | my $find_sql; 32 | if ($self->version_is_minimum("9.x")) { 33 | $find_sql = q{ 34 | SELECT name FROM sys.objects 35 | WHERE name = 'check_mssql_health_thresholds' 36 | }; 37 | } else { 38 | $find_sql = q{ 39 | SELECT name FROM sysobjects 40 | WHERE name = 'check_mssql_health_thresholds' 41 | }; 42 | } 43 | if ($self->{handle}->fetchrow_array($find_sql)) { 44 | $self->{has_threshold_table} = 'check_mssql_health_thresholds'; 45 | } else { 46 | $self->{has_threshold_table} = undef; 47 | } 48 | } 49 | return $self->{has_threshold_table}; 50 | } 51 | 52 | -------------------------------------------------------------------------------- /plugins-scripts/Classes/Sybase/SqlRelay.pm: -------------------------------------------------------------------------------- 1 | package Classes::Sybase::SqlRelay; 2 | our @ISA = qw(Classes::Sybase Monitoring::GLPlugin::DB::DBI); 3 | use strict; 4 | use File::Basename; 5 | 6 | sub check_connect { 7 | my $self = shift; 8 | my $stderrvar; 9 | my $dbi_options = { RaiseError => 1, AutoCommit => $self->opts->commit, PrintError => 1 }; 10 | my $dsn = "DBI:SQLRelay:"; 11 | $dsn .= sprintf ";host=%s", $self->opts->hostname; 12 | $dsn .= sprintf ";port=%s", $self->opts->port; 13 | $dsn .= sprintf ";socket=%s", $self->opts->socket; 14 | if ($self->opts->currentdb) { 15 | if (index($self->opts->currentdb,"-") != -1) { 16 | $dsn .= sprintf ";database=\"%s\"", $self->opts->currentdb; 17 | } else { 18 | $dsn .= sprintf ";database=%s", $self->opts->currentdb; 19 | } 20 | } 21 | $self->set_variable("dsn", $dsn); 22 | eval { 23 | require DBI; 24 | $self->set_timeout_alarm($self->opts->timeout - 1, sub { 25 | die "alrm"; 26 | }); 27 | *SAVEERR = *STDERR; 28 | open OUT ,'>',\$stderrvar; 29 | *STDERR = *OUT; 30 | $self->{tic} = Time::HiRes::time(); 31 | if ($self->{handle} = DBI->connect( 32 | $dsn, 33 | $self->opts->username, 34 | $self->opts->password, 35 | $dbi_options)) { 36 | $Monitoring::GLPlugin::DB::session = $self->{handle}; 37 | } 38 | $self->{tac} = Time::HiRes::time(); 39 | *STDERR = *SAVEERR; 40 | }; 41 | if ($@) { 42 | if ($@ =~ /alrm/) { 43 | $self->add_critical( 44 | sprintf "connection could not be established within %s seconds", 45 | $self->opts->timeout); 46 | } else { 47 | $self->add_critical($@); 48 | } 49 | } elsif (! $self->{handle}) { 50 | $self->add_critical("no connection"); 51 | } else { 52 | $self->set_timeout_alarm($self->opts->timeout - ($self->{tac} - $self->{tic})); 53 | } 54 | } 55 | 56 | -------------------------------------------------------------------------------- /plugins-scripts/Classes/APS/Component/ComponentSubsystem.pm: -------------------------------------------------------------------------------- 1 | package Classes::APS::Component::ComponentSubsystem; 2 | our @ISA = qw(Monitoring::GLPlugin::DB::Item); 3 | use strict; 4 | 5 | sub init { 6 | my $self = shift; 7 | my $sql = undef; 8 | if ($self->mode =~ /server::aps::component::failed/) { 9 | my $columns = ['node_name', 'name', 'instance_id', 10 | 'property_name', 'property_value', 'update_time']; 11 | my $sql = q{ 12 | SELECT 13 | NodeName, 14 | ComponentName, 15 | ComponentInstanceId, 16 | ComponentPropertyName, 17 | ComponentPropertyValue, 18 | UpdateTime 19 | FROM 20 | SQL_ADMIN.[dbo].status_components_dc 21 | WHERE 22 | ComponentPropertyValue NOT IN ('OK','UNKNOWN') 23 | ORDER BY 24 | ComponentName desc"; 25 | }; 26 | $self->get_db_tables([ 27 | ['components', $sql, 'Classes::APS::Component::ComponentSubsystem::Component', sub { my $o = shift; $self->filter_name($o->{name}); }, $columns], 28 | ]); 29 | } 30 | } 31 | 32 | sub check { 33 | my $self = shift; 34 | $self->add_info('checking components'); 35 | if ($self->mode =~ /server::aps::component::failed/) { 36 | if (@{$self->{components}}) { 37 | $self->add_critical( 38 | sprintf '%d failed components', scalar(@{$self->{components}}) 39 | ); 40 | $self->SUPER::check(); 41 | } else { 42 | $self->add_ok("no failed components"); 43 | } 44 | } else { 45 | $self->SUPER::check(); 46 | } 47 | } 48 | 49 | package Classes::APS::Component::ComponentSubsystem::Component; 50 | our @ISA = qw(Monitoring::GLPlugin::DB::TableItem); 51 | use strict; 52 | 53 | sub finish { 54 | my $self = shift; 55 | my $columns = ['node_name', 'name', 'instance_id', 56 | 'property_name', 'property_value', 'update_time']; 57 | $self->{message} = join(",", map { $self->{$_} } @{$columns}); 58 | } 59 | 60 | sub check { 61 | my $self = shift; 62 | if ($self->{property_value} !~ /^(OK|UNKNOWN)$/) { 63 | $self->add_critical($self->{message}); 64 | } 65 | } 66 | 67 | -------------------------------------------------------------------------------- /plugins-scripts/Classes/ASE.pm: -------------------------------------------------------------------------------- 1 | package Classes::ASE; 2 | our @ISA = qw(Classes::Sybase); 3 | 4 | use strict; 5 | use Time::HiRes; 6 | use IO::File; 7 | use File::Copy 'cp'; 8 | use Data::Dumper; 9 | our $AUTOLOAD; 10 | 11 | 12 | sub init { 13 | my $self = shift; 14 | $self->set_variable("dbuser", $self->fetchrow_array( 15 | q{ SELECT SUSER_NAME() } 16 | )); 17 | $self->set_variable("maxpagesize", $self->fetchrow_array( 18 | q{ SELECT @@MAXPAGESIZE } 19 | )); 20 | if ($self->mode =~ /^server::connectedusers/) { 21 | my $connectedusers = $self->fetchrow_array(q{ 22 | SELECT 23 | COUNT(*) 24 | FROM 25 | master..sysprocesses 26 | WHERE 27 | hostprocess IS NOT NULL AND program_name != 'JS Agent' 28 | }); 29 | if (! defined $connectedusers) { 30 | $self->add_unknown("unable to count connected users"); 31 | } else { 32 | $self->set_thresholds(warning => 50, critical => 80); 33 | $self->add_message($self->check_thresholds($connectedusers), 34 | sprintf "%d connected users", $connectedusers); 35 | $self->add_perfdata( 36 | label => "connected_users", 37 | value => $connectedusers 38 | ); 39 | } 40 | } elsif ($self->mode =~ /^server::database/) { 41 | $self->analyze_and_check_database_subsystem("Classes::ASE::Component::DatabaseSubsystem"); 42 | $self->reduce_messages_short(); 43 | } else { 44 | $self->no_such_mode(); 45 | } 46 | } 47 | 48 | sub has_threshold_table { 49 | my $self = shift; 50 | if (! exists $self->{has_threshold_table}) { 51 | my $find_sql; 52 | if ($self->version_is_minimum("9.x")) { 53 | $find_sql = q{ 54 | SELECT name FROM sys.objects 55 | WHERE name = 'check_ase_health_thresholds' 56 | }; 57 | } else { 58 | $find_sql = q{ 59 | SELECT name FROM sysobjects 60 | WHERE name = 'check_ase_health_thresholds' 61 | }; 62 | } 63 | if ($self->{handle}->fetchrow_array($find_sql)) { 64 | $self->{has_threshold_table} = 'check_ase_health_thresholds'; 65 | } else { 66 | $self->{has_threshold_table} = undef; 67 | } 68 | } 69 | return $self->{has_threshold_table}; 70 | } 71 | 72 | 73 | -------------------------------------------------------------------------------- /plugins-scripts/Classes/Device.pm: -------------------------------------------------------------------------------- 1 | package Classes::Device; 2 | our @ISA = qw(Monitoring::GLPlugin::DB); 3 | use strict; 4 | 5 | 6 | sub classify { 7 | my $self = shift; 8 | if ($self->opts->method eq "dbi") { 9 | bless $self, "Classes::Sybase::DBI"; 10 | if ((! $self->opts->hostname && ! $self->opts->server) || 11 | ! $self->opts->username || ! $self->opts->password) { 12 | $self->add_unknown('Please specify hostname or server, username and password'); 13 | } 14 | if (! eval "require DBD::Sybase") { 15 | $self->add_critical('could not load perl module DBD::Sybase'); 16 | } 17 | } elsif ($self->opts->method eq "sqsh") { 18 | bless $self, "Classes::Sybase::Sqsh"; 19 | if ((! $self->opts->hostname && ! $self->opts->server) || 20 | ! $self->opts->username || ! $self->opts->password) { 21 | $self->add_unknown('Please specify hostname or server, username and password'); 22 | } 23 | } elsif ($self->opts->method eq "sqlcmd") { 24 | bless $self, "Classes::Sybase::Sqlcmd"; 25 | if ((! $self->opts->hostname && ! $self->opts->server) || 26 | ! $self->opts->username || ! $self->opts->password) { 27 | $self->add_unknown('Please specify hostname or server, username and password'); 28 | } 29 | } elsif ($self->opts->method eq "sqlrelay") { 30 | bless $self, "Classes::Sybase::Sqlrelay"; 31 | if ((! $self->opts->hostname && ! $self->opts->server) || 32 | ! $self->opts->username || ! $self->opts->password) { 33 | $self->add_unknown('Please specify hostname or server, username and password'); 34 | } 35 | if (! eval "require DBD::SQLRelay") { 36 | $self->add_critical('could not load perl module SQLRelay'); 37 | } 38 | } 39 | if (! $self->check_messages()) { 40 | $self->check_connect(); 41 | if (! $self->check_messages()) { 42 | $self->add_dbi_funcs(); 43 | $self->check_version(); 44 | my $class = ref($self); 45 | $class =~ s/::Sybase::/::MSSQL::/ if $self->get_variable("product") eq "MSSQL"; 46 | $class =~ s/::Sybase::/::ASE::/ if $self->get_variable("product") eq "ASE"; 47 | $class =~ s/::Sybase::/::APS::/ if $self->get_variable("product") eq "APS"; 48 | bless $self, $class; 49 | $self->add_dbi_funcs(); 50 | if ($self->opts->mode =~ /^my-/) { 51 | $self->load_my_extension(); 52 | } 53 | } 54 | } 55 | } 56 | 57 | -------------------------------------------------------------------------------- /plugins-scripts/Classes/Sybase.pm: -------------------------------------------------------------------------------- 1 | package Classes::Sybase; 2 | our @ISA = qw(Classes::Device); 3 | 4 | use strict; 5 | use Time::HiRes; 6 | use IO::File; 7 | use File::Copy 'cp'; 8 | use Data::Dumper; 9 | our $AUTOLOAD; 10 | 11 | 12 | sub check_version { 13 | my $self = shift; 14 | #$self->{version} = $self->{handle}->fetchrow_array( 15 | # q{ SELECT SERVERPROPERTY('productversion') }); 16 | # @@VERSION: 17 | # Variant1: 18 | # Adaptive Server Enterprise/15.5/EBF 18164 SMP ESD#2/P/x86_64/Enterprise Linux/asear155/2514/64-bit/FBO/Wed Aug 25 11:17:26 2010 19 | # Variant2: 20 | # Microsoft SQL Server 2005 - 9.00.1399.06 (Intel X86) 21 | # Oct 14 2005 00:33:37 22 | # Copyright (c) 1988-2005 Microsoft Corporation 23 | # Enterprise Edition on Windows NT 5.2 (Build 3790: Service Pack 2) 24 | map { 25 | $self->set_variable("os", "Linux") if /Linux/; 26 | $self->set_variable("version", $1) if /Adaptive Server Enterprise\/([\d\.]+)/; 27 | $self->set_variable("os", $1) if /Windows (.*)/; 28 | $self->set_variable("version", $1) if /SQL Server.*\-\s*([\d\.]+)/; 29 | $self->set_variable("product", "ASE") if /Adaptive Server/; 30 | $self->set_variable("product", "MSSQL") if /SQL Server/; 31 | $self->set_variable("product", "APS") if /Parallel Data Warehouse/; 32 | } $self->fetchrow_array(q{ SELECT @@VERSION }); 33 | } 34 | 35 | sub create_statefile { 36 | my $self = shift; 37 | my %params = @_; 38 | my $extension = ""; 39 | $extension .= $params{name} ? '_'.$params{name} : ''; 40 | if ($self->opts->can('hostname') && $self->opts->hostname) { 41 | $extension .= '_'.$self->opts->hostname; 42 | $extension .= '_'.$self->opts->port; 43 | } 44 | if ($self->opts->can('server') && $self->opts->server) { 45 | $extension .= '_'.$self->opts->server; 46 | } 47 | if ($self->opts->mode eq 'sql' && $self->opts->username) { 48 | $extension .= '_'.$self->opts->username; 49 | } 50 | $extension =~ s/\//_/g; 51 | $extension =~ s/\(/_/g; 52 | $extension =~ s/\)/_/g; 53 | $extension =~ s/\*/_/g; 54 | $extension =~ s/\s/_/g; 55 | return sprintf "%s/%s%s", $self->statefilesdir(), 56 | $self->opts->mode, lc $extension; 57 | } 58 | 59 | sub add_dbi_funcs { 60 | my $self = shift; 61 | { 62 | no strict 'refs'; 63 | *{'Monitoring::GLPlugin::DB::CSF::create_statefile'} = \&{"Classes::Sybase::create_statefile"}; 64 | } 65 | } 66 | 67 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | dnl Process this file with autoconf to produce a configure script. 2 | AC_REVISION ($Revision: 1.150 $) 3 | AC_PREREQ(2.58) 4 | AC_INIT(check_mssql_health,2.7.8) 5 | AM_INIT_AUTOMAKE([1.9 tar-pax]) 6 | AM_MAINTAINER_MODE([disable]) 7 | AC_CANONICAL_HOST 8 | 9 | RELEASE=1 10 | AC_SUBST(RELEASE) 11 | 12 | AC_PREFIX_DEFAULT(/usr/local/nagios) 13 | 14 | dnl Figure out how to invoke "install" and what install options to use. 15 | AC_PROG_INSTALL 16 | AC_SUBST(INSTALL) 17 | 18 | AC_PROG_MAKE_SET 19 | AC_PROG_AWK 20 | 21 | WARRANTY="This plugin comes with ABSOLUTELY NO WARRANTY. You may redistribute\ncopies of the plugin under the terms of the GNU General Public License.\nFor more information about these matters, see the file named COPYING.\n" 22 | AC_SUBST(WARRANTY) 23 | 24 | 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" 25 | AC_SUBST(SUPPORT) 26 | 27 | AC_ARG_WITH(nagios_user, 28 | ACX_HELP_STRING([--with-nagios-user=USER], 29 | [set user name to run nagios]), 30 | with_nagios_user=$withval, 31 | with_nagios_user=nagios) 32 | AC_ARG_WITH(nagios_group, 33 | ACX_HELP_STRING([--with-nagios-group=GROUP], 34 | [set group name to run nagios]), 35 | with_nagios_group=$withval, 36 | with_nagios_group=nagios) 37 | AC_SUBST(with_nagios_user) 38 | AC_SUBST(with_nagios_group) 39 | INSTALL_OPTS="-o $with_nagios_user -g $with_nagios_group" 40 | AC_SUBST(INSTALL_OPTS) 41 | 42 | EXTRAS= 43 | dnl PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/etc:/usr/local/bin:/usr/local/sbin:$PATH 44 | 45 | dnl Checks for programs. 46 | AC_PATH_PROG(SH,sh) 47 | AC_PATH_PROG(PERL,perl) 48 | 49 | dnl allow them to override the path of perl 50 | AC_ARG_WITH(perl, 51 | ACX_HELP_STRING([--with-perl=PATH], 52 | [sets path to perl executable]), 53 | with_perl=$withval,with_perl=$PERL) 54 | AC_SUBST(PERL, $with_perl) 55 | 56 | AC_ARG_ENABLE([standalone], 57 | AS_HELP_STRING([--disable-standalone], [Disable feature standalone])) 58 | AM_CONDITIONAL([DISABLE_STANDALONE], [test "$enable_standalone" = "no"]) 59 | 60 | AC_OUTPUT(Makefile plugins-scripts/Makefile plugins-scripts/subst) 61 | 62 | ACX_FEATURE([with],[perl]) 63 | ACX_FEATURE([with],[nagios-user]) 64 | ACX_FEATURE([with],[nagios-group]) 65 | ACX_FEATURE([disable],[standalone], $disable_standalone) 66 | -------------------------------------------------------------------------------- /plugins-scripts/Classes/APS/Component/AlertSubsystem.pm: -------------------------------------------------------------------------------- 1 | package Classes::APS::Component::AlertSubsystem; 2 | our @ISA = qw(Monitoring::GLPlugin::DB::Item); 3 | use strict; 4 | 5 | sub init { 6 | my $self = shift; 7 | my $sql = undef; 8 | if ($self->mode =~ /server::aps::alert::active/) { 9 | my $columns = ['node_name', 'component_name', 'component_instance_id', 10 | 'name', 'state', 'severity', 'type', 'status', 'create_time']; 11 | my $sql = q{ 12 | SELECT 13 | NodeName, 14 | ComponentName, 15 | ComponentInstanceId, 16 | AlertName, 17 | AlertState, 18 | AlertSeverity, 19 | AlertType, 20 | AlertStatus, 21 | CreateTime 22 | FROM 23 | SQL_ADMIN.[dbo].current_alerts_dc 24 | -- WHERE 25 | -- AlertSeverity <> 'Informational' 26 | ORDER BY 27 | CreateTime DESC 28 | }; 29 | $self->get_db_tables([ 30 | ['alerts', $sql, 'Classes::APS::Component::AlertSubsystem::Alert', sub { my $o = shift; $self->filter_name($o->{name}); }, $columns], 31 | ]); 32 | } 33 | } 34 | 35 | sub check { 36 | my $self = shift; 37 | $self->add_info('checking alerts'); 38 | if ($self->mode =~ /server::aps::alert::active/) { 39 | $self->set_thresholds( 40 | metric => 'active_alerts', 41 | warning => 0, 42 | critical => 0, 43 | ); 44 | my @active_alerts = grep { $_->{severity} ne "Informational" } @{$self->{alerts}}; 45 | if (scalar(@active_alerts)) { 46 | $self->add_message( 47 | $self->check_thresholds(metric => 'active_alerts', value => scalar(@active_alerts)), 48 | sprintf '%d active alerts', scalar(@{$self->{alerts}}) 49 | ); 50 | foreach (@active_alerts) { 51 | $self->add_ok($_->{message}); 52 | } 53 | } else { 54 | $self->add_ok("no active alerts"); 55 | } 56 | } else { 57 | $self->SUPER::check(); 58 | } 59 | } 60 | 61 | package Classes::APS::Component::AlertSubsystem::Alert; 62 | our @ISA = qw(Monitoring::GLPlugin::DB::TableItem); 63 | use strict; 64 | 65 | sub finish { 66 | my $self = shift; 67 | my $columns = ['node_name', 'component_name', 'component_instance_id', 68 | 'name', 'state', 'severity', 'type', 'status', 'create_time']; 69 | $self->{message} = join(",", map { $self->{$_} } @{$columns}); 70 | } 71 | 72 | sub check { 73 | my $self = shift; 74 | if ($self->{severity} ne "Informational") { 75 | $self->add_critical($self->{message}); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /acinclude.m4: -------------------------------------------------------------------------------- 1 | dnl @synopsis ACX_WHICH_GETHOSTBYNAME_R 2 | dnl 3 | dnl Provides a test to determine the correct way to call gethostbyname_r 4 | dnl 5 | dnl defines HAVE_GETHOSTBYNAME_R to the number of arguments required 6 | dnl 7 | dnl e.g. 6 arguments (linux) 8 | dnl e.g. 5 arguments (solaris) 9 | dnl e.g. 3 arguments (osf/1) 10 | dnl 11 | dnl @version $Id: acinclude.m4,v 1.5 2004/02/18 14:56:34 kdebisschop Exp $ 12 | dnl @author Brian Stafford 13 | dnl 14 | dnl based on version by Caolan McNamara 15 | dnl based on David Arnold's autoconf suggestion in the threads faq 16 | dnl 17 | AC_DEFUN([ACX_WHICH_GETHOSTBYNAME_R], 18 | [AC_CACHE_CHECK(number of arguments to gethostbyname_r, 19 | acx_which_gethostbyname_r, [ 20 | AC_TRY_COMPILE([ 21 | # include 22 | ], [ 23 | 24 | char *name; 25 | struct hostent *he; 26 | struct hostent_data data; 27 | (void) gethostbyname_r(name, he, &data); 28 | 29 | ],acx_which_gethostbyname_r=3, 30 | [ 31 | dnl acx_which_gethostbyname_r=0 32 | AC_TRY_COMPILE([ 33 | # include 34 | ], [ 35 | char *name; 36 | struct hostent *he, *res; 37 | char *buffer = NULL; 38 | int buflen = 2048; 39 | int h_errnop; 40 | (void) gethostbyname_r(name, he, buffer, buflen, &res, &h_errnop) 41 | ],acx_which_gethostbyname_r=6, 42 | 43 | [ 44 | dnl acx_which_gethostbyname_r=0 45 | AC_TRY_COMPILE([ 46 | # include 47 | ], [ 48 | char *name; 49 | struct hostent *he; 50 | char *buffer = NULL; 51 | int buflen = 2048; 52 | int h_errnop; 53 | (void) gethostbyname_r(name, he, buffer, buflen, &h_errnop) 54 | ],acx_which_gethostbyname_r=5,acx_which_gethostbyname_r=0) 55 | 56 | ] 57 | 58 | ) 59 | ] 60 | ) 61 | ]) 62 | 63 | if test $acx_which_gethostbyname_r -gt 0 ; then 64 | AC_DEFINE_UNQUOTED([HAVE_GETHOSTBYNAME_R], $acx_which_gethostbyname_r, 65 | [Number of parameters to gethostbyname_r or 0 if not available]) 66 | fi 67 | 68 | ]) 69 | 70 | dnl @synopsis ACX_HELP_STRING(OPTION,DESCRIPTION) 71 | AC_DEFUN([ACX_HELP_STRING], 72 | [ $1 builtin([substr],[ ],len($1))[$2]]) 73 | 74 | 75 | dnl @synopsis ACX_FEATURE(ENABLE_OR_WITH,NAME[,VALUE]) 76 | AC_DEFUN([ACX_FEATURE], 77 | [echo "builtin([substr],[ ],len(--$1-$2))--$1-$2: ifelse($3,,[$]translit($1-$2,-,_),$3)"]) 78 | 79 | -------------------------------------------------------------------------------- /plugins-scripts/Makefile.am: -------------------------------------------------------------------------------- 1 | libexec_SCRIPTS=check_mssql_health 2 | GL_MODULES=\ 3 | ../GLPlugin/lib/Monitoring/GLPlugin/Commandline/Extraopts.pm \ 4 | ../GLPlugin/lib/Monitoring/GLPlugin/Commandline/Getopt.pm \ 5 | ../GLPlugin/lib/Monitoring/GLPlugin/Commandline.pm \ 6 | ../GLPlugin/lib/Monitoring/GLPlugin.pm \ 7 | ../GLPlugin/lib/Monitoring/GLPlugin/Item.pm \ 8 | ../GLPlugin/lib/Monitoring/GLPlugin/TableItem.pm \ 9 | ../GLPlugin/lib/Monitoring/GLPlugin/DB.pm \ 10 | ../GLPlugin/lib/Monitoring/GLPlugin/DB/DBI.pm \ 11 | ../GLPlugin/lib/Monitoring/GLPlugin/DB/CSF.pm \ 12 | ../GLPlugin/lib/Monitoring/GLPlugin/DB/Item.pm \ 13 | ../GLPlugin/lib/Monitoring/GLPlugin/DB/TableItem.pm 14 | EXTRA_MODULES=\ 15 | Classes/MSSQL/Component/AvailabilitygroupSubsystem.pm \ 16 | Classes/MSSQL/Component/DatabaseSubsystem.pm \ 17 | Classes/MSSQL/Component/MemorypoolSubsystem/Buffercache.pm \ 18 | Classes/MSSQL/Component/MemorypoolSubsystem/Lock.pm \ 19 | Classes/MSSQL/Component/MemorypoolSubsystem.pm \ 20 | Classes/MSSQL/Component/JobSubsystem.pm \ 21 | Classes/MSSQL/SqlRelay.pm \ 22 | Classes/MSSQL/Sqsh.pm \ 23 | Classes/MSSQL/DBI.pm \ 24 | Classes/MSSQL.pm \ 25 | Classes/ASE/Component/DatabaseSubsystem.pm \ 26 | Classes/ASE/SqlRelay.pm \ 27 | Classes/ASE/Sqsh.pm \ 28 | Classes/ASE/DBI.pm \ 29 | Classes/ASE.pm \ 30 | Classes/APS/Component/ComponentSubsystem.pm \ 31 | Classes/APS/Component/DiskSubsystem.pm \ 32 | Classes/APS/Component/AlertSubsystem.pm \ 33 | Classes/APS/SqlRelay.pm \ 34 | Classes/APS/Sqsh.pm \ 35 | Classes/APS/DBI.pm \ 36 | Classes/APS.pm \ 37 | Classes/Sybase/SqlRelay.pm \ 38 | Classes/Sybase/Sqsh.pm \ 39 | Classes/Sybase/DBI.pm \ 40 | Classes/Sybase.pm \ 41 | Classes/Device.pm 42 | 43 | 44 | SED=/bin/sed 45 | GREP=/bin/grep 46 | CAT=/bin/cat 47 | ECHO=/bin/echo 48 | if DISABLE_STANDALONE 49 | STANDALONE = no 50 | else 51 | STANDALONE = yes 52 | endif 53 | 54 | SUFFIXES = .pl .pm .sh 55 | 56 | VPATH=$(top_srcdir) $(top_srcdir)/plugins-scripts $(top_srcdir)/plugins-scripts/t 57 | 58 | EXTRA_DIST=$(libexec_SCRIPTS).pl $(EXTRA_MODULES) $(GL_MODULES) 59 | 60 | CLEANFILES=$(libexec_SCRIPTS) 61 | 62 | AM_INSTALL_PROGRAM_FLAGS=@INSTALL_OPTS@ 63 | 64 | .pm : 65 | $(AWK) -f ./subst $< > $@ 66 | chmod +x $@ 67 | 68 | .pl : 69 | $(AWK) -f ./subst $< > $@ 70 | chmod +x $@ 71 | 72 | .sh : 73 | $(AWK) -f ./subst $< > $@ 74 | chmod +x $@ 75 | 76 | $(libexec_SCRIPTS) : $(EXTRA_DIST) 77 | $(ECHO) "#! #PERL# -w" | $(AWK) -f ./subst > $@ 78 | $(ECHO) "# nagios: -epn" >> $@ 79 | $(ECHO) >> $@ 80 | if [ "${STANDALONE}" == "yes" ]; then \ 81 | $(ECHO) i am standalone; \ 82 | for m in ${GL_MODULES}; do \ 83 | $(SED) -e 's/^1;//g' < $$m | $(SED) -e '/^__END__/,$$d' | $(SED) -e '/^__PACKAGE__/,$$d' | $(AWK) -f ./subst >> $@; \ 84 | done \ 85 | fi 86 | for m in ${EXTRA_MODULES}; do \ 87 | $(SED) -e 's/^1;//g' < $$m | $(SED) -e '/^__END__/,$$d' | $(AWK) -f ./subst >> $@; \ 88 | done 89 | $(ECHO) "package main;" >> $@ 90 | $(CAT) $(libexec_SCRIPTS).pl | $(AWK) -f ./subst >> $@ 91 | chmod +x $@ 92 | 93 | -------------------------------------------------------------------------------- /rel-eng/releasers.conf: -------------------------------------------------------------------------------- 1 | # Fedora FC16 2 | [production-fc16-x86_64] 3 | releaser = tito.release.YumRepoReleaser 4 | builder = tito.builder.MockBuilder 5 | builder.mock = fedora-16-x86_64 6 | rsync = tito@opensource.is:/var/www/sites/opensource.ok.is/repo/fedora16/x86_64/ 7 | 8 | 9 | 10 | # RHEL 6 11 | [production-el6-x86_64] 12 | releaser = tito.release.YumRepoReleaser 13 | builder = tito.builder.MockBuilder 14 | builder.mock = epel-6-x86_64 15 | rsync = tito@opensource.is:/var/www/sites/opensource.ok.is/repo/rhel6/x86_64/ 16 | 17 | [production-el6-i386] 18 | releaser = tito.release.YumRepoReleaser 19 | builder = tito.builder.MockBuilder 20 | builder.mock = epel-6-i386 21 | rsync = tito@opensource.is:/var/www/sites/opensource.ok.is/repo/rhel6/i386/ 22 | 23 | 24 | 25 | # RHEL 5 Production 26 | [production-el5-x86_64] 27 | releaser = tito.release.YumRepoReleaser 28 | builder = tito.builder.MockBuilder 29 | builder.mock = epel-5-x86_64 30 | createrepo_command = createrepo -s sha1 . 31 | rsync = tito@opensource.is:/var/www/sites/opensource.ok.is/repo/rhel5/x86_64/ 32 | 33 | 34 | [production-el5-i386] 35 | releaser = tito.release.YumRepoReleaser 36 | builder = tito.builder.MockBuilder 37 | builder.mock = epel-5-i386 38 | createrepo_command = createrepo -s sha1 . 39 | rsync = tito@opensource.is:/var/www/sites/opensource.ok.is/repo/rhel5/i386/ 40 | 41 | 42 | # RHEL 5 Testing 43 | [test-el5-x86_64] 44 | releaser = tito.release.YumRepoReleaser 45 | builder = tito.builder.MockBuilder 46 | builder.mock = epel-5-x86_64 47 | builder.test = 1 48 | createrepo_command = createrepo -s sha1 . 49 | rsync = tito@opensource.is:/var/www/sites/opensource.ok.is/repo/testing/rhel5/x86_64/ 50 | 51 | 52 | [test-el5-i386] 53 | releaser = tito.release.YumRepoReleaser 54 | builder = tito.builder.MockBuilder 55 | builder.mock = epel-5-i386 56 | builder.test = 1 57 | createrepo_command = createrepo -s sha1 . 58 | rsync = tito@opensource.is:/var/www/sites/opensource.ok.is/repo/testing/rhel5/i386/ 59 | 60 | 61 | # RHEL 6 Test 62 | [test-el6-x86_64] 63 | releaser = tito.release.YumRepoReleaser 64 | builder = tito.builder.MockBuilder 65 | builder.mock = epel-6-x86_64 66 | builder.test = 1 67 | rsync = tito@opensource.is:/var/www/sites/opensource.ok.is/repo/testing/rhel6/x86_64/ 68 | 69 | [test-el6-i386] 70 | releaser = tito.release.YumRepoReleaser 71 | builder = tito.builder.MockBuilder 72 | builder.mock = epel-6-i386 73 | builder.test = 1 74 | rsync = tito@opensource.is:/var/www/sites/opensource.ok.is/repo/testing/rhel6/i386/ 75 | 76 | 77 | 78 | # Fedora FC16 79 | [test-fc16-x86_64] 80 | releaser = tito.release.YumRepoReleaser 81 | builder = tito.builder.MockBuilder 82 | builder.mock = fedora-16-x86_64 83 | rsync = tito@opensource.is:/var/www/sites/opensource.ok.is/repo/testing/fedora16/x86_64/ 84 | 85 | 86 | # sources 87 | [production-tarballs] 88 | releaser = tito.release.RsyncReleaser 89 | builder = tito.builder.Builder 90 | filetypes = tgz 91 | rsync = tito@opensource.is:/var/www/sites/opensource.ok.is/repo/sources/ 92 | 93 | 94 | [gcode] 95 | releaser = gcode.GoogleCodeReleaser 96 | project_name = pynag 97 | summary = Wooh hoo, i was uploaded with tito 98 | -------------------------------------------------------------------------------- /contrib/create_user.sql: -------------------------------------------------------------------------------- 1 | declare @dbname varchar(255) 2 | declare @check_mssql_health_USER varchar(255) 3 | declare @check_mssql_health_PASS varchar(255) 4 | declare @check_mssql_health_ROLE varchar(255) 5 | declare @source varchar(255) 6 | declare @options varchar(255) 7 | declare @backslash int 8 | 9 | /*******************************************************************/ 10 | SET @check_mssql_health_USER = '"[Servername|Domainname]\Username"' 11 | SET @check_mssql_health_PASS = 'Password' 12 | SET @check_mssql_health_ROLE = 'Rolename' 13 | /******************************************************************* 14 | 15 | PLEASE CHANGE THE ABOVE VALUES ACCORDING TO YOUR REQUIREMENTS 16 | 17 | - Example for Windows authentication: 18 | SET @check_mssql_health_USER = '"[Servername|Domainname]\Username"' 19 | SET @check_mssql_health_ROLE = 'Rolename' 20 | 21 | - Example for SQL Server authentication: 22 | SET @check_mssql_health_USER = 'Username' 23 | SET @check_mssql_health_PASS = 'Password' 24 | SET @check_mssql_health_ROLE = 'Rolename' 25 | 26 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 27 | It is strongly recommended to use Windows authentication. Otherwise 28 | you will get no reliable results for database usage. 29 | !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 30 | 31 | *********** NO NEED TO CHANGE ANYTHING BELOW THIS LINE *************/ 32 | 33 | SET @options = 'DEFAULT_DATABASE=MASTER, DEFAULT_LANGUAGE=English' 34 | SET @backslash = (SELECT CHARINDEX('\', @check_mssql_health_USER)) 35 | IF @backslash > 0 36 | BEGIN 37 | SET @source = ' FROM WINDOWS' 38 | SET @options = ' WITH ' + @options 39 | END 40 | ELSE 41 | BEGIN 42 | SET @source = '' 43 | SET @options = ' WITH PASSWORD=''' + @check_mssql_health_PASS + ''',' + @options 44 | END 45 | 46 | PRINT 'create Nagios plugin user ' + @check_mssql_health_USER 47 | EXEC ('CREATE LOGIN ' + @check_mssql_health_USER + @source + @options) 48 | EXEC ('USE MASTER GRANT VIEW SERVER STATE TO ' + @check_mssql_health_USER) 49 | PRINT 'User ' + @check_mssql_health_USER + ' created.' 50 | PRINT '' 51 | 52 | declare dblist cursor for 53 | select name from sysdatabases WHERE name NOT IN ('master', 'tempdb', 'msdb') open dblist 54 | fetch next from dblist into @dbname 55 | while @@fetch_status = 0 begin 56 | EXEC ('USE ' + @dbname + ' print ''Grant permissions in the db '' + ''"'' + DB_NAME() + ''"''') 57 | EXEC ('USE ' + @dbname + ' CREATE ROLE ' + @check_mssql_health_ROLE) 58 | EXEC ('USE ' + @dbname + ' GRANT EXECUTE TO ' + @check_mssql_health_ROLE) 59 | EXEC ('USE ' + @dbname + ' GRANT VIEW DATABASE STATE TO ' + @check_mssql_health_ROLE) 60 | EXEC ('USE ' + @dbname + ' GRANT VIEW DEFINITION TO ' + @check_mssql_health_ROLE) 61 | EXEC ('USE ' + @dbname + ' CREATE USER ' + @check_mssql_health_USER + ' FOR LOGIN ' + @check_mssql_health_USER) 62 | EXEC ('USE ' + @dbname + ' EXEC sp_addrolemember ' + @check_mssql_health_ROLE + ' , ' + @check_mssql_health_USER) 63 | EXEC ('USE ' + @dbname + ' print ''Permissions in the db '' + ''"'' + DB_NAME() + ''" granted.''') 64 | fetch next from dblist into @dbname 65 | end 66 | close dblist 67 | deallocate dblist 68 | 69 | -------------------------------------------------------------------------------- /plugins-scripts/Classes/MSSQL/Component/MemorypoolSubsystem/Lock.pm: -------------------------------------------------------------------------------- 1 | package Classes::MSSQL::Component::MemorypoolSubsystem::Lock; 2 | our @ISA = qw(Monitoring::GLPlugin::DB::TableItem); 3 | use strict; 4 | 5 | sub check { 6 | my $self = shift; 7 | if ($self->mode =~ /server::memorypool::lock::waits/) { 8 | $self->get_perf_counters([ 9 | ["waits", "SQLServer:Locks", "Lock Waits/sec", $self->{name}], 10 | ]); 11 | return if $self->check_messages(); 12 | my $label = $self->{name}.'_waits_per_sec'; 13 | $self->set_thresholds( 14 | metric => $label, 15 | warning => 100, critical => 500 16 | ); 17 | $self->add_message($self->check_thresholds( 18 | metric => $label, 19 | value => $self->{waits_per_sec}, 20 | ), sprintf "%.4f lock waits / sec for %s", 21 | $self->{waits_per_sec}, $self->{name} 22 | ); 23 | $self->add_perfdata( 24 | label => $label, 25 | value => $self->{waits_per_sec}, 26 | ); 27 | } elsif ($self->mode =~ /^server::memorypool::lock::timeouts/) { 28 | $self->get_perf_counters([ 29 | ["timeouts", "SQLServer:Locks", "Lock Timeouts/sec", $self->{name}], 30 | ]); 31 | return if $self->check_messages(); 32 | my $label = $self->{name}.'_timeouts_per_sec'; 33 | $self->set_thresholds( 34 | metric => $label, 35 | warning => 1, critical => 5 36 | ); 37 | $self->add_message($self->check_thresholds( 38 | metric => $label, 39 | value => $self->{timeouts_per_sec}, 40 | ), sprintf "%.4f lock timeouts / sec for %s", 41 | $self->{timeouts_per_sec}, $self->{name} 42 | ); 43 | $self->add_perfdata( 44 | label => $label, 45 | value => $self->{timeouts_per_sec}, 46 | ); 47 | } elsif ($self->mode =~ /^server::memorypool::lock::timeoutsgt0/) { 48 | $self->get_perf_counters([ 49 | ["timeoutsgt0", "SQLServer:Locks", "Lock Timeouts (timeout > 0)/sec", $self->{name}], 50 | ]); 51 | return if $self->check_messages(); 52 | my $label = $self->{name}.'_timeoutsgt0_per_sec'; 53 | $self->set_thresholds( 54 | metric => $label, 55 | warning => 1, critical => 5 56 | ); 57 | $self->add_message($self->check_thresholds( 58 | metric => $label, 59 | value => $self->{timeoutsgt0_per_sec}, 60 | ), sprintf "%.4f lock timeouts (timeout > 0)/sec for %s", 61 | $self->{timeoutsgt0_per_sec}, $self->{name} 62 | ); 63 | $self->add_perfdata( 64 | label => $label, 65 | value => $self->{timeoutsgt0_per_sec}, 66 | ); 67 | } elsif ($self->mode =~ /^server::memorypool::lock::deadlocks/) { 68 | $self->get_perf_counters([ 69 | ["deadlocks", "SQLServer:Locks", "Number of Deadlocks/sec", $self->{name}], 70 | ]); 71 | return if $self->check_messages(); 72 | my $label = $self->{name}.'_deadlocks_per_sec'; 73 | $self->set_thresholds( 74 | metric => $label, 75 | warning => 1, critical => 5 76 | ); 77 | $self->add_message($self->check_thresholds( 78 | metric => $label, 79 | value => $self->{deadlocks_per_sec}, 80 | ), sprintf "%.4f lock deadlocks / sec for %s", 81 | $self->{deadlocks_per_sec}, $self->{name} 82 | ); 83 | $self->add_perfdata( 84 | label => $label, 85 | value => $self->{deadlocks_per_sec}, 86 | ); 87 | } 88 | } 89 | 90 | 91 | -------------------------------------------------------------------------------- /contrib/README.formula: -------------------------------------------------------------------------------- 1 | ========================================================================================== 2 | http://www.sqlservercentral.com/Forums/Topic261080-5-1.aspx#bm261128 3 | 4 | MachineName InstanceName DbName FileGroupName AllocatedMb UsedMb FreeMb FreePercent AutoGrowMb AutoGrowMaxSize 5 | WIN2K3R2EE Default master PRIMARY 4 2 1 49 0.4 2147483647 6 | WIN2K3R2EE Default tempdb PRIMARY 8 1 6 86 0.8 2147483647 7 | WIN2K3R2EE Default model PRIMARY 1 0 0 17 1 2147483647 8 | WIN2K3R2EE Default msdb PRIMARY 4 3 0 15 0.25 2147483647 9 | WIN2K3R2EE Default ReportServer PRIMARY 3 1 1 38 1 2147483647 10 | WIN2K3R2EE Default ReportServerTempDB PRIMARY 2 1 1 53 1 2147483647 11 | WIN2K3R2EE Default AdventureWorksDW PRIMARY 68 60 8 12 16 2147483647 12 | WIN2K3R2EE Default AdventureWorks PRIMARY 163 153 10 6 16 2147483647 13 | 14 | 15 | set nocount on 16 | create table #DBSpace 17 | (DbName sysname 18 | ,FileGroupName sysname 19 | ,AllocatedMb integer 20 | ,UsedMb integer 21 | ,FreeMb integer 22 | ,FreePercent integer 23 | ,AutoGrowMb decimal(12,2) 24 | ,AutoGrowMaxSize integer 25 | ) 26 | exec master.dbo.sp_MSForEachDb @command1 = 27 | 'dbcc updateusage([?]) with no_infomsgs 28 | insert into #DBSpace 29 | select ''?'' 30 | , sysFileGroups.groupname 31 | , F.AllocatedPages / 128 as AllocatedMb 32 | , U.UsedPages / 128 as UsedMb 33 | , (F.AllocatedPages - U.UsedPages) / 128 as FreeMb 34 | , (F.AllocatedPages - U.UsedPages) * 100 35 | / F.AllocatedPages as FreePercent 36 | , CAST(F.GrowthPages / 128.0 as decimal(12,2) ) as AutoGrowMb 37 | , F.MaxSize as AutoGrowMaxSize 38 | FROM (select GroupId 39 | , sum( cast( used as bigint) ) 40 | from [?].dbo.sysindexes 41 | where indid in (0,1,255) 42 | group by GroupId 43 | ) as U ( GroupId , UsedPages) 44 | join (select GroupId 45 | , sum(cast( size as bigint) ) 46 | , Max(growth) 47 | , MAX(case status & 0x100000 48 | WHEN 0x100000 then Growth * Size / 100 -- Increase in Percentage 49 | else Growth -- Increase in Pages 50 | end) 51 | , MAX( case maxsize when -1 then 2147483647 else maxsize end) 52 | from [?].dbo.sysfiles 53 | where (status & 64 = 0) 54 | group by GroupId 55 | ) as F (GroupId , AllocatedPages, Growth, GrowthPages, maxsize) 56 | on F.GroupId = U.groupid 57 | join sysFileGroups 58 | on sysFileGroups.GroupId = U.groupId 59 | ' 60 | 61 | 62 | select CAST( SERVERPROPERTY ('MachineName') as nvarchar(128) ) AS MachineName 63 | , COALESCE ( CAST( SERVERPROPERTY ('InstanceName') as nvarchar(128) ) , 'Default') AS InstanceName 64 | , DbName 65 | , FileGroupName 66 | , AllocatedMb 67 | , UsedMb 68 | , FreeMb 69 | , FreePercent 70 | , AutoGrowMb 71 | , AutoGrowMaxSize 72 | from #DBSpace 73 | 74 | -------------------------------------------------------------------------------- /plugins-scripts/Classes/APS/Component/DiskSubsystem.pm: -------------------------------------------------------------------------------- 1 | package Classes::APS::Disk::DiskSubsystem; 2 | our @ISA = qw(Monitoring::GLPlugin::DB::Item); 3 | use strict; 4 | 5 | sub init { 6 | my $self = shift; 7 | my $sql = undef; 8 | if ($self->mode =~ /server::aps::disk::free/) { 9 | $self->override_opt("units", "%") if ! $self->opts->units; 10 | my $columns = ['node_name', 'name', 'size_mb', 11 | 'free_space_mb', 'space_utilized_mb', 'free_space_pct']; 12 | my $sql = q{ 13 | SELECT 14 | NodeName, 15 | VolumeName, 16 | VolumeSizeMB, 17 | FreeSpaceMB, 18 | SpaceUtilized, 19 | FreeSpaceMBPct 20 | FROM 21 | SQL_ADMIN.[dbo].disk_space 22 | ORDER BY 23 | NodeName, VolumeName DESC"; 24 | }; 25 | $self->get_db_tables([ 26 | ['disks', $sql, 'Classes::APS::Disk::DiskSubsystem::Disk', sub { my $o = shift; $self->filter_name($o->{name}); }, $columns], 27 | ]); 28 | } 29 | } 30 | 31 | 32 | package Classes::APS::Disk::DiskSubsystem::Disk; 33 | our @ISA = qw(Monitoring::GLPlugin::DB::TableItem); 34 | use strict; 35 | 36 | sub finish { 37 | my $self = shift; 38 | $self->{name} = $self->{node_name}.'_'.$self->{name}; 39 | $self->{name} = lc $self->{name}; 40 | my $factor = 1; # MB 41 | if ($self->opts->units ne "%") { 42 | if (uc $self->opts->units eq "GB") { 43 | $factor = 1024; 44 | } elsif (uc $self->opts->units eq "MB") { 45 | $factor = 1; 46 | } elsif (uc $self->opts->units eq "KB") { 47 | $factor = 1 / 1024; 48 | } 49 | } 50 | $self->{size} = $self->{size_mb} / $factor; 51 | $self->{free_space} = $self->{free_space_mb} / $factor; 52 | $self->{space_utilized} = $self->{space_utilized_mb} / $factor; 53 | } 54 | 55 | sub check { 56 | my $self = shift; 57 | my $warning_units; 58 | my $critical_units; 59 | my $warning_pct; 60 | my $critical_pct; 61 | my $metric_units = $self->{name}.'_free'; 62 | my $metric_pct = $self->{name}.'_free_pct'; 63 | if ($self->opts->units eq "%") { 64 | $self->set_thresholds(metric => $metric_pct, warning => "10:", critical => "5:"); 65 | ($warning_pct, $critical_pct) = ($self->get_thresholds(metric => $metric_pct)); 66 | ($warning_units, $critical_units) = map { 67 | $_ =~ s/://g; ($_ * $self->{size} / 100).":"; 68 | } map { my $tmp = $_; $tmp; } ($warning_pct, $critical_pct); # sonst schnippelt der von den originalen den : weg 69 | $self->set_thresholds(metric => $metric_units, warning => $warning_units, critical => $critical_units); 70 | $self->add_message($self->check_thresholds(metric => $metric_pct, value => $self->{free_space_pct}), 71 | sprintf("disk %s has %.2f%s free space left", $self->{name}, $self->{free_space_pct}, $self->opts->units)); 72 | } else { 73 | $self->set_thresholds(metric => $metric_units, warning => "5:", critical => "10:"); 74 | ($warning_units, $critical_units) = ($self->get_thresholds(metric => $metric_units)); 75 | ($warning_pct, $critical_pct) = map { 76 | $_ =~ s/://g; (100 * $_ / $self->{size}).":"; 77 | } map { my $tmp = $_; $tmp; } ($warning_units, $critical_units); 78 | $self->set_thresholds(metric => $metric_pct, warning => $warning_pct, critical => $critical_pct); 79 | $self->add_message($self->check_thresholds(metric => $metric_units, value => $self->{free_space}), 80 | sprintf("disk %s has %.2f%s free space left", $self->{name}, $self->{free_space}, $self->opts->units)); 81 | } 82 | $self->add_perfdata( 83 | label => $metric_pct, 84 | value => $self->{free_space_pct}, 85 | places => 2, 86 | uom => '%', 87 | warning => $warning_pct, 88 | critical => $critical_pct, 89 | ); 90 | $self->add_perfdata( 91 | label => $metric_units, 92 | value => $self->{free_space}, 93 | uom => $self->opts->units eq "%" ? "MB" : $self->opts->units, 94 | places => 2, 95 | warning => $warning_units, 96 | critical => $critical_units, 97 | min => 0, 98 | max => $self->{size}, 99 | ); 100 | } 101 | 102 | -------------------------------------------------------------------------------- /plugins-scripts/Classes/MSSQL/Component/MemorypoolSubsystem/Buffercache.pm: -------------------------------------------------------------------------------- 1 | package Classes::MSSQL::Component::MemorypoolSubsystem::Buffercache; 2 | our @ISA = qw(Monitoring::GLPlugin::DB::Item); 3 | use strict; 4 | 5 | sub init { 6 | my $self = shift; 7 | if ($self->mode =~ /server::memorypool::buffercache::hitratio/) { 8 | # https://social.msdn.microsoft.com/Forums/sqlserver/en-US/263e847a-fd9d-4fbf-a8f0-2aed9565aca1/buffer-hit-ratio-over-100?forum=sqldatabaseengine 9 | $self->get_perf_counters([ 10 | ['cnthitratio', 'SQLServer:Buffer Manager', 'Buffer cache hit ratio'], 11 | ['cnthitratiobase', 'SQLServer:Buffer Manager', 'Buffer cache hit ratio base'], 12 | ]); 13 | my $sql = q{ 14 | SELECT 15 | (a.cntr_value * 1.0 / b.cntr_value) * 100.0 AS BufferCacheHitRatio 16 | FROM 17 | sys.dm_os_performance_counters a 18 | JOIN ( 19 | SELECT 20 | cntr_value, OBJECT_NAME 21 | FROM 22 | sys.dm_os_performance_counters 23 | WHERE 24 | counter_name = 'Buffer cache hit ratio base' 25 | AND 26 | object_name = 'SQLServer:Buffer Manager' 27 | ) b 28 | ON 29 | a.OBJECT_NAME = b.OBJECT_NAME 30 | WHERE 31 | a.counter_name = 'Buffer cache hit ratio' 32 | AND 33 | a.OBJECT_NAME = 'SQLServer:Buffer Manager' 34 | }; 35 | my $instance = $self->get_variable("servicename"); 36 | $sql =~ s/SQLServer/$instance/g; 37 | $self->{buffer_cache_hit_ratio} = $self->fetchrow_array($sql); 38 | $self->protect_value('buffer_cache_hit_ratio', 'buffer_cache_hit_ratio', 'percent'); 39 | } elsif ($self->mode =~ /server::memorypool::buffercache::lazywrites/) { 40 | $self->get_perf_counters([ 41 | ['lazy_writes', 'SQLServer:Buffer Manager', 'Lazy writes/sec'], 42 | ]); 43 | # -> lazy_writes_per_sec 44 | } elsif ($self->mode =~ /server::memorypool::buffercache::pagelifeexpectancy/) { 45 | $self->get_perf_counters([ 46 | ['page_life_expectancy', 'SQLServer:Buffer Manager', 'Page life expectancy'], 47 | ]); 48 | } elsif ($self->mode =~ /server::memorypool::buffercache::freeliststalls/) { 49 | $self->get_perf_counters([ 50 | ['free_list_stalls', 'SQLServer:Buffer Manager', 'Free list stalls/sec'], 51 | ]); 52 | } elsif ($self->mode =~ /server::memorypool::buffercache::checkpointpages/) { 53 | $self->get_perf_counters([ 54 | ['checkpoint_pages', 'SQLServer:Buffer Manager', 'Checkpoint pages/sec'], 55 | ]); 56 | } 57 | } 58 | 59 | sub check { 60 | my $self = shift; 61 | return if $self->check_messages(); 62 | if ($self->mode =~ /server::memorypool::buffercache::hitratio/) { 63 | $self->set_thresholds( 64 | warning => '90:', critical => '80:' 65 | ); 66 | $self->add_message( 67 | $self->check_thresholds($self->{buffer_cache_hit_ratio}), 68 | sprintf "buffer cache hit ratio is %.2f%%", $self->{buffer_cache_hit_ratio} 69 | ); 70 | $self->add_perfdata( 71 | label => 'buffer_cache_hit_ratio', 72 | value => $self->{buffer_cache_hit_ratio}, 73 | uom => '%', 74 | ); 75 | } elsif ($self->mode =~ /server::memorypool::buffercache::lazywrites/) { 76 | $self->set_thresholds( 77 | warning => 20, critical => 40, 78 | ); 79 | $self->add_message( 80 | $self->check_thresholds($self->{lazy_writes_per_sec}), 81 | sprintf "%.2f lazy writes per second", $self->{lazy_writes_per_sec} 82 | ); 83 | $self->add_perfdata( 84 | label => 'lazy_writes_per_sec', 85 | value => $self->{lazy_writes_per_sec}, 86 | ); 87 | } elsif ($self->mode =~ /server::memorypool::buffercache::pagelifeexpectancy/) { 88 | $self->set_thresholds( 89 | warning => '300:', critical => '180:', 90 | ); 91 | $self->add_message( 92 | $self->check_thresholds($self->{page_life_expectancy}), 93 | sprintf "page life expectancy is %d seconds", $self->{page_life_expectancy} 94 | ); 95 | $self->add_perfdata( 96 | label => 'page_life_expectancy', 97 | value => $self->{page_life_expectancy}, 98 | ); 99 | } elsif ($self->mode =~ /server::memorypool::buffercache::freeliststalls/) { 100 | $self->set_thresholds( 101 | warning => '4', critical => '10', 102 | ); 103 | $self->add_message( 104 | $self->check_thresholds($self->{free_list_stalls_per_sec}), 105 | sprintf "%.2f free list stalls per second", $self->{free_list_stalls_per_sec} 106 | ); 107 | $self->add_perfdata( 108 | label => 'free_list_stalls_per_sec', 109 | value => $self->{free_list_stalls_per_sec}, 110 | ); 111 | } elsif ($self->mode =~ /server::memorypool::buffercache::checkpointpages/) { 112 | $self->set_thresholds( 113 | warning => '100', critical => '500', 114 | ); 115 | $self->add_message( 116 | $self->check_thresholds($self->{checkpoint_pages_per_sec}), 117 | sprintf "%.2f pages flushed per second", $self->{checkpoint_pages_per_sec} 118 | ); 119 | $self->add_perfdata( 120 | label => 'checkpoint_pages_per_sec', 121 | value => $self->{checkpoint_pages_per_sec}, 122 | ); 123 | } 124 | } 125 | 126 | 127 | -------------------------------------------------------------------------------- /plugins-scripts/Classes/MSSQL/Component/AvailabilitygroupSubsystem.pm: -------------------------------------------------------------------------------- 1 | package Classes::MSSQL::Component::AvailabilitygroupSubsystem; 2 | our @ISA = qw(Monitoring::GLPlugin::DB::Item); 3 | use strict; 4 | 5 | sub init { 6 | my ($self) = @_; 7 | my $sql = undef; 8 | my $allfilter = sub { 9 | my ($o) = @_; 10 | $self->filter_name($o->{name}); 11 | }; 12 | if ($self->mode =~ /server::availabilitygroup::status/) { 13 | if ($self->version_is_minimum("11.x")) { 14 | my $avgfilter = sub { 15 | my $o = shift; 16 | $self->filter_name($o->{name}); 17 | }; 18 | my $columnsag = [qw(server_name group_id name 19 | primary_replica primary_recovery_health_desc 20 | secondary_recovery_health_desc synchronization_health_desc 21 | )]; 22 | # returns 1 line with availability group 23 | my $sqlag = q{ 24 | SELECT 25 | @@ServerName, 26 | [ag].[group_id], 27 | [ag].[name], 28 | [gs].[primary_replica], 29 | [gs].[primary_recovery_health_desc], 30 | [gs].[secondary_recovery_health_desc], 31 | [gs].[synchronization_health_desc] 32 | FROM 33 | [master].[sys].[availability_groups] 34 | AS 35 | [ag] 36 | INNER JOIN 37 | [master].[sys].[dm_hadr_availability_group_states] 38 | AS 39 | [gs] 40 | ON 41 | [ag].[group_id] = [gs].[group_id] 42 | }; 43 | my $columnsrs = [qw(server_name group_id name database_name 44 | synchronization_state_desc replica_id group_database_id 45 | )]; 46 | # returns n lines with availability group + 47 | # database (probably always the same, i never saw different records) + 48 | # replica_id (which is unique), so name+replica_id are unique here 49 | my $sqlrs = q{ 50 | SELECT 51 | @@ServerName, 52 | [ag].[group_id], 53 | [ag].[name], 54 | [db].[name] AS Databasename, 55 | [rs].[synchronization_state_desc], 56 | [rs].[replica_id], 57 | [rs].[group_database_id] 58 | FROM [master].[sys].[availability_groups] AS [ag] 59 | INNER JOIN [master].[sys].[dm_hadr_database_replica_states] AS [rs] ON [ag].[group_id] = [rs].[group_id] 60 | INNER JOIN [master].[sys].[databases] AS [db] ON [rs].[database_id] = [db].[database_id] 61 | }; 62 | 63 | $self->get_db_tables([ 64 | ['avgroups', $sqlag, 'Classes::MSSQL::Component::AvailabilitygroupSubsystem::Availabilitygroup', $avgfilter, $columnsag], 65 | ['replicas', $sqlrs, 'Monitoring::GLPlugin::DB::TableItem', $avgfilter, $columnsrs], 66 | ]); 67 | foreach my $avgroup (@{$self->{avgroups}}) { 68 | foreach my $replica (@{$self->{replicas}}) { 69 | if ($avgroup->{name} eq $replica->{name}) { 70 | push(@{$avgroup->{replicas}}, $replica); 71 | } 72 | } 73 | } 74 | delete $self->{replicas}; 75 | } 76 | } 77 | } 78 | 79 | sub check { 80 | my ($self) = @_; 81 | if ($self->mode =~ /server::availabilitygroup::status/) { 82 | if ($self->version_is_minimum("11.x")) { 83 | if (! scalar(@{$self->{avgroups}})) { 84 | $self->add_ok("no availability groups found"); 85 | } else { 86 | foreach (@{$self->{avgroups}}) { 87 | $_->check(); 88 | } 89 | } 90 | } else { 91 | $self->add_ok(sprintf 'your version %s is too old, availability group monitoring is not possible', $self->get_variable('version')); 92 | } 93 | } 94 | } 95 | 96 | 97 | package Classes::MSSQL::Component::AvailabilitygroupSubsystem::Replicastate; 98 | our @ISA = qw(Monitoring::GLPlugin::DB::TableItem); 99 | use strict; 100 | 101 | package Classes::MSSQL::Component::AvailabilitygroupSubsystem::Availabilitygroup; 102 | our @ISA = qw(Monitoring::GLPlugin::DB::TableItem); 103 | use strict; 104 | 105 | sub finish { 106 | my ($self) = @_; 107 | $self->{replicas} = []; 108 | } 109 | 110 | sub check { 111 | my ($self) = @_; 112 | if ($self->mode =~ /server::availabilitygroup::status/) { 113 | $self->add_info( 114 | sprintf 'availability group %s synchronization is %s', 115 | $self->{name}, lc $self->{synchronization_health_desc} 116 | ); 117 | if (lc $self->{server_name} ne lc $self->{primary_replica}) { 118 | $self->add_ok(sprintf 'this is is a secondary replica of group %s. for a reliable status you have to ask the primary replica', 119 | $self->{name}); 120 | } elsif ($self->{synchronization_health_desc} eq 'HEALTHY') { 121 | my $nok = scalar(grep { $_->{synchronization_state_desc} !~ /^SYNCHRONIZ/ } @{$self->{replicas}}); 122 | if (! $nok) { 123 | $self->add_ok(); 124 | } else { 125 | foreach my $replica (@{$self->{replicas}}) { 126 | if ($replica->{synchronization_state_desc} ne 'SYNCHRONIZING' && 127 | $replica->{synchronization_state_desc} ne 'SYNCHRONIZED') { 128 | $self->add_info(sprintf 'replica %s@%s has synchronization state %s', 129 | $replica->{replica_id}, $self->{name}, 130 | lc $replica->{synchronization_state_desc} 131 | ); 132 | $self->add_critical(); 133 | } 134 | } 135 | } 136 | } elsif ($self->{synchronization_health_desc} eq 'PARTIALLY_HEALTHY') { 137 | $self->add_warning(); 138 | } elsif ($self->{synchronization_health_desc} eq 'NOT_HEALTHY') { 139 | $self->add_critical(); 140 | } else { 141 | $self->add_unknown(); 142 | } 143 | } 144 | } 145 | 146 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | check_mssql_health Nagios Plugin README 2 | --------------------- 3 | 4 | This plugin is used to monitor a variety of MS SQL Server database metrics. 5 | 6 | * For instructions on installing this plugin for use with Nagios, 7 | see below. In addition, generic instructions for the GNU toolchain 8 | can be found in the INSTALL file. 9 | 10 | * For major changes between releases, read the CHANGES file. 11 | 12 | * For information on detailed changes that have been made, 13 | read the Changelog file. 14 | 15 | * This plugin is self documenting. All plugins that comply with 16 | the basic guidelines for development will provide detailed help when 17 | invoked with the '-h' or '--help' options. 18 | 19 | You can check for the latest plugin at: 20 | http://www.consol.com/opensource/nagios/check-mssql-health 21 | 22 | The documentation in this README covers only the most common features. 23 | To view the full documentation and examples, go to 24 | http://www.consol.com/opensource/nagios/check-mssql-health or 25 | http://www.consol.de/opensource/nagios/check-mssql-health 26 | 27 | Send mail to gerhard.lausser@consol.de for assistance. 28 | Please include the OS type/version and the Perl DBI/DBD version 29 | that you are using. 30 | Also, run the plugin with the '-vvv' option and provide the resulting 31 | version information. Of course, there may be additional diagnostic information 32 | required as well. Use good judgment. 33 | 34 | For patch submissions and bug reports, please send me a mail. You can also find 35 | me at http://www.nagios-portal.de 36 | 37 | Requirements 38 | -------------------------------------------------------- 39 | You need to install the Perl module DBD::Sybase first. 40 | It is very important to set the protocol version in /etc/freetds.conf to 8.0 41 | Otherwise your database password will be visible on the network. 42 | 43 | [global] 44 | # TDS protocol version 45 | tds version = 8.0 46 | 47 | 48 | 49 | How to "compile" the check_mssql_health script. 50 | -------------------------------------------------------- 51 | 52 | 1) Run the configure script to initialize variables and create a Makefile, etc. 53 | 54 | ./configure --prefix=BASEDIRECTORY --with-nagios-user=SOMEUSER --with-nagios-group=SOMEGROUP --with-perl=PATH_TO_PERL --with-statefiles-dir=STATE_PATH 55 | 56 | a) Replace BASEDIRECTORY with the path of the directory under which Nagios 57 | is installed (default is '/usr/local/nagios') 58 | b) Replace SOMEUSER with the name of a user on your system that will be 59 | assigned permissions to the installed plugins (default is 'nagios') 60 | c) Replace SOMEGRP with the name of a group on your system that will be 61 | assigned permissions to the installed plugins (default is 'nagios') 62 | d) Replace PATH_TO_PERL with the path where a perl binary can be found. 63 | Besides the system wide perl you might have installed a private perl 64 | just for the nagios plugins (default is the perl in your path). 65 | e) Replace STATE_PATH with the directory where you want the script to 66 | write state files which transport information from one run to the next. 67 | (default is /tmp) 68 | 69 | Simply running ./configure will be sufficient to create a check_mssql_health 70 | script which you can customize later. 71 | 72 | 73 | 2) "Compile" the plugin with the following command: 74 | 75 | make 76 | 77 | This will produce a "check_mssql_health" script. You will also find 78 | a "check_mssql_health.pl" which you better ignore. It is the base for 79 | the compilation filled with placeholders. These will be replaced during 80 | the make process. 81 | 82 | 83 | 3) Install the compiled plugin script with the following command: 84 | 85 | make install 86 | 87 | The installation procedure will attempt to place the plugin in a 88 | 'libexec/' subdirectory in the base directory you specified with 89 | the --prefix argument to the configure script. 90 | 91 | 92 | 4) Verify that your configuration files for Nagios contains 93 | the correct paths to the new plugin. 94 | 95 | 96 | Command line parameters 97 | ----------------------- 98 | 99 | --hostname= 100 | This is the hostname or the ip-address. 101 | 102 | --port= 103 | This is the port where an instance listens. Default: 1433 104 | 105 | --server= 106 | This can be used instead of a hostname/port combination. 107 | The servername given here is used for a lookup in /etc/freetds.conf 108 | 109 | --user= 110 | This is the user which reads the system tables. 111 | 112 | --password= 113 | This is the user's password. 114 | 115 | --mode= 116 | This parameter tells the plugin what it should check. 117 | The list of known modes may grow frequently. Please look at 118 | http://www.consol.com/opensource/nagios/check-mssql-health for a list 119 | of features. 120 | 121 | --database= 122 | Database-related modes check all databases in one run by default. 123 | If only a single database should be checked, use this parameter. 124 | 125 | --warning= 126 | If the metric is out of this range, the plugin returns a warning. 127 | 128 | --critical= 129 | If the metric is out of this range, the plugin returns a critical. 130 | 131 | 132 | Connecting 133 | ---------- 134 | 135 | 136 | You can call the plugin with "--hostname [--port ]" 137 | This bypasses the freetds.conf file and directly connects you to 138 | whatever is listening on port 1433 or 139 | This will surely be the default instance. If you have different (named) instances 140 | listening on the same port, you need to edit /etc/freetds.conf 141 | 142 | [dbsrv1instance01] 143 | host = 192.168.1.1 144 | port = 1433 145 | instance = instance01 146 | 147 | [dbsrv1instance02] 148 | host = 192.168.1.1 149 | port = 1433 150 | instance = instance02 151 | 152 | .... 153 | 154 | Then you call the plugin with "--server dbsrv1instance02" for example. 155 | 156 | Testing the connection 157 | ---------------------- 158 | 159 | use DBI; 160 | use strict; 161 | 162 | my $username = "xxxxx"; 163 | my $password = "xxxxx"; 164 | my $dsn = "DBI:Sybase:;host=127.0.1.1;port=1433"; 165 | #my $dsn = "DBI:Sybase:;server=dbsrv_in_freetds_conf"; 166 | if (my $dbh = DBI->connect( 167 | $dsn, $username, $password, 168 | { RaiseError => 1, AutoCommit => 0, PrintError => 1 })) { 169 | printf "connection succeeded\n"; 170 | } else { 171 | printf "connection failed\n"; 172 | } 173 | 174 | In Sybase, login as sa and switch on auditing: 175 | sp_configure "log audit logon success", 1 176 | sp_configure "log audit logon failure", 1 177 | go 178 | shutdown 179 | go 180 | 181 | Then startup again 182 | startserver -f /opt/sybase/ASE-15_0/install/RUN_backup_server -f /opt/sybase/ASE-15_0/install/RUN_ase_server -f /opt/sybase/ASE-15_0/install/RUN_monitor_server 183 | 184 | 185 | 186 | -------------------------------------- 187 | That's it. If you have any problems or questions, feel free to send mail 188 | to gerhard.lausser@consol.de 189 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | check_mssql_health Nagios Plugin README 2 | --------------------- 3 | 4 |
5 | Buy Me A Coffee 6 |
7 | 8 | This plugin is used to monitor a variety of MS SQL Server database metrics. 9 | 10 | * For instructions on installing this plugin for use with Nagios, 11 | see below. In addition, generic instructions for the GNU toolchain 12 | can be found in the INSTALL file. 13 | 14 | * For major changes between releases, read the CHANGES file. 15 | 16 | * For information on detailed changes that have been made, 17 | read the Changelog file. 18 | 19 | * This plugin is self documenting. All plugins that comply with 20 | the basic guidelines for development will provide detailed help when 21 | invoked with the '-h' or '--help' options. 22 | 23 | You can check for the latest plugin at: 24 | http://www.consol.com/opensource/nagios/check-mssql-health 25 | 26 | The documentation in this README covers only the most common features. 27 | To view the full documentation and examples, go to 28 | http://www.consol.com/opensource/nagios/check-mssql-health or 29 | http://www.consol.de/opensource/nagios/check-mssql-health 30 | 31 | Send mail to gerhard.lausser@consol.de for assistance. 32 | Please include the OS type/version and the Perl DBI/DBD version 33 | that you are using. 34 | Also, run the plugin with the '-vvv' option and provide the resulting 35 | version information. Of course, there may be additional diagnostic information 36 | required as well. Use good judgment. 37 | 38 | For patch submissions and bug reports, please send me a mail. You can also find 39 | me at http://www.nagios-portal.de 40 | 41 | Requirements 42 | -------------------------------------------------------- 43 | You need to install the Perl module DBD::Sybase first. 44 | It is very important to set the protocol version in /etc/freetds.conf to 8.0 45 | Otherwise your database password will be visible on the network. 46 | 47 | [global] 48 | # TDS protocol version 49 | tds version = 8.0 50 | 51 | 52 | 53 | How to "compile" the check_mssql_health script. 54 | -------------------------------------------------------- 55 | 56 | 1) Run the configure script to initialize variables and create a Makefile, etc. 57 | 58 | ./configure --prefix=BASEDIRECTORY --with-nagios-user=SOMEUSER --with-nagios-group=SOMEGROUP --with-perl=PATH_TO_PERL --with-statefiles-dir=STATE_PATH 59 | 60 | a) Replace BASEDIRECTORY with the path of the directory under which Nagios 61 | is installed (default is '/usr/local/nagios') 62 | b) Replace SOMEUSER with the name of a user on your system that will be 63 | assigned permissions to the installed plugins (default is 'nagios') 64 | c) Replace SOMEGRP with the name of a group on your system that will be 65 | assigned permissions to the installed plugins (default is 'nagios') 66 | d) Replace PATH_TO_PERL with the path where a perl binary can be found. 67 | Besides the system wide perl you might have installed a private perl 68 | just for the nagios plugins (default is the perl in your path). 69 | e) Replace STATE_PATH with the directory where you want the script to 70 | write state files which transport information from one run to the next. 71 | (default is /tmp) 72 | 73 | Simply running ./configure will be sufficient to create a check_mssql_health 74 | script which you can customize later. 75 | 76 | 77 | 2) "Compile" the plugin with the following command: 78 | 79 | make 80 | 81 | This will produce a "check_mssql_health" script. You will also find 82 | a "check_mssql_health.pl" which you better ignore. It is the base for 83 | the compilation filled with placeholders. These will be replaced during 84 | the make process. 85 | 86 | 87 | 3) Install the compiled plugin script with the following command: 88 | 89 | make install 90 | 91 | The installation procedure will attempt to place the plugin in a 92 | 'libexec/' subdirectory in the base directory you specified with 93 | the --prefix argument to the configure script. 94 | 95 | 96 | 4) Verify that your configuration files for Nagios contains 97 | the correct paths to the new plugin. 98 | 99 | 100 | Command line parameters 101 | ----------------------- 102 | 103 | --hostname= 104 | This is the hostname or the ip-address. 105 | 106 | --port= 107 | This is the port where an instance listens. Default: 1433 108 | 109 | --server= 110 | This can be used instead of a hostname/port combination. 111 | The servername given here is used for a lookup in /etc/freetds.conf 112 | 113 | --user= 114 | This is the user which reads the system tables. 115 | 116 | --password= 117 | This is the user's password. 118 | 119 | --mode= 120 | This parameter tells the plugin what it should check. 121 | The list of known modes may grow frequently. Please look at 122 | http://www.consol.com/opensource/nagios/check-mssql-health for a list 123 | of features. 124 | 125 | --database= 126 | Database-related modes check all databases in one run by default. 127 | If only a single database should be checked, use this parameter. 128 | 129 | --warning= 130 | If the metric is out of this range, the plugin returns a warning. 131 | 132 | --critical= 133 | If the metric is out of this range, the plugin returns a critical. 134 | 135 | 136 | Connecting 137 | ---------- 138 | 139 | 140 | You can call the plugin with "--hostname [--port ]" 141 | This bypasses the freetds.conf file and directly connects you to 142 | whatever is listening on port 1433 or 143 | This will surely be the default instance. If you have different (named) instances 144 | listening on the same port, you need to edit /etc/freetds.conf 145 | 146 | [dbsrv1instance01] 147 | host = 192.168.1.1 148 | port = 1433 149 | instance = instance01 150 | 151 | [dbsrv1instance02] 152 | host = 192.168.1.1 153 | port = 1433 154 | instance = instance02 155 | 156 | .... 157 | 158 | Then you call the plugin with "--server dbsrv1instance02" for example. 159 | 160 | Testing the connection 161 | ---------------------- 162 | 163 | use DBI; 164 | use strict; 165 | 166 | my $username = "xxxxx"; 167 | my $password = "xxxxx"; 168 | my $dsn = "DBI:Sybase:;host=127.0.1.1;port=1433"; 169 | #my $dsn = "DBI:Sybase:;server=dbsrv_in_freetds_conf"; 170 | if (my $dbh = DBI->connect( 171 | $dsn, $username, $password, 172 | { RaiseError => 1, AutoCommit => 0, PrintError => 1 })) { 173 | printf "connection succeeded\n"; 174 | } else { 175 | printf "connection failed\n"; 176 | } 177 | 178 | In Sybase, login as sa and switch on auditing: 179 | sp_configure "log audit logon success", 1 180 | sp_configure "log audit logon failure", 1 181 | go 182 | shutdown 183 | go 184 | 185 | Then startup again 186 | startserver -f /opt/sybase/ASE-15_0/install/RUN_backup_server -f /opt/sybase/ASE-15_0/install/RUN_ase_server -f /opt/sybase/ASE-15_0/install/RUN_monitor_server 187 | 188 | 189 | 190 | -------------------------------------- 191 | That's it. If you have any problems or questions, feel free to send mail 192 | to gerhard.lausser@consol.de 193 | -------------------------------------------------------------------------------- /plugins-scripts/Classes/MSSQL/Component/JobSubsystem.pm: -------------------------------------------------------------------------------- 1 | package Classes::MSSQL::Component::JobSubsystem; 2 | our @ISA = qw(Monitoring::GLPlugin::DB::Item); 3 | use strict; 4 | 5 | sub init { 6 | my $self = shift; 7 | my $sql = undef; 8 | if ($self->mode =~ /server::jobs::(failed|enabled|list)/) { 9 | $self->override_opt('lookback', 30) if ! $self->opts->lookback; 10 | if ($self->version_is_minimum("9.x")) { 11 | my $columns = ['id', 'name', 'now', 'minutessincestart', 'lastrundurationseconds', 'lastrundatetime', 'lastrunstatus', 'lastrunduration', 'lastrunstatusmessage', 'nextrundatetime']; 12 | my $sql = q{ 13 | SELECT 14 | [sJOB].[job_id] AS [JobID], 15 | [sJOB].[name] AS [JobName], 16 | CURRENT_TIMESTAMP, --can be used for debugging 17 | CASE 18 | WHEN 19 | [sJOBH].[run_date] IS NULL OR [sJOBH].[run_time] IS NULL 20 | THEN 21 | NULL 22 | ELSE 23 | DATEDIFF(Minute, CAST(CAST([sJOBH].[run_date] AS CHAR(8)) + ' ' + 24 | STUFF(STUFF(RIGHT('000000' + CAST([sJOBH].[run_time] AS VARCHAR(6)), 6), 3, 0, ':'), 6, 0, ':') AS DATETIME), CURRENT_TIMESTAMP) 25 | END AS [MinutesSinceStart], 26 | round([run_duration] / 10000, 0) * 3600 + 27 | CAST(SUBSTRING(RIGHT('00000000' + CAST([run_duration] AS VARCHAR(30)), 8), 5, 2) AS INT) * 60 + 28 | CAST(SUBSTRING(RIGHT('00000000' + CAST([run_duration] AS VARCHAR(30)), 8), 7, 2) AS INT) AS LastRunDurationSeconds, 29 | CASE 30 | WHEN 31 | [sJOBH].[run_date] IS NULL OR [sJOBH].[run_time] IS NULL 32 | THEN 33 | NULL 34 | ELSE 35 | CAST( 36 | CAST([sJOBH].[run_date] AS CHAR(8)) + ' ' + 37 | STUFF(STUFF(RIGHT('000000' + CAST([sJOBH].[run_time] AS VARCHAR(6)), 6), 3, 0, ':'), 6, 0, ':') AS DATETIME) 38 | END AS [LastRunDateTime], 39 | CASE [sJOBH].[run_status] 40 | WHEN 0 THEN 'Failed' 41 | WHEN 1 THEN 'Succeeded' 42 | WHEN 2 THEN 'Retry' 43 | WHEN 3 THEN 'Canceled' 44 | WHEN 4 THEN 'Running' -- In Progress 45 | ELSE 'DidNeverRun' 46 | END AS [LastRunStatus], 47 | cast( round([run_duration] / 10000, 0) as VARCHAR(30)) + ':' + 48 | STUFF(RIGHT('00000000' + CAST([run_duration] AS VARCHAR(30)), 4), 3, 0, ':') AS [LastRunDuration (HH:MM:SS)], 49 | [sJOBH].[message] AS [LastRunStatusMessage], 50 | CASE [sJOBSCH].[NextRunDate] 51 | WHEN 52 | 0 53 | THEN 54 | NULL 55 | ELSE 56 | CAST( 57 | CAST([sJOBSCH].[NextRunDate] AS CHAR(8)) + ' ' + STUFF(STUFF(RIGHT('000000' + CAST([sJOBSCH].[NextRunTime] AS VARCHAR(6)), 6), 3, 0, ':'), 6, 0, ':') AS DATETIME) 58 | END AS [NextRunDateTime] 59 | FROM 60 | [msdb].[dbo].[sysjobs] AS [sJOB] 61 | LEFT JOIN ( 62 | SELECT 63 | [job_id], 64 | MIN([next_run_date]) AS [NextRunDate], 65 | MIN([next_run_time]) AS [NextRunTime] 66 | FROM 67 | [msdb].[dbo].[sysjobschedules] 68 | GROUP BY 69 | [job_id] 70 | ) AS [sJOBSCH] 71 | ON 72 | [sJOB].[job_id] = [sJOBSCH].[job_id] 73 | LEFT JOIN ( 74 | SELECT 75 | [job_id], 76 | [run_date], 77 | [run_time], 78 | [run_status], 79 | [run_duration], 80 | [message], 81 | ROW_NUMBER() 82 | OVER ( 83 | PARTITION BY [job_id] 84 | ORDER BY [run_date] DESC, [run_time] DESC 85 | ) AS RowNumber 86 | FROM 87 | [msdb].[dbo].[sysjobhistory] 88 | WHERE 89 | [step_id] = 0 90 | ) AS [sJOBH] 91 | ON 92 | [sJOB].[job_id] = [sJOBH].[job_id] 93 | AND 94 | [sJOBH].[RowNumber] = 1 95 | ORDER BY 96 | [JobName] 97 | }; 98 | $self->get_db_tables([ 99 | ['jobs', $sql, 'Classes::MSSQL::Component::JobSubsystem::Job', sub { $self->opts->lookback;my $o = shift; $self->filter_name($o->{name}) && (! defined $o->{minutessincestart} || $o->{minutessincestart} <= $self->opts->lookback); }, $columns], 100 | ]); 101 | @{$self->{jobs}} = reverse @{$self->{jobs}}; 102 | } 103 | } else { 104 | $self->no_such_mode(); 105 | } 106 | } 107 | 108 | sub check { 109 | my $self = shift; 110 | $self->add_info('checking jobs'); 111 | if ($self->mode =~ /server::jobs::listjobs/) { 112 | foreach (@{$self->{jobs}}) { 113 | printf "%s\n", $_->{name}; 114 | } 115 | $self->add_ok("have fun"); 116 | } else { 117 | $self->SUPER::check(); 118 | if (scalar @{$self->{jobs}} == 0) { 119 | $self->add_ok(sprintf "no jobs ran within the last %d minutes", $self->opts->lookback); 120 | } 121 | } 122 | } 123 | 124 | package Classes::MSSQL::Component::JobSubsystem::Job; 125 | our @ISA = qw(Monitoring::GLPlugin::DB::TableItem); 126 | use strict; 127 | 128 | sub check { 129 | my $self = shift; 130 | if ($self->mode =~ /server::jobs::failed/) { 131 | if (! defined $self->{lastrundatetime}) { 132 | $self->add_ok(sprintf "%s did never run", $self->{name}); 133 | } elsif ($self->{lastrunstatus} eq "Failed") { 134 | $self->add_critical(sprintf "%s failed at %s: %s", 135 | $self->{name}, $self->{lastrundatetime}, 136 | $self->{lastrunstatusmessage}); 137 | } elsif ($self->{lastrunstatus} eq "Retry" || $self->{lastrunstatus} eq "Canceled") { 138 | $self->add_warning(sprintf "%s %s: %s", 139 | $self->{name}, $self->{lastrunstatus}, $self->{lastrunstatusmessage}); 140 | } else { 141 | my $label = 'job_'.$self->{name}.'_runtime'; 142 | $self->set_thresholds( 143 | metric => $label, 144 | warning => 60, 145 | critical => 300, 146 | ); 147 | $self->add_message( 148 | $self->check_thresholds(metric => $label, value => $self->{lastrundurationseconds}), 149 | sprintf("job %s ran for %d seconds (started %s)", $self->{name}, 150 | $self->{lastrundurationseconds}, $self->{lastrundatetime}) 151 | ); 152 | $self->add_perfdata( 153 | label => $label, 154 | value => $self->{lastrundurationseconds}, 155 | uom => 's', 156 | ); 157 | } 158 | } elsif ($self->mode =~ /server::jobs::enabled/) { 159 | if (! defined $self->{nextrundatetime}) { 160 | $self->add_critical(sprintf "%s is not enabled", 161 | $self->{name}); 162 | } else { 163 | $self->add_ok(sprintf "job %s will run at %s", 164 | $self->{name}, $self->{nextrundatetime}); 165 | } 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /missing: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # Common wrapper for a few potentially missing GNU programs. 3 | 4 | scriptversion=2012-06-26.16; # UTC 5 | 6 | # Copyright (C) 1996-2013 Free Software Foundation, Inc. 7 | # Originally written by Fran,cois Pinard , 1996. 8 | 9 | # This program is free software; you can redistribute it and/or modify 10 | # it under the terms of the GNU General Public License as published by 11 | # the Free Software Foundation; either version 2, or (at your option) 12 | # any later version. 13 | 14 | # This program is distributed in the hope that it will be useful, 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | # GNU General Public License for more details. 18 | 19 | # You should have received a copy of the GNU General Public License 20 | # along with this program. If not, see . 21 | 22 | # As a special exception to the GNU General Public License, if you 23 | # distribute this file as part of a program that contains a 24 | # configuration script generated by Autoconf, you may include it under 25 | # the same distribution terms that you use for the rest of that program. 26 | 27 | if test $# -eq 0; then 28 | echo 1>&2 "Try '$0 --help' for more information" 29 | exit 1 30 | fi 31 | 32 | case $1 in 33 | 34 | --is-lightweight) 35 | # Used by our autoconf macros to check whether the available missing 36 | # script is modern enough. 37 | exit 0 38 | ;; 39 | 40 | --run) 41 | # Back-compat with the calling convention used by older automake. 42 | shift 43 | ;; 44 | 45 | -h|--h|--he|--hel|--help) 46 | echo "\ 47 | $0 [OPTION]... PROGRAM [ARGUMENT]... 48 | 49 | Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due 50 | to PROGRAM being missing or too old. 51 | 52 | Options: 53 | -h, --help display this help and exit 54 | -v, --version output version information and exit 55 | 56 | Supported PROGRAM values: 57 | aclocal autoconf autoheader autom4te automake makeinfo 58 | bison yacc flex lex help2man 59 | 60 | Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and 61 | 'g' are ignored when checking the name. 62 | 63 | Send bug reports to ." 64 | exit $? 65 | ;; 66 | 67 | -v|--v|--ve|--ver|--vers|--versi|--versio|--version) 68 | echo "missing $scriptversion (GNU Automake)" 69 | exit $? 70 | ;; 71 | 72 | -*) 73 | echo 1>&2 "$0: unknown '$1' option" 74 | echo 1>&2 "Try '$0 --help' for more information" 75 | exit 1 76 | ;; 77 | 78 | esac 79 | 80 | # Run the given program, remember its exit status. 81 | "$@"; st=$? 82 | 83 | # If it succeeded, we are done. 84 | test $st -eq 0 && exit 0 85 | 86 | # Also exit now if we it failed (or wasn't found), and '--version' was 87 | # passed; such an option is passed most likely to detect whether the 88 | # program is present and works. 89 | case $2 in --version|--help) exit $st;; esac 90 | 91 | # Exit code 63 means version mismatch. This often happens when the user 92 | # tries to use an ancient version of a tool on a file that requires a 93 | # minimum version. 94 | if test $st -eq 63; then 95 | msg="probably too old" 96 | elif test $st -eq 127; then 97 | # Program was missing. 98 | msg="missing on your system" 99 | else 100 | # Program was found and executed, but failed. Give up. 101 | exit $st 102 | fi 103 | 104 | perl_URL=http://www.perl.org/ 105 | flex_URL=http://flex.sourceforge.net/ 106 | gnu_software_URL=http://www.gnu.org/software 107 | 108 | program_details () 109 | { 110 | case $1 in 111 | aclocal|automake) 112 | echo "The '$1' program is part of the GNU Automake package:" 113 | echo "<$gnu_software_URL/automake>" 114 | echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:" 115 | echo "<$gnu_software_URL/autoconf>" 116 | echo "<$gnu_software_URL/m4/>" 117 | echo "<$perl_URL>" 118 | ;; 119 | autoconf|autom4te|autoheader) 120 | echo "The '$1' program is part of the GNU Autoconf package:" 121 | echo "<$gnu_software_URL/autoconf/>" 122 | echo "It also requires GNU m4 and Perl in order to run:" 123 | echo "<$gnu_software_URL/m4/>" 124 | echo "<$perl_URL>" 125 | ;; 126 | esac 127 | } 128 | 129 | give_advice () 130 | { 131 | # Normalize program name to check for. 132 | normalized_program=`echo "$1" | sed ' 133 | s/^gnu-//; t 134 | s/^gnu//; t 135 | s/^g//; t'` 136 | 137 | printf '%s\n' "'$1' is $msg." 138 | 139 | configure_deps="'configure.ac' or m4 files included by 'configure.ac'" 140 | case $normalized_program in 141 | autoconf*) 142 | echo "You should only need it if you modified 'configure.ac'," 143 | echo "or m4 files included by it." 144 | program_details 'autoconf' 145 | ;; 146 | autoheader*) 147 | echo "You should only need it if you modified 'acconfig.h' or" 148 | echo "$configure_deps." 149 | program_details 'autoheader' 150 | ;; 151 | automake*) 152 | echo "You should only need it if you modified 'Makefile.am' or" 153 | echo "$configure_deps." 154 | program_details 'automake' 155 | ;; 156 | aclocal*) 157 | echo "You should only need it if you modified 'acinclude.m4' or" 158 | echo "$configure_deps." 159 | program_details 'aclocal' 160 | ;; 161 | autom4te*) 162 | echo "You might have modified some maintainer files that require" 163 | echo "the 'automa4te' program to be rebuilt." 164 | program_details 'autom4te' 165 | ;; 166 | bison*|yacc*) 167 | echo "You should only need it if you modified a '.y' file." 168 | echo "You may want to install the GNU Bison package:" 169 | echo "<$gnu_software_URL/bison/>" 170 | ;; 171 | lex*|flex*) 172 | echo "You should only need it if you modified a '.l' file." 173 | echo "You may want to install the Fast Lexical Analyzer package:" 174 | echo "<$flex_URL>" 175 | ;; 176 | help2man*) 177 | echo "You should only need it if you modified a dependency" \ 178 | "of a man page." 179 | echo "You may want to install the GNU Help2man package:" 180 | echo "<$gnu_software_URL/help2man/>" 181 | ;; 182 | makeinfo*) 183 | echo "You should only need it if you modified a '.texi' file, or" 184 | echo "any other file indirectly affecting the aspect of the manual." 185 | echo "You might want to install the Texinfo package:" 186 | echo "<$gnu_software_URL/texinfo/>" 187 | echo "The spurious makeinfo call might also be the consequence of" 188 | echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might" 189 | echo "want to install GNU make:" 190 | echo "<$gnu_software_URL/make/>" 191 | ;; 192 | *) 193 | echo "You might have modified some files without having the proper" 194 | echo "tools for further handling them. Check the 'README' file, it" 195 | echo "often tells you about the needed prerequisites for installing" 196 | echo "this package. You may also peek at any GNU archive site, in" 197 | echo "case some other package contains this missing '$1' program." 198 | ;; 199 | esac 200 | } 201 | 202 | give_advice "$1" | sed -e '1s/^/WARNING: /' \ 203 | -e '2,$s/^/ /' >&2 204 | 205 | # Propagate the correct exit status (expected to be 127 for a program 206 | # not found, 63 for a program that failed due to version mismatch). 207 | exit $st 208 | 209 | # Local variables: 210 | # eval: (add-hook 'write-file-hooks 'time-stamp) 211 | # time-stamp-start: "scriptversion=" 212 | # time-stamp-format: "%:y-%02m-%02d.%02H" 213 | # time-stamp-time-zone: "UTC" 214 | # time-stamp-end: "; # UTC" 215 | # End: 216 | -------------------------------------------------------------------------------- /plugins-scripts/Classes/Sybase/DBI.pm: -------------------------------------------------------------------------------- 1 | package Classes::Sybase::DBI; 2 | our @ISA = qw(Classes::Sybase Monitoring::GLPlugin::DB::DBI); 3 | use strict; 4 | use File::Basename; 5 | 6 | sub check_connect { 7 | my ($self) = @_; 8 | my $stderrvar; 9 | my $dbi_options = { RaiseError => 1, AutoCommit => $self->opts->commit, PrintError => 1 }; 10 | my $dsn = "DBI:Sybase:"; 11 | if ($self->opts->hostname) { 12 | $dsn .= sprintf ";host=%s", $self->opts->hostname; 13 | $dsn .= sprintf ";port=%s", $self->opts->port; 14 | } else { 15 | $dsn .= sprintf ";server=%s", $self->opts->server; 16 | } 17 | $dsn .= ";encryptPassword=1"; 18 | if ($self->opts->currentdb) { 19 | if (index($self->opts->currentdb,"-") != -1) { 20 | # once the database name had to be put in quotes.... 21 | $dsn .= sprintf ";database=%s", $self->opts->currentdb; 22 | } else { 23 | $dsn .= sprintf ";database=%s", $self->opts->currentdb; 24 | } 25 | } 26 | if (basename($0) =~ /_sybase_/) { 27 | $dbi_options->{syb_chained_txn} = 1; 28 | $dsn .= sprintf ";tdsLevel=CS_TDS_42"; 29 | } 30 | $self->set_variable("dsn", $dsn); 31 | eval { 32 | require DBI; 33 | $self->set_timeout_alarm($self->opts->timeout - 1, sub { 34 | die "alrm"; 35 | }); 36 | *SAVEERR = *STDERR; 37 | open OUT ,'>',\$stderrvar; 38 | *STDERR = *OUT; 39 | $self->{tic} = Time::HiRes::time(); 40 | if ($self->{handle} = DBI->connect( 41 | $dsn, 42 | $self->opts->username, 43 | $self->opts->password, 44 | $dbi_options)) { 45 | $Monitoring::GLPlugin::DB::session = $self->{handle}; 46 | } 47 | $self->{tac} = Time::HiRes::time(); 48 | $Monitoring::GLPlugin::DB::session->{syb_flush_finish} = 1; 49 | *STDERR = *SAVEERR; 50 | }; 51 | if ($@) { 52 | if ($@ =~ /alrm/) { 53 | $self->add_critical( 54 | sprintf "connection could not be established within %s seconds", 55 | $self->opts->timeout); 56 | } else { 57 | $self->add_critical($@); 58 | } 59 | } elsif ($stderrvar && $stderrvar =~ /can't change context to database/) { 60 | $self->add_critical($stderrvar); 61 | } elsif (! $self->{handle}) { 62 | $self->add_critical("no connection"); 63 | } else { 64 | $self->set_timeout_alarm($self->opts->timeout - ($self->{tac} - $self->{tic})); 65 | } 66 | } 67 | 68 | sub fetchrow_array { 69 | my ($self, $sql, @arguments) = @_; 70 | my @row = (); 71 | my $errvar = ""; 72 | my $stderrvar = ""; 73 | $self->set_variable("verbosity", 2); 74 | *SAVEERR = *STDERR; 75 | open ERR ,'>',\$stderrvar; 76 | *STDERR = *ERR; 77 | eval { 78 | if ($self->get_variable("dsn") =~ /tdsLevel/) { 79 | # better install a handler here. otherwise the plugin output is 80 | # unreadable when errors occur 81 | $Monitoring::GLPlugin::DB::session->{syb_err_handler} = sub { 82 | my($err, $sev, $state, $line, $server, 83 | $proc, $msg, $sql, $err_type) = @_; 84 | $errvar = join("\n", (split(/\n/, $errvar), $msg)); 85 | return 0; 86 | }; 87 | } 88 | $self->debug(sprintf "SQL:\n%s\nARGS:\n%s\n", 89 | $sql, Data::Dumper::Dumper(\@arguments)); 90 | my $sth = $Monitoring::GLPlugin::DB::session->prepare($sql); 91 | if (scalar(@arguments)) { 92 | $sth->execute(@arguments) || die DBI::errstr(); 93 | } else { 94 | $sth->execute() || die DBI::errstr(); 95 | } 96 | if (lc $sql =~ /^\s*(exec |sp_)/ || $sql =~ /^\s*exec sp/im) { 97 | # flatten the result sets 98 | do { 99 | while (my $aref = $sth->fetchrow_arrayref()) { 100 | push(@row, @{$aref}); 101 | } 102 | } while ($sth->{syb_more_results}); 103 | } else { 104 | @row = $sth->fetchrow_array(); 105 | } 106 | $self->debug(sprintf "RESULT:\n%s\n", 107 | Data::Dumper::Dumper(\@row)); 108 | $sth->finish(); 109 | }; 110 | *STDERR = *SAVEERR; 111 | if ($@) { 112 | $self->debug(sprintf "bumm %s", $@); 113 | $self->add_critical($@); 114 | } elsif ($stderrvar || $errvar) { 115 | $errvar = join("\n", (split(/\n/, $errvar), $stderrvar)); 116 | $self->debug(sprintf "stderr %s", $errvar) ; 117 | $self->add_warning($errvar); 118 | } 119 | return $row[0] unless wantarray; 120 | return @row; 121 | } 122 | 123 | sub fetchall_array { 124 | my ($self, $sql, @arguments) = @_; 125 | my $rows = undef; 126 | my $errvar = ""; 127 | my $stderrvar = ""; 128 | *SAVEERR = *STDERR; 129 | open ERR ,'>',\$stderrvar; 130 | *STDERR = *ERR; 131 | eval { 132 | $self->debug(sprintf "SQL:\n%s\nARGS:\n%s\n", 133 | $sql, Data::Dumper::Dumper(\@arguments)); 134 | if ($sql =~ /^\s*dbcc /im) { 135 | # dbcc schreibt auf stdout. Die Ausgabe muss daher 136 | # mit einem eigenen Handler aufgefangen werden. 137 | $Monitoring::GLPlugin::DB::session->{syb_err_handler} = sub { 138 | my($err, $sev, $state, $line, $server, 139 | $proc, $msg, $sql, $err_type) = @_; 140 | push(@{$rows}, $msg); 141 | return 0; 142 | }; 143 | } 144 | my $sth = $Monitoring::GLPlugin::DB::session->prepare($sql); 145 | if (scalar(@arguments)) { 146 | $sth->execute(@arguments); 147 | } else { 148 | $sth->execute(); 149 | } 150 | if ($sql !~ /^\s*dbcc /im) { 151 | $rows = $sth->fetchall_arrayref(); 152 | } 153 | $sth->finish(); 154 | $self->debug(sprintf "RESULT:\n%s\n", 155 | Data::Dumper::Dumper($rows)); 156 | }; 157 | *STDERR = *SAVEERR; 158 | if ($@) { 159 | $self->debug(sprintf "bumm %s", $@); 160 | $self->add_critical($@); 161 | $rows = []; 162 | } elsif ($stderrvar || $errvar) { 163 | $errvar = join("\n", (split(/\n/, $errvar), $stderrvar)); 164 | $self->debug(sprintf "stderr %s", $errvar) ; 165 | $self->add_warning($errvar); 166 | } 167 | return @{$rows}; 168 | } 169 | 170 | sub exec_sp_1hash { 171 | my ($self, $sql, @arguments) = @_; 172 | my $rows = undef; 173 | my $stderrvar; 174 | *SAVEERR = *STDERR; 175 | open ERR ,'>',\$stderrvar; 176 | *STDERR = *ERR; 177 | eval { 178 | $self->debug(sprintf "EXEC\n%s\nARGS:\n%s\n", 179 | $sql, Data::Dumper::Dumper(\@arguments)); 180 | my $sth = $Monitoring::GLPlugin::DB::session->prepare($sql); 181 | if (scalar(@arguments)) { 182 | $sth->execute(@arguments); 183 | } else { 184 | $sth->execute(); 185 | } 186 | do { 187 | while (my $href = $sth->fetchrow_hashref()) { 188 | foreach (keys %{$href}) { 189 | push(@{$rows}, [ $_, $href->{$_} ]); 190 | } 191 | } 192 | } while ($sth->{syb_more_results}); 193 | $self->debug(sprintf "RESULT:\n%s\n", 194 | Data::Dumper::Dumper($rows)); 195 | $sth->finish(); 196 | }; 197 | *STDERR = *SAVEERR; 198 | if ($@) { 199 | $self->debug(sprintf "bumm %s", $@); 200 | $self->add_critical($@); 201 | $rows = []; 202 | } elsif ($stderrvar) { 203 | $self->debug(sprintf "stderr %s", $stderrvar) ; 204 | $self->add_warning($stderrvar); 205 | $rows = []; 206 | } 207 | return @{$rows}; 208 | } 209 | 210 | sub execute { 211 | my ($self, $sql, @arguments) = @_; 212 | my $errvar = ""; 213 | my $stderrvar = ""; 214 | $Monitoring::GLPlugin::DB::session->{syb_err_handler} = sub { 215 | # exec sometimes a status code which, if not caught by this handler, 216 | # is output to stderr. So even if the procedure was run correctly 217 | # there may be a warning 218 | my($err, $sev, $state, $line, $server, 219 | $proc, $msg, $sql, $err_type) = @_; 220 | $errvar = join("\n", (split(/\n/, $errvar), $msg)); 221 | return 0; 222 | }; 223 | *SAVEERR = *STDERR; 224 | open ERR ,'>',\$stderrvar; 225 | *STDERR = *ERR; 226 | eval { 227 | $self->debug(sprintf "EXEC\n%s\nARGS:\n%s\n", 228 | $sql, Data::Dumper::Dumper(\@arguments)); 229 | my $sth = $Monitoring::GLPlugin::DB::session->prepare($sql); 230 | $sth->execute(); 231 | $sth->finish(); 232 | }; 233 | *STDERR = *SAVEERR; 234 | if ($@) { 235 | $self->debug(sprintf "bumm %s", $@); 236 | $self->add_critical($@); 237 | } elsif ($stderrvar || $errvar) { 238 | $errvar = join("\n", (split(/\n/, $errvar), $stderrvar)); 239 | $self->debug(sprintf "stderr %s", $errvar) ; 240 | $self->add_warning($errvar); 241 | } 242 | } 243 | 244 | 245 | sub add_dbi_funcs { 246 | my $self = shift; 247 | $self->SUPER::add_dbi_funcs(); 248 | { 249 | no strict 'refs'; 250 | *{'Monitoring::GLPlugin::DB::fetchall_array'} = \&{"Classes::Sybase::DBI::fetchall_array"}; 251 | *{'Monitoring::GLPlugin::DB::fetchrow_array'} = \&{"Classes::Sybase::DBI::fetchrow_array"}; 252 | *{'Monitoring::GLPlugin::DB::exec_sp_1hash'} = \&{"Classes::Sybase::DBI::exec_sp_1hash"}; 253 | *{'Monitoring::GLPlugin::DB::execute'} = \&{"Classes::Sybase::DBI::execute"}; 254 | } 255 | } 256 | 257 | -------------------------------------------------------------------------------- /plugins-scripts/Classes/Sybase/Sqsh.pm: -------------------------------------------------------------------------------- 1 | package Classes::Sybase::Sqsh; 2 | our @ISA = qw(Classes::Sybase); 3 | use strict; 4 | use File::Basename; 5 | 6 | sub create_cmd_line { 7 | my $self = shift; 8 | my @args = (); 9 | if ($self->opts->server) { 10 | push (@args, sprintf "-S '%s'", $self->opts->server); 11 | } elsif ($self->opts->hostname) { 12 | push (@args, sprintf "-S '%s:%d'", $self->opts->hostname, $self->opts->port || 1433); 13 | } else { 14 | $self->add_critical("-S oder -H waere nicht schlecht"); 15 | } 16 | push (@args, sprintf "-U '%s'", $self->opts->username); 17 | push (@args, sprintf "-P '%s'", 18 | $self->decode_rfc3986($self->opts->password)); 19 | push (@args, sprintf "-i '%s'", 20 | $Monitoring::GLPlugin::DB::sql_commandfile); 21 | push (@args, sprintf "-o '%s'", 22 | $Monitoring::GLPlugin::DB::sql_resultfile); 23 | if ($self->opts->currentdb) { 24 | push (@args, sprintf "-D '%s'", $self->opts->currentdb); 25 | } 26 | push (@args, sprintf "-h -s '|' -m bcp"); 27 | $Monitoring::GLPlugin::DB::session = 28 | sprintf '"%s" %s', $self->{extcmd}, join(" ", @args); 29 | } 30 | 31 | sub check_connect { 32 | my $self = shift; 33 | my $stderrvar; 34 | if (! $self->find_extcmd("sqsh", "SQL_HOME")) { 35 | $self->add_unknown("sqsh command was not found"); 36 | return; 37 | } 38 | $self->create_extcmd_files(); 39 | $self->create_cmd_line(); 40 | eval { 41 | $self->set_timeout_alarm($self->opts->timeout - 1, sub { 42 | die "alrm"; 43 | }); 44 | *SAVEERR = *STDERR; 45 | open OUT ,'>',\$stderrvar; 46 | *STDERR = *OUT; 47 | $self->{tic} = Time::HiRes::time(); 48 | my $answer = $self->fetchrow_array(q{ 49 | SELECT 'schnorch' 50 | }); 51 | die unless defined $answer and $answer eq 'schnorch'; 52 | $self->{tac} = Time::HiRes::time(); 53 | *STDERR = *SAVEERR; 54 | }; 55 | if ($@) { 56 | if ($@ =~ /alrm/) { 57 | $self->add_critical( 58 | sprintf "connection could not be established within %s seconds", 59 | $self->opts->timeout); 60 | } else { 61 | $self->add_critical($@); 62 | } 63 | } elsif ($stderrvar && $stderrvar =~ /can't change context to database/) { 64 | $self->add_critical($stderrvar); 65 | } else { 66 | $self->set_timeout_alarm($self->opts->timeout - ($self->{tac} - $self->{tic})); 67 | } 68 | } 69 | 70 | sub write_extcmd_file { 71 | my $self = shift; 72 | my $sql = shift; 73 | open CMDCMD, "> $Monitoring::GLPlugin::DB::sql_commandfile"; 74 | printf CMDCMD "%s\n", $sql; 75 | printf CMDCMD "go\n"; 76 | close CMDCMD; 77 | } 78 | 79 | sub fetchrow_array { 80 | my $self = shift; 81 | my $sql = shift; 82 | my @arguments = @_; 83 | my @row = (); 84 | my $stderrvar = ""; 85 | foreach (@arguments) { 86 | # replace the ? by the parameters 87 | if (/^\d+$/) { 88 | $sql =~ s/\?/$_/; 89 | } else { 90 | $sql =~ s/\?/'$_'/; 91 | } 92 | } 93 | $self->set_variable("verbosity", 2); 94 | $self->debug(sprintf "SQL (? resolved):\n%s\nARGS:\n%s\n", 95 | $sql, Data::Dumper::Dumper(\@arguments)); 96 | $self->write_extcmd_file($sql); 97 | *SAVEERR = *STDERR; 98 | open OUT ,'>',\$stderrvar; 99 | *STDERR = *OUT; 100 | $self->debug($Monitoring::GLPlugin::DB::session); 101 | my $exit_output = `$Monitoring::GLPlugin::DB::session`; 102 | *STDERR = *SAVEERR; 103 | if ($?) { 104 | my $output = do { local (@ARGV, $/) = $Monitoring::GLPlugin::DB::sql_resultfile; my $x = <>; close ARGV; $x } || ''; 105 | $self->debug(sprintf "stderr %s", $stderrvar) ; 106 | $self->add_warning($stderrvar); 107 | } else { 108 | my $output = do { local (@ARGV, $/) = $Monitoring::GLPlugin::DB::sql_resultfile; my $x = <>; close ARGV; $x } || ''; 109 | @row = map { $self->convert_scientific_numbers($_) } 110 | map { s/^\s+([\.\d]+)$/$1/g; $_ } # strip leading space from numbers 111 | map { s/\s+$//g; $_ } # strip trailing space 112 | split(/\|/, (map { s/^\|//; $_; } grep {! /^\s*$/ } split(/\n/, $output) 113 | )[0]); 114 | $self->debug(sprintf "RESULT:\n%s\n", 115 | Data::Dumper::Dumper(\@row)); 116 | } 117 | if ($@) { 118 | $self->debug(sprintf "bumm %s", $@); 119 | $self->add_critical($@); 120 | } 121 | return $row[0] unless wantarray; 122 | return @row; 123 | } 124 | 125 | sub fetchall_array { 126 | my $self = shift; 127 | my $sql = shift; 128 | my @arguments = @_; 129 | my $rows = []; 130 | my $stderrvar = ""; 131 | foreach (@arguments) { 132 | # replace the ? by the parameters 133 | if (/^\d+$/) { 134 | $sql =~ s/\?/$_/; 135 | } else { 136 | $sql =~ s/\?/'$_'/; 137 | } 138 | } 139 | $self->set_variable("verbosity", 2); 140 | $self->debug(sprintf "SQL (? resolved):\n%s\nARGS:\n%s\n", 141 | $sql, Data::Dumper::Dumper(\@arguments)); 142 | $self->write_extcmd_file($sql); 143 | *SAVEERR = *STDERR; 144 | open OUT ,'>',\$stderrvar; 145 | *STDERR = *OUT; 146 | $self->debug($Monitoring::GLPlugin::DB::session); 147 | my $exit_output = `$Monitoring::GLPlugin::DB::session`; 148 | *STDERR = *SAVEERR; 149 | if ($?) { 150 | my $output = do { local (@ARGV, $/) = $Monitoring::GLPlugin::DB::sql_resultfile; my $x = <>; close ARGV; $x } || ''; 151 | $self->debug(sprintf "stderr %s", $stderrvar) ; 152 | $self->add_warning($stderrvar) if $stderrvar; 153 | $self->add_warning($output); 154 | } else { 155 | my $output = do { local (@ARGV, $/) = $Monitoring::GLPlugin::DB::sql_resultfile; my $x = <>; close ARGV; $x } || ''; 156 | my @rows = map { [ 157 | map { $self->convert_scientific_numbers($_) } 158 | map { s/^\s+([\.\d]+)$/$1/g; $_ } 159 | map { s/\s+$//g; $_ } 160 | split /\|/ 161 | ] } grep { ! /^\d+ rows selected/ } 162 | grep { ! /^\d+ [Zz]eilen ausgew / } 163 | grep { ! /^Elapsed: / } 164 | grep { ! /^\s*$/ } map { s/^\|//; $_; } split(/\n/, $output); 165 | $rows = \@rows; 166 | $self->debug(sprintf "RESULT:\n%s\n", 167 | Data::Dumper::Dumper($rows)); 168 | } 169 | return @{$rows}; 170 | } 171 | 172 | sub execute { 173 | my $self = shift; 174 | my $sql = shift; 175 | my @arguments = @_; 176 | my $rows = []; 177 | my $stderrvar = ""; 178 | foreach (@arguments) { 179 | # replace the ? by the parameters 180 | if (/^\d+$/) { 181 | $sql =~ s/\?/$_/; 182 | } else { 183 | $sql =~ s/\?/'$_'/; 184 | } 185 | } 186 | $self->set_variable("verbosity", 2); 187 | $self->debug(sprintf "EXEC (? resolved):\n%s\nARGS:\n%s\n", 188 | $sql, Data::Dumper::Dumper(\@arguments)); 189 | $self->write_extcmd_file($sql); 190 | *SAVEERR = *STDERR; 191 | open OUT ,'>',\$stderrvar; 192 | *STDERR = *OUT; 193 | $self->debug($Monitoring::GLPlugin::DB::session); 194 | my $exit_output = `$Monitoring::GLPlugin::DB::session`; 195 | *STDERR = *SAVEERR; 196 | if ($?) { 197 | my $output = do { local (@ARGV, $/) = $Monitoring::GLPlugin::DB::sql_resultfile; my $x = <>; close ARGV; $x } || ''; 198 | $self->debug(sprintf "stderr %s", $stderrvar) ; 199 | $self->add_warning($stderrvar) if $stderrvar; 200 | $self->add_warning($output); 201 | } else { 202 | my $output = do { local (@ARGV, $/) = $Monitoring::GLPlugin::DB::sql_resultfile; my $x = <>; close ARGV; $x } || ''; 203 | my @rows = map { [ 204 | map { $self->convert_scientific_numbers($_) } 205 | map { s/^\s+([\.\d]+)$/$1/g; $_ } 206 | map { s/\s+$//g; $_ } 207 | split /\|/ 208 | ] } grep { ! /^\d+ rows selected/ } 209 | grep { ! /^\d+ [Zz]eilen ausgew / } 210 | grep { ! /^Elapsed: / } 211 | grep { ! /^\s*$/ } map { s/^\|//; $_; } split(/\n/, $output); 212 | $rows = \@rows; 213 | $self->debug(sprintf "RESULT:\n%s\n", 214 | Data::Dumper::Dumper($rows)); 215 | } 216 | return @{$rows}; 217 | } 218 | 219 | sub decode_rfc3986 { 220 | my $self = shift; 221 | my $password = shift; 222 | eval { 223 | no warnings 'all'; 224 | $password = $Monitoring::GLPlugin::plugin->{opts}->decode_rfc3986($password); 225 | }; 226 | # we call '...%s/%s@...' inside backticks where the second %s is the password 227 | # abc'xcv -> ''abc'\''xcv'' 228 | # abc'`xcv -> ''abc'\''\`xcv'' 229 | if ($password && $password =~ /'/) { 230 | $password = "'".join("\\'", map { "'".$_."'"; } split("'", $password))."'"; 231 | } 232 | return $password; 233 | } 234 | 235 | sub add_dbi_funcs { 236 | my $self = shift; 237 | $self->SUPER::add_dbi_funcs(); 238 | { 239 | no strict 'refs'; 240 | *{'Monitoring::GLPlugin::DB::create_cmd_line'} = \&{"Classes::Sybase::Sqsh::create_cmd_line"}; 241 | *{'Monitoring::GLPlugin::DB::write_extcmd_file'} = \&{"Classes::Sybase::Sqsh::write_extcmd_file"}; 242 | *{'Monitoring::GLPlugin::DB::decode_rfc3986'} = \&{"Classes::Sybase::Sqsh::decode_rfc3986"}; 243 | *{'Monitoring::GLPlugin::DB::fetchall_array'} = \&{"Classes::Sybase::Sqsh::fetchall_array"}; 244 | *{'Monitoring::GLPlugin::DB::fetchrow_array'} = \&{"Classes::Sybase::Sqsh::fetchrow_array"}; 245 | *{'Monitoring::GLPlugin::DB::execute'} = \&{"Classes::Sybase::Sqsh::execute"}; 246 | } 247 | } 248 | 249 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2008 Free Software 2 | Foundation, Inc. 3 | 4 | This file is free documentation; the Free Software Foundation gives 5 | unlimited permission to copy, distribute and modify it. 6 | 7 | Basic Installation 8 | ================== 9 | 10 | These are generic installation instructions. 11 | 12 | The `configure' shell script attempts to guess correct values for 13 | various system-dependent variables used during compilation. It uses 14 | those values to create a `Makefile' in each directory of the package. 15 | It may also create one or more `.h' files containing system-dependent 16 | definitions. Finally, it creates a shell script `config.status' that 17 | you can run in the future to recreate the current configuration, and a 18 | file `config.log' containing compiler output (useful mainly for 19 | debugging `configure'). 20 | 21 | It can also use an optional file (typically called `config.cache' 22 | and enabled with `--cache-file=config.cache' or simply `-C') that saves 23 | the results of its tests to speed up reconfiguring. (Caching is 24 | disabled by default to prevent problems with accidental use of stale 25 | cache files.) 26 | 27 | If you need to do unusual things to compile the package, please try 28 | to figure out how `configure' could check whether to do them, and mail 29 | diffs or instructions to the address given in the `README' so they can 30 | be considered for the next release. If you are using the cache, and at 31 | some point `config.cache' contains results you don't want to keep, you 32 | may remove or edit it. 33 | 34 | The file `configure.ac' (or `configure.in') is used to create 35 | `configure' by a program called `autoconf'. You only need 36 | `configure.ac' if you want to change it or regenerate `configure' using 37 | a newer version of `autoconf'. 38 | 39 | The simplest way to compile this package is: 40 | 41 | 1. `cd' to the directory containing the package's source code and type 42 | `./configure' to configure the package for your system. If you're 43 | using `csh' on an old version of System V, you might need to type 44 | `sh ./configure' instead to prevent `csh' from trying to execute 45 | `configure' itself. 46 | 47 | Running `configure' takes awhile. While running, it prints some 48 | messages telling which features it is checking for. 49 | 50 | 2. Type `make' to compile the package. 51 | 52 | 3. Optionally, type `make check' to run any self-tests that come with 53 | the package. 54 | 55 | 4. Type `make install' to install the programs and any data files and 56 | documentation. 57 | 58 | 5. You can remove the program binaries and object files from the 59 | source code directory by typing `make clean'. To also remove the 60 | files that `configure' created (so you can compile the package for 61 | a different kind of computer), type `make distclean'. There is 62 | also a `make maintainer-clean' target, but that is intended mainly 63 | for the package's developers. If you use it, you may have to get 64 | all sorts of other programs in order to regenerate files that came 65 | with the distribution. 66 | 67 | Compilers and Options 68 | ===================== 69 | 70 | Some systems require unusual options for compilation or linking that 71 | the `configure' script does not know about. Run `./configure --help' 72 | for details on some of the pertinent environment variables. 73 | 74 | You can give `configure' initial values for configuration parameters 75 | by setting variables in the command line or in the environment. Here 76 | is an example: 77 | 78 | ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix 79 | 80 | *Note Defining Variables::, for more details. 81 | 82 | Compiling For Multiple Architectures 83 | ==================================== 84 | 85 | You can compile the package for more than one kind of computer at the 86 | same time, by placing the object files for each architecture in their 87 | own directory. To do this, you must use a version of `make' that 88 | supports the `VPATH' variable, such as GNU `make'. `cd' to the 89 | directory where you want the object files and executables to go and run 90 | the `configure' script. `configure' automatically checks for the 91 | source code in the directory that `configure' is in and in `..'. 92 | 93 | If you have to use a `make' that does not support the `VPATH' 94 | variable, you have to compile the package for one architecture at a 95 | time in the source code directory. After you have installed the 96 | package for one architecture, use `make distclean' before reconfiguring 97 | for another architecture. 98 | 99 | Installation Names 100 | ================== 101 | 102 | By default, `make install' will install the package's files in 103 | `/usr/local/bin', `/usr/local/man', etc. You can specify an 104 | installation prefix other than `/usr/local' by giving `configure' the 105 | option `--prefix=PATH'. 106 | 107 | You can specify separate installation prefixes for 108 | architecture-specific files and architecture-independent files. If you 109 | give `configure' the option `--exec-prefix=PATH', the package will use 110 | PATH as the prefix for installing programs and libraries. 111 | Documentation and other data files will still use the regular prefix. 112 | 113 | In addition, if you use an unusual directory layout you can give 114 | options like `--bindir=PATH' to specify different values for particular 115 | kinds of files. Run `configure --help' for a list of the directories 116 | you can set and what kinds of files go in them. 117 | 118 | If the package supports it, you can cause programs to be installed 119 | with an extra prefix or suffix on their names by giving `configure' the 120 | option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. 121 | 122 | Optional Features 123 | ================= 124 | 125 | Some packages pay attention to `--enable-FEATURE' options to 126 | `configure', where FEATURE indicates an optional part of the package. 127 | They may also pay attention to `--with-PACKAGE' options, where PACKAGE 128 | is something like `gnu-as' or `x' (for the X Window System). The 129 | `README' should mention any `--enable-' and `--with-' options that the 130 | package recognizes. 131 | 132 | For packages that use the X Window System, `configure' can usually 133 | find the X include and library files automatically, but if it doesn't, 134 | you can use the `configure' options `--x-includes=DIR' and 135 | `--x-libraries=DIR' to specify their locations. 136 | 137 | Specifying the System Type 138 | ========================== 139 | 140 | There may be some features `configure' cannot figure out 141 | automatically, but needs to determine by the type of machine the package 142 | will run on. Usually, assuming the package is built to be run on the 143 | _same_ architectures, `configure' can figure that out, but if it prints 144 | a message saying it cannot guess the machine type, give it the 145 | `--build=TYPE' option. TYPE can either be a short name for the system 146 | type, such as `sun4', or a canonical name which has the form: 147 | 148 | CPU-COMPANY-SYSTEM 149 | 150 | where SYSTEM can have one of these forms: 151 | 152 | OS KERNEL-OS 153 | 154 | See the file `config.sub' for the possible values of each field. If 155 | `config.sub' isn't included in this package, then this package doesn't 156 | need to know the machine type. 157 | 158 | If you are _building_ compiler tools for cross-compiling, you should 159 | use the `--target=TYPE' option to select the type of system they will 160 | produce code for. 161 | 162 | If you want to _use_ a cross compiler, that generates code for a 163 | platform different from the build platform, you should specify the 164 | "host" platform (i.e., that on which the generated programs will 165 | eventually be run) with `--host=TYPE'. 166 | 167 | Sharing Defaults 168 | ================ 169 | 170 | If you want to set default values for `configure' scripts to share, 171 | you can create a site shell script called `config.site' that gives 172 | default values for variables like `CC', `cache_file', and `prefix'. 173 | `configure' looks for `PREFIX/share/config.site' if it exists, then 174 | `PREFIX/etc/config.site' if it exists. Or, you can set the 175 | `CONFIG_SITE' environment variable to the location of the site script. 176 | A warning: not all `configure' scripts look for a site script. 177 | 178 | Defining Variables 179 | ================== 180 | 181 | Variables not defined in a site shell script can be set in the 182 | environment passed to `configure'. However, some packages may run 183 | configure again during the build, and the customized values of these 184 | variables may be lost. In order to avoid this problem, you should set 185 | them in the `configure' command line, using `VAR=value'. For example: 186 | 187 | ./configure CC=/usr/local2/bin/gcc 188 | 189 | will cause the specified gcc to be used as the C compiler (unless it is 190 | overridden in the site shell script). 191 | 192 | `configure' Invocation 193 | ====================== 194 | 195 | `configure' recognizes the following options to control how it 196 | operates. 197 | 198 | `--help' 199 | `-h' 200 | Print a summary of the options to `configure', and exit. 201 | 202 | `--version' 203 | `-V' 204 | Print the version of Autoconf used to generate the `configure' 205 | script, and exit. 206 | 207 | `--cache-file=FILE' 208 | Enable the cache: use and save the results of the tests in FILE, 209 | traditionally `config.cache'. FILE defaults to `/dev/null' to 210 | disable caching. 211 | 212 | `--config-cache' 213 | `-C' 214 | Alias for `--cache-file=config.cache'. 215 | 216 | `--quiet' 217 | `--silent' 218 | `-q' 219 | Do not print messages saying which checks are being made. To 220 | suppress all normal output, redirect it to `/dev/null' (any error 221 | messages will still be shown). 222 | 223 | `--srcdir=DIR' 224 | Look for the package's source code in directory DIR. Usually 225 | `configure' can determine that directory automatically. 226 | 227 | `configure' also accepts some other, not widely useful, options. Run 228 | `configure --help' for more details. 229 | 230 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | * 2024-11-12 2.7.8 2 | add flag --check-all-replicas so that all replicas get proper backup checks 3 | in mode database-free you can use --name2 to filter for filegroups. Matching 4 | filegroups will be checked against thresholds, nonmatching will always be OK. 5 | (Actually used as --name2 '^(?!(DB::ROFG))' to ignore readonly filegroups) 6 | * 2024-04-16 2.7.7 7 | add modes database-differential-backup-age and database-full-backup-age 8 | * 2024-01-08 2.7.6.1 9 | fix the url in the help text 10 | * 2024-01-08 2.7.6 11 | add mode uptime 12 | * 2023-09-22 2.7.5 13 | update version&changelog for PR#52, thanks tectumopticum 14 | * 2022-08-31 2.7.4 15 | detect recovering mirror databases (requires sa privilege) 16 | * 2022-04-20 2.7.3 17 | leave some time for the first backup of new databases (--mitigation ok=24) 18 | * 2021-08-05 2.7.2.2 19 | bugfix in database-free perfdata 20 | * 2020-12-10 2.7.2.1 21 | Merge pull request #45 from GalipoliX/patch-1, improve a query in availability-mode 22 | * 2020-11-25 2.7.2 23 | database-online is more strict now, restoring is a bad state 24 | * 2020-11-11 2.7.1.2 25 | write a message if no availability groups were found 26 | * 2020-11-10 2.7.1.1 27 | bugfix in availability-group-health 28 | * 2020-11-02 2.7.1 29 | improve availability-group-health, check synchronization_state+health 30 | * 2020-10-26 2.7 31 | Update GLPlugin, commandline parameters can be set as environment variables 32 | * 2020-07-17 2.6.4.17 33 | Merge pull request #42 from ulikl/fix_long_running_jobs 34 | * 2020-04-04 2.6.4.16 35 | fix a bug in is_online() 36 | * 2019-07-17 2.6.4.15 37 | apply filter --nooffline and --notemp to the backup-modes 38 | encrypt password 39 | * 2018-03-22 2.6.4.14 40 | fix a bug in password decoding 41 | * 2018-03-16 2.6.4.13 42 | add db max size as threshold in database-size 43 | * 2017-07-29 2.6.4.12 44 | fix currentdb with a - in the database name 45 | * 2017-05-29 2.6.4.11 46 | update glplugin 47 | * 2017-04-18 2.6.4.10 48 | the same, forgotten to fix it in database-online 49 | * 2017-04-12 2.6.4.9 50 | fix a bug in database-*, is_primary_replica does not exist in sqlsrv 2012 51 | * 2017-02-08 2.6.4.8 52 | ignore alwayson replicas in database-free 53 | * 2016-11-03 2.6.4.7 54 | bugfix in database-free with zero-size filestreams. (Thanks Ivo) 55 | * 2016-09-20 2.6.4.6 56 | ignore database snapshots in database-free 57 | * 2016-08-12 2.6.4.5 58 | fix a bug in database-free (was introduced in 2.6.4.2) 59 | * 2016-08-10 2.6.4.4 60 | added Extraopts to the dist 61 | * 2016-08-05 2.6.4.3 62 | availability-group-health only for primary replica 63 | * 2016-08-03 2.6.4.2 64 | Remove a uninitialized-message in database-free&db-user 65 | * 2016-07-29 2.6.4.1 66 | availability-group-health only for versions >= 11.x 67 | * 2016-07-26 2.6.4 68 | add --mode availability-group-health 69 | * 2016-06-23 2.6.3.1 70 | use AlwaysOn tables only if enabled 71 | * 2016-06-23 2.6.3 72 | fix create-database-user, fix execute error handling 73 | * 2016-06-20 2.6.2.4 74 | update GLPlugin (encode) 75 | cleanup deprecated files 76 | * 2016-06-03 2.6.2.3 77 | update GLPlugin 78 | * 2016-05-11 2.6.2.2 79 | unset syb_flush_finish 80 | use NOLOCK for msdb.dbo.backupset, otherwise selects during backups take too long 81 | * 2016-05-02 2.6.2.1 82 | set syb_flush_finish 83 | * 2016-04-19 2.6.2 84 | let sql statements run into their private timeouts 85 | fix create-monitoring-user 86 | * 2016-04-04 2.6.1 87 | improve backup-age runtime for large number of databases 88 | * 2016-03-23 2.6 89 | add modes database-*free-details, database-filegroup-free, database-file-free 90 | improved calculation of free space 91 | * 2016-02-09 2.5 92 | add glplugin submodule 93 | * 2016-01-27 2.3.1.1 94 | bugfix in backup-age (The multi-part identifier "ar.replica_id" could not be bound). Korinthenkacker! 95 | * 2016-01-27 2.3.1 96 | bugfix in database-modes ("-" in database name) 97 | * 2016-01-24 2.3 98 | add method sqsh and sqlrelay (to redesign) 99 | * 2016-01-24 2.2.2 100 | add sybase database* (to redesign) 101 | * 2016-01-19 2.2.1 102 | fix aps detection 103 | * 2016-01-15 2.2 104 | add aps modes 105 | * 2015-08-10 2.1 106 | add more modes 107 | * 2015-07-13 2.0.3 108 | new directory layout, standalone 109 | * 2015-04-23 2.0.2.1 110 | update GLPlugin[SNMP] 111 | * 2.0.2 2015-01-08 112 | mitigation of stderr and sql errors in sql-runtime is possible 113 | * 2.0.1 2014-10-01 114 | update GLPlugin 115 | * 2.0 2014-07 116 | complete redesign, based on GLPlugin.pm 117 | * 1.5.20.5 2014-06-06 118 | allow mitigation for failed-jobs if no jobs were run 119 | * 1.5.20.4 2014-06-03 120 | add --commit which forces auto-commit on 121 | * 1.5.20.3 2014-04-01 122 | implement --negate old_level=new_level 123 | output also ok-messages for my-modes 124 | allow floating point numbers in thresholds 125 | * 1.5.20.2 2014-02-28 126 | bugfix in transactions. handles databases with auto-close 127 | * 1.5.20.1 2014-01-07 128 | update configure.ac 129 | add mode jobs-enabled (Thanks Thomas Gelf) 130 | * 1.5.20 2013-12-06 131 | handle wrong io_busy and cpu_busy values (hickups of 500% caused by counter overflows 132 | are replaced by the last valid value. if the error persists dirung 5 plugin runs 133 | the obviously wrong value is reported) 134 | * 1.5.19.3 2013-09-11 135 | fix an uninitialized state_desc 136 | * 1.5.19.2 2013-09-06 137 | parameter --notemp is now usable for many modes 138 | * 1.5.19.1 2013-05-27 139 | fixed a bug in batch-requests, which affected case sensitive colletion systems like SAP (Thanks Andreas Seemueller) 140 | * 1.5.19 2013-02-28 141 | rewrote database-free for sybase 142 | * 1.5.18.1 2013-01-22 143 | fixed a bug in sybase database-free 144 | * 1.5.18 2012-01-03 145 | added asciidoc 146 | * 1.5.17 2012-12-20 147 | fixed a bug in database-free for sybase (many thanks to siemens audiologische technik gmbh!!) 148 | * 1.5.16 2012-11-29 149 | fixed a bug in database-free (where the offline state of 1 db was propagated to some others) 150 | implemented all sorts of thresholds 151 | add mode sql-runtime 152 | * 1.5.15.2 2012-11-22 153 | catch generic error-messages 154 | * 1.5.15.1 2012-11-19 155 | catch a "insufficient-rights"-error-message 156 | * 1.5.15 2012-11-16 157 | add parameter mitigation (which can reduce errorlevels for offline databases or dbs which were never backed up) 158 | tracedebug ouputs a bit more information now 159 | * 1.5.14 2012-11-07 160 | database-free can now handle offline databases 161 | add --offlineok 162 | exclude dbs with recovery model simple from database-logbackup-age 163 | * 1.5.13 2012-10-25 164 | add failed-jobs 165 | add database-online 166 | * 1.5.12 2012-10-24 167 | add database-file-auto-growths (and database-logfile-auto-growths, database-datafile-auto-growths) 168 | add database-file-auto-shrinks (and database-logfile-auto-growths, database-datafile-auto-growths) 169 | add database-file-dbcc-shrinks 170 | * 1.5.11 2012-07-05 171 | add selects for cpu-busy to see the return values with -v 172 | add some enhancements writen by Pall Sigurdsson 173 | * 1.5.10 2012-06-27 174 | split database-backup-age to database-backup-age and database-logbackup-age (Thanks Simon Meggle) 175 | fix warnings for newer Perl versions 176 | fix cpu-busy & io-busy 177 | * 1.5.9.3 2012-04-12 178 | fix warnings for newer Perl versions (Thanks Stephan Classen) 179 | * 1.5.9.2 2012-03-15 180 | bugfix in timeout-alarm handling under windows 181 | * 1.5.9.1 2011-09-19 182 | fix a bug in --currentdb (with a "-" in the database name"). (Thanks Markus Stollwerk) 183 | single ticks around the --name argument under Windows CMD will be removed auto matically 184 | * 1.5.9 2011-08-12 185 | fix a bug in save_state for statefilesdirs with capial letters 186 | * 1.5.8.4 2011-06-29 187 | fix a bug in sybase chained transaction handling 188 | * 1.5.8.3 2011-06-03 189 | sites in an OMD (http://omdistro.org) environment have now private statefile directories 190 | fix a bug in extra-opts 191 | conection-time, connected-users, database-free and backup-age can be used with sybase ase 15.x servers 192 | * 1.5.8.2 2011-01-19 193 | output a nicer error message if a sqlrelay connection fails 194 | * 1.5.8.1 2011-01-03 195 | bugfix in --mode sql (numeric vs. regexp result) 196 | * 1.5.8 2010-12-20 197 | mode sql can now have a non-numerical output which is compared to a string/regexp 198 | new parameter --dbthresholds 199 | new mode report can be used to output only the bad news (short,long,html) 200 | * 1.5.7 2010-09-10 201 | fixed a bug in database-free (too much free space was calculated when more than one datafile of a database was on the same filesystem). (Thanks Juergen Essberger) 202 | new parameter extra-opts 203 | * 1.5.6 2010-08-12 204 | new parameter --dbthresholds. thresholds can now also be deposited in the table check_mssql_health_thresholds 205 | added --currentdb so that the plugin can connect to a non-default database 206 | --with-mymodules-dyn-dir on the commandline overrides the configure-option of the same name 207 | * 1.5.5 208 | backup-age is now an alias for the "official" database-backup-age 209 | catch the "can't change context to database" error 210 | --mode sqlcmd 211 | * 1.5.3 2009-11-02 212 | fixed a bug in mode database-free (results are more accurate now) 213 | added new mode backup-age which checks the age (in hours) of the last backup 214 | * 1.5.2 215 | fixed a bug where database names with special characters showed errors. (Thanks Hugh Ranalli) 216 | * 1.5.1 2009-05-26 217 | added --server which can be used instead of --hostname/port (Thanks Mark Monaghan) 218 | lots of fixes. sql server 2000 should now be fully supported. (Thanks Mereghetti Stefano) 219 | --warning/--critical were ignored for memory-pool-related modes (Thanks Mereghetti Stefano) 220 | * 1.5.0.2 2009-05-05 221 | fixed a bug which led to error messages when using the plugin with sql server 2000 (Thanks Christian Mies) 222 | fixed a bug so sql server 2000 can list-databases (Thanks Mereghetti Stefano) 223 | * 1.5.0.1 2009-04-29 224 | added a security advice to the README (Thanks Mathieu Barret) 225 | fixed a bug in database-free (Thanks Michael Luebben) 226 | fixed a typo (Thanks Bernd Staudacher) 227 | * 1.5 - 2009-03-20 228 | rewrote database-free so that unrestricted growth is taken into account (limit is disk) 229 | added support for SQLRelay 230 | * 1.2 - 2009-03-19 231 | added support for object_name <> SQLServer:... (this caused "unable to aquire"-errors sometimes) 232 | fixed a bug in the PNP template 233 | * 1.1 - 2009-03-11 234 | added modes: transactions, latches-wait-time, locks-waits, locks-timeouts, 235 | locks-deadlocks, sql-recompilations, total-server-memory 236 | beautified the PNP template 237 | fixed counter rollovers after database restart 238 | * 1.0 - 2009-03-10 239 | --------------- 240 | Initial release 241 | -------------------------------------------------------------------------------- /plugins-scripts/Classes/ASE/Component/DatabaseSubsystem.pm: -------------------------------------------------------------------------------- 1 | package Classes::ASE::Component::DatabaseSubsystem; 2 | our @ISA = qw(Monitoring::GLPlugin::DB::Item); 3 | use strict; 4 | 5 | sub filter_all { 6 | my $self = shift; 7 | } 8 | 9 | sub init { 10 | my $self = shift; 11 | my $sql = undef; 12 | my $allfilter = sub { 13 | my $o = shift; 14 | $self->filter_name($o->{name}) && 15 | ! (($self->opts->notemp && $o->is_temp) || ($self->opts->nooffline && ! $o->is_online)); 16 | }; 17 | if ($self->mode =~ /server::database::(createuser|listdatabases|databasefree)$/) { 18 | my $columns = ['name', 'state', 'rows_max_size', 'rows_used_size', 'log_max_size', 'log_used_size']; 19 | my $sql = q{ 20 | SELECT 21 | db_name(d.dbid) AS name, 22 | d.status2 AS state, 23 | SUM( 24 | CASE WHEN u.segmap != 4 25 | THEN u.size/1048576.*@@maxpagesize 26 | END 27 | ) AS data_size, 28 | SUM( 29 | CASE WHEN u.segmap != 4 30 | THEN size - curunreservedpgs(u.dbid, u.lstart, u.unreservedpgs) 31 | END 32 | ) / 1048576. * @@maxpagesize AS data_used, 33 | SUM( 34 | CASE WHEN u.segmap = 4 35 | THEN u.size/1048576.*@@maxpagesize 36 | END 37 | ) AS log_size, 38 | SUM( 39 | CASE WHEN u.segmap = 4 40 | THEN u.size/1048576.*@@maxpagesize 41 | END 42 | ) - 43 | lct_admin("logsegment_freepages", d.dbid) / 1048576. * @@maxpagesize AS log_used 44 | FROM 45 | master..sysdatabases d, master..sysusages u 46 | WHERE 47 | u.dbid = d.dbid AND d.status != 256 48 | GROUP BY 49 | d.dbid 50 | ORDER BY 51 | db_name(d.dbid) 52 | }; 53 | $self->get_db_tables([ 54 | ['databases', $sql, 'Classes::ASE::Component::DatabaseSubsystem::Database', $allfilter, $columns], 55 | ]); 56 | @{$self->{databases}} = reverse sort {$a->{name} cmp $b->{name}} @{$self->{databases}}; 57 | } elsif ($self->mode =~ /server::database::online/) { 58 | my $columns = ['name', 'state', 'state_desc', 'collation_name']; 59 | $sql = q{ 60 | SELECT name, state, state_desc, collation_name FROM master.sys.databases 61 | }; 62 | $self->get_db_tables([ 63 | ['databases', $sql, 'Classes::ASE::Component::DatabaseSubsystem::Database', $allfilter, $columns], 64 | ]); 65 | @{$self->{databases}} = reverse sort {$a->{name} cmp $b->{name}} @{$self->{databases}}; 66 | } elsif ($self->mode =~ /server::database::.*backupage/) { 67 | my $columns = ['name', 'id']; 68 | $sql = q{ 69 | SELECT name, dbid FROM master..sysdatabases 70 | }; 71 | $self->get_db_tables([ 72 | ['databases', $sql, 'Classes::ASE::Component::DatabaseSubsystem::DatabaseStub', $allfilter, $columns], 73 | ]); 74 | foreach (@{$self->{databases}}) { 75 | bless $_, 'Classes::ASE::Component::DatabaseSubsystem::Database'; 76 | $_->finish(); 77 | } 78 | } else { 79 | $self->no_such_mode(); 80 | } 81 | } 82 | 83 | 84 | package Classes::ASE::Component::DatabaseSubsystem::DatabaseStub; 85 | our @ISA = qw(Classes::ASE::Component::DatabaseSubsystem::Database); 86 | use strict; 87 | 88 | sub finish { 89 | my $self = shift; 90 | my $sql = sprintf q{ 91 | DBCC TRACEON(3604) 92 | DBCC DBTABLE("%s") 93 | }, $self->{name}; 94 | my @dbccresult = $self->fetchall_array($sql); 95 | foreach (@dbccresult) { 96 | #dbt_backup_start: 0x1686303d8 (dtdays=40599, dttime=7316475) Feb 27 2011 6:46:28:250AM 97 | if (/dbt_backup_start: \w+\s+\(dtdays=0, dttime=0\) \(uninitialized\)/) { 98 | # never backed up 99 | last; 100 | } elsif (/dbt_backup_start: \w+\s+\(dtdays=\d+, dttime=\d+\)\s+(\w+)\s+(\d+)\s+(\d+)\s+(\d+):(\d+):(\d+):\d+([AP])/) { 101 | require Time::Local; 102 | my %months = ("Jan" => 0, "Feb" => 1, "Mar" => 2, "Apr" => 3, "May" => 4, "Jun" => 5, "Jul" => 6, "Aug" => 7, "Sep" => 8, "Oct" => 9, "Nov" => 10, "Dec" => 11); 103 | $self->{backup_age} = (time - Time::Local::timelocal($6, $5, $4 + ($7 eq "A" ? 0 : 12), $2, $months{$1}, $3 - 1900)) / 3600; 104 | $self->{backup_duration} = 0; 105 | last; 106 | } 107 | } 108 | # to keep compatibility with mssql. recovery_model=3=simple will be skipped later 109 | $self->{recovery_model} = 0; 110 | } 111 | 112 | package Classes::ASE::Component::DatabaseSubsystem::Database; 113 | our @ISA = qw(Monitoring::GLPlugin::DB::TableItem); 114 | use strict; 115 | 116 | sub finish { 117 | my $self = shift; 118 | if ($self->mode =~ /server::database::databasefree$/) { 119 | $self->{log_max_size} = 0 if ! defined $self->{log_max_size}; 120 | $self->{log_used_size} = 0 if ! defined $self->{log_used_size}; 121 | $self->{rows_max_size} *= 1024*1024; 122 | $self->{rows_used_size} *= 1024*1024; 123 | $self->{log_max_size} *= 1024*1024; 124 | $self->{log_used_size} *= 1024*1024; 125 | $self->{rows_used_pct} = 100 * $self->{rows_used_size} / $self->{rows_max_size}; 126 | $self->{log_used_pct} = $self->{log_used_size} ? 100 * $self->{log_used_size} / $self->{log_max_size} : 0; 127 | $self->{rows_free_size} = $self->{rows_max_size} - $self->{rows_used_size}; 128 | $self->{log_free_size} = $self->{log_max_size} - $self->{log_used_size}; 129 | } 130 | } 131 | 132 | sub is_backup_node { 133 | my $self = shift; 134 | # to be done 135 | return 0; 136 | } 137 | 138 | sub is_online { 139 | my $self = shift; 140 | return 0 if $self->{messages}->{critical} && grep /is offline/, @{$self->{messages}->{critical}}; 141 | # 0x0010 offline 142 | # 0x0020 offline until recovery completes 143 | return $self->{state} & 0x0030 ? 0 : 1; 144 | } 145 | 146 | sub is_problematic { 147 | my $self = shift; 148 | if ($self->{messages}->{critical}) { 149 | my $error = join(", ", @{$self->{messages}->{critical}}); 150 | if ($error =~ /Message String: ([\w ]+)/) { 151 | return $1; 152 | } else { 153 | return $error; 154 | } 155 | } else { 156 | return 0; 157 | } 158 | } 159 | 160 | sub is_readable { 161 | my $self = shift; 162 | return ($self->{messages}->{critical} && grep /is not able to access the database/i, @{$self->{messages}->{critical}}) ? 0 : 1; 163 | } 164 | 165 | sub is_temp { 166 | my $self = shift; 167 | return $self->{name} eq "tempdb" ? 1 : 0; 168 | } 169 | 170 | 171 | sub check { 172 | my $self = shift; 173 | if ($self->mode =~ /server::database::(listdatabases)$/) { 174 | printf "%s\n", $self->{name}; 175 | } elsif ($self->mode =~ /server::database::(databasefree)$/) { 176 | $self->override_opt("units", "%") if ! $self->opts->units; 177 | if (! $self->is_online) { 178 | # offlineok hat vorrang 179 | $self->override_opt("mitigation", $self->opts->offlineok ? 0 : $self->opts->mitigation ? $self->opts->mitigation : 1); 180 | $self->add_message($self->opts->mitigation, 181 | sprintf("database %s is not online", $self->{name}) 182 | ); 183 | } elsif (! $self->is_readable) { 184 | $self->add_message($self->opts->mitigation ? $self->opts->mitigation : 1, 185 | sprintf("insufficient privileges to access %s", $self->{name}) 186 | ); 187 | } elsif ($self->is_problematic) { 188 | $self->add_message($self->opts->mitigation ? $self->opts->mitigation : 1, 189 | sprintf("error accessing %s: %s", $self->{name}, $self->is_problematic) 190 | ); 191 | } else { 192 | foreach my $type (qw(rows log)) { 193 | next if ! defined $self->{$type."_max_size"}; # not every db has a separate log 194 | my $metric_pct = ($type eq "rows") ? 195 | 'db_'.lc $self->{name}.'_free_pct' : 'db_'.lc $self->{name}.'_log_free_pct'; 196 | my $metric_units = ($type eq "rows") ? 197 | 'db_'.lc $self->{name}.'_free' : 'db_'.lc $self->{name}.'_log_free'; 198 | my $factor = 1048576; # MB 199 | my $warning_units; 200 | my $critical_units; 201 | my $warning_pct; 202 | my $critical_pct; 203 | if ($self->opts->units ne "%") { 204 | if (uc $self->opts->units eq "GB") { 205 | $factor = 1024 * 1024 * 1024; 206 | } elsif (uc $self->opts->units eq "MB") { 207 | $factor = 1024 * 1024; 208 | } elsif (uc $self->opts->units eq "KB") { 209 | $factor = 1024; 210 | } 211 | } 212 | my $free_percent = 100 - $self->{$type."_used_pct"}; 213 | my $free_size = $self->{$type."_max_size"} - $self->{$type."_used_size"}; 214 | my $free_units = $free_size / $factor; 215 | if ($self->opts->units eq "%") { 216 | $self->set_thresholds(metric => $metric_pct, warning => "10:", critical => "5:"); 217 | ($warning_pct, $critical_pct) = ($self->get_thresholds(metric => $metric_pct)); 218 | ($warning_units, $critical_units) = map { 219 | $_ =~ s/://g; (($_ * $self->{$type."_max_size"} / 100) / $factor).":"; 220 | } map { my $tmp = $_; $tmp; } ($warning_pct, $critical_pct); # sonst schnippelt der von den originalen den : weg 221 | $self->set_thresholds(metric => $metric_units, warning => $warning_units, critical => $critical_units); 222 | $self->add_message($self->check_thresholds(metric => $metric_pct, value => $free_percent), 223 | sprintf("database %s has %.2f%s free %sspace left", $self->{name}, $free_percent, $self->opts->units, ($type eq "log" ? "log " : ""))); 224 | } else { 225 | $self->set_thresholds(metric => $metric_units, warning => "5:", critical => "10:"); 226 | ($warning_units, $critical_units) = ($self->get_thresholds(metric => $metric_units)); 227 | ($warning_pct, $critical_pct) = map { 228 | $_ =~ s/://g; (100 * ($_ * $factor) / $self->{$type."_max_size"}).":"; 229 | } map { my $tmp = $_; $tmp; } ($warning_units, $critical_units); 230 | $self->set_thresholds(metric => $metric_pct, warning => $warning_pct, critical => $critical_pct); 231 | $self->add_message($self->check_thresholds(metric => $metric_units, value => $free_units), 232 | sprintf("database %s has %.2f%s free %sspace left", $self->{name}, $free_units, $self->opts->units, ($type eq "log" ? "log " : ""))); 233 | } 234 | $self->add_perfdata( 235 | label => $metric_pct, 236 | value => $free_percent, 237 | places => 2, 238 | uom => '%', 239 | warning => $warning_pct, 240 | critical => $critical_pct, 241 | ); 242 | $self->add_perfdata( 243 | label => $metric_units, 244 | value => $free_size / $factor, 245 | uom => $self->opts->units eq "%" ? "MB" : $self->opts->units, 246 | places => 2, 247 | warning => $warning_units, 248 | critical => $critical_units, 249 | min => 0, 250 | max => $self->{$type."_max_size"} / $factor, 251 | ); 252 | } 253 | } 254 | } elsif ($self->mode =~ /server::database::online/) { 255 | if ($self->is_online) { 256 | if ($self->{collation_name}) { 257 | $self->add_ok( 258 | sprintf "%s is %s and accepting connections", $self->{name}, $self->{state_desc}); 259 | } else { 260 | $self->add_warning(sprintf "%s is %s but not accepting connections", 261 | $self->{name}, $self->{state_desc}); 262 | } 263 | } elsif ($self->{state_desc} =~ /^recover/i) { 264 | $self->add_warning(sprintf "%s is %s", $self->{name}, $self->{state_desc}); 265 | } else { 266 | $self->add_critical(sprintf "%s is %s", $self->{name}, $self->{state_desc}); 267 | } 268 | } elsif ($self->mode =~ /server::database::.*backupage/) { 269 | if (! $self->is_backup_node) { 270 | $self->add_ok(sprintf "this is not the preferred replica for backups of %s", $self->{name}); 271 | return; 272 | } 273 | my $log = ""; 274 | if ($self->mode =~ /server::database::logbackupage/) { 275 | $log = "log of "; 276 | } 277 | if ($self->mode =~ /server::database::logbackupage/ && $self->{recovery_model} == 3) { 278 | $self->add_ok(sprintf "%s has no logs", $self->{name}); 279 | } else { 280 | $self->set_thresholds(metric => $self->{name}.'_bck_age', warning => 48, critical => 72); 281 | if (! defined $self->{backup_age}) { 282 | $self->add_message(defined $self->opts->mitigation() ? $self->opts->mitigation() : 2, 283 | sprintf "%s%s was never backed up", $log, $self->{name}); 284 | $self->{backup_age} = 0; 285 | $self->{backup_duration} = 0; 286 | } else { 287 | $self->add_message( 288 | $self->check_thresholds(metric => $self->{name}.'_bck_age', value => $self->{backup_age}), 289 | sprintf "%s%s was backed up %dh ago", $log, $self->{name}, $self->{backup_age}); 290 | } 291 | $self->add_perfdata( 292 | label => $self->{name}.'_bck_age', 293 | value => $self->{backup_age}, 294 | ); 295 | $self->add_perfdata( 296 | label => $self->{name}.'_bck_time', 297 | value => $self->{backup_duration}, 298 | ); 299 | } 300 | } 301 | } 302 | 303 | 304 | -------------------------------------------------------------------------------- /plugins-scripts/check_mssql_health.pl: -------------------------------------------------------------------------------- 1 | #! /usr/bin/perl 2 | 3 | use strict; 4 | 5 | eval { 6 | if ( ! grep /BEGIN/, keys %Monitoring::GLPlugin::) { 7 | require Monitoring::GLPlugin; 8 | require Monitoring::GLPlugin::DB; 9 | } 10 | }; 11 | if ($@) { 12 | printf "UNKNOWN - module Monitoring::GLPlugin was not found. Either build a standalone version of this plugin or set PERL5LIB\n"; 13 | printf "%s\n", $@; 14 | exit 3; 15 | } 16 | 17 | my $plugin = Classes::Device->new( 18 | shortname => '', 19 | usage => '%s [-v] [-t ] '. 20 | '--hostname= [--port ] '. 21 | '--username= --password= '. 22 | '--mode= '. 23 | '...', 24 | version => '$Revision: #PACKAGE_VERSION# $', 25 | blurb => 'This plugin checks microsoft sql servers ', 26 | url => 'http://labs.consol.de/nagios/check_mssql_health', 27 | timeout => 60, 28 | ); 29 | $plugin->add_db_modes(); 30 | $plugin->add_mode( 31 | internal => 'server::uptime', 32 | spec => 'uptime', 33 | alias => undef, 34 | help => 'The time since the server started', 35 | ); 36 | $plugin->add_mode( 37 | internal => 'server::cpubusy', 38 | spec => 'cpu-busy', 39 | alias => undef, 40 | help => 'Cpu busy in percent', 41 | ); 42 | $plugin->add_mode( 43 | internal => 'server::iobusy', 44 | spec => 'io-busy', 45 | alias => undef, 46 | help => 'IO busy in percent', 47 | ); 48 | $plugin->add_mode( 49 | internal => 'server::fullscans', 50 | spec => 'full-scans', 51 | alias => undef, 52 | help => 'Full table scans per second', 53 | ); 54 | $plugin->add_mode( 55 | internal => 'server::connectedusers', 56 | spec => 'connected-users', 57 | alias => undef, 58 | help => 'Number of currently connected users', 59 | ); 60 | $plugin->add_mode( 61 | internal => 'server::database::transactions', 62 | spec => 'transactions', 63 | alias => undef, 64 | help => 'Transactions per second (per database)', 65 | ); 66 | $plugin->add_mode( 67 | internal => 'server::batchrequests', 68 | spec => 'batch-requests', 69 | alias => undef, 70 | help => 'Batch requests per second', 71 | ); 72 | $plugin->add_mode( 73 | internal => 'server::latch::waits', 74 | spec => 'latches-waits', 75 | alias => undef, 76 | help => 'Number of latch requests that could not be granted immediately', 77 | ); 78 | $plugin->add_mode( 79 | internal => 'server::latch::waittime', 80 | spec => 'latches-wait-time', 81 | alias => undef, 82 | help => 'Average time for a latch to wait before the request is met', 83 | ); 84 | $plugin->add_mode( 85 | internal => 'server::memorypool::lock::waits', 86 | spec => 'locks-waits', 87 | alias => undef, 88 | help => 'The number of locks per second that had to wait', 89 | ); 90 | $plugin->add_mode( 91 | internal => 'server::memorypool::lock::timeouts', 92 | spec => 'locks-timeouts', 93 | alias => undef, 94 | help => 'The number of locks per second that timed out', 95 | ); 96 | $plugin->add_mode( 97 | internal => 'server::memorypool::lock::timeoutsgt0', 98 | spec => 'locks-timeouts-greater-0s', 99 | alias => undef, 100 | help => 'The number of locks per second where timeout is greater than 0', 101 | ); 102 | $plugin->add_mode( 103 | internal => 'server::memorypool::lock::deadlocks', 104 | spec => 'locks-deadlocks', 105 | alias => undef, 106 | help => 'The number of deadlocks per second', 107 | ); 108 | $plugin->add_mode( 109 | internal => 'server::sql::recompilations', 110 | spec => 'sql-recompilations', 111 | alias => undef, 112 | help => 'Re-Compilations per second', 113 | ); 114 | $plugin->add_mode( 115 | internal => 'server::sql::initcompilations', 116 | spec => 'sql-initcompilations', 117 | alias => undef, 118 | help => 'Initial compilations per second', 119 | ); 120 | $plugin->add_mode( 121 | internal => 'server::totalmemory', 122 | spec => 'total-server-memory', 123 | alias => undef, 124 | help => 'The amount of memory that SQL Server has allocated to it', 125 | ); 126 | $plugin->add_mode( 127 | internal => 'server::memorypool::buffercache::hitratio', 128 | spec => 'mem-pool-data-buffer-hit-ratio', 129 | alias => ['buffer-cache-hit-ratio'], 130 | help => 'Data Buffer Cache Hit Ratio', 131 | ); 132 | $plugin->add_mode( 133 | internal => 'server::memorypool::buffercache::lazywrites', 134 | spec => 'lazy-writes', 135 | alias => undef, 136 | help => 'Lazy writes per second', 137 | ); 138 | $plugin->add_mode( 139 | internal => 'server::memorypool::buffercache::pagelifeexpectancy', 140 | spec => 'page-life-expectancy', 141 | alias => undef, 142 | help => 'Seconds a page is kept in memory before being flushed', 143 | ); 144 | $plugin->add_mode( 145 | internal => 'server::memorypool::buffercache::freeliststalls', 146 | spec => 'free-list-stalls', 147 | alias => undef, 148 | help => 'Requests per second that had to wait for a free page', 149 | ); 150 | $plugin->add_mode( 151 | internal => 'server::memorypool::buffercache::checkpointpages', 152 | spec => 'checkpoint-pages', 153 | alias => undef, 154 | help => 'Dirty pages flushed to disk per second. (usually by a checkpoint)', 155 | ); 156 | $plugin->add_mode( 157 | internal => 'server::database::online', 158 | spec => 'database-online', 159 | alias => undef, 160 | help => 'Check if a database is online and accepting connections', 161 | ); 162 | $plugin->add_mode( 163 | internal => 'server::database::free', 164 | spec => 'database-free', 165 | alias => undef, 166 | help => 'Free space in database', 167 | ); 168 | $plugin->add_mode( 169 | internal => 'server::database::datafree', 170 | spec => 'database-data-free', 171 | alias => undef, 172 | help => 'Free (data) space in database', 173 | ); 174 | $plugin->add_mode( 175 | internal => 'server::database::logfree', 176 | spec => 'database-log-free', 177 | alias => undef, 178 | help => 'Free (transaction log) space in database', 179 | ); 180 | $plugin->add_mode( 181 | internal => 'server::database::free::details', 182 | spec => 'database-free-details', 183 | alias => undef, 184 | help => 'Free space in database and filegroups', 185 | ); 186 | $plugin->add_mode( 187 | internal => 'server::database::datafree::details', 188 | spec => 'database-data-free-details', 189 | alias => undef, 190 | help => 'Free (data) space in database and filegroups', 191 | ); 192 | $plugin->add_mode( 193 | internal => 'server::database::logfree::details', 194 | spec => 'database-log-free-details', 195 | alias => undef, 196 | help => 'Free (transaction log) space in database and filegroups', 197 | ); 198 | $plugin->add_mode( 199 | internal => 'server::database::filegroup::free', 200 | spec => 'database-filegroup-free', 201 | alias => undef, 202 | help => 'Free space in database filegroups', 203 | ); 204 | $plugin->add_mode( 205 | internal => 'server::database::file::free', 206 | spec => 'database-file-free', 207 | alias => undef, 208 | help => 'Free space in database files', 209 | ); 210 | $plugin->add_mode( 211 | internal => 'server::database::size', 212 | spec => 'database-size', 213 | alias => undef, 214 | help => 'Size of a database', 215 | ); 216 | $plugin->add_mode( 217 | internal => 'server::database::backupage', 218 | spec => 'database-backup-age', 219 | alias => ['backup-age'], 220 | help => 'Elapsed time (in hours) since a database was last backed up', 221 | ); 222 | $plugin->add_mode( 223 | internal => 'server::database::backupage::full', 224 | spec => 'database-full-backup-age', 225 | alias => undef, 226 | help => 'Elapsed time (in hours) since a database was last fully backed up', 227 | ); 228 | $plugin->add_mode( 229 | internal => 'server::database::backupage::differential', 230 | spec => 'database-differential-backup-age', 231 | alias => undef, 232 | help => 'Elapsed time (in hours) since a database was last differentially backed up', 233 | ); 234 | $plugin->add_mode( 235 | internal => 'server::database::logbackupage', 236 | spec => 'database-logbackup-age', 237 | alias => ['logbackup-age'], 238 | help => 'Elapsed time (in hours) since a database transaction log was last backed up', 239 | ); 240 | $plugin->add_mode( 241 | internal => 'server::database::autogrowths::file', 242 | spec => 'database-file-auto-growths', 243 | alias => undef, 244 | help => 'The number of File Auto Grow events (either data or log) in the last minutes (use --lookback)', 245 | ); 246 | $plugin->add_mode( 247 | internal => 'server::database::autogrowths::logfile', 248 | spec => 'database-logfile-auto-growths', 249 | alias => undef, 250 | help => 'The number of Log File Auto Grow events in the last minutes (use --lookback)', 251 | ); 252 | $plugin->add_mode( 253 | internal => 'server::database::autogrowths::datafile', 254 | spec => 'database-datafile-auto-growths', 255 | alias => undef, 256 | help => 'The number of Data File Auto Grow events in the last minutes (use --lookback)', 257 | ); 258 | $plugin->add_mode( 259 | internal => 'server::database::autoshrinks::file', 260 | spec => 'database-file-auto-shrinks', 261 | alias => undef, 262 | help => 'The number of File Auto Shrink events (either data or log) in the last minutes (use --lookback)', 263 | ); 264 | $plugin->add_mode( 265 | internal => 'server::database::autoshrinks::logfile', 266 | spec => 'database-logfile-auto-shrinks', 267 | alias => undef, 268 | help => 'The number of Log File Auto Shrink events in the last minutes (use --lookback)', 269 | ); 270 | $plugin->add_mode( 271 | internal => 'server::database::autoshrinks::datafile', 272 | spec => 'database-datafile-auto-shrinks', 273 | alias => undef, 274 | help => 'The number of Data File Auto Shrink events in the last minutes (use --lookback)', 275 | ); 276 | $plugin->add_mode( 277 | internal => 'server::database::dbccshrinks::file', 278 | spec => 'database-file-dbcc-shrinks', 279 | alias => undef, 280 | help => 'The number of DBCC File Shrink events (either data or log) in the last minutes (use --lookback)', 281 | ); 282 | $plugin->add_mode( 283 | internal => 'server::availabilitygroup::status', 284 | spec => 'availability-group-health', 285 | alias => undef, 286 | help => 'Checks the health status of availability groups', 287 | ); 288 | $plugin->add_mode( 289 | internal => 'server::jobs::failed', 290 | spec => 'failed-jobs', 291 | alias => undef, 292 | help => 'The jobs which did not exit successful in the last minutes (use --lookback)', 293 | ); 294 | $plugin->add_mode( 295 | internal => 'server::jobs::enabled', 296 | spec => 'jobs-enabled', 297 | alias => undef, 298 | help => 'The jobs which are not enabled (scheduled)', 299 | ); 300 | $plugin->add_mode( 301 | internal => 'server::database::createuser', 302 | spec => 'create-monitoring-user', 303 | alias => undef, 304 | help => 'convenience function which creates a monitoring user', 305 | ); 306 | $plugin->add_mode( 307 | internal => 'server::database::deleteuser', 308 | spec => 'delete-monitoring-user', 309 | alias => undef, 310 | help => 'convenience function which deletes a monitoring user', 311 | ); 312 | $plugin->add_mode( 313 | internal => 'server::database::list', 314 | spec => 'list-databases', 315 | alias => undef, 316 | help => 'convenience function which lists all databases', 317 | ); 318 | $plugin->add_mode( 319 | internal => 'server::database::file::list', 320 | spec => 'list-database-files', 321 | alias => undef, 322 | help => 'convenience function which lists all datafiles', 323 | ); 324 | $plugin->add_mode( 325 | internal => 'server::database::filegroup::list', 326 | spec => 'list-database-filegroups', 327 | alias => undef, 328 | help => 'convenience function which lists all data file groups', 329 | ); 330 | $plugin->add_mode( 331 | internal => 'server::memorypool::lock::listlocks', 332 | spec => 'list-locks', 333 | alias => undef, 334 | help => 'convenience function which lists all locks', 335 | ); 336 | $plugin->add_mode( 337 | internal => 'server::jobs::listjobs', 338 | spec => 'list-jobs', 339 | alias => undef, 340 | help => 'convenience function which lists all jobs', 341 | ); 342 | $plugin->add_mode( 343 | internal => 'server::aps::component::failed', 344 | spec => 'aps-failed-components', 345 | alias => undef, 346 | help => 'check faulty components (Microsoft Analytics Platform only)', 347 | ); 348 | $plugin->add_mode( 349 | internal => 'server::aps::alert::active', 350 | spec => 'aps-alerts', 351 | alias => undef, 352 | help => 'check for severe alerts (Microsoft Analytics Platform only)', 353 | ); 354 | $plugin->add_mode( 355 | internal => 'server::aps::disk::free', 356 | spec => 'aps-disk-free', 357 | alias => undef, 358 | help => 'check free disk space (Microsoft Analytics Platform only)', 359 | ); 360 | $plugin->add_arg( 361 | spec => 'hostname=s', 362 | help => "--hostname 363 | the database server", 364 | required => 0, 365 | ); 366 | $plugin->add_arg( 367 | spec => 'username=s', 368 | help => "--username 369 | the mssql user", 370 | required => 0, 371 | decode => "rfc3986", 372 | ); 373 | $plugin->add_arg( 374 | spec => 'password=s', 375 | help => "--password 376 | the mssql user's password", 377 | required => 0, 378 | decode => "rfc3986", 379 | ); 380 | $plugin->add_arg( 381 | spec => 'port=i', 382 | default => 1433, 383 | help => "--port 384 | the database server's port", 385 | required => 0, 386 | ); 387 | $plugin->add_arg( 388 | spec => 'server=s', 389 | help => "--server 390 | use a section in freetds.conf instead of hostname/port", 391 | required => 0, 392 | ); 393 | $plugin->add_arg( 394 | spec => 'currentdb=s', 395 | help => "--currentdb 396 | the name of a database which is used as the current database 397 | for the connection. (don't use this parameter unless you 398 | know what you're doing)", 399 | required => 0, 400 | ); 401 | $plugin->add_arg( 402 | spec => 'offlineok', 403 | help => "--offlineok 404 | if mode database-free finds a database which is currently offline, 405 | a WARNING is issued. If you don't want this and if offline databases 406 | are perfectly ok for you, then add --offlineok. You will get OK instead.", 407 | required => 0, 408 | ); 409 | $plugin->add_arg( 410 | spec => 'nooffline', 411 | help => "--nooffline 412 | skip the offline databases", 413 | required => 0,); 414 | $plugin->add_arg( 415 | spec => 'check-all-replicas', 416 | help => "--check-all-replicas 417 | In an Always On setup the backup the default is to run backup checks 418 | only on the preferred replica. 419 | For secondary replicas the backup checks return OK by default. Use this flag 420 | to check them as well for backup problems.", 421 | required => 0, 422 | ); 423 | 424 | $plugin->add_db_args(); 425 | $plugin->add_default_args(); 426 | 427 | $plugin->getopts(); 428 | $plugin->classify(); 429 | $plugin->validate_args(); 430 | 431 | 432 | if (! $plugin->check_messages()) { 433 | $plugin->init(); 434 | if (! $plugin->check_messages()) { 435 | $plugin->add_ok($plugin->get_summary()) 436 | if $plugin->get_summary(); 437 | $plugin->add_ok($plugin->get_extendedinfo(" ")) 438 | if $plugin->get_extendedinfo(); 439 | } 440 | } else { 441 | # $plugin->add_critical('wrong device'); 442 | } 443 | my ($code, $message) = $plugin->opts->multiline ? 444 | $plugin->check_messages(join => "\n", join_all => ', ') : 445 | $plugin->check_messages(join => ', ', join_all => ', '); 446 | $message .= sprintf "\n%s\n", $plugin->get_info("\n") 447 | if $plugin->opts->verbose >= 1; 448 | #printf "%s\n", Data::Dumper::Dumper($plugin); 449 | $plugin->nagios_exit($code, $message); 450 | 451 | 452 | -------------------------------------------------------------------------------- /install-sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # install - install a program, script, or datafile 3 | 4 | scriptversion=2011-11-20.07; # UTC 5 | 6 | # This originates from X11R5 (mit/util/scripts/install.sh), which was 7 | # later released in X11R6 (xc/config/util/install.sh) with the 8 | # following copyright and license. 9 | # 10 | # Copyright (C) 1994 X Consortium 11 | # 12 | # Permission is hereby granted, free of charge, to any person obtaining a copy 13 | # of this software and associated documentation files (the "Software"), to 14 | # deal in the Software without restriction, including without limitation the 15 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 16 | # sell copies of the Software, and to permit persons to whom the Software is 17 | # furnished to do so, subject to the following conditions: 18 | # 19 | # The above copyright notice and this permission notice shall be included in 20 | # all copies or substantial portions of the Software. 21 | # 22 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 26 | # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- 27 | # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 | # 29 | # Except as contained in this notice, the name of the X Consortium shall not 30 | # be used in advertising or otherwise to promote the sale, use or other deal- 31 | # ings in this Software without prior written authorization from the X Consor- 32 | # tium. 33 | # 34 | # 35 | # FSF changes to this file are in the public domain. 36 | # 37 | # Calling this script install-sh is preferred over install.sh, to prevent 38 | # 'make' implicit rules from creating a file called install from it 39 | # when there is no Makefile. 40 | # 41 | # This script is compatible with the BSD install script, but was written 42 | # from scratch. 43 | 44 | nl=' 45 | ' 46 | IFS=" "" $nl" 47 | 48 | # set DOITPROG to echo to test this script 49 | 50 | # Don't use :- since 4.3BSD and earlier shells don't like it. 51 | doit=${DOITPROG-} 52 | if test -z "$doit"; then 53 | doit_exec=exec 54 | else 55 | doit_exec=$doit 56 | fi 57 | 58 | # Put in absolute file names if you don't have them in your path; 59 | # or use environment vars. 60 | 61 | chgrpprog=${CHGRPPROG-chgrp} 62 | chmodprog=${CHMODPROG-chmod} 63 | chownprog=${CHOWNPROG-chown} 64 | cmpprog=${CMPPROG-cmp} 65 | cpprog=${CPPROG-cp} 66 | mkdirprog=${MKDIRPROG-mkdir} 67 | mvprog=${MVPROG-mv} 68 | rmprog=${RMPROG-rm} 69 | stripprog=${STRIPPROG-strip} 70 | 71 | posix_glob='?' 72 | initialize_posix_glob=' 73 | test "$posix_glob" != "?" || { 74 | if (set -f) 2>/dev/null; then 75 | posix_glob= 76 | else 77 | posix_glob=: 78 | fi 79 | } 80 | ' 81 | 82 | posix_mkdir= 83 | 84 | # Desired mode of installed file. 85 | mode=0755 86 | 87 | chgrpcmd= 88 | chmodcmd=$chmodprog 89 | chowncmd= 90 | mvcmd=$mvprog 91 | rmcmd="$rmprog -f" 92 | stripcmd= 93 | 94 | src= 95 | dst= 96 | dir_arg= 97 | dst_arg= 98 | 99 | copy_on_change=false 100 | no_target_directory= 101 | 102 | usage="\ 103 | Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE 104 | or: $0 [OPTION]... SRCFILES... DIRECTORY 105 | or: $0 [OPTION]... -t DIRECTORY SRCFILES... 106 | or: $0 [OPTION]... -d DIRECTORIES... 107 | 108 | In the 1st form, copy SRCFILE to DSTFILE. 109 | In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. 110 | In the 4th, create DIRECTORIES. 111 | 112 | Options: 113 | --help display this help and exit. 114 | --version display version info and exit. 115 | 116 | -c (ignored) 117 | -C install only if different (preserve the last data modification time) 118 | -d create directories instead of installing files. 119 | -g GROUP $chgrpprog installed files to GROUP. 120 | -m MODE $chmodprog installed files to MODE. 121 | -o USER $chownprog installed files to USER. 122 | -s $stripprog installed files. 123 | -t DIRECTORY install into DIRECTORY. 124 | -T report an error if DSTFILE is a directory. 125 | 126 | Environment variables override the default commands: 127 | CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG 128 | RMPROG STRIPPROG 129 | " 130 | 131 | while test $# -ne 0; do 132 | case $1 in 133 | -c) ;; 134 | 135 | -C) copy_on_change=true;; 136 | 137 | -d) dir_arg=true;; 138 | 139 | -g) chgrpcmd="$chgrpprog $2" 140 | shift;; 141 | 142 | --help) echo "$usage"; exit $?;; 143 | 144 | -m) mode=$2 145 | case $mode in 146 | *' '* | *' '* | *' 147 | '* | *'*'* | *'?'* | *'['*) 148 | echo "$0: invalid mode: $mode" >&2 149 | exit 1;; 150 | esac 151 | shift;; 152 | 153 | -o) chowncmd="$chownprog $2" 154 | shift;; 155 | 156 | -s) stripcmd=$stripprog;; 157 | 158 | -t) dst_arg=$2 159 | # Protect names problematic for 'test' and other utilities. 160 | case $dst_arg in 161 | -* | [=\(\)!]) dst_arg=./$dst_arg;; 162 | esac 163 | shift;; 164 | 165 | -T) no_target_directory=true;; 166 | 167 | --version) echo "$0 $scriptversion"; exit $?;; 168 | 169 | --) shift 170 | break;; 171 | 172 | -*) echo "$0: invalid option: $1" >&2 173 | exit 1;; 174 | 175 | *) break;; 176 | esac 177 | shift 178 | done 179 | 180 | if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then 181 | # When -d is used, all remaining arguments are directories to create. 182 | # When -t is used, the destination is already specified. 183 | # Otherwise, the last argument is the destination. Remove it from $@. 184 | for arg 185 | do 186 | if test -n "$dst_arg"; then 187 | # $@ is not empty: it contains at least $arg. 188 | set fnord "$@" "$dst_arg" 189 | shift # fnord 190 | fi 191 | shift # arg 192 | dst_arg=$arg 193 | # Protect names problematic for 'test' and other utilities. 194 | case $dst_arg in 195 | -* | [=\(\)!]) dst_arg=./$dst_arg;; 196 | esac 197 | done 198 | fi 199 | 200 | if test $# -eq 0; then 201 | if test -z "$dir_arg"; then 202 | echo "$0: no input file specified." >&2 203 | exit 1 204 | fi 205 | # It's OK to call 'install-sh -d' without argument. 206 | # This can happen when creating conditional directories. 207 | exit 0 208 | fi 209 | 210 | if test -z "$dir_arg"; then 211 | do_exit='(exit $ret); exit $ret' 212 | trap "ret=129; $do_exit" 1 213 | trap "ret=130; $do_exit" 2 214 | trap "ret=141; $do_exit" 13 215 | trap "ret=143; $do_exit" 15 216 | 217 | # Set umask so as not to create temps with too-generous modes. 218 | # However, 'strip' requires both read and write access to temps. 219 | case $mode in 220 | # Optimize common cases. 221 | *644) cp_umask=133;; 222 | *755) cp_umask=22;; 223 | 224 | *[0-7]) 225 | if test -z "$stripcmd"; then 226 | u_plus_rw= 227 | else 228 | u_plus_rw='% 200' 229 | fi 230 | cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; 231 | *) 232 | if test -z "$stripcmd"; then 233 | u_plus_rw= 234 | else 235 | u_plus_rw=,u+rw 236 | fi 237 | cp_umask=$mode$u_plus_rw;; 238 | esac 239 | fi 240 | 241 | for src 242 | do 243 | # Protect names problematic for 'test' and other utilities. 244 | case $src in 245 | -* | [=\(\)!]) src=./$src;; 246 | esac 247 | 248 | if test -n "$dir_arg"; then 249 | dst=$src 250 | dstdir=$dst 251 | test -d "$dstdir" 252 | dstdir_status=$? 253 | else 254 | 255 | # Waiting for this to be detected by the "$cpprog $src $dsttmp" command 256 | # might cause directories to be created, which would be especially bad 257 | # if $src (and thus $dsttmp) contains '*'. 258 | if test ! -f "$src" && test ! -d "$src"; then 259 | echo "$0: $src does not exist." >&2 260 | exit 1 261 | fi 262 | 263 | if test -z "$dst_arg"; then 264 | echo "$0: no destination specified." >&2 265 | exit 1 266 | fi 267 | dst=$dst_arg 268 | 269 | # If destination is a directory, append the input filename; won't work 270 | # if double slashes aren't ignored. 271 | if test -d "$dst"; then 272 | if test -n "$no_target_directory"; then 273 | echo "$0: $dst_arg: Is a directory" >&2 274 | exit 1 275 | fi 276 | dstdir=$dst 277 | dst=$dstdir/`basename "$src"` 278 | dstdir_status=0 279 | else 280 | # Prefer dirname, but fall back on a substitute if dirname fails. 281 | dstdir=` 282 | (dirname "$dst") 2>/dev/null || 283 | expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ 284 | X"$dst" : 'X\(//\)[^/]' \| \ 285 | X"$dst" : 'X\(//\)$' \| \ 286 | X"$dst" : 'X\(/\)' \| . 2>/dev/null || 287 | echo X"$dst" | 288 | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ 289 | s//\1/ 290 | q 291 | } 292 | /^X\(\/\/\)[^/].*/{ 293 | s//\1/ 294 | q 295 | } 296 | /^X\(\/\/\)$/{ 297 | s//\1/ 298 | q 299 | } 300 | /^X\(\/\).*/{ 301 | s//\1/ 302 | q 303 | } 304 | s/.*/./; q' 305 | ` 306 | 307 | test -d "$dstdir" 308 | dstdir_status=$? 309 | fi 310 | fi 311 | 312 | obsolete_mkdir_used=false 313 | 314 | if test $dstdir_status != 0; then 315 | case $posix_mkdir in 316 | '') 317 | # Create intermediate dirs using mode 755 as modified by the umask. 318 | # This is like FreeBSD 'install' as of 1997-10-28. 319 | umask=`umask` 320 | case $stripcmd.$umask in 321 | # Optimize common cases. 322 | *[2367][2367]) mkdir_umask=$umask;; 323 | .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; 324 | 325 | *[0-7]) 326 | mkdir_umask=`expr $umask + 22 \ 327 | - $umask % 100 % 40 + $umask % 20 \ 328 | - $umask % 10 % 4 + $umask % 2 329 | `;; 330 | *) mkdir_umask=$umask,go-w;; 331 | esac 332 | 333 | # With -d, create the new directory with the user-specified mode. 334 | # Otherwise, rely on $mkdir_umask. 335 | if test -n "$dir_arg"; then 336 | mkdir_mode=-m$mode 337 | else 338 | mkdir_mode= 339 | fi 340 | 341 | posix_mkdir=false 342 | case $umask in 343 | *[123567][0-7][0-7]) 344 | # POSIX mkdir -p sets u+wx bits regardless of umask, which 345 | # is incompatible with FreeBSD 'install' when (umask & 300) != 0. 346 | ;; 347 | *) 348 | tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ 349 | trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 350 | 351 | if (umask $mkdir_umask && 352 | exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 353 | then 354 | if test -z "$dir_arg" || { 355 | # Check for POSIX incompatibilities with -m. 356 | # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or 357 | # other-writable bit of parent directory when it shouldn't. 358 | # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. 359 | ls_ld_tmpdir=`ls -ld "$tmpdir"` 360 | case $ls_ld_tmpdir in 361 | d????-?r-*) different_mode=700;; 362 | d????-?--*) different_mode=755;; 363 | *) false;; 364 | esac && 365 | $mkdirprog -m$different_mode -p -- "$tmpdir" && { 366 | ls_ld_tmpdir_1=`ls -ld "$tmpdir"` 367 | test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" 368 | } 369 | } 370 | then posix_mkdir=: 371 | fi 372 | rmdir "$tmpdir/d" "$tmpdir" 373 | else 374 | # Remove any dirs left behind by ancient mkdir implementations. 375 | rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null 376 | fi 377 | trap '' 0;; 378 | esac;; 379 | esac 380 | 381 | if 382 | $posix_mkdir && ( 383 | umask $mkdir_umask && 384 | $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" 385 | ) 386 | then : 387 | else 388 | 389 | # The umask is ridiculous, or mkdir does not conform to POSIX, 390 | # or it failed possibly due to a race condition. Create the 391 | # directory the slow way, step by step, checking for races as we go. 392 | 393 | case $dstdir in 394 | /*) prefix='/';; 395 | [-=\(\)!]*) prefix='./';; 396 | *) prefix='';; 397 | esac 398 | 399 | eval "$initialize_posix_glob" 400 | 401 | oIFS=$IFS 402 | IFS=/ 403 | $posix_glob set -f 404 | set fnord $dstdir 405 | shift 406 | $posix_glob set +f 407 | IFS=$oIFS 408 | 409 | prefixes= 410 | 411 | for d 412 | do 413 | test X"$d" = X && continue 414 | 415 | prefix=$prefix$d 416 | if test -d "$prefix"; then 417 | prefixes= 418 | else 419 | if $posix_mkdir; then 420 | (umask=$mkdir_umask && 421 | $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break 422 | # Don't fail if two instances are running concurrently. 423 | test -d "$prefix" || exit 1 424 | else 425 | case $prefix in 426 | *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; 427 | *) qprefix=$prefix;; 428 | esac 429 | prefixes="$prefixes '$qprefix'" 430 | fi 431 | fi 432 | prefix=$prefix/ 433 | done 434 | 435 | if test -n "$prefixes"; then 436 | # Don't fail if two instances are running concurrently. 437 | (umask $mkdir_umask && 438 | eval "\$doit_exec \$mkdirprog $prefixes") || 439 | test -d "$dstdir" || exit 1 440 | obsolete_mkdir_used=true 441 | fi 442 | fi 443 | fi 444 | 445 | if test -n "$dir_arg"; then 446 | { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && 447 | { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && 448 | { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || 449 | test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 450 | else 451 | 452 | # Make a couple of temp file names in the proper directory. 453 | dsttmp=$dstdir/_inst.$$_ 454 | rmtmp=$dstdir/_rm.$$_ 455 | 456 | # Trap to clean up those temp files at exit. 457 | trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 458 | 459 | # Copy the file name to the temp name. 460 | (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && 461 | 462 | # and set any options; do chmod last to preserve setuid bits. 463 | # 464 | # If any of these fail, we abort the whole thing. If we want to 465 | # ignore errors from any of these, just make sure not to ignore 466 | # errors from the above "$doit $cpprog $src $dsttmp" command. 467 | # 468 | { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && 469 | { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && 470 | { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && 471 | { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && 472 | 473 | # If -C, don't bother to copy if it wouldn't change the file. 474 | if $copy_on_change && 475 | old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && 476 | new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && 477 | 478 | eval "$initialize_posix_glob" && 479 | $posix_glob set -f && 480 | set X $old && old=:$2:$4:$5:$6 && 481 | set X $new && new=:$2:$4:$5:$6 && 482 | $posix_glob set +f && 483 | 484 | test "$old" = "$new" && 485 | $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 486 | then 487 | rm -f "$dsttmp" 488 | else 489 | # Rename the file to the real destination. 490 | $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || 491 | 492 | # The rename failed, perhaps because mv can't rename something else 493 | # to itself, or perhaps because mv is so ancient that it does not 494 | # support -f. 495 | { 496 | # Now remove or move aside any old file at destination location. 497 | # We try this two ways since rm can't unlink itself on some 498 | # systems and the destination file might be busy for other 499 | # reasons. In this case, the final cleanup might fail but the new 500 | # file should still install successfully. 501 | { 502 | test ! -f "$dst" || 503 | $doit $rmcmd -f "$dst" 2>/dev/null || 504 | { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && 505 | { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } 506 | } || 507 | { echo "$0: cannot unlink or rename $dst" >&2 508 | (exit 1); exit 1 509 | } 510 | } && 511 | 512 | # Now rename the file to the real destination. 513 | $doit $mvcmd "$dsttmp" "$dst" 514 | } 515 | fi || exit 1 516 | 517 | trap '' 0 518 | fi 519 | done 520 | 521 | # Local variables: 522 | # eval: (add-hook 'write-file-hooks 'time-stamp) 523 | # time-stamp-start: "scriptversion=" 524 | # time-stamp-format: "%:y-%02m-%02d.%02H" 525 | # time-stamp-time-zone: "UTC" 526 | # time-stamp-end: "; # UTC" 527 | # End: 528 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 5 | 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Library General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 19yy 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License 307 | along with this program; if not, write to the Free Software 308 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 309 | 310 | 311 | Also add information on how to contact you by electronic and paper mail. 312 | 313 | If the program is interactive, make it output a short notice like this 314 | when it starts in an interactive mode: 315 | 316 | Gnomovision version 69, Copyright (C) 19yy name of author 317 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 318 | This is free software, and you are welcome to redistribute it 319 | under certain conditions; type `show c' for details. 320 | 321 | The hypothetical commands `show w' and `show c' should show the appropriate 322 | parts of the General Public License. Of course, the commands you use may 323 | be called something other than `show w' and `show c'; they could even be 324 | mouse-clicks or menu items--whatever suits your program. 325 | 326 | You should also get your employer (if you work as a programmer) or your 327 | school, if any, to sign a "copyright disclaimer" for the program, if 328 | necessary. Here is a sample; alter the names: 329 | 330 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 331 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 332 | 333 | , 1 April 1989 334 | Ty Coon, President of Vice 335 | 336 | This General Public License does not permit incorporating your program into 337 | proprietary programs. If your program is a subroutine library, you may 338 | consider it more useful to permit linking proprietary applications with the 339 | library. If this is what you want to do, use the GNU Library General 340 | Public License instead of this License. 341 | -------------------------------------------------------------------------------- /plugins-scripts/Classes/MSSQL.pm: -------------------------------------------------------------------------------- 1 | package Classes::MSSQL; 2 | our @ISA = qw(Classes::Sybase); 3 | 4 | use strict; 5 | use Time::HiRes; 6 | use IO::File; 7 | use File::Copy 'cp'; 8 | use Data::Dumper; 9 | our $AUTOLOAD; 10 | 11 | 12 | sub init { 13 | my $self = shift; 14 | $self->set_variable("dbuser", $self->fetchrow_array( 15 | q{ SELECT SYSTEM_USER } 16 | )); 17 | $self->set_variable("servicename", $self->fetchrow_array( 18 | q{ SELECT @@SERVICENAME } 19 | )); 20 | if (lc $self->get_variable("servicename") ne 'mssqlserver') { 21 | # braucht man fuer abfragen von dm_os_performance_counters 22 | # object_name ist entweder "SQLServer:Buffer Node" oder z.b. "MSSQL$OASH:Buffer Node" 23 | $self->set_variable("servicename", 'MSSQL$'.$self->get_variable("servicename")); 24 | } else { 25 | $self->set_variable("servicename", 'SQLServer'); 26 | } 27 | $self->set_variable("ishadrenabled", $self->fetchrow_array( 28 | q{ SELECT CAST(COALESCE(SERVERPROPERTY('IsHadrEnabled'), 0) as int) } 29 | )); 30 | if ($self->mode =~ /^server::connectedusers/) { 31 | my $connectedusers; 32 | if ($self->get_variable("product") eq "ASE") { 33 | $connectedusers = $self->fetchrow_array(q{ 34 | SELECT 35 | COUNT(*) 36 | FROM 37 | master..sysprocesses 38 | WHERE 39 | hostprocess IS NOT NULL AND program_name != 'JS Agent' 40 | }); 41 | } else { 42 | # http://www.sqlservercentral.com/articles/System+Tables/66335/ 43 | # user processes start at 51 44 | $connectedusers = $self->fetchrow_array(q{ 45 | SELECT 46 | COUNT(*) 47 | FROM 48 | master..sysprocesses 49 | WHERE 50 | spid >= 51 51 | }); 52 | } 53 | if (! defined $connectedusers) { 54 | $self->add_unknown("unable to count connected users"); 55 | } else { 56 | $self->set_thresholds(warning => 50, critical => 80); 57 | $self->add_message($self->check_thresholds($connectedusers), 58 | sprintf "%d connected users", $connectedusers); 59 | $self->add_perfdata( 60 | label => "connected_users", 61 | value => $connectedusers 62 | ); 63 | } 64 | } elsif ($self->mode =~ /^server::cpubusy/) { 65 | if ($self->version_is_minimum("9.x")) { 66 | if (! defined ($self->{secs_busy} = $self->fetchrow_array(q{ 67 | SELECT ((@@CPU_BUSY * CAST(@@TIMETICKS AS FLOAT)) / 68 | (SELECT CAST(CPU_COUNT AS FLOAT) FROM sys.dm_os_sys_info) / 69 | 1000000) 70 | }))) { 71 | $self->add_unknown("got no cputime from dm_os_sys_info"); 72 | } else { 73 | $self->valdiff({ name => 'secs_busy' }, qw(secs_busy)); 74 | $self->{cpu_busy} = 100 * 75 | $self->{delta_secs_busy} / $self->{delta_timestamp}; 76 | $self->protect_value('cpu_busy', 'cpu_busy', 'percent'); 77 | } 78 | } else { 79 | my @monitor = $self->exec_sp_1hash(q{exec sp_monitor}); 80 | foreach (@monitor) { 81 | if ($_->[0] eq 'cpu_busy') { 82 | if ($_->[1] =~ /(\d+)%/) { 83 | $self->{cpu_busy} = $1; 84 | } 85 | } 86 | } 87 | self->requires_version('9') unless defined $self->{cpu_busy}; 88 | } 89 | if (! $self->check_messages()) { 90 | $self->set_thresholds(warning => 80, critical => 90); 91 | $self->add_message($self->check_thresholds($self->{cpu_busy}), 92 | sprintf "CPU busy %.2f%%", $self->{cpu_busy}); 93 | $self->add_perfdata( 94 | label => 'cpu_busy', 95 | value => $self->{cpu_busy}, 96 | uom => '%', 97 | ); 98 | } 99 | } elsif ($self->mode =~ /^server::iobusy/) { 100 | if ($self->version_is_minimum("9.x")) { 101 | if (! defined ($self->{secs_busy} = $self->fetchrow_array(q{ 102 | SELECT ((@@IO_BUSY * CAST(@@TIMETICKS AS FLOAT)) / 103 | (SELECT CAST(CPU_COUNT AS FLOAT) FROM sys.dm_os_sys_info) / 104 | 1000000) 105 | }))) { 106 | $self->add_unknown("got no iotime from dm_os_sys_info"); 107 | } else { 108 | $self->valdiff({ name => 'secs_busy' }, qw(secs_busy)); 109 | $self->{io_busy} = 100 * 110 | $self->{delta_secs_busy} / $self->{delta_timestamp}; 111 | $self->protect_value('io_busy', 'io_busy', 'percent'); 112 | } 113 | } else { 114 | my @monitor = $self->exec_sp_1hash(q{exec sp_monitor}); 115 | foreach (@monitor) { 116 | if ($_->[0] eq 'io_busy') { 117 | if ($_->[1] =~ /(\d+)%/) { 118 | $self->{io_busy} = $1; 119 | } 120 | } 121 | } 122 | self->requires_version('9') unless defined $self->{io_busy}; 123 | } 124 | if (! $self->check_messages()) { 125 | $self->set_thresholds(warning => 80, critical => 90); 126 | $self->add_message($self->check_thresholds($self->{io_busy}), 127 | sprintf "IO busy %.2f%%", $self->{io_busy}); 128 | $self->add_perfdata( 129 | label => 'io_busy', 130 | value => $self->{io_busy}, 131 | uom => '%', 132 | ); 133 | } 134 | } elsif ($self->mode =~ /^server::fullscans/) { 135 | $self->get_perf_counters([ 136 | ['full_scans', 'SQLServer:Access Methods', 'Full Scans/sec'], 137 | ]); 138 | return if $self->check_messages(); 139 | $self->set_thresholds( 140 | metric => 'full_scans_per_sec', 141 | warning => 100, critical => 500); 142 | $self->add_message( 143 | $self->check_thresholds( 144 | metric => 'full_scans_per_sec', 145 | value => $self->{full_scans_per_sec}), 146 | sprintf "%.2f full table scans / sec", $self->{full_scans_per_sec}); 147 | $self->add_perfdata( 148 | label => 'full_scans_per_sec', 149 | value => $self->{full_scans_per_sec}, 150 | ); 151 | } elsif ($self->mode =~ /^server::latch::waittime/) { 152 | $self->get_perf_counters([ 153 | ['latch_avg_wait_time', 'SQLServer:Latches', 'Average Latch Wait Time (ms)'], 154 | ['latch_wait_time_base', 'SQLServer:Latches', 'Average Latch Wait Time Base'], 155 | ]); 156 | return if $self->check_messages(); 157 | $self->{latch_avg_wait_time} = $self->{latch_avg_wait_time} / $self->{latch_wait_time_base}; 158 | $self->set_thresholds( 159 | metric => 'latch_avg_wait_time', 160 | warning => 1, critical => 5); 161 | $self->add_message( 162 | $self->check_thresholds( 163 | metric => 'latch_avg_wait_time', 164 | value => $self->{latch_avg_wait_time}), 165 | sprintf "latches have to wait %.2f ms avg", $self->{latch_avg_wait_time}); 166 | $self->add_perfdata( 167 | label => 'latch_avg_wait_time', 168 | value => $self->{latch_avg_wait_time}, 169 | uom => 'ms', 170 | ); 171 | } elsif ($self->mode =~ /^server::latch::waits/) { 172 | $self->get_perf_counters([ 173 | ['latch_waits', 'SQLServer:Latches', 'Latch Waits/sec'], 174 | ]); 175 | return if $self->check_messages(); 176 | $self->set_thresholds( 177 | metric => 'latch_waits_per_sec', 178 | warning => 10, critical => 50); 179 | $self->add_message( 180 | $self->check_thresholds( 181 | metric => 'latch_waits_per_sec', 182 | value => $self->{latch_waits_per_sec}), 183 | sprintf "%.2f latches / sec have to wait", $self->{latch_waits_per_sec}); 184 | $self->add_perfdata( 185 | label => 'latch_waits_per_sec', 186 | value => $self->{latch_waits_per_sec}, 187 | ); 188 | } elsif ($self->mode =~ /^server::sql.*compilations/) { 189 | $self->get_perf_counters([ 190 | ['sql_recompilations', 'SQLServer:SQL Statistics', 'SQL Re-Compilations/sec'], 191 | ['sql_compilations', 'SQLServer:SQL Statistics', 'SQL Compilations/sec'], 192 | ]); 193 | return if $self->check_messages(); 194 | # http://www.sqlmag.com/Articles/ArticleID/40925/pg/3/3.html 195 | # http://www.grumpyolddba.co.uk/monitoring/Performance%20Counter%20Guidance%20-%20SQL%20Server.htm 196 | if ($self->mode =~ /^server::sql::recompilations/) { 197 | $self->set_thresholds( 198 | metric => 'sql_recompilations_per_sec', 199 | warning => 1, critical => 10); 200 | $self->add_message( 201 | $self->check_thresholds( 202 | metric => 'sql_recompilations_per_sec', 203 | value => $self->{sql_recompilations_per_sec}), 204 | sprintf "%.2f SQL recompilations / sec", $self->{sql_recompilations_per_sec}); 205 | $self->add_perfdata( 206 | label => 'sql_recompilations_per_sec', 207 | value => $self->{sql_recompilations_per_sec}, 208 | ); 209 | } else { # server::sql::initcompilations 210 | # ginge auch (weiter oben, mit sql_initcompilations im valdiff), birgt aber gefahren. warum? denksport 211 | # $self->{sql_initcompilations} = $self->{sql_compilations} - $self->{sql_recompilations}; 212 | # $self->protect_value("sql_initcompilations", "sql_initcompilations", "positive"); 213 | $self->{delta_sql_initcompilations} = $self->{delta_sql_compilations} - $self->{delta_sql_recompilations}; 214 | $self->{sql_initcompilations_per_sec} = $self->{delta_sql_initcompilations} / $self->{delta_timestamp}; 215 | $self->set_thresholds( 216 | metric => 'sql_initcompilations_per_sec', 217 | warning => 100, critical => 200); 218 | $self->add_message( 219 | $self->check_thresholds( 220 | metric => 'sql_initcompilations_per_sec', 221 | value => $self->{sql_initcompilations_per_sec}), 222 | sprintf "%.2f initial compilations / sec", $self->{sql_initcompilations_per_sec}); 223 | $self->add_perfdata( 224 | label => 'sql_initcompilations_per_sec', 225 | value => $self->{sql_initcompilations_per_sec}, 226 | ); 227 | } 228 | } elsif ($self->mode =~ /^server::batchrequests/) { 229 | $self->get_perf_counters([ 230 | ['batch_requests', 'SQLServer:SQL Statistics', 'Batch Requests/sec'], 231 | ]); 232 | return if $self->check_messages(); 233 | $self->set_thresholds( 234 | metric => 'batch_requests_per_sec', 235 | warning => 100, critical => 200); 236 | $self->add_message( 237 | $self->check_thresholds( 238 | metric => 'batch_requests_per_sec', 239 | value => $self->{batch_requests_per_sec}), 240 | sprintf "%.2f batch requests / sec", $self->{batch_requests_per_sec}); 241 | $self->add_perfdata( 242 | label => 'batch_requests_per_sec', 243 | value => $self->{batch_requests_per_sec}, 244 | ); 245 | } elsif ($self->mode =~ /^server::totalmemory/) { 246 | $self->get_perf_counters([ 247 | ['total_server_memory', 'SQLServer:Memory Manager', 'Total Server Memory (KB)'], 248 | ]); 249 | return if $self->check_messages(); 250 | my $warn = 1024*1024; 251 | my $crit = 1024*1024*5; 252 | my $factor = 1; 253 | if ($self->opts->units && lc $self->opts->units eq "mb") { 254 | $warn = 1024; 255 | $crit = 1024*5; 256 | $factor = 1024; 257 | } elsif ($self->opts->units && lc $self->opts->units eq "gb") { 258 | $warn = 1; 259 | $crit = 1*5; 260 | $factor = 1024*1024; 261 | } else { 262 | $self->override_opt("units", "kb"); 263 | } 264 | $self->{total_server_memory} /= $factor; 265 | $self->set_thresholds( 266 | metric => 'total_server_memory', 267 | warning => $warn, critical => $crit); 268 | $self->add_message( 269 | $self->check_thresholds( 270 | metric => 'total_server_memory', 271 | value => $self->{total_server_memory}), 272 | sprintf "total server memory %.2f%s", $self->{total_server_memory}, $self->opts->units); 273 | $self->add_perfdata( 274 | label => 'total_server_memory', 275 | value => $self->{total_server_memory}, 276 | uom => $self->opts->units, 277 | ); 278 | } elsif ($self->mode =~ /^server::memorypool/) { 279 | $self->analyze_and_check_memorypool_subsystem("Classes::MSSQL::Component::MemorypoolSubsystem"); 280 | $self->reduce_messages_short(); 281 | } elsif ($self->mode =~ /^server::database/) { 282 | $self->analyze_and_check_database_subsystem("Classes::MSSQL::Component::DatabaseSubsystem"); 283 | $self->reduce_messages_short(); 284 | } elsif ($self->mode =~ /^server::availabilitygroup/) { 285 | $self->analyze_and_check_avgroup_subsystem("Classes::MSSQL::Component::AvailabilitygroupSubsystem"); 286 | $self->reduce_messages_short(); 287 | } elsif ($self->mode =~ /^server::jobs/) { 288 | $self->analyze_and_check_job_subsystem("Classes::MSSQL::Component::JobSubsystem"); 289 | $self->reduce_messages_short(); 290 | } elsif ($self->mode =~ /^server::uptime/) { 291 | ($self->{starttime}, $self->{uptime}) = $self->fetchrow_array(q{ 292 | SELECT 293 | CONVERT(VARCHAR, sqlserver_start_time, 127) AS STARTUP_TIME_ISO8601, 294 | ROUND(DATEDIFF(SECOND, sqlserver_start_time, GETDATE()), 0) AS UPTIME_SECONDS 295 | FROM 296 | sys.dm_os_sys_info 297 | }); 298 | $self->set_thresholds( 299 | metric => 'uptime', 300 | warning => "900:", critical => "300:"); 301 | $self->add_message( 302 | $self->check_thresholds( 303 | metric => 'uptime', 304 | value => $self->{uptime}), 305 | sprintf "instance started at %s", $self->{starttime}); 306 | $self->add_perfdata( 307 | label => 'uptime', 308 | value => $self->{uptime}, 309 | ); 310 | } else { 311 | $self->no_such_mode(); 312 | } 313 | } 314 | 315 | sub get_perf_counters { 316 | my $self = shift; 317 | my $counters = shift; 318 | my @vars = (); 319 | foreach (@{$counters}) { 320 | my $var = $_->[0]; 321 | push(@vars, $_->[3] ? $var.'_'.$_->[3] : $var); 322 | my $object_name = $_->[1]; 323 | my $counter_name = $_->[2]; 324 | my $instance_name = $_->[3]; 325 | $self->{$var} = $self->get_perf_counter( 326 | $object_name, $counter_name, $instance_name 327 | ); 328 | $self->add_unknown(sprintf "unable to aquire counter data %s %s%s", 329 | $object_name, $counter_name, 330 | $instance_name ? " (".$instance_name.")" : "" 331 | ) if ! defined $self->{$var}; 332 | $self->valdiff({ name => $instance_name ? $var.'_'.$instance_name : $var }, $var) if $var; 333 | } 334 | } 335 | 336 | sub get_perf_counter { 337 | my $self = shift; 338 | my $object_name = shift; 339 | my $counter_name = shift; 340 | my $instance_name = shift; 341 | my $sql; 342 | if ($object_name =~ /SQLServer:(.*)/) { 343 | $object_name = $self->get_variable("servicename").':'.$1; 344 | } 345 | if ($self->version_is_minimum("9.x")) { 346 | $sql = q{ 347 | SELECT 348 | cntr_value 349 | FROM 350 | sys.dm_os_performance_counters 351 | WHERE 352 | counter_name = ? AND 353 | object_name = ? 354 | }; 355 | } else { 356 | $sql = q{ 357 | SELECT 358 | cntr_value 359 | FROM 360 | master.dbo.sysperfinfo 361 | WHERE 362 | counter_name = ? AND 363 | object_name = ? 364 | }; 365 | } 366 | if ($instance_name) { 367 | $sql .= " AND instance_name = ?"; 368 | return $self->fetchrow_array($sql, $counter_name, $object_name, $instance_name); 369 | } else { 370 | return $self->fetchrow_array($sql, $counter_name, $object_name); 371 | } 372 | } 373 | 374 | sub get_perf_counter_instance { 375 | my $self = shift; 376 | my $object_name = shift; 377 | my $counter_name = shift; 378 | my $instance_name = shift; 379 | if ($object_name =~ /SQLServer:(.*)/) { 380 | $object_name = $self->get_variable("servicename").':'.$1; 381 | } 382 | if ($self->version_is_minimum("9.x")) { 383 | return $self->fetchrow_array(q{ 384 | SELECT 385 | cntr_value 386 | FROM 387 | sys.dm_os_performance_counters 388 | WHERE 389 | counter_name = ? AND 390 | object_name = ? AND 391 | instance_name = ? 392 | }, $counter_name, $object_name, $instance_name); 393 | } else { 394 | return $self->fetchrow_array(q{ 395 | SELECT 396 | cntr_value 397 | FROM 398 | master.dbo.sysperfinfo 399 | WHERE 400 | counter_name = ? AND 401 | object_name = ? AND 402 | instance_name = ? 403 | }, $counter_name, $object_name, $instance_name); 404 | } 405 | } 406 | 407 | sub get_instance_names { 408 | my $self = shift; 409 | my $object_name = shift; 410 | if ($object_name =~ /SQLServer:(.*)/) { 411 | $object_name = $self->get_variable("servicename").':'.$1; 412 | } 413 | if ($self->version_is_minimum("9.x")) { 414 | return $self->fetchall_array(q{ 415 | SELECT 416 | DISTINCT instance_name 417 | FROM 418 | sys.dm_os_performance_counters 419 | WHERE 420 | object_name = ? 421 | }, $object_name); 422 | } else { 423 | return $self->fetchall_array(q{ 424 | SELECT 425 | DISTINCT instance_name 426 | FROM 427 | master.dbo.sysperfinfo 428 | WHERE 429 | object_name = ? 430 | }, $object_name); 431 | } 432 | } 433 | 434 | sub has_threshold_table { 435 | my $self = shift; 436 | if (! exists $self->{has_threshold_table}) { 437 | my $find_sql; 438 | if ($self->version_is_minimum("9.x")) { 439 | $find_sql = q{ 440 | SELECT name FROM sys.objects 441 | WHERE name = 'check_mssql_health_thresholds' 442 | }; 443 | } else { 444 | $find_sql = q{ 445 | SELECT name FROM sysobjects 446 | WHERE name = 'check_mssql_health_thresholds' 447 | }; 448 | } 449 | if ($self->{handle}->fetchrow_array($find_sql)) { 450 | $self->{has_threshold_table} = 'check_mssql_health_thresholds'; 451 | } else { 452 | $self->{has_threshold_table} = undef; 453 | } 454 | } 455 | return $self->{has_threshold_table}; 456 | } 457 | 458 | sub add_dbi_funcs { 459 | my $self = shift; 460 | $self->SUPER::add_dbi_funcs() if $self->SUPER::can('add_dbi_funcs'); 461 | { 462 | no strict 'refs'; 463 | *{'Monitoring::GLPlugin::DB::get_instance_names'} = \&{"Classes::MSSQL::get_instance_names"}; 464 | *{'Monitoring::GLPlugin::DB::get_perf_counters'} = \&{"Classes::MSSQL::get_perf_counters"}; 465 | *{'Monitoring::GLPlugin::DB::get_perf_counter'} = \&{"Classes::MSSQL::get_perf_counter"}; 466 | *{'Monitoring::GLPlugin::DB::get_perf_counter_instance'} = \&{"Classes::MSSQL::get_perf_counter_instance"}; 467 | } 468 | } 469 | 470 | sub compatibility_class { 471 | my $self = shift; 472 | # old extension packages inherit from DBD::MSSQL::Server 473 | # let DBD::MSSQL::Server inherit myself, so we can reach compatibility_methods 474 | { 475 | no strict 'refs'; 476 | *{'DBD::MSSQL::Server::new'} = sub {}; 477 | push(@DBD::MSSQL::Server::ISA, ref($self)); 478 | } 479 | } 480 | 481 | sub compatibility_methods { 482 | my $self = shift; 483 | if ($self->isa("DBD::MSSQL::Server")) { 484 | # a old-style extension was loaded 485 | $self->SUPER::compatibility_methods() if $self->SUPER::can('compatibility_methods'); 486 | } 487 | } 488 | 489 | __END__ 490 | 491 | RTM (no SP) SP1 SP2 SP3 SP4 492 | SQL Server 2014 12.00.2000.8 493 | (Hekaton, later SQL14) 494 | 495 | SQL Server 2012 11.00.2100.60 11.00.3000.0 11.00.5058.0 496 | (Denali) 497 | 498 | SQL Server 2008 R2 10.50.1600.1 10.50.2500.0 10.50.4000.0 499 | (Kilimanjaro) 10.51.2500.0 10.52.4000.0 500 | 501 | SQL Server 2008 10.00.1600.22 10.00.2531.0 10.00.4000.0 10.00.5500.0 502 | (Katmai) 503 | 504 | SQL Server 2005 9.00.1399.06 9.00.2047 9.00.3042 9.00.4035 9.00.5000 505 | (Yukon) 506 | 507 | SQL Server 2000 8.00.194 8.00.384 8.00.532 8.00.760 8.00.2039 508 | (Shiloh) 509 | 510 | SQL Server 7.0 7.00.623 7.00.699 7.00.842 7.00.961 7.00.1063 511 | (Shpinx) 512 | 513 | 514 | 515 | 516 | 517 | --------------------------------------------------------------------------------