Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add support for domain-scoped projects #185

Merged
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 30 additions & 15 deletions google/cloud/alloydb/connector/instance.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

import asyncio
import logging
import re
from typing import Tuple, TYPE_CHECKING

from google.cloud.alloydb.connector.exceptions import RefreshError
Expand All @@ -33,6 +34,27 @@

logger = logging.getLogger(name=__name__)

INSTANCE_URI_REGEX = re.compile(
"projects/([^:]+(:[^:]+)?)/locations/([^:]+)/clusters/([^:]+)/instances/([^:]+)"
)


def _parse_instance_uri(instance_uri: str) -> Tuple[str, str, str, str]:
# should take form "projects/<PROJECT>/locations/<REGION>/clusters/<CLUSTER>/instances/<INSTANCE>"
if INSTANCE_URI_REGEX.fullmatch(instance_uri) is None:
raise ValueError(
"Arg `instance_uri` must have "
"format: projects/<PROJECT>/locations/<REGION>/clusters/<CLUSTER>/instances/<INSTANCE>, projects/<DOMAIN>:<PROJECT>/locations/<REGION>/clusters/<CLUSTER>/instances/<INSTANCE>"
f"got {instance_uri}."
)
instance_uri_split = INSTANCE_URI_REGEX.split(instance_uri)
return (
instance_uri_split[1],
instance_uri_split[3],
instance_uri_split[4],
instance_uri_split[5],
)


class Instance:
"""
Expand All @@ -56,21 +78,14 @@ def __init__(
keys: asyncio.Future[Tuple[rsa.RSAPrivateKey, str]],
) -> None:
# validate and parse instance_uri
instance_uri_split = instance_uri.split("/")
# should take form "projects/<PROJECT>/locations/<REGION>/clusters/<CLUSTER>/instances/<INSTANCE>"
if len(instance_uri_split) == 8:
self._instance_uri = instance_uri
self._project = instance_uri_split[1]
self._region = instance_uri_split[3]
self._cluster = instance_uri_split[5]
self._name = instance_uri_split[7]
else:
raise ValueError(
"Arg `instance_uri` must have "
"format: projects/<PROJECT>/locations/<REGION>/clusters/<CLUSTER>/instances/<INSTANCE>, "
f"got {instance_uri}."
)

(
self._project,
self._region,
self._cluster,
self._name,
) = _parse_instance_uri(instance_uri)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is the linter adding the () around this tuple? I don't think we need them as the function can just unpack the tuple into the appropriate variables.

Suggested change
(
self._project,
self._region,
self._cluster,
self._name,
) = _parse_instance_uri(instance_uri)
self._project, self._region, self._cluster, self._name = _parse_instance_uri(instance_uri)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes @jackwotherspoon , the tuple was causing the formatting. I have removed it in the latest push.

self._instance_uri = instance_uri
self._client = client
self._keys = keys
self._refresh_rate_limiter = AsyncRateLimiter(
Expand Down
37 changes: 36 additions & 1 deletion tests/unit/test_instance.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,52 @@

import asyncio
from datetime import datetime, timedelta
from typing import Tuple

import aiohttp
from mocks import FakeAlloyDBClient
import pytest

from google.cloud.alloydb.connector.exceptions import RefreshError
from google.cloud.alloydb.connector.instance import Instance
from google.cloud.alloydb.connector.instance import _parse_instance_uri, Instance
from google.cloud.alloydb.connector.refresh import _is_valid, RefreshResult
from google.cloud.alloydb.connector.utils import generate_keys


@pytest.mark.parametrize(
"instance_uri, expected",
[
(
"projects/test-project/locations/test-region/clusters/test-cluster/instances/test-instance",
("test-project", "test-region", "test-cluster", "test-instance"),
),
(
"projects/test-domain:test-project/locations/test-region/clusters/test-cluster/instances/test-instance",
(
"test-domain:test-project",
"test-region",
"test-cluster",
"test-instance",
),
),
],
)
def test_parse_instance_uri(instance_uri: str, expected: Tuple[str, str, str]) -> None:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need the 4th str for the tuple...

Suggested change
def test_parse_instance_uri(instance_uri: str, expected: Tuple[str, str, str]) -> None:
def test_parse_instance_uri(instance_uri: str, expected: Tuple[str, str, str, str]) -> None:

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

my bad, I have added and pushed again with latest changes.

"""
Test that _parse_instance_uri correctly on
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Test that _parse_instance_uri correctly on
Test that _parse_instance_uri works correctly on

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

again, my bad! I have added it.

normal instance uri and domain-scoped projects.
"""
assert expected == _parse_instance_uri(instance_uri)


def test_parse_bad_instance_uri() -> None:
"""
Tests that ValueError is thrown for bad instance uri.
"""
with pytest.raises(ValueError):
_parse_instance_uri("test-project:test-instance")


@pytest.mark.asyncio
async def test_Instance_init() -> None:
"""
Expand Down