Skip to content

Commit 07e8311

Browse files
committed
Add v2 APIs for Rule
We have added several APIs for retrieving, updating and deleting Rule.
1 parent ad74502 commit 07e8311

16 files changed

+507
-4
lines changed

promgen/filters.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,3 +105,34 @@ class NotifierFilter(django_filters.rest_framework.FilterSet):
105105
lookup_expr="exact",
106106
help_text="Filter by exact owner username. Example: owner=Example Owner",
107107
)
108+
109+
110+
class RuleFilterV2(django_filters.rest_framework.FilterSet):
111+
name = django_filters.CharFilter(
112+
field_name="name",
113+
lookup_expr="contains",
114+
help_text="Filter by rule name containing a specific substring. Example: name=Example Rule",
115+
)
116+
parent = django_filters.CharFilter(
117+
field_name="parent__name",
118+
lookup_expr="contains",
119+
help_text="Filter by parent rule name containing a specific substring. Example: parent=Example Parent",
120+
)
121+
enabled = django_filters.BooleanFilter(
122+
field_name="enabled",
123+
help_text="Filter by enabled status (true or false). Example: enabled=true",
124+
)
125+
object_id = django_filters.NumberFilter(
126+
field_name="object_id",
127+
lookup_expr="exact",
128+
help_text="Filter by exact object ID. Example: object_id=123",
129+
)
130+
content_type = django_filters.ChoiceFilter(
131+
field_name="content_type",
132+
choices=[
133+
("service", "Service"),
134+
("project", "Project"),
135+
],
136+
method=filter_content_type,
137+
help_text="Filter by content type model name. Example: content_type=service",
138+
)

promgen/fixtures/testcases.yaml

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,4 +129,29 @@
129129
fields:
130130
sender: 1
131131
name: "severity"
132-
value: "critical"
132+
value: "critical"
133+
- model: promgen.rule
134+
pk: 1
135+
fields:
136+
content_type: ["promgen", "service"]
137+
object_id: 1
138+
name: "Test Rule"
139+
clause: "up == 0"
140+
duration: 5m
141+
enabled: true
142+
description: "Test Rule Description"
143+
labels: { "severity": "critical" }
144+
annotations: { "rule": "http://promgen.example.com/rule/1" }
145+
- model: promgen.rule
146+
pk: 2
147+
fields:
148+
content_type: ["promgen", "project"]
149+
object_id: 1
150+
name: "Test Rule 2"
151+
clause: "up != 0"
152+
duration: 1m
153+
enabled: false
154+
description: "Test Rule 2 Description"
155+
labels: { "severity": "warning" }
156+
annotations: { "rule": "http://promgen.example.com/rule/2" }
157+
parent: 1

promgen/rest_v2.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,3 +146,30 @@ def delete_filter(self, request, id):
146146
value=serializer.validated_data["value"],
147147
).delete()
148148
return Response(serializers.NotifierSerializer(notifier).data)
149+
150+
151+
@extend_schema_view(
152+
list=extend_schema(summary="List Rules", description="Retrieve a list of all rules."),
153+
retrieve=extend_schema(
154+
summary="Retrieve Rule", description="Retrieve detailed information about a specific rule."
155+
),
156+
update=extend_schema(summary="Update Rule", description="Update an existing rule."),
157+
partial_update=extend_schema(
158+
summary="Partially Update Rule", description="Partially update an existing rule."
159+
),
160+
destroy=extend_schema(summary="Delete Rule", description="Delete an existing rule."),
161+
)
162+
@extend_schema(tags=["Rule"])
163+
class RuleViewSet(
164+
mixins.RetrieveModelMixin,
165+
mixins.ListModelMixin,
166+
mixins.UpdateModelMixin,
167+
mixins.DestroyModelMixin,
168+
viewsets.GenericViewSet,
169+
):
170+
queryset = models.Rule.objects.all()
171+
filterset_class = filters.RuleFilterV2
172+
serializer_class = serializers.RuleSerializer
173+
lookup_value_regex = "[^/]+"
174+
lookup_field = "id"
175+
pagination_class = PromgenPagination

promgen/serializers.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,3 +190,27 @@ class UpdateNotifierSerializer(serializers.ModelSerializer):
190190
class Meta:
191191
model = models.Sender
192192
fields = ["enabled"]
193+
194+
195+
class RuleField(serializers.Field):
196+
def to_internal_value(self, data):
197+
try:
198+
rule = models.Rule.objects.get(pk=data)
199+
except models.Rule.DoesNotExist:
200+
raise serializers.ValidationError("Owner does not exist.")
201+
return rule
202+
203+
def to_representation(self, value):
204+
return value.name
205+
206+
207+
class RuleSerializer(serializers.ModelSerializer):
208+
content_name = serializers.ReadOnlyField(source="content_object.name")
209+
content_type = serializers.ReadOnlyField(source="content_type.model")
210+
labels = serializers.JSONField(required=False)
211+
annotations = serializers.JSONField(required=False)
212+
parent = RuleField(required=False)
213+
214+
class Meta:
215+
model = models.Rule
216+
exclude = ("object_id",)
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
{
2+
"count": 2,
3+
"next": null,
4+
"previous": null,
5+
"results": [
6+
{
7+
"annotations": {
8+
"rule": "http://promgen.example.com/rule/2"
9+
},
10+
"clause": "up != 0",
11+
"content_name": "test-project",
12+
"content_type": "project",
13+
"description": "Test Rule 2 Description",
14+
"duration": "1m",
15+
"enabled": false,
16+
"id": 2,
17+
"labels": {
18+
"severity": "warning"
19+
},
20+
"name": "Test Rule 2",
21+
"parent": "Test Rule"
22+
},
23+
{
24+
"annotations": {
25+
"rule": "http://promgen.example.com/rule/1"
26+
},
27+
"clause": "up == 0",
28+
"content_name": "test-service",
29+
"content_type": "service",
30+
"description": "Test Rule Description",
31+
"duration": "5m",
32+
"enabled": true,
33+
"id": 1,
34+
"labels": {
35+
"severity": "critical"
36+
},
37+
"name": "Test Rule",
38+
"parent": null
39+
}
40+
]
41+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"annotations": {
3+
"rule": "http://promgen.example.com/rule/1"
4+
},
5+
"clause": "up == 0",
6+
"content_name": "test-service",
7+
"content_type": "service",
8+
"description": "Test Rule Description",
9+
"duration": "5m",
10+
"enabled": true,
11+
"id": 1,
12+
"labels": {
13+
"severity": "critical"
14+
},
15+
"name": "Test Rule",
16+
"parent": null
17+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"count": 1,
3+
"next": null,
4+
"previous": null,
5+
"results": [
6+
{
7+
"annotations": {
8+
"rule": "http://promgen.example.com/rule/1"
9+
},
10+
"clause": "up == 0",
11+
"content_name": "test-service",
12+
"content_type": "service",
13+
"description": "Test Rule Description",
14+
"duration": "5m",
15+
"enabled": true,
16+
"id": 1,
17+
"labels": {
18+
"severity": "critical"
19+
},
20+
"name": "Test Rule",
21+
"parent": null
22+
}
23+
]
24+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"count": 1,
3+
"next": null,
4+
"previous": null,
5+
"results": [
6+
{
7+
"annotations": {
8+
"rule": "http://promgen.example.com/rule/1"
9+
},
10+
"clause": "up == 0",
11+
"content_name": "test-service",
12+
"content_type": "service",
13+
"description": "Test Rule Description",
14+
"duration": "5m",
15+
"enabled": true,
16+
"id": 1,
17+
"labels": {
18+
"severity": "critical"
19+
},
20+
"name": "Test Rule",
21+
"parent": null
22+
}
23+
]
24+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
{
2+
"count": 2,
3+
"next": null,
4+
"previous": null,
5+
"results": [
6+
{
7+
"annotations": {
8+
"rule": "http://promgen.example.com/rule/2"
9+
},
10+
"clause": "up != 0",
11+
"content_name": "test-project",
12+
"content_type": "project",
13+
"description": "Test Rule 2 Description",
14+
"duration": "1m",
15+
"enabled": false,
16+
"id": 2,
17+
"labels": {
18+
"severity": "warning"
19+
},
20+
"name": "Test Rule 2",
21+
"parent": "Test Rule"
22+
},
23+
{
24+
"annotations": {
25+
"rule": "http://promgen.example.com/rule/1"
26+
},
27+
"clause": "up == 0",
28+
"content_name": "test-service",
29+
"content_type": "service",
30+
"description": "Test Rule Description",
31+
"duration": "5m",
32+
"enabled": true,
33+
"id": 1,
34+
"labels": {
35+
"severity": "critical"
36+
},
37+
"name": "Test Rule",
38+
"parent": null
39+
}
40+
]
41+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"count": 1,
3+
"next": null,
4+
"previous": null,
5+
"results": [
6+
{
7+
"annotations": {
8+
"rule": "http://promgen.example.com/rule/2"
9+
},
10+
"clause": "up != 0",
11+
"content_name": "test-project",
12+
"content_type": "project",
13+
"description": "Test Rule 2 Description",
14+
"duration": "1m",
15+
"enabled": false,
16+
"id": 2,
17+
"labels": {
18+
"severity": "warning"
19+
},
20+
"name": "Test Rule 2",
21+
"parent": "Test Rule"
22+
}
23+
]
24+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"count": 2,
3+
"next": "http://testserver/rest/v2/rules/?page_number=2&page_size=1",
4+
"previous": null,
5+
"results": [
6+
{
7+
"annotations": {
8+
"rule": "http://promgen.example.com/rule/2"
9+
},
10+
"clause": "up != 0",
11+
"content_name": "test-project",
12+
"content_type": "project",
13+
"description": "Test Rule 2 Description",
14+
"duration": "1m",
15+
"enabled": false,
16+
"id": 2,
17+
"labels": {
18+
"severity": "warning"
19+
},
20+
"name": "Test Rule 2",
21+
"parent": "Test Rule"
22+
}
23+
]
24+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"annotations": {
3+
"rule": "http://promgen.example.com/rule/2"
4+
},
5+
"clause": "up != 0",
6+
"content_name": "test-project",
7+
"content_type": "project",
8+
"description": "Test Rule 2 Description",
9+
"duration": "1m",
10+
"enabled": true,
11+
"id": 2,
12+
"labels": {
13+
"severity": "warning"
14+
},
15+
"name": "Test Rule 2",
16+
"parent": "TestRuleUpdated"
17+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"annotations": {
3+
"rule": "http://promgen.example.com/rule/1",
4+
"summary": "Test Rule Summary"
5+
},
6+
"clause": "up == 1",
7+
"content_name": "test-service",
8+
"content_type": "service",
9+
"description": "Test Rule Description",
10+
"duration": "5m",
11+
"enabled": false,
12+
"id": 1,
13+
"labels": {
14+
"severity": "critical"
15+
},
16+
"name": "TestRuleUpdated",
17+
"parent": null
18+
}

promgen/tests/test_alert_rules.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ def test_import_v2(self, mock_post):
5757

5858
# Includes count of our setUp rule + imported rules
5959
self.assertRoute(response, views.RuleImport, status=200)
60-
self.assertCount(models.Rule, 3, "Missing Rule")
60+
self.assertCount(models.Rule, 4, "Missing Rule")
6161

6262
@skip
6363
@override_settings(PROMGEN=TEST_SETTINGS)
@@ -98,8 +98,8 @@ def test_missing_permission(self, mock_post):
9898
{"rules": tests.Data("examples", "import.rule.yml").raw()},
9999
)
100100

101-
# Should only be a single rule from our initial setup
102-
self.assertCount(models.Rule, 1, "Missing Rule")
101+
# Should only be number of rules from our initial setup
102+
self.assertCount(models.Rule, 2, "Missing Rule")
103103

104104
@mock.patch("django.dispatch.dispatcher.Signal.send")
105105
def test_macro(self, mock_post):

0 commit comments

Comments
 (0)