-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathcheck_irods
executable file
·429 lines (349 loc) · 9.48 KB
/
check_irods
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
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
#!/usr/bin/env bash
#
# NB this should follow the Nagios plugin guidelines. See
# https://nagios-plugins.org/doc/guidelines.html
# TODO run network connection in separate process and kill it after a certain amount of time. (nagios DEFAULT_SOCKET_TIMEOUT)
# TODO switch to using -p (lowercase) for PORT option
# TODO connecting to something other than iRODS should be a CRITICAL
# TODO add support for verbosity=1 See https://nagios-plugins.org/doc/guidelines.html#VERBOSELEVELS
print_usage() {
/bin/cat <<EOF
Usage:
$EXEC_NAME [-v|--verbose][(-P|--port) PORT] IRODS-HOST
$EXEC_NAME (-h|--help)
$EXEC_NAME (-?|--usage)
$EXEC_NAME (-V|--version)
EOF
}
print_description() {
/bin/cat <<EOF
Nagios plugin that checks to see is if an iRODS server is online. It supports
Nagios version 2 or later and iRODS version 4 or later.
Parameters:
HOST the FQDN or IP address of the server hosting the service
Options:
-h, --help show help and exit
-P, --port PORT the TCP port the iRODS server listens to on HOST (default
1247)
-?, --usage show a usage message and exit
-v, --verbose show additional information, a repeat of this flag will show
the response from the server
-V, --version show version and exit
Output:
Unless otherwise indicated, it writes the status of the iRODS service on
IRODS-HOST to stdout in a form interpretable by nagios. When the plugin
successfully connects to iRODS, it provides the amount of time it took to
connect as a performance datum in the form "time=<duration>s" where <duration>
is the amount of time in seconds.
Exit Status:
0 connected to iRODS
2 failed to connect to iRODS
3 an error occurred or connected to something other than iRODS
© 2024 The Arizona Board of Regents on behalf of The University of Arizona. For
license information, see https://cyverse.org/license.
EOF
}
set -o errexit -o nounset -o pipefail
readonly VERSION=9
readonly DEFAULT_EXEC_NAME=check_irods
readonly DEFAULT_PORT=1247
# exit and return statuses
declare -i -r OK=0
#declare -i -r WARNING=1 # Not used yet
declare -i -r CRITICAL=2
declare -r -r UNKNOWN=3
# verbosity
declare -i -r TERSE=0
#declare -i -r VERBOSE=1 # Not used yet
declare EXEC_NAME
main() {
# If stderr isn't a terminal, redirect it to stdout
if ! [[ -t 2 ]]; then
exec 2>&-
exec 2>&1
fi
verify_sys_cmds
if ! EXEC_NAME="$(/usr/bin/basename "$(/usr/bin/realpath --canonicalize-missing "$0")")"; then
printf 'cannot determine executable name, using %s\n' "$DEFAULT_EXEC_NAME" >&2 || true
EXEC_NAME="$DEFAULT_EXEC_NAME"
fi
readonly EXEC_NAME
declare -A argMap=(
[help]=''
[host]=''
[port]="$DEFAULT_PORT"
[usage]=''
[verbose]="$TERSE"
[version]='' )
if ! map_args argMap "$@"; then
print_usage >&2 || true
return $UNKNOWN
fi
if [[ -n "${argMap[help]}" ]]; then
if ! print_help; then
return $UNKNOWN
fi
elif [[ -n "${argMap[usage]}" ]]; then
if ! print_usage; then
return $UNKNOWN
fi
elif [[ -n "${argMap[version]}" ]]; then
if ! print_version; then
return $UNKNOWN
fi
else
if [[ -z "${argMap[host]}" ]]; then
printf 'iRODS host required\n' >&2 || true
print_usage >&2 || true
return $UNKNOWN
fi
ping "${argMap[host]}" "${argMap[port]}" "${argMap[verbose]}" 2> /dev/null
return
fi
return $OK
}
# This checks to see if the system commands used by this script are symbolic links.
# Output:
# For each command that is a symbolic link, it writes a warning message to stderr.
verify_sys_cmds() {
local cmds=(
/bin/cat
/bin/date
/usr/bin/basename
/usr/bin/bc
/usr/bin/getopt
/usr/bin/od
/usr/bin/realpath
/usr/bin/tr
/usr/bin/xxd )
local cmd
for cmd in "${cmds[@]}"; do
if [[ -L "$cmd" ]]; then
printf 'Warning: system command %s is a symbolic link.\n' "$cmd" >&2
fi
done
}
# It resolves the command line arguments, storing them in an associative array
# using the long option names as the keys.
# Arguments:
# The first argument is the name of the associative array where the resolved.
# The remaining arguments hold the raw command line arguments to resolve.
map_args() {
local mapVar="$1"
shift
local opts
if ! opts="$(format_opts "$@")"; then
return 1
fi
eval set -- "$opts"
while true; do
case "$1" in
-h|--help)
eval "$mapVar""[help]=help"
shift
;;
-P|--port)
eval "$mapVar""[port]='$2'"
shift 2
;;
-\?|--usage)
eval "$mapVar""[usage]=usage"
shift
;;
-v|--verbose)
eval "$mapVar"'[verbose]=$(( ${'"$mapVar"'[verbose]} + 1 ))'
shift
;;
-V|--version)
eval "$mapVar""[version]=version"
shift
;;
--)
shift
break
;;
esac
done
if [[ "$#" -ge 1 ]]; then
eval "$mapVar""[host]='$1'"
fi
}
# formats the command line options like `getopt`
# Arguments:
# the raw command line arguments
# Globals:
# EXEC_NAME used to indicate the name of the program in error messages
# Output:
# It writes the command line arguments as generated by `getopt` to stdout.
format_opts() {
# getopt doesn't support "?" as a short option, so replace all instances of -?
# with --usage
local transArgs=()
local ai
for (( ai=1; ai<=$#; ai++ )); do
local arg="${!ai}"
if [[ "$arg" =~ ^-[^-] ]]; then
local shopts=''
local ci
for (( ci=1; ci<${#arg}; ci++ )); do
local c="${arg:$ci:1}"
if [[ "$c" == '?' ]]; then
if [[ -n "$shopts" ]]; then
transArgs+=( -"$shopts" )
shopts=''
fi
transArgs+=( --usage )
else
shopts+="$c"
fi
done
if [[ -n "$shopts" ]]; then
transArgs+=( -"$shopts" )
fi
else
transArgs+=( "$arg" )
fi
done
/usr/bin/getopt \
--name "$EXEC_NAME" \
--longoptions help,port:,service:,usage,verbose,version,zone: \
--options 'hP:S:VvZ:' \
-- "${transArgs[@]}"
}
# displays detailed help
# Output:
# the help text formatted to fit on an 80 character wide terminal
print_help() {
print_version
printf '\n'
print_usage
printf '\n'
print_description
}
# displays the program version in the format required of Nagios plugins
# Globals:
# EXEC_NAME indicates the program name in the version string
# VERSION indicates the version identifier in the version string
print_version() {
printf '%s v%s\n' "$EXEC_NAME" "$VERSION"
}
# attempt to connect to an iRODS server and time how long it takes to establish
# a connection
# Arguments:
# host the IP address or hostname of the server hosting iRODS
# port the TCP port the iRODS listens on
# Globals:
# CRITICAL return status when failed to connect to iRODS
# OK return status when connected to iRODS
# UNKNOWN return status when an error occurred or connected to something
# other than iRODS
# Output:
# it writes the status to stdout in a form interpretable by nagios. When the
# plugin successfully connects to iRODS, it provides the amount of time it took
# to connect as a performance datum in the form "time=<duration>s" where
# <duration> is the amount of time in seconds.
# Return:
# OK connected to iRODS
# CRITICAL failed to connect to iRODS
# UNKNOWN an error occurred or connected to something other than iRODS
ping() {
local host="$1"
local port="$2"
local startTime
startTime="$(/bin/date +%s.%N)"
if ! exec 3<>/dev/tcp/"$host"/"$port"; then
printf 'CRITICAL: down\n' || true
return $CRITICAL
fi
trap 'exec 3<&- || true; exec 3>&- || true; trap - RETURN' RETURN
if ! mk_req HEARTBEAT >&3; then
return $UNKNOWN
fi
local respMsg
respMsg="$(/bin/cat <&3)"
if [[ "$respMsg" != HEARTBEAT ]]; then
printf 'CRITICAL: not iRODS\n' || true
return $UNKNOWN
fi
local stopTime
stopTime="$(/bin/date +%s.%N)"
local dt
if [[ -n "$startTime" ]] && [[ -n "$stopTime" ]]; then
dt="$(printf '%s - %s\n' "$stopTime" "$startTime" | /usr/bin/bc)"
fi
local status='OK: up'
if [[ -n "${dt-}" ]]; then
printf -v status '%s | time=%.3fs' "$status" "$dt" || true
fi
printf '%s\n' "$status" || true
return $OK
}
# It creates an iRODS protocol request message.
# Arguments:
# type the message type
# msg optional the message body
# Output:
# It writes the serialized request to stdout.
mk_req() {
local msgType="$1"
local msg=''
if [[ $# -ge 2 ]]; then
msg="$2"
fi
local header
if ! header="$(mk_header "$msgType" ${#msg})"; then
return 1
fi
encode_header_len ${#header}
printf '%s%s' "$header" "$msg"
}
# It creates an iRODS protocol message header.
# Arguments:
# type the message type
# msgLen the message body length in bytes
# Output:
# It writes the message header to stdout.
mk_header() {
local type="$1"
local msgLen="$2"
/bin/cat <<EOX
<MsgHeader_PI>
<type>$type</type>
<msgLen>$msgLen</msgLen>
<errorLen>0</errorLen>
<bsLen>0</bsLen>
</MsgHeader_PI>
EOX
}
# It encodes the length of a serialized iRODS protocol packet header.
# Arguments:
# the header length to encode
# Output:
# the length encoded as 32 bit unsigned integer.
encode_header_len() {
local len="$1"
printf '0: %.8x' "$len" | /usr/bin/xxd -revert -g 0
}
# It decodes a serialized iRODS protocol packet header length as a decimal
# Input:
# the serialized length
# Output:
# the decimal value to stdout.
decode_header_len() {
local lenHex
if ! lenHex="$(decode_header_len_hex)"; then
return 1
fi
printf '%d' $(( 16#$lenHex ))
}
# It decodes a serialized iRODS protocol packet header length as a hexadecimal
# Input:
# the serialized length
# Output:
# the hexadecimal value to stdout.
decode_header_len_hex() {
if ! /usr/bin/od --address-radix n --format x1 --read-bytes 4 | /usr/bin/tr --delete ' '; then
return 1
fi
}
main "$@"