mirror of
https://github.com/bashclub/check-opnsense.git
synced 2024-12-25 00:10:11 +01:00
Update opnsense_checkmk_agent.py
0.69
This commit is contained in:
parent
e9174e7f9d
commit
f6175d5832
@ -22,7 +22,7 @@
|
||||
## copy to /usr/local/etc/rc.syshook.d/start/99-checkmk_agent and chmod +x
|
||||
##
|
||||
|
||||
__VERSION__ = "0.67"
|
||||
__VERSION__ = "0.69"
|
||||
|
||||
import sys
|
||||
import os
|
||||
@ -84,7 +84,7 @@ class checkmk_checker(object):
|
||||
_certificate_timestamp = 0
|
||||
_datastore_mutex = threading.RLock()
|
||||
_datastore = object_dict()
|
||||
def do_checks(self):
|
||||
def do_checks(self,debug=False):
|
||||
self._getosinfo()
|
||||
_errors = []
|
||||
_lines = ["<<<check_mk>>>"]
|
||||
@ -105,6 +105,7 @@ class checkmk_checker(object):
|
||||
except:
|
||||
_errors.append(traceback.format_exc())
|
||||
_lines.append("")
|
||||
if debug:
|
||||
sys.stderr.write("\n".join(_errors))
|
||||
sys.stderr.flush()
|
||||
return "\n".join(_lines)
|
||||
@ -334,8 +335,8 @@ class checkmk_checker(object):
|
||||
_sock = None
|
||||
return ""
|
||||
|
||||
def _get_openvpn_traffic(self,interface,totalbytesin,totalbytesout):
|
||||
_hist_data = self._get_storedata("openvpn",interface)
|
||||
def _get_traffic(self,modul,interface,totalbytesin,totalbytesout):
|
||||
_hist_data = self._get_storedata(modul,interface)
|
||||
_slot = int(time.time())
|
||||
_slot -= _slot%60
|
||||
_hist_slot = 0
|
||||
@ -345,7 +346,7 @@ class checkmk_checker(object):
|
||||
_traffic_in = int(totalbytesin -_hist_bytesin) / max(1,_slot - _hist_slot)
|
||||
_traffic_out = int(totalbytesout - _hist_bytesout) / max(1,_slot - _hist_slot)
|
||||
if _hist_slot != _slot:
|
||||
self._set_storedata("openvpn",interface,(_slot,totalbytesin,totalbytesout))
|
||||
self._set_storedata(modul,interface,(_slot,totalbytesin,totalbytesout))
|
||||
return _traffic_in,_traffic_out
|
||||
|
||||
@staticmethod
|
||||
@ -434,7 +435,7 @@ class checkmk_checker(object):
|
||||
_unix = "/var/etc/openvpn/{type}{vpnid}.sock".format(**_server)
|
||||
try:
|
||||
|
||||
_server["bytesin"], _server["bytesout"] = self._get_openvpn_traffic(
|
||||
_server["bytesin"], _server["bytesout"] = self._get_traffic("openvpn",
|
||||
"SRV_{name}".format(**_server),
|
||||
*(map(lambda x: int(x),re.findall("bytes\w+=(\d+)",self._read_from_openvpnsocket(_unix,"load-stats"))))
|
||||
)
|
||||
@ -468,7 +469,7 @@ class checkmk_checker(object):
|
||||
_unix = "/var/etc/openvpn/{type}{vpnid}.sock".format(**_server)
|
||||
try:
|
||||
|
||||
_server["bytesin"], _server["bytesout"] = self._get_openvpn_traffic(
|
||||
_server["bytesin"], _server["bytesout"] = self._get_traffic("openvpn",
|
||||
"SRV_{name}".format(**_server),
|
||||
*(map(lambda x: int(x),re.findall("bytes\w+=(\d+)",self._read_from_openvpnsocket(_unix,"load-stats"))))
|
||||
)
|
||||
@ -525,7 +526,7 @@ class checkmk_checker(object):
|
||||
if _current_conn:
|
||||
_client["uptime"] = max(map(lambda x: x.get("uptime"),_current_conn))
|
||||
_client["count"] = len(_current_conn)
|
||||
_client["bytes_received"], _client["bytes_sent"] = self._get_openvpn_traffic(
|
||||
_client["bytes_received"], _client["bytes_sent"] = self._get_traffic("openvpn",
|
||||
"CL_{description}".format(**_client),
|
||||
sum(map(lambda x: x.get("bytes_received"),_current_conn)),
|
||||
sum(map(lambda x: x.get("bytes_sent"),_current_conn))
|
||||
@ -541,7 +542,10 @@ class checkmk_checker(object):
|
||||
|
||||
def checklocal_ipsec(self):
|
||||
_ret = []
|
||||
for _con in json.loads(subprocess.check_output("/usr/local/opnsense/scripts/ipsec/list_status.py",encoding="utf-8")).values():
|
||||
_json_data = subprocess.check_output("/usr/local/opnsense/scripts/ipsec/list_status.py",encoding="utf-8")
|
||||
if len(_json_data) < 10:
|
||||
return []
|
||||
for _con in json.loads(_json_data).values():
|
||||
_childsas = None
|
||||
_con["status"] = 2
|
||||
_con["bytes_received"] = 0
|
||||
@ -549,7 +553,7 @@ class checkmk_checker(object):
|
||||
for _sas in _con.get("sas",[]):
|
||||
_con["state"] = _sas.get("state","unknown")
|
||||
_childsas = filter(lambda x: x.get("state") == "INSTALLED",_sas.get("child-sas").values())
|
||||
if _childsas:
|
||||
try:
|
||||
_childsas = next(_childsas)
|
||||
_con["remote-host"] = _sas.get("remote-host")
|
||||
_connecttime = int(_childsas.get("install-time",0))
|
||||
@ -557,10 +561,52 @@ class checkmk_checker(object):
|
||||
_con["bytes_sent"] = int(int(_childsas.get("bytes-out",0)) / _connecttime)
|
||||
_con["status"] = 0
|
||||
break
|
||||
except StopIteration:
|
||||
pass
|
||||
if _childsas:
|
||||
_ret.append("{status} \"IPsec Tunnel: {remote-id}\" if_in_octets={bytes_received}|if_out_octets={bytes_sent} {state} {local-id} - {remote-id}({remote-host})".format(**_con))
|
||||
return _ret
|
||||
|
||||
def checklocal_wireguard(self):
|
||||
_ret = []
|
||||
try:
|
||||
_clients = self._config_reader().get("OPNsense").get("wireguard").get("client").get("clients").get("client")
|
||||
if type(_clients) != list:
|
||||
_clients = [_clients] if _clients else []
|
||||
_clients = dict(map(lambda x: (x.get("pubkey"),x),_clients))
|
||||
except:
|
||||
return []
|
||||
|
||||
_now = time.time()
|
||||
for _client in _clients.values(): ## fill defaults
|
||||
_client["interface"] = ""
|
||||
_client["endpoint"] = ""
|
||||
_client["last_handshake"] = 0
|
||||
_client["bytes_received"] = 0
|
||||
_client["bytes_sent"] = 0
|
||||
_client["status"] = 2
|
||||
|
||||
_dump = subprocess.check_output(["wg","show","all","dump"],encoding="utf-8").strip()
|
||||
for _line in _dump.split("\n"):
|
||||
_values = _line.split("\t")
|
||||
if len(_values) != 9:
|
||||
continue
|
||||
_client = _clients.get(_values[1].strip())
|
||||
if not _client:
|
||||
continue
|
||||
_client["interface"] = _values[0].strip()
|
||||
_client["endpoint"] = _values[3].strip().split(":")[0]
|
||||
_client["last_handshake"] = int(_values[5].strip())
|
||||
_client["bytes_received"], _client["bytes_sent"] = self._get_traffic("wireguard","",int(_values[6].strip()),int(_values[7].strip()))
|
||||
_client["status"] = 2 if _now - _client["last_handshake"] > 300 else 0 ## 5min timeout
|
||||
|
||||
for _client in _clients.values():
|
||||
if _client.get("status") == 2 and _client.get("endpoint") != "":
|
||||
_client["endpoint"] = "last IP:" + _client["endpoint"]
|
||||
_ret.append('{status} "WireGuard Client: {name}" if_in_octets={bytes_received}|if_out_octets={bytes_sent} {interface}: {endpoint} - {tunneladdress}'.format(**_client))
|
||||
|
||||
return _ret
|
||||
|
||||
def checklocal_unbound(self):
|
||||
_ret = []
|
||||
try:
|
||||
@ -583,6 +629,8 @@ class checkmk_checker(object):
|
||||
_now = time.time()
|
||||
try:
|
||||
_acmecerts = self._config_reader().get("OPNsense").get("AcmeClient").get("certificates").get("certificate")
|
||||
if type(_acmecerts) == dict:
|
||||
_acmecerts = [_acmecerts]
|
||||
except:
|
||||
_acmecerts = []
|
||||
for _cert_info in _acmecerts:
|
||||
@ -646,6 +694,18 @@ class checkmk_checker(object):
|
||||
_ret.append(_line)
|
||||
return _ret
|
||||
|
||||
def check_smartinfo(self):
|
||||
if not os.path.exists("/usr/local/sbin/smartctl"):
|
||||
return []
|
||||
REGEX_DISCPATH = re.compile("(sd[a-z]+|da[0-9]+|nvme[0-9]+|ada[0-9]+)$")
|
||||
_ret = ["<<<disk_smart_info:sep(124)>>>"]
|
||||
for _dev in filter(lambda x: REGEX_DISCPATH.match(x),os.listdir("/dev/")):
|
||||
try:
|
||||
_ret.append(str(smart_disc(_dev)))
|
||||
except:
|
||||
pass
|
||||
return _ret
|
||||
|
||||
def check_df(self):
|
||||
_ret = ["<<<df>>>"]
|
||||
_ret += self._run_prog("df -kTP -t ufs").split("\n")[1:]
|
||||
@ -738,10 +798,10 @@ class checkmk_server(TCPServer,checkmk_checker):
|
||||
|
||||
def server_start(self):
|
||||
sys.stderr.write("starting checkmk_agent\n")
|
||||
sys.stderr.flush()
|
||||
signal.signal(signal.SIGTERM, self._signal_handler)
|
||||
signal.signal(signal.SIGINT, self._signal_handler)
|
||||
signal.signal(signal.SIGHUP, self._signal_handler)
|
||||
sys.stderr.flush()
|
||||
self._change_user()
|
||||
try:
|
||||
self.server_bind()
|
||||
@ -811,6 +871,99 @@ class checkmk_server(TCPServer,checkmk_checker):
|
||||
def __del__(self):
|
||||
pass ## todo
|
||||
|
||||
|
||||
REGEX_SMART_VENDOR = re.compile(r"^\s*(?P<num>\d+)\s(?P<name>[-\w]+).*\s{2,}(?P<value>[\w\/() ]+)$",re.M)
|
||||
REGEX_SMART_DICT = re.compile(r"^(.*?):\s*(.*?)$",re.M)
|
||||
class smart_disc(object):
|
||||
def __init__(self,device):
|
||||
self.device = device
|
||||
MAPPING = {
|
||||
"Model Family" : ("model_family" ,lambda x: x),
|
||||
"Model Number" : ("model_family" ,lambda x: x),
|
||||
"Product" : ("model_family" ,lambda x: x),
|
||||
"Vendor" : ("vendor" ,lambda x: x),
|
||||
"Revision" : ("revision" ,lambda x: x),
|
||||
"Device Model" : ("model_type" ,lambda x: x),
|
||||
"Serial Number" : ("serial_number" ,lambda x: x),
|
||||
"Serial number" : ("serial_number" ,lambda x: x),
|
||||
"Firmware Version" : ("firmware_version" ,lambda x: x),
|
||||
"User Capacity" : ("capacity" ,lambda x: x.split(" ")[0].replace(",","")),
|
||||
"Total NVM Capacity": ("capacity" ,lambda x: x.split(" ")[0].replace(",","")),
|
||||
"Rotation Rate" : ("rpm" ,lambda x: x.replace(" rpm","")),
|
||||
"Form Factor" : ("formfactor" ,lambda x: x),
|
||||
"SATA Version is" : ("transport" ,lambda x: x.split(",")[0]),
|
||||
"Transport protocol": ("transport" ,lambda x: x),
|
||||
"SMART support is" : ("smart" ,lambda x: int(x.lower() == "enabled")),
|
||||
"Critical Warning" : ("critical" ,lambda x: self._saveint(x,base=16)),
|
||||
"Temperature" : ("temperature" ,lambda x: x.split(" ")[0]),
|
||||
"Data Units Read" : ("data_read_bytes" ,lambda x: x.split(" ")[0].replace(",","")),
|
||||
"Data Units Written": ("data_write_bytes" ,lambda x: x.split(" ")[0].replace(",","")),
|
||||
"Power On Hours" : ("poweronhours" ,lambda x: x.replace(",","")),
|
||||
"Power Cycles" : ("powercycles" ,lambda x: x.replace(",","")),
|
||||
"NVMe Version" : ("transport" ,lambda x: f"NVMe {x}"),
|
||||
"Raw_Read_Error_Rate" : ("error_rate" ,lambda x: x.replace(",","")),
|
||||
"Reallocated_Sector_Ct" : ("reallocate" ,lambda x: x.replace(",","")),
|
||||
"Seek_Error_Rate" : ("seek_error_rate",lambda x: x.replace(",","")),
|
||||
"Power_Cycle_Count" : ("powercycles" ,lambda x: x.replace(",","")),
|
||||
"Temperature_Celsius" : ("temperature" ,lambda x: x.split(" ")[0]),
|
||||
"UDMA_CRC_Error_Count" : ("udma_error" ,lambda x: x.replace(",","")),
|
||||
"Offline_Uncorrectable" : ("uncorrectable" ,lambda x: x.replace(",","")),
|
||||
"Power_On_Hours" : ("poweronhours" ,lambda x: x.replace(",","")),
|
||||
"Spin_Retry_Count" : ("spinretry" ,lambda x: x.replace(",","")),
|
||||
"Current_Pending_Sector": ("pendingsector" ,lambda x: x.replace(",","")),
|
||||
"Current Drive Temperature" : ("temperature" ,lambda x: x.split(" ")[0]),
|
||||
"Reallocated_Event_Count" : ("reallocate_ev" ,lambda x: x.split(" ")[0]),
|
||||
"Warning Comp. Temp. Threshold" : ("temperature_warn" ,lambda x: x.split(" ")[0]),
|
||||
"Critical Comp. Temp. Threshold" : ("temperature_crit" ,lambda x: x.split(" ")[0]),
|
||||
"Media and Data Integrity Errors" : ("media_errors" ,lambda x: x),
|
||||
"Airflow_Temperature_Cel" : ("temperature" ,lambda x: x),
|
||||
"SMART overall-health self-assessment test result" : ("smart_status" ,lambda x: int(x.lower() == "passed")),
|
||||
"SMART Health Status" : ("smart_status" ,lambda x: int(x.lower() == "ok")),
|
||||
}
|
||||
self._get_data()
|
||||
for _key, _value in REGEX_SMART_DICT.findall(self._smartctl_output):
|
||||
if _key in MAPPING.keys():
|
||||
_map = MAPPING[_key]
|
||||
setattr(self,_map[0],_map[1](_value))
|
||||
|
||||
for _vendor_num,_vendor_text,_value in REGEX_SMART_VENDOR.findall(self._smartctl_output):
|
||||
if _vendor_text in MAPPING.keys():
|
||||
_map = MAPPING[_vendor_text]
|
||||
setattr(self,_map[0],_map[1](_value))
|
||||
|
||||
def _saveint(self,val,base=10):
|
||||
try:
|
||||
return int(val,base)
|
||||
except (TypeError,ValueError):
|
||||
return 0
|
||||
|
||||
def _get_data(self):
|
||||
try:
|
||||
self._smartctl_output = subprocess.check_output(["smartctl","-a","-n","standby", f"/dev/{self.device}"],encoding=sys.stdout.encoding)
|
||||
except subprocess.CalledProcessError as e:
|
||||
if e.returncode & 0x1:
|
||||
raise
|
||||
_status = ""
|
||||
self._smartctl_output = e.output
|
||||
if e.returncode & 0x2:
|
||||
_status = "SMART Health Status: CRC Error"
|
||||
if e.returncode & 0x4:
|
||||
_status = "SMART Health Status: PREFAIL"
|
||||
if e.returncode & 0x3:
|
||||
_status = "SMART Health Status: DISK FAILING"
|
||||
|
||||
self._smartctl_output += f"\n{_status}\n"
|
||||
|
||||
def __str__(self):
|
||||
_ret = []
|
||||
if not getattr(self,"model_type",None):
|
||||
self.model_type = getattr(self,"model_family","unknown")
|
||||
for _k,_v in self.__dict__.items():
|
||||
if _k.startswith("_") or _k in ("device"):
|
||||
continue
|
||||
_ret.append(f"{self.device}|{_k}|{_v}")
|
||||
return "\n".join(_ret)
|
||||
|
||||
if __name__ == "__main__":
|
||||
import argparse
|
||||
_ = lambda x: x
|
||||
@ -866,7 +1019,7 @@ if __name__ == "__main__":
|
||||
os.kill(int(_pid),signal.SIGTERM)
|
||||
|
||||
elif args.debug:
|
||||
print(_server.do_checks())
|
||||
print(_server.do_checks(debug=True))
|
||||
elif args.nodaemon:
|
||||
_server.server_start()
|
||||
else:
|
||||
|
Loading…
Reference in New Issue
Block a user