123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373 |
- # Copyright 2016 Google LLC
- #
- # Licensed under the Apache License, Version 2.0 (the "License");
- # you may not use this file except in compliance with the License.
- # You may obtain a copy of the License at
- #
- # http://www.apache.org/licenses/LICENSE-2.0
- #
- # Unless required by applicable law or agreed to in writing, software
- # distributed under the License is distributed on an "AS IS" BASIS,
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- # See the License for the specific language governing permissions and
- # limitations under the License.
- import datetime
- import json
- import os
- import mock
- import pytest
- from six.moves import http_client
- from six.moves import reload_module
- from google.auth import _helpers
- from google.auth import environment_vars
- from google.auth import exceptions
- from google.auth import transport
- from google.auth.compute_engine import _metadata
- PATH = "instance/service-accounts/default"
- def make_request(data, status=http_client.OK, headers=None, retry=False):
- response = mock.create_autospec(transport.Response, instance=True)
- response.status = status
- response.data = _helpers.to_bytes(data)
- response.headers = headers or {}
- request = mock.create_autospec(transport.Request)
- if retry:
- request.side_effect = [exceptions.TransportError(), response]
- else:
- request.return_value = response
- return request
- def test_ping_success():
- request = make_request("", headers=_metadata._METADATA_HEADERS)
- assert _metadata.ping(request)
- request.assert_called_once_with(
- method="GET",
- url=_metadata._METADATA_IP_ROOT,
- headers=_metadata._METADATA_HEADERS,
- timeout=_metadata._METADATA_DEFAULT_TIMEOUT,
- )
- def test_ping_success_retry():
- request = make_request("", headers=_metadata._METADATA_HEADERS, retry=True)
- assert _metadata.ping(request)
- request.assert_called_with(
- method="GET",
- url=_metadata._METADATA_IP_ROOT,
- headers=_metadata._METADATA_HEADERS,
- timeout=_metadata._METADATA_DEFAULT_TIMEOUT,
- )
- assert request.call_count == 2
- def test_ping_failure_bad_flavor():
- request = make_request("", headers={_metadata._METADATA_FLAVOR_HEADER: "meep"})
- assert not _metadata.ping(request)
- def test_ping_failure_connection_failed():
- request = make_request("")
- request.side_effect = exceptions.TransportError()
- assert not _metadata.ping(request)
- def _test_ping_success_custom_root():
- request = make_request("", headers=_metadata._METADATA_HEADERS)
- fake_ip = "1.2.3.4"
- os.environ[environment_vars.GCE_METADATA_IP] = fake_ip
- reload_module(_metadata)
- try:
- assert _metadata.ping(request)
- finally:
- del os.environ[environment_vars.GCE_METADATA_IP]
- reload_module(_metadata)
- request.assert_called_once_with(
- method="GET",
- url="http://" + fake_ip,
- headers=_metadata._METADATA_HEADERS,
- timeout=_metadata._METADATA_DEFAULT_TIMEOUT,
- )
- def test_get_success_json():
- key, value = "foo", "bar"
- data = json.dumps({key: value})
- request = make_request(data, headers={"content-type": "application/json"})
- result = _metadata.get(request, PATH)
- request.assert_called_once_with(
- method="GET",
- url=_metadata._METADATA_ROOT + PATH,
- headers=_metadata._METADATA_HEADERS,
- )
- assert result[key] == value
- def test_get_success_retry():
- key, value = "foo", "bar"
- data = json.dumps({key: value})
- request = make_request(
- data, headers={"content-type": "application/json"}, retry=True
- )
- result = _metadata.get(request, PATH)
- request.assert_called_with(
- method="GET",
- url=_metadata._METADATA_ROOT + PATH,
- headers=_metadata._METADATA_HEADERS,
- )
- assert request.call_count == 2
- assert result[key] == value
- def test_get_success_text():
- data = "foobar"
- request = make_request(data, headers={"content-type": "text/plain"})
- result = _metadata.get(request, PATH)
- request.assert_called_once_with(
- method="GET",
- url=_metadata._METADATA_ROOT + PATH,
- headers=_metadata._METADATA_HEADERS,
- )
- assert result == data
- def test_get_success_params():
- data = "foobar"
- request = make_request(data, headers={"content-type": "text/plain"})
- params = {"recursive": "true"}
- result = _metadata.get(request, PATH, params=params)
- request.assert_called_once_with(
- method="GET",
- url=_metadata._METADATA_ROOT + PATH + "?recursive=true",
- headers=_metadata._METADATA_HEADERS,
- )
- assert result == data
- def test_get_success_recursive_and_params():
- data = "foobar"
- request = make_request(data, headers={"content-type": "text/plain"})
- params = {"recursive": "false"}
- result = _metadata.get(request, PATH, recursive=True, params=params)
- request.assert_called_once_with(
- method="GET",
- url=_metadata._METADATA_ROOT + PATH + "?recursive=true",
- headers=_metadata._METADATA_HEADERS,
- )
- assert result == data
- def test_get_success_recursive():
- data = "foobar"
- request = make_request(data, headers={"content-type": "text/plain"})
- result = _metadata.get(request, PATH, recursive=True)
- request.assert_called_once_with(
- method="GET",
- url=_metadata._METADATA_ROOT + PATH + "?recursive=true",
- headers=_metadata._METADATA_HEADERS,
- )
- assert result == data
- def _test_get_success_custom_root_new_variable():
- request = make_request("{}", headers={"content-type": "application/json"})
- fake_root = "another.metadata.service"
- os.environ[environment_vars.GCE_METADATA_HOST] = fake_root
- reload_module(_metadata)
- try:
- _metadata.get(request, PATH)
- finally:
- del os.environ[environment_vars.GCE_METADATA_HOST]
- reload_module(_metadata)
- request.assert_called_once_with(
- method="GET",
- url="http://{}/computeMetadata/v1/{}".format(fake_root, PATH),
- headers=_metadata._METADATA_HEADERS,
- )
- def _test_get_success_custom_root_old_variable():
- request = make_request("{}", headers={"content-type": "application/json"})
- fake_root = "another.metadata.service"
- os.environ[environment_vars.GCE_METADATA_ROOT] = fake_root
- reload_module(_metadata)
- try:
- _metadata.get(request, PATH)
- finally:
- del os.environ[environment_vars.GCE_METADATA_ROOT]
- reload_module(_metadata)
- request.assert_called_once_with(
- method="GET",
- url="http://{}/computeMetadata/v1/{}".format(fake_root, PATH),
- headers=_metadata._METADATA_HEADERS,
- )
- def test_get_failure():
- request = make_request("Metadata error", status=http_client.NOT_FOUND)
- with pytest.raises(exceptions.TransportError) as excinfo:
- _metadata.get(request, PATH)
- assert excinfo.match(r"Metadata error")
- request.assert_called_once_with(
- method="GET",
- url=_metadata._METADATA_ROOT + PATH,
- headers=_metadata._METADATA_HEADERS,
- )
- def test_get_failure_connection_failed():
- request = make_request("")
- request.side_effect = exceptions.TransportError()
- with pytest.raises(exceptions.TransportError) as excinfo:
- _metadata.get(request, PATH)
- assert excinfo.match(r"Compute Engine Metadata server unavailable")
- request.assert_called_with(
- method="GET",
- url=_metadata._METADATA_ROOT + PATH,
- headers=_metadata._METADATA_HEADERS,
- )
- assert request.call_count == 5
- def test_get_failure_bad_json():
- request = make_request("{", headers={"content-type": "application/json"})
- with pytest.raises(exceptions.TransportError) as excinfo:
- _metadata.get(request, PATH)
- assert excinfo.match(r"invalid JSON")
- request.assert_called_once_with(
- method="GET",
- url=_metadata._METADATA_ROOT + PATH,
- headers=_metadata._METADATA_HEADERS,
- )
- def test_get_project_id():
- project = "example-project"
- request = make_request(project, headers={"content-type": "text/plain"})
- project_id = _metadata.get_project_id(request)
- request.assert_called_once_with(
- method="GET",
- url=_metadata._METADATA_ROOT + "project/project-id",
- headers=_metadata._METADATA_HEADERS,
- )
- assert project_id == project
- @mock.patch("google.auth._helpers.utcnow", return_value=datetime.datetime.min)
- def test_get_service_account_token(utcnow):
- ttl = 500
- request = make_request(
- json.dumps({"access_token": "token", "expires_in": ttl}),
- headers={"content-type": "application/json"},
- )
- token, expiry = _metadata.get_service_account_token(request)
- request.assert_called_once_with(
- method="GET",
- url=_metadata._METADATA_ROOT + PATH + "/token",
- headers=_metadata._METADATA_HEADERS,
- )
- assert token == "token"
- assert expiry == utcnow() + datetime.timedelta(seconds=ttl)
- @mock.patch("google.auth._helpers.utcnow", return_value=datetime.datetime.min)
- def test_get_service_account_token_with_scopes_list(utcnow):
- ttl = 500
- request = make_request(
- json.dumps({"access_token": "token", "expires_in": ttl}),
- headers={"content-type": "application/json"},
- )
- token, expiry = _metadata.get_service_account_token(request, scopes=["foo", "bar"])
- request.assert_called_once_with(
- method="GET",
- url=_metadata._METADATA_ROOT + PATH + "/token" + "?scopes=foo%2Cbar",
- headers=_metadata._METADATA_HEADERS,
- )
- assert token == "token"
- assert expiry == utcnow() + datetime.timedelta(seconds=ttl)
- @mock.patch("google.auth._helpers.utcnow", return_value=datetime.datetime.min)
- def test_get_service_account_token_with_scopes_string(utcnow):
- ttl = 500
- request = make_request(
- json.dumps({"access_token": "token", "expires_in": ttl}),
- headers={"content-type": "application/json"},
- )
- token, expiry = _metadata.get_service_account_token(request, scopes="foo,bar")
- request.assert_called_once_with(
- method="GET",
- url=_metadata._METADATA_ROOT + PATH + "/token" + "?scopes=foo%2Cbar",
- headers=_metadata._METADATA_HEADERS,
- )
- assert token == "token"
- assert expiry == utcnow() + datetime.timedelta(seconds=ttl)
- def test_get_service_account_info():
- key, value = "foo", "bar"
- request = make_request(
- json.dumps({key: value}), headers={"content-type": "application/json"}
- )
- info = _metadata.get_service_account_info(request)
- request.assert_called_once_with(
- method="GET",
- url=_metadata._METADATA_ROOT + PATH + "/?recursive=true",
- headers=_metadata._METADATA_HEADERS,
- )
- assert info[key] == value
|