Skip to content

Commit d858ff0

Browse files
committed
Merge pull request #577 from dhermes/fix-575
Using httplib instead of httplib2 to get GCE metadata.
2 parents bf93d46 + 8febd04 commit d858ff0

File tree

2 files changed

+75
-63
lines changed

2 files changed

+75
-63
lines changed

gcloud/datastore/_implicit_environ.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
imply the current dataset ID and connection from the enviroment.
1919
"""
2020

21-
import httplib2
21+
import httplib
2222
import socket
2323

2424
try:
@@ -64,17 +64,17 @@ def compute_engine_id():
6464
:returns: Compute Engine project ID if the metadata service is available,
6565
else ``None``.
6666
"""
67-
http = httplib2.Http(timeout=0.1)
68-
uri = 'http://169.254.169.254/computeMetadata/v1/project/project-id'
67+
host = '169.254.169.254'
68+
uri_path = '/computeMetadata/v1/project/project-id'
6969
headers = {'Metadata-Flavor': 'Google'}
70+
connection = httplib.HTTPConnection(host, timeout=0.1)
7071

71-
response = content = None
7272
try:
73-
response, content = http.request(uri, method='GET', headers=headers)
74-
except socket.timeout:
73+
connection.request('GET', uri_path, headers=headers)
74+
response = connection.getresponse()
75+
if response.status == 200:
76+
return response.read()
77+
except socket.error: # socket.timeout or socket.error(64, 'Host is down')
7578
pass
76-
77-
if response is None or response['status'] != '200':
78-
return None
79-
80-
return content
79+
finally:
80+
connection.close()

gcloud/datastore/test___init__.py

Lines changed: 64 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,19 @@ def _callFUT(self, dataset_id=None):
3030
from gcloud.datastore import set_default_dataset_id
3131
return set_default_dataset_id(dataset_id=dataset_id)
3232

33-
def _monkey(self, implicit_dataset_id):
33+
def _monkey(self, implicit_dataset_id, httplib=None, app_identity=None):
34+
from contextlib import nested
3435
import os
35-
from gcloud.datastore import _DATASET_ENV_VAR_NAME
36+
3637
from gcloud._testing import _Monkey
38+
from gcloud.datastore import _DATASET_ENV_VAR_NAME
39+
from gcloud.datastore import _implicit_environ
40+
3741
environ = {_DATASET_ENV_VAR_NAME: implicit_dataset_id}
38-
return _Monkey(os, getenv=environ.get)
42+
httplib = httplib or _Httplib(None, status=404)
43+
return nested(_Monkey(os, getenv=environ.get),
44+
_Monkey(_implicit_environ, httplib=httplib,
45+
app_identity=app_identity))
3946

4047
def test_no_env_var_set(self):
4148
from gcloud.datastore import _implicit_environ
@@ -79,102 +86,92 @@ def test_set_explicit_None_w_env_var_set(self):
7986
self.assertEqual(_implicit_environ.DATASET_ID, IMPLICIT_DATASET_ID)
8087

8188
def test_set_implicit_from_appengine(self):
82-
from gcloud._testing import _Monkey
8389
from gcloud.datastore import _implicit_environ
8490

8591
APP_ENGINE_ID = 'GAE'
8692
APP_IDENTITY = _AppIdentity(APP_ENGINE_ID)
8793

88-
with self._monkey(None):
89-
with _Monkey(_implicit_environ, app_identity=APP_IDENTITY):
90-
self._callFUT()
94+
with self._monkey(None, app_identity=APP_IDENTITY):
95+
self._callFUT()
9196

9297
self.assertEqual(_implicit_environ.DATASET_ID, APP_ENGINE_ID)
9398

9499
def test_set_implicit_both_env_and_appengine(self):
95-
from gcloud._testing import _Monkey
96100
from gcloud.datastore import _implicit_environ
97101

98102
IMPLICIT_DATASET_ID = 'IMPLICIT'
99103
APP_IDENTITY = _AppIdentity('GAE')
100104

101-
with self._monkey(IMPLICIT_DATASET_ID):
102-
with _Monkey(_implicit_environ, app_identity=APP_IDENTITY):
103-
self._callFUT()
105+
with self._monkey(IMPLICIT_DATASET_ID, app_identity=APP_IDENTITY):
106+
self._callFUT()
104107

105108
self.assertEqual(_implicit_environ.DATASET_ID, IMPLICIT_DATASET_ID)
106109

107110
def _implicit_compute_engine_helper(self, status):
108-
from gcloud._testing import _Monkey
109111
from gcloud.datastore import _implicit_environ
110112

111113
COMPUTE_ENGINE_ID = 'GCE'
112-
HTTPLIB2 = _Httplib2(COMPUTE_ENGINE_ID, status=status)
113-
if status == '200':
114+
HTTPLIB = _Httplib(COMPUTE_ENGINE_ID, status=status)
115+
if status == 200:
114116
EXPECTED_ID = COMPUTE_ENGINE_ID
115117
else:
116118
EXPECTED_ID = None
117119

118-
with self._monkey(None):
119-
with _Monkey(_implicit_environ, httplib2=HTTPLIB2):
120-
self._callFUT()
120+
with self._monkey(None, httplib=HTTPLIB):
121+
self._callFUT()
121122

122123
self.assertEqual(_implicit_environ.DATASET_ID, EXPECTED_ID)
123-
self.assertEqual(len(HTTPLIB2._http_instances), 1)
124+
self.assertEqual(len(HTTPLIB._http_connections), 1)
124125

125-
(timeout, http_instance), = HTTPLIB2._http_instances
126+
(host, timeout, http_connection), = HTTPLIB._http_connections
127+
self.assertEqual(host, '169.254.169.254')
126128
self.assertEqual(timeout, 0.1)
127129
self.assertEqual(
128-
http_instance._called_uris,
129-
['http://169.254.169.254/computeMetadata/v1/project/project-id'])
130+
http_connection._called_args,
131+
[('GET', '/computeMetadata/v1/project/project-id')])
130132
expected_kwargs = {
131-
'method': 'GET',
132133
'headers': {
133134
'Metadata-Flavor': 'Google',
134135
},
135136
}
136-
self.assertEqual(http_instance._called_kwargs, [expected_kwargs])
137+
self.assertEqual(http_connection._called_kwargs, [expected_kwargs])
138+
self.assertEqual(http_connection._close_count, 1)
137139

138140
def test_set_implicit_from_compute_engine(self):
139-
self._implicit_compute_engine_helper('200')
141+
self._implicit_compute_engine_helper(200)
140142

141143
def test_set_implicit_from_compute_engine_bad_status(self):
142-
self._implicit_compute_engine_helper('404')
144+
self._implicit_compute_engine_helper(404)
143145

144146
def test_set_implicit_from_compute_engine_raise_timeout(self):
145147
self._implicit_compute_engine_helper('RAISE')
146148

147149
def test_set_implicit_both_appengine_and_compute(self):
148-
from gcloud._testing import _Monkey
149150
from gcloud.datastore import _implicit_environ
150151

151152
APP_ENGINE_ID = 'GAE'
152153
APP_IDENTITY = _AppIdentity(APP_ENGINE_ID)
153-
HTTPLIB2 = _Httplib2('GCE')
154+
HTTPLIB = _Httplib('GCE')
154155

155-
with self._monkey(None):
156-
with _Monkey(_implicit_environ, app_identity=APP_IDENTITY,
157-
httplib2=HTTPLIB2):
158-
self._callFUT()
156+
with self._monkey(None, httplib=HTTPLIB, app_identity=APP_IDENTITY):
157+
self._callFUT()
159158

160159
self.assertEqual(_implicit_environ.DATASET_ID, APP_ENGINE_ID)
161-
self.assertEqual(len(HTTPLIB2._http_instances), 0)
160+
self.assertEqual(len(HTTPLIB._http_connections), 0)
162161

163162
def test_set_implicit_three_env_appengine_and_compute(self):
164-
from gcloud._testing import _Monkey
165163
from gcloud.datastore import _implicit_environ
166164

167165
IMPLICIT_DATASET_ID = 'IMPLICIT'
168166
APP_IDENTITY = _AppIdentity('GAE')
169-
HTTPLIB2 = _Httplib2('GCE')
167+
HTTPLIB = _Httplib('GCE')
170168

171-
with self._monkey(IMPLICIT_DATASET_ID):
172-
with _Monkey(_implicit_environ, app_identity=APP_IDENTITY,
173-
httplib2=HTTPLIB2):
174-
self._callFUT()
169+
with self._monkey(IMPLICIT_DATASET_ID, httplib=HTTPLIB,
170+
app_identity=APP_IDENTITY):
171+
self._callFUT()
175172

176173
self.assertEqual(_implicit_environ.DATASET_ID, IMPLICIT_DATASET_ID)
177-
self.assertEqual(len(HTTPLIB2._http_instances), 0)
174+
self.assertEqual(len(HTTPLIB._http_connections), 0)
178175

179176

180177
class Test_set_default_connection(unittest2.TestCase):
@@ -274,33 +271,48 @@ def get_application_id(self):
274271
return self.app_id
275272

276273

277-
class _Http(object):
274+
class _HTTPResponse(object):
275+
276+
def __init__(self, status, data):
277+
self.status = status
278+
self.data = data
279+
280+
def read(self):
281+
return self.data
282+
283+
284+
class _HTTPConnection(object):
278285

279286
def __init__(self, parent):
280287
self.parent = parent
281-
self._called_uris = []
288+
self._close_count = 0
289+
self._called_args = []
282290
self._called_kwargs = []
283291

284-
def request(self, uri, **kwargs):
285-
import socket
286-
287-
self._called_uris.append(uri)
292+
def request(self, method, uri, **kwargs):
293+
self._called_args.append((method, uri))
288294
self._called_kwargs.append(kwargs)
289295

296+
def getresponse(self):
297+
import socket
298+
290299
if self.parent.status == 'RAISE':
291300
raise socket.timeout('timed out')
292301
else:
293-
return {'status': self.parent.status}, self.parent.project_id
302+
return _HTTPResponse(self.parent.status, self.parent.project_id)
303+
304+
def close(self):
305+
self._close_count += 1
294306

295307

296-
class _Httplib2(object):
308+
class _Httplib(object):
297309

298-
def __init__(self, project_id, status='200'):
310+
def __init__(self, project_id, status=200):
299311
self.project_id = project_id
300312
self.status = status
301-
self._http_instances = []
313+
self._http_connections = []
302314

303-
def Http(self, timeout=None):
304-
result = _Http(self)
305-
self._http_instances.append((timeout, result))
315+
def HTTPConnection(self, host, timeout=None):
316+
result = _HTTPConnection(self)
317+
self._http_connections.append((host, timeout, result))
306318
return result

0 commit comments

Comments
 (0)