318 lines
7.2 KiB
Python
318 lines
7.2 KiB
Python
|
|
def conf_schema_active():
|
||
|
|
return {
|
||
|
|
"type": "boolean",
|
||
|
|
"default": True
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
def conf_schema_threshold():
|
||
|
|
return {
|
||
|
|
"description": "how often a condition has to occur in order to be reported",
|
||
|
|
"type": "integer",
|
||
|
|
"minimum": 1,
|
||
|
|
"default": 3
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
def conf_schema_annoy():
|
||
|
|
return {
|
||
|
|
"description": "whether notifications shall be kept sending after the threshold has been surpassed",
|
||
|
|
"type": "boolean",
|
||
|
|
"default": False
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
def conf_schema_interval(default):
|
||
|
|
return {
|
||
|
|
"description": "in seconds or as text",
|
||
|
|
"anyOf": [
|
||
|
|
{
|
||
|
|
"type": "integer",
|
||
|
|
"exclusiveMinimum": 0
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"type": "string",
|
||
|
|
"enum": [
|
||
|
|
"minute",
|
||
|
|
"hour",
|
||
|
|
"day",
|
||
|
|
"week",
|
||
|
|
]
|
||
|
|
},
|
||
|
|
],
|
||
|
|
"default": default,
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
def conf_schema_schedule():
|
||
|
|
return {
|
||
|
|
"type": "object",
|
||
|
|
"additionalProperties": False,
|
||
|
|
"properties": {
|
||
|
|
"regular_interval": conf_schema_interval(60 * 60),
|
||
|
|
"attentive_interval": conf_schema_interval(60 * 2),
|
||
|
|
},
|
||
|
|
"required": [
|
||
|
|
]
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
def conf_schema_notifications(notification_channel_implementations):
|
||
|
|
return {
|
||
|
|
"type": "array",
|
||
|
|
"items": {
|
||
|
|
"anyOf": list(
|
||
|
|
map(
|
||
|
|
lambda pair: {
|
||
|
|
"title": ("check kind '%s'" % pair[0]),
|
||
|
|
"type": "object",
|
||
|
|
"unevaluatedProperties": False,
|
||
|
|
"properties": {
|
||
|
|
"kind": {
|
||
|
|
"type": "string",
|
||
|
|
"enum": [pair[0]]
|
||
|
|
},
|
||
|
|
"parameters": pair[1].parameters_schema(),
|
||
|
|
},
|
||
|
|
"required": [
|
||
|
|
"kind",
|
||
|
|
"parameters"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
notification_channel_implementations.items()
|
||
|
|
)
|
||
|
|
)
|
||
|
|
},
|
||
|
|
"default": [
|
||
|
|
{
|
||
|
|
"kind": "console",
|
||
|
|
"parameters": {
|
||
|
|
}
|
||
|
|
}
|
||
|
|
]
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
def conf_schema_root(check_kind_implementations, notification_channel_implementations):
|
||
|
|
return {
|
||
|
|
"type": "object",
|
||
|
|
"additionalProperties": False,
|
||
|
|
"properties": {
|
||
|
|
"defaults": {
|
||
|
|
"description": "default values for checks",
|
||
|
|
"type": "object",
|
||
|
|
"additionalProperties": False,
|
||
|
|
"properties": {
|
||
|
|
"active": conf_schema_active(),
|
||
|
|
"threshold": conf_schema_threshold(),
|
||
|
|
"annoy": conf_schema_annoy(),
|
||
|
|
"schedule": conf_schema_schedule(),
|
||
|
|
"notifications": conf_schema_notifications(notification_channel_implementations),
|
||
|
|
},
|
||
|
|
"required": [
|
||
|
|
]
|
||
|
|
},
|
||
|
|
"checks": {
|
||
|
|
"type": "array",
|
||
|
|
"items": {
|
||
|
|
"allOf": [
|
||
|
|
{
|
||
|
|
"description": "should represent a specific check",
|
||
|
|
"type": "object",
|
||
|
|
"unevaluatedProperties": False,
|
||
|
|
"properties": {
|
||
|
|
"name": {
|
||
|
|
"type": "string"
|
||
|
|
},
|
||
|
|
"title": {
|
||
|
|
"type": "string"
|
||
|
|
},
|
||
|
|
"active": conf_schema_active(),
|
||
|
|
"threshold": conf_schema_threshold(),
|
||
|
|
"annoy": conf_schema_annoy(),
|
||
|
|
"schedule": conf_schema_schedule(),
|
||
|
|
"notifications": conf_schema_notifications(notification_channel_implementations),
|
||
|
|
},
|
||
|
|
"required": [
|
||
|
|
"name",
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"anyOf": list(
|
||
|
|
map(
|
||
|
|
lambda pair: {
|
||
|
|
"title": ("notification channel '%s'" % pair[0]),
|
||
|
|
"type": "object",
|
||
|
|
"unevaluatedProperties": False,
|
||
|
|
"properties": {
|
||
|
|
"kind": {
|
||
|
|
"type": "string",
|
||
|
|
"enum": [pair[0]]
|
||
|
|
},
|
||
|
|
"parameters": pair[1].parameters_schema(),
|
||
|
|
},
|
||
|
|
"required": [
|
||
|
|
"kind",
|
||
|
|
"parameters"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
check_kind_implementations.items()
|
||
|
|
)
|
||
|
|
),
|
||
|
|
},
|
||
|
|
]
|
||
|
|
}
|
||
|
|
}
|
||
|
|
},
|
||
|
|
"required": [
|
||
|
|
"defaults",
|
||
|
|
"checks",
|
||
|
|
]
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
def conf_normalize_interval(interval_raw):
|
||
|
|
if (type(interval_raw) == int):
|
||
|
|
return interval_raw
|
||
|
|
elif (type(interval_raw) == str):
|
||
|
|
map_ = {
|
||
|
|
"minute": (60),
|
||
|
|
"hour": (60 * 60),
|
||
|
|
"day": (60 * 60 * 24),
|
||
|
|
"week": (60 * 60 * 24 * 7),
|
||
|
|
}
|
||
|
|
if (interval_raw not in map_):
|
||
|
|
raise ValueError("invalid string interval value: %s" % interval_raw)
|
||
|
|
else:
|
||
|
|
return map_[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_notification(notification_channel_implementations, node):
|
||
|
|
if (node["kind"] not in notification_channel_implementations):
|
||
|
|
raise ValueError("invalid notification kind: %s" % notification["kind"])
|
||
|
|
else:
|
||
|
|
return {
|
||
|
|
"kind": node["kind"],
|
||
|
|
"parameters": notification_channel_implementations[node["kind"]].normalize_conf_node(node["parameters"]),
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
def conf_normalize_defaults(notification_channel_implementations, node):
|
||
|
|
node_ = dict_merge(
|
||
|
|
{
|
||
|
|
"active": True,
|
||
|
|
"threshold": 3,
|
||
|
|
"annoy": False,
|
||
|
|
"schedule": {
|
||
|
|
"regular_interval": (60 * 60),
|
||
|
|
"attentive_interval": (60 * 2),
|
||
|
|
},
|
||
|
|
"notifications": [
|
||
|
|
],
|
||
|
|
},
|
||
|
|
node
|
||
|
|
)
|
||
|
|
return {
|
||
|
|
"active": node_["active"],
|
||
|
|
"threshold": node_["threshold"],
|
||
|
|
"annoy": node_["annoy"],
|
||
|
|
"schedule": node_["schedule"],
|
||
|
|
"notifications": list(
|
||
|
|
map(
|
||
|
|
lambda x: conf_normalize_notification(notification_channel_implementations, x),
|
||
|
|
node_["notifications"]
|
||
|
|
)
|
||
|
|
),
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
def conf_normalize_check(check_kind_implementations, notification_channel_implementations, defaults, node):
|
||
|
|
if ("name" not in node):
|
||
|
|
raise ValueError("missing mandatory field in 'check' node: 'name'")
|
||
|
|
else:
|
||
|
|
if ("kind" not in node):
|
||
|
|
raise ValueError("missing mandatory field in 'check' node: 'kind'")
|
||
|
|
else:
|
||
|
|
if (node["kind"] not in check_kind_implementations):
|
||
|
|
raise ValueError("invalid check kind: '%s'" % node["kind"])
|
||
|
|
else:
|
||
|
|
node_ = dict_merge(
|
||
|
|
{
|
||
|
|
"title": node["name"],
|
||
|
|
"active": defaults["active"],
|
||
|
|
"threshold": defaults["threshold"],
|
||
|
|
"annoy": defaults["annoy"],
|
||
|
|
"schedule": defaults["schedule"],
|
||
|
|
"notifications": defaults["notifications"],
|
||
|
|
"parameters": {},
|
||
|
|
},
|
||
|
|
node
|
||
|
|
)
|
||
|
|
return {
|
||
|
|
"name": node_["name"],
|
||
|
|
"title": node_["title"],
|
||
|
|
"active": node_["active"],
|
||
|
|
"threshold": node_["threshold"],
|
||
|
|
"annoy": node_["annoy"],
|
||
|
|
"schedule": conf_normalize_schedule(node_["schedule"]),
|
||
|
|
"notifications": list(
|
||
|
|
map(
|
||
|
|
lambda x: conf_normalize_notification(notification_channel_implementations, x),
|
||
|
|
node_["notifications"]
|
||
|
|
)
|
||
|
|
),
|
||
|
|
"kind": node_["kind"],
|
||
|
|
"parameters": check_kind_implementations[node_["kind"]].normalize_conf_node(node_["parameters"]),
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
def conf_normalize_root(check_kind_implementations, notification_channel_implementations, node):
|
||
|
|
counts = {}
|
||
|
|
for node_ in node["checks"]:
|
||
|
|
if (node_["name"] not in counts):
|
||
|
|
counts[node_["name"]] = 0
|
||
|
|
counts[node_["name"]] += 1
|
||
|
|
fails = list(filter(lambda pair: (pair[1] > 1), counts.items()))
|
||
|
|
if (len(fails) > 0):
|
||
|
|
raise ValueError(
|
||
|
|
string_coin(
|
||
|
|
"ambiguous check names: {{names}}",
|
||
|
|
{
|
||
|
|
"names": ",".join(counts.keys()),
|
||
|
|
}
|
||
|
|
)
|
||
|
|
)
|
||
|
|
else:
|
||
|
|
defaults = conf_normalize_defaults(notification_channel_implementations, node["defaults"])
|
||
|
|
return {
|
||
|
|
"defaults": defaults,
|
||
|
|
"checks": list(
|
||
|
|
map(
|
||
|
|
lambda node_: conf_normalize_check(
|
||
|
|
check_kind_implementations,
|
||
|
|
notification_channel_implementations,
|
||
|
|
defaults,
|
||
|
|
node_
|
||
|
|
),
|
||
|
|
node["checks"]
|
||
|
|
)
|
||
|
|
)
|
||
|
|
}
|
||
|
|
|