-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmongodb_rs.pl
More file actions
executable file
·215 lines (176 loc) · 5.11 KB
/
mongodb_rs.pl
File metadata and controls
executable file
·215 lines (176 loc) · 5.11 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
#!usr/bin/env perl
use warnings;
use strict;
use MongoDB 0.702.2;
use Getopt::Long;
use feature qw{say};
sub _say_and_exit {
my ($msg) = @_;
unless (defined $msg) {
say 'CRITICAL - empty message';
exit 1;
}
say $msg;
exit;
}
my %h_RS_myState_map = (
0 => 'STARTUP',
1 => 'PRIMARY',
2 => 'SECONDARY',
3 => 'RECOVERING',
4 => 'FATAL',
5 => 'STARTUP2',
6 => 'UNKNOWN',
7 => 'ARBITER',
8 => 'DOWN',
9 => 'ROLLBACK',
10 => 'SHUNNED',
);
our %context = (
'hostname' => 'localhost',
'port' => 27017,
'user' => undef,
'password' => undef,
'help' => 0,
);
GetOptions(
'h|hostname=s' => \$context{'hostname'},
'p|port=i' => \$context{'port'},
'u|user=s' => \$context{'user'},
'ps|password=s' => \$context{'password'},
'help' => \$context{'help'},
);
if ($context{'help'}) {
print q{Synopsis
perl mongodb_rs.pl [options]
Desription
Script return rs.status() in shortened form: "status - message",
e.g. "CRITICAL - MongoClient call failed, maybe cannot connect?".
Possible statuses and their descriptions:
CRITICAL:
- couldn't connect to mongodb;
- cannot change database to "admin";
- db.runCommand({replSetGetStatus:1}) exec failure;
- replSetGetStatus have no true "ok", possible error;
- cannot find or not defined fileds: members, myState, set;
- rs member have status FATAL, UNKNOWN, DOWN, ROLLBACK or STUNNED;
- PRIMARY not found;
WARNING:
- rs member have status STARTUP, STARTUP2 or RECOREVING;
- cannot find or not defined fields for members: health, state, stateStr;
- not epmty errmsg for RS-members (exception: "syncing to: ");
OK:
- all okay ;)
Options and default values:
-h, --hostname localhost
-p, --port 27017
-u, --user undefined
-ps, --password undefined
--help
};
exit;
}
my $client;
my %h_conn = (host => $context{'hostname'} . ':' . $context{'port'});
$h_conn{username} = $context{'user'} if (defined $context{'user'});
$h_conn{password} = $context{'password'} if (defined $context{'password'});
eval { $client = MongoDB::MongoClient->new(%h_conn) };
_say_and_exit('CRITICAL - MongoClient call failed, maybe cannot connect?')
if ($@ or !$client);
my $database = $client->get_database("admin");
_say_and_exit('CRITICAL - get_database admin call failed')
unless ($database);
my $rs_status = $database->run_command({replSetGetStatus => 1});
_say_and_exit('CRITICAL - error in call db.runCommand({replSetGetStatus:1})')
unless ($rs_status and ref($rs_status) eq 'HASH');
_say_and_exit('CRITICAL - error message: ' . $rs_status->{errmsg})
if (exists $rs_status->{errmsg} and $rs_status->{errmsg});
# validate hash data
unless (
exists $rs_status->{ok} and
exists $rs_status->{members} and
exists $rs_status->{myState} and
exists $rs_status->{set}
) {
_say_and_exit('CRITICAL - invalid some data (e.g. "ok", "members", "myState", "set"); check rs.status() manually');
}
_say_and_exit('CRITICAL - output not ok, check rs.status() manually')
unless ($rs_status->{ok});
my @warnings;
# error states:
# 4 - FATAL
# 6 - UNKNOWN
# 8 - DOWN
# 9 - ROLLBACK
# 10 - STUNNED
if (defined $rs_status->{myState}) {
if (
$rs_status->{myState} == 4 or
$rs_status->{myState} == 6 or
$rs_status->{myState} >= 8
) {
_say_and_exit('CRITICAL - RS err state: ' . $h_RS_myState_map{$rs_status->{myState}});
}
# Initialization states:
# 0 - STARTUP
# 3 - RECOREVING
# 5 - STARTUP2
if (
$rs_status->{myState} == 0 or
$rs_status->{myState} == 3 or
$rs_status->{myState} == 5
) {
push(@warnings, 'RS init state: ' . $h_RS_myState_map{$rs_status->{myState}});
}
} else {
_say_and_exit('CRITICAL - RS state not defined');
}
_say_and_exit('CRITICAL - empty RS members list')
unless (scalar @{$rs_status->{members}});
my $primary_found_flag = 0;
# Search broken members
for my $member ( @{$rs_status->{members}} ) {
# check that member have no PRIMARY/SECONDARY/ARBITER state
if (defined $member->{state}) {
# set true flag if found Primary server
if ($member->{state} == 1) { $primary_found_flag++; }
# SECONDARY/ARBITER - normally state
elsif (
scalar(@warnings) < 1 and
$member->{state} != 2 and
$member->{state} != 7
) {
push(@warnings, $member->{name} . ' state: ' . $member->{stateStr});
next;
}
}
# added warnings RS if empty array with warnings on this server
unless ( scalar(@warnings) ) {
unless (exists $member->{name}) {
push(@warnings, 'cannot get name for RS member...?');
next;
}
# message "syncing to" isn't error: jira.mongodb.org/browse/SERVER-7099
if (exists $member->{errmsg} and $member->{errmsg} and index($member->{errmsg}, 'syncing to: ') < 0) {
push(@warnings, $member->{name} . ' errmsg: ' . $member->{errmsg});
next;
}
unless (
exists $member->{health} or
exists $member->{state} or
exists $member->{stateStr}
) {
push(@warnings, 'cannot define ' . $member->{name} . ' health status and state');
next;
}
unless ($member->{health}) {
push(@warnings, 'false health status for ' . $member->{name});
next;
}
}
}
_say_and_exit('CRITICAL - not found PRIMARY')
unless ($primary_found_flag);
_say_and_exit('WARNING - ' . join('; ', @warnings))
if (scalar @warnings);
say 'OK - I seem, that all is working';