[mod] aufgeräumt
This commit is contained in:
parent
f29c4e2f7a
commit
3749ac6a60
|
|
@ -1,270 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
|
|
||||||
import sys as _sys
|
|
||||||
import os as _os
|
|
||||||
import json as _json
|
|
||||||
import argparse as _argparse
|
|
||||||
|
|
||||||
from lib import *
|
|
||||||
from implementation_check_kind_script import *
|
|
||||||
from implementation_check_kind_http_request import *
|
|
||||||
from implementation_notification_channel_console import *
|
|
||||||
from implementation_notification_channel_email import *
|
|
||||||
|
|
||||||
|
|
||||||
def state_encode(state):
|
|
||||||
return {
|
|
||||||
"timestamp": state["timestamp"],
|
|
||||||
"condition": condition_encode(state["condition"]),
|
|
||||||
"count": state["count"],
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def state_decode(state_encoded):
|
|
||||||
return {
|
|
||||||
"timestamp": state_encoded["timestamp"],
|
|
||||||
"condition": condition_decode(state_encoded["condition"]),
|
|
||||||
"count": state_encoded["count"],
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def conf_normalize_check(check_kind_implementations, defaults, name, node):
|
|
||||||
if ("kind" not in node):
|
|
||||||
raise ValueError("missing mandatory 'member' field 'kind'")
|
|
||||||
else:
|
|
||||||
if (node["kind"] not in check_kind_implementations):
|
|
||||||
raise ValueError("unhandled kind: %s" % node["kind"])
|
|
||||||
else:
|
|
||||||
node_ = dict_merge(
|
|
||||||
{
|
|
||||||
"title": name,
|
|
||||||
"active": True,
|
|
||||||
"schedule": defaults["schedule"],
|
|
||||||
"notifications": defaults["notifications"],
|
|
||||||
"parameters": {},
|
|
||||||
},
|
|
||||||
node
|
|
||||||
)
|
|
||||||
return {
|
|
||||||
"title": node_["title"],
|
|
||||||
"active": node_["active"],
|
|
||||||
"schedule": node_["schedule"],
|
|
||||||
"notifications": node_["notifications"],
|
|
||||||
"kind": node_["kind"],
|
|
||||||
"parameters": check_kind_implementations[node_["kind"]].normalize_conf_node(node_["parameters"]),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def conf_normalize_defaults(node):
|
|
||||||
return dict_merge(
|
|
||||||
{
|
|
||||||
"active": True,
|
|
||||||
"schedule": {"kind": "hourly"},
|
|
||||||
"notifications": [],
|
|
||||||
},
|
|
||||||
node
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def conf_normalize_root(check_kind_implementations, node):
|
|
||||||
return dict(
|
|
||||||
map(
|
|
||||||
lambda check_pair: (
|
|
||||||
check_pair[0],
|
|
||||||
conf_normalize_check(
|
|
||||||
check_kind_implementations,
|
|
||||||
conf_normalize_defaults(node["defaults"]),
|
|
||||||
check_pair[0],
|
|
||||||
check_pair[1]
|
|
||||||
),
|
|
||||||
),
|
|
||||||
node["checks"].items()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
## args
|
|
||||||
argumentparser = _argparse.ArgumentParser(
|
|
||||||
description = "monitoring processor",
|
|
||||||
formatter_class = _argparse.ArgumentDefaultsHelpFormatter
|
|
||||||
)
|
|
||||||
argumentparser.add_argument(
|
|
||||||
"-c",
|
|
||||||
"--conf-path",
|
|
||||||
type = str,
|
|
||||||
default = "conf.json",
|
|
||||||
dest = "conf_path",
|
|
||||||
metavar = "<conf-path>",
|
|
||||||
help = "path to the configuration file"
|
|
||||||
)
|
|
||||||
argumentparser.add_argument(
|
|
||||||
"-s",
|
|
||||||
"--state-path",
|
|
||||||
type = str,
|
|
||||||
default = "/tmp/monitoring-state.json",
|
|
||||||
dest = "state_path",
|
|
||||||
metavar = "<state-path>",
|
|
||||||
help = "path to the state file, which contains information about the recent checks"
|
|
||||||
)
|
|
||||||
argumentparser.add_argument(
|
|
||||||
"-t",
|
|
||||||
"--threshold",
|
|
||||||
type = int,
|
|
||||||
default = 3,
|
|
||||||
dest = "threshold",
|
|
||||||
metavar = "<threshold>",
|
|
||||||
help = "how often a condition has to occur in order to be reported"
|
|
||||||
)
|
|
||||||
argumentparser.add_argument(
|
|
||||||
"-k",
|
|
||||||
"--keep-notifying",
|
|
||||||
action = "store_true",
|
|
||||||
default = False,
|
|
||||||
dest = "keep_notifying",
|
|
||||||
help = "whether notifications shall be kept sending after the threshold has been surpassed"
|
|
||||||
)
|
|
||||||
argumentparser.add_argument(
|
|
||||||
"-x",
|
|
||||||
"--expose-full-conf",
|
|
||||||
action = "store_true",
|
|
||||||
default = False,
|
|
||||||
dest = "expose_full_conf",
|
|
||||||
help = "only print the extended configuration to stdout and exit (useful for debug purposes)"
|
|
||||||
)
|
|
||||||
args = argumentparser.parse_args()
|
|
||||||
|
|
||||||
## exec
|
|
||||||
|
|
||||||
### load check kind implementations
|
|
||||||
check_kind_implementations = {
|
|
||||||
"script": implementation_check_kind_script(),
|
|
||||||
"http_request": implementation_check_kind_http_request(),
|
|
||||||
}
|
|
||||||
|
|
||||||
### load notification channel implementations
|
|
||||||
notification_channel_implementations = {
|
|
||||||
"console": implementation_notification_channel_console(),
|
|
||||||
"email": implementation_notification_channel_email(),
|
|
||||||
}
|
|
||||||
|
|
||||||
### get configuration data
|
|
||||||
checks = conf_normalize_root(check_kind_implementations, _json.loads(file_read(args.conf_path)))
|
|
||||||
if (args.expose_full_conf):
|
|
||||||
_sys.stdout.write(_json.dumps(checks, indent = "\t") + "\n")
|
|
||||||
_sys.exit(1)
|
|
||||||
else:
|
|
||||||
### get state data
|
|
||||||
if (not _os.path.exists(args.state_path)):
|
|
||||||
state_data = {}
|
|
||||||
file_write(args.state_path, _json.dumps(state_data, indent = "\t"))
|
|
||||||
else:
|
|
||||||
state_data = _json.loads(file_read(args.state_path))
|
|
||||||
|
|
||||||
### iterate through checks
|
|
||||||
for (check_name, check_data, ) in checks.items():
|
|
||||||
if (not check_data["active"]):
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
### get old state and examine whether the check shall be executed
|
|
||||||
old_item_state = (
|
|
||||||
None
|
|
||||||
if (check_name not in state_data) else
|
|
||||||
state_decode(state_data[check_name])
|
|
||||||
)
|
|
||||||
timestamp = get_current_timestamp()
|
|
||||||
due = (
|
|
||||||
(old_item_state is None)
|
|
||||||
or
|
|
||||||
(
|
|
||||||
(old_item_state["count"] is not None)
|
|
||||||
and
|
|
||||||
((timestamp - old_item_state["timestamp"]) >= (1 * 5))
|
|
||||||
)
|
|
||||||
or
|
|
||||||
(
|
|
||||||
(
|
|
||||||
(check_data["schedule"]["kind"] == "minutely")
|
|
||||||
and
|
|
||||||
((timestamp - old_item_state["timestamp"]) >= (60))
|
|
||||||
)
|
|
||||||
or
|
|
||||||
(
|
|
||||||
(check_data["schedule"]["kind"] == "hourly")
|
|
||||||
and
|
|
||||||
((timestamp - old_item_state["timestamp"]) >= (60 * 60))
|
|
||||||
)
|
|
||||||
or
|
|
||||||
(
|
|
||||||
(check_data["schedule"]["kind"] == "daily")
|
|
||||||
and
|
|
||||||
((timestamp - old_item_state["timestamp"]) >= (60 * 60 * 24))
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
if (not due):
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
_sys.stderr.write(
|
|
||||||
string_coin(
|
|
||||||
"-- {{check_name}}\n",
|
|
||||||
{
|
|
||||||
"check_name": check_name,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
### execute check and set new state
|
|
||||||
result = check_kind_implementations[check_data["kind"]].run(check_data)
|
|
||||||
new_item_state = {
|
|
||||||
"timestamp": timestamp,
|
|
||||||
"condition": result["condition"],
|
|
||||||
"count": (
|
|
||||||
1
|
|
||||||
if (
|
|
||||||
(old_item_state is None)
|
|
||||||
or
|
|
||||||
(old_item_state["condition"] != result["condition"])
|
|
||||||
) else
|
|
||||||
(
|
|
||||||
(old_item_state["count"] + 1)
|
|
||||||
if (
|
|
||||||
(old_item_state["count"] is not None)
|
|
||||||
and
|
|
||||||
((old_item_state["count"] + 1) <= args.threshold)
|
|
||||||
) else
|
|
||||||
None
|
|
||||||
)
|
|
||||||
),
|
|
||||||
}
|
|
||||||
state_data[check_name] = state_encode(new_item_state)
|
|
||||||
file_write(args.state_path, _json.dumps(state_data, indent = "\t"))
|
|
||||||
|
|
||||||
### send notifications
|
|
||||||
if (
|
|
||||||
(
|
|
||||||
(new_item_state["count"] is not None)
|
|
||||||
and
|
|
||||||
(new_item_state["count"] == args.threshold)
|
|
||||||
)
|
|
||||||
or
|
|
||||||
(
|
|
||||||
(new_item_state["count"] is None)
|
|
||||||
and
|
|
||||||
args.keep_notifying
|
|
||||||
)
|
|
||||||
):
|
|
||||||
for notification in check_data["notifications"]:
|
|
||||||
if (notification["kind"] in notification_channel_implementations):
|
|
||||||
notification_channel_implementations[notification["kind"]].notify(
|
|
||||||
notification["parameters"],
|
|
||||||
check_name,
|
|
||||||
check_data,
|
|
||||||
new_item_state,
|
|
||||||
result["output"]
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
raise ValueError("invalid notification kind: %s" % notification["kind"])
|
|
||||||
|
|
||||||
|
|
||||||
main()
|
|
||||||
|
|
@ -72,14 +72,14 @@ def conf_normalize_root(check_kind_implementations, node):
|
||||||
def main():
|
def main():
|
||||||
## args
|
## args
|
||||||
argumentparser = _argparse.ArgumentParser(
|
argumentparser = _argparse.ArgumentParser(
|
||||||
description = "monitoring processor",
|
description = "Heimdall-Monitoring-Tool",
|
||||||
formatter_class = _argparse.ArgumentDefaultsHelpFormatter
|
formatter_class = _argparse.ArgumentDefaultsHelpFormatter
|
||||||
)
|
)
|
||||||
argumentparser.add_argument(
|
argumentparser.add_argument(
|
||||||
"-c",
|
"-c",
|
||||||
"--conf-path",
|
"--conf-path",
|
||||||
type = str,
|
type = str,
|
||||||
default = "conf.json",
|
default = "monitoring.hmdl.json",
|
||||||
dest = "conf_path",
|
dest = "conf_path",
|
||||||
metavar = "<conf-path>",
|
metavar = "<conf-path>",
|
||||||
help = "path to the configuration file"
|
help = "path to the configuration file"
|
||||||
|
|
@ -88,10 +88,10 @@ def main():
|
||||||
"-s",
|
"-s",
|
||||||
"--state-path",
|
"--state-path",
|
||||||
type = str,
|
type = str,
|
||||||
default = "/tmp/monitoring-state.json",
|
default = None,
|
||||||
dest = "state_path",
|
dest = "state_path",
|
||||||
metavar = "<state-path>",
|
metavar = "<state-path>",
|
||||||
help = "path to the state file, which contains information about the recent checks"
|
help = "path to the state file, which contains information about the recent checks; default: file in temporary directory, unique for the conf-path input"
|
||||||
)
|
)
|
||||||
argumentparser.add_argument(
|
argumentparser.add_argument(
|
||||||
"-t",
|
"-t",
|
||||||
|
|
@ -102,6 +102,15 @@ def main():
|
||||||
metavar = "<threshold>",
|
metavar = "<threshold>",
|
||||||
help = "how often a condition has to occur in order to be reported"
|
help = "how often a condition has to occur in order to be reported"
|
||||||
)
|
)
|
||||||
|
argumentparser.add_argument(
|
||||||
|
"-a",
|
||||||
|
"--awareness-interval",
|
||||||
|
type = int,
|
||||||
|
default = 120,
|
||||||
|
dest = "awareness_interval",
|
||||||
|
metavar = "<awareness-interval>",
|
||||||
|
help = "seconds to wait until starting the next run of a check, for which the condition has changed recently"
|
||||||
|
)
|
||||||
argumentparser.add_argument(
|
argumentparser.add_argument(
|
||||||
"-k",
|
"-k",
|
||||||
"--keep-notifying",
|
"--keep-notifying",
|
||||||
|
|
@ -120,8 +129,21 @@ def main():
|
||||||
)
|
)
|
||||||
args = argumentparser.parse_args()
|
args = argumentparser.parse_args()
|
||||||
|
|
||||||
|
## vars
|
||||||
|
id_ = _hashlib.sha256(_os.path.abspath(args.conf_path).encode("ascii")).hexdigest()[:8]
|
||||||
|
state_path = (
|
||||||
|
args.state_path
|
||||||
|
if (args.state_path is not None) else
|
||||||
|
_os.path.join(
|
||||||
|
_tempfile.gettempdir(),
|
||||||
|
string_coin("monitoring-state-{{id}}.json", {"id": id_})
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
## exec
|
## exec
|
||||||
|
|
||||||
|
_sys.stderr.write(">> state file path: %s\n" % state_path)
|
||||||
|
|
||||||
### load check kind implementations
|
### load check kind implementations
|
||||||
check_kind_implementations = {
|
check_kind_implementations = {
|
||||||
"script": implementation_check_kind_script(),
|
"script": implementation_check_kind_script(),
|
||||||
|
|
@ -141,11 +163,11 @@ def main():
|
||||||
_sys.exit(1)
|
_sys.exit(1)
|
||||||
else:
|
else:
|
||||||
### get state data
|
### get state data
|
||||||
if (not _os.path.exists(args.state_path)):
|
if (not _os.path.exists(state_path)):
|
||||||
state_data = {}
|
state_data = {}
|
||||||
file_write(args.state_path, _json.dumps(state_data, indent = "\t"))
|
file_write(state_path, _json.dumps(state_data, indent = "\t"))
|
||||||
else:
|
else:
|
||||||
state_data = _json.loads(file_read(args.state_path))
|
state_data = _json.loads(file_read(state_path))
|
||||||
|
|
||||||
### iterate through checks
|
### iterate through checks
|
||||||
for (check_name, check_data, ) in checks.items():
|
for (check_name, check_data, ) in checks.items():
|
||||||
|
|
@ -165,7 +187,7 @@ def main():
|
||||||
(
|
(
|
||||||
(old_item_state["count"] is not None)
|
(old_item_state["count"] is not None)
|
||||||
and
|
and
|
||||||
((timestamp - old_item_state["timestamp"]) >= (1 * 5))
|
((timestamp - old_item_state["timestamp"]) >= args.awareness_interval)
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
(
|
(
|
||||||
|
|
@ -224,7 +246,7 @@ def main():
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
state_data[check_name] = state_encode(new_item_state)
|
state_data[check_name] = state_encode(new_item_state)
|
||||||
file_write(args.state_path, _json.dumps(state_data, indent = "\t"))
|
file_write(state_path, _json.dumps(state_data, indent = "\t"))
|
||||||
|
|
||||||
### send notifications
|
### send notifications
|
||||||
if (
|
if (
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
import sys as _sys
|
import sys as _sys
|
||||||
import os as _os
|
import os as _os
|
||||||
import subprocess as _subprocess
|
import subprocess as _subprocess
|
||||||
|
import hashlib as _hashlib
|
||||||
|
import tempfile as _tempfile
|
||||||
import argparse as _argparse
|
import argparse as _argparse
|
||||||
import json as _json
|
import json as _json
|
||||||
import requests as _requests
|
import requests as _requests
|
||||||
import smtplib as _smtplib
|
import smtplib as _smtplib
|
||||||
from email.mime.text import MIMEText
|
from email.mime.text import MIMEText
|
||||||
|
|
||||||
|
|
|
||||||
12
tools/build
12
tools/build
|
|
@ -5,12 +5,12 @@ echo "#!/usr/bin/env python3" > build/heimdall
|
||||||
cat \
|
cat \
|
||||||
source/packages.py \
|
source/packages.py \
|
||||||
source/lib.py \
|
source/lib.py \
|
||||||
source/interface_check_kind.py \
|
source/check_kinds/_interface.py \
|
||||||
source/implementation_check_kind_script.py \
|
source/check_kinds/script.py \
|
||||||
source/implementation_check_kind_http_request.py \
|
source/check_kinds/http_request.py \
|
||||||
source/interface_notification_channel.py \
|
source/notification_channels/_interface.py \
|
||||||
source/implementation_notification_channel_console.py \
|
source/notification_channels/console.py \
|
||||||
source/implementation_notification_channel_email.py \
|
source/notification_channels/email.py \
|
||||||
source/main.py \
|
source/main.py \
|
||||||
>> build/heimdall
|
>> build/heimdall
|
||||||
chmod +x build/heimdall
|
chmod +x build/heimdall
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue