API for grafana alerting (including test fix) (#2737)

# What this PR does

This PR is related to #2645. That PR was reverted in #2730. This reverts
the revert + adds a fix for the test that was failing

## Checklist

- [x] Unit, integration, and e2e (if applicable) tests updated
- [x] Documentation added (or `pr:no public docs` PR label added if not
required)
- [x] `CHANGELOG.md` updated (or `pr:no changelog` PR label added if not
required)

---------

Co-authored-by: Innokentii Konstantinov <innokenty.konstantinov@grafana.com>
This commit is contained in:
Joey Orlando 2023-08-03 11:12:52 +02:00 committed by GitHub
parent 33c5e89299
commit d7e2f7053d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 71 additions and 3 deletions

View file

@ -227,7 +227,7 @@ class FilterAlertReceiveChannelSerializer(serializers.ModelSerializer):
class Meta:
model = AlertReceiveChannel
fields = ["value", "display_name"]
fields = ["value", "display_name", "integration_url"]
def get_value(self, obj):
return obj.public_primary_key

View file

@ -33,6 +33,41 @@ def test_get_alert_receive_channel(alert_receive_channel_internal_api_setup, mak
assert response.status_code == status.HTTP_200_OK
@pytest.mark.django_db
@pytest.mark.parametrize(
"query_param,should_be_unpaginated",
[
("True", True),
("true", True),
("TRUE", True),
("", False),
("False", False),
("false", False),
("FALSE", False),
],
)
def test_list_alert_receive_channel_skip_pagination_for_grafana_alerting(
alert_receive_channel_internal_api_setup,
make_user_auth_headers,
query_param,
should_be_unpaginated,
):
user, token, _ = alert_receive_channel_internal_api_setup
client = APIClient()
url = reverse("api-internal:alert_receive_channel-list")
response = client.get(f"{url}?skip_pagination={query_param}", format="json", **make_user_auth_headers(user, token))
results = response.json()
assert response.status_code == status.HTTP_200_OK
if should_be_unpaginated:
assert type(results) == list
assert len(results) > 0
else:
assert type(results["results"]) == list
assert len(results["results"]) > 0
@pytest.mark.django_db
def test_heartbeat_data_absence_alert_receive_channel(alert_receive_channel_internal_api_setup, make_user_auth_headers):
"""

View file

@ -38,7 +38,7 @@ class AlertReceiveChannelFilter(ByTeamModelFieldFilterMixin, filters.FilterSet):
maintenance_mode = filters.MultipleChoiceFilter(
choices=AlertReceiveChannel.MAINTENANCE_MODE_CHOICES, method="filter_maintenance_mode"
)
integration = filters.ChoiceFilter(choices=AlertReceiveChannel.INTEGRATION_CHOICES)
integration = filters.MultipleChoiceFilter(choices=AlertReceiveChannel.INTEGRATION_CHOICES)
team = TeamModelMultipleChoiceFilter()
class Meta:
@ -80,7 +80,7 @@ class AlertReceiveChannelView(
update_serializer_class = AlertReceiveChannelUpdateSerializer
filter_backends = [SearchFilter, DjangoFilterBackend]
search_fields = ("verbal_name", "integration")
search_fields = ("verbal_name",)
filterset_class = AlertReceiveChannelFilter
pagination_class = FifteenPageSizePaginator
@ -102,6 +102,7 @@ class AlertReceiveChannelView(
"filters": [RBACPermission.Permissions.INTEGRATIONS_READ],
"start_maintenance": [RBACPermission.Permissions.INTEGRATIONS_WRITE],
"stop_maintenance": [RBACPermission.Permissions.INTEGRATIONS_WRITE],
"validate_name": [RBACPermission.Permissions.INTEGRATIONS_WRITE],
"migrate": [RBACPermission.Permissions.INTEGRATIONS_WRITE],
}
@ -144,6 +145,15 @@ class AlertReceiveChannelView(
return queryset
def paginate_queryset(self, queryset):
"""
If `skip_pagination` is provided and is equal to "true" (or "True"), it will return
a non paginated list of results. This is useful for Grafana Alerting
"""
if self.request.query_params.get("skip_pagination", "false").lower() == "true":
return None
return super().paginate_queryset(queryset)
@action(detail=True, methods=["post"], throttle_classes=[DemoAlertThrottler])
def send_demo_alert(self, request, pk):
instance = self.get_object()
@ -333,3 +343,21 @@ class AlertReceiveChannelView(
instance.save()
return Response(status=status.HTTP_200_OK)
@action(detail=False, methods=["get"])
def validate_name(self, request):
"""
Checks if verbal_name is available.
It is needed for OnCall <-> Alerting integration.
"""
verbal_name = self.request.query_params.get("verbal_name")
if verbal_name is None:
raise BadRequest("verbal_name is required")
organization = self.request.auth.organization
name_used = AlertReceiveChannel.objects.filter(organization=organization, verbal_name=verbal_name).exists()
if name_used:
r = Response(status=status.HTTP_409_CONFLICT)
else:
r = Response(status=status.HTTP_200_OK)
return r

View file

@ -10,6 +10,7 @@ FEATURE_TELEGRAM = "telegram"
FEATURE_LIVE_SETTINGS = "live_settings"
FEATURE_GRAFANA_CLOUD_NOTIFICATIONS = "grafana_cloud_notifications"
FEATURE_GRAFANA_CLOUD_CONNECTION = "grafana_cloud_connection"
FEATURE_GRAFANA_ALERTING_V2 = "grafana_alerting_v2"
class FeaturesAPIView(APIView):
@ -40,4 +41,7 @@ class FeaturesAPIView(APIView):
if live_settings.GRAFANA_CLOUD_NOTIFICATIONS_ENABLED:
enabled_features.append(FEATURE_GRAFANA_CLOUD_NOTIFICATIONS)
if settings.FEATURE_GRAFANA_ALERTING_V2_ENABLED:
enabled_features.append(FEATURE_GRAFANA_ALERTING_V2)
return enabled_features

View file

@ -65,6 +65,7 @@ FEATURE_MULTIREGION_ENABLED = getenv_boolean("FEATURE_MULTIREGION_ENABLED", defa
FEATURE_INBOUND_EMAIL_ENABLED = getenv_boolean("FEATURE_INBOUND_EMAIL_ENABLED", default=False)
FEATURE_PROMETHEUS_EXPORTER_ENABLED = getenv_boolean("FEATURE_PROMETHEUS_EXPORTER_ENABLED", default=False)
FEATURE_SHIFT_SWAPS_ENABLED = getenv_boolean("FEATURE_SHIFT_SWAPS_ENABLED", default=False)
FEATURE_GRAFANA_ALERTING_V2_ENABLED = getenv_boolean("FEATURE_GRAFANA_ALERTING_V2_ENABLED", default=False)
GRAFANA_CLOUD_ONCALL_HEARTBEAT_ENABLED = getenv_boolean("GRAFANA_CLOUD_ONCALL_HEARTBEAT_ENABLED", default=True)
GRAFANA_CLOUD_NOTIFICATIONS_ENABLED = getenv_boolean("GRAFANA_CLOUD_NOTIFICATIONS_ENABLED", default=True)