Skip to content

Commit

Permalink
Move validate_grafana_token_format to common location, use in sync_v2 (
Browse files Browse the repository at this point in the history
…#4919)

# What this PR does
Moves validate_grafana_token_format to GrafanaAPIClient, use it in
sync_v2 to improve logging and skip requests that would not work.

## Which issue(s) this PR closes

Related to [issue link here]

<!--
*Note*: If you want the issue to be auto-closed once the PR is merged,
change "Related to" to "Closes" in the line above.
If you have more than one GitHub issue that this PR closes, be sure to
preface
each issue link with a [closing
keyword](https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/using-keywords-in-issues-and-pull-requests#linking-a-pull-request-to-an-issue).
This ensures that the issue(s) are auto-closed once the PR has been
merged.
-->

## 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.
  • Loading branch information
mderynck authored Aug 23, 2024
1 parent a577030 commit a25d44d
Show file tree
Hide file tree
Showing 4 changed files with 16 additions and 14 deletions.
10 changes: 10 additions & 0 deletions engine/apps/grafana_plugin/helpers/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,8 @@ class GrafanaAPIClient(APIClient):

USER_PERMISSION_ENDPOINT = f"api/access-control/users/permissions/search?actionPrefix={ACTION_PREFIX}"

MIN_GRAFANA_TOKEN_LENGTH = 16

class Types:
class _BaseGrafanaAPIResponse(typing.TypedDict):
totalCount: int
Expand Down Expand Up @@ -330,6 +332,14 @@ def get_service_account_token_permissions(self) -> APIClientResponse[typing.Dict
def sync(self) -> APIClientResponse:
return self.api_post("api/plugins/grafana-oncall-app/resources/plugin/sync")

@staticmethod
def validate_grafana_token_format(grafana_token: str) -> bool:
if not grafana_token or not isinstance(grafana_token, str):
return False
if len(grafana_token) < GrafanaAPIClient.MIN_GRAFANA_TOKEN_LENGTH:
return False
return True


class GcomAPIClient(APIClient):
ACTIVE_INSTANCE_QUERY = "instances?status=active"
Expand Down
13 changes: 2 additions & 11 deletions engine/apps/grafana_plugin/helpers/gcom.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,19 @@

from apps.auth_token.exceptions import InvalidToken
from apps.auth_token.models import PluginAuthToken
from apps.grafana_plugin.helpers import GcomAPIClient
from apps.grafana_plugin.helpers import GcomAPIClient, GrafanaAPIClient
from apps.user_management.models import Organization

logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
GCOM_TOKEN_CHECK_PERIOD = timezone.timedelta(minutes=60)
MIN_GRAFANA_TOKEN_LENGTH = 16


class GcomToken:
def __init__(self, organization):
self.organization = organization


def _validate_grafana_token_format(grafana_token: str) -> bool:
if not grafana_token or not isinstance(grafana_token, str):
return False
if len(grafana_token) < MIN_GRAFANA_TOKEN_LENGTH:
return False
return True


def check_gcom_permission(token_string: str, context) -> GcomToken:
"""
Verify that request from plugin is valid. Check it and synchronize the organization details
Expand All @@ -54,7 +45,7 @@ def check_gcom_permission(token_string: str, context) -> GcomToken:
if not instance_info or str(instance_info["orgId"]) != org_id:
raise InvalidToken

grafana_token_format_is_valid = _validate_grafana_token_format(grafana_token)
grafana_token_format_is_valid = GrafanaAPIClient.validate_grafana_token_format(grafana_token)

if not organization:
from apps.base.models import DynamicSetting
Expand Down
4 changes: 2 additions & 2 deletions engine/apps/grafana_plugin/tasks/sync_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def sync_organizations_v2(org_ids=None):
orgs_per_second = math.ceil(len(organization_qs) / SYNC_PERIOD.seconds)
logger.info(f"Syncing {len(organization_qs)} organizations @ {orgs_per_second} per 1s pause")
for idx, org in enumerate(organization_qs):
if org.api_token:
if GrafanaAPIClient.validate_grafana_token_format(org.api_token):
client = GrafanaAPIClient(api_url=org.grafana_url, api_token=org.api_token)
_, status = client.sync()
if status["status_code"] != 200:
Expand All @@ -52,6 +52,6 @@ def sync_organizations_v2(org_ids=None):
logger.info(f"Sleep 1s after {idx + 1} organizations processed")
sleep(1)
else:
logger.info(f"Skipping stack_slug={org.stack_slug}, api_token is not set")
logger.info(f"Skipping stack_slug={org.stack_slug}, api_token format is invalid or not set")
else:
logger.info(f"Issuing sync requests already in progress lock_id={lock_id}, check slow outgoing requests")
3 changes: 2 additions & 1 deletion engine/apps/grafana_plugin/tests/test_sync_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ def test_invalid_auth(make_organization_and_user_with_plugin_token, make_user_au
"api_token, sync_called",
[
("", False),
("abc", True),
("abc", False),
("glsa_abcdefghijklmnopqrstuvwxyz", True),
],
)
@pytest.mark.django_db
Expand Down

0 comments on commit a25d44d

Please sign in to comment.