# 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.
172 lines
7.1 KiB
Python
172 lines
7.1 KiB
Python
import json
|
|
from unittest.mock import patch
|
|
|
|
import pytest
|
|
from django.conf import settings
|
|
from django.test import override_settings
|
|
from django.urls import reverse
|
|
from rest_framework import status
|
|
from rest_framework.test import APIClient
|
|
|
|
GRAFANA_TOKEN = "TEST_TOKEN"
|
|
STACK_ID = 1
|
|
ORG_ID = 5
|
|
GRAFANA_API_URL = "hello.com"
|
|
LICENSE = "OpenSource"
|
|
STACK_SLUG = "asdfasdf"
|
|
ORG_SLUG = "hellooo"
|
|
ORG_TITLE = "nmvcnmvnmvc"
|
|
REGION_SLUG = "nmcvnmcvnmcvnmcv"
|
|
CLUSTER_SLUG = "nmcvnmcvnmcvnmcvnmcv"
|
|
SELF_HOSTED_SETTINGS = {
|
|
"GRAFANA_API_URL": GRAFANA_API_URL,
|
|
"STACK_ID": STACK_ID,
|
|
"ORG_ID": ORG_ID,
|
|
"LICENSE": LICENSE,
|
|
"STACK_SLUG": STACK_SLUG,
|
|
"ORG_SLUG": ORG_SLUG,
|
|
"ORG_TITLE": ORG_TITLE,
|
|
"REGION_SLUG": REGION_SLUG,
|
|
"CLUSTER_SLUG": CLUSTER_SLUG,
|
|
}
|
|
|
|
UNABLE_TO_FIND_GRAFANA_ERROR_MSG = f"Unable to connect to the specified Grafana API - {GRAFANA_API_URL}"
|
|
UNAUTHED_GRAFANA_API_ERROR_MSG = (
|
|
f"You are not authorized to communicate with the specified Grafana API - {GRAFANA_API_URL}"
|
|
)
|
|
|
|
|
|
@pytest.fixture
|
|
def make_self_hosted_install_header():
|
|
def _make_instance_context_header(token):
|
|
return {
|
|
"HTTP_X-Instance-Context": json.dumps({"grafana_token": token}),
|
|
}
|
|
|
|
return _make_instance_context_header
|
|
|
|
|
|
@override_settings(LICENSE=settings.CLOUD_LICENSE_NAME)
|
|
def test_a_cloud_license_gets_an_unauthorized_error(make_self_hosted_install_header):
|
|
client = APIClient()
|
|
url = reverse("grafana-plugin:self-hosted-install")
|
|
response = client.post(url, format="json", **make_self_hosted_install_header(GRAFANA_TOKEN))
|
|
|
|
assert response.status_code == status.HTTP_403_FORBIDDEN
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"grafana_api_status_code,expected_error_msg",
|
|
[
|
|
(status.HTTP_404_NOT_FOUND, UNABLE_TO_FIND_GRAFANA_ERROR_MSG),
|
|
(status.HTTP_401_UNAUTHORIZED, UNAUTHED_GRAFANA_API_ERROR_MSG),
|
|
(status.HTTP_401_UNAUTHORIZED, UNAUTHED_GRAFANA_API_ERROR_MSG),
|
|
],
|
|
)
|
|
@override_settings(SELF_HOSTED_SETTINGS=SELF_HOSTED_SETTINGS)
|
|
@patch("apps.grafana_plugin.views.self_hosted_install.GrafanaAPIClient")
|
|
def test_it_properly_handles_errors_from_the_grafana_api(
|
|
mocked_grafana_api_client, make_self_hosted_install_header, grafana_api_status_code, expected_error_msg
|
|
):
|
|
mocked_grafana_api_client.return_value.check_token.return_value = (None, {"status_code": grafana_api_status_code})
|
|
|
|
client = APIClient()
|
|
url = reverse("grafana-plugin:self-hosted-install")
|
|
response = client.post(url, format="json", **make_self_hosted_install_header(GRAFANA_TOKEN))
|
|
|
|
mocked_grafana_api_client.assert_called_once_with(api_url=GRAFANA_API_URL, api_token=GRAFANA_TOKEN)
|
|
mocked_grafana_api_client.return_value.check_token.assert_called_once_with()
|
|
|
|
assert response.status_code == status.HTTP_400_BAD_REQUEST
|
|
assert response.data["error"] == expected_error_msg
|
|
|
|
|
|
@override_settings(SELF_HOSTED_SETTINGS=SELF_HOSTED_SETTINGS)
|
|
@pytest.mark.django_db
|
|
@patch("apps.grafana_plugin.views.self_hosted_install.GrafanaAPIClient")
|
|
@patch("apps.grafana_plugin.views.self_hosted_install.sync_organization")
|
|
@patch("apps.grafana_plugin.views.self_hosted_install.Organization.provision_plugin")
|
|
@patch("apps.grafana_plugin.views.self_hosted_install.Organization.revoke_plugin")
|
|
def test_if_organization_exists_it_is_updated(
|
|
mocked_revoke_plugin,
|
|
mocked_provision_plugin,
|
|
mocked_sync_organization,
|
|
mocked_grafana_api_client,
|
|
make_self_hosted_install_header,
|
|
make_organization,
|
|
):
|
|
organization = make_organization(stack_id=STACK_ID, org_id=ORG_ID)
|
|
provision_plugin_response = {"stackId": STACK_ID, "orgId": ORG_ID, "onCallToken": "HELLOOO", "license": LICENSE}
|
|
|
|
mocked_provision_plugin.return_value = provision_plugin_response
|
|
mocked_grafana_api_client.return_value.check_token.return_value = (None, {"status_code": status.HTTP_200_OK})
|
|
mocked_grafana_api_client.return_value.is_rbac_enabled_for_organization.return_value = True, False
|
|
|
|
client = APIClient()
|
|
url = reverse("grafana-plugin:self-hosted-install")
|
|
response = client.post(url, format="json", **make_self_hosted_install_header(GRAFANA_TOKEN))
|
|
|
|
mocked_grafana_api_client.assert_called_once_with(api_url=GRAFANA_API_URL, api_token=GRAFANA_TOKEN)
|
|
mocked_grafana_api_client.return_value.check_token.assert_called_once_with()
|
|
mocked_grafana_api_client.return_value.is_rbac_enabled_for_organization.assert_called_once_with()
|
|
|
|
mocked_sync_organization.assert_called_once_with(organization)
|
|
mocked_provision_plugin.assert_called_once_with()
|
|
mocked_revoke_plugin.assert_called_once_with()
|
|
|
|
assert response.status_code == status.HTTP_201_CREATED
|
|
assert response.data == {"error": None, **provision_plugin_response}
|
|
|
|
organization.refresh_from_db()
|
|
|
|
assert organization.grafana_url == GRAFANA_API_URL
|
|
assert organization.api_token == GRAFANA_TOKEN
|
|
assert organization.is_rbac_permissions_enabled is True
|
|
|
|
|
|
@override_settings(SELF_HOSTED_SETTINGS=SELF_HOSTED_SETTINGS)
|
|
@pytest.mark.django_db
|
|
@patch("apps.grafana_plugin.views.self_hosted_install.GrafanaAPIClient")
|
|
@patch("apps.grafana_plugin.views.self_hosted_install.sync_organization")
|
|
@patch("apps.grafana_plugin.views.self_hosted_install.Organization.provision_plugin")
|
|
@patch("apps.grafana_plugin.views.self_hosted_install.Organization.revoke_plugin")
|
|
def test_if_organization_does_not_exist_it_is_created(
|
|
mocked_revoke_plugin,
|
|
mocked_provision_plugin,
|
|
mocked_sync_organization,
|
|
mocked_grafana_api_client,
|
|
make_self_hosted_install_header,
|
|
):
|
|
provision_plugin_response = {"stackId": STACK_ID, "orgId": ORG_ID, "onCallToken": "HELLOOO", "license": LICENSE}
|
|
|
|
mocked_provision_plugin.return_value = provision_plugin_response
|
|
mocked_grafana_api_client.return_value.check_token.return_value = (None, {"status_code": status.HTTP_200_OK})
|
|
mocked_grafana_api_client.return_value.is_rbac_enabled_for_organization.return_value = True, False
|
|
|
|
client = APIClient()
|
|
url = reverse("grafana-plugin:self-hosted-install")
|
|
response = client.post(url, format="json", **make_self_hosted_install_header(GRAFANA_TOKEN))
|
|
|
|
from apps.user_management.models import Organization
|
|
|
|
organization = Organization.objects.filter(stack_id=STACK_ID, org_id=ORG_ID).first()
|
|
|
|
mocked_grafana_api_client.assert_called_once_with(api_url=GRAFANA_API_URL, api_token=GRAFANA_TOKEN)
|
|
mocked_grafana_api_client.return_value.check_token.assert_called_once_with()
|
|
mocked_grafana_api_client.return_value.is_rbac_enabled_for_organization.assert_called_once_with()
|
|
|
|
mocked_sync_organization.assert_called_once_with(organization)
|
|
mocked_provision_plugin.assert_called_once_with()
|
|
assert not mocked_revoke_plugin.called
|
|
|
|
assert response.status_code == status.HTTP_201_CREATED
|
|
assert response.data == {"error": None, **provision_plugin_response}
|
|
|
|
assert organization.stack_id == STACK_ID
|
|
assert organization.stack_slug == STACK_SLUG
|
|
assert organization.org_slug == ORG_SLUG
|
|
assert organization.org_title == ORG_TITLE
|
|
assert organization.region_slug == REGION_SLUG
|
|
assert organization.grafana_url == GRAFANA_API_URL
|
|
assert organization.api_token == GRAFANA_TOKEN
|
|
assert organization.is_rbac_permissions_enabled is True
|