diff --git a/promgen/fixtures/testcases.yaml b/promgen/fixtures/testcases.yaml
index e2923ebc3..31b0d427e 100644
--- a/promgen/fixtures/testcases.yaml
+++ b/promgen/fixtures/testcases.yaml
@@ -57,3 +57,16 @@
service: 1
shard: 1
farm: 1
+- model: promgen.exporter
+ pk: 1
+ fields:
+ project: 1
+ job: node
+ port: 9100
+- model: promgen.exporter
+ pk: 2
+ fields:
+ project: 2
+ job: node
+ port: 9100
+ enabled: false
diff --git a/promgen/rest.py b/promgen/rest.py
index fd0e368d7..335f984b2 100644
--- a/promgen/rest.py
+++ b/promgen/rest.py
@@ -32,6 +32,13 @@ def rules(self, request):
headers={"Content-Disposition": "attachment; filename=alert.rule.yml"},
)
+ @action(detail=False, methods=["get"], renderer_classes=[renderers.renderers.JSONRenderer])
+ def targets(self, request):
+ return HttpResponse(
+ prometheus.render_config(),
+ content_type="application/json",
+ )
+
class ShardViewSet(viewsets.ModelViewSet):
queryset = models.Shard.objects.all()
diff --git a/promgen/templates/promgen/navbar.html b/promgen/templates/promgen/navbar.html
index 152e143d9..7fd28b468 100644
--- a/promgen/templates/promgen/navbar.html
+++ b/promgen/templates/promgen/navbar.html
@@ -34,7 +34,7 @@
API
- Export Targets
+ Export Targets
Export Rules
Export URL
diff --git a/promgen/tests/examples/export.rule.yml b/promgen/tests/examples/export.rule.yml
new file mode 100644
index 000000000..6ada95ca7
--- /dev/null
+++ b/promgen/tests/examples/export.rule.yml
@@ -0,0 +1,11 @@
+groups:
+ - name: promgen.example.com
+ rules:
+ - alert: example-rule
+ annotations:
+ rule: http://promgen.example.com/rule/1
+ summary: Example rule summary
+ expr: up==1
+ for: 1s
+ labels:
+ severity: high
diff --git a/promgen/tests/examples/export.targets.json b/promgen/tests/examples/export.targets.json
new file mode 100644
index 000000000..12bd5bf53
--- /dev/null
+++ b/promgen/tests/examples/export.targets.json
@@ -0,0 +1,16 @@
+[
+ {
+ "labels": {
+ "__farm_source": "promgen",
+ "__scheme__": "http",
+ "__shard": "test-shard",
+ "farm": "test-farm",
+ "job": "node",
+ "project": "test-project",
+ "service": "test-service"
+ },
+ "targets": [
+ "example.com:9100"
+ ]
+ }
+ ]
diff --git a/promgen/tests/test_cli.py b/promgen/tests/test_cli.py
index 5b49b5e11..b5cfd7b8a 100644
--- a/promgen/tests/test_cli.py
+++ b/promgen/tests/test_cli.py
@@ -22,15 +22,15 @@ def test_register_job(self, mock_signal):
management.call_command("register-job", "test-project", "example", 1234)
# Ensure the jobs we expect exist
- self.assertCount(models.Exporter, 1)
+ self.assertCount(models.Exporter, 3, "Import a new exporter")
# Registering the same job again shouldn't change our count
management.call_command("register-job", "test-project", "example", 1234)
- self.assertCount(models.Exporter, 1)
+ self.assertCount(models.Exporter, 3, "Import additional exporter")
# But registering a new one will
management.call_command("register-job", "test-project", "example", 4321)
- self.assertCount(models.Exporter, 2)
+ self.assertCount(models.Exporter, 4, 'Import additional exporter')
@mock.patch("promgen.signals._trigger_write_config")
def test_register_host(self, mock_signal):
diff --git a/promgen/tests/test_renderers.py b/promgen/tests/test_renderers.py
new file mode 100644
index 000000000..337c6c160
--- /dev/null
+++ b/promgen/tests/test_renderers.py
@@ -0,0 +1,25 @@
+# Copyright (c) 2024 LINE Corporation
+# These sources are released under the terms of the MIT license: see LICENSE
+
+from django.urls import reverse
+from yaml import safe_load
+
+from promgen import tests
+
+
+class RendererTests(tests.PromgenTest):
+ fixtures = ["testcases.yaml", "extras.yaml"]
+
+ def test_global_rule(self):
+ expected = tests.Data("examples", "export.rule.yml").yaml()
+ response = self.client.get(reverse("api:all-rules"))
+ self.assertEqual(response.status_code, 200)
+ # The test client does not have a shortcut to decode yaml
+ data = safe_load(response.content)
+ self.assertEqual(data, expected)
+
+ def test_global_targets(self):
+ expected = tests.Data("examples", "export.targets.json").json()
+ response = self.client.get(reverse("api:all-targets"))
+ self.assertEqual(response.status_code, 200)
+ self.assertEqual(response.json(), expected)
diff --git a/promgen/tests/test_routes.py b/promgen/tests/test_routes.py
index 84d19000b..32f05f2df 100644
--- a/promgen/tests/test_routes.py
+++ b/promgen/tests/test_routes.py
@@ -30,7 +30,7 @@ def test_import(self, mock_write, mock_reload):
self.assertRoute(response, views.Import, 302, "Redirect to imported object")
self.assertCount(models.Service, 3, "Import one service (Fixture has two services)")
self.assertCount(models.Project, 4, "Import two projects")
- self.assertCount(models.Exporter, 2, "Import two exporters")
+ self.assertCount(models.Exporter, 4, "Import two more exporters")
self.assertCount(models.Host, 3, "Import three hosts")
@override_settings(PROMGEN=TEST_SETTINGS)
@@ -50,7 +50,7 @@ def test_replace(self, mock_write, mock_reload):
self.assertCount(models.Service, 3, "Import one service (Fixture has two services)")
self.assertCount(models.Project, 4, "Import two projects (Fixture has 2 projectsa)")
- self.assertCount(models.Exporter, 2, "Import two exporters")
+ self.assertCount(models.Exporter, 4, "Import two more exporters")
self.assertCount(
models.Farm, 4, "Original two farms and one new farm (fixture has one farm)"
)