From c22ee05c435f709b38dfb93b0f6d262af892ae01 Mon Sep 17 00:00:00 2001 From: qgarnier Date: Mon, 2 Oct 2023 09:44:39 +0100 Subject: [PATCH] (plugin) database::mongodb - add shards option (#4535) --- src/database/mongodb/custom/driver.pm | 4 +- .../mongodb/mode/collectionstatistics.pm | 173 +++++++---- src/database/mongodb/mode/connections.pm | 73 ++--- src/database/mongodb/mode/connectiontime.pm | 9 +- .../mongodb/mode/databasestatistics.pm | 273 ++++++++++++------ src/database/mongodb/mode/queries.pm | 61 ++-- .../mongodb/mode/replicationstatus.pm | 160 +++++----- src/database/mongodb/plugin.pm | 11 +- 8 files changed, 450 insertions(+), 314 deletions(-) diff --git a/src/database/mongodb/custom/driver.pm b/src/database/mongodb/custom/driver.pm index 3d6156069..3a019c577 100644 --- a/src/database/mongodb/custom/driver.pm +++ b/src/database/mongodb/custom/driver.pm @@ -81,7 +81,7 @@ sub check_options { $self->{password} = (defined($self->{option_results}->{password})) ? $self->{option_results}->{password} : ''; $self->{no_ssl} = (defined($self->{option_results}->{no_ssl})) ? 1 : 0; - if (!defined($self->{hostname}) || $self->{hostname} eq '') { + if ($self->{hostname} eq '') { $self->{output}->add_option_msg(short_msg => "Need to specify --hostname option."); $self->{output}->option_exit(); } @@ -227,7 +227,7 @@ Set timeout in seconds (Default: 10). =item B<--ssl-opt> -Set SSL Options (--ssl-opt="SSL_version => TLSv1" --ssl-opt="SSL_verify_mode => SSL_VERIFY_NONE"). +Set SSL Options (--ssl-opt="SSL_version => 'TLSv1'" --ssl-opt="SSL_verify_mode => SSL_VERIFY_NONE"). =item B<--no-ssl> diff --git a/src/database/mongodb/mode/collectionstatistics.pm b/src/database/mongodb/mode/collectionstatistics.pm index 86c1c0d15..81756f986 100644 --- a/src/database/mongodb/mode/collectionstatistics.pm +++ b/src/database/mongodb/mode/collectionstatistics.pm @@ -25,6 +25,42 @@ use base qw(centreon::plugins::templates::counter); use strict; use warnings; +sub custom_shard_perfdata { + my ($self, %options) = @_; + + $self->{output}->perfdata_add( + nlabel => $self->{nlabel}, + unit => $self->{instance_mode}->{option_results}->{unit}, + instances => [$self->{result_values}->{dbName}, $self->{result_values}->{collectionName}, $self->{result_values}->{shardName}], + value => $self->{result_values}->{ $self->{key_values}->[0]->{name} }, + warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{thlabel}), + critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{thlabel}), + min => 0 + ); +} + +sub long_output { + my ($self, %options) = @_; + + return "checking database '" . $options{instance_value}->{display} . "' "; +} + +sub prefix_output_collection { + my ($self, %options) = @_; + + return "collection '" . $options{instance} . "' "; +} + +sub prefix_output_shard { + my ($self, %options) = @_; + + return sprintf( + "collection '%s' shard '%s' ", + $options{instance_value}->{collectionName}, + $options{instance_value}->{shardName} + ); +} + sub set_counters { my ($self, %options) = @_; @@ -34,71 +70,88 @@ sub set_counters { group => [ { name => 'collections', display_long => 1, cb_prefix_output => 'prefix_output_collection', message_multiple => 'All collections statistics are ok', type => 1 }, + { name => 'shards', display_long => 1, cb_prefix_output => 'prefix_output_shard', + message_multiple => 'All shards collections statistics are ok', type => 1 } ] } ]; $self->{maps_counters}->{collections} = [ { label => 'storage-size', nlabel => 'collection.size.storage.bytes', set => { - key_values => [ { name => 'storageSize' }, { name => 'display' } ], - output_template => 'Storage Size: %s %s', + key_values => [ { name => 'storageSize' } ], + output_template => 'storage size: %s %s', output_change_bytes => 1, perfdatas => [ - { value => 'storageSize', template => '%s', - min => 0, unit => 'B', label_extra_instance => 1 }, - ], + { template => '%s', min => 0, unit => 'B', label_extra_instance => 1 } + ] } }, { label => 'index-size', nlabel => 'collection.size.index.bytes', set => { - key_values => [ { name => 'totalIndexSize' }, { name => 'display' } ], - output_template => 'Index Size: %s %s', + key_values => [ { name => 'totalIndexSize' } ], + output_template => 'index size: %s %s', output_change_bytes => 1, perfdatas => [ - { value => 'totalIndexSize', template => '%s', - min => 0, unit => 'B', label_extra_instance => 1 }, - ], + { template => '%s', min => 0, unit => 'B', label_extra_instance => 1 } + ] } }, { label => 'documents', nlabel => 'collection.documents.count', set => { - key_values => [ { name => 'count' }, { name => 'display' } ], - output_template => 'Documents: %s', + key_values => [ { name => 'count' } ], + output_template => 'documents: %s', perfdatas => [ - { value => 'count', template => '%s', - min => 0, label_extra_instance => 1 }, - ], + { template => '%s', min => 0, label_extra_instance => 1 } + ] } }, { label => 'indexes', nlabel => 'collection.indexes.count', set => { - key_values => [ { name => 'nindexes' }, { name => 'display' } ], - output_template => 'Indexes: %s', + key_values => [ { name => 'nindexes' } ], + output_template => 'indexes: %s', perfdatas => [ - { value => 'nindexes', template => '%s', - min => 0, label_extra_instance => 1 }, - ], + { template => '%s', min => 0, label_extra_instance => 1 } + ] + } + } + ]; + + $self->{maps_counters}->{shards} = [ + { label => 'shard-storage-size', nlabel => 'collection.size.storage.bytes', set => { + key_values => [ { name => 'storageSize' }, { name => 'dbName' }, { name => 'collectionName' }, { name => 'shardName' } ], + output_template => 'storage size: %s %s', + output_change_bytes => 1, + closure_custom_perfdata => $self->can('custom_shard_perfdata') } }, + { label => 'shard-index-size', nlabel => 'collection.size.index.bytes', set => { + key_values => [ { name => 'totalIndexSize' }, { name => 'dbName' }, { name => 'collectionName' }, { name => 'shardName' } ], + output_template => 'index size: %s %s', + output_change_bytes => 1, + closure_custom_perfdata => $self->can('custom_shard_perfdata') + } + }, + { label => 'shard-documents', nlabel => 'collection.documents.count', set => { + key_values => [ { name => 'count' }, { name => 'dbName' }, { name => 'collectionName' }, { name => 'shardName' } ], + output_template => 'documents: %s', + closure_custom_perfdata => $self->can('custom_shard_perfdata') + } + }, + { label => 'shard-indexes', nlabel => 'collection.indexes.count', set => { + key_values => [ { name => 'nindexes' }, { name => 'dbName' }, { name => 'collectionName' }, { name => 'shardName' } ], + output_template => 'indexes: %s', + closure_custom_perfdata => $self->can('custom_shard_perfdata') + } + } ]; } -sub long_output { - my ($self, %options) = @_; - - return "Checking database '" . $options{instance_value}->{display} . "' "; -} - -sub prefix_output_collection { - my ($self, %options) = @_; - - return "Collection '" . $options{instance_value}->{display} . "' "; -} - sub new { my ($class, %options) = @_; my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1); bless $self, $class; $options{options}->add_options(arguments => { - "filter-database:s" => { name => 'filter_database' }, + 'filter-database:s' => { name => 'filter_database' }, + 'filter-shard:s' => { name => 'filter_shard' }, + 'add-shards' => { name => 'add_shards' } }); return $self; } @@ -115,21 +168,41 @@ sub manage_selection { my $collections = $options{custom}->list_collections(database => $database); - $self->{databases}->{$database}->{display} = $database; + $self->{databases}->{$database} = { + display => $database, + collections => {}, + shards => {} + }; foreach my $collection (sort @{$collections}) { my $cl_stats = $options{custom}->run_command( database => $database, - command => $options{custom}->ordered_hash(collStats => $collection), + command => $options{custom}->ordered_hash(collStats => $collection) ); - + $self->{databases}->{$database}->{collections}->{$collection} = { - display => $collection, storageSize => $cl_stats->{storageSize}, totalIndexSize => $cl_stats->{totalIndexSize}, count => $cl_stats->{count}, - nindexes => $cl_stats->{nindexes}, + nindexes => $cl_stats->{nindexes} }; + + if (defined($self->{option_results}->{add_shards}) && defined($cl_stats->{shards})) { + foreach my $shard_name (keys %{$cl_stats->{shards}}) { + next if (defined($self->{option_results}->{filter_shard}) && $self->{option_results}->{filter_shard} ne '' + && $shard_name !~ /$self->{option_results}->{filter_shard}/); + + $self->{databases}->{$database}->{shards}->{$collection . $shard_name} = { + dbName => $database, + collectionName => $collection, + shardName => $shard_name, + storageSize => $cl_stats->{shards}->{$shard_name}->{storageSize}, + totalIndexSize => $cl_stats->{shards}->{$shard_name}->{totalIndexSize}, + count => $cl_stats->{shards}->{$shard_name}->{count}, + nindexes => $cl_stats->{shards}->{$shard_name}->{nindexes} + }; + } + } } } @@ -151,27 +224,21 @@ Check collections statistics per databases =item B<--filter-database> -Filter database name (Can use regexp). +Filter databases by name (Can use regexp). -=item B<--warning-subinstance-collection-size-*-bytes> +=item B<--filter-shard> -Warning threshold. -Can be: 'storage', 'index'. +Filter shards by name (Can use regexp). -=item B<--critical-subinstance-collection-size-*-bytes> +=item B<--add-shards> -Critical threshold. -Can be: 'storage', 'index'. +Add collection statistics by shards. -=item B<--warning-subinstance-collection-*-count> +=item B<--warning-*> B<--critical-*> -Warning threshold. -Can be: 'documents', 'indexes'. - -=item B<--critical-subinstance-collection-*-count> - -Critical threshold. -Can be: 'documents', 'indexes'. +Thresholds. +Can be: 'storage-size', 'index-size', 'documents', 'indexes', +'shard-storage-size', 'shard-index-size', 'shard-documents', 'shard-indexes'. =back diff --git a/src/database/mongodb/mode/connections.pm b/src/database/mongodb/mode/connections.pm index d06d24226..a828737e9 100644 --- a/src/database/mongodb/mode/connections.pm +++ b/src/database/mongodb/mode/connections.pm @@ -26,55 +26,55 @@ use strict; use warnings; use Digest::MD5 qw(md5_hex); +sub prefix_output { + my ($self, %options) = @_; + + return 'Connections '; +} + sub set_counters { my ($self, %options) = @_; $self->{maps_counters_type} = [ - { name => 'global', type => 0, cb_prefix_output => 'prefix_output' }, + { name => 'global', type => 0, cb_prefix_output => 'prefix_output' } ]; $self->{maps_counters}->{global} = [ { label => 'active', nlabel => 'connections.active.count', set => { key_values => [ { name => 'active' } ], - output_template => 'Active: %d', + output_template => 'active: %d', perfdatas => [ - { template => '%d', min => 0, unit => 'conn' }, - ], + { template => '%d', min => 0 } + ] } }, { label => 'current', nlabel => 'connections.current.count', set => { key_values => [ { name => 'current' } ], - output_template => 'Current: %d', + output_template => 'current: %d', perfdatas => [ - { template => '%d', min => 0, unit => 'conn' }, - ], + { template => '%d', min => 0 } + ] } }, { label => 'usage', nlabel => 'connections.usage.percentage', set => { key_values => [ { name => 'usage' } ], - output_template => 'Usage: %.2f %%', + output_template => 'usage: %.2f %%', perfdatas => [ - { template => '%.2f', min => 0, max => 100, unit => '%' }, - ], + { template => '%.2f', min => 0, max => 100, unit => '%' } + ] } }, { label => 'total-created', nlabel => 'connections.created.persecond', set => { key_values => [ { name => 'totalCreated', per_second => 1 } ], - output_template => 'Created: %.2f/s', + output_template => 'created: %.2f/s', perfdatas => [ - { template => '%.2f', min => 0, unit => 'conn/s' }, - ], + { template => '%.2f', min => 0 } + ] } - }, + } ]; } -sub prefix_output { - my ($self, %options) = @_; - - return "Connections "; -} - sub new { my ($class, %options) = @_; my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1, statefile => 1); @@ -99,8 +99,8 @@ sub manage_selection { $self->{global}->{current} = $server_stats->{connections}->{current}; $self->{global}->{usage} = $server_stats->{connections}->{current} / ($server_stats->{connections}->{current} + $server_stats->{connections}->{available}); $self->{global}->{totalCreated} = $server_stats->{connections}->{totalCreated}; - - $self->{cache_name} = "mongodb_" . $self->{mode} . '_' . $options{custom}->get_hostname() . '_' . $options{custom}->get_port() . '_' . + + $self->{cache_name} = 'mongodb_' . $self->{mode} . '_' . $options{custom}->get_hostname() . '_' . $options{custom}->get_port() . '_' . (defined($self->{option_results}->{filter_counters}) ? md5_hex($self->{option_results}->{filter_counters}) : md5_hex('all')); } @@ -110,35 +110,14 @@ __END__ =head1 MODE -Check connections statistics +Check connections statistics. =over 8 -=item B<--warning-connections-*-count> +=item B<--warning-*> B<--critical-*> -Warning threshold. -Can be: 'active', 'current'. - -=item B<--critical-connections-*-count> - -Critical threshold. -Can be: 'active', 'current'. - -=item B<--warning-connections-usage-percentage> - -Warning threshold for connections usage (current over available) - -=item B<--critical-connections-usage-percentage> - -Critical threshold for connections usage (current over available) - -=item B<--warning-connections-created-persecond> - -Warning threshold for connections created per second. - -=item B<--critical-connections-created-persecond> - -Critical threshold for connections created per second. +Thresholds. +Can be: 'active', 'current', 'usage', 'total-created'. =back diff --git a/src/database/mongodb/mode/connectiontime.pm b/src/database/mongodb/mode/connectiontime.pm index bc5606a9f..a7b5517a1 100644 --- a/src/database/mongodb/mode/connectiontime.pm +++ b/src/database/mongodb/mode/connectiontime.pm @@ -30,7 +30,7 @@ sub set_counters { my ($self, %options) = @_; $self->{maps_counters_type} = [ - { name => 'global', type => 0 }, + { name => 'global', type => 0 } ]; $self->{maps_counters}->{global} = [ @@ -38,11 +38,10 @@ sub set_counters { key_values => [ { name => 'connection_time' } ], output_template => 'Connection established in %d ms', perfdatas => [ - { value => 'connection_time', template => '%d', unit => 'ms', - min => 0 }, - ], + { template => '%d', unit => 'ms', min => 0 } + ] } - }, + } ]; } diff --git a/src/database/mongodb/mode/databasestatistics.pm b/src/database/mongodb/mode/databasestatistics.pm index 1fb944bda..d1bd560c6 100644 --- a/src/database/mongodb/mode/databasestatistics.pm +++ b/src/database/mongodb/mode/databasestatistics.pm @@ -25,82 +25,18 @@ use base qw(centreon::plugins::templates::counter); use strict; use warnings; -sub set_counters { +sub custom_shard_perfdata { my ($self, %options) = @_; - $self->{maps_counters_type} = [ - { name => 'databases', type => 1, cb_prefix_output => 'prefix_database_output', - message_multiple => 'All databases statistics are ok' }, - ]; - - $self->{maps_counters}->{databases} = [ - { label => 'storage-size', nlabel => 'database.size.storage.bytes', set => { - key_values => [ { name => 'storageSize' }, { name => 'display' } ], - output_template => 'Storage Size: %s %s', - output_change_bytes => 1, - perfdatas => [ - { value => 'storageSize', template => '%s', - min => 0, unit => 'B', label_extra_instance => 1, instance_use => 'display' }, - ], - } - }, - { label => 'data-size', nlabel => 'database.size.data.bytes', set => { - key_values => [ { name => 'dataSize' }, { name => 'display' } ], - output_template => 'Data Size: %s %s', - output_change_bytes => 1, - perfdatas => [ - { value => 'dataSize', template => '%s', - min => 0, unit => 'B', label_extra_instance => 1, instance_use => 'display' }, - ], - } - }, - { label => 'index-size', nlabel => 'database.size.index.bytes', set => { - key_values => [ { name => 'indexSize' }, { name => 'display' } ], - output_template => 'Index Size: %s %s', - output_change_bytes => 1, - perfdatas => [ - { value => 'indexSize', template => '%s', - min => 0, unit => 'B', label_extra_instance => 1, instance_use => 'display' }, - ], - } - }, - { label => 'collections', nlabel => 'database.collections.count', set => { - key_values => [ { name => 'collections' }, { name => 'display' } ], - output_template => 'Collections: %s', - perfdatas => [ - { value => 'collections', template => '%s', - min => 0, label_extra_instance => 1, instance_use => 'display' }, - ], - } - }, - { label => 'views', nlabel => 'database.views.count', set => { - key_values => [ { name => 'views' }, { name => 'display' } ], - output_template => 'Views: %s', - perfdatas => [ - { value => 'views', template => '%s', - min => 0, label_extra_instance => 1, instance_use => 'display' }, - ], - } - }, - { label => 'documents', nlabel => 'database.documents.count', set => { - key_values => [ { name => 'documents' }, { name => 'display' } ], - output_template => 'Documents: %s', - perfdatas => [ - { value => 'documents', template => '%s', - min => 0, label_extra_instance => 1, instance_use => 'display' }, - ], - } - }, - { label => 'indexes', nlabel => 'database.indexes.count', set => { - key_values => [ { name => 'indexes' }, { name => 'display' } ], - output_template => 'Indexes: %s', - perfdatas => [ - { value => 'indexes', template => '%s', - min => 0, label_extra_instance => 1, instance_use => 'display' }, - ], - } - }, - ]; + $self->{output}->perfdata_add( + nlabel => $self->{nlabel}, + unit => $self->{instance_mode}->{option_results}->{unit}, + instances => [$self->{result_values}->{dbName}, $self->{result_values}->{shardName}], + value => $self->{result_values}->{ $self->{key_values}->[0]->{name} }, + warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{thlabel}), + critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{thlabel}), + min => 0 + ); } sub prefix_database_output { @@ -109,13 +45,146 @@ sub prefix_database_output { return "Database '" . $options{instance_value}->{display} . "' "; } +sub prefix_shard_output { + my ($self, %options) = @_; + + return sprintf( + "Database '%s' shard '%s' ", + $options{instance_value}->{dbName}, + $options{instance_value}->{shardName} + ); +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'databases', type => 1, cb_prefix_output => 'prefix_database_output', + message_multiple => 'All databases statistics are ok' }, + { name => 'shards', type => 1, cb_prefix_output => 'prefix_shard_output', + message_multiple => 'All shards databases statistics are ok' }, + ]; + + $self->{maps_counters}->{databases} = [ + { label => 'storage-size', nlabel => 'database.size.storage.bytes', set => { + key_values => [ { name => 'storageSize' } ], + output_template => 'storage size: %s %s', + output_change_bytes => 1, + perfdatas => [ + { template => '%s', min => 0, unit => 'B', label_extra_instance => 1 } + ] + } + }, + { label => 'data-size', nlabel => 'database.size.data.bytes', set => { + key_values => [ { name => 'dataSize' } ], + output_template => 'data size: %s %s', + output_change_bytes => 1, + perfdatas => [ + { template => '%s', min => 0, unit => 'B', label_extra_instance => 1 } + ] + } + }, + { label => 'index-size', nlabel => 'database.size.index.bytes', set => { + key_values => [ { name => 'indexSize' } ], + output_template => 'index size: %s %s', + output_change_bytes => 1, + perfdatas => [ + { template => '%s', min => 0, unit => 'B', label_extra_instance => 1 } + ] + } + }, + { label => 'collections', nlabel => 'database.collections.count', set => { + key_values => [ { name => 'collections' } ], + output_template => 'collections: %s', + perfdatas => [ + { template => '%s', min => 0, label_extra_instance => 1 } + ] + } + }, + { label => 'views', nlabel => 'database.views.count', set => { + key_values => [ { name => 'views' } ], + output_template => 'views: %s', + perfdatas => [ + { template => '%s', min => 0, label_extra_instance => 1 } + ] + } + }, + { label => 'documents', nlabel => 'database.documents.count', set => { + key_values => [ { name => 'documents' } ], + output_template => 'documents: %s', + perfdatas => [ + { template => '%s', min => 0, label_extra_instance => 1 } + ] + } + }, + { label => 'indexes', nlabel => 'database.indexes.count', set => { + key_values => [ { name => 'indexes' } ], + output_template => 'indexes: %s', + perfdatas => [ + { template => '%s', min => 0, label_extra_instance => 1 } + ] + } + } + ]; + + $self->{maps_counters}->{shards} = [ + { label => 'shard-storage-size', nlabel => 'database.size.storage.bytes', set => { + key_values => [ { name => 'storageSize' }, { name => 'dbName' }, { name => 'shardName' } ], + output_template => 'storage size: %s %s', + output_change_bytes => 1, + closure_custom_perfdata => $self->can('custom_shard_perfdata') + } + }, + { label => 'shard-data-size', nlabel => 'database.size.data.bytes', set => { + key_values => [ { name => 'dataSize' }, { name => 'dbName' }, { name => 'shardName' } ], + output_template => 'data size: %s %s', + output_change_bytes => 1, + closure_custom_perfdata => $self->can('custom_shard_perfdata') + } + }, + { label => 'shard-index-size', nlabel => 'database.size.index.bytes', set => { + key_values => [ { name => 'indexSize' }, { name => 'dbName' }, { name => 'shardName' } ], + output_template => 'index size: %s %s', + output_change_bytes => 1, + closure_custom_perfdata => $self->can('custom_shard_perfdata') + } + }, + { label => 'shard-collections', nlabel => 'database.collections.count', set => { + key_values => [ { name => 'collections' }, { name => 'dbName' }, { name => 'shardName' } ], + output_template => 'collections: %s', + closure_custom_perfdata => $self->can('custom_shard_perfdata') + } + }, + { label => 'shard-views', nlabel => 'database.views.count', set => { + key_values => [ { name => 'views' }, { name => 'dbName' }, { name => 'shardName' } ], + output_template => 'views: %s', + closure_custom_perfdata => $self->can('custom_shard_perfdata') + } + }, + { label => 'shard-documents', nlabel => 'database.documents.count', set => { + key_values => [ { name => 'documents' }, { name => 'dbName' }, { name => 'shardName' } ], + output_template => 'documents: %s', + closure_custom_perfdata => $self->can('custom_shard_perfdata') + } + }, + { label => 'shard-indexes', nlabel => 'database.indexes.count', set => { + key_values => [ { name => 'indexes' }, { name => 'dbName' }, { name => 'shardName' } ], + output_template => 'indexes: %s', + closure_custom_perfdata => $self->can('custom_shard_perfdata') + } + } + ]; +} + sub new { my ($class, %options) = @_; my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1); bless $self, $class; $options{options}->add_options(arguments => { - 'filter-database:s' => { name => 'filter_database' } + 'filter-database:s' => { name => 'filter_database' }, + 'filter-shard:s' => { name => 'filter_shard' }, + 'add-shards' => { name => 'add_shards' } }); return $self; } @@ -125,6 +194,7 @@ sub manage_selection { my $databases = $options{custom}->list_databases(); + $self->{shards} = {}; $self->{databases} = {}; foreach my $database (sort @{$databases}) { next if (defined($self->{option_results}->{filter_database}) && $self->{option_results}->{filter_database} ne '' @@ -132,18 +202,37 @@ sub manage_selection { my $db_stats = $options{custom}->run_command( database => $database, - command => $options{custom}->ordered_hash(dbStats => 1), + command => $options{custom}->ordered_hash(dbStats => 1) ); - $self->{databases}->{$db_stats->{db}} = { - display => $db_stats->{db}, + $self->{databases}->{$database} = { + display => $database, collections => $db_stats->{collections}, views => $db_stats->{views}, documents => $db_stats->{objects}, storageSize => $db_stats->{storageSize}, indexSize => $db_stats->{indexSize}, dataSize => $db_stats->{dataSize}, - indexes => $db_stats->{indexes}, + indexes => $db_stats->{indexes} + }; + + if (defined($self->{option_results}->{add_shards}) && defined($db_stats->{raw})) { + foreach my $shard_name (keys %{$db_stats->{raw}}) { + next if (defined($self->{option_results}->{filter_shard}) && $self->{option_results}->{filter_shard} ne '' + && $shard_name !~ /$self->{option_results}->{filter_shard}/); + + $self->{shards}->{$database . $shard_name} = { + dbName => $database, + shardName => $shard_name, + collections => $db_stats->{raw}->{$shard_name}->{collections}, + views => $db_stats->{raw}->{$shard_name}->{views}, + documents => $db_stats->{raw}->{$shard_name}->{objects}, + storageSize => $db_stats->{raw}->{$shard_name}->{storageSize}, + indexSize => $db_stats->{raw}->{$shard_name}->{indexSize}, + dataSize => $db_stats->{raw}->{$shard_name}->{dataSize}, + indexes => $db_stats->{raw}->{$shard_name}->{indexes} + }; + } } } @@ -165,29 +254,21 @@ Check databases statistics =item B<--filter-database> -Filter database name (Can use regexp). +Filter databases by name (Can use regexp). -=item B<--warning-instance-database-size-*-bytes> +=item B<--filter-shard> -Warning threshold. -Can be: 'storage', 'data', 'index'. +Filter shards by name (Can use regexp). -=item B<--critical-instance-database-size-*-bytes> +=item B<--add-shards> -Critical threshold. -Can be: 'storage', 'data', 'index'. +Add database statistics by shards. -=item B<--warning-instance-database-*-count> +=item B<--warning-*> B<--critical-*> -Warning threshold. -Can be: 'collections', 'views', 'documents', -'indexes'. - -=item B<--critical-instance-database-*-count> - -Critical threshold. -Can be: 'collections', 'views', 'documents', -'indexes'. +Thresholds. +Can be: 'storage-size', 'data-size', 'index-size', 'collections', 'views', 'documents', 'indexes', +'shard-storage-size', 'shard-data-size', 'shard-index-size', 'shard-collections', 'shard-views', 'shard-documents', 'shard-indexes'. =back diff --git a/src/database/mongodb/mode/queries.pm b/src/database/mongodb/mode/queries.pm index a31cb6df7..695310eba 100644 --- a/src/database/mongodb/mode/queries.pm +++ b/src/database/mongodb/mode/queries.pm @@ -26,22 +26,28 @@ use strict; use warnings; use Digest::MD5 qw(md5_hex); +sub prefix_output { + my ($self, %options) = @_; + + return 'Requests '; +} + sub set_counters { my ($self, %options) = @_; $self->{maps_counters_type} = [ - { name => 'global', type => 0, cb_prefix_output => 'prefix_output' }, + { name => 'global', type => 0, cb_prefix_output => 'prefix_output' } ]; $self->{maps_counters}->{global} = [ { label => 'total', nlabel => 'queries.total.persecond', set => { key_values => [ { name => 'total', per_second => 1 } ], - output_template => 'Total : %d', + output_template => 'total: %d', perfdatas => [ - { template => '%d', unit => '/s', min => 0 }, - ], + { template => '%d', unit => '/s', min => 0 } + ] } - }, + } ]; foreach ('insert', 'query', 'update', 'delete', 'getmore', 'command') { @@ -54,6 +60,7 @@ sub set_counters { ] } }; + push @{$self->{maps_counters}->{global}}, { label => $_ . '-count', , nlabel => 'queries.' . $_ . '.count', display_ok => 0, set => { key_values => [ { name => $_, diff => 1 } ], @@ -66,12 +73,6 @@ sub set_counters { } } -sub prefix_output { - my ($self, %options) = @_; - - return 'Requests '; -} - sub new { my ($class, %options) = @_; my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1, statefile => 1); @@ -85,15 +86,15 @@ sub new { sub manage_selection { my ($self, %options) = @_; - $self->{global} = {}; my $server_stats = $options{custom}->run_command( database => 'admin', - command => $options{custom}->ordered_hash(serverStatus => 1), + command => $options{custom}->ordered_hash(serverStatus => 1) ); - - foreach my $querie (keys %{$server_stats->{opcounters}}) { - $self->{global}->{$querie} = $server_stats->{opcounters}->{$querie}; - $self->{global}->{total} += $server_stats->{opcounters}->{$querie}; + + $self->{global} = {}; + foreach my $query (keys %{$server_stats->{opcounters}}) { + $self->{global}->{$query} = $server_stats->{opcounters}->{$query}; + $self->{global}->{total} += $server_stats->{opcounters}->{$query}; } $self->{cache_name} = 'mongodb_' . $self->{mode} . '_' . $options{custom}->get_hostname() . '_' . $options{custom}->get_port() . '_' . @@ -110,29 +111,11 @@ Check number of queries executed (absolute and per second). =over 8 -=item B<--warning-queries-*-persecond> +=item B<--warning-*> B<--critical-*> -Warning threshold. -Can be: 'total', 'insert', 'query', 'update', -'delete', 'getmore', 'command' - -=item B<--critical-queries-*-persecond> - -Critical threshold. -Can be: 'total', 'insert', 'query', 'update', -'delete', 'getmore', 'command' - -=item B<--warning-queries-*-count> - -Warning threshold. -Can be: 'insert', 'query', 'update', -'delete', 'getmore', 'command' - -=item B<--critical-queries-*-count> - -Critical threshold. -Can be: 'insert', 'query', 'update', -'delete', 'getmore', 'command' +Thresholds. +Can be: 'total', 'insert', 'query', 'update', 'delete', 'getmore', 'command', +'insert-count', 'query-count', 'update-count', 'delete-count', 'getmore-count', 'command-count'. =back diff --git a/src/database/mongodb/mode/replicationstatus.pm b/src/database/mongodb/mode/replicationstatus.pm index d7b189ba4..dacf50ffd 100644 --- a/src/database/mongodb/mode/replicationstatus.pm +++ b/src/database/mongodb/mode/replicationstatus.pm @@ -24,22 +24,22 @@ use base qw(centreon::plugins::templates::counter); use strict; use warnings; -use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold); +use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold_ng); my %mapping_states = ( 0 => 'STARTUP', 1 => 'PRIMARY', 2 => 'SECONDARY', 3 => 'RECOVERING', 5 => 'STARTUP2', 6 => 'UNKNOWN', - 7 => 'ARBITER', 8 => 'DOWN', 9 => 'ROLLBACK', 10 => 'REMOVED', + 7 => 'ARBITER', 8 => 'DOWN', 9 => 'ROLLBACK', 10 => 'REMOVED' ); my %mapping_health = ( 0 => 'down', - 1 => 'up', + 1 => 'up' ); sub custom_status_output { my ($self, %options) = @_; - my $msg = sprintf("Current member state is '%s'", $self->{result_values}->{state}); + my $msg = sprintf("current member state is '%s'", $self->{result_values}->{state}); $msg .= sprintf(", syncing to '%s'", $self->{result_values}->{sync_host}) if ($self->{result_values}->{state} ne 'PRIMARY'); return $msg; } @@ -47,7 +47,7 @@ sub custom_status_output { sub custom_status_calc { my ($self, %options) = @_; - $self->{result_values}->{state} = $mapping_states{$options{new_datas}->{$self->{instance} . '_myState'}}; + $self->{result_values}->{state} = $mapping_states{ $options{new_datas}->{ $self->{instance} . '_myState' } }; $self->{result_values}->{sync_host} = $options{new_datas}->{$self->{instance} . '_syncSourceHost'}; return 0; } @@ -55,7 +55,8 @@ sub custom_status_calc { sub custom_member_status_output { my ($self, %options) = @_; - return sprintf("state is '%s' and health is '%s' [slave delay: %s] [priority: %s]", + return sprintf( + "state is '%s' and health is '%s' [slave delay: %s] [priority: %s]", $self->{result_values}->{state}, $self->{result_values}->{health}, $self->{result_values}->{slave_delay}, @@ -75,84 +76,110 @@ sub custom_member_status_calc { return 0; } +sub prefix_member_output { + my ($self, %options) = @_; + + return "Member '" . $options{instance_value}->{name} . "' "; +} + +sub prefix_members_counters_output { + my ($self, %options) = @_; + + return 'Number of members '; +} + sub set_counters { my ($self, %options) = @_; $self->{maps_counters_type} = [ { name => 'global', type => 0, skipped_code => { -10 => 1 } }, - { name => 'members', type => 1, cb_prefix_output => 'prefix_output', - message_multiple => 'All members statistics are ok', skipped_code => { -10 => 1 } }, + { name => 'members_counters', type => 0, cb_prefix_output => 'prefix_members_counters_output', skipped_code => { -10 => 1 } }, + { name => 'members', type => 1, cb_prefix_output => 'prefix_member_output', + message_multiple => 'All members statistics are ok', skipped_code => { -10 => 1 } } + ]; + + $self->{maps_counters}->{members_counters} = [ + { label => 'members-primary', nlabel => 'members.primary.count', display_ok => 0, set => { + key_values => [ { name => 'primary' } ], + output_template => 'primary: %s', + perfdatas => [ + { template => '%s', min => 0 } + ] + } + }, + { label => 'members-secondary', nlabel => 'members.secondary.count', display_ok => 0, set => { + key_values => [ { name => 'secondary' } ], + output_template => 'secondary: %s', + perfdatas => [ + { template => '%s', min => 0 } + ] + } + }, + { label => 'members-arbiter', nlabel => 'members.arbiter.count', display_ok => 0, set => { + key_values => [ { name => 'arbiter' } ], + output_template => 'arbiter: %s', + perfdatas => [ + { template => '%s', min => 0 } + ] + } + } ]; $self->{maps_counters}->{global} = [ - { label => 'status', set => { + { label => 'status', type => 2, set => { key_values => [ { name => 'myState' }, { name => 'syncSourceHost' } ], closure_custom_calc => $self->can('custom_status_calc'), closure_custom_output => $self->can('custom_status_output'), closure_custom_perfdata => sub { return 0; }, - closure_custom_threshold_check => \&catalog_status_threshold, + closure_custom_threshold_check => \&catalog_status_threshold_ng } - }, + } ]; + $self->{maps_counters}->{members} = [ - { label => 'member-status', set => { - key_values => [ { name => 'stateStr' }, { name => 'health' }, { name => 'slaveDelay' }, - { name => 'priority' }, { name => 'name' } ], + { + label => 'member-status', + type => 2, + warning_default => '%{state} !~ /PRIMARY|SECONDARY/', + critical_default => '%{health} !~ /up/', + set => { + key_values => [ + { name => 'stateStr' }, { name => 'health' }, { name => 'slaveDelay' }, + { name => 'priority' }, { name => 'name' } + ], closure_custom_calc => $self->can('custom_member_status_calc'), closure_custom_output => $self->can('custom_member_status_output'), closure_custom_perfdata => sub { return 0; }, - closure_custom_threshold_check => \&catalog_status_threshold, + closure_custom_threshold_check => \&catalog_status_threshold_ng } }, { label => 'replication-lag', nlabel => 'replication.lag.seconds', set => { key_values => [ { name => 'lag' }, { name => 'name' } ], - output_template => 'Replication Lag: %s s', + output_template => 'replication lag: %s s', perfdatas => [ - { value => 'lag', template => '%d', unit => 's', - min => 0, label_extra_instance => 1, instance_use => 'name' }, - ], + { template => '%d', unit => 's', min => 0, label_extra_instance => 1, instance_use => 'name' } + ] } - }, + } ]; } -sub prefix_output { - my ($self, %options) = @_; - - return "Member '" . $options{instance_value}->{name} . "' "; -} - sub new { my ($class, %options) = @_; my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1); bless $self, $class; - $options{options}->add_options(arguments => { - 'warning-status:s' => { name => 'warning_status', default => '' }, - 'critical-status:s' => { name => 'critical_status', default => '' }, - 'warning-member-status:s' => { name => 'warning_member_status', default => '%{state} !~ /PRIMARY|SECONDARY/' }, - 'critical-member-status:s' => { name => 'critical_member_status', default => '%{health} !~ /up/' }, - }); + $options{options}->add_options(arguments => {}); return $self; } -sub check_options { - my ($self, %options) = @_; - $self->SUPER::check_options(%options); - - $self->change_macros(macros => [ - 'warning_status', 'critical_status', - 'warning_member_status', 'critical_member_status' - ]); -} - sub manage_selection { my ($self, %options) = @_; my $ismaster = $options{custom}->run_command( database => 'admin', - command => $options{custom}->ordered_hash(ismaster => 1), + command => $options{custom}->ordered_hash(ismaster => 1) ); if (!defined($ismaster->{me})) { @@ -161,6 +188,7 @@ sub manage_selection { } $self->{global} = {}; + $self->{members_counters} = { primary => 0, secondary => 0, arbiter => 0 }; $self->{members} = {}; my $repl_conf = $options{custom}->run_command( database => 'admin', @@ -169,12 +197,15 @@ sub manage_selection { my %config; foreach my $member (sort @{$repl_conf->{config}->{members}}) { - $config{$member->{host}} = { priority => $member->{priority}, slaveDelay => $member->{slaveDelay} } + $config{ $member->{host} } = { + priority => $member->{priority}, + slaveDelay => defined($member->{secondaryDelaySecs}) ? $member->{secondaryDelaySecs} : $member->{slaveDelay} + }; } my $repl_status = $options{custom}->run_command( database => 'admin', - command => $options{custom}->ordered_hash(replSetGetStatus => 1), + command => $options{custom}->ordered_hash(replSetGetStatus => 1) ); $self->{global}->{myState} = $repl_status->{myState}; @@ -182,19 +213,22 @@ sub manage_selection { $self->{global}->{syncSourceHost} = '-' if (!defined($self->{global}->{syncSourceHost})); foreach my $member (sort @{$repl_status->{members}}) { - $self->{members}->{$member->{name}} = { + $self->{members_counters}->{ lc($member->{stateStr}) }++ + if (defined($self->{members_counters}->{ lc($member->{stateStr}) })); + + $self->{members}->{ $member->{name} } = { name => $member->{name}, stateStr => $member->{stateStr}, health => $member->{health}, optimeDate => $member->{optime}->{ts}->{seconds}, - slaveDelay => $config{$member->{name}}->{slaveDelay}, - priority => $config{$member->{name}}->{priority} + slaveDelay => $config{ $member->{name} }->{slaveDelay}, + priority => $config{ $member->{name} }->{priority} } } foreach my $member (keys %{$self->{members}}) { next if ($self->{members}->{$member}->{stateStr} !~ /SECONDARY/); - $self->{members}->{$member}->{lag} = $self->{members}->{$ismaster->{primary}}->{optimeDate} - $self->{members}->{$member}->{optimeDate} - $self->{members}->{$member}->{slaveDelay}; + $self->{members}->{$member}->{lag} = $self->{members}->{ $ismaster->{primary} }->{optimeDate} - $self->{members}->{$member}->{optimeDate} - $self->{members}->{$member}->{slaveDelay}; } if (scalar(keys %{$self->{members}}) <= 0) { @@ -209,41 +243,35 @@ __END__ =head1 MODE -Check replication status +Check replication status. =over 8 =item B<--warning-status> -Set warning threshold for checked instance status (Default: ''). +Define the conditions to match for the status to be WARNING. You can use the following variables: %{state}, %{sync_host}. =item B<--critical-status> -Set critical threshold for checked instance status (Default: ''). +Define the conditions to match for the status to be CRITICAL. You can use the following variables: %{state}, %{sync_host}. =item B<--warning-member-status> -Set warning threshold for members status (Default: '%{state} !~ /PRIMARY|SECONDARY/'). -You can use the following variables: %{name}, %{state}, %{health}, -%{slave_delay}, %{priority}. +Define the conditions to match for the status to be WARNING (default: '%{state} !~ /PRIMARY|SECONDARY/'). +You can use the following variables: %{name}, %{state}, %{health}, %{slave_delay}, %{priority}. =item B<--critical-member-status> -Set critical threshold for members status (Default: '%{health} !~ /up/'). -You can use the following variables: %{name}, %{state}, %{health}, -%{slave_delay}, %{priority}. +Define the conditions to match for the status to be CRITICAL (default: '%{health} !~ /up/'). +You can use the following variables: %{name}, %{state}, %{health}, %{slave_delay}, %{priority}. -=item B<--warning-instance-replication-lag-seconds> +=item B<--warning-*> B<--critical-*> -Warning threshold for replication lag between primary and secondary members. -Must not be over 0 (between minus slaveDelay and 0). - -=item B<--critical-instance-replication-lag-seconds> - -Critical threshold for replication lag between primary and secondary members. -Must not be over 0 (between minus slaveDelay and 0). +Thresholds. +Can be: 'members-primary', 'members-secondary', 'members-arbiter', +'replication-lag'. =back diff --git a/src/database/mongodb/plugin.pm b/src/database/mongodb/plugin.pm index c2839261e..832b3e7a2 100644 --- a/src/database/mongodb/plugin.pm +++ b/src/database/mongodb/plugin.pm @@ -29,18 +29,17 @@ sub new { my $self = $class->SUPER::new(package => __PACKAGE__, %options); bless $self, $class; - $self->{version} = '1.0'; - %{$self->{modes}} = ( + $self->{modes} = { 'collection-statistics' => 'database::mongodb::mode::collectionstatistics', 'connections' => 'database::mongodb::mode::connections', 'connection-time' => 'database::mongodb::mode::connectiontime', 'database-statistics' => 'database::mongodb::mode::databasestatistics', 'list-databases' => 'database::mongodb::mode::listdatabases', 'queries' => 'database::mongodb::mode::queries', - 'replication-status' => 'database::mongodb::mode::replicationstatus', - ); - - $self->{custom_modes}{driver} = 'database::mongodb::custom::driver'; + 'replication-status' => 'database::mongodb::mode::replicationstatus' + }; + + $self->{custom_modes}->{driver} = 'database::mongodb::custom::driver'; return $self; }