mirror of
https://github.com/bashclub/check-opnsense.git
synced 2024-12-26 00:30:12 +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
|
## copy to /usr/local/etc/rc.syshook.d/start/99-checkmk_agent and chmod +x
|
||||||
##
|
##
|
||||||
|
|
||||||
__VERSION__ = "0.67"
|
__VERSION__ = "0.69"
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
@ -84,7 +84,7 @@ class checkmk_checker(object):
|
|||||||
_certificate_timestamp = 0
|
_certificate_timestamp = 0
|
||||||
_datastore_mutex = threading.RLock()
|
_datastore_mutex = threading.RLock()
|
||||||
_datastore = object_dict()
|
_datastore = object_dict()
|
||||||
def do_checks(self):
|
def do_checks(self,debug=False):
|
||||||
self._getosinfo()
|
self._getosinfo()
|
||||||
_errors = []
|
_errors = []
|
||||||
_lines = ["<<<check_mk>>>"]
|
_lines = ["<<<check_mk>>>"]
|
||||||
@ -105,8 +105,9 @@ class checkmk_checker(object):
|
|||||||
except:
|
except:
|
||||||
_errors.append(traceback.format_exc())
|
_errors.append(traceback.format_exc())
|
||||||
_lines.append("")
|
_lines.append("")
|
||||||
sys.stderr.write("\n".join(_errors))
|
if debug:
|
||||||
sys.stderr.flush()
|
sys.stderr.write("\n".join(_errors))
|
||||||
|
sys.stderr.flush()
|
||||||
return "\n".join(_lines)
|
return "\n".join(_lines)
|
||||||
|
|
||||||
def _get_storedata(self,section,key):
|
def _get_storedata(self,section,key):
|
||||||
@ -334,8 +335,8 @@ class checkmk_checker(object):
|
|||||||
_sock = None
|
_sock = None
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
def _get_openvpn_traffic(self,interface,totalbytesin,totalbytesout):
|
def _get_traffic(self,modul,interface,totalbytesin,totalbytesout):
|
||||||
_hist_data = self._get_storedata("openvpn",interface)
|
_hist_data = self._get_storedata(modul,interface)
|
||||||
_slot = int(time.time())
|
_slot = int(time.time())
|
||||||
_slot -= _slot%60
|
_slot -= _slot%60
|
||||||
_hist_slot = 0
|
_hist_slot = 0
|
||||||
@ -345,7 +346,7 @@ class checkmk_checker(object):
|
|||||||
_traffic_in = int(totalbytesin -_hist_bytesin) / max(1,_slot - _hist_slot)
|
_traffic_in = int(totalbytesin -_hist_bytesin) / max(1,_slot - _hist_slot)
|
||||||
_traffic_out = int(totalbytesout - _hist_bytesout) / max(1,_slot - _hist_slot)
|
_traffic_out = int(totalbytesout - _hist_bytesout) / max(1,_slot - _hist_slot)
|
||||||
if _hist_slot != _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
|
return _traffic_in,_traffic_out
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@ -434,7 +435,7 @@ class checkmk_checker(object):
|
|||||||
_unix = "/var/etc/openvpn/{type}{vpnid}.sock".format(**_server)
|
_unix = "/var/etc/openvpn/{type}{vpnid}.sock".format(**_server)
|
||||||
try:
|
try:
|
||||||
|
|
||||||
_server["bytesin"], _server["bytesout"] = self._get_openvpn_traffic(
|
_server["bytesin"], _server["bytesout"] = self._get_traffic("openvpn",
|
||||||
"SRV_{name}".format(**_server),
|
"SRV_{name}".format(**_server),
|
||||||
*(map(lambda x: int(x),re.findall("bytes\w+=(\d+)",self._read_from_openvpnsocket(_unix,"load-stats"))))
|
*(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)
|
_unix = "/var/etc/openvpn/{type}{vpnid}.sock".format(**_server)
|
||||||
try:
|
try:
|
||||||
|
|
||||||
_server["bytesin"], _server["bytesout"] = self._get_openvpn_traffic(
|
_server["bytesin"], _server["bytesout"] = self._get_traffic("openvpn",
|
||||||
"SRV_{name}".format(**_server),
|
"SRV_{name}".format(**_server),
|
||||||
*(map(lambda x: int(x),re.findall("bytes\w+=(\d+)",self._read_from_openvpnsocket(_unix,"load-stats"))))
|
*(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:
|
if _current_conn:
|
||||||
_client["uptime"] = max(map(lambda x: x.get("uptime"),_current_conn))
|
_client["uptime"] = max(map(lambda x: x.get("uptime"),_current_conn))
|
||||||
_client["count"] = len(_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),
|
"CL_{description}".format(**_client),
|
||||||
sum(map(lambda x: x.get("bytes_received"),_current_conn)),
|
sum(map(lambda x: x.get("bytes_received"),_current_conn)),
|
||||||
sum(map(lambda x: x.get("bytes_sent"),_current_conn))
|
sum(map(lambda x: x.get("bytes_sent"),_current_conn))
|
||||||
@ -541,7 +542,10 @@ class checkmk_checker(object):
|
|||||||
|
|
||||||
def checklocal_ipsec(self):
|
def checklocal_ipsec(self):
|
||||||
_ret = []
|
_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
|
_childsas = None
|
||||||
_con["status"] = 2
|
_con["status"] = 2
|
||||||
_con["bytes_received"] = 0
|
_con["bytes_received"] = 0
|
||||||
@ -549,7 +553,7 @@ class checkmk_checker(object):
|
|||||||
for _sas in _con.get("sas",[]):
|
for _sas in _con.get("sas",[]):
|
||||||
_con["state"] = _sas.get("state","unknown")
|
_con["state"] = _sas.get("state","unknown")
|
||||||
_childsas = filter(lambda x: x.get("state") == "INSTALLED",_sas.get("child-sas").values())
|
_childsas = filter(lambda x: x.get("state") == "INSTALLED",_sas.get("child-sas").values())
|
||||||
if _childsas:
|
try:
|
||||||
_childsas = next(_childsas)
|
_childsas = next(_childsas)
|
||||||
_con["remote-host"] = _sas.get("remote-host")
|
_con["remote-host"] = _sas.get("remote-host")
|
||||||
_connecttime = int(_childsas.get("install-time",0))
|
_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["bytes_sent"] = int(int(_childsas.get("bytes-out",0)) / _connecttime)
|
||||||
_con["status"] = 0
|
_con["status"] = 0
|
||||||
break
|
break
|
||||||
|
except StopIteration:
|
||||||
|
pass
|
||||||
if _childsas:
|
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))
|
_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
|
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):
|
def checklocal_unbound(self):
|
||||||
_ret = []
|
_ret = []
|
||||||
try:
|
try:
|
||||||
@ -583,6 +629,8 @@ class checkmk_checker(object):
|
|||||||
_now = time.time()
|
_now = time.time()
|
||||||
try:
|
try:
|
||||||
_acmecerts = self._config_reader().get("OPNsense").get("AcmeClient").get("certificates").get("certificate")
|
_acmecerts = self._config_reader().get("OPNsense").get("AcmeClient").get("certificates").get("certificate")
|
||||||
|
if type(_acmecerts) == dict:
|
||||||
|
_acmecerts = [_acmecerts]
|
||||||
except:
|
except:
|
||||||
_acmecerts = []
|
_acmecerts = []
|
||||||
for _cert_info in _acmecerts:
|
for _cert_info in _acmecerts:
|
||||||
@ -646,6 +694,18 @@ class checkmk_checker(object):
|
|||||||
_ret.append(_line)
|
_ret.append(_line)
|
||||||
return _ret
|
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):
|
def check_df(self):
|
||||||
_ret = ["<<<df>>>"]
|
_ret = ["<<<df>>>"]
|
||||||
_ret += self._run_prog("df -kTP -t ufs").split("\n")[1:]
|
_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):
|
def server_start(self):
|
||||||
sys.stderr.write("starting checkmk_agent\n")
|
sys.stderr.write("starting checkmk_agent\n")
|
||||||
|
sys.stderr.flush()
|
||||||
signal.signal(signal.SIGTERM, self._signal_handler)
|
signal.signal(signal.SIGTERM, self._signal_handler)
|
||||||
signal.signal(signal.SIGINT, self._signal_handler)
|
signal.signal(signal.SIGINT, self._signal_handler)
|
||||||
signal.signal(signal.SIGHUP, self._signal_handler)
|
signal.signal(signal.SIGHUP, self._signal_handler)
|
||||||
sys.stderr.flush()
|
|
||||||
self._change_user()
|
self._change_user()
|
||||||
try:
|
try:
|
||||||
self.server_bind()
|
self.server_bind()
|
||||||
@ -811,6 +871,99 @@ class checkmk_server(TCPServer,checkmk_checker):
|
|||||||
def __del__(self):
|
def __del__(self):
|
||||||
pass ## todo
|
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__":
|
if __name__ == "__main__":
|
||||||
import argparse
|
import argparse
|
||||||
_ = lambda x: x
|
_ = lambda x: x
|
||||||
@ -866,7 +1019,7 @@ if __name__ == "__main__":
|
|||||||
os.kill(int(_pid),signal.SIGTERM)
|
os.kill(int(_pid),signal.SIGTERM)
|
||||||
|
|
||||||
elif args.debug:
|
elif args.debug:
|
||||||
print(_server.do_checks())
|
print(_server.do_checks(debug=True))
|
||||||
elif args.nodaemon:
|
elif args.nodaemon:
|
||||||
_server.server_start()
|
_server.server_start()
|
||||||
else:
|
else:
|
||||||
|
Loading…
Reference in New Issue
Block a user