[mod] viele kleine Anpassungen
This commit is contained in:
parent
be60379e35
commit
f7e3357662
|
|
@ -7,17 +7,17 @@
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"properties": {
|
"properties": {
|
||||||
"kind": {
|
"regular_interval": {
|
||||||
"type": "string",
|
"description": "in seconds",
|
||||||
"enum": [
|
"type": "integer"
|
||||||
"minutely",
|
},
|
||||||
"hourly",
|
"attentive_interval": {
|
||||||
"daily"
|
"description": "in seconds",
|
||||||
]
|
"type": "integer"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
"kind"
|
"regular_interval"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
|
|
@ -171,6 +171,42 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"anyOf": [
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"kind": {
|
||||||
|
"type": "string",
|
||||||
|
"const": "test"
|
||||||
|
},
|
||||||
|
"parameters": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"condition": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"unknown",
|
||||||
|
"ok",
|
||||||
|
"warning",
|
||||||
|
"critical"
|
||||||
|
],
|
||||||
|
"default": "warning"
|
||||||
|
},
|
||||||
|
"output": {
|
||||||
|
"type": "string",
|
||||||
|
"default": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"kind",
|
||||||
|
"parameters"
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,6 @@ class interface_check_kind(object):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
def run(self, check_data):
|
def run(self, parameters):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,22 +22,22 @@ class implementation_check_kind_http_request(interface_check_kind):
|
||||||
'''
|
'''
|
||||||
[implementation]
|
[implementation]
|
||||||
'''
|
'''
|
||||||
def run(self, check_data):
|
def run(self, parameters):
|
||||||
if (check_data["parameters"]["request"]["method"] == "GET"):
|
if (parameters["request"]["method"] == "GET"):
|
||||||
method_handled = True
|
method_handled = True
|
||||||
try:
|
try:
|
||||||
response = _requests.get(
|
response = _requests.get(
|
||||||
check_data["parameters"]["request"]["target"]
|
parameters["request"]["target"]
|
||||||
)
|
)
|
||||||
error = None
|
error = None
|
||||||
except Exception as error_:
|
except Exception as error_:
|
||||||
error = error_
|
error = error_
|
||||||
response = None
|
response = None
|
||||||
elif (check_data["parameters"]["request"]["method"] == "POST"):
|
elif (parameters["request"]["method"] == "POST"):
|
||||||
method_handled = True
|
method_handled = True
|
||||||
try:
|
try:
|
||||||
response = _requests.post(
|
response = _requests.post(
|
||||||
check_data["parameters"]["request"]["target"]
|
parameters["request"]["target"]
|
||||||
)
|
)
|
||||||
error = None
|
error = None
|
||||||
except Exception as error_:
|
except Exception as error_:
|
||||||
|
|
@ -49,21 +49,21 @@ class implementation_check_kind_http_request(interface_check_kind):
|
||||||
if (not method_handled):
|
if (not method_handled):
|
||||||
return {
|
return {
|
||||||
"condition": enum_condition.unknown,
|
"condition": enum_condition.unknown,
|
||||||
"output": ("invalid HTTP request method: %s" % check_data["parameters"]["request"]["method"])
|
"output": ("invalid HTTP request method: %s" % parameters["request"]["method"])
|
||||||
}
|
}
|
||||||
else:
|
else:
|
||||||
if (response is None):
|
if (response is None):
|
||||||
return {
|
return {
|
||||||
"condition": (
|
"condition": (
|
||||||
enum_condition.warning
|
enum_condition.warning
|
||||||
if check_data["parameters"]["as_warning"] else
|
if parameters["as_warning"] else
|
||||||
enum_condition.critical
|
enum_condition.critical
|
||||||
),
|
),
|
||||||
"output": "HTTP request failed",
|
"output": "HTTP request failed",
|
||||||
}
|
}
|
||||||
else:
|
else:
|
||||||
lines = []
|
lines = []
|
||||||
for (key, value, ) in check_data["parameters"]["response"].items():
|
for (key, value, ) in parameters["response"].items():
|
||||||
if (key == "status_code"):
|
if (key == "status_code"):
|
||||||
if ((value is None) or (response.status_code == value)):
|
if ((value is None) or (response.status_code == value)):
|
||||||
pass
|
pass
|
||||||
|
|
@ -112,7 +112,7 @@ class implementation_check_kind_http_request(interface_check_kind):
|
||||||
if (len(lines) <= 0) else
|
if (len(lines) <= 0) else
|
||||||
(
|
(
|
||||||
enum_condition.warning
|
enum_condition.warning
|
||||||
if check_data["parameters"]["as_warning"] else
|
if parameters["as_warning"] else
|
||||||
enum_condition.critical
|
enum_condition.critical
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -14,9 +14,9 @@ class implementation_check_kind_script(interface_check_kind):
|
||||||
'''
|
'''
|
||||||
[implementation]
|
[implementation]
|
||||||
'''
|
'''
|
||||||
def run(self, check_data):
|
def run(self, parameters):
|
||||||
result = _subprocess.run(
|
result = _subprocess.run(
|
||||||
[check_data["parameters"]["path"]] + check_data["parameters"]["arguments"],
|
[parameters["path"]] + parameters["arguments"],
|
||||||
capture_output = True
|
capture_output = True
|
||||||
)
|
)
|
||||||
if (result.returncode == 0):
|
if (result.returncode == 0):
|
||||||
|
|
|
||||||
24
source/check_kinds/test.py
Normal file
24
source/check_kinds/test.py
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
class implementation_check_kind_test(interface_check_kind):
|
||||||
|
|
||||||
|
'''
|
||||||
|
[implementation]
|
||||||
|
'''
|
||||||
|
def normalize_conf_node(self, node):
|
||||||
|
return dict_merge(
|
||||||
|
{
|
||||||
|
"condition": condition_encode(enum_condition.warning),
|
||||||
|
"output": "",
|
||||||
|
},
|
||||||
|
node
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
[implementation]
|
||||||
|
'''
|
||||||
|
def run(self, parameters):
|
||||||
|
return {
|
||||||
|
"condition": condition_decode(parameters["condition"]),
|
||||||
|
"output": parameters["output"]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -16,7 +16,7 @@ def state_decode(state_encoded):
|
||||||
|
|
||||||
def conf_normalize_check(check_kind_implementations, defaults, name, node):
|
def conf_normalize_check(check_kind_implementations, defaults, name, node):
|
||||||
if ("kind" not in node):
|
if ("kind" not in node):
|
||||||
raise ValueError("missing mandatory 'member' field 'kind'")
|
raise ValueError("missing mandatory 'check' field 'kind'")
|
||||||
else:
|
else:
|
||||||
if (node["kind"] not in check_kind_implementations):
|
if (node["kind"] not in check_kind_implementations):
|
||||||
raise ValueError("unhandled kind: %s" % node["kind"])
|
raise ValueError("unhandled kind: %s" % node["kind"])
|
||||||
|
|
@ -45,8 +45,12 @@ def conf_normalize_defaults(node):
|
||||||
return dict_merge(
|
return dict_merge(
|
||||||
{
|
{
|
||||||
"active": True,
|
"active": True,
|
||||||
"schedule": {"kind": "hourly"},
|
"schedule": {
|
||||||
"notifications": [],
|
"regular_interval": (60 * 60),
|
||||||
|
"attentive_interval": (60 * 2),
|
||||||
|
},
|
||||||
|
"notifications": [
|
||||||
|
],
|
||||||
},
|
},
|
||||||
node
|
node
|
||||||
)
|
)
|
||||||
|
|
@ -93,6 +97,14 @@ def main():
|
||||||
metavar = "<state-path>",
|
metavar = "<state-path>",
|
||||||
help = "path to the state file, which contains information about the recent checks; default: file in temporary directory, unique for the conf-path input"
|
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(
|
||||||
|
"-x",
|
||||||
|
"--erase-state",
|
||||||
|
action = "store_true",
|
||||||
|
default = False,
|
||||||
|
dest = "erase_state",
|
||||||
|
help = "whether the state shall be deleted on start; this will cause that all checks are executed"
|
||||||
|
)
|
||||||
argumentparser.add_argument(
|
argumentparser.add_argument(
|
||||||
"-t",
|
"-t",
|
||||||
"--threshold",
|
"--threshold",
|
||||||
|
|
@ -102,15 +114,6 @@ 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,7 +123,7 @@ def main():
|
||||||
help = "whether notifications shall be kept sending after the threshold has been surpassed"
|
help = "whether notifications shall be kept sending after the threshold has been surpassed"
|
||||||
)
|
)
|
||||||
argumentparser.add_argument(
|
argumentparser.add_argument(
|
||||||
"-x",
|
"-e",
|
||||||
"--expose-full-conf",
|
"--expose-full-conf",
|
||||||
action = "store_true",
|
action = "store_true",
|
||||||
default = False,
|
default = False,
|
||||||
|
|
@ -146,6 +149,7 @@ def main():
|
||||||
|
|
||||||
### load check kind implementations
|
### load check kind implementations
|
||||||
check_kind_implementations = {
|
check_kind_implementations = {
|
||||||
|
"test": implementation_check_kind_test(),
|
||||||
"script": implementation_check_kind_script(),
|
"script": implementation_check_kind_script(),
|
||||||
"http_request": implementation_check_kind_http_request(),
|
"http_request": implementation_check_kind_http_request(),
|
||||||
}
|
}
|
||||||
|
|
@ -163,7 +167,11 @@ def main():
|
||||||
_sys.exit(1)
|
_sys.exit(1)
|
||||||
else:
|
else:
|
||||||
### get state data
|
### get state data
|
||||||
if (not _os.path.exists(state_path)):
|
if (
|
||||||
|
(not _os.path.exists(state_path))
|
||||||
|
or
|
||||||
|
args.erase_state
|
||||||
|
):
|
||||||
state_data = {}
|
state_data = {}
|
||||||
file_write(state_path, _json.dumps(state_data, indent = "\t"))
|
file_write(state_path, _json.dumps(state_data, indent = "\t"))
|
||||||
else:
|
else:
|
||||||
|
|
@ -184,29 +192,15 @@ def main():
|
||||||
due = (
|
due = (
|
||||||
(old_item_state is None)
|
(old_item_state is None)
|
||||||
or
|
or
|
||||||
|
(old_item_state["condition"] != enum_condition.ok)
|
||||||
|
or
|
||||||
(
|
(
|
||||||
(old_item_state["count"] is not None)
|
(old_item_state["count"] is not None)
|
||||||
and
|
and
|
||||||
((timestamp - old_item_state["timestamp"]) >= args.awareness_interval)
|
|
||||||
)
|
|
||||||
or
|
|
||||||
(
|
|
||||||
(
|
(
|
||||||
(check_data["schedule"]["kind"] == "minutely")
|
((timestamp - old_item_state["timestamp"]) >= check_data["schedule"]["regular_interval"])
|
||||||
and
|
or
|
||||||
((timestamp - old_item_state["timestamp"]) >= (60))
|
((timestamp - old_item_state["timestamp"]) >= check_data["schedule"]["attentive_interval"])
|
||||||
)
|
|
||||||
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))
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
@ -223,7 +217,7 @@ def main():
|
||||||
)
|
)
|
||||||
|
|
||||||
### execute check and set new state
|
### execute check and set new state
|
||||||
result = check_kind_implementations[check_data["kind"]].run(check_data)
|
result = check_kind_implementations[check_data["kind"]].run(check_data["parameters"])
|
||||||
new_item_state = {
|
new_item_state = {
|
||||||
"timestamp": timestamp,
|
"timestamp": timestamp,
|
||||||
"condition": result["condition"],
|
"condition": result["condition"],
|
||||||
|
|
|
||||||
22
test.hmdl.json
Normal file
22
test.hmdl.json
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
{
|
||||||
|
"defaults": {
|
||||||
|
},
|
||||||
|
"checks": {
|
||||||
|
"test": {
|
||||||
|
"schedule": {
|
||||||
|
"regular_interval": 12,
|
||||||
|
"attentive_interval": 5
|
||||||
|
},
|
||||||
|
"notifications": [
|
||||||
|
{
|
||||||
|
"kind": "console",
|
||||||
|
"parameters": {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"kind": "test",
|
||||||
|
"parameters": {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
todo.md
11
todo.md
|
|
@ -1,4 +1,7 @@
|
||||||
- prevent parallel acces to state file?
|
- parallele Zugriffe auf die Zustands-Datei verhindern
|
||||||
- more resililient checks
|
- fehlertolerantere Implementierung
|
||||||
- self check
|
- Selbst-Test
|
||||||
- notification channel "Matrix"
|
- Matrix als Benachrichtigungs-Kanal
|
||||||
|
- JSON-Schema für Konfiguration von Programm erzeugen lassen
|
||||||
|
- Möglichkeit dauerhaft laufen zulassen (evtl. als systemd-Dienst)
|
||||||
|
- Versionierung
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ cat \
|
||||||
source/packages.py \
|
source/packages.py \
|
||||||
source/lib.py \
|
source/lib.py \
|
||||||
source/check_kinds/_interface.py \
|
source/check_kinds/_interface.py \
|
||||||
|
source/check_kinds/test.py \
|
||||||
source/check_kinds/script.py \
|
source/check_kinds/script.py \
|
||||||
source/check_kinds/http_request.py \
|
source/check_kinds/http_request.py \
|
||||||
source/notification_channels/_interface.py \
|
source/notification_channels/_interface.py \
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue