oncall-engine/engine/apps/grafana_plugin/views/self_hosted_install.py
Vadim Stepanov 7a2fc923df
Don't update RBAC status on Grafana server error (#4753)
# What this PR does

Fixes a bug when RBAC permissions are getting erased when Grafana's API
returns a 5xx server error on organization sync.

## Which issue(s) this PR closes

Closes https://github.com/grafana/oncall-private/issues/2834

## 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] Added the relevant release notes label (see labels prefixed w/
`release:`). These labels dictate how your PR will
    show up in the autogenerated release notes.
2024-07-29 16:28:35 +00:00

71 lines
3.5 KiB
Python

from django.conf import settings
from rest_framework import status
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.views import APIView
from apps.grafana_plugin.helpers import GrafanaAPIClient
from apps.user_management.models.organization import Organization
from apps.user_management.sync import sync_organization
from common.api_helpers.mixins import GrafanaHeadersMixin
class SelfHostedInstallView(GrafanaHeadersMixin, APIView):
def post(self, _request: Request) -> Response:
"""
We've already validated that settings.GRAFANA_API_URL is set (in apps.grafana_plugin.GrafanaPluginConfig)
The user is now trying to finish plugin installation. We'll take the Grafana API url that they specified +
the token that we are provided and first verify them. If all is good, upsert the organization in the database,
and provision the plugin.
"""
stack_id = settings.SELF_HOSTED_SETTINGS["STACK_ID"]
org_id = settings.SELF_HOSTED_SETTINGS["ORG_ID"]
grafana_url = settings.SELF_HOSTED_SETTINGS["GRAFANA_API_URL"]
grafana_api_token = self.instance_context["grafana_token"]
provisioning_info = {"error": None}
if settings.LICENSE != settings.OPEN_SOURCE_LICENSE_NAME:
provisioning_info["error"] = "License type not authorized"
return Response(status=status.HTTP_403_FORBIDDEN)
grafana_api_client = GrafanaAPIClient(api_url=grafana_url, api_token=grafana_api_token)
_, client_status = grafana_api_client.check_token()
status_code = client_status["status_code"]
if status_code == status.HTTP_404_NOT_FOUND:
provisioning_info["error"] = f"Unable to connect to the specified Grafana API - {grafana_url}"
return Response(data=provisioning_info, status=status.HTTP_400_BAD_REQUEST)
elif status_code in [status.HTTP_401_UNAUTHORIZED, status.HTTP_403_FORBIDDEN]:
provisioning_info[
"error"
] = f"You are not authorized to communicate with the specified Grafana API - {grafana_url}"
return Response(data=provisioning_info, status=status.HTTP_400_BAD_REQUEST)
organization = Organization.objects.filter(stack_id=stack_id, org_id=org_id).first()
rbac_is_enabled, _ = grafana_api_client.is_rbac_enabled_for_organization()
if organization:
organization.revoke_plugin()
organization.grafana_url = grafana_url
organization.api_token = grafana_api_token
organization.is_rbac_permissions_enabled = rbac_is_enabled
organization.save(update_fields=["grafana_url", "api_token", "is_rbac_permissions_enabled"])
else:
organization = Organization.objects.create(
stack_id=stack_id,
stack_slug=settings.SELF_HOSTED_SETTINGS["STACK_SLUG"],
org_id=org_id,
org_slug=settings.SELF_HOSTED_SETTINGS["ORG_SLUG"],
org_title=settings.SELF_HOSTED_SETTINGS["ORG_TITLE"],
region_slug=settings.SELF_HOSTED_SETTINGS["REGION_SLUG"],
cluster_slug=settings.SELF_HOSTED_SETTINGS["CLUSTER_SLUG"],
grafana_url=grafana_url,
api_token=grafana_api_token,
is_rbac_permissions_enabled=rbac_is_enabled,
)
sync_organization(organization)
provisioning_info.update(organization.provision_plugin())
return Response(data=provisioning_info, status=status.HTTP_201_CREATED)