Implement volume list availability zone filter
Currently volume list supports most of the filters since it directly passes filter parameters to bottom pods. But availability zone filter can not be implememted like that because we don't require top pod and bottom pod to have availability zones with the same name. Since each bottom pod belongs to an availability zone defined in top pod, instead of passing the availability zone filter to bottom pods, we directly filter bottom pods by the availability zone filter then send list request to these filtered bottom pods. With change in this patch, tempest test test_volumes_list can be passed. Change-Id: I8e448a1262ca370ff3bfa9948fee636240a7fb78
This commit is contained in:
parent
353ebcddb1
commit
fa9db37e64
@ -13,6 +13,8 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import urlparse
|
||||
|
||||
import pecan
|
||||
from pecan import expose
|
||||
from pecan import request
|
||||
@ -220,6 +222,16 @@ class VolumeController(rest.RestController):
|
||||
if pod['pod_name'] == '':
|
||||
continue
|
||||
|
||||
query = urlparse.urlsplit(request.url).query
|
||||
query_filters = urlparse.parse_qsl(query)
|
||||
skip_pod = False
|
||||
for k, v in query_filters:
|
||||
if k == 'availability_zone' and v != pod['az_name']:
|
||||
skip_pod = True
|
||||
break
|
||||
if skip_pod:
|
||||
continue
|
||||
|
||||
s_ctx = hclient.get_pod_service_ctx(
|
||||
context,
|
||||
request.url,
|
||||
|
@ -13,6 +13,7 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import urllib
|
||||
import urlparse
|
||||
|
||||
from requests import Request
|
||||
@ -87,7 +88,17 @@ def get_bottom_url(t_ver, t_url, b_ver, b_endpoint):
|
||||
path = '/' + b_ver + '/' + after_ver
|
||||
if b_ver == '':
|
||||
path = '/' + after_ver
|
||||
query = t_parse.query
|
||||
|
||||
# Remove availability_zone filter since it is handled by VolumeController.
|
||||
# VolumeController will send GET request only to bottom pods whose AZ
|
||||
# is specified in availability_zone filter.
|
||||
query_filters = []
|
||||
for k, v in urlparse.parse_qsl(t_parse.query):
|
||||
if k == 'availability_zone':
|
||||
continue
|
||||
query_filters.append((k, v))
|
||||
query = urllib.urlencode(query_filters)
|
||||
|
||||
fragment = t_parse.fragment
|
||||
|
||||
b_url = urlparse.urlunsplit((scheme,
|
||||
|
@ -14,6 +14,7 @@
|
||||
# under the License.
|
||||
|
||||
from mock import patch
|
||||
import urlparse
|
||||
|
||||
import pecan
|
||||
from pecan.configuration import set_config
|
||||
@ -49,6 +50,7 @@ def fake_volumes_forward_req(ctx, action, b_header, b_url, b_req_body):
|
||||
resp = Response()
|
||||
resp.status_code = 404
|
||||
|
||||
parse = urlparse.urlsplit(b_url)
|
||||
if action == 'POST':
|
||||
b_body = jsonutils.loads(b_req_body)
|
||||
if b_body.get('volume'):
|
||||
@ -56,7 +58,7 @@ def fake_volumes_forward_req(ctx, action, b_header, b_url, b_req_body):
|
||||
vol['id'] = uuidutils.generate_uuid()
|
||||
stored_vol = {
|
||||
'volume': vol,
|
||||
'url': b_url
|
||||
'host': parse.hostname
|
||||
}
|
||||
fake_volumes.append(stored_vol)
|
||||
resp.status_code = 202
|
||||
@ -66,17 +68,16 @@ def fake_volumes_forward_req(ctx, action, b_header, b_url, b_req_body):
|
||||
# resp.json = vol_dict
|
||||
return resp
|
||||
|
||||
pos = b_url.rfind('/volumes')
|
||||
b_path = parse.path
|
||||
pos = b_path.rfind('/volumes')
|
||||
op = ''
|
||||
cmp_url = b_url
|
||||
if pos > 0:
|
||||
op = b_url[pos:]
|
||||
cmp_url = b_url[:pos] + '/volumes'
|
||||
op = b_path[pos:]
|
||||
op = op[len('/volumes'):]
|
||||
|
||||
if action == 'GET':
|
||||
if op == '' or op == '/detail':
|
||||
tenant_id = b_url[:pos]
|
||||
tenant_id = b_path[:pos]
|
||||
pos2 = tenant_id.rfind('/')
|
||||
if pos2 > 0:
|
||||
tenant_id = tenant_id[(pos2 + 1):]
|
||||
@ -84,8 +85,9 @@ def fake_volumes_forward_req(ctx, action, b_header, b_url, b_req_body):
|
||||
resp.status_code = 404
|
||||
return resp
|
||||
ret_vols = []
|
||||
cmp_host = parse.hostname
|
||||
for temp_vol in fake_volumes:
|
||||
if temp_vol['url'] != cmp_url:
|
||||
if temp_vol['host'] != cmp_host:
|
||||
continue
|
||||
|
||||
if temp_vol['volume']['project_id'] == tenant_id:
|
||||
@ -210,6 +212,7 @@ class CinderVolumeFunctionalTest(base.TestCase):
|
||||
cfg.CONF.unregister_opts(app.common_opts)
|
||||
pecan.set_config({}, overwrite=True)
|
||||
core.ModelBase.metadata.drop_all(core.get_engine())
|
||||
del fake_volumes[:]
|
||||
|
||||
|
||||
class TestVolumeController(CinderVolumeFunctionalTest):
|
||||
@ -396,6 +399,96 @@ class TestVolumeController(CinderVolumeFunctionalTest):
|
||||
vols = json_body.get('volumes')
|
||||
self.assertEqual(0, len(vols))
|
||||
|
||||
@patch.object(hclient, 'forward_req',
|
||||
new=fake_volumes_forward_req)
|
||||
def test_get_all(self):
|
||||
update_dict = {'pod_az_name': 'fake_pod_az2'}
|
||||
# update pod2 to set pod_az_name
|
||||
db_api.update_pod(self.context, 'fake_pod_id2', update_dict)
|
||||
|
||||
volumes = [
|
||||
# normal volume with correct parameter
|
||||
{
|
||||
"volume":
|
||||
{
|
||||
"name": 'vol_1',
|
||||
"availability_zone": FAKE_AZ,
|
||||
"source_volid": '',
|
||||
"consistencygroup_id": '',
|
||||
"snapshot_id": '',
|
||||
"source_replica": '',
|
||||
"size": 10,
|
||||
"user_id": '',
|
||||
"imageRef": '',
|
||||
"attach_status": "detached",
|
||||
"volume_type": '',
|
||||
"project_id": 'my_tenant_id',
|
||||
"metadata": {}
|
||||
},
|
||||
"expected_error": 202
|
||||
},
|
||||
|
||||
# same tenant, multiple volumes
|
||||
{
|
||||
"volume":
|
||||
{
|
||||
"name": 'vol_2',
|
||||
"availability_zone": FAKE_AZ,
|
||||
"source_volid": '',
|
||||
"consistencygroup_id": '',
|
||||
"snapshot_id": '',
|
||||
"source_replica": '',
|
||||
"size": 20,
|
||||
"user_id": '',
|
||||
"imageRef": '',
|
||||
"attach_status": "detached",
|
||||
"volume_type": '',
|
||||
"project_id": 'my_tenant_id',
|
||||
"metadata": {}
|
||||
},
|
||||
"expected_error": 202
|
||||
},
|
||||
|
||||
# same tenant, different az
|
||||
{
|
||||
"volume":
|
||||
{
|
||||
"name": 'vol_3',
|
||||
"availability_zone": FAKE_AZ + '2',
|
||||
"source_volid": '',
|
||||
"consistencygroup_id": '',
|
||||
"snapshot_id": '',
|
||||
"source_replica": '',
|
||||
"size": 20,
|
||||
"user_id": '',
|
||||
"imageRef": '',
|
||||
"attach_status": "detached",
|
||||
"volume_type": '',
|
||||
"project_id": 'my_tenant_id',
|
||||
"metadata": {}
|
||||
},
|
||||
"expected_error": 202
|
||||
},
|
||||
]
|
||||
tenant_id = 'my_tenant_id'
|
||||
for volume in volumes:
|
||||
self.app.post_json('/v2/' + tenant_id + '/volumes',
|
||||
dict(volume=volume['volume']),
|
||||
expect_errors=True)
|
||||
query_string = '?availability_zone=' + FAKE_AZ
|
||||
resp = self.app.get('/v2/' + tenant_id + '/volumes' + query_string)
|
||||
self.assertEqual(resp.status_int, 200)
|
||||
json_body = jsonutils.loads(resp.body)
|
||||
ret_vols = json_body.get('volumes')
|
||||
self.assertEqual(len(ret_vols), 2)
|
||||
|
||||
query_string = '?availability_zone=' + FAKE_AZ + '2'
|
||||
resp = self.app.get('/v2/' + tenant_id + '/volumes' + query_string)
|
||||
self.assertEqual(resp.status_int, 200)
|
||||
json_body = jsonutils.loads(resp.body)
|
||||
ret_vols = json_body.get('volumes')
|
||||
self.assertEqual(len(ret_vols), 1)
|
||||
|
||||
def _test_and_check(self, volumes, tenant_id):
|
||||
for test_vol in volumes:
|
||||
if test_vol.get('volume'):
|
||||
|
Loading…
Reference in New Issue
Block a user