summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2011-12-12 00:45:28 +0000
committerGerrit Code Review <review@openstack.org>2011-12-12 00:45:28 +0000
commita4e2ed8cb9ba71e96dfadb96f8171054a0d30914 (patch)
tree1eb57529f5fcfbd97b3c1f3c3285ba5b61e1721d
parentce2d62f95cd9b62858c9b4ef37b418881ceaef07 (diff)
parenta33b4d616d8bb877f295383e8649df14c1e19b3c (diff)
downloadnova-a4e2ed8cb9ba71e96dfadb96f8171054a0d30914.tar.gz
nova-a4e2ed8cb9ba71e96dfadb96f8171054a0d30914.tar.xz
nova-a4e2ed8cb9ba71e96dfadb96f8171054a0d30914.zip
Merge "Add templates for selected resource extensions."
-rw-r--r--nova/api/openstack/v2/contrib/virtual_storage_arrays.py228
-rw-r--r--nova/tests/api/openstack/v2/contrib/test_vsa.py265
2 files changed, 444 insertions, 49 deletions
diff --git a/nova/api/openstack/v2/contrib/virtual_storage_arrays.py b/nova/api/openstack/v2/contrib/virtual_storage_arrays.py
index f3a7831d5..cd87e3462 100644
--- a/nova/api/openstack/v2/contrib/virtual_storage_arrays.py
+++ b/nova/api/openstack/v2/contrib/virtual_storage_arrays.py
@@ -26,6 +26,7 @@ from nova.api.openstack.v2.contrib import volumes
from nova.api.openstack.v2 import extensions
from nova.api.openstack.v2 import servers
from nova.api.openstack import wsgi
+from nova.api.openstack import xmlutil
from nova import compute
from nova.compute import instance_types
from nova import network
@@ -84,22 +85,6 @@ def _vsa_view(context, vsa, details=False, instances=None):
class VsaController(object):
"""The Virtual Storage Array API controller for the OpenStack API."""
- _serialization_metadata = {
- 'application/xml': {
- "attributes": {
- "vsa": [
- "id",
- "name",
- "displayName",
- "displayDescription",
- "createTime",
- "status",
- "vcType",
- "vcCount",
- "driveCount",
- "ipAddress",
- ]}}}
-
def __init__(self):
self.vsa_api = vsa.API()
self.compute_api = compute.API()
@@ -230,6 +215,45 @@ class VsaController(object):
# Placeholder
+def make_vsa(elem):
+ elem.set('id')
+ elem.set('name')
+ elem.set('displayName')
+ elem.set('displayDescription')
+ elem.set('createTime')
+ elem.set('status')
+ elem.set('vcType')
+ elem.set('vcCount')
+ elem.set('driveCount')
+ elem.set('ipAddress')
+
+
+class VsaTemplate(xmlutil.TemplateBuilder):
+ def construct(self):
+ root = xmlutil.TemplateElement('vsa', selector='vsa')
+ make_vsa(root)
+ return xmlutil.MasterTemplate(root, 1)
+
+
+class VsaSetTemplate(xmlutil.TemplateBuilder):
+ def construct(self):
+ root = xmlutil.TemplateElement('vsaSet')
+ elem = xmlutil.SubTemplateElement(root, 'vsa', selector='vsaSet')
+ make_vsa(elem)
+ return xmlutil.MasterTemplate(root, 1)
+
+
+class VsaSerializer(xmlutil.XMLTemplateSerializer):
+ def default(self):
+ return VsaTemplate()
+
+ def index(self):
+ return VsaSetTemplate()
+
+ def detail(self):
+ return VsaSetTemplate()
+
+
class VsaVolumeDriveController(volumes.VolumeController):
"""The base class for VSA volumes & drives.
@@ -238,21 +262,6 @@ class VsaVolumeDriveController(volumes.VolumeController):
"""
- _serialization_metadata = {
- 'application/xml': {
- "attributes": {
- "volume": [
- "id",
- "name",
- "status",
- "size",
- "availabilityZone",
- "createdAt",
- "displayName",
- "displayDescription",
- "vsaId",
- ]}}}
-
def __init__(self):
self.volume_api = volume.API()
self.vsa_api = vsa.API()
@@ -401,6 +410,12 @@ class VsaVolumeDriveController(volumes.VolumeController):
return super(VsaVolumeDriveController, self).show(req, id)
+def make_volume(elem):
+ volumes.make_volume(elem)
+ elem.set('name')
+ elem.set('vsaId')
+
+
class VsaVolumeController(VsaVolumeDriveController):
"""The VSA volume API controller for the Openstack API.
@@ -416,6 +431,32 @@ class VsaVolumeController(VsaVolumeDriveController):
super(VsaVolumeController, self).__init__()
+class VsaVolumeTemplate(xmlutil.TemplateBuilder):
+ def construct(self):
+ root = xmlutil.TemplateElement('volume', selector='volume')
+ make_volume(root)
+ return xmlutil.MasterTemplate(root, 1)
+
+
+class VsaVolumesTemplate(xmlutil.TemplateBuilder):
+ def construct(self):
+ root = xmlutil.TemplateElement('volumes')
+ elem = xmlutil.SubTemplateElement(root, 'volume', selector='volumes')
+ make_volume(elem)
+ return xmlutil.MasterTemplate(root, 1)
+
+
+class VsaVolumeSerializer(xmlutil.XMLTemplateSerializer):
+ def default(self):
+ return VsaVolumeTemplate()
+
+ def index(self):
+ return VsaVolumesTemplate()
+
+ def detail(self):
+ return VsaVolumesTemplate()
+
+
class VsaDriveController(VsaVolumeDriveController):
"""The VSA Drive API controller for the Openstack API.
@@ -443,27 +484,35 @@ class VsaDriveController(VsaVolumeDriveController):
raise exc.HTTPBadRequest()
+class VsaDriveTemplate(xmlutil.TemplateBuilder):
+ def construct(self):
+ root = xmlutil.TemplateElement('drive', selector='drive')
+ make_volume(root)
+ return xmlutil.MasterTemplate(root, 1)
+
+
+class VsaDrivesTemplate(xmlutil.TemplateBuilder):
+ def construct(self):
+ root = xmlutil.TemplateElement('drives')
+ elem = xmlutil.SubTemplateElement(root, 'drive', selector='drives')
+ make_volume(elem)
+ return xmlutil.MasterTemplate(root, 1)
+
+
+class VsaDriveSerializer(xmlutil.XMLTemplateSerializer):
+ def default(self):
+ return VsaDriveTemplate()
+
+ def index(self):
+ return VsaDrivesTemplate()
+
+ def detail(self):
+ return VsaDrivesTemplate()
+
+
class VsaVPoolController(object):
"""The vPool VSA API controller for the OpenStack API."""
- _serialization_metadata = {
- 'application/xml': {
- "attributes": {
- "vpool": [
- "id",
- "vsaId",
- "name",
- "displayName",
- "displayDescription",
- "driveCount",
- "driveIds",
- "protection",
- "stripeSize",
- "stripeWidth",
- "createTime",
- "status",
- ]}}}
-
def __init__(self):
self.vsa_api = vsa.API()
super(VsaVPoolController, self).__init__()
@@ -489,6 +538,48 @@ class VsaVPoolController(object):
raise exc.HTTPBadRequest()
+def make_vpool(elem):
+ elem.set('id')
+ elem.set('vsaId')
+ elem.set('name')
+ elem.set('displayName')
+ elem.set('displayDescription')
+ elem.set('driveCount')
+ elem.set('protection')
+ elem.set('stripeSize')
+ elem.set('stripeWidth')
+ elem.set('createTime')
+ elem.set('status')
+
+ drive_ids = xmlutil.SubTemplateElement(elem, 'driveIds')
+ drive_id = xmlutil.SubTemplateElement(drive_ids, 'driveId',
+ selector='driveIds')
+ drive_id.text = xmlutil.Selector()
+
+
+class VsaVPoolTemplate(xmlutil.TemplateBuilder):
+ def construct(self):
+ root = xmlutil.TemplateElement('vpool', selector='vpool')
+ make_vpool(root)
+ return xmlutil.MasterTemplate(root, 1)
+
+
+class VsaVPoolsTemplate(xmlutil.TemplateBuilder):
+ def construct(self):
+ root = xmlutil.TemplateElement('vpools')
+ elem = xmlutil.SubTemplateElement(root, 'vpool', selector='vpools')
+ make_vpool(elem)
+ return xmlutil.MasterTemplate(root, 1)
+
+
+class VsaVPoolSerializer(xmlutil.XMLTemplateSerializer):
+ def default(self):
+ return VsaVPoolTemplate()
+
+ def index(self):
+ return VsaVPoolsTemplate()
+
+
class VsaVCController(servers.Controller):
"""The VSA Virtual Controller API controller for the OpenStack API."""
@@ -554,9 +645,16 @@ class Virtual_storage_arrays(extensions.ExtensionDescriptor):
def get_resources(self):
resources = []
+
+ body_serializers = {
+ 'application/xml': VsaSerializer(),
+ }
+ serializer = wsgi.ResponseSerializer(body_serializers)
+
res = extensions.ResourceExtension(
'zadr-vsa',
VsaController(),
+ serializer=serializer,
collection_actions={'detail': 'GET'},
member_actions={'add_capacity': 'POST',
'remove_capacity': 'POST',
@@ -564,31 +662,63 @@ class Virtual_storage_arrays(extensions.ExtensionDescriptor):
'disassociate_address': 'POST'})
resources.append(res)
+ body_serializers = {
+ 'application/xml': VsaVolumeSerializer(),
+ }
+ serializer = wsgi.ResponseSerializer(body_serializers)
+
res = extensions.ResourceExtension('volumes',
VsaVolumeController(),
+ serializer=serializer,
collection_actions={'detail': 'GET'},
parent=dict(
member_name='vsa',
collection_name='zadr-vsa'))
resources.append(res)
+ body_serializers = {
+ 'application/xml': VsaDriveSerializer(),
+ }
+ serializer = wsgi.ResponseSerializer(body_serializers)
+
res = extensions.ResourceExtension('drives',
VsaDriveController(),
+ serializer=serializer,
collection_actions={'detail': 'GET'},
parent=dict(
member_name='vsa',
collection_name='zadr-vsa'))
resources.append(res)
+ body_serializers = {
+ 'application/xml': VsaVPoolSerializer(),
+ }
+ serializer = wsgi.ResponseSerializer(body_serializers)
+
res = extensions.ResourceExtension('vpools',
VsaVPoolController(),
+ serializer=serializer,
parent=dict(
member_name='vsa',
collection_name='zadr-vsa'))
resources.append(res)
+ headers_serializer = servers.HeadersSerializer()
+ body_serializers = {
+ 'application/xml': servers.ServerXMLSerializer(),
+ }
+ serializer = wsgi.ResponseSerializer(body_serializers,
+ headers_serializer)
+
+ body_deserializers = {
+ 'application/xml': servers.ServerXMLDeserializer(),
+ }
+ deserializer = wsgi.RequestDeserializer(body_deserializers)
+
res = extensions.ResourceExtension('instances',
VsaVCController(),
+ serializer=serializer,
+ deserializer=deserializer,
parent=dict(
member_name='vsa',
collection_name='zadr-vsa'))
diff --git a/nova/tests/api/openstack/v2/contrib/test_vsa.py b/nova/tests/api/openstack/v2/contrib/test_vsa.py
index 7b3ea1810..03c9d4449 100644
--- a/nova/tests/api/openstack/v2/contrib/test_vsa.py
+++ b/nova/tests/api/openstack/v2/contrib/test_vsa.py
@@ -13,11 +13,14 @@
# License for the specific language governing permissions and limitations
# under the License.
+import datetime
import json
+from lxml import etree
import stubout
import webob
+from nova.api.openstack.v2.contrib import virtual_storage_arrays as vsa_ext
from nova import context
import nova.db
from nova import exception
@@ -445,3 +448,265 @@ class VSADriveApiTest(VSAVolumeApiTest):
def tearDown(self):
self.stubs.UnsetAll()
super(VSADriveApiTest, self).tearDown()
+
+
+class SerializerTestCommon(test.TestCase):
+ def setUp(self):
+ super(SerializerTestCommon, self).setUp()
+ self.serializer = self.serializer_class()
+
+ def _verify_attrs(self, obj, tree, attrs):
+ for attr in attrs:
+ self.assertEqual(str(obj[attr]), tree.get(attr))
+
+
+class VsaSerializerTest(SerializerTestCommon):
+ serializer_class = vsa_ext.VsaSerializer
+
+ def test_serialize_show_create(self):
+ exemplar = dict(
+ id='vsa_id',
+ name='vsa_name',
+ displayName='vsa_display_name',
+ displayDescription='vsa_display_desc',
+ createTime=datetime.datetime.now(),
+ status='active',
+ vcType='vsa_instance_type',
+ vcCount=24,
+ driveCount=48,
+ ipAddress='10.11.12.13')
+ text = self.serializer.serialize(dict(vsa=exemplar), 'show')
+
+ print text
+ tree = etree.fromstring(text)
+
+ self.assertEqual('vsa', tree.tag)
+ self._verify_attrs(exemplar, tree, exemplar.keys())
+
+ def test_serialize_index_detail(self):
+ exemplar = [dict(
+ id='vsa1_id',
+ name='vsa1_name',
+ displayName='vsa1_display_name',
+ displayDescription='vsa1_display_desc',
+ createTime=datetime.datetime.now(),
+ status='active',
+ vcType='vsa1_instance_type',
+ vcCount=24,
+ driveCount=48,
+ ipAddress='10.11.12.13'),
+ dict(
+ id='vsa2_id',
+ name='vsa2_name',
+ displayName='vsa2_display_name',
+ displayDescription='vsa2_display_desc',
+ createTime=datetime.datetime.now(),
+ status='active',
+ vcType='vsa2_instance_type',
+ vcCount=42,
+ driveCount=84,
+ ipAddress='11.12.13.14')]
+ text = self.serializer.serialize(dict(vsaSet=exemplar), 'index')
+
+ print text
+ tree = etree.fromstring(text)
+
+ self.assertEqual('vsaSet', tree.tag)
+ self.assertEqual(len(exemplar), len(tree))
+ for idx, child in enumerate(tree):
+ self.assertEqual('vsa', child.tag)
+ self._verify_attrs(exemplar[idx], child, exemplar[idx].keys())
+
+
+class VsaVolumeSerializerTest(SerializerTestCommon):
+ serializer_class = vsa_ext.VsaVolumeSerializer
+ object = 'volume'
+ objects = 'volumes'
+
+ def _verify_voldrive(self, vol, tree):
+ self.assertEqual(self.object, tree.tag)
+
+ self._verify_attrs(vol, tree, ('id', 'status', 'size',
+ 'availabilityZone', 'createdAt',
+ 'displayName', 'displayDescription',
+ 'volumeType', 'vsaId', 'name'))
+
+ for child in tree:
+ self.assertTrue(child.tag in ('attachments', 'metadata'))
+ if child.tag == 'attachments':
+ self.assertEqual(1, len(child))
+ self.assertEqual('attachment', child[0].tag)
+ self._verify_attrs(vol['attachments'][0], child[0],
+ ('id', 'volumeId', 'serverId', 'device'))
+ elif child.tag == 'metadata':
+ not_seen = set(vol['metadata'].keys())
+ for gr_child in child:
+ self.assertTrue(gr_child.tag in not_seen)
+ self.assertEqual(str(vol['metadata'][gr_child.tag]),
+ gr_child.text)
+ not_seen.remove(gr_child.tag)
+ self.assertEqual(0, len(not_seen))
+
+ def test_show_create_serializer(self):
+ raw_volume = dict(
+ id='vol_id',
+ status='vol_status',
+ size=1024,
+ availabilityZone='vol_availability',
+ createdAt=datetime.datetime.now(),
+ attachments=[dict(
+ id='vol_id',
+ volumeId='vol_id',
+ serverId='instance_uuid',
+ device='/foo')],
+ displayName='vol_name',
+ displayDescription='vol_desc',
+ volumeType='vol_type',
+ metadata=dict(
+ foo='bar',
+ baz='quux',
+ ),
+ vsaId='vol_vsa_id',
+ name='vol_vsa_name',
+ )
+ text = self.serializer.serialize({self.object: raw_volume}, 'show')
+
+ print text
+ tree = etree.fromstring(text)
+
+ self._verify_voldrive(raw_volume, tree)
+
+ def test_index_detail_serializer(self):
+ raw_volumes = [dict(
+ id='vol1_id',
+ status='vol1_status',
+ size=1024,
+ availabilityZone='vol1_availability',
+ createdAt=datetime.datetime.now(),
+ attachments=[dict(
+ id='vol1_id',
+ volumeId='vol1_id',
+ serverId='instance_uuid',
+ device='/foo1')],
+ displayName='vol1_name',
+ displayDescription='vol1_desc',
+ volumeType='vol1_type',
+ metadata=dict(
+ foo='vol1_foo',
+ bar='vol1_bar',
+ ),
+ vsaId='vol1_vsa_id',
+ name='vol1_vsa_name',
+ ),
+ dict(
+ id='vol2_id',
+ status='vol2_status',
+ size=1024,
+ availabilityZone='vol2_availability',
+ createdAt=datetime.datetime.now(),
+ attachments=[dict(
+ id='vol2_id',
+ volumeId='vol2_id',
+ serverId='instance_uuid',
+ device='/foo2')],
+ displayName='vol2_name',
+ displayDescription='vol2_desc',
+ volumeType='vol2_type',
+ metadata=dict(
+ foo='vol2_foo',
+ bar='vol2_bar',
+ ),
+ vsaId='vol2_vsa_id',
+ name='vol2_vsa_name',
+ )]
+ text = self.serializer.serialize({self.objects: raw_volumes}, 'index')
+
+ print text
+ tree = etree.fromstring(text)
+
+ self.assertEqual(self.objects, tree.tag)
+ self.assertEqual(len(raw_volumes), len(tree))
+ for idx, child in enumerate(tree):
+ self._verify_voldrive(raw_volumes[idx], child)
+
+
+class VsaDriveSerializerTest(VsaVolumeSerializerTest):
+ serializer_class = vsa_ext.VsaDriveSerializer
+ object = 'drive'
+ objects = 'drives'
+
+
+class VsaVPoolSerializerTest(SerializerTestCommon):
+ serializer_class = vsa_ext.VsaVPoolSerializer
+
+ def _verify_vpool(self, vpool, tree):
+ self._verify_attrs(vpool, tree, ('id', 'vsaId', 'name', 'displayName',
+ 'displayDescription', 'driveCount',
+ 'protection', 'stripeSize',
+ 'stripeWidth', 'createTime',
+ 'status'))
+
+ self.assertEqual(1, len(tree))
+ self.assertEqual('driveIds', tree[0].tag)
+ self.assertEqual(len(vpool['driveIds']), len(tree[0]))
+ for idx, gr_child in enumerate(tree[0]):
+ self.assertEqual('driveId', gr_child.tag)
+ self.assertEqual(str(vpool['driveIds'][idx]), gr_child.text)
+
+ def test_vpool_create_show_serializer(self):
+ exemplar = dict(
+ id='vpool_id',
+ vsaId='vpool_vsa_id',
+ name='vpool_vsa_name',
+ displayName='vpool_display_name',
+ displayDescription='vpool_display_desc',
+ driveCount=24,
+ driveIds=['drive1', 'drive2', 'drive3'],
+ protection='protected',
+ stripeSize=1024,
+ stripeWidth=2048,
+ createTime=datetime.datetime.now(),
+ status='available')
+ text = self.serializer.serialize(dict(vpool=exemplar), 'show')
+
+ print text
+ tree = etree.fromstring(text)
+
+ self._verify_vpool(exemplar, tree)
+
+ def test_vpool_index_serializer(self):
+ exemplar = [dict(
+ id='vpool1_id',
+ vsaId='vpool1_vsa_id',
+ name='vpool1_vsa_name',
+ displayName='vpool1_display_name',
+ displayDescription='vpool1_display_desc',
+ driveCount=24,
+ driveIds=['drive1', 'drive2', 'drive3'],
+ protection='protected',
+ stripeSize=1024,
+ stripeWidth=2048,
+ createTime=datetime.datetime.now(),
+ status='available'),
+ dict(
+ id='vpool2_id',
+ vsaId='vpool2_vsa_id',
+ name='vpool2_vsa_name',
+ displayName='vpool2_display_name',
+ displayDescription='vpool2_display_desc',
+ driveCount=42,
+ driveIds=['drive4', 'drive5', 'drive6'],
+ protection='protected',
+ stripeSize=512,
+ stripeWidth=256,
+ createTime=datetime.datetime.now(),
+ status='available')]
+ text = self.serializer.serialize(dict(vpools=exemplar), 'index')
+
+ print text
+ tree = etree.fromstring(text)
+
+ self.assertEqual('vpools', tree.tag)
+ self.assertEqual(len(exemplar), len(tree))
+ for idx, child in enumerate(tree):
+ self._verify_vpool(exemplar[idx], child)