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: avoid authentication when use emulator #328
Conversation
google/cloud/storage/client.py
Outdated
project = os.getenv("GCLOUD_PROJECT") | ||
if project is None: | ||
raise ValueError( | ||
"For emulator pass `project` as a argument or set `GCLOUD_PROJECT` via environment variable" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"For emulator pass `project` as a argument or set `GCLOUD_PROJECT` via environment variable" | |
"To use the GCS emulator, pass 'project' as an argument " | |
"or set GCLOUD_PROJECT environment variable" |
tests/unit/test_client.py
Outdated
def test_ctor_w_emulator_w_env_var_glcoud_project(self): | ||
from google.cloud.storage._helpers import STORAGE_EMULATOR_ENV_VAR | ||
|
||
HOST = "https://api.example.com" | ||
PROJECT = "test" | ||
|
||
with mock.patch("os.environ", {STORAGE_EMULATOR_ENV_VAR: HOST}): | ||
with mock.patch("os.getenv", side_effect=[HOST, PROJECT]): | ||
client = self._make_one() | ||
self.assertEqual(client.project, PROJECT) | ||
self.assertEqual(client._connection.API_BASE_URL, HOST) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test needs an assertion that the client's credentials is an instance of AnonymousCredentials
.
Also, rather than patching os.getenv
, this would be clearer if we just patched in the expected environment:
def test_ctor_w_emulator_w_env_var_glcoud_project(self): | |
from google.cloud.storage._helpers import STORAGE_EMULATOR_ENV_VAR | |
HOST = "https://api.example.com" | |
PROJECT = "test" | |
with mock.patch("os.environ", {STORAGE_EMULATOR_ENV_VAR: HOST}): | |
with mock.patch("os.getenv", side_effect=[HOST, PROJECT]): | |
client = self._make_one() | |
self.assertEqual(client.project, PROJECT) | |
self.assertEqual(client._connection.API_BASE_URL, HOST) | |
def test_ctor_w_emulator_w_env_var_glcoud_project(self): | |
from google.auth.credentials import AnonymousCredentials | |
from google.cloud.storage._helpers import STORAGE_EMULATOR_ENV_VAR | |
HOST = "https://api.example.com" | |
PROJECT = "test" | |
environ = { | |
STORAGE_EMULATOR_ENV_VAR: HOST, | |
"GCLOUD_PROJECT": PROJECT, | |
} | |
with mock.patch("os.environ", environ): | |
client = self._make_one() | |
self.assertEqual(client.project, PROJECT) | |
self.assertEqual(client._connection.API_BASE_URL, HOST) | |
self.assertIsInstance(client._credentials, AnonymousCredentials) |
tests/unit/test_client.py
Outdated
def test_ctor_w_emulator_w_project_argument(self): | ||
HOST = "https://api.example.com" | ||
PROJECT = "test" | ||
|
||
with mock.patch("os.getenv", side_effect=[HOST]): | ||
client = self._make_one(project=PROJECT) | ||
self.assertEqual(client.project, PROJECT) | ||
|
||
def test_ctor_w_emulator_missing_project(self): | ||
HOST = "https://api.example.com" | ||
with mock.patch("os.getenv", side_effect=[HOST, None]): | ||
with self.assertRaises(ValueError): | ||
self._make_one() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to verify that the passed-in project overrides the one in the environment. Likewise for these tests, just patch os.environ
:
def test_ctor_w_emulator_w_project_argument(self): | |
HOST = "https://api.example.com" | |
PROJECT = "test" | |
with mock.patch("os.getenv", side_effect=[HOST]): | |
client = self._make_one(project=PROJECT) | |
self.assertEqual(client.project, PROJECT) | |
def test_ctor_w_emulator_missing_project(self): | |
HOST = "https://api.example.com" | |
with mock.patch("os.getenv", side_effect=[HOST, None]): | |
with self.assertRaises(ValueError): | |
self._make_one() | |
def test_ctor_w_emulator_w_project_argument(self): | |
from google.auth.credentials import AnonymousCredentials | |
from google.cloud.storage._helpers import STORAGE_EMULATOR_ENV_VAR | |
HOST = "https://api.example.com" | |
PROJECT = "test" | |
ENVIRON_PROJECT = "environ-project" | |
environ = { | |
STORAGE_EMULATOR_ENV_VAR: HOST, | |
"GCLOUD_PROJECT": ENVIRON_PROJECT, | |
} | |
with mock.patch("os.environ", environ): | |
client = self._make_one(project=PROJECT) | |
self.assertEqual(client.project, PROJECT) | |
self.assertEqual(client._connection.API_BASE_URL, HOST) | |
self.assertIsInstance(client._credentials, AnonymousCredentials) | |
def test_ctor_w_emulator_missing_project(self): | |
from google.cloud.storage._helpers import STORAGE_EMULATOR_ENV_VAR | |
HOST = "https://api.example.com" | |
environ = {STORAGE_EMULATOR_ENV_VAR: HOST} | |
with mock.patch("os.environ", environ): | |
with self.assertRaises(ValueError): | |
self._make_one() |
@@ -112,6 +114,15 @@ def __init__( | |||
if project is _marker: | |||
project = None | |||
|
|||
if os.getenv(STORAGE_EMULATOR_ENV_VAR) is not None: | |||
credentials = AnonymousCredentials() | |||
if project in [_marker, None]: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is project validation necessary given the super class will fall back to the expected environment variables?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, when we are passing credentials
as a keyword argument and if not passing project then it found the project in fall back but then throw an error about Default credential from here https://github.com/googleapis/google-auth-library-python/blob/bc92abbce5e0a5e7b5de8157e7772db84349a6cb/google/auth/_default.py#L356 when called a method google.auth.default()
method because method unable to find credential from the given four options .
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think i can remove this condition after merge of cloud-core-51 PR
@@ -112,6 +114,15 @@ def __init__( | |||
if project is _marker: | |||
project = None | |||
|
|||
if os.getenv(STORAGE_EMULATOR_ENV_VAR) is not None: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be good to infer this from endpoint value in client_options.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry didn't get the point, few questions regarding that
-
what if client_options didn't pass
-
which value use to compare with kw_args["api_endpoint"]? _DEFAULT_STORAGE_HOST which is
https://storage.googleapis.com
? -
Right now first we call the super class of client with credentials and then iterate the
client_options
and_get_storage_host()
for an api_endpoint, should we need to change that order?
…into storage_issue_324
Replaced by #679 |
Fixes #324