Skip to content

Commit 5f053b6

Browse files
committed
Merge pull request googleapis#101 from craigcitro/timeout
Add a timeout for GCE detection.
2 parents 289dfa8 + 9722b32 commit 5f053b6

File tree

3 files changed

+28
-36
lines changed

3 files changed

+28
-36
lines changed

oauth2client/client.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import json
2727
import logging
2828
import os
29+
import socket
2930
import sys
3031
import time
3132
import six
@@ -930,12 +931,22 @@ def _detect_gce_environment(urlopen=None):
930931
Compute Engine.
931932
"""
932933
urlopen = urlopen or urllib.request.urlopen
933-
934+
# Note: the explicit `timeout` below is a workaround. The underlying
935+
# issue is that resolving an unknown host on some networks will take
936+
# 20-30 seconds; making this timeout short fixes the issue, but
937+
# could lead to false negatives in the event that we are on GCE, but
938+
# the metadata resolution was particularly slow. The latter case is
939+
# "unlikely".
934940
try:
935-
response = urlopen('http://metadata.google.internal')
941+
response = urlopen('http://metadata.google.internal/', timeout=1)
936942
return any('Metadata-Flavor: Google' in header
937943
for header in response.info().headers)
938-
except urllib.error.URLError:
944+
except socket.timeout:
945+
logger.info('Timeout attempting to reach GCE metadata service.')
946+
return False
947+
except urllib.error.URLError as e:
948+
if isinstance(getattr(e, 'reason', None), socket.timeout):
949+
logger.info('Timeout attempting to reach GCE metadata service.')
939950
return False
940951

941952

tests/test_oauth2client.py

Lines changed: 12 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,11 @@
2525
import base64
2626
import datetime
2727
import json
28-
try:
29-
from mox3 import mox
30-
except ImportError:
31-
import mox
3228
import os
3329
import time
3430
import unittest
31+
32+
import mock
3533
import six
3634
from six.moves import urllib
3735

@@ -208,37 +206,19 @@ def test_get_environment_gae_local(self):
208206

209207
def test_get_environment_gce_production(self):
210208
os.environ['SERVER_SOFTWARE'] = ''
211-
mockResponse = MockResponse(['Metadata-Flavor: Google\r\n'])
212-
213-
m = mox.Mox()
214-
215-
urllib2_urlopen = m.CreateMock(object)
216-
urllib2_urlopen.__call__(('http://metadata.google.internal'
217-
)).AndReturn(mockResponse)
218-
219-
m.ReplayAll()
220-
221-
self.assertEqual('GCE_PRODUCTION', _get_environment(urllib2_urlopen))
222-
223-
m.UnsetStubs()
224-
m.VerifyAll()
209+
with mock.patch.object(urllib.request, 'urlopen') as urlopen:
210+
urlopen.return_value = MockResponse(['Metadata-Flavor: Google\r\n'])
211+
self.assertEqual('GCE_PRODUCTION', _get_environment())
212+
urlopen.assert_called_once_with(
213+
'http://metadata.google.internal/', timeout=1)
225214

226215
def test_get_environment_unknown(self):
227216
os.environ['SERVER_SOFTWARE'] = ''
228-
mockResponse = MockResponse([])
229-
230-
m = mox.Mox()
231-
232-
urllib2_urlopen = m.CreateMock(object)
233-
urllib2_urlopen.__call__(('http://metadata.google.internal'
234-
)).AndReturn(mockResponse)
235-
236-
m.ReplayAll()
237-
238-
self.assertEqual(DEFAULT_ENV_NAME, _get_environment(urllib2_urlopen))
239-
240-
m.UnsetStubs()
241-
m.VerifyAll()
217+
with mock.patch.object(urllib.request, 'urlopen') as urlopen:
218+
urlopen.return_value = MockResponse([])
219+
self.assertEqual(DEFAULT_ENV_NAME, _get_environment())
220+
urlopen.assert_called_once_with(
221+
'http://metadata.google.internal/', timeout=1)
242222

243223
def test_get_environment_variable_file(self):
244224
environment_variable_file = datafile(

tox.ini

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,15 @@ envlist = py26,py27,py33,py34,pypy,cover
44
[testenv]
55
basedeps = keyring
66
mox3
7+
mock
78
pycrypto==2.6
89
django>=1.5,<1.6
910
webtest
1011
nose
1112
deps = {[testenv]basedeps}
1213
pyopenssl==0.14
1314
setenv = PYTHONPATH=../google_appengine
14-
commands = nosetests --ignore-files=test_appengine\.py
15+
commands = nosetests --ignore-files=test_appengine\.py {posargs}
1516

1617
# whitelist
1718
branches:

0 commit comments

Comments
 (0)