Skip to content

Commit cbb0345

Browse files
committed
Add v2 APIs for Exporter
We have added several APIs for retrieving Exporter data.
1 parent c4e9c19 commit cbb0345

15 files changed

+264
-1
lines changed

promgen/filters.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,3 +145,34 @@ class RuleFilterV2(django_filters.rest_framework.FilterSet):
145145
method=filter_content_type,
146146
help_text="Filter by content type model name. Example: content_type=service",
147147
)
148+
149+
150+
class ExporterFilter(django_filters.rest_framework.FilterSet):
151+
project = django_filters.CharFilter(
152+
field_name="project__name",
153+
lookup_expr="contains",
154+
help_text="Filter by project name containing a specific substring. Example: project=Example Project",
155+
)
156+
job = django_filters.CharFilter(
157+
field_name="job",
158+
lookup_expr="contains",
159+
help_text="Filter by job name containing a specific substring. Example: job=prometheus",
160+
)
161+
path = django_filters.CharFilter(
162+
field_name="path",
163+
lookup_expr="contains",
164+
help_text="Filter by path containing a specific substring. Example: path=/metrics",
165+
)
166+
scheme = django_filters.ChoiceFilter(
167+
field_name="scheme",
168+
choices=[
169+
("http", "HTTP"),
170+
("https", "HTTPS"),
171+
],
172+
lookup_expr="exact",
173+
help_text="Filter by exact scheme. Example: scheme=http",
174+
)
175+
enabled = django_filters.BooleanFilter(
176+
field_name="enabled",
177+
help_text="Filter by enabled status (true or false). Example: enabled=true",
178+
)

promgen/fixtures/testcases.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,13 +85,15 @@
8585
project: 1
8686
job: node
8787
port: 9100
88+
path: /metrics
8889
- model: promgen.exporter
8990
pk: 2
9091
fields:
9192
project: 2
92-
job: node
93+
job: nginx
9394
port: 9100
9495
enabled: false
96+
scheme: https
9597
- model: promgen.probe
9698
pk: 1
9799
fields:

promgen/rest_v2.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,3 +255,20 @@ def delete_host(self, request, id):
255255
for hostname in hostnames:
256256
farm.host_set.filter(name=hostname).delete()
257257
return Response(serializers.HostRetrieveSerializer(farm.host_set, many=True).data)
258+
259+
260+
@extend_schema_view(
261+
list=extend_schema(summary="List Exporters", description="Retrieve a list of all exporters."),
262+
retrieve=extend_schema(
263+
summary="Retrieve Exporter",
264+
description="Retrieve detailed information about a specific exporter.",
265+
),
266+
)
267+
@extend_schema(tags=["Exporter"])
268+
class ExporterViewSet(mixins.RetrieveModelMixin, mixins.ListModelMixin, viewsets.GenericViewSet):
269+
queryset = models.Exporter.objects.all()
270+
filterset_class = filters.ExporterFilter
271+
serializer_class = serializers.ExporterSerializer
272+
lookup_value_regex = "[^/]+"
273+
lookup_field = "id"
274+
pagination_class = PromgenPagination

promgen/serializers.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,3 +232,11 @@ class HostListSerializer(serializers.Serializer):
232232
hosts = serializers.ListField(
233233
child=serializers.CharField(), help_text="List of hostnames to add."
234234
)
235+
236+
237+
class ExporterSerializer(serializers.ModelSerializer):
238+
project = serializers.ReadOnlyField(source="project.name")
239+
240+
class Meta:
241+
model = models.Exporter
242+
fields = "__all__"

promgen/tests/examples/export.targets.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
{
33
"labels": {
44
"__farm_source": "promgen",
5+
"__metrics_path__": "/metrics",
56
"__scheme__": "http",
67
"__shard": "test-shard",
78
"farm": "test-farm",
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"count": 2,
3+
"next": null,
4+
"previous": null,
5+
"results": [
6+
{
7+
"enabled": false,
8+
"id": 2,
9+
"job": "nginx",
10+
"path": "",
11+
"port": 9100,
12+
"project": "another-project",
13+
"scheme": "https"
14+
},
15+
{
16+
"enabled": true,
17+
"id": 1,
18+
"job": "node",
19+
"path": "/metrics",
20+
"port": 9100,
21+
"project": "test-project",
22+
"scheme": "http"
23+
}
24+
]
25+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"enabled": true,
3+
"id": 1,
4+
"job": "node",
5+
"path": "/metrics",
6+
"port": 9100,
7+
"project": "test-project",
8+
"scheme": "http"
9+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"count": 1,
3+
"next": null,
4+
"previous": null,
5+
"results": [
6+
{
7+
"enabled": true,
8+
"id": 1,
9+
"job": "node",
10+
"path": "/metrics",
11+
"port": 9100,
12+
"project": "test-project",
13+
"scheme": "http"
14+
}
15+
]
16+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"count": 1,
3+
"next": null,
4+
"previous": null,
5+
"results": [
6+
{
7+
"enabled": false,
8+
"id": 2,
9+
"job": "nginx",
10+
"path": "",
11+
"port": 9100,
12+
"project": "another-project",
13+
"scheme": "https"
14+
}
15+
]
16+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"count": 1,
3+
"next": null,
4+
"previous": null,
5+
"results": [
6+
{
7+
"enabled": true,
8+
"id": 1,
9+
"job": "node",
10+
"path": "/metrics",
11+
"port": 9100,
12+
"project": "test-project",
13+
"scheme": "http"
14+
}
15+
]
16+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"count": 1,
3+
"next": null,
4+
"previous": null,
5+
"results": [
6+
{
7+
"enabled": true,
8+
"id": 1,
9+
"job": "node",
10+
"path": "/metrics",
11+
"port": 9100,
12+
"project": "test-project",
13+
"scheme": "http"
14+
}
15+
]
16+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"count": 1,
3+
"next": null,
4+
"previous": null,
5+
"results": [
6+
{
7+
"enabled": false,
8+
"id": 2,
9+
"job": "nginx",
10+
"path": "",
11+
"port": 9100,
12+
"project": "another-project",
13+
"scheme": "https"
14+
}
15+
]
16+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"count": 2,
3+
"next": "http://testserver/rest/v2/exporters/?page_number=2&page_size=1",
4+
"previous": null,
5+
"results": [
6+
{
7+
"enabled": false,
8+
"id": 2,
9+
"job": "nginx",
10+
"path": "",
11+
"port": 9100,
12+
"project": "another-project",
13+
"scheme": "https"
14+
}
15+
]
16+
}

promgen/tests/test_rest.py

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -775,3 +775,76 @@ def test_rest_rule(self):
775775
reverse("api-v2:rule-detail", args=[1]), HTTP_AUTHORIZATION=f"Token {token}"
776776
)
777777
self.assertEqual(response.status_code, 204)
778+
779+
@override_settings(PROMGEN=tests.SETTINGS)
780+
def test_rest_exporter(self):
781+
# Check retrieving all exporters
782+
expected = tests.Data("examples", "rest.exporter.default.json").json()
783+
response = self.client.get(reverse("api-v2:exporter-list"))
784+
self.assertEqual(response.status_code, 200)
785+
self.assertEqual(response.json(), expected)
786+
787+
# Check retrieving paginated exporters
788+
expected = tests.Data("examples", "rest.exporter.paginated.json").json()
789+
response = self.client.get(reverse("api-v2:exporter-list"), {"page_number": 1, "page_size": 1})
790+
self.assertEqual(response.status_code, 200)
791+
self.assertEqual(response.json(), expected)
792+
793+
# Check retrieving exporters whose "enabled" is "true"
794+
expected = tests.Data("examples", "rest.exporter.filter_by_enabled.json").json()
795+
response = self.client.get(reverse("api-v2:exporter-list"), {"enabled": "true"})
796+
self.assertEqual(response.status_code, 200)
797+
self.assertEqual(response.json(), expected)
798+
799+
# Check retrieving exporters whose "job" contains "inx"
800+
expected = tests.Data("examples", "rest.exporter.filter_by_job.json").json()
801+
response = self.client.get(reverse("api-v2:exporter-list"), {"job": "inx"})
802+
self.assertEqual(response.status_code, 200)
803+
self.assertEqual(response.json(), expected)
804+
805+
# Check retrieving exporters with a non-existent "job" returns an empty list
806+
response = self.client.get(reverse("api-v2:exporter-list"), {"job": "non-existent"})
807+
self.assertEqual(response.status_code, 200)
808+
self.assertEqual(response.data["count"], 0)
809+
810+
# Check retrieving exporters whose "path" contains "metrics"
811+
expected = tests.Data("examples", "rest.exporter.filter_by_path.json").json()
812+
response = self.client.get(reverse("api-v2:exporter-list"), {"path": "/metrics"})
813+
self.assertEqual(response.status_code, 200)
814+
self.assertEqual(response.json(), expected)
815+
816+
# Check retrieving exporters with a non-existent "path" returns an empty list
817+
response = self.client.get(reverse("api-v2:exporter-list"), {"path": "non-existent"})
818+
self.assertEqual(response.status_code, 200)
819+
self.assertEqual(response.data["count"], 0)
820+
821+
# Check retrieving exporters whose "project" contains "test"
822+
expected = tests.Data("examples", "rest.exporter.filter_by_project.json").json()
823+
response = self.client.get(reverse("api-v2:exporter-list"), {"project": "test"})
824+
self.assertEqual(response.status_code, 200)
825+
self.assertEqual(response.json(), expected)
826+
827+
# Check retrieving exporters with a non-existent "project" returns an empty list
828+
response = self.client.get(reverse("api-v2:exporter-list"), {"project": "non-existent"})
829+
self.assertEqual(response.status_code, 200)
830+
self.assertEqual(response.data["count"], 0)
831+
832+
# Check retrieving exporters whose "scheme" is "http"
833+
expected = tests.Data("examples", "rest.exporter.filter_by_scheme.json").json()
834+
response = self.client.get(reverse("api-v2:exporter-list"), {"scheme": "https"})
835+
self.assertEqual(response.status_code, 200)
836+
self.assertEqual(response.json(), expected)
837+
838+
# Check retrieving exporters with a non-existent "scheme" returns an 400 Bad Request
839+
response = self.client.get(reverse("api-v2:exporter-list"), {"scheme": "non-existent"})
840+
self.assertEqual(response.status_code, 400)
841+
842+
# Check retrieving exporters whose "id" is "1"
843+
expected = tests.Data("examples", "rest.exporter.detail.json").json()
844+
response = self.client.get(reverse("api-v2:exporter-detail", args=[1]))
845+
self.assertEqual(response.status_code, 200)
846+
self.assertEqual(response.json(), expected)
847+
848+
# Check retrieving exporters with a non-existent "id" returns 404 Not Found
849+
response = self.client.get(reverse("api-v2:exporter-detail", args=[-1]))
850+
self.assertEqual(response.status_code, 404)

promgen/urls.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
v2_router.register("notifiers", rest_v2.NotifierViewSet)
3939
v2_router.register("rules", rest_v2.RuleViewSet)
4040
v2_router.register("farms", rest_v2.FarmViewSet)
41+
v2_router.register("exporters", rest_v2.ExporterViewSet)
4142

4243
urlpatterns = [
4344
path("admin/", admin.site.urls),

0 commit comments

Comments
 (0)