Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ Custom timeouts (`-t`) and retries (`-r`) can be specified by using `-t` and `-r
| storage | Detects and checks all disks (free, total, %) | if more used than w/c in % |
| update | Shows the current DSM version and if DSM update is available | if update is "Unavailable", will trigger OK <br> if update is "Available", will trigger WARNING <br> otherwise: UNKNOWN |
| status | Shows model, s/n, temp and status of system, fan, cpu fan and power supply | if temp higher than w/c in °C |
| raid | Shows raid volume status for every storage pool | WARNING for intermediate states (Repairing/Migrating/Expanding/Deleting/Creating/RaidSyncing/RaidParityChecking/RaidAssembling/Canceling); CRITICAL for Degrade and Crashed; OK for Normal |



Expand Down
68 changes: 62 additions & 6 deletions check_synology.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@
parser.add_argument("username", help="the snmp user name", type=str)
parser.add_argument("authkey", help="the auth key", type=str)
parser.add_argument("privkey", help="the priv key", type=str)
parser.add_argument("mode", help="the mode", type=str, choices=["load", "memory", "disk", "storage", "update", "status"])
parser.add_argument("-w", help="warning value for selected mode", type=int)
parser.add_argument("-c", help="critical value for selected mode", type=int)
parser.add_argument("mode", help="the mode", type=str, choices=["load", "memory", "disk", "storage", "update", "status", "raid"])
parser.add_argument("-w", help="warning value for selected mode (storage mode: PERC_USED, warn if used > N)", type=int)
parser.add_argument("-c", help="critical value for selected mode (storage mode: PERC_USED, crit if used > N)", type=int)
parser.add_argument("--warning-free", help="storage mode only: PERC_FREE, warn if free < N (matches check_disk -w convention; takes precedence over -w if both set)", type=str, default=None, dest="warning_free")
parser.add_argument("--critical-free", help="storage mode only: PERC_FREE, crit if free < N (matches check_disk -c convention; takes precedence over -c if both set)", type=str, default=None, dest="critical_free")
parser.add_argument("-p", help="the snmp port", type=int, dest="port", default=161)
parser.add_argument("-e", help="SNMP privacy protocol encryption", type=str, default="AES128", choices=["AES128", "DES"])
parser.add_argument("-t", help="timeout for snmp connection", type=int, default=10)
Expand All @@ -32,6 +34,17 @@
mode = args.mode
warning = args.w
critical = args.c

def _parse_pct(s):
"""Strip optional '%' and whitespace, convert to int. None → None."""
if s is None:
return None
return int(str(s).strip().rstrip('%').strip())

warning_free = _parse_pct(args.warning_free)
critical_free = _parse_pct(args.critical_free)
if (warning_free is not None and warning is not None) or (critical_free is not None and critical is not None):
print("check_synology: both -w/-c and --warning-free/--critical-free given; using free thresholds", file=sys.stderr)
priv_protocol = args.e
snmp_timeout = args.t
snmp_retries = args.r
Expand Down Expand Up @@ -225,15 +238,25 @@ def exitCode():
continue

storage_used_percent = int(storage_used * 100 / storage_size)
storage_free_percent = 100 - storage_used_percent

if warning and warning < int(storage_used_percent):
# Free-percent (PERC_FREE) wins; falls back to upstream -w/-c PERC_USED.
if warning_free is not None:
if storage_free_percent < warning_free and state != 'CRITICAL':
state = 'WARNING'
elif warning and warning < storage_used_percent:
if state != 'CRITICAL':
state = 'WARNING'
if critical and critical < int(storage_used_percent):

if critical_free is not None:
if storage_free_percent < critical_free:
state = 'CRITICAL'
elif critical and critical < storage_used_percent:
state = 'CRITICAL'

output += ' - free space: ' + storage_name + ' ' + str(storage_free) + ' GB (' + str(storage_used) + ' GB of ' + str(storage_size) + ' GB used, ' + str(storage_used_percent) + '%)'
perfdata += storage_name + '=' + str(storage_used) + 'c '
# Perfdata format: value;warn;crit;min;max — max=storage_size enables disk_forecast (.max series in Graphite).
perfdata += storage_name + '=' + str(storage_used) + 'c;;;0;' + str(storage_size) + ' '
print('%s%s %s' % (state, output, perfdata))
exitCode()

Expand Down Expand Up @@ -302,3 +325,36 @@ def exitCode():
# 3. Respond with textual and perfdata output and propagate exit code.
print(state + ' - Model: %s, S/N: %s, System Temperature: %s C, System Status: %s, System Fan: %s, CPU Fan: %s, Powersupply : %s' % (status_model, status_serial, status_temperature, status_system, status_system_fan, status_cpu_fan, status_power) + ' | system_temp=%sc' % status_temperature)
exitCode()

if mode == 'raid':
output = ''
perfdata = '|'
# Synology raid status values (from synology MIB).
# 1 = Normal — the raid functions normally.
# 2 = Repairing
# 3 = Migrating
# 4 = Expanding
# 5 = Deleting
# 6 = Creating
# 7 = RaidSyncing
# 8 = RaidParityChecking
# 9 = RaidAssembling
# 10 = Canceling
# 11 = Degrade — a tolerable disk failure has occurred (still actionable).
# 12 = Crashed — raid is in read-only state.
WARNING_STATUSES = {"2", "3", "4", "5", "6", "7", "8", "9", "10"}
CRITICAL_STATUSES = {"11", "12"} # 11 = Degrade, 12 = Crashed
for item in snmpwalk('1.3.6.1.4.1.6574.3.1.1.1'):
i = item.oid_index or item.oid.split('.')[-1]
storage_name = snmpget('1.3.6.1.4.1.6574.3.1.1.2.' + str(i))
raid_status = str(snmpget('1.3.6.1.4.1.6574.3.1.1.3.' + str(i)))
if raid_status in CRITICAL_STATUSES:
state = "CRITICAL"
elif raid_status in WARNING_STATUSES and state != "CRITICAL":
state = "WARNING"
elif raid_status != "1" and state == "OK":
state = "UNKNOWN"
output += ' - raid status: [' + storage_name + '] status=' + raid_status
perfdata += ' "' + storage_name + '"=' + raid_status
print('%s%s %s' % (state, output, perfdata))
exitCode()