Browse Source

Avoid request loops between mixmatch proxies

Closes-Bug:#1763549

Change-Id: I9ad9a2363024ce722c1cb2b1bac27be755fc6888
Lohith 1 year ago
parent
commit
902c033af8

+ 20
- 1
mixmatch/proxy.py View File

@@ -108,6 +108,15 @@ class RequestHandler(object):
108 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 120
         for extension in self.extensions:
112 121
             extension.handle_request(self.details)
113 122
 
@@ -301,7 +310,7 @@ class RequestHandler(object):
301 310
         headers = dict()
302 311
         headers['ACCEPT'] = user_headers.get('ACCEPT', '')
303 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 314
         for key, value in user_headers.items():
306 315
             if ((key.startswith('X-') and not is_token_header_key(key)) or
307 316
                     key in accepted_headers):
@@ -320,6 +329,16 @@ class RequestHandler(object):
320 329
             args.pop('marker', None)
321 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 342
     @utils.CachedProperty
324 343
     def chunked(self):
325 344
         encoding = self.details.headers.get('TRANSFER-ENCODING', '')

+ 36
- 0
mixmatch/tests/unit/test_images.py View File

@@ -183,6 +183,42 @@ class TestImages(base.BaseTest):
183 183
         self.assertEqual(response.get_data(as_text=True),
184 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 222
     def test_get_image_search_nexists(self):
187 223
         self.config_fixture.load_raw_values(search_by_broadcast=True)
188 224
         image_id = uuid.uuid4().hex

+ 4
- 2
mixmatch/tests/unit/test_request_details.py View File

@@ -22,10 +22,12 @@ class TestRequestDetails(testcase.TestCase):
22 22
     def test_capitalized_headers(self):
23 23
         normal_headers = {"Mm-Service-Provider": "default",
24 24
                           "X-Auth-Token": "tok",
25
-                          "Transfer-Encoding": "chunked"}
25
+                          "Transfer-Encoding": "chunked",
26
+                          "mM-Proxy-List": 'default'}
26 27
         with proxy.app.test_request_context():
27 28
             rd = proxy.RequestDetails("GET", "image/v2/images", normal_headers)
28 29
         expected = {"MM-SERVICE-PROVIDER": "default",
29 30
                     "X-AUTH-TOKEN": "tok",
30
-                    "TRANSFER-ENCODING": "chunked"}
31
+                    "TRANSFER-ENCODING": "chunked",
32
+                    "MM-PROXY-LIST": 'default'}
31 33
         self.assertEqual(expected, rd.headers)

+ 32
- 2
mixmatch/tests/unit/test_request_handler.py View File

@@ -44,7 +44,8 @@ class TestRequestHandler(BaseTest):
44 44
             'XAUTH-TOKEN': 'x-auth-token',
45 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 50
         expected_headers = {
50 51
             'X-TRA CHEESE': 'extra cheese',
@@ -52,7 +53,8 @@ class TestRequestHandler(BaseTest):
52 53
             'X-MEN': 'X MEN',
53 54
             'ACCEPT': '',
54 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 59
         headers = proxy.RequestHandler._prepare_headers(user_headers)
58 60
         self.assertEqual(expected_headers, headers)
@@ -70,6 +72,34 @@ class TestRequestHandler(BaseTest):
70 72
         self.assertTrue('OPENSTACK-API-VERSION' in headers.keys() and
71 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 103
     def test_strip_tokens_from_logs(self):
74 104
         token = uuid.uuid4()
75 105
         headers = {

+ 34
- 0
mixmatch/tests/unit/test_volumes.py View File

@@ -212,6 +212,40 @@ class TestVolumesV2(base.BaseTest):
212 212
         self.assertEqual(response.get_data(as_text=True),
213 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 249
     def test_get_volume_search_remote(self):
216 250
         self.config_fixture.load_raw_values(search_by_broadcast=True)
217 251
 

Loading…
Cancel
Save