Add a timeout for GCE detection.

This is a temporary workaround for #93, though may end up being the final fix.

I did some test cleanup while I was here, switching to `mock`.
This commit is contained in:
Craig Citro
2014-12-19 11:34:07 -08:00
parent 289dfa865f
commit 9722b3206f
3 changed files with 28 additions and 36 deletions

View File

@@ -26,6 +26,7 @@ import datetime
import json import json
import logging import logging
import os import os
import socket
import sys import sys
import time import time
import six import six
@@ -930,12 +931,22 @@ def _detect_gce_environment(urlopen=None):
Compute Engine. Compute Engine.
""" """
urlopen = urlopen or urllib.request.urlopen urlopen = urlopen or urllib.request.urlopen
# Note: the explicit `timeout` below is a workaround. The underlying
# issue is that resolving an unknown host on some networks will take
# 20-30 seconds; making this timeout short fixes the issue, but
# could lead to false negatives in the event that we are on GCE, but
# the metadata resolution was particularly slow. The latter case is
# "unlikely".
try: try:
response = urlopen('http://metadata.google.internal') response = urlopen('http://metadata.google.internal/', timeout=1)
return any('Metadata-Flavor: Google' in header return any('Metadata-Flavor: Google' in header
for header in response.info().headers) for header in response.info().headers)
except urllib.error.URLError: except socket.timeout:
logger.info('Timeout attempting to reach GCE metadata service.')
return False
except urllib.error.URLError as e:
if isinstance(getattr(e, 'reason', None), socket.timeout):
logger.info('Timeout attempting to reach GCE metadata service.')
return False return False

View File

@@ -25,13 +25,11 @@ __author__ = 'jcgregorio@google.com (Joe Gregorio)'
import base64 import base64
import datetime import datetime
import json import json
try:
from mox3 import mox
except ImportError:
import mox
import os import os
import time import time
import unittest import unittest
import mock
import six import six
from six.moves import urllib from six.moves import urllib
@@ -208,37 +206,19 @@ class GoogleCredentialsTests(unittest.TestCase):
def test_get_environment_gce_production(self): def test_get_environment_gce_production(self):
os.environ['SERVER_SOFTWARE'] = '' os.environ['SERVER_SOFTWARE'] = ''
mockResponse = MockResponse(['Metadata-Flavor: Google\r\n']) with mock.patch.object(urllib.request, 'urlopen') as urlopen:
urlopen.return_value = MockResponse(['Metadata-Flavor: Google\r\n'])
m = mox.Mox() self.assertEqual('GCE_PRODUCTION', _get_environment())
urlopen.assert_called_once_with(
urllib2_urlopen = m.CreateMock(object) 'http://metadata.google.internal/', timeout=1)
urllib2_urlopen.__call__(('http://metadata.google.internal'
)).AndReturn(mockResponse)
m.ReplayAll()
self.assertEqual('GCE_PRODUCTION', _get_environment(urllib2_urlopen))
m.UnsetStubs()
m.VerifyAll()
def test_get_environment_unknown(self): def test_get_environment_unknown(self):
os.environ['SERVER_SOFTWARE'] = '' os.environ['SERVER_SOFTWARE'] = ''
mockResponse = MockResponse([]) with mock.patch.object(urllib.request, 'urlopen') as urlopen:
urlopen.return_value = MockResponse([])
m = mox.Mox() self.assertEqual(DEFAULT_ENV_NAME, _get_environment())
urlopen.assert_called_once_with(
urllib2_urlopen = m.CreateMock(object) 'http://metadata.google.internal/', timeout=1)
urllib2_urlopen.__call__(('http://metadata.google.internal'
)).AndReturn(mockResponse)
m.ReplayAll()
self.assertEqual(DEFAULT_ENV_NAME, _get_environment(urllib2_urlopen))
m.UnsetStubs()
m.VerifyAll()
def test_get_environment_variable_file(self): def test_get_environment_variable_file(self):
environment_variable_file = datafile( environment_variable_file = datafile(

View File

@@ -4,6 +4,7 @@ envlist = py26,py27,py33,py34,pypy,cover
[testenv] [testenv]
basedeps = keyring basedeps = keyring
mox3 mox3
mock
pycrypto==2.6 pycrypto==2.6
django>=1.5,<1.6 django>=1.5,<1.6
webtest webtest
@@ -11,7 +12,7 @@ basedeps = keyring
deps = {[testenv]basedeps} deps = {[testenv]basedeps}
pyopenssl==0.14 pyopenssl==0.14
setenv = PYTHONPATH=../google_appengine setenv = PYTHONPATH=../google_appengine
commands = nosetests --ignore-files=test_appengine\.py commands = nosetests --ignore-files=test_appengine\.py {posargs}
# whitelist # whitelist
branches: branches: