[mod] viele kleine Anpassungen

This commit is contained in:
Christian Fraß 2022-11-30 08:15:35 +01:00
parent be60379e35
commit f7e3357662
9 changed files with 138 additions and 58 deletions

View file

@ -7,17 +7,17 @@
"type": "object",
"additionalProperties": false,
"properties": {
"kind": {
"type": "string",
"enum": [
"minutely",
"hourly",
"daily"
]
"regular_interval": {
"description": "in seconds",
"type": "integer"
},
"attentive_interval": {
"description": "in seconds",
"type": "integer"
}
},
"required": [
"kind"
"regular_interval"
]
},
"notifications": {
@ -171,6 +171,42 @@
},
{
"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",
"additionalProperties": false,

View file

@ -4,6 +4,6 @@ class interface_check_kind(object):
raise NotImplementedError
def run(self, check_data):
def run(self, parameters):
raise NotImplementedError

View file

@ -22,22 +22,22 @@ class implementation_check_kind_http_request(interface_check_kind):
'''
[implementation]
'''
def run(self, check_data):
if (check_data["parameters"]["request"]["method"] == "GET"):
def run(self, parameters):
if (parameters["request"]["method"] == "GET"):
method_handled = True
try:
response = _requests.get(
check_data["parameters"]["request"]["target"]
parameters["request"]["target"]
)
error = None
except Exception as error_:
error = error_
response = None
elif (check_data["parameters"]["request"]["method"] == "POST"):
elif (parameters["request"]["method"] == "POST"):
method_handled = True
try:
response = _requests.post(
check_data["parameters"]["request"]["target"]
parameters["request"]["target"]
)
error = None
except Exception as error_:
@ -49,21 +49,21 @@ class implementation_check_kind_http_request(interface_check_kind):
if (not method_handled):
return {
"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:
if (response is None):
return {
"condition": (
enum_condition.warning
if check_data["parameters"]["as_warning"] else
if parameters["as_warning"] else
enum_condition.critical
),
"output": "HTTP request failed",
}
else:
lines = []
for (key, value, ) in check_data["parameters"]["response"].items():
for (key, value, ) in parameters["response"].items():
if (key == "status_code"):
if ((value is None) or (response.status_code == value)):
pass
@ -112,7 +112,7 @@ class implementation_check_kind_http_request(interface_check_kind):
if (len(lines) <= 0) else
(
enum_condition.warning
if check_data["parameters"]["as_warning"] else
if parameters["as_warning"] else
enum_condition.critical
)
),

View file

@ -14,9 +14,9 @@ class implementation_check_kind_script(interface_check_kind):
'''
[implementation]
'''
def run(self, check_data):
def run(self, parameters):
result = _subprocess.run(
[check_data["parameters"]["path"]] + check_data["parameters"]["arguments"],
[parameters["path"]] + parameters["arguments"],
capture_output = True
)
if (result.returncode == 0):

View 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"]
}

View file

@ -16,7 +16,7 @@ def state_decode(state_encoded):
def conf_normalize_check(check_kind_implementations, defaults, name, node):
if ("kind" not in node):
raise ValueError("missing mandatory 'member' field 'kind'")
raise ValueError("missing mandatory 'check' field 'kind'")
else:
if (node["kind"] not in check_kind_implementations):
raise ValueError("unhandled kind: %s" % node["kind"])
@ -45,8 +45,12 @@ def conf_normalize_defaults(node):
return dict_merge(
{
"active": True,
"schedule": {"kind": "hourly"},
"notifications": [],
"schedule": {
"regular_interval": (60 * 60),
"attentive_interval": (60 * 2),
},
"notifications": [
],
},
node
)
@ -93,6 +97,14 @@ def main():
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"
)
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(
"-t",
"--threshold",
@ -102,15 +114,6 @@ def main():
metavar = "<threshold>",
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(
"-k",
"--keep-notifying",
@ -120,7 +123,7 @@ def main():
help = "whether notifications shall be kept sending after the threshold has been surpassed"
)
argumentparser.add_argument(
"-x",
"-e",
"--expose-full-conf",
action = "store_true",
default = False,
@ -146,6 +149,7 @@ def main():
### load check kind implementations
check_kind_implementations = {
"test": implementation_check_kind_test(),
"script": implementation_check_kind_script(),
"http_request": implementation_check_kind_http_request(),
}
@ -163,7 +167,11 @@ def main():
_sys.exit(1)
else:
### get state data
if (not _os.path.exists(state_path)):
if (
(not _os.path.exists(state_path))
or
args.erase_state
):
state_data = {}
file_write(state_path, _json.dumps(state_data, indent = "\t"))
else:
@ -184,29 +192,15 @@ def main():
due = (
(old_item_state is None)
or
(old_item_state["condition"] != enum_condition.ok)
or
(
(old_item_state["count"] is not None)
and
((timestamp - old_item_state["timestamp"]) >= args.awareness_interval)
)
(
((timestamp - old_item_state["timestamp"]) >= check_data["schedule"]["regular_interval"])
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))
((timestamp - old_item_state["timestamp"]) >= check_data["schedule"]["attentive_interval"])
)
)
)
@ -223,7 +217,7 @@ def main():
)
### 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 = {
"timestamp": timestamp,
"condition": result["condition"],

22
test.hmdl.json Normal file
View 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
View file

@ -1,4 +1,7 @@
- prevent parallel acces to state file?
- more resililient checks
- self check
- notification channel "Matrix"
- parallele Zugriffe auf die Zustands-Datei verhindern
- fehlertolerantere Implementierung
- Selbst-Test
- Matrix als Benachrichtigungs-Kanal
- JSON-Schema für Konfiguration von Programm erzeugen lassen
- Möglichkeit dauerhaft laufen zulassen (evtl. als systemd-Dienst)
- Versionierung

View file

@ -6,6 +6,7 @@ cat \
source/packages.py \
source/lib.py \
source/check_kinds/_interface.py \
source/check_kinds/test.py \
source/check_kinds/script.py \
source/check_kinds/http_request.py \
source/notification_channels/_interface.py \