Skip to content

Commit 359b3ac

Browse files
feat: Allow users to configure client option universe_domain (#2368)
* feat: allow users to configure universe client option * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md --------- Co-authored-by: Owl Bot <gcf-owl-bot[bot]@users.noreply.github.com>
1 parent 77666bf commit 359b3ac

File tree

2 files changed

+164
-17
lines changed

2 files changed

+164
-17
lines changed

googleapiclient/discovery.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,13 @@ def build_from_document(
551551

552552
# If an API Endpoint is provided on client options, use that as the base URL
553553
base = urllib.parse.urljoin(service["rootUrl"], service["servicePath"])
554+
universe_domain = None
555+
if HAS_UNIVERSE:
556+
universe_domain = universe.determine_domain(
557+
client_options.universe_domain, None
558+
)
559+
base = base.replace(universe.DEFAULT_UNIVERSE, universe_domain)
560+
554561
audience_for_self_signed_jwt = base
555562
if client_options.api_endpoint:
556563
base = client_options.api_endpoint
@@ -673,6 +680,10 @@ def build_from_document(
673680
if use_mtls_endpoint == "always" or (
674681
use_mtls_endpoint == "auto" and client_cert_to_use
675682
):
683+
if HAS_UNIVERSE and universe_domain != universe.DEFAULT_UNIVERSE:
684+
raise MutualTLSChannelError(
685+
f"mTLS is not supported in any universe other than {universe.DEFAULT_UNIVERSE}."
686+
)
676687
base = mtls_endpoint
677688

678689
if model is None:
@@ -688,6 +699,7 @@ def build_from_document(
688699
resourceDesc=service,
689700
rootDesc=service,
690701
schema=schema,
702+
universe_domain=universe_domain,
691703
)
692704

693705

@@ -1517,6 +1529,7 @@ def methodResource(self):
15171529
resourceDesc=methodDesc,
15181530
rootDesc=rootDesc,
15191531
schema=schema,
1532+
universe_domain=self._universe_domain,
15201533
)
15211534

15221535
setattr(methodResource, "__doc__", "A collection resource.")

tests/test_discovery.py

Lines changed: 151 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2343,6 +2343,25 @@ def test_get_media(self):
23432343
if HAS_UNIVERSE:
23442344

23452345
class Universe(unittest.TestCase):
2346+
def test_validate_credentials_with_no_client_options(self):
2347+
http = build_http()
2348+
discovery = read_datafile("zoo.json")
2349+
service = build_from_document(
2350+
discovery,
2351+
http=http,
2352+
)
2353+
assert service._validate_credentials()
2354+
2355+
def test_validate_credentials_with_client_options_without_universe(self):
2356+
http = build_http()
2357+
discovery = read_datafile("zoo.json")
2358+
service = build_from_document(
2359+
discovery,
2360+
http=http,
2361+
client_options=google.api_core.client_options.ClientOptions(),
2362+
)
2363+
assert service._validate_credentials()
2364+
23462365
def test_validate_credentials_with_no_universe(self):
23472366
fake_universe = "foo.com"
23482367

@@ -2360,9 +2379,20 @@ def test_validate_credentials_with_no_universe(self):
23602379

23612380
assert service._validate_credentials()
23622381

2363-
# TODO(google-api-python-client/issues/2365): Add test case for no configured universe and fake credentials' universe.
2382+
http = google_auth_httplib2.AuthorizedHttp(
2383+
credentials=None, http=build_http()
2384+
)
2385+
discovery = read_datafile("zoo.json")
2386+
service = build_from_document(
2387+
discovery,
2388+
http=http,
2389+
client_options=google.api_core.client_options.ClientOptions(
2390+
universe_domain=fake_universe
2391+
),
2392+
)
23642393

2365-
# TODO(google-api-python-client/issues/2365): Add test case for not specifying universe domain via client option.
2394+
with self.assertRaises(universe.UniverseMismatchError):
2395+
service._validate_credentials()
23662396

23672397
def test_validate_credentials_with_default_universe(self):
23682398
fake_universe = "foo.com"
@@ -2382,12 +2412,39 @@ def test_validate_credentials_with_default_universe(self):
23822412

23832413
assert service._validate_credentials()
23842414

2385-
# TODO(google-api-python-client/issues/2365): # Add test case for "googleapis.com" configured universe and fake credentials' universe.
2415+
http = google_auth_httplib2.AuthorizedHttp(
2416+
credentials=mock.Mock(universe_domain=universe.DEFAULT_UNIVERSE),
2417+
http=build_http(),
2418+
)
2419+
discovery = read_datafile("zoo.json")
2420+
service = build_from_document(
2421+
discovery,
2422+
http=http,
2423+
client_options=google.api_core.client_options.ClientOptions(
2424+
universe_domain=fake_universe
2425+
),
2426+
)
2427+
2428+
with self.assertRaises(universe.UniverseMismatchError):
2429+
service._validate_credentials()
23862430

23872431
def test_validate_credentials_with_a_different_universe(self):
23882432
fake_universe = "foo.com"
23892433

2390-
# TODO(google-api-python-client/issues/2365): Add test case for fake configured universe and fake credentials' universe.
2434+
http = google_auth_httplib2.AuthorizedHttp(
2435+
credentials=mock.Mock(universe_domain=fake_universe),
2436+
http=build_http(),
2437+
)
2438+
discovery = read_datafile("zoo.json")
2439+
service = build_from_document(
2440+
discovery,
2441+
http=http,
2442+
client_options=google.api_core.client_options.ClientOptions(
2443+
universe_domain=fake_universe
2444+
),
2445+
)
2446+
2447+
assert service._validate_credentials()
23912448

23922449
http = google_auth_httplib2.AuthorizedHttp(
23932450
credentials=mock.Mock(universe_domain=fake_universe), http=build_http()
@@ -2426,21 +2483,34 @@ def test_validate_credentials_with_already_validated_credentials(self):
24262483
# Calling service._validate_credentials() again returns service.credentials_validated.
24272484
assert service._validate_credentials()
24282485

2429-
# TODO(google-api-python-client/issues/2365): Add test case for fake configured universe and fake credentials' universe.
2430-
2431-
def test_validate_credentials_before_api_request(self):
2432-
fake_universe = "foo.com"
2433-
24342486
http = google_auth_httplib2.AuthorizedHttp(
2435-
credentials=mock.Mock(universe_domain=universe.DEFAULT_UNIVERSE),
2436-
http=build_http(),
2487+
credentials=mock.Mock(universe_domain=fake_universe), http=build_http()
2488+
)
2489+
discovery = read_datafile("zoo.json")
2490+
service = build_from_document(
2491+
discovery,
2492+
http=http,
2493+
client_options=google.api_core.client_options.ClientOptions(
2494+
universe_domain=fake_universe
2495+
),
24372496
)
2497+
2498+
assert service._validate_credentials()
2499+
assert service._credentials_validated
2500+
2501+
# Calling service._validate_credentials() again returns service.credentials_validated.
2502+
assert service._validate_credentials()
2503+
2504+
def test_validate_credentials_before_api_request_success(self):
2505+
fake_universe = "foo.com"
2506+
credentials = mock.Mock(spec=google.auth.credentials.Credentials)
2507+
credentials.universe_domain = fake_universe
24382508
discovery = read_datafile("tasks.json")
24392509
tasks = build_from_document(
24402510
discovery,
2441-
http=http,
2511+
credentials=credentials,
24422512
client_options=google.api_core.client_options.ClientOptions(
2443-
universe_domain=universe.DEFAULT_UNIVERSE
2513+
universe_domain=fake_universe
24442514
),
24452515
)
24462516

@@ -2450,13 +2520,14 @@ def test_validate_credentials_before_api_request(self):
24502520
# Check that credentials are indeed verified before request.
24512521
assert tasklists._validate_credentials()
24522522

2453-
http = google_auth_httplib2.AuthorizedHttp(
2454-
credentials=mock.Mock(universe_domain=fake_universe), http=build_http()
2455-
)
2523+
def test_validate_credentials_before_api_request_failure(self):
2524+
fake_universe = "foo.com"
2525+
credentials = mock.Mock(spec=google.auth.credentials.Credentials)
2526+
credentials.universe_domain = fake_universe
24562527
discovery = read_datafile("tasks.json")
24572528
tasks = build_from_document(
24582529
discovery,
2459-
http=http,
2530+
credentials=credentials,
24602531
client_options=google.api_core.client_options.ClientOptions(
24612532
universe_domain=universe.DEFAULT_UNIVERSE
24622533
),
@@ -2466,6 +2537,69 @@ def test_validate_credentials_before_api_request(self):
24662537
with self.assertRaises(universe.UniverseMismatchError):
24672538
request = tasks.tasklists().list()
24682539

2540+
def test_validate_credentials_before_another_universe_api_request_failure(self):
2541+
fake_universe = "foo.com"
2542+
credentials = mock.Mock(spec=google.auth.credentials.Credentials)
2543+
credentials.universe_domain = fake_universe
2544+
another_fake_universe = "bar.com"
2545+
discovery = read_datafile("tasks.json")
2546+
tasks = build_from_document(
2547+
discovery,
2548+
credentials=credentials,
2549+
client_options=google.api_core.client_options.ClientOptions(
2550+
universe_domain=another_fake_universe
2551+
),
2552+
)
2553+
2554+
# Check that credentials are verified before request.
2555+
with self.assertRaises(universe.UniverseMismatchError):
2556+
request = tasks.tasklists().list()
2557+
2558+
def test_client_options_with_empty_universe(self):
2559+
fake_universe = "foo.com"
2560+
credentials = mock.Mock(spec=google.auth.credentials.Credentials)
2561+
discovery = read_datafile("tasks.json")
2562+
2563+
with self.assertRaises(universe.EmptyUniverseError):
2564+
tasks = build_from_document(
2565+
discovery,
2566+
credentials=credentials,
2567+
client_options=google.api_core.client_options.ClientOptions(
2568+
universe_domain=""
2569+
),
2570+
)
2571+
2572+
def test_client_options_universe_configured_with_mtls(self):
2573+
fake_universe = "foo.com"
2574+
discovery = read_datafile("tasks.json")
2575+
2576+
with self.assertRaises(MutualTLSChannelError):
2577+
with mock.patch.dict(
2578+
"os.environ", {"GOOGLE_API_USE_MTLS_ENDPOINT": "always"}
2579+
):
2580+
tasks = build_from_document(
2581+
discovery,
2582+
client_options=google.api_core.client_options.ClientOptions(
2583+
universe_domain=fake_universe
2584+
),
2585+
)
2586+
2587+
def test_client_options_universe_configured_with_api_override(self):
2588+
fake_universe = "foo.com"
2589+
fake_api_endpoint = "https://www.bar.com/"
2590+
credentials = mock.Mock(universe_domain=fake_universe)
2591+
discovery = read_datafile("tasks.json")
2592+
2593+
tasks = build_from_document(
2594+
discovery,
2595+
credentials=credentials,
2596+
client_options=google.api_core.client_options.ClientOptions(
2597+
api_endpoint=fake_api_endpoint, universe_domain=fake_universe
2598+
),
2599+
)
2600+
2601+
assert tasks._baseUrl == fake_api_endpoint
2602+
24692603

24702604
if __name__ == "__main__":
24712605
unittest.main()

0 commit comments

Comments
 (0)