/usr/share/check_mk/checks/drbd is in check-mk-server 1.2.6p12-1.
This file is owned by root:root, with mode 0o755.
The actual contents of the file can be viewed below.
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 | #!/usr/bin/python
# -*- encoding: utf-8; py-indent-offset: 4 -*-
# +------------------------------------------------------------------+
# | ____ _ _ __ __ _ __ |
# | / ___| |__ ___ ___| | __ | \/ | |/ / |
# | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / |
# | | |___| | | | __/ (__| < | | | | . \ |
# | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ |
# | |
# | Copyright Mathias Kettner 2014 mk@mathias-kettner.de |
# +------------------------------------------------------------------+
#
# This file is part of Check_MK.
# The official homepage is at http://mathias-kettner.de/check_mk.
#
# check_mk is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation in version 2. check_mk is distributed
# in the hope that it will be useful, but WITHOUT ANY WARRANTY; with-
# out even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE. See the GNU General Public License for more de-
# ails. You should have received a copy of the GNU General Public
# License along with GNU Make; see the file COPYING. If not, write
# to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
# Boston, MA 02110-1301 USA.
# Author: Lars Michelsen <lm@mathias-kettner.de>
# Example outputs from agent:
#
# While syncing:
# <<<drbd>>>
# version: 8.3.8 (api:88/proto:86-94)
# GIT-hash: d78846e52224fd00562f7c225bcc25b2d422321d build by cssint@erzc20, 2010-06-17 14:47:26
# 0: cs:SyncSource ro:Primary/Secondary ds:UpToDate/Inconsistent C r----
# ns:12031428 nr:0 dw:12031364 dr:1175992347 al:2179 bm:71877 lo:37 pe:0 ua:37 ap:0 ep:1 wo:b oos:301729988
# [=======>............] sync'ed: 42.4% (294656/510908)M delay_probe: 145637
# finish: 1:23:28 speed: 60,172 (51,448) K/sec
#
# Sync stalled:
# <<<drbd>>>
# b01srv05:~ # cat /proc/drbd
# version: 8.3.8 (api:88/proto:86-94)
# GIT-hash: d78846e52224fd00562f7c225bcc25b2d422321d build by cssint@erzc20, 2010-06-17 14:47:26
# 0: cs:SyncSource ro:Primary/Secondary ds:UpToDate/Inconsistent C r----
# ns:11545876 nr:0 dw:11545900 dr:954551211 al:1955 bm:58360 lo:0 pe:0 ua:0 ap:0 ep:1 wo:b oos:523171100
# [>....................] sync'ed: 0.1% (510908/510908)M delay_probe: 135599
# stalled
#
# Synced:
# <<<drbd>>>
# version: 8.3.8 (api:88/proto:86-94)
# GIT-hash: d78846e52224fd00562f7c225bcc25b2d422321d build by cssint@erzc20, 2010-06-17 14:47:26
# 0: cs:Connected ro:Primary/Secondary ds:UpToDate/UpToDate C r----
# ns:12227928 nr:0 dw:12227864 dr:1477722351 al:2300 bm:90294 lo:0 pe:0 ua:0 ap:0 ep:1 wo:b oos:0
# Description of the /proc/drbd output:
# http://www.drbd.org/users-guide/ch-admin.html#s-proc-drbd
#
# The information from /proc/drbd are grouped as followed (Extracted from doc above)
#
# General:
# cs (connection state). Status of the network connection. See the section called
# “Connection states” for details about the various connection states.
# Available States:
# StandAlone. No network configuration available. The resource has not yet been connected,
# or has been administratively disconnected (using drbdadm disconnect),
# or has dropped its connection due to failed authentication or split brain.
# Disconnecting. Temporary state during disconnection. The next state is StandAlone.
# Unconnected. Temporary state, prior to a connection attempt.
# Possible next states: WFConnection and WFReportParams.
# Timeout. Temporary state following a timeout in the communication with the peer. Next state: Unconnected.
# BrokenPipe. Temporary state after the connection to the peer was lost. Next state: Unconnected.
# NetworkFailure. Temporary state after the connection to the partner was lost. Next state: Unconnected.
# ProtocolError. Temporary state after the connection to the partner was lost. Next state: Unconnected.
# TearDown. Temporary state. The peer is closing the connection. Next state: Unconnected.
# WFConnection. This node is waiting until the peer node becomes visible on the network.
# WFReportParams. TCP connection has been established, this node waits for the first network packet from the peer.
# Connected. A DRBD connection has been established, data mirroring is now active. This is the normal state.
# StartingSyncS. Full synchronization, initiated by the administrator, is just starting.
# The next possible states are: SyncSource or PausedSyncS.
# StartingSyncT. Full synchronization, initiated by the administrator, is just starting. Next state: WFSyncUUID.
# WFBitMapS. Partial synchronization is just starting. Next possible states: SyncSource or PausedSyncS.
# WFBitMapT. Partial synchronization is just starting. Next possible state: WFSyncUUID.
# WFSyncUUID. Synchronization is about to begin. Next possible states: SyncTarget or PausedSyncT.
# SyncSource. Synchronization is currently running, with the local node being the source of synchronization.
# SyncTarget. Synchronization is currently running, with the local node being the target of synchronization.
# PausedSyncS. The local node is the source of an ongoing synchronization, but synchronization is currently paused.
# This may be due to a dependency on the completion of another synchronization process,
# or due to synchronization having been manually interrupted by drbdadm pause-sync.
# PausedSyncT. The local node is the target of an ongoing synchronization, but synchronization
# is currently paused. This may be due to a dependency on the completion of another
# synchronization process, or due to synchronization having been manually interrupted by drbdadm pause-sync.
# VerifyS. On-line device verification is currently running, with the local node being the source of verification.
# VerifyT. On-line device verification is currently running, with the local node being the target of verification.
#
# ro (roles). Roles of the nodes. The role of the local node is displayed first, followed by the role of the partner
# node shown after the slash. See the section called “Resource roles” for details about the possible resource roles.
# Available Roles:
# Primary. The resource is currently in the primary role, and may be read from and written to.
# This role only occurs on one of the two nodes, unless dual-primary node is enabled.
# Secondary. The resource is currently in the secondary role. It normally receives updates
# from its peer (unless running in disconnected mode), but may neither be read from
# nor written to. This role may occur on one node or both nodes.
# Unknown. The resource's role is currently unknown. The local resource role never has this status.
# It is only displayed for the peer's resource role, and only in disconnected mode.
#
# ds (disk states). State of the hard disks. Prior to the slash the state of the local node is displayed,
# after the slash the state of the hard disk of the partner node is shown.
# See the section called “Disk states” for details about the various disk states.
# Disk States:
# Diskless. No local block device has been assigned to the DRBD driver. This may mean that the resource
# has never attached to its backing device, that it has been manually detached using drbdadm detach
# or that it automatically detached after a lower-level I/O error.
# Attaching. Transient state while reading meta data.
# Failed. Transient state following an I/O failure report by the local block device. Next state: Diskless.
# Negotiating. Transient state when an Attach is carried out on an already-connected DRBD device.
# Inconsistent. The data is inconsistent. This status occurs immediately upon creation of a new resource,
# on both nodes (before the initial full sync). Also, this status is found in one node
# (the synchronization target) during synchronization.
# Outdated. Resource data is consistent, but outdated.
# DUnknown. This state is used for the peer disk if no network connection is available.
# Consistent. Consistent data of a node without connection. When the connection
# is established, it is decided whether the data are UpToDate or Outdated.
# UpToDate. Consistent, up-to-date state of the data. This is the normal state.
#
# Network:
# ns (network send). Volume of net data sent to the partner via the network connection; in Kibyte.
# nr (network receive). Volume of net data received by the partner via the network connection; in Kibyte.
# Disk:
# dw (disk write). Net data written on local hard disk; in Kibyte.
# dr (disk read). Net data read from local hard disk; in Kibyte.
# Stats:
# al (activity log). Number of updates of the activity log area of the meta data.
# bm (bit map). Number of updates of the bitmap area of the meta data.
# lo (local count). Number of open requests to the local I/O sub-system issued by DRBD.
# pe (pending). Number of requests sent to the partner, but that have not yet been answered by the latter.
# ua (unacknowledged). Number of requests received by the partner via the network connection, but that have not yet been answered.
# ap (application pending). Number of block I/O requests forwarded to DRBD, but not yet answered by DRBD.
# ep (epochs). Number of epoch objects. Usually 1. Might increase under I/O load
# when using either the barrier or the none write ordering method. Since 8.2.7.
# wo (write order). Currently used write ordering method: b (barrier), f (flush), d (drain) or n (none). Since 8.2.7.
# oos (out of sync). Amount of storage currently out of sync; in Kibibytes. Since 8.2.6.
# Default thresholds for drbd checks
drbd_net_default_levels = ( None, None )
drbd_disk_default_levels = ( None, None )
drbd_stats_default_levels = ( None, None, None, None, None, None, None, None, None )
_drbd_block_start_match = re.compile('^[0-9]+:')
drbd_general_map = [ 'cs', 'ro', 'ds' ]
drbd_net_map = [ 'cs', 'ns', 'nr' ]
drbd_disk_map = [ 'cs', 'dw', 'dr' ]
drbd_stats_map = [ 'cs', 'al', 'bm', 'lo', 'pe', 'ua', 'ap', 'ep', 'wo', 'oos' ]
drbd_cs_map = {
'StandAlone': 1, 'Disconnecting': 1,
'Unconnected': 2, 'Timeout': 2,
'BrokenPipe': 2, 'NetworkFailure': 2,
'ProtocolError': 2, 'TearDown': 2,
'WFConnection': 2, 'WFReportParams': 1,
'Connected': 0, 'StartingSyncS': 1,
'StartingSyncT': 1, 'WFBitMapS': 1,
'WFBitMapT': 1, 'WFSyncUUID': 1,
'SyncSource': 1, 'SyncTarget': 1,
'PausedSyncS': 1, 'PausedSyncT': 1,
'VerifyS': 0, 'VerifyT': 0,
'Ahead': 1, 'Behind': 1,
}
drbd_ds_map = {
"primary_Diskless": 2, "secondary_Diskless": 2,
"primary_Attaching": 2, "secondary_Attaching": 2,
"primary_Failed": 2, "secondary_Failed": 2,
"primary_Negotiating": 2, "secondary_Negotiating": 2,
"primary_Inconsistent": 1, "secondary_Inconsistent": 1,
"primary_Outdated": 2, "secondary_Outdated": 2,
"primary_DUnknown": 2, "secondary_DUnknown": 2,
"primary_Consistent": 2, "secondary_Consistent": 2,
"primary_UpToDate": 0, "secondary_UpToDate": 0,
}
def inventory_drbd(info, checktype):
inventory = []
for line in info[2:]:
if _drbd_block_start_match.search(line[0]) > 0:
parsed = drbd_parse_block(drbd_extract_block('drbd%s' % line[0][:-1], info), checktype)
# Skip unconfigured drbd devices
if parsed['cs'] == 'Unconfigured':
continue
if checktype == 'drbd':
if 'ro' not in parsed or 'ds' not in parsed:
continue
levels = {
"roles_inventory": parsed['ro'],
"diskstates_inventory": parsed['ds'],
}
elif checktype == 'drbd.net':
levels = "drbd_net_default_levels"
elif checktype == 'drbd.disk':
levels = "drbd_disk_default_levels"
elif checktype == 'drbd.stats':
levels = "drbd_stats_default_levels"
inventory.append(('drbd%s' % line[0][:-1], levels))
return inventory
def drbd_parse_block(block, to_parse):
parsed = {}
for line in block:
for field in line:
parts = field.split(':')
if len(parts) > 1:
# Only parse the requested information depending on the check
# to be executed now
if to_parse == 'drbd' and parts[0] in drbd_general_map:
if parts[0] in [ 'ro', 'ds' ]:
parsed[parts[0]] = parts[1].split('/')
else:
parsed[parts[0]] = parts[1]
elif to_parse == 'drbd.net' and parts[0] in drbd_net_map:
parsed[parts[0]] = parts[1]
elif to_parse == 'drbd.disk' and parts[0] in drbd_disk_map:
parsed[parts[0]] = parts[1]
elif to_parse == 'drbd.stats' and parts[0] in drbd_stats_map:
parsed[parts[0]] = parts[1]
return parsed
def drbd_extract_block(item, info):
block = []
inBlock = False
# Ignore the first two lines since they contain drbd version information
for line in info[2:]:
if "drbd" + line[0][:-1] == item:
inBlock = True
elif inBlock and _drbd_block_start_match.search(line[0]) > 0 \
and "drbd" + line[0][:-1] != item:
# Another block starts. So the requested block is finished
break
# Skip unwanted lines
if not inBlock:
continue
# If this is reached we are in the wanted block
block.append(line)
return block
def drbd_get_block(item, info, checktype):
block = drbd_extract_block(item, info)
if len(block) > 0:
return drbd_parse_block(block, checktype)
else:
return None
def check_drbd_general(item, params, info):
parsed = drbd_get_block(item, info, 'drbd')
if type(params) == tuple:
params_conv = {}
params_conv.update({ "roles_inventory": params[0] and params[0] or None })
params_conv.update({ "diskstates_inventory": (params[0] and params[1]) and params[1] or None})
params = params_conv
if not parsed is None:
if parsed['cs'] == 'Unconfigured':
return (2, 'The device is "Unconfigured"')
elif not parsed['cs'] in drbd_cs_map:
return (3, 'Undefined "connection state" in drbd output')
# Weight of connection state is calculated by the drbd_cs_map.
# The roles and disk states are calculated using the expected values
state = drbd_cs_map[parsed['cs']]
output = 'Connection State: %s' % parsed['cs']
# Roles
output += ', Roles: %s/%s' % tuple(parsed['ro'])
current_roles = "_".join(map(str.lower, parsed["ro"]))
found_role_match = False
if "roles" in params:
roles = params.get("roles")
if roles:
for roles_entry, roles_state in roles:
if roles_entry == current_roles:
found_role_match = True
state = max(state, roles_state)
output += ' %s' % state_markers[roles_state]
break
else: # Ignore roles if set to None
found_role_match = True
if not found_role_match:
if "roles_inventory" in params:
roles_inventory = params.get("roles_inventory")
if roles_inventory and parsed["ro"] != roles_inventory:
state = max(2, state)
output += ' (Expected: %s/%s)' % tuple(params.get("roles_inventory"))
else:
state = max(3, state)
output += ' (Check requires a new service discovery)'
output += ', Diskstates: %s/%s' % tuple(parsed['ds'])
# Do not evaluate diskstates. Either set by rule or through the
# legacy configuration option None in the check parameters tuple
if "diskstates" in params and params["diskstates"] == None or \
"diskstates_inventory" in params and params["diskstates_inventory"] == None:
return (state, output)
params_diskstates_dict = dict(params.get("diskstates", []))
diskstates_info = set()
for ro, ds in [ (parsed["ro"][0], parsed["ds"][0]), (parsed["ro"][1], parsed["ds"][1]) ]:
diskstate = "%s_%s" % (ro.lower(), ds)
params_diskstate = params_diskstates_dict.get(diskstate)
if params_diskstate != None:
state = max(state, params_diskstate)
diskstates_info.add('%s/%s is %s' % (ro, ds, state_markers[params_diskstate]))
else:
default_state = drbd_ds_map.get(diskstate, 3)
if default_state > 0:
diskstates_info.add('%s/%s is %s' % (ro, ds, state_markers[default_state]))
state = max(state, drbd_ds_map.get(diskstate, 3))
if diskstates_info:
output += " (%s)" % ", ".join(diskstates_info)
return (state, output)
return (3, "Undefined state")
check_info["drbd"] = {
'inventory_function' : lambda info: inventory_drbd(info, "drbd"),
'check_function' : check_drbd_general,
'group' : 'drbd',
'has_perfdata' : True,
'service_description' : 'DRBD %s status',
}
def drbd_get_rates(list):
now = time.time()
output = ''
perfdata = []
for type, name, item, value, uom in list:
rate = get_rate("%s.%s.%s" % (type, name, item), now, value)
perfdata.append((name, rate))
output += ' %s/sec: %s%s' % (name, rate, uom)
return (output, perfdata)
def check_drbd_net(item, params, info):
parsed = drbd_get_block(item, info, 'drbd.net')
if not parsed is None:
if parsed['cs'] == 'Unconfigured':
return (2, 'The device is "Unconfigured"')
output, perfdata = drbd_get_rates([ ('drbd.net', 'in', item, int(parsed['nr']), 'kb'),
('drbd.net', 'out', item, int(parsed['ns']), 'kb') ])
# FIXME: Maybe handle thresholds in the future
return (0, output, perfdata)
return (3, "Undefined state")
check_info["drbd.net"] = {
'inventory_function' : lambda info: inventory_drbd(info, "drbd.net"),
'check_function' : check_drbd_net,
'group' : 'drbd.net',
'has_perfdata' : True,
'service_description' : 'DRBD %s net',
}
def check_drbd_disk(item, params, info):
parsed = drbd_get_block(item, info, 'drbd.disk')
if not parsed is None:
if parsed['cs'] == 'Unconfigured':
return (2, 'The device is "Unconfigured"')
output, perfdata = drbd_get_rates([ ('drbd.disk', 'write', item, int(parsed['dw']), 'kb'),
('drbd.disk', 'read', item, int(parsed['dr']), 'kb') ])
# FIXME: Maybe handle thresholds in the future
return (0, output, perfdata)
return (3, "Undefined state")
check_info["drbd.disk"] = {
'inventory_function' : lambda info: inventory_drbd(info, "drbd.disk"),
'check_function' : check_drbd_disk,
'group' : 'drbd.disk',
'has_perfdata' : True,
'service_description' : 'DRBD %s disk',
}
def check_drbd_stats(item, params, info):
parsed = drbd_get_block(item, info, 'drbd.stats')
if not parsed is None:
if parsed['cs'] == 'Unconfigured':
return (2, 'The device is "Unconfigured"')
output = ''
perfdata = []
for key, label in [ ('al', 'activity log updates'), ('bm', 'bit map updates'),
('lo', 'local count requests'), ('pe', 'pending requests'),
('ua', 'unacknowledged requests'), ('ap', 'application pending requests'),
('ep', 'epoch objects'), ('wo', 'write order'),
('oos', 'kb out of sync') ]:
if key in parsed:
output += '%s: %s, ' % (label, parsed[key])
else:
parsed[key] = '0' # perfdata must always have same number of entries
if parsed[key].isdigit():
perfdata.append(('%s' % label.replace(" ", "_"), parsed[key]))
return (0, output.rstrip(', '), perfdata)
return (3, "Undefined state")
check_info["drbd.stats"] = {
'inventory_function' : lambda info: inventory_drbd(info, "drbd.stats"),
'check_function' : check_drbd_stats,
'group' : 'drbd.stats',
'has_perfdata' : True,
'service_description' : 'DRBD %s stats',
}
|