Merge "Implement volume list availability zone filter"

This commit is contained in:
Jenkins 2016-05-05 02:29:36 +00:00 committed by Gerrit Code Review
commit 0649d63be4
3 changed files with 124 additions and 8 deletions
tricircle
cinder_apigw/controllers
common
tests/functional/cinder_apigw/controllers

@ -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'):