summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2011-12-09 17:31:34 +0000
committerGerrit Code Review <review@openstack.org>2011-12-09 17:31:34 +0000
commit2aadaba580f0253d64a69a5cf4127e50346a34fb (patch)
tree10b7434fdf5a221720e79f70ff3811a723634cf9
parent8920181a0d8cfb4f78af0fa0b868e864d8971744 (diff)
parentf7df18f22715e958510805db42df818ac0f0d243 (diff)
downloadnova-2aadaba580f0253d64a69a5cf4127e50346a34fb.tar.gz
nova-2aadaba580f0253d64a69a5cf4127e50346a34fb.tar.xz
nova-2aadaba580f0253d64a69a5cf4127e50346a34fb.zip
Merge "Add templates for selected resource extensions."
-rw-r--r--nova/api/openstack/v2/contrib/security_groups.py100
-rw-r--r--nova/api/openstack/v2/contrib/simple_tenant_usage.py51
-rw-r--r--nova/api/openstack/v2/contrib/virtual_interfaces.py31
-rw-r--r--nova/api/openstack/v2/contrib/volumes.py130
-rw-r--r--nova/api/openstack/v2/contrib/volumetypes.py81
-rw-r--r--nova/tests/api/openstack/v2/contrib/test_security_groups.py166
-rw-r--r--nova/tests/api/openstack/v2/contrib/test_simple_tenant_usage.py168
-rw-r--r--nova/tests/api/openstack/v2/contrib/test_virtual_interfaces.py43
-rw-r--r--nova/tests/api/openstack/v2/contrib/test_volume_types.py45
-rw-r--r--nova/tests/api/openstack/v2/contrib/test_volume_types_extra_specs.py36
-rw-r--r--nova/tests/api/openstack/v2/contrib/test_volumes.py149
11 files changed, 946 insertions, 54 deletions
diff --git a/nova/api/openstack/v2/contrib/security_groups.py b/nova/api/openstack/v2/contrib/security_groups.py
index 50f129bd6..3c4f0e473 100644
--- a/nova/api/openstack/v2/contrib/security_groups.py
+++ b/nova/api/openstack/v2/contrib/security_groups.py
@@ -24,6 +24,7 @@ import webob
from nova.api.openstack import common
from nova.api.openstack.v2 import extensions
from nova.api.openstack import wsgi
+from nova.api.openstack import xmlutil
from nova import compute
from nova import db
from nova import exception
@@ -355,6 +356,85 @@ class SecurityGroupRulesController(SecurityGroupController):
return webob.Response(status_int=202)
+def make_rule(elem):
+ elem.set('id')
+ elem.set('parent_group_id')
+
+ proto = xmlutil.SubTemplateElement(elem, 'ip_protocol')
+ proto.text = 'ip_protocol'
+
+ from_port = xmlutil.SubTemplateElement(elem, 'from_port')
+ from_port.text = 'from_port'
+
+ to_port = xmlutil.SubTemplateElement(elem, 'to_port')
+ to_port.text = 'to_port'
+
+ group = xmlutil.SubTemplateElement(elem, 'group', selector='group')
+ name = xmlutil.SubTemplateElement(group, 'name')
+ name.text = 'name'
+ tenant_id = xmlutil.SubTemplateElement(group, 'tenant_id')
+ tenant_id.text = 'tenant_id'
+
+ ip_range = xmlutil.SubTemplateElement(elem, 'ip_range',
+ selector='ip_range')
+ cidr = xmlutil.SubTemplateElement(ip_range, 'cidr')
+ cidr.text = 'cidr'
+
+
+def make_sg(elem):
+ elem.set('id')
+ elem.set('tenant_id')
+ elem.set('name')
+
+ desc = xmlutil.SubTemplateElement(elem, 'description')
+ desc.text = 'description'
+
+ rules = xmlutil.SubTemplateElement(elem, 'rules')
+ rule = xmlutil.SubTemplateElement(rules, 'rule', selector='rules')
+ make_rule(rule)
+
+
+sg_nsmap = {None: wsgi.XMLNS_V11}
+
+
+class SecurityGroupRuleTemplate(xmlutil.TemplateBuilder):
+ def construct(self):
+ root = xmlutil.TemplateElement('security_group_rule',
+ selector='security_group_rule')
+ make_rule(root)
+ return xmlutil.MasterTemplate(root, 1, nsmap=sg_nsmap)
+
+
+class SecurityGroupTemplate(xmlutil.TemplateBuilder):
+ def construct(self):
+ root = xmlutil.TemplateElement('security_group',
+ selector='security_group')
+ make_sg(root)
+ return xmlutil.MasterTemplate(root, 1, nsmap=sg_nsmap)
+
+
+class SecurityGroupsTemplate(xmlutil.TemplateBuilder):
+ def construct(self):
+ root = xmlutil.TemplateElement('security_groups')
+ elem = xmlutil.SubTemplateElement(root, 'security_group',
+ selector='security_groups')
+ make_sg(elem)
+ return xmlutil.MasterTemplate(root, 1, nsmap=sg_nsmap)
+
+
+class SecurityGroupXMLSerializer(xmlutil.XMLTemplateSerializer):
+ def index(self):
+ return SecurityGroupsTemplate()
+
+ def default(self):
+ return SecurityGroupTemplate()
+
+
+class SecurityGroupRulesXMLSerializer(xmlutil.XMLTemplateSerializer):
+ def default(self):
+ return SecurityGroupRuleTemplate()
+
+
class Security_groups(extensions.ExtensionDescriptor):
"""Security group support"""
@@ -439,10 +519,8 @@ class Security_groups(extensions.ExtensionDescriptor):
def get_resources(self):
resources = []
- metadata = _get_metadata()
body_serializers = {
- 'application/xml': wsgi.XMLDictSerializer(metadata=metadata,
- xmlns=wsgi.XMLNS_V11),
+ 'application/xml': SecurityGroupXMLSerializer(),
}
serializer = wsgi.ResponseSerializer(body_serializers, None)
@@ -458,6 +536,11 @@ class Security_groups(extensions.ExtensionDescriptor):
resources.append(res)
+ body_serializers = {
+ 'application/xml': SecurityGroupRulesXMLSerializer(),
+ }
+ serializer = wsgi.ResponseSerializer(body_serializers, None)
+
body_deserializers = {
'application/xml': SecurityGroupRulesXMLDeserializer(),
}
@@ -538,14 +621,3 @@ class SecurityGroupRulesXMLDeserializer(wsgi.MetadataXMLDeserializer):
sg_rule['cidr'] = self.extract_text(cidr_node)
return sg_rule
-
-
-def _get_metadata():
- metadata = {
- "attributes": {
- "security_group": ["id", "tenant_id", "name"],
- "rule": ["id", "parent_group_id"],
- "security_group_rule": ["id", "parent_group_id"],
- }
- }
- return metadata
diff --git a/nova/api/openstack/v2/contrib/simple_tenant_usage.py b/nova/api/openstack/v2/contrib/simple_tenant_usage.py
index e896371ed..4204c53bf 100644
--- a/nova/api/openstack/v2/contrib/simple_tenant_usage.py
+++ b/nova/api/openstack/v2/contrib/simple_tenant_usage.py
@@ -23,6 +23,8 @@ from webob import exc
from nova.api.openstack.v2 import extensions
from nova.api.openstack.v2 import views
+from nova.api.openstack import wsgi
+from nova.api.openstack import xmlutil
from nova.compute import api
from nova.db.sqlalchemy.session import get_session
from nova import exception
@@ -211,6 +213,47 @@ class SimpleTenantUsageController(object):
return {'tenant_usage': usage}
+def make_usage(elem):
+ for subelem_tag in ('tenant_id', 'total_local_gb_usage',
+ 'total_vcpus_usage', 'total_memory_mb_usage',
+ 'total_hours', 'start', 'stop'):
+ subelem = xmlutil.SubTemplateElement(elem, subelem_tag)
+ subelem.text = subelem_tag
+
+ server_usages = xmlutil.SubTemplateElement(elem, 'server_usages')
+ server_usage = xmlutil.SubTemplateElement(server_usages, 'server_usage',
+ selector='server_usages')
+ for subelem_tag in ('name', 'hours', 'memory_mb', 'local_gb', 'vcpus',
+ 'tenant_id', 'flavor', 'started_at', 'ended_at',
+ 'state', 'uptime'):
+ subelem = xmlutil.SubTemplateElement(server_usage, subelem_tag)
+ subelem.text = subelem_tag
+
+
+class SimpleTenantUsageTemplate(xmlutil.TemplateBuilder):
+ def construct(self):
+ root = xmlutil.TemplateElement('tenant_usage', selector='tenant_usage')
+ make_usage(root)
+ return xmlutil.MasterTemplate(root, 1)
+
+
+class SimpleTenantUsagesTemplate(xmlutil.TemplateBuilder):
+ def construct(self):
+ root = xmlutil.TemplateElement('tenant_usages')
+ elem = xmlutil.SubTemplateElement(root, 'tenant_usage',
+ selector='tenant_usages')
+ make_usage(elem)
+ return xmlutil.MasterTemplate(root, 1)
+
+
+class SimpleTenantUsageSerializer(xmlutil.XMLTemplateSerializer):
+ def index(self):
+ return SimpleTenantUsagesTemplate()
+
+ def show(self):
+ return SimpleTenantUsageTemplate()
+
+
class Simple_tenant_usage(extensions.ExtensionDescriptor):
"""Simple tenant usage extension"""
@@ -222,8 +265,14 @@ class Simple_tenant_usage(extensions.ExtensionDescriptor):
def get_resources(self):
resources = []
+ body_serializers = {
+ 'application/xml': SimpleTenantUsageSerializer(),
+ }
+ serializer = wsgi.ResponseSerializer(body_serializers)
+
res = extensions.ResourceExtension('os-simple-tenant-usage',
- SimpleTenantUsageController())
+ SimpleTenantUsageController(),
+ serializer=serializer)
resources.append(res)
return resources
diff --git a/nova/api/openstack/v2/contrib/virtual_interfaces.py b/nova/api/openstack/v2/contrib/virtual_interfaces.py
index 1975a8dc0..211b8c9be 100644
--- a/nova/api/openstack/v2/contrib/virtual_interfaces.py
+++ b/nova/api/openstack/v2/contrib/virtual_interfaces.py
@@ -18,6 +18,7 @@
from nova.api.openstack import common
from nova.api.openstack.v2 import extensions
from nova.api.openstack import wsgi
+from nova.api.openstack import xmlutil
from nova import log as logging
from nova import network
@@ -33,13 +34,6 @@ def _translate_vif_summary_view(_context, vif):
return d
-def _get_metadata():
- metadata = {
- "attributes": {
- 'virtual_interface': ["id", "mac_address"]}}
- return metadata
-
-
class ServerVirtualInterfaceController(object):
"""The instance VIF API controller for the Openstack API.
"""
@@ -63,6 +57,24 @@ class ServerVirtualInterfaceController(object):
entity_maker=_translate_vif_summary_view)
+vif_nsmap = {None: wsgi.XMLNS_V11}
+
+
+class VirtualInterfaceTemplate(xmlutil.TemplateBuilder):
+ def construct(self):
+ root = xmlutil.TemplateElement('virtual_interfaces')
+ elem = xmlutil.SubTemplateElement(root, 'virtual_interface',
+ selector='virtual_interfaces')
+ elem.set('id')
+ elem.set('mac_address')
+ return xmlutil.MasterTemplate(root, 1, nsmap=vif_nsmap)
+
+
+class VirtualInterfaceSerializer(xmlutil.XMLTemplateSerializer):
+ def default(self):
+ return VirtualInterfaceTemplate()
+
+
class Virtual_interfaces(extensions.ExtensionDescriptor):
"""Virtual interface support"""
@@ -74,10 +86,9 @@ class Virtual_interfaces(extensions.ExtensionDescriptor):
def get_resources(self):
resources = []
- metadata = _get_metadata()
body_serializers = {
- 'application/xml': wsgi.XMLDictSerializer(metadata=metadata,
- xmlns=wsgi.XMLNS_V11)}
+ 'application/xml': VirtualInterfaceSerializer()
+ }
serializer = wsgi.ResponseSerializer(body_serializers, None)
res = extensions.ResourceExtension(
'os-virtual-interfaces',
diff --git a/nova/api/openstack/v2/contrib/volumes.py b/nova/api/openstack/v2/contrib/volumes.py
index 5d86282f2..75d8af803 100644
--- a/nova/api/openstack/v2/contrib/volumes.py
+++ b/nova/api/openstack/v2/contrib/volumes.py
@@ -21,6 +21,8 @@ import webob
from nova.api.openstack import common
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 import db
from nova import exception
@@ -86,21 +88,6 @@ def _translate_volume_summary_view(context, vol):
class VolumeController(object):
"""The Volumes API controller for the OpenStack API."""
- _serialization_metadata = {
- 'application/xml': {
- "attributes": {
- "volume": [
- "id",
- "status",
- "size",
- "availabilityZone",
- "createdAt",
- "displayName",
- "displayDescription",
- "volumeType",
- "metadata",
- ]}}}
-
def __init__(self):
self.volume_api = volume.API()
super(VolumeController, self).__init__()
@@ -180,6 +167,51 @@ class VolumeController(object):
return {'volume': retval}
+def make_volume(elem):
+ elem.set('id')
+ elem.set('status')
+ elem.set('size')
+ elem.set('availabilityZone')
+ elem.set('createdAt')
+ elem.set('displayName')
+ elem.set('displayDescription')
+ elem.set('volumeType')
+
+ attachments = xmlutil.SubTemplateElement(elem, 'attachments')
+ attachment = xmlutil.SubTemplateElement(attachments, 'attachment',
+ selector='attachments')
+ make_attachment(attachment)
+
+ metadata = xmlutil.make_flat_dict('metadata')
+ elem.append(metadata)
+
+
+class VolumeTemplate(xmlutil.TemplateBuilder):
+ def construct(self):
+ root = xmlutil.TemplateElement('volume', selector='volume')
+ make_volume(root)
+ return xmlutil.MasterTemplate(root, 1)
+
+
+class VolumesTemplate(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 VolumeSerializer(xmlutil.XMLTemplateSerializer):
+ def default(self):
+ return VolumeTemplate()
+
+ def index(self):
+ return VolumesTemplate()
+
+ def detail(self):
+ return VolumesTemplate()
+
+
def _translate_attachment_detail_view(_context, vol):
"""Maps keys for attachment details view."""
@@ -216,14 +248,6 @@ class VolumeAttachmentController(object):
"""
- _serialization_metadata = {
- 'application/xml': {
- 'attributes': {
- 'volumeAttachment': ['id',
- 'serverId',
- 'volumeId',
- 'device']}}}
-
def __init__(self):
self.compute_api = compute.API()
self.volume_api = volume.API()
@@ -331,6 +355,38 @@ class VolumeAttachmentController(object):
return {'volumeAttachments': res}
+def make_attachment(elem):
+ elem.set('id')
+ elem.set('serverId')
+ elem.set('volumeId')
+ elem.set('device')
+
+
+class VolumeAttachmentTemplate(xmlutil.TemplateBuilder):
+ def construct(self):
+ root = xmlutil.TemplateElement('volumeAttachment',
+ selector='volumeAttachment')
+ make_attachment(root)
+ return xmlutil.MasterTemplate(root, 1)
+
+
+class VolumeAttachmentsTemplate(xmlutil.TemplateBuilder):
+ def construct(self):
+ root = xmlutil.TemplateElement('volumeAttachments')
+ elem = xmlutil.SubTemplateElement(root, 'volumeAttachment',
+ selector='volumeAttachments')
+ make_attachment(elem)
+ return xmlutil.MasterTemplate(root, 1)
+
+
+class VolumeAttachmentSerializer(xmlutil.XMLTemplateSerializer):
+ def default(self):
+ return VolumeAttachmentTemplate()
+
+ def index(self):
+ return VolumeAttachmentsTemplate()
+
+
class BootFromVolumeController(servers.Controller):
"""The boot from volume API controller for the Openstack API."""
@@ -349,22 +405,48 @@ class Volumes(extensions.ExtensionDescriptor):
def get_resources(self):
resources = []
+ body_serializers = {
+ 'application/xml': VolumeSerializer(),
+ }
+ serializer = wsgi.ResponseSerializer(body_serializers)
+
# NOTE(justinsb): No way to provide singular name ('volume')
# Does this matter?
res = extensions.ResourceExtension('os-volumes',
VolumeController(),
+ serializer=serializer,
collection_actions={'detail': 'GET'})
resources.append(res)
+ body_serializers = {
+ 'application/xml': VolumeAttachmentSerializer(),
+ }
+ serializer = wsgi.ResponseSerializer(body_serializers)
+
res = extensions.ResourceExtension('os-volume_attachments',
VolumeAttachmentController(),
+ serializer=serializer,
parent=dict(
member_name='server',
collection_name='servers'))
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('os-volumes_boot',
- BootFromVolumeController())
+ BootFromVolumeController(),
+ serializer=serializer,
+ deserializer=deserializer)
resources.append(res)
return resources
diff --git a/nova/api/openstack/v2/contrib/volumetypes.py b/nova/api/openstack/v2/contrib/volumetypes.py
index ca3866c99..24ac87d01 100644
--- a/nova/api/openstack/v2/contrib/volumetypes.py
+++ b/nova/api/openstack/v2/contrib/volumetypes.py
@@ -21,6 +21,7 @@ from webob import exc
from nova.api.openstack.v2 import extensions
from nova.api.openstack import wsgi
+from nova.api.openstack import xmlutil
from nova import db
from nova import exception
from nova.volume import volume_types
@@ -89,6 +90,37 @@ class VolumeTypesController(object):
raise error
+def make_voltype(elem):
+ elem.set('id')
+ elem.set('name')
+ extra_specs = xmlutil.make_flat_dict('extra_specs', selector='extra_specs')
+ elem.append(extra_specs)
+
+
+class VolumeTypeTemplate(xmlutil.TemplateBuilder):
+ def construct(self):
+ root = xmlutil.TemplateElement('volume_type', selector='volume_type')
+ make_voltype(root)
+ return xmlutil.MasterTemplate(root, 1)
+
+
+class VolumeTypesTemplate(xmlutil.TemplateBuilder):
+ def construct(self):
+ root = xmlutil.TemplateElement('volume_types')
+ sel = lambda obj, do_raise=False: obj.values()
+ elem = xmlutil.SubTemplateElement(root, 'volume_type', selector=sel)
+ make_voltype(elem)
+ return xmlutil.MasterTemplate(root, 1)
+
+
+class VolumeTypesSerializer(xmlutil.XMLTemplateSerializer):
+ def index(self):
+ return VolumeTypesTemplate()
+
+ def default(self):
+ return VolumeTypeTemplate()
+
+
class VolumeTypeExtraSpecsController(object):
""" The volume type extra specs API controller for the Openstack API """
@@ -160,6 +192,40 @@ class VolumeTypeExtraSpecsController(object):
raise error
+class VolumeTypeExtraSpecsTemplate(xmlutil.TemplateBuilder):
+ def construct(self):
+ root = xmlutil.make_flat_dict('extra_specs', selector='extra_specs')
+ return xmlutil.MasterTemplate(root, 1)
+
+
+class VolumeTypeExtraSpecTemplate(xmlutil.TemplateBuilder):
+ def construct(self):
+ tagname = xmlutil.Selector('key')
+
+ def extraspec_sel(obj, do_raise=False):
+ # Have to extract the key and value for later use...
+ key, value = obj.items()[0]
+ return dict(key=key, value=value)
+
+ root = xmlutil.TemplateElement(tagname, selector=extraspec_sel)
+ root.text = 'value'
+ return xmlutil.MasterTemplate(root, 1)
+
+
+class VolumeTypeExtraSpecsSerializer(xmlutil.XMLTemplateSerializer):
+ def index(self):
+ return VolumeTypeExtraSpecsTemplate()
+
+ def create(self):
+ return VolumeTypeExtraSpecsTemplate()
+
+ def update(self):
+ return VolumeTypeExtraSpecTemplate()
+
+ def show(self):
+ return VolumeTypeExtraSpecTemplate()
+
+
class Volumetypes(extensions.ExtensionDescriptor):
"""Volume types support"""
@@ -170,13 +236,26 @@ class Volumetypes(extensions.ExtensionDescriptor):
def get_resources(self):
resources = []
+
+ body_serializers = {
+ 'application/xml': VolumeTypesSerializer(),
+ }
+ serializer = wsgi.ResponseSerializer(body_serializers)
+
res = extensions.ResourceExtension(
'os-volume-types',
- VolumeTypesController())
+ VolumeTypesController(),
+ serializer=serializer)
resources.append(res)
+ body_serializers = {
+ 'application/xml': VolumeTypeExtraSpecsSerializer(),
+ }
+ serializer = wsgi.ResponseSerializer(body_serializers)
+
res = extensions.ResourceExtension('extra_specs',
VolumeTypeExtraSpecsController(),
+ serializer=serializer,
parent=dict(
member_name='vol_type',
collection_name='os-volume-types'))
diff --git a/nova/tests/api/openstack/v2/contrib/test_security_groups.py b/nova/tests/api/openstack/v2/contrib/test_security_groups.py
index 9055e1bca..b4ef608d8 100644
--- a/nova/tests/api/openstack/v2/contrib/test_security_groups.py
+++ b/nova/tests/api/openstack/v2/contrib/test_security_groups.py
@@ -16,10 +16,12 @@
import unittest
+from lxml import etree
import mox
import webob
from nova.api.openstack.v2.contrib import security_groups
+from nova.api.openstack import wsgi
import nova.db
from nova import exception
from nova import utils
@@ -845,3 +847,167 @@ class TestSecurityGroupXMLDeserializer(unittest.TestCase):
},
}
self.assertEquals(request['body'], expected)
+
+
+class TestSecurityGroupXMLSerializer(unittest.TestCase):
+ def setUp(self):
+ self.namespace = wsgi.XMLNS_V11
+ tmp = security_groups.SecurityGroupRulesXMLSerializer()
+ self.rule_serializer = tmp
+ self.group_serializer = security_groups.SecurityGroupXMLSerializer()
+
+ def _tag(self, elem):
+ tagname = elem.tag
+ self.assertEqual(tagname[0], '{')
+ tmp = tagname.partition('}')
+ namespace = tmp[0][1:]
+ self.assertEqual(namespace, self.namespace)
+ return tmp[2]
+
+ def _verify_security_group_rule(self, raw_rule, tree):
+ self.assertEqual(raw_rule['id'], tree.get('id'))
+ self.assertEqual(raw_rule['parent_group_id'],
+ tree.get('parent_group_id'))
+
+ seen = set()
+ expected = set(['ip_protocol', 'from_port', 'to_port',
+ 'group', 'group/name', 'group/tenant_id',
+ 'ip_range', 'ip_range/cidr'])
+
+ for child in tree:
+ child_tag = self._tag(child)
+ self.assertTrue(child_tag in raw_rule)
+ seen.add(child_tag)
+ if child_tag in ('group', 'ip_range'):
+ for gr_child in child:
+ gr_child_tag = self._tag(gr_child)
+ self.assertTrue(gr_child_tag in raw_rule[child_tag])
+ seen.add('%s/%s' % (child_tag, gr_child_tag))
+ self.assertEqual(gr_child.text,
+ raw_rule[child_tag][gr_child_tag])
+ else:
+ self.assertEqual(child.text, raw_rule[child_tag])
+ self.assertEqual(seen, expected)
+
+ def _verify_security_group(self, raw_group, tree):
+ rules = raw_group['rules']
+ self.assertEqual('security_group', self._tag(tree))
+ self.assertEqual(raw_group['id'], tree.get('id'))
+ self.assertEqual(raw_group['tenant_id'], tree.get('tenant_id'))
+ self.assertEqual(raw_group['name'], tree.get('name'))
+ self.assertEqual(2, len(tree))
+ for child in tree:
+ child_tag = self._tag(child)
+ if child_tag == 'rules':
+ self.assertEqual(2, len(child))
+ for idx, gr_child in enumerate(child):
+ self.assertEqual(self._tag(gr_child), 'rule')
+ self._verify_security_group_rule(rules[idx], gr_child)
+ else:
+ self.assertEqual('description', child_tag)
+ self.assertEqual(raw_group['description'], child.text)
+
+ def test_rule_serializer(self):
+ raw_rule = dict(
+ id='123',
+ parent_group_id='456',
+ ip_protocol='tcp',
+ from_port='789',
+ to_port='987',
+ group=dict(name='group', tenant_id='tenant'),
+ ip_range=dict(cidr='10.0.0.0/8'))
+ rule = dict(security_group_rule=raw_rule)
+ text = self.rule_serializer.serialize(rule)
+
+ print text
+ tree = etree.fromstring(text)
+
+ self.assertEqual('security_group_rule', self._tag(tree))
+ self._verify_security_group_rule(raw_rule, tree)
+
+ def test_group_serializer(self):
+ rules = [dict(
+ id='123',
+ parent_group_id='456',
+ ip_protocol='tcp',
+ from_port='789',
+ to_port='987',
+ group=dict(name='group1', tenant_id='tenant1'),
+ ip_range=dict(cidr='10.55.44.0/24')),
+ dict(
+ id='654',
+ parent_group_id='321',
+ ip_protocol='udp',
+ from_port='234',
+ to_port='567',
+ group=dict(name='group2', tenant_id='tenant2'),
+ ip_range=dict(cidr='10.44.55.0/24'))]
+ raw_group = dict(
+ id='890',
+ description='description',
+ name='name',
+ tenant_id='tenant',
+ rules=rules)
+ sg_group = dict(security_group=raw_group)
+ text = self.group_serializer.serialize(sg_group)
+
+ print text
+ tree = etree.fromstring(text)
+
+ self._verify_security_group(raw_group, tree)
+
+ def test_groups_serializer(self):
+ rules = [dict(
+ id='123',
+ parent_group_id='1234',
+ ip_protocol='tcp',
+ from_port='12345',
+ to_port='123456',
+ group=dict(name='group1', tenant_id='tenant1'),
+ ip_range=dict(cidr='10.123.0.0/24')),
+ dict(
+ id='234',
+ parent_group_id='2345',
+ ip_protocol='udp',
+ from_port='23456',
+ to_port='234567',
+ group=dict(name='group2', tenant_id='tenant2'),
+ ip_range=dict(cidr='10.234.0.0/24')),
+ dict(
+ id='345',
+ parent_group_id='3456',
+ ip_protocol='tcp',
+ from_port='34567',
+ to_port='345678',
+ group=dict(name='group3', tenant_id='tenant3'),
+ ip_range=dict(cidr='10.345.0.0/24')),
+ dict(
+ id='456',
+ parent_group_id='4567',
+ ip_protocol='udp',
+ from_port='45678',
+ to_port='456789',
+ group=dict(name='group4', tenant_id='tenant4'),
+ ip_range=dict(cidr='10.456.0.0/24'))]
+ groups = [dict(
+ id='567',
+ description='description1',
+ name='name1',
+ tenant_id='tenant1',
+ rules=rules[0:2]),
+ dict(
+ id='678',
+ description='description2',
+ name='name2',
+ tenant_id='tenant2',
+ rules=rules[2:4])]
+ sg_groups = dict(security_groups=groups)
+ text = self.group_serializer.serialize(sg_groups, 'index')
+
+ print text
+ tree = etree.fromstring(text)
+
+ self.assertEqual('security_groups', self._tag(tree))
+ self.assertEqual(len(groups), len(tree))
+ for idx, child in enumerate(tree):
+ self._verify_security_group(groups[idx], child)
diff --git a/nova/tests/api/openstack/v2/contrib/test_simple_tenant_usage.py b/nova/tests/api/openstack/v2/contrib/test_simple_tenant_usage.py
index 56d8de7d2..5d36518a6 100644
--- a/nova/tests/api/openstack/v2/contrib/test_simple_tenant_usage.py
+++ b/nova/tests/api/openstack/v2/contrib/test_simple_tenant_usage.py
@@ -17,8 +17,11 @@
import datetime
import json
+
+from lxml import etree
import webob
+from nova.api.openstack.v2.contrib import simple_tenant_usage
from nova.compute import api
from nova import context
from nova import flags
@@ -170,3 +173,168 @@ class SimpleTenantUsageTest(test.TestCase):
res = req.get_response(fakes.wsgi_app(
fake_auth_context=self.alt_user_context))
self.assertEqual(res.status_int, 403)
+
+
+class SimpleTenantUsageSerializerTest(test.TestCase):
+ def setUp(self):
+ super(SimpleTenantUsageSerializerTest, self).setUp()
+ self.serializer = simple_tenant_usage.SimpleTenantUsageSerializer()
+
+ def _verify_server_usage(self, raw_usage, tree):
+ self.assertEqual('server_usage', tree.tag)
+
+ # Figure out what fields we expect
+ not_seen = set(raw_usage.keys())
+
+ for child in tree:
+ self.assertTrue(child.tag in not_seen)
+ not_seen.remove(child.tag)
+ self.assertEqual(str(raw_usage[child.tag]), child.text)
+
+ self.assertEqual(len(not_seen), 0)
+
+ def _verify_tenant_usage(self, raw_usage, tree):
+ self.assertEqual('tenant_usage', tree.tag)
+
+ # Figure out what fields we expect
+ not_seen = set(raw_usage.keys())
+
+ for child in tree:
+ self.assertTrue(child.tag in not_seen)
+ not_seen.remove(child.tag)
+ if child.tag == 'server_usages':
+ for idx, gr_child in enumerate(child):
+ self._verify_server_usage(raw_usage['server_usages'][idx],
+ gr_child)
+ else:
+ self.assertEqual(str(raw_usage[child.tag]), child.text)
+
+ self.assertEqual(len(not_seen), 0)
+
+ def test_serializer_show(self):
+ today = datetime.datetime.now()
+ yesterday = today - datetime.timedelta(days=1)
+ raw_usage = dict(
+ tenant_id='tenant',
+ total_local_gb_usage=789,
+ total_vcpus_usage=456,
+ total_memory_mb_usage=123,
+ total_hours=24,
+ start=yesterday,
+ stop=today,
+ server_usages=[dict(
+ name='test',
+ hours=24,
+ memory_mb=1024,
+ local_gb=50,
+ vcpus=1,
+ tenant_id='tenant',
+ flavor='m1.small',
+ started_at=yesterday,
+ ended_at=today,
+ state='terminated',
+ uptime=86400),
+ dict(
+ name='test2',
+ hours=12,
+ memory_mb=512,
+ local_gb=25,
+ vcpus=2,
+ tenant_id='tenant',
+ flavor='m1.tiny',
+ started_at=yesterday,
+ ended_at=today,
+ state='terminated',
+ uptime=43200),
+ ],
+ )
+ tenant_usage = dict(tenant_usage=raw_usage)
+ text = self.serializer.serialize(tenant_usage, 'show')
+
+ print text
+ tree = etree.fromstring(text)
+
+ self._verify_tenant_usage(raw_usage, tree)
+
+ def test_serializer_index(self):
+ today = datetime.datetime.now()
+ yesterday = today - datetime.timedelta(days=1)
+ raw_usages = [dict(
+ tenant_id='tenant1',
+ total_local_gb_usage=1024,
+ total_vcpus_usage=23,
+ total_memory_mb_usage=512,
+ total_hours=24,
+ start=yesterday,
+ stop=today,
+ server_usages=[dict(
+ name='test1',
+ hours=24,
+ memory_mb=1024,
+ local_gb=50,
+ vcpus=2,
+ tenant_id='tenant1',
+ flavor='m1.small',
+ started_at=yesterday,
+ ended_at=today,
+ state='terminated',
+ uptime=86400),
+ dict(
+ name='test2',
+ hours=42,
+ memory_mb=4201,
+ local_gb=25,
+ vcpus=1,
+ tenant_id='tenant1',
+ flavor='m1.tiny',
+ started_at=today,
+ ended_at=yesterday,
+ state='terminated',
+ uptime=43200),
+ ],
+ ),
+ dict(
+ tenant_id='tenant2',
+ total_local_gb_usage=512,
+ total_vcpus_usage=32,
+ total_memory_mb_usage=1024,
+ total_hours=42,
+ start=today,
+ stop=yesterday,
+ server_usages=[dict(
+ name='test3',
+ hours=24,
+ memory_mb=1024,
+ local_gb=50,
+ vcpus=2,
+ tenant_id='tenant2',
+ flavor='m1.small',
+ started_at=yesterday,
+ ended_at=today,
+ state='terminated',
+ uptime=86400),
+ dict(
+ name='test2',
+ hours=42,
+ memory_mb=4201,
+ local_gb=25,
+ vcpus=1,
+ tenant_id='tenant4',
+ flavor='m1.tiny',
+ started_at=today,
+ ended_at=yesterday,
+ state='terminated',
+ uptime=43200),
+ ],
+ ),
+ ]
+ tenant_usages = dict(tenant_usages=raw_usages)
+ text = self.serializer.serialize(tenant_usages, 'index')
+
+ print text
+ tree = etree.fromstring(text)
+
+ self.assertEqual('tenant_usages', tree.tag)
+ self.assertEqual(len(raw_usages), len(tree))
+ for idx, child in enumerate(tree):
+ self._verify_tenant_usage(raw_usages[idx], child)
diff --git a/nova/tests/api/openstack/v2/contrib/test_virtual_interfaces.py b/nova/tests/api/openstack/v2/contrib/test_virtual_interfaces.py
index 3e03fed34..47f085b00 100644
--- a/nova/tests/api/openstack/v2/contrib/test_virtual_interfaces.py
+++ b/nova/tests/api/openstack/v2/contrib/test_virtual_interfaces.py
@@ -15,10 +15,11 @@
import json
+from lxml import etree
import webob
-from nova.api.openstack.v2.contrib.virtual_interfaces import \
- ServerVirtualInterfaceController
+from nova.api.openstack.v2.contrib import virtual_interfaces
+from nova.api.openstack import wsgi
from nova import network
from nova import test
from nova.tests.api.openstack import fakes
@@ -35,7 +36,7 @@ class ServerVirtualInterfaceTest(test.TestCase):
def setUp(self):
super(ServerVirtualInterfaceTest, self).setUp()
- self.controller = ServerVirtualInterfaceController()
+ self.controller = virtual_interfaces.ServerVirtualInterfaceController()
self.stubs.Set(network.api.API, "get_vifs_by_instance",
get_vifs_by_instance)
@@ -54,3 +55,39 @@ class ServerVirtualInterfaceTest(test.TestCase):
{'id': '11111111-1111-1111-1111-11111111111111111',
'mac_address': '11-11-11-11-11-11'}]}
self.assertEqual(res_dict, response)
+
+
+class ServerVirtualInterfaceSerializerTest(test.TestCase):
+ def setUp(self):
+ super(ServerVirtualInterfaceSerializerTest, self).setUp()
+ self.namespace = wsgi.XMLNS_V11
+ self.serializer = virtual_interfaces.VirtualInterfaceSerializer()
+
+ def _tag(self, elem):
+ tagname = elem.tag
+ self.assertEqual(tagname[0], '{')
+ tmp = tagname.partition('}')
+ namespace = tmp[0][1:]
+ self.assertEqual(namespace, self.namespace)
+ return tmp[2]
+
+ def test_serializer(self):
+ raw_vifs = [dict(
+ id='uuid1',
+ mac_address='aa:bb:cc:dd:ee:ff'),
+ dict(
+ id='uuid2',
+ mac_address='bb:aa:dd:cc:ff:ee')]
+ vifs = dict(virtual_interfaces=raw_vifs)
+ text = self.serializer.serialize(vifs)
+
+ print text
+ tree = etree.fromstring(text)
+
+ self.assertEqual('virtual_interfaces', self._tag(tree))
+ self.assertEqual(len(raw_vifs), len(tree))
+ for idx, child in enumerate(tree):
+ self.assertEqual('virtual_interface', self._tag(child))
+ self.assertEqual(raw_vifs[idx]['id'], child.get('id'))
+ self.assertEqual(raw_vifs[idx]['mac_address'],
+ child.get('mac_address'))
diff --git a/nova/tests/api/openstack/v2/contrib/test_volume_types.py b/nova/tests/api/openstack/v2/contrib/test_volume_types.py
index db7b4ee71..4343a6d04 100644
--- a/nova/tests/api/openstack/v2/contrib/test_volume_types.py
+++ b/nova/tests/api/openstack/v2/contrib/test_volume_types.py
@@ -13,6 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+from lxml import etree
import webob
from nova.api.openstack.v2.contrib import volumetypes
@@ -162,3 +163,47 @@ class VolumeTypesApiTest(test.TestCase):
req = fakes.HTTPRequest.blank('/v2/123/os-volume-types')
self.assertRaises(webob.exc.HTTPUnprocessableEntity,
self.controller.create, req, '')
+
+
+class VolumeTypesSerializerTest(test.TestCase):
+ def setUp(self):
+ super(VolumeTypesSerializerTest, self).setUp()
+ self.serializer = volumetypes.VolumeTypesSerializer()
+
+ def _verify_volume_type(self, vtype, tree):
+ self.assertEqual('volume_type', tree.tag)
+ self.assertEqual(vtype['name'], tree.get('name'))
+ self.assertEqual(str(vtype['id']), tree.get('id'))
+ self.assertEqual(1, len(tree))
+ extra_specs = tree[0]
+ self.assertEqual('extra_specs', extra_specs.tag)
+ seen = set(vtype['extra_specs'].keys())
+ for child in extra_specs:
+ self.assertTrue(child.tag in seen)
+ self.assertEqual(vtype['extra_specs'][child.tag], child.text)
+ seen.remove(child.tag)
+ self.assertEqual(len(seen), 0)
+
+ def test_index_serializer(self):
+ # Just getting some input data
+ vtypes = return_volume_types_get_all_types(None)
+ text = self.serializer.serialize(vtypes, 'index')
+
+ print text
+ tree = etree.fromstring(text)
+
+ self.assertEqual('volume_types', tree.tag)
+ self.assertEqual(len(vtypes), len(tree))
+ for child in tree:
+ name = child.get('name')
+ self.assertTrue(name in vtypes)
+ self._verify_volume_type(vtypes[name], child)
+
+ def test_voltype_serializer(self):
+ vtype = stub_volume_type(1)
+ text = self.serializer.serialize(dict(volume_type=vtype))
+
+ print text
+ tree = etree.fromstring(text)
+
+ self._verify_volume_type(vtype, tree)
diff --git a/nova/tests/api/openstack/v2/contrib/test_volume_types_extra_specs.py b/nova/tests/api/openstack/v2/contrib/test_volume_types_extra_specs.py
index 9947ff9c1..41b50118f 100644
--- a/nova/tests/api/openstack/v2/contrib/test_volume_types_extra_specs.py
+++ b/nova/tests/api/openstack/v2/contrib/test_volume_types_extra_specs.py
@@ -17,6 +17,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+from lxml import etree
import webob
from nova.api.openstack.v2.contrib import volumetypes
@@ -161,3 +162,38 @@ class VolumeTypesExtraSpecsTest(test.TestCase):
req = fakes.HTTPRequest.blank(self.api_path + '/bad')
self.assertRaises(webob.exc.HTTPBadRequest, self.controller.update,
req, 1, 'bad', body)
+
+
+class VolumeTypeExtraSpecsSerializerTest(test.TestCase):
+ def setUp(self):
+ super(VolumeTypeExtraSpecsSerializerTest, self).setUp()
+ self.serializer = volumetypes.VolumeTypeExtraSpecsSerializer()
+
+ def test_index_create_serializer(self):
+ # Just getting some input data
+ extra_specs = stub_volume_type_extra_specs()
+ text = self.serializer.serialize(dict(extra_specs=extra_specs),
+ 'index')
+
+ print text
+ tree = etree.fromstring(text)
+
+ self.assertEqual('extra_specs', tree.tag)
+ self.assertEqual(len(extra_specs), len(tree))
+ seen = set(extra_specs.keys())
+ for child in tree:
+ self.assertTrue(child.tag in seen)
+ self.assertEqual(extra_specs[child.tag], child.text)
+ seen.remove(child.tag)
+ self.assertEqual(len(seen), 0)
+
+ def test_update_show_serializer(self):
+ exemplar = dict(key1='value1')
+ text = self.serializer.serialize(exemplar, 'update')
+
+ print text
+ tree = etree.fromstring(text)
+
+ self.assertEqual('key1', tree.tag)
+ self.assertEqual('value1', tree.text)
+ self.assertEqual(0, len(tree))
diff --git a/nova/tests/api/openstack/v2/contrib/test_volumes.py b/nova/tests/api/openstack/v2/contrib/test_volumes.py
index 2842b5151..f0e7a03b7 100644
--- a/nova/tests/api/openstack/v2/contrib/test_volumes.py
+++ b/nova/tests/api/openstack/v2/contrib/test_volumes.py
@@ -16,9 +16,11 @@
import datetime
import json
+from lxml import etree
import webob
import nova
+from nova.api.openstack.v2.contrib import volumes
from nova.compute import instance_types
from nova import flags
from nova import test
@@ -79,7 +81,7 @@ class BootFromVolumeTest(test.TestCase):
req.body = json.dumps(body)
req.headers['content-type'] = 'application/json'
res = req.get_response(fakes.wsgi_app())
- self.assertEqual(res.status_int, 200)
+ self.assertEqual(res.status_int, 202)
server = json.loads(res.body)['server']
self.assertEqual(FAKE_UUID, server['id'])
self.assertEqual(FLAGS.password_length, len(server['adminPass']))
@@ -87,3 +89,148 @@ class BootFromVolumeTest(test.TestCase):
self.assertEqual(_block_device_mapping_seen[0]['volume_id'], 1)
self.assertEqual(_block_device_mapping_seen[0]['device_name'],
'/dev/vda')
+
+
+class VolumeSerializerTest(test.TestCase):
+ def _verify_volume_attachment(self, attach, tree):
+ for attr in ('id', 'volumeId', 'serverId', 'device'):
+ self.assertEqual(str(attach[attr]), tree.get(attr))
+
+ def _verify_volume(self, vol, tree):
+ self.assertEqual(tree.tag, 'volume')
+
+ for attr in ('id', 'status', 'size', 'availabilityZone', 'createdAt',
+ 'displayName', 'displayDescription', 'volumeType'):
+ self.assertEqual(str(vol[attr]), tree.get(attr))
+
+ 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_volume_attachment(vol['attachments'][0], child[0])
+ 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_attach_show_create_serializer(self):
+ serializer = volumes.VolumeAttachmentSerializer()
+ raw_attach = dict(
+ id='vol_id',
+ volumeId='vol_id',
+ serverId='instance_uuid',
+ device='/foo')
+ text = serializer.serialize(dict(volumeAttachment=raw_attach), 'show')
+
+ print text
+ tree = etree.fromstring(text)
+
+ self.assertEqual('volumeAttachment', tree.tag)
+ self._verify_volume_attachment(raw_attach, tree)
+
+ def test_attach_index_serializer(self):
+ serializer = volumes.VolumeAttachmentSerializer()
+ raw_attaches = [dict(
+ id='vol_id1',
+ volumeId='vol_id1',
+ serverId='instance1_uuid',
+ device='/foo1'),
+ dict(
+ id='vol_id2',
+ volumeId='vol_id2',
+ serverId='instance2_uuid',
+ device='/foo2')]
+ text = serializer.serialize(dict(volumeAttachments=raw_attaches),
+ 'index')
+
+ print text
+ tree = etree.fromstring(text)
+
+ self.assertEqual('volumeAttachments', tree.tag)
+ self.assertEqual(len(raw_attaches), len(tree))
+ for idx, child in enumerate(tree):
+ self.assertEqual('volumeAttachment', child.tag)
+ self._verify_volume_attachment(raw_attaches[idx], child)
+
+ def test_volume_show_create_serializer(self):
+ serializer = volumes.VolumeSerializer()
+ 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',
+ ),
+ )
+ text = serializer.serialize(dict(volume=raw_volume), 'show')
+
+ print text
+ tree = etree.fromstring(text)
+
+ self._verify_volume(raw_volume, tree)
+
+ def test_volume_index_detail_serializer(self):
+ serializer = volumes.VolumeSerializer()
+ 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',
+ ),
+ ),
+ 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',
+ ),
+ )]
+ text = serializer.serialize(dict(volumes=raw_volumes), 'index')
+
+ print text
+ tree = etree.fromstring(text)
+
+ self.assertEqual('volumes', tree.tag)
+ self.assertEqual(len(raw_volumes), len(tree))
+ for idx, child in enumerate(tree):
+ self._verify_volume(raw_volumes[idx], child)