Skip to content

Commit

Permalink
feat: add grafana v10 AlertRule support
Browse files Browse the repository at this point in the history
  • Loading branch information
desmaraisp committed Jan 26, 2024
1 parent bc9e6e3 commit baee5f9
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 6 deletions.
74 changes: 68 additions & 6 deletions grafanalib/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ def to_json_data(self):
EXP_TYPE_REDUCE = 'reduce'
EXP_TYPE_RESAMPLE = 'resample'
EXP_TYPE_MATH = 'math'
EXP_TYPE_THRESHOLD = 'threshold'

# Alert Expression Reducer Function
EXP_REDUCER_FUNC_MIN = 'min'
Expand Down Expand Up @@ -1418,6 +1419,23 @@ def to_json_data(self):

return expression

@attr.s
class AlertExpressionv10(AlertExpression):
"""
Specific to Grafana v10.x, adds support for threshold expression type
"""

expressionType = attr.ib(
default=EXP_TYPE_CLASSIC,
validator=in_([
EXP_TYPE_CLASSIC,
EXP_TYPE_REDUCE,
EXP_TYPE_RESAMPLE,
EXP_TYPE_MATH,
EXP_TYPE_THRESHOLD
])
)


@attr.s
class Alert(object):
Expand Down Expand Up @@ -1510,6 +1528,16 @@ def is_valid_triggersv9(instance, attribute, value):
is_valid_target(instance, "alert trigger target", trigger)


def is_valid_triggersv10(instance, attribute, value):
"""Validator for AlertRule triggers for Grafana v9"""
for trigger in value:
if not (isinstance(trigger, Target) or isinstance(trigger, AlertExpressionv10)):
raise ValueError(f"{attribute.name} must either be a Target or AlertExpressionV10")

if isinstance(trigger, Target):
is_valid_target(instance, "alert trigger target", trigger)


@attr.s
class AlertRulev8(object):
"""
Expand Down Expand Up @@ -1620,10 +1648,8 @@ def to_json_data(self):


@attr.s
class AlertRulev9(object):
class _BaseAlertRule(object):
"""
Create a Grafana 9.x+ Alert Rule
:param title: The alert's title, must be unique per folder
:param triggers: A list of Targets and AlertConditions.
The Target specifies the query, and the AlertCondition specifies how this is used to alert.
Expand All @@ -1650,7 +1676,6 @@ class AlertRulev9(object):
"""

title = attr.ib()
triggers = attr.ib(factory=list, validator=is_valid_triggersv9)
annotations = attr.ib(factory=dict, validator=instance_of(dict))
labels = attr.ib(factory=dict, validator=instance_of(dict))

Expand Down Expand Up @@ -1678,7 +1703,7 @@ class AlertRulev9(object):
dashboard_uid = attr.ib(default="", validator=instance_of(str))
panel_id = attr.ib(default=0, validator=instance_of(int))

def to_json_data(self):
def _render_triggers(self):
data = []

for trigger in self.triggers:
Expand All @@ -1696,6 +1721,21 @@ def to_json_data(self):
else:
data += [trigger.to_json_data()]

return data

def to_json_data(self):
pass


@attr.s
class AlertRulev9(_BaseAlertRule):
"""
Create a Grafana 9.x+ Alert Rule
"""

triggers = attr.ib(factory=list, validator=is_valid_triggersv9)

def to_json_data(self):
return {
"uid": self.uid,
"for": self.evaluateFor,
Expand All @@ -1704,13 +1744,35 @@ def to_json_data(self):
"grafana_alert": {
"title": self.title,
"condition": self.condition,
"data": data,
"data": self._render_triggers(),
"no_data_state": self.noDataAlertState,
"exec_err_state": self.errorAlertState,
},
}


@attr.s
class AlertRulev10(_BaseAlertRule):
"""
Create a Grafana 10.x+ Alert Rule
"""

triggers = attr.ib(factory=list, validator=is_valid_triggersv10)

def to_json_data(self):
return {
"uid": self.uid,
"for": self.evaluateFor,
"labels": self.labels,
"annotations": self.annotations,
"title": self.title,
"condition": self.condition,
"data": self._render_triggers(),
"noDataState": self.noDataAlertState,
"execErrState": self.errorAlertState,
}


@attr.s
class AlertFileBasedProvisioning(object):
"""
Expand Down
41 changes: 41 additions & 0 deletions grafanalib/tests/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -908,6 +908,47 @@ def test_alertrulev9():
assert data['grafana_alert']['condition'] == condition


def test_alertrulev10():
title = "My Important Alert!"
annotations = {"summary": "this alert fires when prod is down!!!"}
labels = {"severity": "serious"}
condition = 'C'
rule = G.AlertRulev10(
title=title,
uid='alert1',
condition=condition,
triggers=[
G.Target(
expr='query',
refId='A',
datasource='Prometheus',
),
G.AlertExpression(
refId='B',
expressionType=G.EXP_TYPE_CLASSIC,
expression='A',
conditions=[
G.AlertCondition(
evaluator=G.GreaterThan(3),
operator=G.OP_AND,
reducerType=G.RTYPE_LAST
)
]
),
],
annotations=annotations,
labels=labels,
evaluateFor="3m",
)

data = rule.to_json_data()
assert data['annotations'] == annotations
assert data['labels'] == labels
assert data['for'] == "3m"
assert data['title'] == title
assert data['condition'] == condition


def test_alertexpression():
refId = 'D'
expression = 'C'
Expand Down

0 comments on commit baee5f9

Please sign in to comment.