[add] notification-channel "libnotify" [add] notification-channel "file_touch" [add] check-kind "file_timestamp" [mod] threshold + annoy
This commit is contained in:
parent
f7e3357662
commit
2c2af6bed9
472
hmdl.schema.json
472
hmdl.schema.json
|
|
@ -1,177 +1,38 @@
|
||||||
{
|
{
|
||||||
"$defs": {
|
"$defs": {
|
||||||
"active": {
|
"active": {
|
||||||
"type": "boolean"
|
"type": "boolean",
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
|
"threshold": {
|
||||||
|
"description": "how often a condition has to occur in order to be reported",
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 1,
|
||||||
|
"default": 3
|
||||||
|
},
|
||||||
|
"annoy": {
|
||||||
|
"description": "whether notifications shall be kept sending after the threshold has been surpassed",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false
|
||||||
},
|
},
|
||||||
"schedule": {
|
"schedule": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"properties": {
|
"properties": {
|
||||||
"regular_interval": {
|
"regular_interval": {
|
||||||
"description": "in seconds",
|
"description": "in seconds or as text: minute, hour, day, week",
|
||||||
"type": "integer"
|
"type": ["integer", "string"]
|
||||||
},
|
},
|
||||||
"attentive_interval": {
|
"attentive_interval": {
|
||||||
"description": "in seconds",
|
"description": "in seconds or as text: minute, hour, day, week",
|
||||||
"type": "integer"
|
"type": ["integer", "string"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
"regular_interval"
|
"regular_interval"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"notifications": {
|
"check_kind_test": {
|
||||||
"type": "array",
|
|
||||||
"item": {
|
|
||||||
"anyOf": [
|
|
||||||
{
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": false,
|
|
||||||
"properties": {
|
|
||||||
"kind": {
|
|
||||||
"type": "string",
|
|
||||||
"const": "console"
|
|
||||||
},
|
|
||||||
"parameters": {
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": false,
|
|
||||||
"properties": {
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"kind",
|
|
||||||
"parameters"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": false,
|
|
||||||
"properties": {
|
|
||||||
"kind": {
|
|
||||||
"type": "string",
|
|
||||||
"const": "email"
|
|
||||||
},
|
|
||||||
"parameters": {
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": false,
|
|
||||||
"properties": {
|
|
||||||
"access": {
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": false,
|
|
||||||
"properties": {
|
|
||||||
"host": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"port": {
|
|
||||||
"type": "integer"
|
|
||||||
},
|
|
||||||
"username": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"password": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"host",
|
|
||||||
"port",
|
|
||||||
"username",
|
|
||||||
"password"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"sender": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"receivers": {
|
|
||||||
"type": "array",
|
|
||||||
"item": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"tags": {
|
|
||||||
"description": "list of strings, which will be placed in the e-mail subject",
|
|
||||||
"type": "array",
|
|
||||||
"item": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"default": []
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"access",
|
|
||||||
"sender",
|
|
||||||
"receivers"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"kind",
|
|
||||||
"parameters"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"default": [
|
|
||||||
{
|
|
||||||
"kind": "console",
|
|
||||||
"parameters": {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": false,
|
|
||||||
"properties": {
|
|
||||||
"defaults": {
|
|
||||||
"description": "default values for checks",
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": false,
|
|
||||||
"properties": {
|
|
||||||
"active": {
|
|
||||||
"$ref": "#/$defs/active"
|
|
||||||
},
|
|
||||||
"schedule": {
|
|
||||||
"$ref": "#/$defs/schedule"
|
|
||||||
},
|
|
||||||
"notifications": {
|
|
||||||
"$ref": "#/$defs/notifications"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"checks": {
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": {
|
|
||||||
"allOf": [
|
|
||||||
{
|
|
||||||
"description": "should represent a specific check",
|
|
||||||
"type": "object",
|
|
||||||
"additionalProperties": false,
|
|
||||||
"properties": {
|
|
||||||
"title": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"active": {
|
|
||||||
"$ref": "#/$defs/active"
|
|
||||||
},
|
|
||||||
"schedule": {
|
|
||||||
"$ref": "#/$defs/schedule"
|
|
||||||
},
|
|
||||||
"notifications": {
|
|
||||||
"$ref": "#/$defs/notifications"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"anyOf": [
|
|
||||||
{
|
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -207,7 +68,7 @@
|
||||||
"parameters"
|
"parameters"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
"check_kind_script": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -239,7 +100,65 @@
|
||||||
"parameters"
|
"parameters"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
"check_kind_file_timestamp": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"kind": {
|
||||||
|
"type": "string",
|
||||||
|
"const": "file_timestamp"
|
||||||
|
},
|
||||||
|
"parameters": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"path": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"warning_age": {
|
||||||
|
"type": "integer",
|
||||||
|
"exclusiveMinimum": 0,
|
||||||
|
"default": 3600
|
||||||
|
},
|
||||||
|
"critical_age": {
|
||||||
|
"type": "integer",
|
||||||
|
"exclusiveMinimum": 0,
|
||||||
|
"default": 86400
|
||||||
|
},
|
||||||
|
"condition_on_missing": {
|
||||||
|
"description": "which condition to report if file is missing",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"unknown",
|
||||||
|
"ok",
|
||||||
|
"warning",
|
||||||
|
"critical"
|
||||||
|
],
|
||||||
|
"default": "warning"
|
||||||
|
},
|
||||||
|
"condition_on_implausible": {
|
||||||
|
"description": "which condition to report if the age is negative, i.e. the file is apparently from the future",
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"unknown",
|
||||||
|
"ok",
|
||||||
|
"warning",
|
||||||
|
"critical"
|
||||||
|
],
|
||||||
|
"default": "warning"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"path"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"kind",
|
||||||
|
"parameters"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"check_kind_http_request": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": false,
|
"additionalProperties": false,
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -317,6 +236,241 @@
|
||||||
"kind",
|
"kind",
|
||||||
"parameters"
|
"parameters"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"notification_channel_console": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"kind": {
|
||||||
|
"type": "string",
|
||||||
|
"const": "console"
|
||||||
|
},
|
||||||
|
"parameters": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"kind",
|
||||||
|
"parameters"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification_channel_file_touch": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"kind": {
|
||||||
|
"type": "string",
|
||||||
|
"const": "file_touch"
|
||||||
|
},
|
||||||
|
"parameters": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"path": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"path"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"kind",
|
||||||
|
"parameters"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification_channel_libnotify": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"kind": {
|
||||||
|
"type": "string",
|
||||||
|
"const": "libnotify"
|
||||||
|
},
|
||||||
|
"parameters": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"icon": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"kind",
|
||||||
|
"parameters"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notification_channel_email": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"kind": {
|
||||||
|
"type": "string",
|
||||||
|
"const": "email"
|
||||||
|
},
|
||||||
|
"parameters": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"access": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"host": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"port": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"username": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"password": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"host",
|
||||||
|
"port",
|
||||||
|
"username",
|
||||||
|
"password"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"sender": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"receivers": {
|
||||||
|
"type": "array",
|
||||||
|
"item": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tags": {
|
||||||
|
"description": "list of strings, which will be placed in the e-mail subject",
|
||||||
|
"type": "array",
|
||||||
|
"item": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"default": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"access",
|
||||||
|
"sender",
|
||||||
|
"receivers"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"kind",
|
||||||
|
"parameters"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"notifications": {
|
||||||
|
"type": "array",
|
||||||
|
"item": {
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/$defs/notification_channel_console"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$ref": "#/$defs/notification_channel_file_touch"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$ref": "#/$defs/notification_channel_email"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"default": [
|
||||||
|
{
|
||||||
|
"kind": "console",
|
||||||
|
"parameters": {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"defaults": {
|
||||||
|
"description": "default values for checks",
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"active": {
|
||||||
|
"$ref": "#/$defs/active"
|
||||||
|
},
|
||||||
|
"threshold": {
|
||||||
|
"$ref": "#/$defs/threshold"
|
||||||
|
},
|
||||||
|
"annoy": {
|
||||||
|
"$ref": "#/$defs/annoy"
|
||||||
|
},
|
||||||
|
"schedule": {
|
||||||
|
"$ref": "#/$defs/schedule"
|
||||||
|
},
|
||||||
|
"notifications": {
|
||||||
|
"$ref": "#/$defs/notifications"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"checks": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"allOf": [
|
||||||
|
{
|
||||||
|
"description": "should represent a specific check",
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"title": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"active": {
|
||||||
|
"$ref": "#/$defs/active"
|
||||||
|
},
|
||||||
|
"threshold": {
|
||||||
|
"$ref": "#/$defs/threshold"
|
||||||
|
},
|
||||||
|
"annoy": {
|
||||||
|
"$ref": "#/$defs/annoy"
|
||||||
|
},
|
||||||
|
"schedule": {
|
||||||
|
"$ref": "#/$defs/schedule"
|
||||||
|
},
|
||||||
|
"notifications": {
|
||||||
|
"$ref": "#/$defs/notifications"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"anyOf": [
|
||||||
|
{
|
||||||
|
"$ref": "#/$defs/check_kind_test"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$ref": "#/$defs/check_kind_script"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$ref": "#/$defs/check_kind_file_timestamp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$ref": "#/$defs/check_kind_http_request"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
65
source/check_kinds/file_timestamp.py
Normal file
65
source/check_kinds/file_timestamp.py
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
class implementation_check_kind_file_timestamp(interface_check_kind):
|
||||||
|
|
||||||
|
'''
|
||||||
|
[implementation]
|
||||||
|
'''
|
||||||
|
def normalize_conf_node(self, node):
|
||||||
|
if ("path" not in node):
|
||||||
|
raise ValueError("missing mandatory field 'path'")
|
||||||
|
else:
|
||||||
|
return dict_merge(
|
||||||
|
{
|
||||||
|
"warning_age": (60 * 60),
|
||||||
|
"critical_age": (60 * 60 * 24),
|
||||||
|
"condition_on_missing": condition_encode(enum_condition.warning),
|
||||||
|
"condition_on_implausible": condition_encode(enum_condition.warning),
|
||||||
|
},
|
||||||
|
node
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
[implementation]
|
||||||
|
'''
|
||||||
|
def run(self, parameters):
|
||||||
|
if (not _os.path.exists(parameters["path"])):
|
||||||
|
return {
|
||||||
|
"condition": condition_decode(parameters["condition_on_missing"]),
|
||||||
|
"output": "file is missing"
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
result = _os.stat(parameters["path"])
|
||||||
|
timestamp = get_current_timestamp()
|
||||||
|
age = (timestamp - result.st_atime)
|
||||||
|
if (age < 0):
|
||||||
|
return {
|
||||||
|
"condition": condition_decode(parameters["condition_on_implausible"]),
|
||||||
|
"output": string_coin(
|
||||||
|
"file is apparently from the future; timestamp of checking instance: {{timestamp_this}}; timestamp of file: {{timestamp_that}} (age in seconds: {{age}})",
|
||||||
|
{
|
||||||
|
"timestamp_this": timestamp,
|
||||||
|
"timestamp_that": result.st_atime,
|
||||||
|
"age": ("%u" % age),
|
||||||
|
}
|
||||||
|
),
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
if ((age > 0) and (age <= parameters["warning_age"])):
|
||||||
|
condition = enum_condition.ok
|
||||||
|
elif ((age > parameters["warning_age"]) and (age <= parameters["critical_age"])):
|
||||||
|
condition = enum_condition.warning
|
||||||
|
elif (age > parameters["critical_age"]):
|
||||||
|
condition = enum_condition.critical
|
||||||
|
else:
|
||||||
|
raise ValueError("impossible state")
|
||||||
|
return {
|
||||||
|
"condition": condition,
|
||||||
|
"output": string_coin(
|
||||||
|
"age in seconds: {{age}}",
|
||||||
|
{
|
||||||
|
"age": ("%u" % age),
|
||||||
|
}
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
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"]
|
|
||||||
}
|
|
||||||
|
|
||||||
103
source/main.py
103
source/main.py
|
|
@ -14,6 +14,55 @@ def state_decode(state_encoded):
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def conf_normalize_interval(interval_raw):
|
||||||
|
if (type(interval_raw) == int):
|
||||||
|
return interval_raw
|
||||||
|
elif (type(interval_raw) == str):
|
||||||
|
if (interval_raw == "minute"):
|
||||||
|
return (60)
|
||||||
|
elif (interval_raw == "hour"):
|
||||||
|
return (60 * 60)
|
||||||
|
elif (interval_raw == "day"):
|
||||||
|
return (60 * 60 * 24)
|
||||||
|
elif (interval_raw == "week"):
|
||||||
|
return (60 * 60 * 24 * 7)
|
||||||
|
else:
|
||||||
|
raise ValueError("invalid string interval value: %s" % interval_raw)
|
||||||
|
else:
|
||||||
|
raise ValueError("invalid type for interval value")
|
||||||
|
|
||||||
|
|
||||||
|
def conf_normalize_schedule(node):
|
||||||
|
node_ = dict_merge(
|
||||||
|
{
|
||||||
|
"regular_interval": (60 * 60),
|
||||||
|
"attentive_interval": (60 * 2),
|
||||||
|
},
|
||||||
|
node
|
||||||
|
)
|
||||||
|
return {
|
||||||
|
"regular_interval": conf_normalize_interval(node["regular_interval"]),
|
||||||
|
"attentive_interval": conf_normalize_interval(node["attentive_interval"]),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def conf_normalize_defaults(node):
|
||||||
|
return dict_merge(
|
||||||
|
{
|
||||||
|
"active": True,
|
||||||
|
"threshold": 3,
|
||||||
|
"annoy": False,
|
||||||
|
"schedule": {
|
||||||
|
"regular_interval": (60 * 60),
|
||||||
|
"attentive_interval": (60 * 2),
|
||||||
|
},
|
||||||
|
"notifications": [
|
||||||
|
],
|
||||||
|
},
|
||||||
|
node
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
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 'check' field 'kind'")
|
raise ValueError("missing mandatory 'check' field 'kind'")
|
||||||
|
|
@ -25,6 +74,8 @@ def conf_normalize_check(check_kind_implementations, defaults, name, node):
|
||||||
{
|
{
|
||||||
"title": name,
|
"title": name,
|
||||||
"active": defaults["active"],
|
"active": defaults["active"],
|
||||||
|
"threshold": defaults["threshold"],
|
||||||
|
"annoy": defaults["annoy"],
|
||||||
"schedule": defaults["schedule"],
|
"schedule": defaults["schedule"],
|
||||||
"notifications": defaults["notifications"],
|
"notifications": defaults["notifications"],
|
||||||
"parameters": {},
|
"parameters": {},
|
||||||
|
|
@ -34,28 +85,15 @@ def conf_normalize_check(check_kind_implementations, defaults, name, node):
|
||||||
return {
|
return {
|
||||||
"title": node_["title"],
|
"title": node_["title"],
|
||||||
"active": node_["active"],
|
"active": node_["active"],
|
||||||
"schedule": node_["schedule"],
|
"threshold": node_["threshold"],
|
||||||
|
"annoy": node_["annoy"],
|
||||||
|
"schedule": conf_normalize_schedule(node_["schedule"]),
|
||||||
"notifications": node_["notifications"],
|
"notifications": node_["notifications"],
|
||||||
"kind": node_["kind"],
|
"kind": node_["kind"],
|
||||||
"parameters": check_kind_implementations[node_["kind"]].normalize_conf_node(node_["parameters"]),
|
"parameters": check_kind_implementations[node_["kind"]].normalize_conf_node(node_["parameters"]),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def conf_normalize_defaults(node):
|
|
||||||
return dict_merge(
|
|
||||||
{
|
|
||||||
"active": True,
|
|
||||||
"schedule": {
|
|
||||||
"regular_interval": (60 * 60),
|
|
||||||
"attentive_interval": (60 * 2),
|
|
||||||
},
|
|
||||||
"notifications": [
|
|
||||||
],
|
|
||||||
},
|
|
||||||
node
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def conf_normalize_root(check_kind_implementations, node):
|
def conf_normalize_root(check_kind_implementations, node):
|
||||||
return dict(
|
return dict(
|
||||||
map(
|
map(
|
||||||
|
|
@ -105,23 +143,6 @@ def main():
|
||||||
dest = "erase_state",
|
dest = "erase_state",
|
||||||
help = "whether the state shall be deleted on start; this will cause that all checks are executed"
|
help = "whether the state shall be deleted on start; this will cause that all checks are executed"
|
||||||
)
|
)
|
||||||
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(
|
argumentparser.add_argument(
|
||||||
"-e",
|
"-e",
|
||||||
"--expose-full-conf",
|
"--expose-full-conf",
|
||||||
|
|
@ -149,15 +170,17 @@ 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(),
|
||||||
|
"file_timestamp": implementation_check_kind_file_timestamp(),
|
||||||
"http_request": implementation_check_kind_http_request(),
|
"http_request": implementation_check_kind_http_request(),
|
||||||
}
|
}
|
||||||
|
|
||||||
### load notification channel implementations
|
### load notification channel implementations
|
||||||
notification_channel_implementations = {
|
notification_channel_implementations = {
|
||||||
"console": implementation_notification_channel_console(),
|
"console": implementation_notification_channel_console(),
|
||||||
|
"file_touch": implementation_notification_channel_file_touch(),
|
||||||
"email": implementation_notification_channel_email(),
|
"email": implementation_notification_channel_email(),
|
||||||
|
"libnotify": implementation_notification_channel_libnotify(),
|
||||||
}
|
}
|
||||||
|
|
||||||
### get configuration data
|
### get configuration data
|
||||||
|
|
@ -194,16 +217,14 @@ def main():
|
||||||
or
|
or
|
||||||
(old_item_state["condition"] != enum_condition.ok)
|
(old_item_state["condition"] != enum_condition.ok)
|
||||||
or
|
or
|
||||||
|
((timestamp - old_item_state["timestamp"]) >= check_data["schedule"]["regular_interval"])
|
||||||
|
or
|
||||||
(
|
(
|
||||||
(old_item_state["count"] is not None)
|
(old_item_state["count"] is not None)
|
||||||
and
|
and
|
||||||
(
|
|
||||||
((timestamp - old_item_state["timestamp"]) >= check_data["schedule"]["regular_interval"])
|
|
||||||
or
|
|
||||||
((timestamp - old_item_state["timestamp"]) >= check_data["schedule"]["attentive_interval"])
|
((timestamp - old_item_state["timestamp"]) >= check_data["schedule"]["attentive_interval"])
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
|
||||||
if (not due):
|
if (not due):
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
|
|
@ -233,7 +254,7 @@ def main():
|
||||||
if (
|
if (
|
||||||
(old_item_state["count"] is not None)
|
(old_item_state["count"] is not None)
|
||||||
and
|
and
|
||||||
((old_item_state["count"] + 1) <= args.threshold)
|
((old_item_state["count"] + 1) <= check_data["threshold"])
|
||||||
) else
|
) else
|
||||||
None
|
None
|
||||||
)
|
)
|
||||||
|
|
@ -247,13 +268,13 @@ def main():
|
||||||
(
|
(
|
||||||
(new_item_state["count"] is not None)
|
(new_item_state["count"] is not None)
|
||||||
and
|
and
|
||||||
(new_item_state["count"] == args.threshold)
|
(new_item_state["count"] == check_data["threshold"])
|
||||||
)
|
)
|
||||||
or
|
or
|
||||||
(
|
(
|
||||||
(new_item_state["count"] is None)
|
(new_item_state["count"] is None)
|
||||||
and
|
and
|
||||||
args.keep_notifying
|
check_data["annoy"]
|
||||||
)
|
)
|
||||||
):
|
):
|
||||||
for notification in check_data["notifications"]:
|
for notification in check_data["notifications"]:
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,9 @@
|
||||||
class interface_notification_channel(object):
|
class interface_notification_channel(object):
|
||||||
|
|
||||||
|
def normalize_conf_node(self, node):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
def notify(self, parameters, name, data, state, output):
|
def notify(self, parameters, name, data, state, output):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,16 @@
|
||||||
class implementation_notification_channel_console(interface_notification_channel):
|
class implementation_notification_channel_console(interface_notification_channel):
|
||||||
|
|
||||||
|
'''
|
||||||
|
[implementation]
|
||||||
|
'''
|
||||||
|
def normalize_conf_node(self, node):
|
||||||
|
return dict_merge(
|
||||||
|
{
|
||||||
|
},
|
||||||
|
node
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
[implementation]
|
[implementation]
|
||||||
'''
|
'''
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,16 @@
|
||||||
class implementation_notification_channel_email(interface_notification_channel):
|
class implementation_notification_channel_email(interface_notification_channel):
|
||||||
|
|
||||||
|
'''
|
||||||
|
[implementation]
|
||||||
|
'''
|
||||||
|
def normalize_conf_node(self, node):
|
||||||
|
return dict_merge(
|
||||||
|
{
|
||||||
|
},
|
||||||
|
node
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
'''
|
'''
|
||||||
[implementation]
|
[implementation]
|
||||||
'''
|
'''
|
||||||
|
|
|
||||||
19
source/notification_channels/file_touch.py
Normal file
19
source/notification_channels/file_touch.py
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
class implementation_notification_channel_file_touch(interface_notification_channel):
|
||||||
|
|
||||||
|
'''
|
||||||
|
[implementation]
|
||||||
|
'''
|
||||||
|
def normalize_conf_node(self, node):
|
||||||
|
return dict_merge(
|
||||||
|
{
|
||||||
|
},
|
||||||
|
node
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
[implementation]
|
||||||
|
'''
|
||||||
|
def notify(self, parameters, name, data, state, output):
|
||||||
|
_os.path.touch(parameters["path"])
|
||||||
|
|
||||||
81
source/notification_channels/libnotify.py
Normal file
81
source/notification_channels/libnotify.py
Normal file
|
|
@ -0,0 +1,81 @@
|
||||||
|
class implementation_notification_channel_libnotify(interface_notification_channel):
|
||||||
|
|
||||||
|
'''
|
||||||
|
[implementation]
|
||||||
|
'''
|
||||||
|
def normalize_conf_node(self, node):
|
||||||
|
return dict_merge(
|
||||||
|
{
|
||||||
|
"icon": None,
|
||||||
|
},
|
||||||
|
node
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
[implementation]
|
||||||
|
'''
|
||||||
|
def notify(self, parameters, name, data, state, output):
|
||||||
|
def condition_translate(condition):
|
||||||
|
if (condition == enum_condition.unknown):
|
||||||
|
return "normal"
|
||||||
|
elif (condition == enum_condition.ok):
|
||||||
|
return "low"
|
||||||
|
elif (condition == enum_condition.warning):
|
||||||
|
return "normal"
|
||||||
|
elif (condition == enum_condition.critical):
|
||||||
|
return "critical"
|
||||||
|
else:
|
||||||
|
raise ValueError("impossible condition")
|
||||||
|
parts = []
|
||||||
|
parts.append(
|
||||||
|
"notify-send"
|
||||||
|
)
|
||||||
|
## app name
|
||||||
|
parts.append(
|
||||||
|
string_coin(
|
||||||
|
"--app-name={{app_name}}",
|
||||||
|
{
|
||||||
|
"app_name": "heimdall",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
## urgency
|
||||||
|
parts.append(
|
||||||
|
string_coin(
|
||||||
|
"--urgency={{urgency}}",
|
||||||
|
{
|
||||||
|
"urgency": condition_translate(state["condition"]),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
## icon
|
||||||
|
if ("icon" not in parameters):
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
parts.append(
|
||||||
|
string_coin(
|
||||||
|
"--icon={{icon}}",
|
||||||
|
{
|
||||||
|
"icon": parameters["icon"],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
## summary
|
||||||
|
parts.append(
|
||||||
|
string_coin(
|
||||||
|
"{{condition}} | {{title}}",
|
||||||
|
{
|
||||||
|
"title": data["title"],
|
||||||
|
"condition": condition_encode(state["condition"]).upper(),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
## body
|
||||||
|
parts.append(
|
||||||
|
"(no infos)"
|
||||||
|
if (output == "") else
|
||||||
|
output
|
||||||
|
)
|
||||||
|
_subprocess.run(parts)
|
||||||
|
|
||||||
|
|
@ -3,8 +3,10 @@
|
||||||
},
|
},
|
||||||
"checks": {
|
"checks": {
|
||||||
"test": {
|
"test": {
|
||||||
|
"threshold": 1,
|
||||||
|
"annoy": true,
|
||||||
"schedule": {
|
"schedule": {
|
||||||
"regular_interval": 12,
|
"regular_interval": 60,
|
||||||
"attentive_interval": 5
|
"attentive_interval": 5
|
||||||
},
|
},
|
||||||
"notifications": [
|
"notifications": [
|
||||||
|
|
@ -12,10 +14,19 @@
|
||||||
"kind": "console",
|
"kind": "console",
|
||||||
"parameters": {
|
"parameters": {
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"kind": "libnotify",
|
||||||
|
"parameters": {
|
||||||
|
"icon": "/home/fenris/bilder/zeug/heimdall.png"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"kind": "test",
|
"kind": "file_timestamp",
|
||||||
"parameters": {
|
"parameters": {
|
||||||
|
"path": "/tmp/test",
|
||||||
|
"warning_age": 60,
|
||||||
|
"critical_age": 120
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
5
todo.md
5
todo.md
|
|
@ -1,7 +1,10 @@
|
||||||
- parallele Zugriffe auf die Zustands-Datei verhindern
|
- parallele Zugriffe auf die Zustands-Datei verhindern
|
||||||
- fehlertolerantere Implementierung
|
- fehlertolerantere Implementierung
|
||||||
- Selbst-Test
|
- Selbst-Test
|
||||||
- Matrix als Benachrichtigungs-Kanal
|
- Benachrichtigungs-Kanäle:
|
||||||
|
- Matrix
|
||||||
- JSON-Schema für Konfiguration von Programm erzeugen lassen
|
- JSON-Schema für Konfiguration von Programm erzeugen lassen
|
||||||
- Möglichkeit dauerhaft laufen zulassen (evtl. als systemd-Dienst)
|
- Möglichkeit dauerhaft laufen zulassen (evtl. als systemd-Dienst)
|
||||||
- Versionierung
|
- Versionierung
|
||||||
|
- Umbenennung: `output` zu `info`
|
||||||
|
- Test-Routinen
|
||||||
|
|
|
||||||
|
|
@ -6,12 +6,14 @@ 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/file_timestamp.py \
|
||||||
source/check_kinds/http_request.py \
|
source/check_kinds/http_request.py \
|
||||||
source/notification_channels/_interface.py \
|
source/notification_channels/_interface.py \
|
||||||
source/notification_channels/console.py \
|
source/notification_channels/console.py \
|
||||||
|
source/notification_channels/file_touch.py \
|
||||||
source/notification_channels/email.py \
|
source/notification_channels/email.py \
|
||||||
|
source/notification_channels/libnotify.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