Skip to content

Commit 56ce0a3

Browse files
DaniilAnichinbusunkim96
authored andcommitted
fix(google.auth.compute_engine.metadata): add retry to google.auth.compute_engine._metadata.get() (#398)
Initial fix of issue #211 was done in CL #323, but only for .ping() This one is adding same behaviour & tests for .get() method, as the problem still occurres See the issue for details Refs: #323 Resolves: #211
1 parent 3402e43 commit 56ce0a3

File tree

2 files changed

+76
-4
lines changed

2 files changed

+76
-4
lines changed

packages/google-auth/google/auth/compute_engine/_metadata.py

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ def ping(request, timeout=_METADATA_DEFAULT_TIMEOUT, retry_count=3):
9999
return False
100100

101101

102-
def get(request, path, root=_METADATA_ROOT, recursive=False):
102+
def get(request, path, root=_METADATA_ROOT, recursive=False, retry_count=5):
103103
"""Fetch a resource from the metadata server.
104104
105105
Args:
@@ -111,6 +111,8 @@ def get(request, path, root=_METADATA_ROOT, recursive=False):
111111
recursive (bool): Whether to do a recursive query of metadata. See
112112
https://cloud.google.com/compute/docs/metadata#aggcontents for more
113113
details.
114+
retry_count (int): How many times to attempt connecting to metadata
115+
server using above timeout.
114116
115117
Returns:
116118
Union[Mapping, str]: If the metadata server returns JSON, a mapping of
@@ -129,7 +131,24 @@ def get(request, path, root=_METADATA_ROOT, recursive=False):
129131

130132
url = _helpers.update_query(base_url, query_params)
131133

132-
response = request(url=url, method="GET", headers=_METADATA_HEADERS)
134+
retries = 0
135+
while retries < retry_count:
136+
try:
137+
response = request(url=url, method="GET", headers=_METADATA_HEADERS)
138+
break
139+
140+
except exceptions.TransportError:
141+
_LOGGER.info(
142+
"Compute Engine Metadata server unavailable on" "attempt %s of %s",
143+
retries + 1,
144+
retry_count,
145+
)
146+
retries += 1
147+
else:
148+
raise exceptions.TransportError(
149+
"Failed to retrieve {} from the Google Compute Engine"
150+
"metadata service. Compute Engine Metadata server unavailable".format(url)
151+
)
133152

134153
if response.status == http_client.OK:
135154
content = _helpers.from_bytes(response.data)

packages/google-auth/tests/compute_engine/test__metadata.py

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,17 @@
3030
PATH = "instance/service-accounts/default"
3131

3232

33-
def make_request(data, status=http_client.OK, headers=None):
33+
def make_request(data, status=http_client.OK, headers=None, retry=False):
3434
response = mock.create_autospec(transport.Response, instance=True)
3535
response.status = status
3636
response.data = _helpers.to_bytes(data)
3737
response.headers = headers or {}
3838

3939
request = mock.create_autospec(transport.Request)
40-
request.return_value = response
40+
if retry:
41+
request.side_effect = [exceptions.TransportError(), response]
42+
else:
43+
request.return_value = response
4144

4245
return request
4346

@@ -55,6 +58,20 @@ def test_ping_success():
5558
)
5659

5760

61+
def test_ping_success_retry():
62+
request = make_request("", headers=_metadata._METADATA_HEADERS, retry=True)
63+
64+
assert _metadata.ping(request)
65+
66+
request.assert_called_with(
67+
method="GET",
68+
url=_metadata._METADATA_IP_ROOT,
69+
headers=_metadata._METADATA_HEADERS,
70+
timeout=_metadata._METADATA_DEFAULT_TIMEOUT,
71+
)
72+
assert request.call_count == 2
73+
74+
5875
def test_ping_failure_bad_flavor():
5976
request = make_request("", headers={_metadata._METADATA_FLAVOR_HEADER: "meep"})
6077

@@ -105,6 +122,25 @@ def test_get_success_json():
105122
assert result[key] == value
106123

107124

125+
def test_get_success_retry():
126+
key, value = "foo", "bar"
127+
128+
data = json.dumps({key: value})
129+
request = make_request(
130+
data, headers={"content-type": "application/json"}, retry=True
131+
)
132+
133+
result = _metadata.get(request, PATH)
134+
135+
request.assert_called_with(
136+
method="GET",
137+
url=_metadata._METADATA_ROOT + PATH,
138+
headers=_metadata._METADATA_HEADERS,
139+
)
140+
assert request.call_count == 2
141+
assert result[key] == value
142+
143+
108144
def test_get_success_text():
109145
data = "foobar"
110146
request = make_request(data, headers={"content-type": "text/plain"})
@@ -154,6 +190,23 @@ def test_get_failure():
154190
)
155191

156192

193+
def test_get_failure_connection_failed():
194+
request = make_request("")
195+
request.side_effect = exceptions.TransportError()
196+
197+
with pytest.raises(exceptions.TransportError) as excinfo:
198+
_metadata.get(request, PATH)
199+
200+
assert excinfo.match(r"Compute Engine Metadata server unavailable")
201+
202+
request.assert_called_with(
203+
method="GET",
204+
url=_metadata._METADATA_ROOT + PATH,
205+
headers=_metadata._METADATA_HEADERS,
206+
)
207+
assert request.call_count == 5
208+
209+
157210
def test_get_failure_bad_json():
158211
request = make_request("{", headers={"content-type": "application/json"})
159212

0 commit comments

Comments
 (0)