#!/usr/bin/env python3
import argparse
import subprocess
import sys
import time
import signal
STATUS_OK = 0
STATUS_WARNING = 1
STATUS_CRITICAL = 2
STATUS_UNKNOWN = 3
TIMEOUT_SECONDS = 60
def handle_timeout(signum, frame):
print(f"UNKNOWN - Script timed out after {TIMEOUT_SECONDS} seconds")
sys.exit(STATUS_UNKNOWN)
def snmpget(oid, args):
cmd = [
"snmpget", "-v3", "-u", args.user,
"-a", args.auth_proto, "-A", args.auth_pass,
"-x", args.priv_proto, "-X", args.priv_pass,
"-l", "authPriv", args.host, oid, "-Ovq"
]
try:
out = subprocess.check_output(cmd, stderr=subprocess.DEVNULL, text=True).strip()
if args.debug:
print(f"DEBUG: snmpget {oid} → {out}")
return out
except:
return ""
def snmpwalk(oid, args):
cmd = [
"snmpwalk", "-v3", "-u", args.user,
"-a", args.auth_proto, "-A", args.auth_pass,
"-x", args.priv_proto, "-X", args.priv_pass,
"-l", "authPriv", args.host, oid, "-Ovq"
]
try:
out = subprocess.check_output(cmd, stderr=subprocess.DEVNULL, text=True).splitlines()
if args.debug:
print(f"DEBUG: snmpwalk {oid} → {out}")
return out
except:
return []
def main():
global TIMEOUT_SECONDS
parser = argparse.ArgumentParser(description="SNMP CPU Usage Checker")
parser.add_argument("-H", "--host", required=True)
parser.add_argument("-u", "--user", required=True)
parser.add_argument("-a", "--auth_pass", required=True)
parser.add_argument("-p", "--priv_pass", required=True)
parser.add_argument("-A", "--auth_proto", required=True, choices=["MD5", "SHA"])
parser.add_argument("-X", "--priv_proto", required=True, choices=["DES", "AES"])
parser.add_argument("-w", "--warning", type=float, default=60)
parser.add_argument("-c", "--critical", type=float, default=80)
parser.add_argument("--timeout", type=int, default=60)
parser.add_argument("--debug", action="store_true")
args = parser.parse_args()
TIMEOUT_SECONDS = args.timeout
signal.signal(signal.SIGALRM, handle_timeout)
signal.alarm(TIMEOUT_SECONDS)
sysdescr = snmpget("1.3.6.1.2.1.1.1.0", args)
if not sysdescr:
print("UNKNOWN - Unable to retrieve sysDescr")
sys.exit(STATUS_UNKNOWN)
if args.debug:
print(f"DEBUG: sysDescr → {sysdescr}")
status = STATUS_OK
summary = []
if "BIG-IP" in sysdescr:
# F5 BIG-IP
OID_TOTAL = "1.3.6.1.4.1.3375.2.1.1.2.1.41"
OID_IDLE = "1.3.6.1.4.1.3375.2.1.1.2.1.42"
OID_SLEEP = "1.3.6.1.4.1.3375.2.1.1.2.1.43"
t1 = list(map(int, snmpwalk(OID_TOTAL, args)))
i1 = list(map(int, snmpwalk(OID_IDLE, args)))
s1 = list(map(int, snmpwalk(OID_SLEEP, args)))
time.sleep(2)
t2 = list(map(int, snmpwalk(OID_TOTAL, args)))
i2 = list(map(int, snmpwalk(OID_IDLE, args)))
s2 = list(map(int, snmpwalk(OID_SLEEP, args)))
if not (t1 and t2):
print("UNKNOWN - Unable to retrieve F5 CPU counters")
sys.exit(STATUS_UNKNOWN)
for i in range(min(len(t1), len(t2))):
dt = t2[i] - t1[i]
di = i2[i] - i1[i]
ds = s2[i] - s1[i]
du = dt - di - ds
usage = round((du / dt) * 100, 2) if dt > 0 else 0
summary.append(f"TMM_CPU[{i}]={usage}%")
if usage >= args.critical:
status = STATUS_CRITICAL
elif usage >= args.warning and status < STATUS_CRITICAL:
status = STATUS_WARNING
else:
# Cisco device
CPU_OID = "1.3.6.1.4.1.9.9.109.1.1.1.1.7"
cpu_output = snmpwalk(CPU_OID, args)
if not cpu_output:
print("UNKNOWN - Unable to retrieve Cisco CPU usage")
sys.exit(STATUS_UNKNOWN)
for line in cpu_output:
parts = line.strip().split()
if len(parts) < 2:
continue
value = parts[-1]
index = parts[0].split(".")[-1]
if value.isdigit():
val = int(value)
summary.append(f"CPU[{index}]={val}%")
if val >= args.critical:
status = STATUS_CRITICAL
elif val >= args.warning and status < STATUS_CRITICAL:
status = STATUS_WARNING
status_text = ["OK", "WARNING", "CRITICAL", "UNKNOWN"][status]
print(f"{status_text} - {'; '.join(summary)}")
sys.exit(status)
if __name__ == "__main__":
main()