Merge "Add XML deserializer for qos_manage delete_keys API"
This commit is contained in:
commit
15aeee5026
@ -26,6 +26,7 @@ from cinder import exception
|
|||||||
from cinder.openstack.common import log as logging
|
from cinder.openstack.common import log as logging
|
||||||
from cinder.openstack.common import strutils
|
from cinder.openstack.common import strutils
|
||||||
from cinder import rpc
|
from cinder import rpc
|
||||||
|
from cinder import utils
|
||||||
from cinder.volume import qos_specs
|
from cinder.volume import qos_specs
|
||||||
|
|
||||||
|
|
||||||
@ -61,6 +62,26 @@ class QoSSpecsTemplate(xmlutil.TemplateBuilder):
|
|||||||
return xmlutil.MasterTemplate(root, 1)
|
return xmlutil.MasterTemplate(root, 1)
|
||||||
|
|
||||||
|
|
||||||
|
class QoSSpecsKeyDeserializer(wsgi.XMLDeserializer):
|
||||||
|
def _extract_keys(self, key_node):
|
||||||
|
keys = []
|
||||||
|
for key in key_node.childNodes:
|
||||||
|
key_name = key.tagName
|
||||||
|
keys.append(key_name)
|
||||||
|
|
||||||
|
return keys
|
||||||
|
|
||||||
|
def default(self, string):
|
||||||
|
dom = utils.safe_minidom_parse_string(string)
|
||||||
|
key_node = self.find_first_child_named(dom, 'keys')
|
||||||
|
if not key_node:
|
||||||
|
LOG.info(_("Unable to parse XML input."))
|
||||||
|
msg = _("Unable to parse XML request. "
|
||||||
|
"Please provide XML in correct format.")
|
||||||
|
raise webob.exc.HTTPBadRequest(explanation=msg)
|
||||||
|
return {'body': {'keys': self._extract_keys(key_node)}}
|
||||||
|
|
||||||
|
|
||||||
class AssociationsTemplate(xmlutil.TemplateBuilder):
|
class AssociationsTemplate(xmlutil.TemplateBuilder):
|
||||||
def construct(self):
|
def construct(self):
|
||||||
root = xmlutil.TemplateElement('qos_associations')
|
root = xmlutil.TemplateElement('qos_associations')
|
||||||
@ -225,6 +246,7 @@ class QoSSpecsController(wsgi.Controller):
|
|||||||
|
|
||||||
return webob.Response(status_int=202)
|
return webob.Response(status_int=202)
|
||||||
|
|
||||||
|
@wsgi.deserializers(xml=QoSSpecsKeyDeserializer)
|
||||||
def delete_keys(self, req, id, body):
|
def delete_keys(self, req, id, body):
|
||||||
"""Deletes specified keys in qos specs."""
|
"""Deletes specified keys in qos specs."""
|
||||||
context = req.environ['cinder.context']
|
context = req.environ['cinder.context']
|
||||||
|
8
cinder/api/schemas/v1.1/qos_association.rng
Normal file
8
cinder/api/schemas/v1.1/qos_association.rng
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<element name="associations" xmlns="http://relaxng.org/ns/structure/1.0">
|
||||||
|
<attribute name="name"> <text/> </attribute>
|
||||||
|
<attribute name="id"> <text/> </attribute>
|
||||||
|
<attribute name="association_type"> <text/> </attribute>
|
||||||
|
<zeroOrMore>
|
||||||
|
<externalRef href="../atom-link.rng"/>
|
||||||
|
</zeroOrMore>
|
||||||
|
</element>
|
5
cinder/api/schemas/v1.1/qos_associations.rng
Normal file
5
cinder/api/schemas/v1.1/qos_associations.rng
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<element name="qos_associations" xmlns="http://relaxng.org/ns/structure/1.0">
|
||||||
|
<zeroOrMore>
|
||||||
|
<externalRef href="qos_association.rng"/>
|
||||||
|
</zeroOrMore>
|
||||||
|
</element>
|
16
cinder/api/schemas/v1.1/qos_spec.rng
Normal file
16
cinder/api/schemas/v1.1/qos_spec.rng
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<element name="qos_spec" xmlns="http://relaxng.org/ns/structure/1.0">
|
||||||
|
<attribute name="name"> <text/> </attribute>
|
||||||
|
<attribute name="id"> <text/> </attribute>
|
||||||
|
<attribute name="consumer"> <text/> </attribute>
|
||||||
|
<element name="specs">
|
||||||
|
<zeroOrMore>
|
||||||
|
<element>
|
||||||
|
<anyName/>
|
||||||
|
<text/>
|
||||||
|
</element>
|
||||||
|
</zeroOrMore>
|
||||||
|
</element>
|
||||||
|
<zeroOrMore>
|
||||||
|
<externalRef href="../atom-link.rng"/>
|
||||||
|
</zeroOrMore>
|
||||||
|
</element>
|
5
cinder/api/schemas/v1.1/qos_specs.rng
Normal file
5
cinder/api/schemas/v1.1/qos_specs.rng
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<element name="qos_specs" xmlns="http://relaxng.org/ns/structure/1.0">
|
||||||
|
<zeroOrMore>
|
||||||
|
<externalRef href="qos_spec.rng"/>
|
||||||
|
</zeroOrMore>
|
||||||
|
</element>
|
@ -14,11 +14,13 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
from lxml import etree
|
||||||
from xml.dom import minidom
|
from xml.dom import minidom
|
||||||
|
|
||||||
import webob
|
import webob
|
||||||
|
|
||||||
from cinder.api.contrib import qos_specs_manage
|
from cinder.api.contrib import qos_specs_manage
|
||||||
|
from cinder.api import xmlutil
|
||||||
from cinder import exception
|
from cinder import exception
|
||||||
from cinder import test
|
from cinder import test
|
||||||
from cinder.tests.api import fakes
|
from cinder.tests.api import fakes
|
||||||
@ -598,3 +600,108 @@ class QoSSpecManageApiTest(test.TestCase):
|
|||||||
'/v2/fake/qos-specs/222/disassociate_all')
|
'/v2/fake/qos-specs/222/disassociate_all')
|
||||||
self.assertRaises(webob.exc.HTTPInternalServerError,
|
self.assertRaises(webob.exc.HTTPInternalServerError,
|
||||||
self.controller.disassociate_all, req, '222')
|
self.controller.disassociate_all, req, '222')
|
||||||
|
|
||||||
|
|
||||||
|
class TestQoSSpecsTemplate(test.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
super(TestQoSSpecsTemplate, self).setUp()
|
||||||
|
self.serializer = qos_specs_manage.QoSSpecsTemplate()
|
||||||
|
|
||||||
|
def test_qos_specs_serializer(self):
|
||||||
|
fixture = {
|
||||||
|
"qos_specs": [
|
||||||
|
{
|
||||||
|
"specs": {
|
||||||
|
"key1": "v1",
|
||||||
|
"key2": "v2",
|
||||||
|
},
|
||||||
|
"consumer": "back-end",
|
||||||
|
"name": "qos-2",
|
||||||
|
"id": "61e7b72f-ef15-46d9-b00e-b80f699999d0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"specs": {"total_iops_sec": "200"},
|
||||||
|
"consumer": "front-end",
|
||||||
|
"name": "qos-1",
|
||||||
|
"id": "e44bba5e-b629-4b96-9aa3-0404753a619b"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
output = self.serializer.serialize(fixture)
|
||||||
|
root = etree.XML(output)
|
||||||
|
xmlutil.validate_schema(root, 'qos_specs')
|
||||||
|
qos_elems = root.findall("qos_spec")
|
||||||
|
self.assertEqual(len(qos_elems), 2)
|
||||||
|
for i, qos_elem in enumerate(qos_elems):
|
||||||
|
qos_dict = fixture['qos_specs'][i]
|
||||||
|
|
||||||
|
# check qos_spec attributes
|
||||||
|
for key in ['name', 'id', 'consumer']:
|
||||||
|
self.assertEqual(qos_elem.get(key), str(qos_dict[key]))
|
||||||
|
|
||||||
|
# check specs
|
||||||
|
specs = qos_elem.find("specs")
|
||||||
|
new_dict = {}
|
||||||
|
for element in specs.iter(tag=etree.Element):
|
||||||
|
# skip root element for specs
|
||||||
|
if element.tag == "specs":
|
||||||
|
continue
|
||||||
|
new_dict.update({element.tag: element.text})
|
||||||
|
|
||||||
|
self.assertDictMatch(new_dict, qos_dict['specs'])
|
||||||
|
|
||||||
|
|
||||||
|
class TestAssociationsTemplate(test.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
super(TestAssociationsTemplate, self).setUp()
|
||||||
|
self.serializer = qos_specs_manage.AssociationsTemplate()
|
||||||
|
|
||||||
|
def test_qos_associations_serializer(self):
|
||||||
|
fixture = {
|
||||||
|
"qos_associations": [
|
||||||
|
{
|
||||||
|
"association_type": "volume_type",
|
||||||
|
"name": "type-4",
|
||||||
|
"id": "14d54d29-51a4-4046-9f6f-cf9800323563"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"association_type": "volume_type",
|
||||||
|
"name": "type-2",
|
||||||
|
"id": "3689ce83-308d-4ba1-8faf-7f1be04a282b"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
output = self.serializer.serialize(fixture)
|
||||||
|
root = etree.XML(output)
|
||||||
|
xmlutil.validate_schema(root, 'qos_associations')
|
||||||
|
association_elems = root.findall("associations")
|
||||||
|
self.assertEqual(len(association_elems), 2)
|
||||||
|
for i, association_elem in enumerate(association_elems):
|
||||||
|
association_dict = fixture['qos_associations'][i]
|
||||||
|
|
||||||
|
# check qos_spec attributes
|
||||||
|
for key in ['name', 'id', 'association_type']:
|
||||||
|
self.assertEqual(association_elem.get(key),
|
||||||
|
str(association_dict[key]))
|
||||||
|
|
||||||
|
|
||||||
|
class TestQoSSpecsKeyDeserializer(test.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
super(TestQoSSpecsKeyDeserializer, self).setUp()
|
||||||
|
self.deserializer = qos_specs_manage.QoSSpecsKeyDeserializer()
|
||||||
|
|
||||||
|
def test_keys(self):
|
||||||
|
self_request = """
|
||||||
|
<keys><xyz /><abc /></keys>"""
|
||||||
|
request = self.deserializer.deserialize(self_request)
|
||||||
|
expected = {
|
||||||
|
"keys": ["xyz", "abc"]
|
||||||
|
}
|
||||||
|
self.assertEqual(request['body'], expected)
|
||||||
|
|
||||||
|
def test_bad_format(self):
|
||||||
|
self_request = """
|
||||||
|
<qos_specs><keys><xyz /><abc /></keys></qos_specs>"""
|
||||||
|
self.assertRaises(webob.exc.HTTPBadRequest,
|
||||||
|
self.deserializer.deserialize, self_request)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user