summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZuul <zuul@review.openstack.org>2018-05-11 15:26:14 +0000
committerGerrit Code Review <review@openstack.org>2018-05-11 15:26:14 +0000
commit15612af71ae81733126e8e4aeed13c27ff6509db (patch)
tree78bb5e31b2de71885532f9cad823f749273a8e15
parentd53b471264572ae648ee74b477ef7e5a23a17585 (diff)
parent902c033af80102efc8b0f4906bf85046491a3f69 (diff)
Merge "Avoid request loops between mixmatch proxies"
-rw-r--r--mixmatch/proxy.py21
-rw-r--r--mixmatch/tests/unit/test_images.py36
-rw-r--r--mixmatch/tests/unit/test_request_details.py6
-rw-r--r--mixmatch/tests/unit/test_request_handler.py34
-rw-r--r--mixmatch/tests/unit/test_volumes.py34
5 files changed, 126 insertions, 5 deletions
diff --git a/mixmatch/proxy.py b/mixmatch/proxy.py
index e1e04c1..c8a9e51 100644
--- a/mixmatch/proxy.py
+++ b/mixmatch/proxy.py
@@ -108,6 +108,15 @@ class RequestHandler(object):
108 CONF.service_providers 108 CONF.service_providers
109 ) 109 )
110 110
111 if 'MM-PROXY-LIST' in self.details.headers:
112 proxy_csv = self.details.headers.get('MM-PROXY-LIST', None)
113 if proxy_csv:
114 proxy_list = proxy_csv.split(',')
115 self.enabled_sps = filter(
116 lambda sp: (sp not in proxy_list), self.enabled_sps)
117
118 self.append_proxy(self.details.headers)
119
111 for extension in self.extensions: 120 for extension in self.extensions:
112 extension.handle_request(self.details) 121 extension.handle_request(self.details)
113 122
@@ -301,7 +310,7 @@ class RequestHandler(object):
301 headers = dict() 310 headers = dict()
302 headers['ACCEPT'] = user_headers.get('ACCEPT', '') 311 headers['ACCEPT'] = user_headers.get('ACCEPT', '')
303 headers['CONTENT-TYPE'] = user_headers.get('CONTENT-TYPE', '') 312 headers['CONTENT-TYPE'] = user_headers.get('CONTENT-TYPE', '')
304 accepted_headers = ['OPENSTACK-API-VERSION'] 313 accepted_headers = ['OPENSTACK-API-VERSION', 'MM-PROXY-LIST']
305 for key, value in user_headers.items(): 314 for key, value in user_headers.items():
306 if ((key.startswith('X-') and not is_token_header_key(key)) or 315 if ((key.startswith('X-') and not is_token_header_key(key)) or
307 key in accepted_headers): 316 key in accepted_headers):
@@ -320,6 +329,16 @@ class RequestHandler(object):
320 args.pop('marker', None) 329 args.pop('marker', None)
321 return args 330 return args
322 331
332 @staticmethod
333 def append_proxy(headers):
334 proxy_list = headers.get('MM-PROXY-LIST', None)
335 default_sp_name = service_providers.get(CONF, 'default').sp_name
336 if proxy_list:
337 proxy_list = proxy_list + ',' + default_sp_name
338 else:
339 proxy_list = default_sp_name
340 headers['MM-PROXY-LIST'] = proxy_list
341
323 @utils.CachedProperty 342 @utils.CachedProperty
324 def chunked(self): 343 def chunked(self):
325 encoding = self.details.headers.get('TRANSFER-ENCODING', '') 344 encoding = self.details.headers.get('TRANSFER-ENCODING', '')
diff --git a/mixmatch/tests/unit/test_images.py b/mixmatch/tests/unit/test_images.py
index e2f1ed7..b95d61b 100644
--- a/mixmatch/tests/unit/test_images.py
+++ b/mixmatch/tests/unit/test_images.py
@@ -183,6 +183,42 @@ class TestImages(base.BaseTest):
183 self.assertEqual(response.get_data(as_text=True), 183 self.assertEqual(response.get_data(as_text=True),
184 image_data) 184 image_data)
185 185
186 def test_get_image_skip_proxy(self):
187 self.config_fixture.load_raw_values(search_by_broadcast=True)
188 image_id = uuid.uuid4().hex
189 image_data = uuid.uuid4().hex
190
191 self.requests_fixture.get(
192 self._construct_url(image_id=image_id, sp='default'),
193 status_code=404,
194 request_headers=self.auth.get_headers(),
195 headers={'CONTENT-TYPE': 'application/json'}
196 )
197 self.requests_fixture.get(
198 self._construct_url(image_id=image_id, sp='remote1'),
199 text=image_data,
200 status_code=200,
201 request_headers=self.remote_auth.get_headers(),
202 headers={'CONTENT-TYPE': 'application/json'}
203 )
204 response = self.app.get(
205 self._construct_url(image_id),
206 headers=self.auth.get_headers()
207 )
208 self.assertEqual(response.status_code, 200)
209 self.assertEqual(response.get_data(as_text=True),
210 image_data)
211
212 # Add 'remote1' to MM-PROXY-LIST
213 # request should not go to remote1 and we should get 404 as the
214 # status_code (from 'default')
215 request_header = self.auth.get_headers()
216 request_header['MM-PROXY-LIST'] = 'remote1'
217 response = self.app.get(
218 self._construct_url(image_id),
219 headers=request_header)
220 self.assertEqual(response.status_code, 404)
221
186 def test_get_image_search_nexists(self): 222 def test_get_image_search_nexists(self):
187 self.config_fixture.load_raw_values(search_by_broadcast=True) 223 self.config_fixture.load_raw_values(search_by_broadcast=True)
188 image_id = uuid.uuid4().hex 224 image_id = uuid.uuid4().hex
diff --git a/mixmatch/tests/unit/test_request_details.py b/mixmatch/tests/unit/test_request_details.py
index 30c1341..a0b9380 100644
--- a/mixmatch/tests/unit/test_request_details.py
+++ b/mixmatch/tests/unit/test_request_details.py
@@ -22,10 +22,12 @@ class TestRequestDetails(testcase.TestCase):
22 def test_capitalized_headers(self): 22 def test_capitalized_headers(self):
23 normal_headers = {"Mm-Service-Provider": "default", 23 normal_headers = {"Mm-Service-Provider": "default",
24 "X-Auth-Token": "tok", 24 "X-Auth-Token": "tok",
25 "Transfer-Encoding": "chunked"} 25 "Transfer-Encoding": "chunked",
26 "mM-Proxy-List": 'default'}
26 with proxy.app.test_request_context(): 27 with proxy.app.test_request_context():
27 rd = proxy.RequestDetails("GET", "image/v2/images", normal_headers) 28 rd = proxy.RequestDetails("GET", "image/v2/images", normal_headers)
28 expected = {"MM-SERVICE-PROVIDER": "default", 29 expected = {"MM-SERVICE-PROVIDER": "default",
29 "X-AUTH-TOKEN": "tok", 30 "X-AUTH-TOKEN": "tok",
30 "TRANSFER-ENCODING": "chunked"} 31 "TRANSFER-ENCODING": "chunked",
32 "MM-PROXY-LIST": 'default'}
31 self.assertEqual(expected, rd.headers) 33 self.assertEqual(expected, rd.headers)
diff --git a/mixmatch/tests/unit/test_request_handler.py b/mixmatch/tests/unit/test_request_handler.py
index 48ce23d..7cd298d 100644
--- a/mixmatch/tests/unit/test_request_handler.py
+++ b/mixmatch/tests/unit/test_request_handler.py
@@ -44,7 +44,8 @@ class TestRequestHandler(BaseTest):
44 'XAUTH-TOKEN': 'x-auth-token', 44 'XAUTH-TOKEN': 'x-auth-token',
45 'START-X': 'startx', 45 'START-X': 'startx',
46 46
47 'OPENSTACK-API-VERSION': 'volume 3.0' 47 'OPENSTACK-API-VERSION': 'volume 3.0',
48 'MM-PROXY-LIST': 'sp1'
48 } 49 }
49 expected_headers = { 50 expected_headers = {
50 'X-TRA CHEESE': 'extra cheese', 51 'X-TRA CHEESE': 'extra cheese',
@@ -52,7 +53,8 @@ class TestRequestHandler(BaseTest):
52 'X-MEN': 'X MEN', 53 'X-MEN': 'X MEN',
53 'ACCEPT': '', 54 'ACCEPT': '',
54 'CONTENT-TYPE': '', 55 'CONTENT-TYPE': '',
55 'OPENSTACK-API-VERSION': 'volume 3.0' 56 'OPENSTACK-API-VERSION': 'volume 3.0',
57 'MM-PROXY-LIST': 'sp1'
56 } 58 }
57 headers = proxy.RequestHandler._prepare_headers(user_headers) 59 headers = proxy.RequestHandler._prepare_headers(user_headers)
58 self.assertEqual(expected_headers, headers) 60 self.assertEqual(expected_headers, headers)
@@ -70,6 +72,34 @@ class TestRequestHandler(BaseTest):
70 self.assertTrue('OPENSTACK-API-VERSION' in headers.keys() and 72 self.assertTrue('OPENSTACK-API-VERSION' in headers.keys() and
71 'Openstack-Api-Version' not in headers.keys()) 73 'Openstack-Api-Version' not in headers.keys())
72 74
75 def test_prepare_headers_allow_proxy_list(self):
76 user_headers = {
77 'X-Auth-Token': 'AUTH TOKEN',
78 'X-Service-Token': 'SERVICE TOKEN',
79 'Openstack-Api-Version': 'volume 3.0',
80 'MM-PROXY-LIST': 'sp1'
81 }
82 headers = proxy.RequestHandler._prepare_headers(user_headers)
83 self.assertTrue('MM-PROXY-LIST' in headers.keys())
84 headers = proxy.RequestHandler._prepare_headers(user_headers, True)
85 self.assertTrue('MM-PROXY-LIST' in headers.keys())
86
87 def test_append_proxy_to_list(self):
88 user_headers = {
89 'X-Auth-Token': 'AUTH TOKEN',
90 'X-Service-Token': 'SERVICE TOKEN',
91 'Openstack-Api-Version': 'volume 3.0',
92 'MM-PROXY-LIST': 'sp1'
93 }
94 expected = {
95 'X-Auth-Token': 'AUTH TOKEN',
96 'X-Service-Token': 'SERVICE TOKEN',
97 'Openstack-Api-Version': 'volume 3.0',
98 'MM-PROXY-LIST': 'sp1,default'
99 }
100 proxy.RequestHandler.append_proxy(user_headers)
101 self.assertEqual(expected, user_headers)
102
73 def test_strip_tokens_from_logs(self): 103 def test_strip_tokens_from_logs(self):
74 token = uuid.uuid4() 104 token = uuid.uuid4()
75 headers = { 105 headers = {
diff --git a/mixmatch/tests/unit/test_volumes.py b/mixmatch/tests/unit/test_volumes.py
index b5e2a50..4fa583a 100644
--- a/mixmatch/tests/unit/test_volumes.py
+++ b/mixmatch/tests/unit/test_volumes.py
@@ -212,6 +212,40 @@ class TestVolumesV2(base.BaseTest):
212 self.assertEqual(response.get_data(as_text=True), 212 self.assertEqual(response.get_data(as_text=True),
213 volume_id) 213 volume_id)
214 214
215 def test_get_volume_skip_proxy(self):
216 self.config_fixture.load_raw_values(search_by_broadcast=True)
217 volume_id = uuid.uuid4().hex
218
219 self.requests_fixture.get(
220 self._construct_url(self.auth, volume_id, sp='default'),
221 status_code=404,
222 request_headers=self.auth.get_headers(),
223 headers={'CONTENT-TYPE': 'application/json'})
224
225 self.requests_fixture.get(
226 self._construct_url(self.remote_auth, volume_id, sp='remote1'),
227 text=volume_id,
228 status_code=200,
229 request_headers=self.remote_auth.get_headers(),
230 headers={'CONTENT-TYPE': 'application/json'})
231
232 response = self.app.get(
233 self._construct_url(self.auth, volume_id),
234 headers=self.auth.get_headers())
235 self.assertEqual(response.status_code, 200)
236 self.assertEqual(response.get_data(as_text=True),
237 volume_id)
238
239 # Add 'remote1' to MM-PROXY-LIST
240 # request should not go to 'remote1' and we should get 404 as the
241 # status_code (from 'default')
242 request_header = self.auth.get_headers()
243 request_header['MM-PROXY-LIST'] = 'remote1'
244 response = self.app.get(
245 self._construct_url(self.auth, volume_id),
246 headers=request_header)
247 self.assertEqual(response.status_code, 404)
248
215 def test_get_volume_search_remote(self): 249 def test_get_volume_search_remote(self):
216 self.config_fixture.load_raw_values(search_by_broadcast=True) 250 self.config_fixture.load_raw_values(search_by_broadcast=True)
217 251