Avoid request loops between mixmatch proxies

Closes-Bug:#1763549

Change-Id: I9ad9a2363024ce722c1cb2b1bac27be755fc6888
This commit is contained in:
Lohith 2018-04-12 22:14:56 -04:00
parent 167482401e
commit 902c033af8
5 changed files with 126 additions and 5 deletions

View File

@ -108,6 +108,15 @@ class RequestHandler(object):
CONF.service_providers
)
if 'MM-PROXY-LIST' in self.details.headers:
proxy_csv = self.details.headers.get('MM-PROXY-LIST', None)
if proxy_csv:
proxy_list = proxy_csv.split(',')
self.enabled_sps = filter(
lambda sp: (sp not in proxy_list), self.enabled_sps)
self.append_proxy(self.details.headers)
for extension in self.extensions:
extension.handle_request(self.details)
@ -301,7 +310,7 @@ class RequestHandler(object):
headers = dict()
headers['ACCEPT'] = user_headers.get('ACCEPT', '')
headers['CONTENT-TYPE'] = user_headers.get('CONTENT-TYPE', '')
accepted_headers = ['OPENSTACK-API-VERSION']
accepted_headers = ['OPENSTACK-API-VERSION', 'MM-PROXY-LIST']
for key, value in user_headers.items():
if ((key.startswith('X-') and not is_token_header_key(key)) or
key in accepted_headers):
@ -320,6 +329,16 @@ class RequestHandler(object):
args.pop('marker', None)
return args
@staticmethod
def append_proxy(headers):
proxy_list = headers.get('MM-PROXY-LIST', None)
default_sp_name = service_providers.get(CONF, 'default').sp_name
if proxy_list:
proxy_list = proxy_list + ',' + default_sp_name
else:
proxy_list = default_sp_name
headers['MM-PROXY-LIST'] = proxy_list
@utils.CachedProperty
def chunked(self):
encoding = self.details.headers.get('TRANSFER-ENCODING', '')

View File

@ -183,6 +183,42 @@ class TestImages(base.BaseTest):
self.assertEqual(response.get_data(as_text=True),
image_data)
def test_get_image_skip_proxy(self):
self.config_fixture.load_raw_values(search_by_broadcast=True)
image_id = uuid.uuid4().hex
image_data = uuid.uuid4().hex
self.requests_fixture.get(
self._construct_url(image_id=image_id, sp='default'),
status_code=404,
request_headers=self.auth.get_headers(),
headers={'CONTENT-TYPE': 'application/json'}
)
self.requests_fixture.get(
self._construct_url(image_id=image_id, sp='remote1'),
text=image_data,
status_code=200,
request_headers=self.remote_auth.get_headers(),
headers={'CONTENT-TYPE': 'application/json'}
)
response = self.app.get(
self._construct_url(image_id),
headers=self.auth.get_headers()
)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.get_data(as_text=True),
image_data)
# Add 'remote1' to MM-PROXY-LIST
# request should not go to remote1 and we should get 404 as the
# status_code (from 'default')
request_header = self.auth.get_headers()
request_header['MM-PROXY-LIST'] = 'remote1'
response = self.app.get(
self._construct_url(image_id),
headers=request_header)
self.assertEqual(response.status_code, 404)
def test_get_image_search_nexists(self):
self.config_fixture.load_raw_values(search_by_broadcast=True)
image_id = uuid.uuid4().hex

View File

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

View File

@ -44,7 +44,8 @@ class TestRequestHandler(BaseTest):
'XAUTH-TOKEN': 'x-auth-token',
'START-X': 'startx',
'OPENSTACK-API-VERSION': 'volume 3.0'
'OPENSTACK-API-VERSION': 'volume 3.0',
'MM-PROXY-LIST': 'sp1'
}
expected_headers = {
'X-TRA CHEESE': 'extra cheese',
@ -52,7 +53,8 @@ class TestRequestHandler(BaseTest):
'X-MEN': 'X MEN',
'ACCEPT': '',
'CONTENT-TYPE': '',
'OPENSTACK-API-VERSION': 'volume 3.0'
'OPENSTACK-API-VERSION': 'volume 3.0',
'MM-PROXY-LIST': 'sp1'
}
headers = proxy.RequestHandler._prepare_headers(user_headers)
self.assertEqual(expected_headers, headers)
@ -70,6 +72,34 @@ class TestRequestHandler(BaseTest):
self.assertTrue('OPENSTACK-API-VERSION' in headers.keys() and
'Openstack-Api-Version' not in headers.keys())
def test_prepare_headers_allow_proxy_list(self):
user_headers = {
'X-Auth-Token': 'AUTH TOKEN',
'X-Service-Token': 'SERVICE TOKEN',
'Openstack-Api-Version': 'volume 3.0',
'MM-PROXY-LIST': 'sp1'
}
headers = proxy.RequestHandler._prepare_headers(user_headers)
self.assertTrue('MM-PROXY-LIST' in headers.keys())
headers = proxy.RequestHandler._prepare_headers(user_headers, True)
self.assertTrue('MM-PROXY-LIST' in headers.keys())
def test_append_proxy_to_list(self):
user_headers = {
'X-Auth-Token': 'AUTH TOKEN',
'X-Service-Token': 'SERVICE TOKEN',
'Openstack-Api-Version': 'volume 3.0',
'MM-PROXY-LIST': 'sp1'
}
expected = {
'X-Auth-Token': 'AUTH TOKEN',
'X-Service-Token': 'SERVICE TOKEN',
'Openstack-Api-Version': 'volume 3.0',
'MM-PROXY-LIST': 'sp1,default'
}
proxy.RequestHandler.append_proxy(user_headers)
self.assertEqual(expected, user_headers)
def test_strip_tokens_from_logs(self):
token = uuid.uuid4()
headers = {

View File

@ -212,6 +212,40 @@ class TestVolumesV2(base.BaseTest):
self.assertEqual(response.get_data(as_text=True),
volume_id)
def test_get_volume_skip_proxy(self):
self.config_fixture.load_raw_values(search_by_broadcast=True)
volume_id = uuid.uuid4().hex
self.requests_fixture.get(
self._construct_url(self.auth, volume_id, sp='default'),
status_code=404,
request_headers=self.auth.get_headers(),
headers={'CONTENT-TYPE': 'application/json'})
self.requests_fixture.get(
self._construct_url(self.remote_auth, volume_id, sp='remote1'),
text=volume_id,
status_code=200,
request_headers=self.remote_auth.get_headers(),
headers={'CONTENT-TYPE': 'application/json'})
response = self.app.get(
self._construct_url(self.auth, volume_id),
headers=self.auth.get_headers())
self.assertEqual(response.status_code, 200)
self.assertEqual(response.get_data(as_text=True),
volume_id)
# Add 'remote1' to MM-PROXY-LIST
# request should not go to 'remote1' and we should get 404 as the
# status_code (from 'default')
request_header = self.auth.get_headers()
request_header['MM-PROXY-LIST'] = 'remote1'
response = self.app.get(
self._construct_url(self.auth, volume_id),
headers=request_header)
self.assertEqual(response.status_code, 404)
def test_get_volume_search_remote(self):
self.config_fixture.load_raw_values(search_by_broadcast=True)