Add view builder to QoS specs API extension
Add view builder for qos_specs.create(), index(), show() and associations() to in order to make the response more easier to be consumed by client. This patch also: fixed circular reference error when raising HTTP exception. fixed some typo in debug message and removed unused imports. fix bug: # 1219016 Change-Id: I107888e6b4dac8eb5f1b45a87721a7b5efc45632
This commit is contained in:
@@ -21,13 +21,12 @@ import webob
|
||||
|
||||
from cinder.api import extensions
|
||||
from cinder.api.openstack import wsgi
|
||||
from cinder.api.views import qos_specs as view_qos_specs
|
||||
from cinder.api import xmlutil
|
||||
from cinder import db
|
||||
from cinder import exception
|
||||
from cinder.openstack.common import log as logging
|
||||
from cinder.openstack.common.notifier import api as notifier_api
|
||||
from cinder.volume import qos_specs
|
||||
from cinder.volume import volume_types
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
@@ -66,6 +65,8 @@ def _check_specs(context, specs_id):
|
||||
class QoSSpecsController(wsgi.Controller):
|
||||
"""The volume type extra specs API controller for the OpenStack API."""
|
||||
|
||||
_view_builder_class = view_qos_specs.ViewBuilder
|
||||
|
||||
@staticmethod
|
||||
def _notify_qos_specs_error(context, method, payload):
|
||||
notifier_api.notify(context,
|
||||
@@ -80,7 +81,7 @@ class QoSSpecsController(wsgi.Controller):
|
||||
context = req.environ['cinder.context']
|
||||
authorize(context)
|
||||
specs = qos_specs.get_all_specs(context)
|
||||
return specs
|
||||
return self._view_builder.summary_list(req, specs)
|
||||
|
||||
@wsgi.serializers(xml=QoSSpecsTemplate)
|
||||
def create(self, req, body=None):
|
||||
@@ -97,8 +98,8 @@ class QoSSpecsController(wsgi.Controller):
|
||||
raise webob.exc.HTTPBadRequest(explanation=msg)
|
||||
|
||||
try:
|
||||
specs_ref = qos_specs.create(context, name, specs)
|
||||
qos_specs.get_qos_specs_by_name(context, name)
|
||||
qos_specs.create(context, name, specs)
|
||||
spec = qos_specs.get_qos_specs_by_name(context, name)
|
||||
notifier_info = dict(name=name, specs=specs)
|
||||
notifier_api.notify(context, 'QoSSpecs',
|
||||
'QoSSpecs.create',
|
||||
@@ -122,7 +123,7 @@ class QoSSpecsController(wsgi.Controller):
|
||||
notifier_err)
|
||||
raise webob.exc.HTTPInternalServerError(explanation=str(err))
|
||||
|
||||
return body
|
||||
return self._view_builder.detail(req, spec)
|
||||
|
||||
@wsgi.serializers(xml=QoSSpecsTemplate)
|
||||
def update(self, req, id, body=None):
|
||||
@@ -166,10 +167,10 @@ class QoSSpecsController(wsgi.Controller):
|
||||
|
||||
try:
|
||||
spec = qos_specs.get_qos_specs(context, id)
|
||||
except exception.NotFound:
|
||||
raise webob.exc.HTTPNotFound()
|
||||
except exception.QoSSpecsNotFound as err:
|
||||
raise webob.exc.HTTPNotFound(explanation=str(err))
|
||||
|
||||
return spec
|
||||
return self._view_builder.detail(req, spec)
|
||||
|
||||
def delete(self, req, id):
|
||||
"""Deletes an existing qos specs."""
|
||||
@@ -178,7 +179,8 @@ class QoSSpecsController(wsgi.Controller):
|
||||
|
||||
force = req.params.get('force', None)
|
||||
|
||||
LOG.debug("qos_specs_manage.delete(): id: %s, force: %s" % (id, force))
|
||||
LOG.debug("Delete qos_spec: %(id)s, force: %(force)s" %
|
||||
{'id': id, 'force': force})
|
||||
|
||||
try:
|
||||
qos_specs.get_qos_specs(context, id)
|
||||
@@ -187,12 +189,12 @@ class QoSSpecsController(wsgi.Controller):
|
||||
notifier_api.notify(context, 'QoSSpecs',
|
||||
'qos_specs.delete',
|
||||
notifier_api.INFO, notifier_info)
|
||||
except exception.NotFound as err:
|
||||
except exception.QoSSpecsNotFound as err:
|
||||
notifier_err = dict(id=id, error_message=str(err))
|
||||
self._notify_qos_specs_error(context,
|
||||
'qos_specs.delete',
|
||||
notifier_err)
|
||||
raise webob.exc.HTTPNotFound()
|
||||
raise webob.exc.HTTPNotFound(explanation=str(err))
|
||||
except exception.QoSSpecsInUse as err:
|
||||
notifier_err = dict(id=id, error_message=str(err))
|
||||
self._notify_qos_specs_error(context,
|
||||
@@ -212,7 +214,7 @@ class QoSSpecsController(wsgi.Controller):
|
||||
context = req.environ['cinder.context']
|
||||
authorize(context)
|
||||
|
||||
LOG.debug("assocications(): id: %s" % id)
|
||||
LOG.debug("Get associations for qos_spec id: %s" % id)
|
||||
|
||||
try:
|
||||
associates = qos_specs.get_associations(context, id)
|
||||
@@ -225,15 +227,15 @@ class QoSSpecsController(wsgi.Controller):
|
||||
self._notify_qos_specs_error(context,
|
||||
'qos_specs.associations',
|
||||
notifier_err)
|
||||
raise webob.exc.HTTPNotFound(explanation=err)
|
||||
raise webob.exc.HTTPNotFound(explanation=str(err))
|
||||
except exception.CinderException as err:
|
||||
notifier_err = dict(id=id, error_message=str(err))
|
||||
self._notify_qos_specs_error(context,
|
||||
'qos_specs.associations',
|
||||
notifier_err)
|
||||
raise webob.exc.HTTPInternalServerError(explanation=err)
|
||||
raise webob.exc.HTTPInternalServerError(explanation=str(err))
|
||||
|
||||
return associates
|
||||
return self._view_builder.associations(req, associates)
|
||||
|
||||
def associate(self, req, id):
|
||||
"""Associate a qos specs with a volume type."""
|
||||
@@ -249,7 +251,8 @@ class QoSSpecsController(wsgi.Controller):
|
||||
'qos_specs.delete',
|
||||
notifier_err)
|
||||
raise webob.exc.HTTPBadRequest(explanation=msg)
|
||||
LOG.debug("associcate(): id: %s, type_id: %s" % (id, type_id))
|
||||
LOG.debug("Associate qos_spec: %(id)s with type: %(type_id)s" %
|
||||
{'id': id, 'type_id': type_id})
|
||||
|
||||
try:
|
||||
qos_specs.get_qos_specs(context, id)
|
||||
@@ -263,19 +266,19 @@ class QoSSpecsController(wsgi.Controller):
|
||||
self._notify_qos_specs_error(context,
|
||||
'qos_specs.associate',
|
||||
notifier_err)
|
||||
raise webob.exc.HTTPNotFound(explanation=err)
|
||||
raise webob.exc.HTTPNotFound(explanation=str(err))
|
||||
except exception.QoSSpecsNotFound as err:
|
||||
notifier_err = dict(id=id, error_message=str(err))
|
||||
self._notify_qos_specs_error(context,
|
||||
'qos_specs.associate',
|
||||
notifier_err)
|
||||
raise webob.exc.HTTPNotFound(explanation=err)
|
||||
raise webob.exc.HTTPNotFound(explanation=str(err))
|
||||
except exception.QoSSpecsAssociateFailed as err:
|
||||
notifier_err = dict(id=id, error_message=str(err))
|
||||
self._notify_qos_specs_error(context,
|
||||
'qos_specs.associate',
|
||||
notifier_err)
|
||||
raise webob.exc.HTTPInternalServerError(explanation=err)
|
||||
raise webob.exc.HTTPInternalServerError(explanation=str(err))
|
||||
|
||||
return webob.Response(status_int=202)
|
||||
|
||||
@@ -293,7 +296,8 @@ class QoSSpecsController(wsgi.Controller):
|
||||
'qos_specs.delete',
|
||||
notifier_err)
|
||||
raise webob.exc.HTTPBadRequest(explanation=msg)
|
||||
LOG.debug("disassocicate(): id: %s, type_id: %s" % (id, type_id))
|
||||
LOG.debug("Disassociate qos_spec: %(id)s from type: %(type_id)s" %
|
||||
{'id': id, 'type_id': type_id})
|
||||
|
||||
try:
|
||||
qos_specs.get_qos_specs(context, id)
|
||||
@@ -307,19 +311,19 @@ class QoSSpecsController(wsgi.Controller):
|
||||
self._notify_qos_specs_error(context,
|
||||
'qos_specs.disassociate',
|
||||
notifier_err)
|
||||
raise webob.exc.HTTPNotFound(explanation=err)
|
||||
raise webob.exc.HTTPNotFound(explanation=str(err))
|
||||
except exception.QoSSpecsNotFound as err:
|
||||
notifier_err = dict(id=id, error_message=str(err))
|
||||
self._notify_qos_specs_error(context,
|
||||
'qos_specs.disassociate',
|
||||
notifier_err)
|
||||
raise webob.exc.HTTPNotFound(explanation=err)
|
||||
raise webob.exc.HTTPNotFound(explanation=str(err))
|
||||
except exception.QoSSpecsDisassociateFailed as err:
|
||||
notifier_err = dict(id=id, error_message=str(err))
|
||||
self._notify_qos_specs_error(context,
|
||||
'qos_specs.disassociate',
|
||||
notifier_err)
|
||||
raise webob.exc.HTTPInternalServerError(explanation=err)
|
||||
raise webob.exc.HTTPInternalServerError(explanation=str(err))
|
||||
|
||||
return webob.Response(status_int=202)
|
||||
|
||||
@@ -328,7 +332,7 @@ class QoSSpecsController(wsgi.Controller):
|
||||
context = req.environ['cinder.context']
|
||||
authorize(context)
|
||||
|
||||
LOG.debug("disassocicate_all(): id: %s" % id)
|
||||
LOG.debug("Disassociate qos_spec: %s from all." % id)
|
||||
|
||||
try:
|
||||
qos_specs.get_qos_specs(context, id)
|
||||
@@ -342,13 +346,13 @@ class QoSSpecsController(wsgi.Controller):
|
||||
self._notify_qos_specs_error(context,
|
||||
'qos_specs.disassociate_all',
|
||||
notifier_err)
|
||||
raise webob.exc.HTTPNotFound(explanation=err)
|
||||
raise webob.exc.HTTPNotFound(explanation=str(err))
|
||||
except exception.QoSSpecsDisassociateFailed as err:
|
||||
notifier_err = dict(id=id, error_message=str(err))
|
||||
self._notify_qos_specs_error(context,
|
||||
'qos_specs.disassociate_all',
|
||||
notifier_err)
|
||||
raise webob.exc.HTTPInternalServerError(explanation=err)
|
||||
raise webob.exc.HTTPInternalServerError(explanation=str(err))
|
||||
|
||||
return webob.Response(status_int=202)
|
||||
|
||||
|
64
cinder/api/views/qos_specs.py
Normal file
64
cinder/api/views/qos_specs.py
Normal file
@@ -0,0 +1,64 @@
|
||||
# Copyright (C) 2013 eBay Inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from cinder.api import common
|
||||
from cinder.openstack.common import log as logging
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ViewBuilder(common.ViewBuilder):
|
||||
"""Model QoS specs API responses as a python dictionary."""
|
||||
|
||||
_collection_name = "qos_specs"
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize view builder."""
|
||||
super(ViewBuilder, self).__init__()
|
||||
|
||||
def summary_list(self, request, qos_specs):
|
||||
"""Show a list of qos_specs without many details."""
|
||||
return self._list_view(self.detail, request, qos_specs)
|
||||
|
||||
def summary(self, request, qos_spec):
|
||||
"""Generic, non-detailed view of a qos_specs."""
|
||||
return {
|
||||
'qos_specs': qos_spec,
|
||||
'links': self._get_links(request,
|
||||
qos_spec['id']),
|
||||
}
|
||||
|
||||
def detail(self, request, qos_spec):
|
||||
"""Detailed view of a single qos_spec."""
|
||||
#TODO(zhiteng) Add associations to detailed view
|
||||
return {
|
||||
'qos_specs': qos_spec,
|
||||
'links': self._get_links(request,
|
||||
qos_spec['id']),
|
||||
}
|
||||
|
||||
def associations(self, request, associates):
|
||||
"""View of qos specs associations."""
|
||||
return {
|
||||
'qos_associations': associates
|
||||
}
|
||||
|
||||
def _list_view(self, func, request, qos_specs):
|
||||
"""Provide a view for a list of qos_specs."""
|
||||
specs_list = [func(request, specs)['qos_specs'] for specs in qos_specs]
|
||||
specs_dict = dict(qos_specs=specs_list)
|
||||
|
||||
return specs_dict
|
@@ -2022,7 +2022,7 @@ def qos_specs_create(context, values):
|
||||
# the name of QoS specs
|
||||
root['key'] = 'QoS_Specs_Name'
|
||||
root['value'] = values['name']
|
||||
LOG.debug("qos_specs_create(): root %s", root)
|
||||
LOG.debug("DB qos_specs_create(): root %s", root)
|
||||
specs_root.update(root)
|
||||
specs_root.save(session=session)
|
||||
|
||||
@@ -2036,7 +2036,7 @@ def qos_specs_create(context, values):
|
||||
except Exception as e:
|
||||
raise db_exc.DBError(e)
|
||||
|
||||
return specs_root
|
||||
return dict(id=specs_root.id, name=specs_root.value)
|
||||
|
||||
|
||||
@require_admin_context
|
||||
@@ -2078,21 +2078,25 @@ def _dict_with_children_specs(specs):
|
||||
|
||||
|
||||
def _dict_with_qos_specs(rows):
|
||||
"""Convert qos specs query results to dict with name as key.
|
||||
"""Convert qos specs query results to list.
|
||||
|
||||
Qos specs query results are a list of quality_of_service_specs refs,
|
||||
some are root entry of a qos specs (key == 'QoS_Specs_Name') and the
|
||||
rest are children entry, a.k.a detailed specs for a qos specs. This
|
||||
funtion converts query results to a dict using spec name as key.
|
||||
function converts query results to a dict using spec name as key.
|
||||
"""
|
||||
result = {}
|
||||
result = []
|
||||
for row in rows:
|
||||
if row['key'] == 'QoS_Specs_Name':
|
||||
result[row['value']] = dict(id=row['id'])
|
||||
member = {}
|
||||
member['name'] = row['value']
|
||||
member.update(dict(id=row['id']))
|
||||
if row.specs:
|
||||
spec_dict = _dict_with_children_specs(row.specs)
|
||||
result[row['value']].update(spec_dict)
|
||||
|
||||
member.update(dict(consumer=spec_dict['consumer']))
|
||||
del spec_dict['consumer']
|
||||
member.update(dict(specs=spec_dict))
|
||||
result.append(member)
|
||||
return result
|
||||
|
||||
|
||||
@@ -2100,25 +2104,35 @@ def _dict_with_qos_specs(rows):
|
||||
def qos_specs_get(context, qos_specs_id, inactive=False):
|
||||
rows = _qos_specs_get_ref(context, qos_specs_id, None, inactive)
|
||||
|
||||
return _dict_with_qos_specs(rows)
|
||||
return _dict_with_qos_specs(rows)[0]
|
||||
|
||||
|
||||
@require_admin_context
|
||||
def qos_specs_get_all(context, inactive=False, filters=None):
|
||||
"""Returns dicts describing all qos_specs.
|
||||
"""Returns a list of all qos_specs.
|
||||
|
||||
Results is like:
|
||||
{'qos-spec-1': {'id': SPECS-UUID,
|
||||
[{
|
||||
'id': SPECS-UUID,
|
||||
'name': 'qos_spec-1',
|
||||
'consumer': 'back-end',
|
||||
'specs': {
|
||||
'key1': 'value1',
|
||||
'key2': 'value2',
|
||||
...
|
||||
'consumer': 'back-end'}
|
||||
'qos-spec-2': {'id': SPECS-UUID,
|
||||
'key1': 'value1',
|
||||
'key2': 'value2',
|
||||
...
|
||||
'consumer': 'back-end'}
|
||||
}
|
||||
},
|
||||
{
|
||||
'id': SPECS-UUID,
|
||||
'name': 'qos_spec-2',
|
||||
'consumer': 'front-end',
|
||||
'specs': {
|
||||
'key1': 'value1',
|
||||
'key2': 'value2',
|
||||
...
|
||||
}
|
||||
},
|
||||
]
|
||||
"""
|
||||
filters = filters or {}
|
||||
#TODO(zhiteng) Add filters for 'consumer'
|
||||
@@ -2135,7 +2149,7 @@ def qos_specs_get_all(context, inactive=False, filters=None):
|
||||
def qos_specs_get_by_name(context, name, inactive=False):
|
||||
rows = _qos_specs_get_by_name(context, name, None, inactive)
|
||||
|
||||
return _dict_with_qos_specs(rows)
|
||||
return _dict_with_qos_specs(rows)[0]
|
||||
|
||||
|
||||
@require_admin_context
|
||||
@@ -2148,9 +2162,7 @@ def qos_specs_associations_get(context, qos_specs_id):
|
||||
extend qos specs association to other entities, such as volumes,
|
||||
sometime in future.
|
||||
"""
|
||||
rows = _qos_specs_get_ref(context, qos_specs_id, None)
|
||||
if not rows:
|
||||
raise exception.QoSSpecsNotFound(specs_id=qos_specs_id)
|
||||
_qos_specs_get_ref(context, qos_specs_id, None)
|
||||
|
||||
return volume_type_qos_associations_get(context, qos_specs_id)
|
||||
|
||||
|
@@ -26,32 +26,37 @@ from cinder.volume import qos_specs
|
||||
|
||||
|
||||
def stub_qos_specs(id):
|
||||
res = dict(name='qos_specs_' + str(id))
|
||||
res.update(dict(consumer='back-end'))
|
||||
res.update(dict(id=str(id)))
|
||||
specs = {"key1": "value1",
|
||||
"key2": "value2",
|
||||
"key3": "value3",
|
||||
"key4": "value4",
|
||||
"key5": "value5"}
|
||||
specs.update(dict(id=str(id)))
|
||||
return specs
|
||||
res.update(dict(specs=specs))
|
||||
return res
|
||||
|
||||
|
||||
def stub_qos_associates(id):
|
||||
return {str(id): {'FakeVolTypeName': 'FakeVolTypeID'}}
|
||||
return [{
|
||||
'association_type': 'volume_type',
|
||||
'name': 'FakeVolTypeName',
|
||||
'id': 'FakeVolTypeID'}]
|
||||
|
||||
|
||||
def return_qos_specs_get_all(context):
|
||||
return dict(
|
||||
qos_specs_1=stub_qos_specs(1),
|
||||
qos_specs_2=stub_qos_specs(2),
|
||||
qos_specs_3=stub_qos_specs(3)
|
||||
)
|
||||
return [
|
||||
stub_qos_specs(1),
|
||||
stub_qos_specs(2),
|
||||
stub_qos_specs(3),
|
||||
]
|
||||
|
||||
|
||||
def return_qos_specs_get_qos_specs(context, id):
|
||||
if id == "777":
|
||||
raise exception.QoSSpecsNotFound(specs_id=id)
|
||||
name = 'qos_specs_%s' % id
|
||||
return {name: stub_qos_specs(int(id))}
|
||||
return stub_qos_specs(int(id))
|
||||
|
||||
|
||||
def return_qos_specs_delete(context, id, force):
|
||||
@@ -142,14 +147,16 @@ class QoSSpecManageApiTest(test.TestCase):
|
||||
return_qos_specs_get_all)
|
||||
|
||||
req = fakes.HTTPRequest.blank('/v2/fake/qos-specs')
|
||||
res_dict = self.controller.index(req)
|
||||
res = self.controller.index(req)
|
||||
|
||||
self.assertEqual(3, len(res_dict.keys()))
|
||||
self.assertEqual(3, len(res['qos_specs']))
|
||||
|
||||
names = set()
|
||||
for item in res['qos_specs']:
|
||||
self.assertEqual('value1', item['specs']['key1'])
|
||||
names.add(item['name'])
|
||||
expected_names = ['qos_specs_1', 'qos_specs_2', 'qos_specs_3']
|
||||
self.assertEqual(set(res_dict.keys()), set(expected_names))
|
||||
for key in res_dict.keys():
|
||||
self.assertEqual('value1', res_dict[key]['key1'])
|
||||
self.assertEqual(names, set(expected_names))
|
||||
|
||||
def test_qos_specs_delete(self):
|
||||
self.stubs.Set(qos_specs, 'get_qos_specs',
|
||||
@@ -212,7 +219,6 @@ class QoSSpecManageApiTest(test.TestCase):
|
||||
res_dict = self.controller.create(req, body)
|
||||
|
||||
self.assertEquals(len(test_notifier.NOTIFICATIONS), 1)
|
||||
self.assertEqual(1, len(res_dict))
|
||||
self.assertEqual('qos_specs_1', res_dict['qos_specs']['name'])
|
||||
|
||||
def test_create_conflict(self):
|
||||
@@ -318,8 +324,8 @@ class QoSSpecManageApiTest(test.TestCase):
|
||||
req = fakes.HTTPRequest.blank('/v2/fake/qos-specs/1')
|
||||
res_dict = self.controller.show(req, '1')
|
||||
|
||||
self.assertEqual(1, len(res_dict))
|
||||
self.assertEqual('1', res_dict['qos_specs_1']['id'])
|
||||
self.assertEqual('1', res_dict['qos_specs']['id'])
|
||||
self.assertEqual('qos_specs_1', res_dict['qos_specs']['name'])
|
||||
|
||||
def test_get_associations(self):
|
||||
self.stubs.Set(qos_specs, 'get_associations',
|
||||
@@ -329,10 +335,10 @@ class QoSSpecManageApiTest(test.TestCase):
|
||||
'/v2/fake/qos-specs/1/associations')
|
||||
res = self.controller.associations(req, '1')
|
||||
|
||||
self.assertEqual('1', res.keys()[0])
|
||||
self.assertEqual('FakeVolTypeName', res['1'].keys()[0])
|
||||
self.assertEqual('FakeVolTypeName',
|
||||
res['qos_associations'][0]['name'])
|
||||
self.assertEqual('FakeVolTypeID',
|
||||
res['1']['FakeVolTypeName'])
|
||||
res['qos_associations'][0]['id'])
|
||||
|
||||
def test_get_associations_not_found(self):
|
||||
self.stubs.Set(qos_specs, 'get_associations',
|
||||
|
@@ -68,7 +68,7 @@ class QualityOfServiceSpecsTableTestCase(test.TestCase):
|
||||
|
||||
specs_id = self._create_qos_specs('NewName')
|
||||
query_id = db.qos_specs_get_by_name(
|
||||
self.ctxt, 'NewName')['NewName']['id']
|
||||
self.ctxt, 'NewName')['id']
|
||||
self.assertEquals(specs_id, query_id)
|
||||
|
||||
def test_qos_specs_get(self):
|
||||
@@ -81,8 +81,9 @@ class QualityOfServiceSpecsTableTestCase(test.TestCase):
|
||||
db.qos_specs_get, self.ctxt, fake_id)
|
||||
|
||||
specs = db.qos_specs_get(self.ctxt, specs_id)
|
||||
value.update(dict(id=specs_id))
|
||||
expected = dict(Name1=value)
|
||||
expected = dict(name='Name1', id=specs_id, consumer='front-end')
|
||||
del value['consumer']
|
||||
expected.update(dict(specs=value))
|
||||
self.assertDictMatch(specs, expected)
|
||||
|
||||
def test_qos_specs_get_all(self):
|
||||
@@ -101,12 +102,18 @@ class QualityOfServiceSpecsTableTestCase(test.TestCase):
|
||||
self.assertEquals(len(specs), 3,
|
||||
"Unexpected number of qos specs records")
|
||||
|
||||
value1.update({'id': spec_id1})
|
||||
value2.update({'id': spec_id2})
|
||||
value3.update({'id': spec_id3})
|
||||
self.assertDictMatch(specs['Name1'], value1)
|
||||
self.assertDictMatch(specs['Name2'], value2)
|
||||
self.assertDictMatch(specs['Name3'], value3)
|
||||
expected1 = dict(name='Name1', id=spec_id1, consumer='front-end')
|
||||
expected2 = dict(name='Name2', id=spec_id2, consumer='back-end')
|
||||
expected3 = dict(name='Name3', id=spec_id3, consumer='back-end')
|
||||
del value1['consumer']
|
||||
del value2['consumer']
|
||||
del value3['consumer']
|
||||
expected1.update(dict(specs=value1))
|
||||
expected2.update(dict(specs=value2))
|
||||
expected3.update(dict(specs=value3))
|
||||
self.assertIn(expected1, specs)
|
||||
self.assertIn(expected2, specs)
|
||||
self.assertIn(expected3, specs)
|
||||
|
||||
def test_qos_specs_get_by_name(self):
|
||||
name = str(int(time.time()))
|
||||
@@ -114,8 +121,11 @@ class QualityOfServiceSpecsTableTestCase(test.TestCase):
|
||||
foo='Foo', bar='Bar')
|
||||
specs_id = self._create_qos_specs(name, value)
|
||||
specs = db.qos_specs_get_by_name(self.ctxt, name)
|
||||
value.update(dict(id=specs_id))
|
||||
expected = {name: value}
|
||||
del value['consumer']
|
||||
expected = {'name': name,
|
||||
'id': specs_id,
|
||||
'consumer': 'front-end',
|
||||
'specs': value}
|
||||
self.assertDictMatch(specs, expected)
|
||||
|
||||
def test_qos_specs_delete(self):
|
||||
@@ -200,5 +210,5 @@ class QualityOfServiceSpecsTableTestCase(test.TestCase):
|
||||
self.ctxt, 'Fake-UUID', value)
|
||||
db.qos_specs_update(self.ctxt, specs_id, value)
|
||||
specs = db.qos_specs_get(self.ctxt, specs_id)
|
||||
self.assertEqual(specs[name]['key2'], 'new_value2')
|
||||
self.assertEqual(specs[name]['key3'], 'value3')
|
||||
self.assertEqual(specs['specs']['key2'], 'new_value2')
|
||||
self.assertEqual(specs['specs']['key3'], 'value3')
|
||||
|
@@ -66,17 +66,16 @@ class QoSSpecsTestCase(test.TestCase):
|
||||
'key3': 'value3'}
|
||||
ref = qos_specs.create(self.ctxt, 'FakeName', input)
|
||||
specs = qos_specs.get_qos_specs(self.ctxt, ref['id'])
|
||||
input.update(dict(consumer='back-end'))
|
||||
input.update(dict(id=ref['id']))
|
||||
expected = {'FakeName': input}
|
||||
expected = (dict(consumer='back-end'))
|
||||
expected.update(dict(id=ref['id']))
|
||||
expected.update(dict(name='FakeName'))
|
||||
del input['consumer']
|
||||
expected.update(dict(specs=input))
|
||||
self.assertDictMatch(specs, expected)
|
||||
|
||||
self.stubs.Set(db, 'qos_specs_create',
|
||||
fake_db_qos_specs_create)
|
||||
|
||||
# Restore input back to original state
|
||||
del input['id']
|
||||
del input['consumer']
|
||||
# qos specs must have unique name
|
||||
self.assertRaises(exception.QoSSpecsExists,
|
||||
qos_specs.create, self.ctxt, 'DupQoSName', input)
|
||||
@@ -101,7 +100,7 @@ class QoSSpecsTestCase(test.TestCase):
|
||||
self.assertRaises(exception.InvalidQoSSpecs,
|
||||
qos_specs.update, self.ctxt, 'fake_id', input)
|
||||
|
||||
del input['consumer']
|
||||
input['consumer'] = 'front-end'
|
||||
# qos specs must exists
|
||||
self.assertRaises(exception.QoSSpecsNotFound,
|
||||
qos_specs.update, self.ctxt, 'fake_id', input)
|
||||
@@ -111,8 +110,8 @@ class QoSSpecsTestCase(test.TestCase):
|
||||
{'key1': 'newvalue1',
|
||||
'key2': 'value2'})
|
||||
specs = qos_specs.get_qos_specs(self.ctxt, specs_id)
|
||||
self.assertEqual(specs['Name']['key1'], 'newvalue1')
|
||||
self.assertEqual(specs['Name']['key2'], 'value2')
|
||||
self.assertEqual(specs['specs']['key1'], 'newvalue1')
|
||||
self.assertEqual(specs['specs']['key2'], 'value2')
|
||||
|
||||
self.stubs.Set(db, 'qos_specs_update', fake_db_update)
|
||||
self.assertRaises(exception.QoSSpecsUpdateFailed,
|
||||
@@ -155,10 +154,15 @@ class QoSSpecsTestCase(test.TestCase):
|
||||
|
||||
self.stubs.Set(db, 'qos_specs_associations_get',
|
||||
fake_db_associate_get)
|
||||
expected = {'specs-id': {'type-1': 'id-1',
|
||||
'type-2': 'id-2'}}
|
||||
expected1 = {'association_type': 'volume_type',
|
||||
'name': 'type-1',
|
||||
'id': 'id-1'}
|
||||
expected2 = {'association_type': 'volume_type',
|
||||
'name': 'type-2',
|
||||
'id': 'id-2'}
|
||||
res = qos_specs.get_associations(self.ctxt, 'specs-id')
|
||||
self.assertDictMatch(res, expected)
|
||||
self.assertIn(expected1, res)
|
||||
self.assertIn(expected2, res)
|
||||
|
||||
self.assertRaises(exception.CinderException,
|
||||
qos_specs.get_associations, self.ctxt,
|
||||
@@ -178,9 +182,9 @@ class QoSSpecsTestCase(test.TestCase):
|
||||
qos_specs.associate_qos_with_type(self.ctxt, specs_id,
|
||||
type_ref['id'])
|
||||
res = qos_specs.get_associations(self.ctxt, specs_id)
|
||||
self.assertEquals(len(res[specs_id].keys()), 1)
|
||||
self.assertIn('TypeName', res[specs_id].keys())
|
||||
self.assertIn(type_ref['id'], res[specs_id].values())
|
||||
self.assertEquals(len(res), 1)
|
||||
self.assertEquals('TypeName', res[0]['name'])
|
||||
self.assertEquals(type_ref['id'], res[0]['id'])
|
||||
|
||||
self.stubs.Set(db, 'qos_specs_associate',
|
||||
fake_db_associate)
|
||||
@@ -205,11 +209,11 @@ class QoSSpecsTestCase(test.TestCase):
|
||||
qos_specs.associate_qos_with_type(self.ctxt, specs_id,
|
||||
type_ref['id'])
|
||||
res = qos_specs.get_associations(self.ctxt, specs_id)
|
||||
self.assertEquals(len(res[specs_id].keys()), 1)
|
||||
self.assertEquals(len(res), 1)
|
||||
|
||||
qos_specs.disassociate_qos_specs(self.ctxt, specs_id, type_ref['id'])
|
||||
res = qos_specs.get_associations(self.ctxt, specs_id)
|
||||
self.assertEquals(len(res[specs_id].keys()), 0)
|
||||
self.assertEquals(len(res), 0)
|
||||
|
||||
self.stubs.Set(db, 'qos_specs_disassociate',
|
||||
fake_db_disassociate)
|
||||
@@ -235,11 +239,11 @@ class QoSSpecsTestCase(test.TestCase):
|
||||
qos_specs.associate_qos_with_type(self.ctxt, specs_id,
|
||||
type2_ref['id'])
|
||||
res = qos_specs.get_associations(self.ctxt, specs_id)
|
||||
self.assertEquals(len(res[specs_id].keys()), 2)
|
||||
self.assertEquals(len(res), 2)
|
||||
|
||||
qos_specs.disassociate_all(self.ctxt, specs_id)
|
||||
res = qos_specs.get_associations(self.ctxt, specs_id)
|
||||
self.assertEquals(len(res[specs_id].keys()), 0)
|
||||
self.assertEquals(len(res), 0)
|
||||
|
||||
self.stubs.Set(db, 'qos_specs_disassociate_all',
|
||||
fake_db_disassociate_all)
|
||||
@@ -250,31 +254,41 @@ class QoSSpecsTestCase(test.TestCase):
|
||||
def test_get_all_specs(self):
|
||||
input = {'key1': 'value1',
|
||||
'key2': 'value2',
|
||||
'key3': 'value3'}
|
||||
'key3': 'value3',
|
||||
'consumer': 'both'}
|
||||
specs_id1 = self._create_qos_specs('Specs1', input)
|
||||
input.update({'key4': 'value4'})
|
||||
specs_id2 = self._create_qos_specs('Specs2', input)
|
||||
|
||||
expected = {'Specs1': {'key1': 'value1',
|
||||
expected1 = {
|
||||
'id': specs_id1,
|
||||
'name': 'Specs1',
|
||||
'consumer': 'both',
|
||||
'specs': {'key1': 'value1',
|
||||
'key2': 'value2',
|
||||
'key3': 'value3'},
|
||||
'Specs2': {'key1': 'value1',
|
||||
'key3': 'value3'}}
|
||||
expected2 = {
|
||||
'id': specs_id2,
|
||||
'name': 'Specs2',
|
||||
'consumer': 'both',
|
||||
'specs': {'key1': 'value1',
|
||||
'key2': 'value2',
|
||||
'key3': 'value3',
|
||||
'key4': 'value4'}}
|
||||
res = qos_specs.get_all_specs(self.ctxt)
|
||||
self.assertDictMatch(expected, res)
|
||||
self.assertEqual(len(res), 2)
|
||||
self.assertIn(expected1, res)
|
||||
self.assertIn(expected2, res)
|
||||
|
||||
def test_get_qos_specs(self):
|
||||
one_time_value = str(int(time.time()))
|
||||
input = {'key1': one_time_value,
|
||||
'key2': 'value2',
|
||||
'key3': 'value3'}
|
||||
'key3': 'value3',
|
||||
'consumer': 'both'}
|
||||
id = self._create_qos_specs('Specs1', input)
|
||||
specs = qos_specs.get_qos_specs(self.ctxt, id)
|
||||
self.assertEquals(specs['Specs1']['key1'], one_time_value)
|
||||
self.assertEquals(specs['specs']['key1'], one_time_value)
|
||||
|
||||
self.assertRaises(exception.InvalidQoSSpecs,
|
||||
qos_specs.get_qos_specs, self.ctxt, None)
|
||||
@@ -283,11 +297,12 @@ class QoSSpecsTestCase(test.TestCase):
|
||||
one_time_value = str(int(time.time()))
|
||||
input = {'key1': one_time_value,
|
||||
'key2': 'value2',
|
||||
'key3': 'value3'}
|
||||
'key3': 'value3',
|
||||
'consumer': 'back-end'}
|
||||
id = self._create_qos_specs(one_time_value, input)
|
||||
specs = qos_specs.get_qos_specs_by_name(self.ctxt,
|
||||
one_time_value)
|
||||
self.assertEquals(specs[one_time_value]['key1'], one_time_value)
|
||||
self.assertEquals(specs['specs']['key1'], one_time_value)
|
||||
|
||||
self.assertRaises(exception.InvalidQoSSpecs,
|
||||
qos_specs.get_qos_specs_by_name, self.ctxt, None)
|
||||
|
@@ -147,11 +147,14 @@ def get_associations(context, specs_id):
|
||||
LOG.warn(msg)
|
||||
raise exception.CinderException(message=msg)
|
||||
|
||||
result = {}
|
||||
result = []
|
||||
for vol_type in associates:
|
||||
result[vol_type['name']] = vol_type['id']
|
||||
member = dict(association_type='volume_type')
|
||||
member.update(dict(name=vol_type['name']))
|
||||
member.update(dict(id=vol_type['id']))
|
||||
result.append(member)
|
||||
|
||||
return {specs_id: result}
|
||||
return result
|
||||
|
||||
|
||||
def associate_qos_with_type(context, specs_id, type_id):
|
||||
|
Reference in New Issue
Block a user