Skip to content

Commit 6d2ffcd

Browse files
committed
Add v2 APIs for Service
We have added several APIs to help users easily manage Services and objects related to each service, includes notifiers and rules.
1 parent ffe88a5 commit 6d2ffcd

19 files changed

+627
-1
lines changed

promgen/filters.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,3 +214,16 @@ class ProjectFilterV2(django_filters.rest_framework.FilterSet):
214214
lookup_expr="exact",
215215
help_text="Filter by exact owner username. Example: owner=Example Owner",
216216
)
217+
218+
219+
class ServiceFilterV2(django_filters.rest_framework.FilterSet):
220+
name = django_filters.CharFilter(
221+
field_name="name",
222+
lookup_expr="contains",
223+
help_text="Filter by service name containing a specific substring. Example: name=Example Service",
224+
)
225+
owner = django_filters.CharFilter(
226+
field_name="owner__username",
227+
lookup_expr="exact",
228+
help_text="Filter by exact owner username. Example: owner=Example Owner",
229+
)

promgen/fixtures/testcases.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
pk: 2
4848
fields:
4949
name: other-service
50-
owner: 1
50+
owner: 2
5151
- model: promgen.farm
5252
pk: 1
5353
fields:

promgen/rest_v2.py

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -595,3 +595,105 @@ def register_rule(self, request, id):
595595

596596
rule, _ = models.Rule.objects.get_or_create(**attributes)
597597
return Response(serializers.RuleSerializer(project.rule_set, many=True).data)
598+
599+
600+
@extend_schema_view(
601+
list=extend_schema(
602+
summary="List Services",
603+
description="Retrieve a list of all services.",
604+
),
605+
retrieve=extend_schema(
606+
summary="Retrieve Service",
607+
description="Retrieve detailed information about a specific service.",
608+
),
609+
create=extend_schema(summary="Create Service", description="Create a new service."),
610+
update=extend_schema(summary="Update Service", description="Update an existing service."),
611+
partial_update=extend_schema(
612+
summary="Partially Update Service", description="Partially update an existing service."
613+
),
614+
destroy=extend_schema(summary="Delete Service", description="Delete an existing service."),
615+
)
616+
@extend_schema(tags=["Service"])
617+
class ServiceViewSet(NotifierMixin, RuleMixin, viewsets.ModelViewSet):
618+
model = "Service"
619+
queryset = models.Service.objects.all()
620+
filterset_class = filters.ServiceFilterV2
621+
serializer_class = serializers.ServiceSerializer
622+
lookup_value_regex = "[^/]+"
623+
lookup_field = "id"
624+
pagination_class = PromgenPagination
625+
626+
def get_serializer_class(self):
627+
if self.action == "list":
628+
return serializers.ServiceRetrieveSerializer
629+
if self.action == "retrieve":
630+
return serializers.ServiceRetrieveSerializer
631+
if self.action == "create":
632+
return serializers.ServiceCreateSerializer
633+
if self.action == "update":
634+
return serializers.ServiceUpdateSerializer
635+
if self.action == "partial_update":
636+
return serializers.ServiceUpdateSerializer
637+
return None
638+
639+
@extend_schema(
640+
summary="List Projects",
641+
description="Retrieve all projects associated with the specified service.",
642+
responses=serializers.ProjectSerializer(many=True),
643+
)
644+
@action(detail=True, methods=["get"], pagination_class=None, filterset_class=None)
645+
def projects(self, request, id):
646+
service = self.get_object()
647+
return Response(serializers.ProjectSerializer(service.project_set.all(), many=True).data)
648+
649+
@extend_schema(
650+
summary="Register Notifier",
651+
description="Register a new notifier for the specified service.",
652+
request=serializers.RegisterNotifierSerializer,
653+
responses=serializers.NotifierSerializer(many=True),
654+
)
655+
@action(detail=True, methods=["post"], url_path="notifiers/register")
656+
def register_notifier(self, request, id):
657+
serializer = serializers.RegisterNotifierSerializer(data=request.data)
658+
serializer.is_valid(raise_exception=True)
659+
service = self.get_object()
660+
661+
attributes = {
662+
"content_type_id": get_content_type_for_model(models.Service).id,
663+
"object_id": service.id,
664+
}
665+
666+
for field in serializer.fields:
667+
value = serializer.validated_data.get(field)
668+
if value is not None and field != "filters":
669+
attributes[field] = value
670+
671+
notifier, _ = models.Sender.objects.get_or_create(**attributes)
672+
for filter_data in serializer.validated_data.get("filters", []):
673+
models.Filter.objects.get_or_create(sender=notifier, **filter_data)
674+
return Response(serializers.NotifierSerializer(service.notifiers, many=True).data)
675+
676+
@extend_schema(
677+
summary="Register Rule",
678+
description="Register a new rule for the specified service.",
679+
request=serializers.RuleSerializer,
680+
responses=serializers.RuleSerializer(many=True),
681+
)
682+
@action(detail=True, methods=["post"], url_path="rules/register")
683+
def register_rule(self, request, id):
684+
serializer = serializers.RuleSerializer(data=request.data)
685+
serializer.is_valid(raise_exception=True)
686+
service = self.get_object()
687+
688+
attributes = {
689+
"content_type_id": get_content_type_for_model(models.Service).id,
690+
"object_id": service.id,
691+
}
692+
693+
for field in serializer.fields:
694+
value = serializer.validated_data.get(field)
695+
if value is not None:
696+
attributes[field] = value
697+
698+
rule, _ = models.Rule.objects.get_or_create(**attributes)
699+
return Response(serializers.RuleSerializer(service.rule_set, many=True).data)

promgen/serializers.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,3 +362,31 @@ class RegisterNotifierSerializer(serializers.Serializer):
362362
alias = serializers.CharField(required=False)
363363
enabled = serializers.BooleanField(required=False, default=True)
364364
filters = FilterSerializer(many=True, required=False)
365+
366+
367+
class ServiceRetrieveSerializer(serializers.ModelSerializer):
368+
owner = serializers.ReadOnlyField(source="owner.username")
369+
370+
class Meta:
371+
model = models.Service
372+
fields = "__all__"
373+
374+
375+
class ServiceCreateSerializer(serializers.ModelSerializer):
376+
owner = OwnerField(required=False, default=serializers.CurrentUserDefault())
377+
id = serializers.ReadOnlyField()
378+
379+
class Meta:
380+
model = models.Service
381+
fields = "__all__"
382+
383+
384+
class ServiceUpdateSerializer(serializers.ModelSerializer):
385+
owner = OwnerField(required=False)
386+
name = serializers.CharField(required=False)
387+
description = serializers.CharField(required=False)
388+
id = serializers.ReadOnlyField()
389+
390+
class Meta:
391+
model = models.Service
392+
fields = "__all__"
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"description": "Test New Service Description",
3+
"id": 3,
4+
"name": "new-service",
5+
"owner": "demo"
6+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"count": 2,
3+
"next": null,
4+
"previous": null,
5+
"results": [
6+
{
7+
"description": "",
8+
"id": 2,
9+
"name": "other-service",
10+
"owner": "demo"
11+
},
12+
{
13+
"description": "",
14+
"id": 1,
15+
"name": "test-service",
16+
"owner": "admin"
17+
}
18+
]
19+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"description": "",
3+
"id": 1,
4+
"name": "test-service",
5+
"owner": "admin"
6+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"count": 1,
3+
"next": null,
4+
"previous": null,
5+
"results": [
6+
{
7+
"description": "",
8+
"id": 1,
9+
"name": "test-service",
10+
"owner": "admin"
11+
}
12+
]
13+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"count": 1,
3+
"next": null,
4+
"previous": null,
5+
"results": [
6+
{
7+
"description": "",
8+
"id": 2,
9+
"name": "other-service",
10+
"owner": "demo"
11+
}
12+
]
13+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[
2+
{
3+
"alias": "",
4+
"content_type": 11,
5+
"enabled": true,
6+
"id": 1,
7+
"label": "[email protected]",
8+
"object_id": 1,
9+
"owner": "admin",
10+
"sender": "promgen.notification.email",
11+
"value": "[email protected]"
12+
}
13+
]
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"count": 2,
3+
"next": "http://testserver/rest/v2/services/?page_number=2&page_size=1",
4+
"previous": null,
5+
"results": [
6+
{
7+
"description": "",
8+
"id": 2,
9+
"name": "other-service",
10+
"owner": "demo"
11+
}
12+
]
13+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"description": "Test Updated Description",
3+
"id": 1,
4+
"name": "partial-updated-service",
5+
"owner": "demo"
6+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[
2+
{
3+
"description": "",
4+
"html": "http://promgen.example.com/project/1",
5+
"name": "test-project",
6+
"owner": "admin",
7+
"service": "test-service"
8+
}
9+
]
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
[
2+
{
3+
"alias": "",
4+
"content_name": "partial-updated-service",
5+
"content_type": "service",
6+
"enabled": true,
7+
"filters": [
8+
{
9+
"name": "severity",
10+
"value": "critical"
11+
}
12+
],
13+
"id": 1,
14+
"owner": "admin",
15+
"sender": "promgen.notification.email",
16+
"value": "[email protected]"
17+
},
18+
{
19+
"alias": "",
20+
"content_name": "partial-updated-service",
21+
"content_type": "service",
22+
"enabled": false,
23+
"filters": [
24+
{
25+
"name": "test-name",
26+
"value": "test-value"
27+
}
28+
],
29+
"id": 6,
30+
"sender": "promgen.notification.slack",
31+
"value": "https://test.slack.com"
32+
}
33+
]
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
[
2+
{
3+
"annotations": {
4+
"rule": "http://promgen.example.com/rule/1"
5+
},
6+
"clause": "up == 0",
7+
"content_name": "partial-updated-service",
8+
"content_type": "service",
9+
"description": "Test Rule Description",
10+
"duration": "5m",
11+
"enabled": true,
12+
"id": 1,
13+
"labels": {
14+
"severity": "critical"
15+
},
16+
"name": "Test Rule",
17+
"parent": null
18+
},
19+
{
20+
"annotations": {
21+
"rule": "http://promgen.example.com/rule/4",
22+
"summary": "Test Rule Summary"
23+
},
24+
"clause": "up == 1",
25+
"content_name": "partial-updated-service",
26+
"content_type": "service",
27+
"description": "Test Rule Description",
28+
"duration": "5m",
29+
"enabled": false,
30+
"id": 4,
31+
"labels": {
32+
"severity": "critical"
33+
},
34+
"name": "TestRuleCreated",
35+
"parent": null
36+
}
37+
]
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
[
2+
{
3+
"annotations": {
4+
"rule": "http://promgen.example.com/rule/1"
5+
},
6+
"clause": "up == 0",
7+
"content_name": "test-service",
8+
"content_type": "service",
9+
"description": "Test Rule Description",
10+
"duration": "5m",
11+
"enabled": true,
12+
"id": 1,
13+
"labels": {
14+
"severity": "critical"
15+
},
16+
"name": "Test Rule",
17+
"parent": null
18+
}
19+
]
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"description": "Test Updated Description",
3+
"id": 1,
4+
"name": "updated-service",
5+
"owner": "demo"
6+
}

0 commit comments

Comments
 (0)