apc_snmp_shutdown/shutdown_ups.py

109 lines
3.9 KiB
Python
Raw Normal View History

2024-08-13 04:42:02 +03:00
#!/usr/bin/env python3
2024-08-13 18:32:24 +03:00
2024-08-13 04:18:53 +03:00
import subprocess
import time
import socket
import os
2024-08-13 04:39:38 +03:00
2024-08-13 18:32:24 +03:00
UPS_IP = "10.31.41.46"
TIME_THRESHOLD = 6
INTERVAL_LINE = 60
INTERVAL_BATTERY = 5
OID_ON_BATTERY_TIME = "1.3.6.1.4.1.318.1.1.1.2.2.3.0"
OID_STATES = "1.3.6.1.4.1.318.1.1.1.11.1.1.0"
OID_BATTERY_PERCENT = "1.3.6.1.4.1.318.1.1.1.2.2.1.0"
2024-08-13 04:18:53 +03:00
def parse_time(time_str):
2024-08-13 18:32:24 +03:00
if time_str == "" or time_str is None:
return None
2024-08-13 04:18:53 +03:00
try:
time_parts = time_str.split(":")[-4:]
days = int(time_parts[0])
hours = int(time_parts[1])
minutes = int(time_parts[2])
seconds = float(time_parts[3])
2024-08-13 18:32:24 +03:00
return (days * 24 * 60) + (hours * 60) + minutes + (int(seconds // 60))
except Exception as e:
print(f"Error parsing time: {e}")
return None
2024-08-13 04:18:53 +03:00
def send_email(recipient, subject, body, sender):
email_message = f"Subject: {subject}\nFrom: {sender}\nTo: {recipient}\n\n{body}"
process = os.popen('/usr/sbin/sendmail -t', 'w')
process.write(email_message)
process.close()
def parse_states(states_str):
2024-08-13 18:32:24 +03:00
states_str = states_str.strip('"')
if states_str == "": return "Invalid input"
if len(states_str) < 64: return "Invalid input"
if states_str[1] == '0': return "on-line"
if states_str[1] == '1': return "on-battery"
return "Invalid input"
2024-08-13 04:18:53 +03:00
def run_command(command):
2024-08-13 18:32:24 +03:00
result = subprocess.run(f"{command}", shell=True,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
text=True, check=False)
data = result.stdout.strip()
if "No such file or directory" in data:
print(f"Error: {data}", flush=True)
return None
2024-08-13 04:18:53 +03:00
return result.stdout.strip()
2024-08-13 18:32:24 +03:00
def snmp_get(oid):
result = run_command(f'/usr/bin/snmpget -v2c -O v -O q -c public {UPS_IP} {oid}')
if result is None or result == "":
return None
if "Timeout" in result:
print(f"UPS {UPS_IP} OID {oid} is unreachable, skipping...", flush=True)
return None
if "No Such Instance" in result:
print(f"UPS {UPS_IP} OID {oid} not found, skipping...", flush=True)
return None
if "No Such Object" in result:
print(f"UPS {UPS_IP} OID {oid} not found, skipping...", flush=True)
return None
if "No response" in result:
print(f"UPS {UPS_IP} OID {oid} not response, skipping...", flush=True)
return None
return result
2024-08-13 04:39:38 +03:00
def main():
2024-08-13 18:32:24 +03:00
state = "on-line"
2024-08-13 04:26:50 +03:00
while True:
2024-08-13 18:32:24 +03:00
if state == "on-battery": time.sleep(INTERVAL_BATTERY)
if state == "on-line": time.sleep(INTERVAL_LINE)
result = snmp_get(OID_ON_BATTERY_TIME)
if result is None: continue
2024-08-13 04:26:50 +03:00
time_on_battery = parse_time(result)
2024-08-13 18:32:24 +03:00
result = snmp_get(OID_STATES)
if result is None: continue
state = parse_states(result)
2024-08-13 04:18:53 +03:00
2024-08-13 18:32:24 +03:00
result = snmp_get(OID_BATTERY_PERCENT)
if result is None: continue
battery_percent = int(result)
2024-08-13 04:18:53 +03:00
2024-08-13 18:52:03 +03:00
print(f"Batterry {battery_percent}%, {state}, estimated time on battery: {time_on_battery} minutes", flush=True)
2024-08-13 18:32:24 +03:00
shutdown_status = run_command('shutdown --show')
2024-08-13 05:11:02 +03:00
2024-08-13 18:32:24 +03:00
if (state == "on-battery") and (time_on_battery > TIME_THRESHOLD) and ("No scheduled shutdown" in shutdown_status):
2024-08-13 05:11:02 +03:00
print("UPS is failing, shutting down in 60 seconds...", flush=True)
2024-08-13 18:32:24 +03:00
send_email(f"{socket.gethostname()}@vvzvlad.xyz", "UPS is failing, shutting down in 60 seconds...",
f"Proxmox node '{socket.gethostname()}': UPS is failing, shutting down in 60 seconds...",
f"{socket.gethostname()}@vvzvlad.xyz")
run_command('shutdown -h 3 "Shutting down due to UPS failure"')
2024-08-13 05:11:02 +03:00
if (state == "on-line") and ("Shutdown scheduled" in shutdown_status):
print("UPS is back online, cancelling shutdown...", flush=True)
2024-08-13 18:32:24 +03:00
run_command('shutdown -c')
2024-08-13 04:26:50 +03:00
if __name__ == "__main__":
2024-08-13 04:49:09 +03:00
print("Starting UPS monitoring...", flush=True)
2024-08-13 04:39:38 +03:00
main()