Skip to content

Commit e220f5b

Browse files
chore: update ClientResponse error with detailed message (GoogleCloudPlatform#362)
1 parent 3d5975a commit e220f5b

File tree

2 files changed

+62
-2
lines changed

2 files changed

+62
-2
lines changed

google/cloud/sql/connector/instance.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,14 @@ async def _perform_refresh(self) -> InstanceMetadata:
358358
if expiration > token_expiration:
359359
expiration = token_expiration
360360

361+
except aiohttp.ClientResponseError as e:
362+
logger.debug(
363+
f"['{self._instance_connection_string}']: Error occurred during _perform_refresh."
364+
)
365+
if e.status == 403:
366+
e.message = "Forbidden: Authenticated IAM principal does not seeem authorized to make API request. Verify 'Cloud SQL Admin API' is enabled within your GCP project and 'Cloud SQL Client' role has been granted to IAM principal."
367+
raise
368+
361369
except Exception as e:
362370
logger.debug(
363371
f"['{self._instance_connection_string}']: Error occurred during _perform_refresh."

tests/unit/test_instance.py

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,9 @@
1515
"""
1616

1717
import asyncio
18-
from mock import patch
18+
import pytest # noqa F401 Needed to run the tests
1919
import datetime
2020
from google.cloud.sql.connector.rate_limiter import AsyncRateLimiter
21-
import pytest # noqa F401 Needed to run the tests
2221
from google.auth.credentials import Credentials
2322
from google.cloud.sql.connector.instance import (
2423
IPTypes,
@@ -28,6 +27,9 @@
2827
InstanceMetadata,
2928
)
3029
from google.cloud.sql.connector.utils import generate_keys
30+
from mock import patch
31+
from aioresponses import aioresponses
32+
from aiohttp import ClientResponseError, RequestInfo
3133

3234
# import mocks
3335
import mocks
@@ -344,3 +346,53 @@ async def test_get_preferred_ip_CloudSQLIPTypeError(instance: Instance) -> None:
344346
instance_metadata.ip_addrs = {"PRIMARY": "0.0.0.0"}
345347
with pytest.raises(CloudSQLIPTypeError):
346348
instance_metadata.get_preferred_ip(IPTypes.PRIVATE)
349+
350+
351+
@pytest.mark.asyncio
352+
async def test_ClientResponseError(
353+
fake_credentials: Credentials, event_loop: asyncio.AbstractEventLoop
354+
) -> None:
355+
"""
356+
Test that detailed error message is applied to ClientResponseError.
357+
"""
358+
# mock Cloud SQL Admin API calls with exceptions
359+
keys = asyncio.run_coroutine_threadsafe(generate_keys(), event_loop)
360+
get_url = "https://sqladmin.googleapis.com/sql/v1beta4/projects/my-project/instances/my-instance/connectSettings"
361+
post_url = "https://sqladmin.googleapis.com/sql/v1beta4/projects/my-project/instances/my-instance:generateEphemeralCert"
362+
with aioresponses() as mocked:
363+
mocked.get(
364+
get_url,
365+
status=403,
366+
exception=ClientResponseError(
367+
RequestInfo(get_url, "GET", headers=[]), history=[], status=403 # type: ignore
368+
),
369+
repeat=True,
370+
)
371+
mocked.post(
372+
post_url,
373+
status=403,
374+
exception=ClientResponseError(
375+
RequestInfo(post_url, "POST", headers=[]), history=[], status=403 # type: ignore
376+
),
377+
repeat=True,
378+
)
379+
# verify that error is raised with detailed error message
380+
try:
381+
instance = Instance(
382+
"my-project:my-region:my-instance",
383+
"pymysql",
384+
keys,
385+
event_loop,
386+
credentials=fake_credentials,
387+
)
388+
await instance._current
389+
except ClientResponseError as e:
390+
assert e.status == 403
391+
assert (
392+
e.message == "Forbidden: Authenticated IAM principal does not "
393+
"seeem authorized to make API request. Verify "
394+
"'Cloud SQL Admin API' is enabled within your GCP project and "
395+
"'Cloud SQL Client' role has been granted to IAM principal."
396+
)
397+
finally:
398+
await instance.close()

0 commit comments

Comments
 (0)