diff --git a/contrib/tempest/tempest/api/share/test_extensions.py b/contrib/tempest/tempest/api/share/test_extensions.py index c6d1712d5d..4520755ea3 100644 --- a/contrib/tempest/tempest/api/share/test_extensions.py +++ b/contrib/tempest/tempest/api/share/test_extensions.py @@ -27,5 +27,5 @@ class ExtensionsTest(base.BaseSharesTest): # verify response self.assertIn(int(resp["status"]), self.HTTP_SUCCESS) - keys = ["alias", "updated", "namespace", "name", "description"] + keys = ["alias", "updated", "name", "description"] [self.assertIn(key, ext.keys()) for ext in extensions for key in keys] diff --git a/manila/api/common.py b/manila/api/common.py index c3146bd281..bff254481e 100644 --- a/manila/api/common.py +++ b/manila/api/common.py @@ -22,10 +22,7 @@ import six from six.moves.urllib import parse import webob -from manila.api.openstack import wsgi -from manila.api import xmlutil from manila.i18n import _ -from manila import utils api_common_opts = [ cfg.IntOpt( @@ -41,7 +38,6 @@ api_common_opts = [ CONF = cfg.CONF CONF.register_opts(api_common_opts) LOG = log.getLogger(__name__) -XML_NS_V1 = 'http://docs.openstack.org/volume/api/v1' # Regex that matches alphanumeric characters, periods, hypens, @@ -267,78 +263,6 @@ class ViewBuilder(object): return parse.urlunsplit(url_parts) -class MetadataDeserializer(wsgi.MetadataXMLDeserializer): - def deserialize(self, text): - dom = utils.safe_minidom_parse_string(text) - metadata_node = self.find_first_child_named(dom, "metadata") - metadata = self.extract_metadata(metadata_node) - return {'body': {'metadata': metadata}} - - -class MetaItemDeserializer(wsgi.MetadataXMLDeserializer): - def deserialize(self, text): - dom = utils.safe_minidom_parse_string(text) - metadata_item = self.extract_metadata(dom) - return {'body': {'meta': metadata_item}} - - -class MetadataXMLDeserializer(wsgi.XMLDeserializer): - - def extract_metadata(self, metadata_node): - """Marshal the metadata attribute of a parsed request.""" - if metadata_node is None: - return {} - metadata = {} - for meta_node in self.find_children_named(metadata_node, "meta"): - key = meta_node.getAttribute("key") - metadata[key] = self.extract_text(meta_node) - return metadata - - def _extract_metadata_container(self, datastring): - dom = utils.safe_minidom_parse_string(datastring) - metadata_node = self.find_first_child_named(dom, "metadata") - metadata = self.extract_metadata(metadata_node) - return {'body': {'metadata': metadata}} - - def create(self, datastring): - return self._extract_metadata_container(datastring) - - def update_all(self, datastring): - return self._extract_metadata_container(datastring) - - def update(self, datastring): - dom = utils.safe_minidom_parse_string(datastring) - metadata_item = self.extract_metadata(dom) - return {'body': {'meta': metadata_item}} - - -metadata_nsmap = {None: xmlutil.XMLNS_V11} - - -class MetaItemTemplate(xmlutil.TemplateBuilder): - def construct(self): - sel = xmlutil.Selector('meta', xmlutil.get_items, 0) - root = xmlutil.TemplateElement('meta', selector=sel) - root.set('key', 0) - root.text = 1 - return xmlutil.MasterTemplate(root, 1, nsmap=metadata_nsmap) - - -class MetadataTemplateElement(xmlutil.TemplateElement): - def will_render(self, datum): - return True - - -class MetadataTemplate(xmlutil.TemplateBuilder): - def construct(self): - root = MetadataTemplateElement('metadata', selector='metadata') - elem = xmlutil.SubTemplateElement(root, 'meta', - selector=xmlutil.get_items) - elem.set('key', 0) - elem.text = 1 - return xmlutil.MasterTemplate(root, 1, nsmap=metadata_nsmap) - - def remove_invalid_options(context, search_options, allowed_search_options): """Remove search options that are not valid for non-admin API/context.""" if context.is_admin: diff --git a/manila/api/contrib/admin_actions.py b/manila/api/contrib/admin_actions.py index dd9f0d20f3..d42764b4e9 100644 --- a/manila/api/contrib/admin_actions.py +++ b/manila/api/contrib/admin_actions.py @@ -131,7 +131,6 @@ class Admin_actions(extensions.ExtensionDescriptor): name = "AdminActions" alias = "os-admin-actions" - namespace = "http://docs.openstack.org/share/ext/admin-actions/api/v1.1" updated = "2012-08-25T00:00:00+00:00" def get_controller_extensions(self): diff --git a/manila/api/contrib/extended_quotas.py b/manila/api/contrib/extended_quotas.py index 82efeeeac6..b2c5e50f53 100644 --- a/manila/api/contrib/extended_quotas.py +++ b/manila/api/contrib/extended_quotas.py @@ -25,6 +25,4 @@ class Extended_quotas(extensions.ExtensionDescriptor): name = "ExtendedQuotas" alias = "os-extended-quotas" - namespace = ("http://docs.openstack.org/compute/ext/extended_quotas" - "/api/v1.1") updated = "2013-06-09T00:00:00+00:00" diff --git a/manila/api/contrib/quota_classes.py b/manila/api/contrib/quota_classes.py index 9dd256782c..05a4342dab 100644 --- a/manila/api/contrib/quota_classes.py +++ b/manila/api/contrib/quota_classes.py @@ -16,32 +16,14 @@ import webob from manila.api import extensions -from manila.api.openstack import wsgi -from manila.api import xmlutil from manila import db from manila import exception from manila import quota - QUOTAS = quota.QUOTAS - - authorize = extensions.extension_authorizer('share', 'quota_classes') -class QuotaClassTemplate(xmlutil.TemplateBuilder): - def construct(self): - root = xmlutil.TemplateElement('quota_class_set', - selector='quota_class_set') - root.set('id') - - for resource in QUOTAS.resources: - elem = xmlutil.SubTemplateElement(root, resource) - elem.text = resource - - return xmlutil.MasterTemplate(root, 1) - - class QuotaClassSetsController(object): def _format_quota_set(self, quota_class, quota_set): @@ -54,7 +36,6 @@ class QuotaClassSetsController(object): return dict(quota_class_set=result) - @wsgi.serializers(xml=QuotaClassTemplate) def show(self, req, id): context = req.environ['manila.context'] authorize(context) @@ -66,7 +47,6 @@ class QuotaClassSetsController(object): return self._format_quota_set(id, QUOTAS.get_class_quotas(context, id)) - @wsgi.serializers(xml=QuotaClassTemplate) def update(self, req, id, body): context = req.environ['manila.context'] authorize(context) @@ -89,8 +69,6 @@ class Quota_classes(extensions.ExtensionDescriptor): name = "QuotaClasses" alias = "os-quota-class-sets" - namespace = ("http://docs.openstack.org/volume/ext/" - "quota-classes-sets/api/v1.1") updated = "2012-03-12T00:00:00+00:00" def get_resources(self): diff --git a/manila/api/contrib/quotas.py b/manila/api/contrib/quotas.py index 594fa55b3f..4c27f90c49 100644 --- a/manila/api/contrib/quotas.py +++ b/manila/api/contrib/quotas.py @@ -19,8 +19,6 @@ from six.moves.urllib import parse import webob from manila.api import extensions -from manila.api.openstack import wsgi -from manila.api import xmlutil from manila import db from manila.db.sqlalchemy import api as sqlalchemy_api from manila import exception @@ -38,18 +36,6 @@ authorize_show = extensions.extension_authorizer('compute', 'quotas:show') authorize_delete = extensions.extension_authorizer('compute', 'quotas:delete') -class QuotaTemplate(xmlutil.TemplateBuilder): - def construct(self): - root = xmlutil.TemplateElement('quota_set', selector='quota_set') - root.set('id') - - for resource in QUOTAS.resources: - elem = xmlutil.SubTemplateElement(root, resource) - elem.text = resource - - return xmlutil.MasterTemplate(root, 1) - - class QuotaSetsController(object): def __init__(self, ext_mgr): @@ -90,7 +76,6 @@ class QuotaSetsController(object): else: return dict((k, v['limit']) for k, v in values.items()) - @wsgi.serializers(xml=QuotaTemplate) def show(self, req, id): context = req.environ['manila.context'] authorize_show(context) @@ -105,7 +90,6 @@ class QuotaSetsController(object): except exception.NotAuthorized: raise webob.exc.HTTPForbidden() - @wsgi.serializers(xml=QuotaTemplate) def update(self, req, id, body): context = req.environ['manila.context'] authorize_update(context) @@ -209,7 +193,6 @@ class QuotaSetsController(object): raise webob.exc.HTTPForbidden() return {'quota_set': self._get_quotas(context, id, user_id=user_id)} - @wsgi.serializers(xml=QuotaTemplate) def defaults(self, req, id): context = req.environ['manila.context'] authorize_show(context) @@ -241,7 +224,6 @@ class Quotas(extensions.ExtensionDescriptor): name = "Quotas" alias = "os-quota-sets" - namespace = "http://docs.openstack.org/compute/ext/quotas-sets/api/v1.1" updated = "2011-08-08T00:00:00+00:00" def get_resources(self): diff --git a/manila/api/contrib/services.py b/manila/api/contrib/services.py index a28f9a416a..4df0980054 100644 --- a/manila/api/contrib/services.py +++ b/manila/api/contrib/services.py @@ -17,8 +17,6 @@ from oslo_log import log import webob.exc from manila.api import extensions -from manila.api.openstack import wsgi -from manila.api import xmlutil from manila import db from manila import exception from manila import utils @@ -27,33 +25,7 @@ LOG = log.getLogger(__name__) authorize = extensions.extension_authorizer('share', 'services') -class ServicesIndexTemplate(xmlutil.TemplateBuilder): - def construct(self): - root = xmlutil.TemplateElement('services') - elem = xmlutil.SubTemplateElement(root, 'service', selector='services') - elem.set('binary') - elem.set('host') - elem.set('zone') - elem.set('status') - elem.set('state') - elem.set('update_at') - - return xmlutil.MasterTemplate(root, 1) - - -class ServicesUpdateTemplate(xmlutil.TemplateBuilder): - def construct(self): - root = xmlutil.TemplateElement('host') - root.set('host') - root.set('disabled') - root.set('binary') - root.set('status') - - return xmlutil.MasterTemplate(root, 1) - - class ServiceController(object): - @wsgi.serializers(xml=ServicesIndexTemplate) def index(self, req): """Return a list of all running services.""" context = req.environ['manila.context'] @@ -90,7 +62,6 @@ class ServiceController(object): return {'services': services} - @wsgi.serializers(xml=ServicesUpdateTemplate) def update(self, req, id, body): """Enable/Disable scheduling for a service.""" context = req.environ['manila.context'] @@ -126,7 +97,6 @@ class Services(extensions.ExtensionDescriptor): name = "Services" alias = "os-services" - namespace = "http://docs.openstack.org/volume/ext/services/api/v2" updated = "2012-10-28T00:00:00-00:00" def get_resources(self): diff --git a/manila/api/contrib/share_actions.py b/manila/api/contrib/share_actions.py index d31eaa0fd7..a625612087 100644 --- a/manila/api/contrib/share_actions.py +++ b/manila/api/contrib/share_actions.py @@ -19,7 +19,6 @@ import webob from manila.api import extensions from manila.api.openstack import wsgi -from manila.api import xmlutil from manila import exception from manila.i18n import _ from manila import share @@ -28,40 +27,6 @@ from manila import share authorize = extensions.extension_authorizer('share', 'services') -class ShareAccessTemplate(xmlutil.TemplateBuilder): - """XML Template for share access management methods.""" - - def construct(self): - root = xmlutil.TemplateElement('access', - selector='access') - root.set("share_id") - root.set("deleted") - root.set("created_at") - root.set("updated_at") - root.set("access_type") - root.set("access_to") - root.set("state") - root.set("deleted_at") - root.set("id") - - return xmlutil.MasterTemplate(root, 1) - - -class ShareAccessListTemplate(xmlutil.TemplateBuilder): - """XML Template for share access list.""" - - def construct(self): - root = xmlutil.TemplateElement('access_list') - elem = xmlutil.SubTemplateElement(root, 'share', - selector='access_list') - elem.set("state") - elem.set("id") - elem.set("access_type") - elem.set("access_to") - - return xmlutil.MasterTemplate(root, 1) - - class ShareActionsController(wsgi.Controller): def __init__(self, *args, **kwargs): super(ShareActionsController, self).__init__(*args, **kwargs) @@ -118,7 +83,6 @@ class ShareActionsController(wsgi.Controller): raise webob.exc.HTTPBadRequest(explanation=exc_str) @wsgi.action('os-allow_access') - @wsgi.serializers(xml=ShareAccessTemplate) def _allow_access(self, req, id, body): """Add share access rule.""" context = req.environ['manila.context'] @@ -146,7 +110,6 @@ class ShareActionsController(wsgi.Controller): return {'access': access} @wsgi.action('os-deny_access') - @wsgi.serializers(xml=ShareAccessTemplate) def _deny_access(self, req, id, body): """Remove access rule.""" context = req.environ['manila.context'] @@ -164,7 +127,6 @@ class ShareActionsController(wsgi.Controller): return webob.Response(status_int=202) @wsgi.action('os-access_list') - @wsgi.serializers(xml=ShareAccessListTemplate) def _access_list(self, req, id, body): """list access rules.""" context = req.environ['manila.context'] @@ -183,7 +145,6 @@ class Share_actions(extensions.ExtensionDescriptor): name = 'ShareActions' alias = 'share-actions' - namespace = '' updated = '2012-08-14T00:00:00+00:00' def get_controller_extensions(self): diff --git a/manila/api/contrib/share_manage.py b/manila/api/contrib/share_manage.py index 61aef4dd74..ebe3559ad5 100644 --- a/manila/api/contrib/share_manage.py +++ b/manila/api/contrib/share_manage.py @@ -120,8 +120,6 @@ class Share_manage(extensions.ExtensionDescriptor): name = 'ShareManage' alias = 'os-share-manage' - namespace = ('http://docs.openstack.org/share/ext/' - 'os-share-manage/api/v1') updated = '2015-02-17T00:00:00+00:00' def get_resources(self): diff --git a/manila/api/contrib/share_type_access.py b/manila/api/contrib/share_type_access.py index 20e302b06f..2e54b98e1b 100644 --- a/manila/api/contrib/share_type_access.py +++ b/manila/api/contrib/share_type_access.py @@ -20,7 +20,6 @@ import webob from manila.api import extensions from manila.api.openstack import wsgi -from manila.api import xmlutil from manila import exception from manila.i18n import _ from manila.share import share_types @@ -31,45 +30,6 @@ soft_authorize = extensions.soft_extension_authorizer('share', authorize = extensions.extension_authorizer('share', 'share_type_access') -def make_share_type(elem): - elem.set('{%s}is_public' % Share_type_access.namespace, - '%s:is_public' % Share_type_access.alias) - - -def make_share_type_access(elem): - elem.set('share_type_id') - elem.set('project_id') - - -class ShareTypeTemplate(xmlutil.TemplateBuilder): - def construct(self): - root = xmlutil.TemplateElement('share_type', selector='share_type') - make_share_type(root) - alias = Share_type_access.alias - namespace = Share_type_access.namespace - return xmlutil.SlaveTemplate(root, 1, nsmap={alias: namespace}) - - -class ShareTypesTemplate(xmlutil.TemplateBuilder): - def construct(self): - root = xmlutil.TemplateElement('share_types') - elem = xmlutil.SubTemplateElement( - root, 'share_type', selector='share_types') - make_share_type(elem) - alias = Share_type_access.alias - namespace = Share_type_access.namespace - return xmlutil.SlaveTemplate(root, 1, nsmap={alias: namespace}) - - -class ShareTypeAccessTemplate(xmlutil.TemplateBuilder): - def construct(self): - root = xmlutil.TemplateElement('share_type_access') - elem = xmlutil.SubTemplateElement(root, 'access', - selector='share_type_access') - make_share_type_access(elem) - return xmlutil.MasterTemplate(root, 1) - - def _marshall_share_type_access(share_type): rval = [] for project_id in share_type['projects']: @@ -82,7 +42,6 @@ def _marshall_share_type_access(share_type): class ShareTypeAccessController(object): """The share type access API controller for the OpenStack API.""" - @wsgi.serializers(xml=ShareTypeAccessTemplate) def index(self, req, type_id): context = req.environ['manila.context'] authorize(context) @@ -123,8 +82,6 @@ class ShareTypeActionController(wsgi.Controller): def show(self, req, resp_obj, id): context = req.environ['manila.context'] if soft_authorize(context): - # Attach our slave template to the response object - resp_obj.attach(xml=ShareTypeTemplate()) share_type = req.get_db_share_type(id) self._extend_share_type(resp_obj.obj['share_type'], share_type) @@ -132,8 +89,6 @@ class ShareTypeActionController(wsgi.Controller): def index(self, req, resp_obj): context = req.environ['manila.context'] if soft_authorize(context): - # Attach our slave template to the response object - resp_obj.attach(xml=ShareTypesTemplate()) for share_type_rval in list(resp_obj.obj['share_types']): type_id = share_type_rval['id'] share_type = req.get_db_share_type(type_id) @@ -143,8 +98,6 @@ class ShareTypeActionController(wsgi.Controller): def create(self, req, body, resp_obj): context = req.environ['manila.context'] if soft_authorize(context): - # Attach our slave template to the response object - resp_obj.attach(xml=ShareTypeTemplate()) type_id = resp_obj.obj['share_type']['id'] share_type = req.get_db_share_type(type_id) self._extend_share_type(resp_obj.obj['share_type'], share_type) @@ -193,8 +146,6 @@ class Share_type_access(extensions.ExtensionDescriptor): name = "ShareTypeAccess" alias = "os-share-type-access" - namespace = ("http://docs.openstack.org/share/" - "ext/os-share-type-access/api/v1") updated = "2015-03-02T00:00:00Z" def get_resources(self): diff --git a/manila/api/contrib/share_unmanage.py b/manila/api/contrib/share_unmanage.py index 98e3d61fa2..420271d81b 100644 --- a/manila/api/contrib/share_unmanage.py +++ b/manila/api/contrib/share_unmanage.py @@ -78,8 +78,6 @@ class Share_unmanage(extensions.ExtensionDescriptor): name = 'ShareUnmanage' alias = 'os-share-unmanage' - namespace = ('http://docs.openstack.org/share/ext/' - 'os-share-unmanage/api/v1') updated = '2015-02-17T00:00:00+00:00' def get_resources(self): diff --git a/manila/api/contrib/types_extra_specs.py b/manila/api/contrib/types_extra_specs.py index 87452479a8..3fafc9104c 100644 --- a/manila/api/contrib/types_extra_specs.py +++ b/manila/api/contrib/types_extra_specs.py @@ -162,7 +162,6 @@ class Types_extra_specs(extensions.ExtensionDescriptor): name = "TypesExtraSpecs" alias = "os-types-extra-specs" - namespace = "http://docs.openstack.org/share/ext/types-extra-specs/api/v1" updated = "2011-08-24T00:00:00+00:00" def get_resources(self): diff --git a/manila/api/contrib/types_manage.py b/manila/api/contrib/types_manage.py index 973a6f052e..7d2054f09c 100644 --- a/manila/api/contrib/types_manage.py +++ b/manila/api/contrib/types_manage.py @@ -124,7 +124,6 @@ class Types_manage(extensions.ExtensionDescriptor): name = "TypesManage" alias = "os-types-manage" - namespace = "http://docs.openstack.org/share/ext/types-manage/api/v1" updated = "2011-08-24T00:00:00+00:00" def get_controller_extensions(self): diff --git a/manila/api/contrib/used_limits.py b/manila/api/contrib/used_limits.py index dbdad642b1..b1b0a75a57 100644 --- a/manila/api/contrib/used_limits.py +++ b/manila/api/contrib/used_limits.py @@ -55,7 +55,6 @@ class Used_limits(extensions.ExtensionDescriptor): name = "UsedLimits" alias = 'os-used-limits' - namespace = "http://docs.openstack.org/share/ext/used-limits/api/v1.0" updated = "2014-03-27T00:00:00+00:00" def get_controller_extensions(self): diff --git a/manila/api/contrib/user_quotas.py b/manila/api/contrib/user_quotas.py index 2119fbee0f..224e125539 100644 --- a/manila/api/contrib/user_quotas.py +++ b/manila/api/contrib/user_quotas.py @@ -22,6 +22,4 @@ class User_quotas(extensions.ExtensionDescriptor): name = "UserQuotas" alias = "os-user-quotas" - namespace = ("http://docs.openstack.org/compute/ext/user_quotas" - "/api/v1.1") updated = "2013-07-18T00:00:00+00:00" diff --git a/manila/api/extensions.py b/manila/api/extensions.py index 1853f7bd1f..62f85a7657 100644 --- a/manila/api/extensions.py +++ b/manila/api/extensions.py @@ -25,7 +25,6 @@ import webob.exc import manila.api.openstack from manila.api.openstack import wsgi -from manila.api import xmlutil from manila import exception from manila.i18n import _LE from manila.i18n import _LI @@ -52,10 +51,6 @@ class ExtensionDescriptor(object): # Description comes from the docstring for the class - # The XML namespace for the extension, e.g., - # 'http://www.fox.in.socks/api/ext/pie/v1.0' - namespace = None - # The timestamp when the extension was last updated, e.g., # '2011-01-22T13:25:27-06:00' updated = None @@ -83,55 +78,6 @@ class ExtensionDescriptor(object): controller_exts = [] return controller_exts - @classmethod - def nsmap(cls): - """Synthesize a namespace map from extension.""" - - # Start with a base nsmap - nsmap = ext_nsmap.copy() - - # Add the namespace for the extension - nsmap[cls.alias] = cls.namespace - - return nsmap - - @classmethod - def xmlname(cls, name): - """Synthesize element and attribute names.""" - - return '{%s}%s' % (cls.namespace, name) - - -def make_ext(elem): - elem.set('name') - elem.set('namespace') - elem.set('alias') - elem.set('updated') - - desc = xmlutil.SubTemplateElement(elem, 'description') - desc.text = 'description' - - xmlutil.make_links(elem, 'links') - - -ext_nsmap = {None: xmlutil.XMLNS_COMMON_V10, 'atom': xmlutil.XMLNS_ATOM} - - -class ExtensionTemplate(xmlutil.TemplateBuilder): - def construct(self): - root = xmlutil.TemplateElement('extension', selector='extension') - make_ext(root) - return xmlutil.MasterTemplate(root, 1, nsmap=ext_nsmap) - - -class ExtensionsTemplate(xmlutil.TemplateBuilder): - def construct(self): - root = xmlutil.TemplateElement('extensions') - elem = xmlutil.SubTemplateElement(root, 'extension', - selector='extensions') - make_ext(elem) - return xmlutil.MasterTemplate(root, 1, nsmap=ext_nsmap) - class ExtensionsResource(wsgi.Resource): @@ -144,19 +90,16 @@ class ExtensionsResource(wsgi.Resource): ext_data['name'] = ext.name ext_data['alias'] = ext.alias ext_data['description'] = ext.__doc__ - ext_data['namespace'] = ext.namespace ext_data['updated'] = ext.updated ext_data['links'] = [] # TODO(dprince): implement extension links return ext_data - @wsgi.serializers(xml=ExtensionsTemplate) def index(self, req): extensions = [] for _alias, ext in six.iteritems(self.extension_manager.extensions): extensions.append(self._translate(ext)) return dict(extensions=extensions) - @wsgi.serializers(xml=ExtensionTemplate) def show(self, req, id): try: # NOTE(dprince): the extensions alias is used as the 'id' for show @@ -240,7 +183,6 @@ class ExtensionManager(object): LOG.debug('Ext alias: %s', extension.alias) LOG.debug('Ext description: %s', ' '.join(extension.__doc__.strip().split())) - LOG.debug('Ext namespace: %s', extension.namespace) LOG.debug('Ext updated: %s', extension.updated) except AttributeError as ex: LOG.exception(_LE("Exception loading extension: %s"), diff --git a/manila/api/openstack/wsgi.py b/manila/api/openstack/wsgi.py index 01c9ad319f..be88a902cb 100644 --- a/manila/api/openstack/wsgi.py +++ b/manila/api/openstack/wsgi.py @@ -28,37 +28,14 @@ from manila.i18n import _LI from manila import utils from manila import wsgi -from lxml import etree -from xml.dom import minidom -from xml.parsers import expat - - -XMLNS_V1 = 'http://docs.openstack.org/volume/api/v1' -XMLNS_ATOM = 'http://www.w3.org/2005/Atom' - LOG = log.getLogger(__name__) -# The vendor content types should serialize identically to the non-vendor -# content types. So to avoid littering the code with both options, we -# map the vendor to the other when looking up the type -_CONTENT_TYPE_MAP = { - 'application/vnd.openstack.volume+json': 'application/json', - 'application/vnd.openstack.volume+xml': 'application/xml', -} - SUPPORTED_CONTENT_TYPES = ( 'application/json', - 'application/vnd.openstack.volume+json', - 'application/xml', - 'application/vnd.openstack.volume+xml', ) _MEDIA_TYPE_MAP = { - 'application/vnd.openstack.volume+json': 'json', 'application/json': 'json', - 'application/vnd.openstack.volume+xml': 'xml', - 'application/xml': 'xml', - 'application/atom+xml': 'atom', } @@ -252,95 +229,6 @@ class JSONDeserializer(TextDeserializer): return {'body': self._from_json(datastring)} -class XMLDeserializer(TextDeserializer): - - def __init__(self, metadata=None): - """ - :param metadata: information needed to deserialize xml into - a dictionary. - """ - super(XMLDeserializer, self).__init__() - self.metadata = metadata or {} - - def _from_xml(self, datastring): - plurals = set(self.metadata.get('plurals', {})) - - try: - node = utils.safe_minidom_parse_string(datastring).childNodes[0] - return {node.nodeName: self._from_xml_node(node, plurals)} - except expat.ExpatError: - msg = _("cannot understand XML") - raise exception.MalformedRequestBody(reason=msg) - - def _from_xml_node(self, node, listnames): - """Convert a minidom node to a simple Python type. - - :param listnames: list of XML node names whose subnodes should - be considered list items. - - """ - if len(node.childNodes) == 1 and node.childNodes[0].nodeType == 3: - return node.childNodes[0].nodeValue - elif node.nodeName in listnames: - return [self._from_xml_node(n, listnames) for n in node.childNodes] - else: - result = dict() - for attr in node.attributes.keys(): - result[attr] = node.attributes[attr].nodeValue - for child in node.childNodes: - if child.nodeType != node.TEXT_NODE: - result[child.nodeName] = self._from_xml_node(child, - listnames) - return result - - def find_first_child_named(self, parent, name): - """Search a nodes children for the first child with a given name""" - for node in parent.childNodes: - if node.nodeName == name: - return node - return None - - def find_children_named(self, parent, name): - """Return all of a nodes children who have the given name""" - for node in parent.childNodes: - if node.nodeName == name: - yield node - - def extract_text(self, node): - """Get the text field contained by the given node""" - if len(node.childNodes) == 1: - child = node.childNodes[0] - if child.nodeType == child.TEXT_NODE: - return child.nodeValue - return "" - - def find_attribute_or_element(self, parent, name): - """Get an attribute value; fallback to an element if not found""" - if parent.hasAttribute(name): - return parent.getAttribute(name) - - node = self.find_first_child_named(parent, name) - if node: - return self.extract_text(node) - - return None - - def default(self, datastring): - return {'body': self._from_xml(datastring)} - - -class MetadataXMLDeserializer(XMLDeserializer): - - def extract_metadata(self, metadata_node): - """Marshal the metadata attribute of a parsed request""" - metadata = {} - if metadata_node is not None: - for meta_node in self.find_children_named(metadata_node, "meta"): - key = meta_node.getAttribute("key") - metadata[key] = self.extract_text(meta_node) - return metadata - - class DictSerializer(ActionDispatcher): """Default request body serialization""" @@ -358,110 +246,6 @@ class JSONDictSerializer(DictSerializer): return jsonutils.dumps(data) -class XMLDictSerializer(DictSerializer): - - def __init__(self, metadata=None, xmlns=None): - """ - :param metadata: information needed to deserialize xml into - a dictionary. - :param xmlns: XML namespace to include with serialized xml - """ - super(XMLDictSerializer, self).__init__() - self.metadata = metadata or {} - self.xmlns = xmlns - - def default(self, data): - # We expect data to contain a single key which is the XML root. - root_key = data.keys()[0] - doc = minidom.Document() - node = self._to_xml_node(doc, self.metadata, root_key, data[root_key]) - - return self.to_xml_string(node) - - def to_xml_string(self, node, has_atom=False): - self._add_xmlns(node, has_atom) - return node.toxml('UTF-8') - - # NOTE (ameade): the has_atom should be removed after all of the - # xml serializers and view builders have been updated to the current - # spec that required all responses include the xmlns:atom, the has_atom - # flag is to prevent current tests from breaking - def _add_xmlns(self, node, has_atom=False): - if self.xmlns is not None: - node.setAttribute('xmlns', self.xmlns) - if has_atom: - node.setAttribute('xmlns:atom', "http://www.w3.org/2005/Atom") - - def _to_xml_node(self, doc, metadata, nodename, data): - """Recursive method to convert data members to XML nodes.""" - result = doc.createElement(nodename) - - # Set the xml namespace if one is specified - # TODO(justinsb): We could also use prefixes on the keys - xmlns = metadata.get('xmlns', None) - if xmlns: - result.setAttribute('xmlns', xmlns) - - # TODO(bcwaldon): accomplish this without a type-check - if isinstance(data, list): - collections = metadata.get('list_collections', {}) - if nodename in collections: - metadata = collections[nodename] - for item in data: - node = doc.createElement(metadata['item_name']) - node.setAttribute(metadata['item_key'], str(item)) - result.appendChild(node) - return result - singular = metadata.get('plurals', {}).get(nodename, None) - if singular is None: - if nodename.endswith('s'): - singular = nodename[:-1] - else: - singular = 'item' - for item in data: - node = self._to_xml_node(doc, metadata, singular, item) - result.appendChild(node) - # TODO(bcwaldon): accomplish this without a type-check - elif isinstance(data, dict): - collections = metadata.get('dict_collections', {}) - if nodename in collections: - metadata = collections[nodename] - for k, v in data.items(): - node = doc.createElement(metadata['item_name']) - node.setAttribute(metadata['item_key'], str(k)) - text = doc.createTextNode(str(v)) - node.appendChild(text) - result.appendChild(node) - return result - attrs = metadata.get('attributes', {}).get(nodename, {}) - for k, v in data.items(): - if k in attrs: - result.setAttribute(k, str(v)) - else: - node = self._to_xml_node(doc, metadata, k, v) - result.appendChild(node) - else: - # Type is atom - node = doc.createTextNode(str(data)) - result.appendChild(node) - return result - - def _create_link_nodes(self, xml_doc, links): - link_nodes = [] - for link in links: - link_node = xml_doc.createElement('atom:link') - link_node.setAttribute('rel', link['rel']) - link_node.setAttribute('href', link['href']) - if 'type' in link: - link_node.setAttribute('type', link['type']) - link_nodes.append(link_node) - return link_nodes - - def _to_xml(self, root): - """Convert the xml object to an xml string.""" - return etree.tostring(root, encoding='UTF-8', xml_declaration=True) - - def serializers(**serializers): """Attaches serializers to a method. @@ -660,15 +444,6 @@ def action_peek_json(body): return decoded.keys()[0] -def action_peek_xml(body): - """Determine action to invoke.""" - - dom = utils.safe_minidom_parse_string(body) - action_node = dom.childNodes[0] - - return action_node.tagName - - class ResourceExceptionHandler(object): """Context manager to handle Resource exceptions. @@ -731,16 +506,13 @@ class Resource(wsgi.Application): self.controller = controller - default_deserializers = dict(xml=XMLDeserializer, - json=JSONDeserializer) + default_deserializers = dict(json=JSONDeserializer) default_deserializers.update(deserializers) self.default_deserializers = default_deserializers - self.default_serializers = dict(xml=XMLDictSerializer, - json=JSONDictSerializer) + self.default_serializers = dict(json=JSONDictSerializer) - self.action_peek = dict(xml=action_peek_xml, - json=action_peek_json) + self.action_peek = dict(json=action_peek_json) self.action_peek.update(action_peek or {}) # Copy over the actions dictionary @@ -1186,11 +958,8 @@ class Fault(webob.exc.HTTPException): # 'code' is an attribute on the fault tag itself metadata = {'attributes': {fault_name: 'code'}} - xml_serializer = XMLDictSerializer(metadata, XMLNS_V1) - content_type = req.best_match_content_type() serializer = { - 'application/xml': xml_serializer, 'application/json': JSONDictSerializer(), }[content_type] @@ -1245,9 +1014,7 @@ class OverLimitFault(webob.exc.HTTPException): content_type = request.best_match_content_type() metadata = {"attributes": {"overLimitFault": "code"}} - xml_serializer = XMLDictSerializer(metadata, XMLNS_V1) serializer = { - 'application/xml': xml_serializer, 'application/json': JSONDictSerializer(), }[content_type] diff --git a/manila/api/schemas/atom-link.rng b/manila/api/schemas/atom-link.rng deleted file mode 100644 index edba5eee6c..0000000000 --- a/manila/api/schemas/atom-link.rng +++ /dev/null @@ -1,141 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1 - [^:]* - - - - - - .+/.+ - - - - - - [A-Za-z]{1,8}(-[A-Za-z0-9]{1,8})* - - - - - - - - - - - - xml:base - xml:lang - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/manila/api/schemas/v1.1/extension.rng b/manila/api/schemas/v1.1/extension.rng deleted file mode 100644 index b16d8c1300..0000000000 --- a/manila/api/schemas/v1.1/extension.rng +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - diff --git a/manila/api/schemas/v1.1/extensions.rng b/manila/api/schemas/v1.1/extensions.rng deleted file mode 100644 index 8538eaf2da..0000000000 --- a/manila/api/schemas/v1.1/extensions.rng +++ /dev/null @@ -1,6 +0,0 @@ - - - - - diff --git a/manila/api/schemas/v1.1/limits.rng b/manila/api/schemas/v1.1/limits.rng deleted file mode 100644 index a66af4b9c4..0000000000 --- a/manila/api/schemas/v1.1/limits.rng +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/manila/api/schemas/v1.1/metadata.rng b/manila/api/schemas/v1.1/metadata.rng deleted file mode 100644 index b2f5d702a2..0000000000 --- a/manila/api/schemas/v1.1/metadata.rng +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - diff --git a/manila/api/urlmap.py b/manila/api/urlmap.py index 3a22324daf..09493db064 100644 --- a/manila/api/urlmap.py +++ b/manila/api/urlmap.py @@ -253,24 +253,16 @@ class URLMap(paste.urlmap.URLMap): path_info = environ['PATH_INFO'] path_info = self.normalize_url(path_info, False)[1] - # The MIME type for the response is determined in one of two ways: - # 1) URL path suffix (eg /servers/detail.json) - # 2) Accept header (eg application/json;q=0.8, application/xml;q=0.2) - # The API version is determined in one of three ways: # 1) URL path prefix (eg /v1.1/tenant/servers/detail) # 2) Content-Type header (eg application/json;version=1.1) # 3) Accept header (eg application/json;q=0.8;version=1.1) + # Manila supports only application/json as MIME type for the responses. supported_content_types = list(wsgi.SUPPORTED_CONTENT_TYPES) mime_type, app, app_url = self._path_strategy(host, port, path_info) - # Accept application/atom+xml for the index query of each API - # version mount point as well as the root index - if (app_url and app_url + '/' == path_info) or path_info == '/': - supported_content_types.append('application/atom+xml') - if not app: app = self._content_type_strategy(host, port, environ) diff --git a/manila/api/v1/limits.py b/manila/api/v1/limits.py index 6c3c59f920..fae0dfcd1d 100644 --- a/manila/api/v1/limits.py +++ b/manila/api/v1/limits.py @@ -31,7 +31,6 @@ import webob.exc from manila.api.openstack import wsgi from manila.api.views import limits as limits_views -from manila.api import xmlutil from manila.i18n import _ from manila import quota from manila import wsgi as base_wsgi @@ -46,38 +45,9 @@ PER_HOUR = 60 * 60 PER_DAY = 60 * 60 * 24 -limits_nsmap = {None: xmlutil.XMLNS_COMMON_V10, 'atom': xmlutil.XMLNS_ATOM} - - -class LimitsTemplate(xmlutil.TemplateBuilder): - def construct(self): - root = xmlutil.TemplateElement('limits', selector='limits') - - rates = xmlutil.SubTemplateElement(root, 'rates') - rate = xmlutil.SubTemplateElement(rates, 'rate', selector='rate') - rate.set('uri', 'uri') - rate.set('regex', 'regex') - limit = xmlutil.SubTemplateElement(rate, 'limit', selector='limit') - limit.set('value', 'value') - limit.set('verb', 'verb') - limit.set('remaining', 'remaining') - limit.set('unit', 'unit') - limit.set('next-available', 'next-available') - - absolute = xmlutil.SubTemplateElement(root, 'absolute', - selector='absolute') - limit = xmlutil.SubTemplateElement(absolute, 'limit', - selector=xmlutil.get_items) - limit.set('name', 0) - limit.set('value', 1) - - return xmlutil.MasterTemplate(root, 1, nsmap=limits_nsmap) - - class LimitsController(object): """Controller for accessing limits in the OpenStack API.""" - @wsgi.serializers(xml=LimitsTemplate) def index(self, req): """Return all global and rate limit information.""" context = req.environ['manila.context'] diff --git a/manila/api/v1/security_service.py b/manila/api/v1/security_service.py index 4c3ad5924d..6871b6f033 100644 --- a/manila/api/v1/security_service.py +++ b/manila/api/v1/security_service.py @@ -23,7 +23,6 @@ from webob import exc from manila.api import common from manila.api.openstack import wsgi from manila.api.views import security_service as security_service_views -from manila.api import xmlutil from manila.common import constants from manila import db from manila import exception @@ -36,36 +35,11 @@ RESOURCE_NAME = 'security_service' LOG = log.getLogger(__name__) -def make_security_service(elem): - attrs = ['id', 'name', 'description', 'type', 'server', 'domain', 'user', - 'password', 'dns_ip', 'status', 'updated_at', 'created_at'] - for attr in attrs: - elem.set(attr) - - -class SecurityServiceTemplate(xmlutil.TemplateBuilder): - def construct(self): - root = xmlutil.TemplateElement('security_service', - selector='security_service') - make_security_service(root) - return xmlutil.MasterTemplate(root, 1) - - -class SecurityServicesTemplate(xmlutil.TemplateBuilder): - def construct(self): - root = xmlutil.TemplateElement('security_services') - elem = xmlutil.SubTemplateElement(root, 'security_service', - selector='security_services') - make_security_service(elem) - return xmlutil.MasterTemplate(root, 1) - - class SecurityServiceController(wsgi.Controller): """The Shares API controller for the OpenStack API.""" _view_builder_class = security_service_views.ViewBuilder - @wsgi.serializers(xml=SecurityServiceTemplate) def show(self, req, id): """Return data about the given security service.""" context = req.environ['manila.context'] @@ -102,14 +76,12 @@ class SecurityServiceController(wsgi.Controller): return webob.Response(status_int=202) - @wsgi.serializers(xml=SecurityServicesTemplate) def index(self, req): """Returns a summary list of security services.""" policy.check_policy(req.environ['manila.context'], RESOURCE_NAME, 'index') return self._get_security_services(req, is_detail=False) - @wsgi.serializers(xml=SecurityServicesTemplate) def detail(self, req): """Returns a detailed list of security services.""" policy.check_policy(req.environ['manila.context'], RESOURCE_NAME, @@ -181,7 +153,6 @@ class SecurityServiceController(wsgi.Controller): return True return False - @wsgi.serializers(xml=SecurityServiceTemplate) def update(self, req, id, body): """Update a security service.""" context = req.environ['manila.context'] @@ -221,7 +192,6 @@ class SecurityServiceController(wsgi.Controller): security_service = db.security_service_update(context, id, update_dict) return self._view_builder.detail(req, security_service) - @wsgi.serializers(xml=SecurityServiceTemplate) def create(self, req, body): """Creates a new security service.""" context = req.environ['manila.context'] diff --git a/manila/api/v1/share_metadata.py b/manila/api/v1/share_metadata.py index 7d212dd4c5..971c1b2be2 100644 --- a/manila/api/v1/share_metadata.py +++ b/manila/api/v1/share_metadata.py @@ -16,7 +16,6 @@ import webob from webob import exc -from manila.api import common from manila.api.openstack import wsgi from manila import exception from manila.i18n import _ @@ -39,14 +38,11 @@ class ShareMetadataController(object): raise exc.HTTPNotFound(explanation=msg) return meta - @wsgi.serializers(xml=common.MetadataTemplate) def index(self, req, share_id): """Returns the list of metadata for a given share.""" context = req.environ['manila.context'] return {'metadata': self._get_metadata(context, share_id)} - @wsgi.serializers(xml=common.MetadataTemplate) - @wsgi.deserializers(xml=common.MetadataDeserializer) def create(self, req, share_id, body): try: metadata = body['metadata'] @@ -63,8 +59,6 @@ class ShareMetadataController(object): return {'metadata': new_metadata} - @wsgi.serializers(xml=common.MetaItemTemplate) - @wsgi.deserializers(xml=common.MetaItemDeserializer) def update(self, req, share_id, id, body): try: meta_item = body['meta'] @@ -88,8 +82,6 @@ class ShareMetadataController(object): return {'meta': meta_item} - @wsgi.serializers(xml=common.MetadataTemplate) - @wsgi.deserializers(xml=common.MetadataDeserializer) def update_all(self, req, share_id, body): try: metadata = body['metadata'] @@ -125,7 +117,6 @@ class ShareMetadataController(object): except exception.InvalidShareMetadataSize as error: raise exc.HTTPBadRequest(explanation=error.msg) - @wsgi.serializers(xml=common.MetaItemTemplate) def show(self, req, share_id, id): """Return a single metadata item.""" context = req.environ['manila.context'] diff --git a/manila/api/v1/share_networks.py b/manila/api/v1/share_networks.py index e2a9d7f9ca..6459986666 100644 --- a/manila/api/v1/share_networks.py +++ b/manila/api/v1/share_networks.py @@ -25,7 +25,6 @@ from webob import exc from manila.api import common from manila.api.openstack import wsgi from manila.api.views import share_networks as share_networks_views -from manila.api import xmlutil from manila.db import api as db_api from manila import exception from manila.i18n import _ @@ -39,43 +38,6 @@ RESOURCE_NAME = 'share_network' RESOURCES_NAME = 'share_networks' LOG = log.getLogger(__name__) QUOTAS = quota.QUOTAS -SHARE_NETWORK_ATTRS = ( - 'id', - 'project_id', - 'user_id', - 'created_at', - 'updated_at', - 'nova_net_id', - 'neutron_net_id', - 'neutron_subnet_id', - 'network_type', - 'segmentation_id', - 'cidr', - 'ip_version', - 'name', - 'description', -) - - -def _make_share_network(elem): - for attr in SHARE_NETWORK_ATTRS: - elem.set(attr) - - -class ShareNetworkTemplate(xmlutil.TemplateBuilder): - def construct(self): - root = xmlutil.TemplateElement(RESOURCE_NAME, selector=RESOURCE_NAME) - _make_share_network(root) - return xmlutil.MasterTemplate(root, 1) - - -class ShareNetworksTemplate(xmlutil.TemplateBuilder): - def construct(self): - root = xmlutil.TemplateElement(RESOURCES_NAME) - elem = xmlutil.SubTemplateElement(root, RESOURCE_NAME, - selector=RESOURCES_NAME) - _make_share_network(elem) - return xmlutil.MasterTemplate(root, 1) class ShareNetworkController(wsgi.Controller): @@ -87,7 +49,6 @@ class ShareNetworkController(wsgi.Controller): super(ShareNetworkController, self).__init__() self.share_rpcapi = share_rpcapi.ShareAPI() - @wsgi.serializers(xml=ShareNetworkTemplate) def show(self, req, id): """Return data about the requested network info.""" context = req.environ['manila.context'] @@ -132,7 +93,6 @@ class ShareNetworkController(wsgi.Controller): project_id=share_network['project_id']) return webob.Response(status_int=202) - @wsgi.serializers(xml=ShareNetworksTemplate) def _get_share_networks(self, req, is_detail=True): """Returns a list of share networks.""" context = req.environ['manila.context'] @@ -200,14 +160,12 @@ class ShareNetworkController(wsgi.Controller): limited_list = common.limited(networks, req) return self._view_builder.build_share_networks(limited_list, is_detail) - @wsgi.serializers(xml=ShareNetworksTemplate) def index(self, req): """Returns a summary list of share networks.""" policy.check_policy(req.environ['manila.context'], RESOURCE_NAME, 'index') return self._get_share_networks(req, is_detail=False) - @wsgi.serializers(xml=ShareNetworksTemplate) def detail(self, req): """Returns a detailed list of share networks.""" policy.check_policy(req.environ['manila.context'], RESOURCE_NAME, @@ -231,7 +189,6 @@ class ShareNetworkController(wsgi.Controller): "exclusive. Only one of these are allowed at a time.") raise exc.HTTPBadRequest(explanation=msg) - @wsgi.serializers(xml=ShareNetworkTemplate) def update(self, req, id, body): """Update specified share network.""" context = req.environ['manila.context'] @@ -267,7 +224,6 @@ class ShareNetworkController(wsgi.Controller): return self._view_builder.build_share_network(share_network) - @wsgi.serializers(xml=ShareNetworkTemplate) def create(self, req, body): """Creates a new share network.""" context = req.environ['manila.context'] @@ -309,7 +265,6 @@ class ShareNetworkController(wsgi.Controller): QUOTAS.commit(context, reservations) return self._view_builder.build_share_network(share_network) - @wsgi.serializers(xml=ShareNetworkTemplate) def action(self, req, id, body): _actions = { 'add_security_service': self._add_security_service, diff --git a/manila/api/v1/share_servers.py b/manila/api/v1/share_servers.py index 2c98fafba5..352c156728 100644 --- a/manila/api/v1/share_servers.py +++ b/manila/api/v1/share_servers.py @@ -20,7 +20,6 @@ from webob import exc from manila.api.openstack import wsgi from manila.api.views import share_servers as share_servers_views -from manila.api import xmlutil from manila.common import constants from manila.db import api as db_api from manila import exception @@ -31,37 +30,6 @@ from manila import share RESOURCE_NAME = 'share_server' RESOURCES_NAME = 'share_servers' LOG = log.getLogger(__name__) -SHARE_SERVER_ATTRS = ( - 'id', - 'project_id', - 'updated_at', - 'status', - 'host', - 'share_network_name', -) - - -def _make_share_server(elem, details=False): - for attr in SHARE_SERVER_ATTRS: - elem.set(attr) - if details: - elem.set('backend_details') - - -class ShareServerTemplate(xmlutil.TemplateBuilder): - def construct(self): - root = xmlutil.TemplateElement(RESOURCE_NAME, selector=RESOURCE_NAME) - _make_share_server(root, details=True) - return xmlutil.MasterTemplate(root, 1) - - -class ShareServersTemplate(xmlutil.TemplateBuilder): - def construct(self): - root = xmlutil.TemplateElement(RESOURCES_NAME) - elem = xmlutil.SubTemplateElement(root, RESOURCE_NAME, - selector=RESOURCES_NAME) - _make_share_server(elem) - return xmlutil.MasterTemplate(root, 1) class ShareServerController(wsgi.Controller): @@ -72,7 +40,6 @@ class ShareServerController(wsgi.Controller): self._view_builder_class = share_servers_views.ViewBuilder super(ShareServerController, self).__init__() - @wsgi.serializers(xml=ShareServersTemplate) def index(self, req): """Returns a list of share servers.""" @@ -98,7 +65,6 @@ class ShareServerController(wsgi.Controller): s.share_network['id']])] return self._view_builder.build_share_servers(share_servers) - @wsgi.serializers(xml=ShareServerTemplate) def show(self, req, id): """Return data about the requested share server.""" context = req.environ['manila.context'] diff --git a/manila/api/v1/share_snapshots.py b/manila/api/v1/share_snapshots.py index 0feb6bc455..10db81493b 100644 --- a/manila/api/v1/share_snapshots.py +++ b/manila/api/v1/share_snapshots.py @@ -23,7 +23,6 @@ from webob import exc from manila.api import common from manila.api.openstack import wsgi from manila.api.views import share_snapshots as snapshot_views -from manila.api import xmlutil from manila import exception from manila.i18n import _LI from manila import share @@ -31,30 +30,6 @@ from manila import share LOG = log.getLogger(__name__) -def make_snapshot(elem): - attrs = ['id', 'size', 'status', 'name', 'description', 'share_proto', - 'links', 'share_id', 'created_at', 'share_size'] - for attr in attrs: - elem.set(attr) - - -class SnapshotTemplate(xmlutil.TemplateBuilder): - def construct(self): - root = xmlutil.TemplateElement('snapshot', - selector='snapshot') - make_snapshot(root) - return xmlutil.MasterTemplate(root, 1) - - -class SnapshotsTemplate(xmlutil.TemplateBuilder): - def construct(self): - root = xmlutil.TemplateElement('snapshots') - elem = xmlutil.SubTemplateElement(root, 'snapshot', - selector='snapshots') - make_snapshot(elem) - return xmlutil.MasterTemplate(root, 1) - - class ShareSnapshotsController(wsgi.Controller): """The Share Snapshots API controller for the OpenStack API.""" @@ -64,7 +39,6 @@ class ShareSnapshotsController(wsgi.Controller): super(ShareSnapshotsController, self).__init__() self.share_api = share.API() - @wsgi.serializers(xml=SnapshotTemplate) def show(self, req, id): """Return data about the given snapshot.""" context = req.environ['manila.context'] @@ -89,12 +63,10 @@ class ShareSnapshotsController(wsgi.Controller): raise exc.HTTPNotFound() return webob.Response(status_int=202) - @wsgi.serializers(xml=SnapshotsTemplate) def index(self, req): """Returns a summary list of snapshots.""" return self._get_snapshots(req, is_detail=False) - @wsgi.serializers(xml=SnapshotsTemplate) def detail(self, req): """Returns a detailed list of snapshots.""" return self._get_snapshots(req, is_detail=True) @@ -138,7 +110,6 @@ class ShareSnapshotsController(wsgi.Controller): """Return share search options allowed by non-admin.""" return ('display_name', 'name', 'status', 'share_id', 'size') - @wsgi.serializers(xml=SnapshotTemplate) def update(self, req, id, body): """Update a snapshot.""" context = req.environ['manila.context'] @@ -167,7 +138,6 @@ class ShareSnapshotsController(wsgi.Controller): return self._view_builder.detail(req, snapshot) @wsgi.response(202) - @wsgi.serializers(xml=SnapshotTemplate) def create(self, req, body): """Creates a new snapshot.""" context = req.environ['manila.context'] @@ -204,18 +174,3 @@ class ShareSnapshotsController(wsgi.Controller): def create_resource(): return wsgi.Resource(ShareSnapshotsController()) - -# -# class Share_snapshots(extensions.ExtensionDescriptor): -# """Enable share snapshtos API.""" -# name = 'ShareSnapshots' -# alias = 'snapshots' -# namespace = '' -# updated = '2013-03-01T00:00:00+00:00' -# -# def get_resources(self): -# controller = ShareSnapshotsController() -# resource = extensions.ResourceExtension( -# 'snapshots', controller, -# collection_actions={'detail': 'GET'}) -# return [resource] diff --git a/manila/api/v1/shares.py b/manila/api/v1/shares.py index 028222e8ea..7e8076555f 100644 --- a/manila/api/v1/shares.py +++ b/manila/api/v1/shares.py @@ -26,7 +26,6 @@ from webob import exc from manila.api import common from manila.api.openstack import wsgi from manila.api.views import shares as share_views -from manila.api import xmlutil from manila import exception from manila.i18n import _ from manila.i18n import _LI @@ -36,32 +35,6 @@ from manila.share import share_types LOG = log.getLogger(__name__) -def make_share(elem): - # NOTE(u_glide): - # export_location is backward-compatibility attribute, which contains first - # export location from export_locations list. - attrs = ['id', 'size', 'availability_zone', 'status', 'name', - 'description', 'share_proto', 'export_location', 'links', - 'snapshot_id', 'created_at', 'metadata', 'export_locations'] - for attr in attrs: - elem.set(attr) - - -class ShareTemplate(xmlutil.TemplateBuilder): - def construct(self): - root = xmlutil.TemplateElement('share', selector='share') - make_share(root) - return xmlutil.MasterTemplate(root, 1) - - -class SharesTemplate(xmlutil.TemplateBuilder): - def construct(self): - root = xmlutil.TemplateElement('shares') - elem = xmlutil.SubTemplateElement(root, 'share', selector='shares') - make_share(elem) - return xmlutil.MasterTemplate(root, 1) - - class ShareController(wsgi.Controller): """The Shares API controller for the OpenStack API.""" @@ -71,7 +44,6 @@ class ShareController(wsgi.Controller): super(ShareController, self).__init__() self.share_api = share.API() - @wsgi.serializers(xml=ShareTemplate) def show(self, req, id): """Return data about the given share.""" context = req.environ['manila.context'] @@ -99,12 +71,10 @@ class ShareController(wsgi.Controller): return webob.Response(status_int=202) - @wsgi.serializers(xml=SharesTemplate) def index(self, req): """Returns a summary list of shares.""" return self._get_shares(req, is_detail=False) - @wsgi.serializers(xml=SharesTemplate) def detail(self, req): """Returns a detailed list of shares.""" return self._get_shares(req, is_detail=True) @@ -164,7 +134,6 @@ class ShareController(wsgi.Controller): 'is_public', 'metadata', 'extra_specs', 'sort_key', 'sort_dir', ) - @wsgi.serializers(xml=ShareTemplate) def update(self, req, id, body): """Update a share.""" context = req.environ['manila.context'] @@ -192,7 +161,6 @@ class ShareController(wsgi.Controller): share.update(update_dict) return self._view_builder.detail(req, share) - @wsgi.serializers(xml=ShareTemplate) def create(self, req, body): """Creates a new share.""" context = req.environ['manila.context'] diff --git a/manila/api/versions.py b/manila/api/versions.py index 5d8744047a..545e2802d8 100644 --- a/manila/api/versions.py +++ b/manila/api/versions.py @@ -13,14 +13,10 @@ # License for the specific language governing permissions and limitations # under the License. -import datetime - -from lxml import etree from oslo_config import cfg from manila.api.openstack import wsgi from manila.api.views import versions as views_versions -from manila.api import xmlutil CONF = cfg.CONF @@ -46,13 +42,8 @@ _KNOWN_VERSIONS = { }, ], "media-types": [ - { - "base": "application/xml", - "type": "application/vnd.openstack.volume+xml;version=1", - }, { "base": "application/json", - "type": "application/vnd.openstack.volume+json;version=1", } ], }, @@ -76,13 +67,8 @@ _KNOWN_VERSIONS = { }, ], "media-types": [ - { - "base": "application/xml", - "type": "application/vnd.openstack.volume+xml;version=1", - }, { "base": "application/json", - "type": "application/vnd.openstack.volume+json;version=1", } ], } @@ -101,157 +87,16 @@ def get_supported_versions(): return versions -class MediaTypesTemplateElement(xmlutil.TemplateElement): - def will_render(self, datum): - return 'media-types' in datum - - -def make_version(elem): - elem.set('id') - elem.set('status') - elem.set('updated') - - mts = MediaTypesTemplateElement('media-types') - elem.append(mts) - - mt = xmlutil.SubTemplateElement(mts, 'media-type', selector='media-types') - mt.set('base') - mt.set('type') - - xmlutil.make_links(elem, 'links') - - -version_nsmap = {None: xmlutil.XMLNS_COMMON_V10, 'atom': xmlutil.XMLNS_ATOM} - - -class VersionTemplate(xmlutil.TemplateBuilder): - def construct(self): - root = xmlutil.TemplateElement('version', selector='version') - make_version(root) - return xmlutil.MasterTemplate(root, 1, nsmap=version_nsmap) - - -class VersionsTemplate(xmlutil.TemplateBuilder): - def construct(self): - root = xmlutil.TemplateElement('versions') - elem = xmlutil.SubTemplateElement(root, 'version', selector='versions') - make_version(elem) - return xmlutil.MasterTemplate(root, 1, nsmap=version_nsmap) - - -class ChoicesTemplate(xmlutil.TemplateBuilder): - def construct(self): - root = xmlutil.TemplateElement('choices') - elem = xmlutil.SubTemplateElement(root, 'version', selector='choices') - make_version(elem) - return xmlutil.MasterTemplate(root, 1, nsmap=version_nsmap) - - -class AtomSerializer(wsgi.XMLDictSerializer): - - NSMAP = {None: xmlutil.XMLNS_ATOM} - - def __init__(self, metadata=None, xmlns=None): - self.metadata = metadata or {} - if not xmlns: - self.xmlns = wsgi.XMLNS_ATOM - else: - self.xmlns = xmlns - - def _get_most_recent_update(self, versions): - recent = None - for version in versions: - updated = datetime.datetime.strptime(version['updated'], - '%Y-%m-%dT%H:%M:%SZ') - if not recent: - recent = updated - elif updated > recent: - recent = updated - - return recent.strftime('%Y-%m-%dT%H:%M:%SZ') - - def _get_base_url(self, link_href): - # Make sure no trailing / - link_href = link_href.rstrip('/') - return link_href.rsplit('/', 1)[0] + '/' - - def _create_feed(self, versions, feed_title, feed_id): - feed = etree.Element('feed', nsmap=self.NSMAP) - title = etree.SubElement(feed, 'title') - title.set('type', 'text') - title.text = feed_title - - # Set this updated to the most recently updated version - recent = self._get_most_recent_update(versions) - etree.SubElement(feed, 'updated').text = recent - - etree.SubElement(feed, 'id').text = feed_id - - link = etree.SubElement(feed, 'link') - link.set('rel', 'self') - link.set('href', feed_id) - - author = etree.SubElement(feed, 'author') - etree.SubElement(author, 'name').text = 'Rackspace' - etree.SubElement(author, 'uri').text = 'http://www.rackspace.com/' - - for version in versions: - feed.append(self._create_version_entry(version)) - - return feed - - def _create_version_entry(self, version): - entry = etree.Element('entry') - etree.SubElement(entry, 'id').text = version['links'][0]['href'] - title = etree.SubElement(entry, 'title') - title.set('type', 'text') - title.text = 'Version %s' % version['id'] - etree.SubElement(entry, 'updated').text = version['updated'] - - for link in version['links']: - link_elem = etree.SubElement(entry, 'link') - link_elem.set('rel', link['rel']) - link_elem.set('href', link['href']) - if 'type' in link: - link_elem.set('type', link['type']) - - content = etree.SubElement(entry, 'content') - content.set('type', 'text') - content.text = 'Version %s %s (%s)' % (version['id'], - version['status'], - version['updated']) - return entry - - -class VersionsAtomSerializer(AtomSerializer): - def default(self, data): - versions = data['versions'] - feed_id = self._get_base_url(versions[0]['links'][0]['href']) - feed = self._create_feed(versions, 'Available API Versions', feed_id) - return self._to_xml(feed) - - -class VersionAtomSerializer(AtomSerializer): - def default(self, data): - version = data['version'] - feed_id = version['links'][0]['href'] - feed = self._create_feed([version], 'About This Version', feed_id) - return self._to_xml(feed) - - class Versions(wsgi.Resource): def __init__(self): super(Versions, self).__init__(None) - @wsgi.serializers(xml=VersionsTemplate, - atom=VersionsAtomSerializer) def index(self, req): """Return all versions.""" builder = views_versions.get_view_builder(req) return builder.build_versions(get_supported_versions()) - @wsgi.serializers(xml=ChoicesTemplate) @wsgi.response(300) def multi(self, req): """Return multiple choices.""" @@ -270,8 +115,6 @@ class Versions(wsgi.Resource): class ShareVersionV1(object): - @wsgi.serializers(xml=VersionTemplate, - atom=VersionAtomSerializer) def show(self, req): builder = views_versions.get_view_builder(req) return builder.build_version(_KNOWN_VERSIONS['v1.0']) diff --git a/manila/api/xmlutil.py b/manila/api/xmlutil.py deleted file mode 100644 index 2cc89d84aa..0000000000 --- a/manila/api/xmlutil.py +++ /dev/null @@ -1,913 +0,0 @@ -# Copyright 2011 OpenStack LLC. -# 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. - -import os.path - -from lxml import etree -import six - -from manila.i18n import _ -from manila import utils - - -XMLNS_V10 = 'http://docs.rackspacecloud.com/servers/api/v1.0' -XMLNS_V11 = 'http://docs.openstack.org/compute/api/v1.1' -XMLNS_COMMON_V10 = 'http://docs.openstack.org/common/api/v1.0' -XMLNS_ATOM = 'http://www.w3.org/2005/Atom' -XMLNS_VOLUME_V1 = 'http://docs.openstack.org/volume/api/v1' -XMLNS_VOLUME_V2 = ('http://docs.openstack.org/api/openstack-volume/2.0/' - 'content') -XMLNS_SHARE_V1 = '' - - -def validate_schema(xml, schema_name): - if isinstance(xml, str): - xml = etree.fromstring(xml) - base_path = 'manila/api/schemas/v1.1/' - if schema_name in ('atom', 'atom-link'): - base_path = 'manila/api/schemas/' - schema_path = os.path.join(utils.maniladir(), - '%s%s.rng' % (base_path, schema_name)) - schema_doc = etree.parse(schema_path) - relaxng = etree.RelaxNG(schema_doc) - relaxng.assertValid(xml) - - -class Selector(object): - """Selects datum to operate on from an object.""" - - def __init__(self, *chain): - """Initialize the selector. - - Each argument is a subsequent index into the object. - """ - - self.chain = chain - - def __repr__(self): - """Return a representation of the selector.""" - - return "Selector" + repr(self.chain) - - def __call__(self, obj, do_raise=False): - """Select a datum to operate on. - - Selects the relevant datum within the object. - - :param obj: The object from which to select the object. - :param do_raise: If False (the default), return None if the - indexed datum does not exist. Otherwise, - raise a KeyError. - """ - - # Walk the selector list - for elem in self.chain: - # If it's callable, call it - if callable(elem): - obj = elem(obj) - else: - # Use indexing - try: - obj = obj[elem] - except (KeyError, IndexError): - # No sense going any further - if do_raise: - # Convert to a KeyError, for consistency - raise KeyError(elem) - return None - - # Return the finally-selected object - return obj - - -def get_items(obj): - """Get items in obj.""" - - return list(obj.items()) - - -class EmptyStringSelector(Selector): - """Returns the empty string if Selector would return None.""" - def __call__(self, obj, do_raise=False): - """Returns empty string if the selected value does not exist.""" - - try: - return super(EmptyStringSelector, self).__call__(obj, True) - except KeyError: - return "" - - -class ConstantSelector(object): - """Returns a constant.""" - - def __init__(self, value): - """Initialize the selector. - - :param value: The value to return. - """ - - self.value = value - - def __repr__(self): - """Return a representation of the selector.""" - - return repr(self.value) - - def __call__(self, _obj, _do_raise=False): - """Select a datum to operate on. - - Returns a constant value. Compatible with - Selector.__call__(). - """ - - return self.value - - -class TemplateElement(object): - """Represent an element in the template.""" - - def __init__(self, tag, attrib=None, selector=None, subselector=None, - **extra): - """Initialize an element. - - Initializes an element in the template. Keyword arguments - specify attributes to be set on the element; values must be - callables. See TemplateElement.set() for more information. - - :param tag: The name of the tag to create. - :param attrib: An optional dictionary of element attributes. - :param selector: An optional callable taking an object and - optional boolean do_raise indicator and - returning the object bound to the element. - :param subselector: An optional callable taking an object and - optional boolean do_raise indicator and - returning the object bound to the element. - This is used to further refine the datum - object returned by selector in the event - that it is a list of objects. - """ - - # Convert selector into a Selector - if selector is None: - selector = Selector() - elif not callable(selector): - selector = Selector(selector) - - # Convert subselector into a Selector - if subselector is not None and not callable(subselector): - subselector = Selector(subselector) - - self.tag = tag - self.selector = selector - self.subselector = subselector - self.attrib = {} - self._text = None - self._children = [] - self._childmap = {} - - # Run the incoming attributes through set() so that they - # become selectorized - if not attrib: - attrib = {} - attrib.update(extra) - for k, v in attrib.items(): - self.set(k, v) - - def __repr__(self): - """Return a representation of the template element.""" - - return ('<%s.%s %r at %#x>' % - (self.__class__.__module__, self.__class__.__name__, - self.tag, id(self))) - - def __len__(self): - """Return the number of child elements.""" - - return len(self._children) - - def __contains__(self, key): - """Determine whether a child node named by key exists.""" - - return key in self._childmap - - def __getitem__(self, idx): - """Retrieve a child node by index or name.""" - - if isinstance(idx, six.string_types): - # Allow access by node name - return self._childmap[idx] - else: - return self._children[idx] - - def append(self, elem): - """Append a child to the element.""" - - # Unwrap templates... - elem = elem.unwrap() - - # Avoid duplications - if elem.tag in self._childmap: - raise KeyError(elem.tag) - - self._children.append(elem) - self._childmap[elem.tag] = elem - - def extend(self, elems): - """Append children to the element.""" - - # Pre-evaluate the elements - elemmap = {} - elemlist = [] - for elem in elems: - # Unwrap templates... - elem = elem.unwrap() - - # Avoid duplications - if elem.tag in self._childmap or elem.tag in elemmap: - raise KeyError(elem.tag) - - elemmap[elem.tag] = elem - elemlist.append(elem) - - # Update the children - self._children.extend(elemlist) - self._childmap.update(elemmap) - - def insert(self, idx, elem): - """Insert a child element at the given index.""" - - # Unwrap templates... - elem = elem.unwrap() - - # Avoid duplications - if elem.tag in self._childmap: - raise KeyError(elem.tag) - - self._children.insert(idx, elem) - self._childmap[elem.tag] = elem - - def remove(self, elem): - """Remove a child element.""" - - # Unwrap templates... - elem = elem.unwrap() - - # Check if element exists - if elem.tag not in self._childmap or self._childmap[elem.tag] != elem: - raise ValueError(_('element is not a child')) - - self._children.remove(elem) - del self._childmap[elem.tag] - - def get(self, key): - """Get an attribute. - - Returns a callable which performs datum selection. - - :param key: The name of the attribute to get. - """ - - return self.attrib[key] - - def set(self, key, value=None): - """Set an attribute. - - :param key: The name of the attribute to set. - - :param value: A callable taking an object and optional boolean - do_raise indicator and returning the datum bound - to the attribute. If None, a Selector() will be - constructed from the key. If a string, a - Selector() will be constructed from the string. - """ - - # Convert value to a selector - if value is None: - value = Selector(key) - elif not callable(value): - value = Selector(value) - - self.attrib[key] = value - - def keys(self): - """Return the attribute names.""" - - return self.attrib.keys() - - def items(self): - """Return the attribute names and values.""" - - return self.attrib.items() - - def unwrap(self): - """Unwraps a template to return a template element.""" - - # We are a template element - return self - - def wrap(self): - """Wraps a template element to return a template.""" - - # Wrap in a basic Template - return Template(self) - - def apply(self, elem, obj): - """Apply text and attributes to an etree.Element. - - Applies the text and attribute instructions in the template - element to an etree.Element instance. - - :param elem: An etree.Element instance. - :param obj: The base object associated with this template - element. - """ - - # Start with the text... - if self.text is not None: - elem.text = six.text_type(self.text(obj)) - - # Now set up all the attributes... - for key, value in self.attrib.items(): - try: - elem.set(key, six.text_type(value(obj, True))) - except KeyError: - # Attribute has no value, so don't include it - pass - - def _render(self, parent, datum, patches, nsmap): - """Internal rendering. - - Renders the template node into an etree.Element object. - Returns the etree.Element object. - - :param parent: The parent etree.Element instance. - :param datum: The datum associated with this template element. - :param patches: A list of other template elements that must - also be applied. - :param nsmap: An optional namespace dictionary to be - associated with the etree.Element instance. - """ - - # Allocate a node - if callable(self.tag): - tagname = self.tag(datum) - else: - tagname = self.tag - elem = etree.Element(tagname, nsmap=nsmap) - - # If we have a parent, append the node to the parent - if parent is not None: - parent.append(elem) - - # If the datum is None, do nothing else - if datum is None: - return elem - - # Apply this template element to the element - self.apply(elem, datum) - - # Additionally, apply the patches - for patch in patches: - patch.apply(elem, datum) - - # We have fully rendered the element; return it - return elem - - def render(self, parent, obj, patches=[], nsmap=None): - """Render an object. - - Renders an object against this template node. Returns a list - of two-item tuples, where the first item is an etree.Element - instance and the second item is the datum associated with that - instance. - - :param parent: The parent for the etree.Element instances. - :param obj: The object to render this template element - against. - :param patches: A list of other template elements to apply - when rendering this template element. - :param nsmap: An optional namespace dictionary to attach to - the etree.Element instances. - """ - - # First, get the datum we're rendering - data = None if obj is None else self.selector(obj) - - # Check if we should render at all - if not self.will_render(data): - return [] - elif data is None: - return [(self._render(parent, None, patches, nsmap), None)] - - # Make the data into a list if it isn't already - if not isinstance(data, list): - data = [data] - elif parent is None: - raise ValueError(_('root element selecting a list')) - - # Render all the elements - elems = [] - for datum in data: - if self.subselector is not None: - datum = self.subselector(datum) - elems.append((self._render(parent, datum, patches, nsmap), datum)) - - # Return all the elements rendered, as well as the - # corresponding datum for the next step down the tree - return elems - - def will_render(self, datum): - """Hook method. - - An overridable hook method to determine whether this template - element will be rendered at all. By default, returns False - (inhibiting rendering) if the datum is None. - - :param datum: The datum associated with this template element. - """ - - # Don't render if datum is None - return datum is not None - - def _text_get(self): - """Template element text. - - Either None or a callable taking an object and optional - boolean do_raise indicator and returning the datum bound to - the text of the template element. - """ - - return self._text - - def _text_set(self, value): - # Convert value to a selector - if value is not None and not callable(value): - value = Selector(value) - - self._text = value - - def _text_del(self): - self._text = None - - text = property(_text_get, _text_set, _text_del) - - def tree(self): - """Return string representation of the template tree. - - Returns a representation of the template rooted at this - element as a string, suitable for inclusion in debug logs. - """ - - # Build the inner contents of the tag... - contents = [self.tag, '!selector=%r' % self.selector] - - # Add the text... - if self.text is not None: - contents.append('!text=%r' % self.text) - - # Add all the other attributes - for key, value in self.attrib.items(): - contents.append('%s=%r' % (key, value)) - - # If there are no children, return it as a closed tag - if len(self) == 0: - return '<%s/>' % ' '.join([str(i) for i in contents]) - - # OK, recurse to our children - children = [c.tree() for c in self] - - # Return the result - return ('<%s>%s' % - (' '.join(contents), ''.join(children), self.tag)) - - -def SubTemplateElement(parent, tag, attrib=None, selector=None, - subselector=None, **extra): - """Create a template element as a child of another. - - Corresponds to the etree.SubElement interface. Parameters are as - for TemplateElement, with the addition of the parent. - """ - - # Convert attributes - attrib = attrib or {} - attrib.update(extra) - - # Get a TemplateElement - elem = TemplateElement(tag, attrib=attrib, selector=selector, - subselector=subselector) - - # Append the parent safely - if parent is not None: - parent.append(elem) - - return elem - - -class Template(object): - """Represent a template.""" - - def __init__(self, root, nsmap=None): - """Initialize a template. - - :param root: The root element of the template. - :param nsmap: An optional namespace dictionary to be - associated with the root element of the - template. - """ - - self.root = root.unwrap() if root is not None else None - self.nsmap = nsmap or {} - self.serialize_options = dict(encoding='UTF-8', xml_declaration=True) - - def _serialize(self, parent, obj, siblings, nsmap=None): - """Internal serialization. - - Recursive routine to build a tree of etree.Element instances - from an object based on the template. Returns the first - etree.Element instance rendered, or None. - - :param parent: The parent etree.Element instance. Can be - None. - :param obj: The object to render. - :param siblings: The TemplateElement instances against which - to render the object. - :param nsmap: An optional namespace dictionary to be - associated with the etree.Element instance - rendered. - """ - - # First step, render the element - elems = siblings[0].render(parent, obj, siblings[1:], nsmap) - - # Now, recurse to all child elements - seen = set() - for idx, sibling in enumerate(siblings): - for child in sibling: - # Have we handled this child already? - if child.tag in seen: - continue - seen.add(child.tag) - - # Determine the child's siblings - nieces = [child] - for sib in siblings[idx + 1:]: - if child.tag in sib: - nieces.append(sib[child.tag]) - - # Now we recurse for every data element - for elem, datum in elems: - self._serialize(elem, datum, nieces) - - # Return the first element; at the top level, this will be the - # root element - if elems: - return elems[0][0] - - def serialize(self, obj, *args, **kwargs): - """Serialize an object. - - Serializes an object against the template. Returns a string - with the serialized XML. Positional and keyword arguments are - passed to etree.tostring(). - - :param obj: The object to serialize. - """ - - elem = self.make_tree(obj) - if elem is None: - return '' - - for k, v in self.serialize_options.items(): - kwargs.setdefault(k, v) - - # Serialize it into XML - return etree.tostring(elem, *args, **kwargs) - - def make_tree(self, obj): - """Create a tree. - - Serializes an object against the template. Returns an Element - node with appropriate children. - - :param obj: The object to serialize. - """ - - # If the template is empty, return the empty string - if self.root is None: - return None - - # Get the siblings and nsmap of the root element - siblings = self._siblings() - nsmap = self._nsmap() - - # Form the element tree - return self._serialize(None, obj, siblings, nsmap) - - def _siblings(self): - """Hook method for computing root siblings. - - An overridable hook method to return the siblings of the root - element. By default, this is the root element itself. - """ - - return [self.root] - - def _nsmap(self): - """Hook method for computing the namespace dictionary. - - An overridable hook method to return the namespace dictionary. - """ - - return self.nsmap.copy() - - def unwrap(self): - """Unwraps a template to return a template element.""" - - # Return the root element - return self.root - - def wrap(self): - """Wraps a template element to return a template.""" - - # We are a template - return self - - def apply(self, master): - """Hook method for determining slave applicability. - - An overridable hook method used to determine if this template - is applicable as a slave to a given master template. - - :param master: The master template to test. - """ - - return True - - def tree(self): - """Return string representation of the template tree. - - Returns a representation of the template as a string, suitable - for inclusion in debug logs. - """ - - return "%r: %s" % (self, self.root.tree()) - - -class MasterTemplate(Template): - """Represent a master template. - - Master templates are versioned derivatives of templates that - additionally allow slave templates to be attached. Slave - templates allow modification of the serialized result without - directly changing the master. - """ - - def __init__(self, root, version, nsmap=None): - """Initialize a master template. - - :param root: The root element of the template. - :param version: The version number of the template. - :param nsmap: An optional namespace dictionary to be - associated with the root element of the - template. - """ - - super(MasterTemplate, self).__init__(root, nsmap) - self.version = version - self.slaves = [] - - def __repr__(self): - """Return string representation of the template.""" - - return ("<%s.%s object version %s at %#x>" % - (self.__class__.__module__, self.__class__.__name__, - self.version, id(self))) - - def _siblings(self): - """Hook method for computing root siblings. - - An overridable hook method to return the siblings of the root - element. This is the root element plus the root elements of - all the slave templates. - """ - - return [self.root] + [slave.root for slave in self.slaves] - - def _nsmap(self): - """Hook method for computing the namespace dictionary. - - An overridable hook method to return the namespace dictionary. - The namespace dictionary is computed by taking the master - template's namespace dictionary and updating it from all the - slave templates. - """ - - nsmap = self.nsmap.copy() - for slave in self.slaves: - nsmap.update(slave._nsmap()) - return nsmap - - def attach(self, *slaves): - """Attach one or more slave templates. - - Attaches one or more slave templates to the master template. - Slave templates must have a root element with the same tag as - the master template. The slave template's apply() method will - be called to determine if the slave should be applied to this - master; if it returns False, that slave will be skipped. - (This allows filtering of slaves based on the version of the - master template.) - """ - - slave_list = [] - for slave in slaves: - slave = slave.wrap() - - # Make sure we have a tree match - if slave.root.tag != self.root.tag: - slavetag = slave.root.tag - mastertag = self.root.tag - msg = _("Template tree mismatch; adding slave %(slavetag)s " - "to master %(mastertag)s") % { - "slavetag": slavetag, - "mastertag": mastertag - } - raise ValueError(msg) - - # Make sure slave applies to this template - if not slave.apply(self): - continue - - slave_list.append(slave) - - # Add the slaves - self.slaves.extend(slave_list) - - def copy(self): - """Return a copy of this master template.""" - - # Return a copy of the MasterTemplate - tmp = self.__class__(self.root, self.version, self.nsmap) - tmp.slaves = self.slaves[:] - return tmp - - -class SlaveTemplate(Template): - """Represent a slave template. - - Slave templates are versioned derivatives of templates. Each - slave has a minimum version and optional maximum version of the - master template to which they can be attached. - """ - - def __init__(self, root, min_vers, max_vers=None, nsmap=None): - """Initialize a slave template. - - :param root: The root element of the template. - :param min_vers: The minimum permissible version of the master - template for this slave template to apply. - :param max_vers: An optional upper bound for the master - template version. - :param nsmap: An optional namespace dictionary to be - associated with the root element of the - template. - """ - - super(SlaveTemplate, self).__init__(root, nsmap) - self.min_vers = min_vers - self.max_vers = max_vers - - def __repr__(self): - """Return string representation of the template.""" - - return ("<%s.%s object versions %s-%s at %#x>" % - (self.__class__.__module__, self.__class__.__name__, - self.min_vers, self.max_vers, id(self))) - - def apply(self, master): - """Hook method for determining slave applicability. - - An overridable hook method used to determine if this template - is applicable as a slave to a given master template. This - version requires the master template to have a version number - between min_vers and max_vers. - - :param master: The master template to test. - """ - - # Does the master meet our minimum version requirement? - if master.version < self.min_vers: - return False - - # How about our maximum version requirement? - if self.max_vers is not None and master.version > self.max_vers: - return False - - return True - - -class TemplateBuilder(object): - """Template builder. - - This class exists to allow templates to be lazily built without - having to build them each time they are needed. It must be - subclassed, and the subclass must implement the construct() - method, which must return a Template (or subclass) instance. The - constructor will always return the template returned by - construct(), or, if it has a copy() method, a copy of that - template. - """ - - _tmpl = None - - def __new__(cls, copy=True): - """Construct and return a template. - - :param copy: If True (the default), a copy of the template - will be constructed and returned, if possible. - """ - - # Do we need to construct the template? - if cls._tmpl is None: - tmp = super(TemplateBuilder, cls).__new__(cls) - - # Construct the template - cls._tmpl = tmp.construct() - - # If the template has a copy attribute, return the result of - # calling it - if copy and hasattr(cls._tmpl, 'copy'): - return cls._tmpl.copy() - - # Return the template - return cls._tmpl - - def construct(self): - """Construct a template. - - Called to construct a template instance, which it must return. - Only called once. - """ - - raise NotImplementedError(_("subclasses must implement construct()!")) - - -def make_links(parent, selector=None): - """Attach an Atom element to the parent.""" - - elem = SubTemplateElement(parent, '{%s}link' % XMLNS_ATOM, - selector=selector) - elem.set('rel') - elem.set('type') - elem.set('href') - - # Just for completeness... - return elem - - -def make_flat_dict(name, selector=None, subselector=None, ns=None): - """Utility for simple XML templates. - - Utility for simple XML templates that traditionally used - XMLDictSerializer with no metadata. Returns a template element - where the top-level element has the given tag name, and where - sub-elements have tag names derived from the object's keys and - text derived from the object's values. This only works for flat - dictionary objects, not dictionaries containing nested lists or - dictionaries. - """ - - # Set up the names we need... - if ns is None: - elemname = name - tagname = Selector(0) - else: - elemname = '{%s}%s' % (ns, name) - tagname = lambda obj, do_raise=False: '{%s}%s' % (ns, obj[0]) - - if selector is None: - selector = name - - # Build the root element - root = TemplateElement(elemname, selector=selector, - subselector=subselector) - - # Build an element to represent all the keys and values - elem = SubTemplateElement(root, tagname, selector=get_items) - elem.text = 1 - - # Return the template - return root diff --git a/manila/tests/api/middleware/test_faults.py b/manila/tests/api/middleware/test_faults.py index ba75bc44b7..db80295efd 100644 --- a/manila/tests/api/middleware/test_faults.py +++ b/manila/tests/api/middleware/test_faults.py @@ -13,14 +13,11 @@ # License for the specific language governing permissions and limitations # under the License. -from xml.dom import minidom - from oslo_serialization import jsonutils import webob import webob.dec import webob.exc -from manila.api import common from manila.api.openstack import wsgi from manila import test @@ -88,9 +85,9 @@ class TestFaults(test.TestCase): def raiser(req): raise wsgi.Fault(webob.exc.HTTPNotFound(explanation='whut?')) - req = webob.Request.blank('/.xml') + req = webob.Request.blank('/.json') resp = req.get_response(raiser) - self.assertEqual(resp.content_type, "application/xml") + self.assertEqual(resp.content_type, "application/json") self.assertEqual(resp.status_int, 404) self.assertTrue('whut?' in resp.body) @@ -100,9 +97,9 @@ class TestFaults(test.TestCase): def raiser(req): raise wsgi.Fault(webob.exc.HTTPForbidden(explanation='whut?')) - req = webob.Request.blank('/.xml') + req = webob.Request.blank('/.json') resp = req.get_response(raiser) - self.assertEqual(resp.content_type, "application/xml") + self.assertEqual(resp.content_type, "application/json") self.assertEqual(resp.status_int, 403) self.assertTrue('resizeNotAllowed' not in resp.body) self.assertTrue('forbidden' in resp.body) @@ -111,104 +108,3 @@ class TestFaults(test.TestCase): """Ensure the status_int is set correctly on faults.""" fault = wsgi.Fault(webob.exc.HTTPBadRequest(explanation='what?')) self.assertEqual(fault.status_int, 400) - - def test_xml_serializer(self): - """Ensure that a v1.1 request responds with a v1 xmlns.""" - request = webob.Request.blank('/v1', - headers={"Accept": "application/xml"}) - - fault = wsgi.Fault(webob.exc.HTTPBadRequest(explanation='scram')) - response = request.get_response(fault) - - self.assertTrue(common.XML_NS_V1 in response.body) - self.assertEqual(response.content_type, "application/xml") - self.assertEqual(response.status_int, 400) - - -class FaultsXMLSerializationTestV11(test.TestCase): - """Tests covering `manila.api.openstack.faults:Fault` class.""" - - def _prepare_xml(self, xml_string): - xml_string = xml_string.replace(" ", "") - xml_string = xml_string.replace("\n", "") - xml_string = xml_string.replace("\t", "") - return xml_string - - def test_400_fault(self): - metadata = {'attributes': {"badRequest": 'code'}} - serializer = wsgi.XMLDictSerializer(metadata=metadata, - xmlns=common.XML_NS_V1) - - fixture = { - "badRequest": { - "message": "scram", - "code": 400, - }, - } - - output = serializer.serialize(fixture) - actual = minidom.parseString(self._prepare_xml(output)) - - expected = minidom.parseString(self._prepare_xml(""" - - scram - - """) % common.XML_NS_V1) - - self.assertEqual(expected.toxml(), actual.toxml()) - - def test_413_fault(self): - metadata = {'attributes': {"overLimit": 'code'}} - serializer = wsgi.XMLDictSerializer(metadata=metadata, - xmlns=common.XML_NS_V1) - - fixture = { - "overLimit": { - "message": "sorry", - "code": 413, - "retryAfter": 4, - }, - } - - output = serializer.serialize(fixture) - result = minidom.parseString(self._prepare_xml(output)) - - # result has 1 child - overLimit - self.assertEqual(result.firstChild, result.lastChild) - self.assertEqual(result.firstChild.tagName, 'overLimit') - - # overLimit has attrs code = '413' and xmlns = common.XML_NS_V1 - self.assertEqual(result.firstChild.getAttribute('code'), '413') - self.assertEqual(result.firstChild.getAttribute('xmlns'), - common.XML_NS_V1) - - # overLimit has childs message = 'sorry' and retryAfter = '4' - message = result.firstChild.getElementsByTagName('message') - retry_after = result.firstChild.getElementsByTagName('retryAfter') - self.assertEqual(len(message), 1) - self.assertEqual(len(retry_after), 1) - self.assertEqual(message[0].toxml(), 'sorry') - self.assertEqual(retry_after[0].toxml(), '4') - - def test_404_fault(self): - metadata = {'attributes': {"itemNotFound": 'code'}} - serializer = wsgi.XMLDictSerializer(metadata=metadata, - xmlns=common.XML_NS_V1) - - fixture = { - "itemNotFound": { - "message": "sorry", - "code": 404, - }, - } - - output = serializer.serialize(fixture) - actual = minidom.parseString(self._prepare_xml(output)) - - expected = minidom.parseString(self._prepare_xml(""" - - sorry - - """) % common.XML_NS_V1) - - self.assertEqual(expected.toxml(), actual.toxml()) diff --git a/manila/tests/api/openstack/test_wsgi.py b/manila/tests/api/openstack/test_wsgi.py index d35d877172..788defb8cd 100644 --- a/manila/tests/api/openstack/test_wsgi.py +++ b/manila/tests/api/openstack/test_wsgi.py @@ -29,14 +29,13 @@ class RequestTest(test.TestCase): self.assertEqual(result, "application/json") def test_content_type_from_accept(self): - for content_type in ('application/xml', - 'application/vnd.openstack.volume+xml', - 'application/json', - 'application/vnd.openstack.volume+json'): - request = wsgi.Request.blank('/tests/123') - request.headers["Accept"] = content_type - result = request.best_match_content_type() - self.assertEqual(result, content_type) + content_type = 'application/json' + request = wsgi.Request.blank('/tests/123') + request.headers["Accept"] = content_type + + result = request.best_match_content_type() + + self.assertEqual(result, content_type) def test_content_type_from_accept_best(self): request = wsgi.Request.blank('/tests/123') @@ -48,13 +47,9 @@ class RequestTest(test.TestCase): request.headers["Accept"] = ("application/json; q=0.3, " "application/xml; q=0.9") result = request.best_match_content_type() - self.assertEqual(result, "application/xml") + self.assertEqual(result, "application/json") def test_content_type_from_query_extension(self): - request = wsgi.Request.blank('/tests/123.xml') - result = request.best_match_content_type() - self.assertEqual(result, "application/xml") - request = wsgi.Request.blank('/tests/123.json') result = request.best_match_content_type() self.assertEqual(result, "application/json") @@ -63,12 +58,6 @@ class RequestTest(test.TestCase): result = request.best_match_content_type() self.assertEqual(result, "application/json") - def test_content_type_accept_and_query_extension(self): - request = wsgi.Request.blank('/tests/123.xml') - request.headers["Accept"] = "application/json" - result = request.best_match_content_type() - self.assertEqual(result, "application/xml") - def test_content_type_accept_default(self): request = wsgi.Request.blank('/tests/123.unsupported') request.headers["Accept"] = "application/unsupported1" @@ -162,16 +151,6 @@ class DictSerializerTest(test.TestCase): self.assertEqual(serializer.serialize({}, 'update'), '') -class XMLDictSerializerTest(test.TestCase): - def test_xml(self): - input_dict = dict(servers=dict(a=(2, 3))) - expected_xml = '(2,3)' - serializer = wsgi.XMLDictSerializer(xmlns="asdf") - result = serializer.serialize(input_dict) - result = result.replace('\n', '').replace(' ', '') - self.assertEqual(result, expected_xml) - - class JSONDictSerializerTest(test.TestCase): def test_json(self): input_dict = dict(servers=dict(a=(2, 3))) @@ -211,37 +190,6 @@ class JSONDeserializerTest(test.TestCase): self.assertEqual(deserializer.deserialize(data), as_dict) -class XMLDeserializerTest(test.TestCase): - def test_xml(self): - xml = """ - - 123 - 1 - 1 - - """.strip() - as_dict = { - 'body': { - 'a': { - 'a1': '1', - 'a2': '2', - 'bs': ['1', '2', '3', {'c': {'c1': '1'}}], - 'd': {'e': '1'}, - 'f': '1', - }, - }, - } - metadata = {'plurals': {'bs': 'b', 'ts': 't'}} - deserializer = wsgi.XMLDeserializer(metadata=metadata) - self.assertEqual(deserializer.deserialize(xml), as_dict) - - def test_xml_empty(self): - xml = """""" - as_dict = {"body": {"a": {}}} - deserializer = wsgi.XMLDeserializer() - self.assertEqual(deserializer.deserialize(xml), as_dict) - - class ResourceTest(test.TestCase): def test_resource_call(self): class Controller(object): @@ -299,19 +247,6 @@ class ResourceTest(test.TestCase): '{"fooAction": true}') self.assertEqual(controller._action_foo, method) - def test_get_method_action_xml(self): - class Controller(wsgi.Controller): - @wsgi.action('fooAction') - def _action_foo(self, req, id, body): - return body - - controller = Controller() - resource = wsgi.Resource(controller) - method, extensions = resource.get_method(None, 'action', - 'application/xml', - 'true') - self.assertEqual(controller._action_foo, method) - def test_get_method_action_bad_body(self): class Controller(wsgi.Controller): @wsgi.action('fooAction') @@ -467,20 +402,15 @@ class ResourceTest(test.TestCase): def deserialize(self, body): return 'json' - class XMLDeserializer(object): - def deserialize(self, body): - return 'xml' - class Controller(object): - @wsgi.deserializers(xml=XMLDeserializer) def index(self, req, pants=None): return pants controller = Controller() resource = wsgi.Resource(controller, json=JSONDeserializer) - obj = resource.deserialize(controller.index, 'application/xml', 'foo') - self.assertEqual(obj, 'xml') + obj = resource.deserialize(controller.index, 'application/json', 'foo') + self.assertEqual(obj, 'json') def test_register_actions(self): class Controller(object): diff --git a/manila/tests/api/test_extensions.py b/manila/tests/api/test_extensions.py index e1acf4b793..c478f772b0 100644 --- a/manila/tests/api/test_extensions.py +++ b/manila/tests/api/test_extensions.py @@ -16,7 +16,6 @@ import ddt import iso8601 -from lxml import etree import mock from oslo_config import cfg from oslo_serialization import jsonutils @@ -24,7 +23,6 @@ import webob from manila.api import extensions from manila.api.v1 import router -from manila.api import xmlutil from manila import policy from manila import test @@ -70,8 +68,7 @@ class ExtensionControllerTest(ExtensionTestCase): (fox_ext, ) = [ x for x in data['extensions'] if x['alias'] == 'FOXNSOX'] self.assertEqual( - fox_ext, {'namespace': 'http://www.fox.in.socks/api/ext/pie/v1.0', - 'name': 'Fox In Socks', + fox_ext, {'name': 'Fox In Socks', 'updated': '2011-01-22T13:25:27-06:00', 'description': 'The Fox In Socks Extension.', 'alias': 'FOXNSOX', @@ -93,8 +90,7 @@ class ExtensionControllerTest(ExtensionTestCase): data = jsonutils.loads(response.body) self.assertEqual( data['extension'], - {"namespace": "http://www.fox.in.socks/api/ext/pie/v1.0", - "name": "Fox In Socks", + {"name": "Fox In Socks", "updated": "2011-01-22T13:25:27-06:00", "description": "The Fox In Socks Extension.", "alias": "FOXNSOX", @@ -106,55 +102,6 @@ class ExtensionControllerTest(ExtensionTestCase): response = request.get_response(app) self.assertEqual(404, response.status_int) - def test_list_extensions_xml(self): - app = router.APIRouter() - request = webob.Request.blank("/fake/extensions") - request.accept = "application/xml" - response = request.get_response(app) - self.assertEqual(200, response.status_int) - - root = etree.XML(response.body) - self.assertEqual(root.tag.split('extensions')[0], NS) - - # Make sure we have all the extensions, extras extensions being OK. - exts = root.findall('{0}extension'.format(NS)) - self.assertTrue(len(exts) >= len(self.ext_list)) - - # Make sure that at least Fox in Sox is correct. - (fox_ext, ) = [x for x in exts if x.get('alias') == 'FOXNSOX'] - self.assertEqual(fox_ext.get('name'), 'Fox In Socks') - self.assertEqual( - fox_ext.get('namespace'), - 'http://www.fox.in.socks/api/ext/pie/v1.0') - self.assertEqual(fox_ext.get('updated'), '2011-01-22T13:25:27-06:00') - self.assertEqual( - fox_ext.findtext('{0}description'.format(NS)), - 'The Fox In Socks Extension.') - - xmlutil.validate_schema(root, 'extensions') - - def test_get_extension_xml(self): - app = router.APIRouter() - request = webob.Request.blank("/fake/extensions/FOXNSOX") - request.accept = "application/xml" - response = request.get_response(app) - self.assertEqual(200, response.status_int) - xml = response.body - - root = etree.XML(xml) - self.assertEqual(root.tag.split('extension')[0], NS) - self.assertEqual(root.get('alias'), 'FOXNSOX') - self.assertEqual(root.get('name'), 'Fox In Socks') - self.assertEqual( - root.get('namespace'), - 'http://www.fox.in.socks/api/ext/pie/v1.0') - self.assertEqual(root.get('updated'), '2011-01-22T13:25:27-06:00') - self.assertEqual( - root.findtext('{0}description'.format(NS)), - 'The Fox In Socks Extension.') - - xmlutil.validate_schema(root, 'extension') - @ddt.ddt class ExtensionAuthorizeTestCase(test.TestCase): diff --git a/manila/tests/api/test_xmlutil.py b/manila/tests/api/test_xmlutil.py deleted file mode 100644 index 11eca1496c..0000000000 --- a/manila/tests/api/test_xmlutil.py +++ /dev/null @@ -1,714 +0,0 @@ -# Copyright 2011 OpenStack LLC. -# 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 xml.dom import minidom - -from lxml import etree - -from manila.api import xmlutil -from manila import test - - -class SelectorTest(test.TestCase): - obj_for_test = {'test': {'name': 'test', - 'values': [1, 2, 3], - 'attrs': {'foo': 1, - 'bar': 2, - 'baz': 3, }, }, } - - def test_empty_selector(self): - sel = xmlutil.Selector() - self.assertEqual(len(sel.chain), 0) - self.assertEqual(sel(self.obj_for_test), self.obj_for_test) - - def test_dict_selector(self): - sel = xmlutil.Selector('test') - self.assertEqual(len(sel.chain), 1) - self.assertEqual(sel.chain[0], 'test') - self.assertEqual(sel(self.obj_for_test), - self.obj_for_test['test']) - - def test_datum_selector(self): - sel = xmlutil.Selector('test', 'name') - self.assertEqual(len(sel.chain), 2) - self.assertEqual(sel.chain[0], 'test') - self.assertEqual(sel.chain[1], 'name') - self.assertEqual(sel(self.obj_for_test), 'test') - - def test_list_selector(self): - sel = xmlutil.Selector('test', 'values', 0) - self.assertEqual(len(sel.chain), 3) - self.assertEqual(sel.chain[0], 'test') - self.assertEqual(sel.chain[1], 'values') - self.assertEqual(sel.chain[2], 0) - self.assertEqual(sel(self.obj_for_test), 1) - - def test_items_selector(self): - sel = xmlutil.Selector('test', 'attrs', xmlutil.get_items) - self.assertEqual(len(sel.chain), 3) - self.assertEqual(sel.chain[2], xmlutil.get_items) - for key, val in sel(self.obj_for_test): - self.assertEqual(self.obj_for_test['test']['attrs'][key], val) - - def test_missing_key_selector(self): - sel = xmlutil.Selector('test2', 'attrs') - self.assertEqual(sel(self.obj_for_test), None) - self.assertRaises(KeyError, sel, self.obj_for_test, True) - - def test_constant_selector(self): - sel = xmlutil.ConstantSelector('Foobar') - self.assertEqual(sel.value, 'Foobar') - self.assertEqual(sel(self.obj_for_test), 'Foobar') - - -class TemplateElementTest(test.TestCase): - def test_element_initial_attributes(self): - # Create a template element with some attributes - elem = xmlutil.TemplateElement('test', attrib=dict(a=1, b=2, c=3), - c=4, d=5, e=6) - - # Verify all the attributes are as expected - expected = dict(a=1, b=2, c=4, d=5, e=6) - for k, v in expected.items(): - self.assertEqual(elem.attrib[k].chain[0], v) - - def test_element_get_attributes(self): - expected = dict(a=1, b=2, c=3) - - # Create a template element with some attributes - elem = xmlutil.TemplateElement('test', attrib=expected) - - # Verify that get() retrieves the attributes - for k, v in expected.items(): - self.assertEqual(elem.get(k).chain[0], v) - - def test_element_set_attributes(self): - attrs = dict(a=None, b='foo', c=xmlutil.Selector('foo', 'bar')) - - # Create a bare template element with no attributes - elem = xmlutil.TemplateElement('test') - - # Set the attribute values - for k, v in attrs.items(): - elem.set(k, v) - - # Now verify what got set - self.assertEqual(len(elem.attrib['a'].chain), 1) - self.assertEqual(elem.attrib['a'].chain[0], 'a') - self.assertEqual(len(elem.attrib['b'].chain), 1) - self.assertEqual(elem.attrib['b'].chain[0], 'foo') - self.assertEqual(elem.attrib['c'], attrs['c']) - - def test_element_attribute_keys(self): - attrs = dict(a=1, b=2, c=3, d=4) - expected = set(attrs.keys()) - - # Create a template element with some attributes - elem = xmlutil.TemplateElement('test', attrib=attrs) - - # Now verify keys - self.assertEqual(set(elem.keys()), expected) - - def test_element_attribute_items(self): - expected = dict(a=xmlutil.Selector(1), - b=xmlutil.Selector(2), - c=xmlutil.Selector(3)) - keys = set(expected.keys()) - - # Create a template element with some attributes - elem = xmlutil.TemplateElement('test', attrib=expected) - - # Now verify items - for k, v in elem.items(): - self.assertEqual(expected[k], v) - keys.remove(k) - - # Did we visit all keys? - self.assertEqual(len(keys), 0) - - def test_element_selector_none(self): - # Create a template element with no selector - elem = xmlutil.TemplateElement('test') - - self.assertEqual(len(elem.selector.chain), 0) - - def test_element_selector_string(self): - # Create a template element with a string selector - elem = xmlutil.TemplateElement('test', selector='test') - - self.assertEqual(len(elem.selector.chain), 1) - self.assertEqual(elem.selector.chain[0], 'test') - - def test_element_selector(self): - sel = xmlutil.Selector('a', 'b') - - # Create a template element with an explicit selector - elem = xmlutil.TemplateElement('test', selector=sel) - - self.assertEqual(elem.selector, sel) - - def test_element_subselector_none(self): - # Create a template element with no subselector - elem = xmlutil.TemplateElement('test') - - self.assertEqual(elem.subselector, None) - - def test_element_subselector_string(self): - # Create a template element with a string subselector - elem = xmlutil.TemplateElement('test', subselector='test') - - self.assertEqual(len(elem.subselector.chain), 1) - self.assertEqual(elem.subselector.chain[0], 'test') - - def test_element_subselector(self): - sel = xmlutil.Selector('a', 'b') - - # Create a template element with an explicit subselector - elem = xmlutil.TemplateElement('test', subselector=sel) - - self.assertEqual(elem.subselector, sel) - - def test_element_append_child(self): - # Create an element - elem = xmlutil.TemplateElement('test') - - # Make sure the element starts off empty - self.assertEqual(len(elem), 0) - - # Create a child element - child = xmlutil.TemplateElement('child') - - # Append the child to the parent - elem.append(child) - - # Verify that the child was added - self.assertEqual(len(elem), 1) - self.assertEqual(elem[0], child) - self.assertEqual('child' in elem, True) - self.assertEqual(elem['child'], child) - - # Ensure that multiple children of the same name are rejected - child2 = xmlutil.TemplateElement('child') - self.assertRaises(KeyError, elem.append, child2) - - def test_element_extend_children(self): - # Create an element - elem = xmlutil.TemplateElement('test') - - # Make sure the element starts off empty - self.assertEqual(len(elem), 0) - - # Create a few children - children = [xmlutil.TemplateElement('child1'), - xmlutil.TemplateElement('child2'), - xmlutil.TemplateElement('child3'), ] - - # Extend the parent by those children - elem.extend(children) - - # Verify that the children were added - self.assertEqual(len(elem), 3) - for idx in range(len(elem)): - self.assertEqual(children[idx], elem[idx]) - self.assertEqual(children[idx].tag in elem, True) - self.assertEqual(elem[children[idx].tag], children[idx]) - - # Ensure that multiple children of the same name are rejected - children2 = [xmlutil.TemplateElement('child4'), - xmlutil.TemplateElement('child1'), ] - self.assertRaises(KeyError, elem.extend, children2) - - # Also ensure that child4 was not added - self.assertEqual(len(elem), 3) - self.assertEqual(elem[-1].tag, 'child3') - - def test_element_insert_child(self): - # Create an element - elem = xmlutil.TemplateElement('test') - - # Make sure the element starts off empty - self.assertEqual(len(elem), 0) - - # Create a few children - children = [xmlutil.TemplateElement('child1'), - xmlutil.TemplateElement('child2'), - xmlutil.TemplateElement('child3'), ] - - # Extend the parent by those children - elem.extend(children) - - # Create a child to insert - child = xmlutil.TemplateElement('child4') - - # Insert it - elem.insert(1, child) - - # Ensure the child was inserted in the right place - self.assertEqual(len(elem), 4) - children.insert(1, child) - for idx in range(len(elem)): - self.assertEqual(children[idx], elem[idx]) - self.assertEqual(children[idx].tag in elem, True) - self.assertEqual(elem[children[idx].tag], children[idx]) - - # Ensure that multiple children of the same name are rejected - child2 = xmlutil.TemplateElement('child2') - self.assertRaises(KeyError, elem.insert, 2, child2) - - def test_element_remove_child(self): - # Create an element - elem = xmlutil.TemplateElement('test') - - # Make sure the element starts off empty - self.assertEqual(len(elem), 0) - - # Create a few children - children = [xmlutil.TemplateElement('child1'), - xmlutil.TemplateElement('child2'), - xmlutil.TemplateElement('child3'), ] - - # Extend the parent by those children - elem.extend(children) - - # Create a test child to remove - child = xmlutil.TemplateElement('child2') - - # Try to remove it - self.assertRaises(ValueError, elem.remove, child) - - # Ensure that no child was removed - self.assertEqual(len(elem), 3) - - # Now remove a legitimate child - elem.remove(children[1]) - - # Ensure that the child was removed - self.assertEqual(len(elem), 2) - self.assertEqual(elem[0], children[0]) - self.assertEqual(elem[1], children[2]) - self.assertEqual('child2' in elem, False) - - # Ensure the child cannot be retrieved by name - def get_key(elem, key): - return elem[key] - self.assertRaises(KeyError, get_key, elem, 'child2') - - def test_element_text(self): - # Create an element - elem = xmlutil.TemplateElement('test') - - # Ensure that it has no text - self.assertEqual(elem.text, None) - - # Try setting it to a string and ensure it becomes a selector - elem.text = 'test' - self.assertEqual(hasattr(elem.text, 'chain'), True) - self.assertEqual(len(elem.text.chain), 1) - self.assertEqual(elem.text.chain[0], 'test') - - # Try resetting the text to None - elem.text = None - self.assertEqual(elem.text, None) - - # Now make up a selector and try setting the text to that - sel = xmlutil.Selector() - elem.text = sel - self.assertEqual(elem.text, sel) - - # Finally, try deleting the text and see what happens - del elem.text - self.assertEqual(elem.text, None) - - def test_apply_attrs(self): - # Create a template element - attrs = dict(attr1=xmlutil.ConstantSelector(1), - attr2=xmlutil.ConstantSelector(2)) - tmpl_elem = xmlutil.TemplateElement('test', attrib=attrs) - - # Create an etree element - elem = etree.Element('test') - - # Apply the template to the element - tmpl_elem.apply(elem, None) - - # Now, verify the correct attributes were set - for k, v in elem.items(): - self.assertEqual(str(attrs[k].value), v) - - def test_apply_text(self): - # Create a template element - tmpl_elem = xmlutil.TemplateElement('test') - tmpl_elem.text = xmlutil.ConstantSelector(1) - - # Create an etree element - elem = etree.Element('test') - - # Apply the template to the element - tmpl_elem.apply(elem, None) - - # Now, verify the text was set - self.assertEqual(str(tmpl_elem.text.value), elem.text) - - def test__render(self): - attrs = dict(attr1=xmlutil.ConstantSelector(1), - attr2=xmlutil.ConstantSelector(2), - attr3=xmlutil.ConstantSelector(3)) - - # Create a master template element - master_elem = xmlutil.TemplateElement('test', attr1=attrs['attr1']) - - # Create a couple of slave template element - slave_elems = [xmlutil.TemplateElement('test', attr2=attrs['attr2']), - xmlutil.TemplateElement('test', attr3=attrs['attr3']), ] - - # Try the render - elem = master_elem._render(None, None, slave_elems, None) - - # Verify the particulars of the render - self.assertEqual(elem.tag, 'test') - self.assertEqual(len(elem.nsmap), 0) - for k, v in elem.items(): - self.assertEqual(str(attrs[k].value), v) - - # Create a parent for the element to be rendered - parent = etree.Element('parent') - - # Try the render again... - elem = master_elem._render(parent, None, slave_elems, dict(a='foo')) - - # Verify the particulars of the render - self.assertEqual(len(parent), 1) - self.assertEqual(parent[0], elem) - self.assertEqual(len(elem.nsmap), 1) - self.assertEqual(elem.nsmap['a'], 'foo') - - def test_render(self): - # Create a template element - tmpl_elem = xmlutil.TemplateElement('test') - tmpl_elem.text = xmlutil.Selector() - - # Create the object we're going to render - obj = ['elem1', 'elem2', 'elem3', 'elem4'] - - # Try a render with no object - elems = tmpl_elem.render(None, None) - self.assertEqual(len(elems), 0) - - # Try a render with one object - elems = tmpl_elem.render(None, 'foo') - self.assertEqual(len(elems), 1) - self.assertEqual(elems[0][0].text, 'foo') - self.assertEqual(elems[0][1], 'foo') - - # Now, try rendering an object with multiple entries - parent = etree.Element('parent') - elems = tmpl_elem.render(parent, obj) - self.assertEqual(len(elems), 4) - - # Check the results - for idx in range(len(obj)): - self.assertEqual(elems[idx][0].text, obj[idx]) - self.assertEqual(elems[idx][1], obj[idx]) - - def test_subelement(self): - # Try the SubTemplateElement constructor - parent = xmlutil.SubTemplateElement(None, 'parent') - self.assertEqual(parent.tag, 'parent') - self.assertEqual(len(parent), 0) - - # Now try it with a parent element - child = xmlutil.SubTemplateElement(parent, 'child') - self.assertEqual(child.tag, 'child') - self.assertEqual(len(parent), 1) - self.assertEqual(parent[0], child) - - def test_wrap(self): - # These are strange methods, but they make things easier - elem = xmlutil.TemplateElement('test') - self.assertEqual(elem.unwrap(), elem) - self.assertEqual(elem.wrap().root, elem) - - def test_dyntag(self): - obj = ['a', 'b', 'c'] - - # Create a template element with a dynamic tag - tmpl_elem = xmlutil.TemplateElement(xmlutil.Selector()) - - # Try the render - parent = etree.Element('parent') - elems = tmpl_elem.render(parent, obj) - - # Verify the particulars of the render - self.assertEqual(len(elems), len(obj)) - for idx in range(len(obj)): - self.assertEqual(elems[idx][0].tag, obj[idx]) - - -class TemplateTest(test.TestCase): - def test_wrap(self): - # These are strange methods, but they make things easier - elem = xmlutil.TemplateElement('test') - tmpl = xmlutil.Template(elem) - self.assertEqual(tmpl.unwrap(), elem) - self.assertEqual(tmpl.wrap(), tmpl) - - def test__siblings(self): - # Set up a basic template - elem = xmlutil.TemplateElement('test') - tmpl = xmlutil.Template(elem) - - # Check that we get the right siblings - siblings = tmpl._siblings() - self.assertEqual(len(siblings), 1) - self.assertEqual(siblings[0], elem) - - def test__nsmap(self): - # Set up a basic template - elem = xmlutil.TemplateElement('test') - tmpl = xmlutil.Template(elem, nsmap=dict(a="foo")) - - # Check out that we get the right namespace dictionary - nsmap = tmpl._nsmap() - self.assertNotEqual(id(nsmap), id(tmpl.nsmap)) - self.assertEqual(len(nsmap), 1) - self.assertEqual(nsmap['a'], 'foo') - - def test_master_attach(self): - # Set up a master template - elem = xmlutil.TemplateElement('test') - tmpl = xmlutil.MasterTemplate(elem, 1) - - # Make sure it has a root but no slaves - self.assertEqual(tmpl.root, elem) - self.assertEqual(len(tmpl.slaves), 0) - - # Try to attach an invalid slave - bad_elem = xmlutil.TemplateElement('test2') - self.assertRaises(ValueError, tmpl.attach, bad_elem) - self.assertEqual(len(tmpl.slaves), 0) - - # Try to attach an invalid and a valid slave - good_elem = xmlutil.TemplateElement('test') - self.assertRaises(ValueError, tmpl.attach, good_elem, bad_elem) - self.assertEqual(len(tmpl.slaves), 0) - - # Try to attach an inapplicable template - class InapplicableTemplate(xmlutil.Template): - def apply(self, master): - return False - inapp_tmpl = InapplicableTemplate(good_elem) - tmpl.attach(inapp_tmpl) - self.assertEqual(len(tmpl.slaves), 0) - - # Now try attaching an applicable template - tmpl.attach(good_elem) - self.assertEqual(len(tmpl.slaves), 1) - self.assertEqual(tmpl.slaves[0].root, good_elem) - - def test_master_copy(self): - # Construct a master template - elem = xmlutil.TemplateElement('test') - tmpl = xmlutil.MasterTemplate(elem, 1, nsmap=dict(a='foo')) - - # Give it a slave - slave = xmlutil.TemplateElement('test') - tmpl.attach(slave) - - # Construct a copy - copy = tmpl.copy() - - # Check to see if we actually managed a copy - self.assertNotEqual(tmpl, copy) - self.assertEqual(tmpl.root, copy.root) - self.assertEqual(tmpl.version, copy.version) - self.assertEqual(id(tmpl.nsmap), id(copy.nsmap)) - self.assertNotEqual(id(tmpl.slaves), id(copy.slaves)) - self.assertEqual(len(tmpl.slaves), len(copy.slaves)) - self.assertEqual(tmpl.slaves[0], copy.slaves[0]) - - def test_slave_apply(self): - # Construct a master template - elem = xmlutil.TemplateElement('test') - master = xmlutil.MasterTemplate(elem, 3) - - # Construct a slave template with applicable minimum version - slave = xmlutil.SlaveTemplate(elem, 2) - self.assertEqual(slave.apply(master), True) - - # Construct a slave template with equal minimum version - slave = xmlutil.SlaveTemplate(elem, 3) - self.assertEqual(slave.apply(master), True) - - # Construct a slave template with inapplicable minimum version - slave = xmlutil.SlaveTemplate(elem, 4) - self.assertEqual(slave.apply(master), False) - - # Construct a slave template with applicable version range - slave = xmlutil.SlaveTemplate(elem, 2, 4) - self.assertEqual(slave.apply(master), True) - - # Construct a slave template with low version range - slave = xmlutil.SlaveTemplate(elem, 1, 2) - self.assertEqual(slave.apply(master), False) - - # Construct a slave template with high version range - slave = xmlutil.SlaveTemplate(elem, 4, 5) - self.assertEqual(slave.apply(master), False) - - # Construct a slave template with matching version range - slave = xmlutil.SlaveTemplate(elem, 3, 3) - self.assertEqual(slave.apply(master), True) - - def test__serialize(self): - # Our test object to serialize - obj = {'test': {'name': 'foobar', - 'values': [1, 2, 3, 4], - 'attrs': {'a': 1, - 'b': 2, - 'c': 3, - 'd': 4, }, - 'image': {'name': 'image_foobar', 'id': 42, }, }, } - - # Set up our master template - root = xmlutil.TemplateElement('test', selector='test', - name='name') - value = xmlutil.SubTemplateElement(root, 'value', selector='values') - value.text = xmlutil.Selector() - attrs = xmlutil.SubTemplateElement(root, 'attrs', selector='attrs') - xmlutil.SubTemplateElement(attrs, 'attr', selector=xmlutil.get_items, - key=0, value=1) - master = xmlutil.MasterTemplate(root, 1, nsmap=dict(f='foo')) - - # Set up our slave template - root_slave = xmlutil.TemplateElement('test', selector='test') - image = xmlutil.SubTemplateElement(root_slave, 'image', - selector='image', id='id') - image.text = xmlutil.Selector('name') - slave = xmlutil.SlaveTemplate(root_slave, 1, nsmap=dict(b='bar')) - - # Attach the slave to the master... - master.attach(slave) - - # Try serializing our object - siblings = master._siblings() - nsmap = master._nsmap() - result = master._serialize(None, obj, siblings, nsmap) - - # Now we get to manually walk the element tree... - self.assertEqual(result.tag, 'test') - self.assertEqual(len(result.nsmap), 2) - self.assertEqual(result.nsmap['f'], 'foo') - self.assertEqual(result.nsmap['b'], 'bar') - self.assertEqual(result.get('name'), obj['test']['name']) - for idx, val in enumerate(obj['test']['values']): - self.assertEqual(result[idx].tag, 'value') - self.assertEqual(result[idx].text, str(val)) - idx += 1 - self.assertEqual(result[idx].tag, 'attrs') - for attr in result[idx]: - self.assertEqual(attr.tag, 'attr') - self.assertEqual(attr.get('value'), - str(obj['test']['attrs'][attr.get('key')])) - idx += 1 - self.assertEqual(result[idx].tag, 'image') - self.assertEqual(result[idx].get('id'), - str(obj['test']['image']['id'])) - self.assertEqual(result[idx].text, obj['test']['image']['name']) - - -class MasterTemplateBuilder(xmlutil.TemplateBuilder): - def construct(self): - elem = xmlutil.TemplateElement('test') - return xmlutil.MasterTemplate(elem, 1) - - -class SlaveTemplateBuilder(xmlutil.TemplateBuilder): - def construct(self): - elem = xmlutil.TemplateElement('test') - return xmlutil.SlaveTemplate(elem, 1) - - -class TemplateBuilderTest(test.TestCase): - def test_master_template_builder(self): - # Make sure the template hasn't been built yet - self.assertEqual(MasterTemplateBuilder._tmpl, None) - - # Now, construct the template - tmpl1 = MasterTemplateBuilder() - - # Make sure that there is a template cached... - self.assertNotEqual(MasterTemplateBuilder._tmpl, None) - - # Make sure it wasn't what was returned... - self.assertNotEqual(MasterTemplateBuilder._tmpl, tmpl1) - - # Make sure it doesn't get rebuilt - cached = MasterTemplateBuilder._tmpl - tmpl2 = MasterTemplateBuilder() - self.assertEqual(MasterTemplateBuilder._tmpl, cached) - - # Make sure we're always getting fresh copies - self.assertNotEqual(tmpl1, tmpl2) - - # Make sure we can override the copying behavior - tmpl3 = MasterTemplateBuilder(False) - self.assertEqual(MasterTemplateBuilder._tmpl, tmpl3) - - def test_slave_template_builder(self): - # Make sure the template hasn't been built yet - self.assertEqual(SlaveTemplateBuilder._tmpl, None) - - # Now, construct the template - tmpl1 = SlaveTemplateBuilder() - - # Make sure there is a template cached... - self.assertNotEqual(SlaveTemplateBuilder._tmpl, None) - - # Make sure it was what was returned... - self.assertEqual(SlaveTemplateBuilder._tmpl, tmpl1) - - # Make sure it doesn't get rebuilt - tmpl2 = SlaveTemplateBuilder() - self.assertEqual(SlaveTemplateBuilder._tmpl, tmpl1) - - # Make sure we're always getting the cached copy - self.assertEqual(tmpl1, tmpl2) - - -class MiscellaneousXMLUtilTests(test.TestCase): - def test_make_flat_dict(self): - expected = minidom.parseString( - "" - "foobar" - ) - root = xmlutil.make_flat_dict('wrapper') - tmpl = xmlutil.MasterTemplate(root, 1) - result = tmpl.serialize(dict(wrapper=dict(a='foo', b='bar'))) - actual = minidom.parseString(result) - - self.assertEqual(expected.firstChild.tagName, - actual.firstChild.tagName) - expected_child_a = expected.firstChild.getElementsByTagName('a') - expected_child_b = expected.firstChild.getElementsByTagName('b') - actual_child_a = actual.firstChild.getElementsByTagName('a') - actual_child_b = actual.firstChild.getElementsByTagName('b') - self.assertEqual(len(expected_child_a), 1) - self.assertEqual(len(expected_child_b), 1) - self.assertEqual(len(actual_child_a), 1) - self.assertEqual(len(actual_child_b), 1) - self.assertEqual(expected_child_a[0].toxml(), - actual_child_a[0].toxml()) - self.assertEqual(expected_child_b[0].toxml(), - actual_child_b[0].toxml()) diff --git a/manila/tests/api/v1/test_limits.py b/manila/tests/api/v1/test_limits.py index 5f7df06554..f8354b81c3 100644 --- a/manila/tests/api/v1/test_limits.py +++ b/manila/tests/api/v1/test_limits.py @@ -18,9 +18,7 @@ Tests dealing with HTTP rate-limiting. """ import httplib -from xml.dom import minidom -from lxml import etree from oslo_serialization import jsonutils import six from six import moves @@ -28,7 +26,6 @@ import webob from manila.api.v1 import limits from manila.api import views -from manila.api import xmlutil import manila.context from manila import test @@ -279,26 +276,6 @@ class LimitMiddlewareTest(BaseLimitTestSuite): value = body["overLimitFault"]["details"].strip() self.assertEqual(value, expected) - def test_limited_request_xml(self): - """Test a rate-limited (413) response as XML.""" - request = webob.Request.blank("/") - response = request.get_response(self.app) - self.assertEqual(200, response.status_int) - - request = webob.Request.blank("/") - request.accept = "application/xml" - response = request.get_response(self.app) - self.assertEqual(response.status_int, 413) - - root = minidom.parseString(response.body).childNodes[0] - expected = "Only 1 GET request(s) can be made to * every minute." - - details = root.getElementsByTagName("details") - self.assertEqual(details.length, 1) - - value = details.item(0).firstChild.data.strip() - self.assertEqual(value, expected) - class LimitTest(BaseLimitTestSuite): """Tests for the `limits.Limit` class.""" @@ -802,89 +779,3 @@ class LimitsViewBuilderTest(test.TestCase): rate_limits = [] output = self.view_builder.build(rate_limits, abs_limits) self.assertDictMatch(output, expected_limits) - - -class LimitsXMLSerializationTest(test.TestCase): - def test_xml_declaration(self): - serializer = limits.LimitsTemplate() - - fixture = {"limits": { - "rate": [], - "absolute": {}}} - - output = serializer.serialize(fixture) - has_dec = output.startswith("") - self.assertTrue(has_dec) - - def test_index(self): - serializer = limits.LimitsTemplate() - fixture = { - "limits": { - "rate": [{ - "uri": "*", - "regex": ".*", - "limit": [{ - "value": 10, - "verb": "POST", - "remaining": 2, - "unit": "MINUTE", - "next-available": "2011-12-15T22:42:45Z"}]}, - {"uri": "*/servers", - "regex": "^/servers", - "limit": [{ - "value": 50, - "verb": "POST", - "remaining": 10, - "unit": "DAY", - "next-available": "2011-12-15T22:42:45Z"}]}], - "absolute": {"maxServerMeta": 1, - "maxImageMeta": 1, - "maxPersonality": 5, - "maxPersonalitySize": 10240}}} - - output = serializer.serialize(fixture) - root = etree.XML(output) - xmlutil.validate_schema(root, 'limits') - - # verify absolute limits - absolutes = root.xpath('ns:absolute/ns:limit', namespaces=NS) - self.assertEqual(len(absolutes), 4) - for limit in absolutes: - name = limit.get('name') - value = limit.get('value') - self.assertEqual(value, str(fixture['limits']['absolute'][name])) - - # verify rate limits - rates = root.xpath('ns:rates/ns:rate', namespaces=NS) - self.assertEqual(len(rates), 2) - for i, rate in enumerate(rates): - for key in ['uri', 'regex']: - self.assertEqual(rate.get(key), - str(fixture['limits']['rate'][i][key])) - rate_limits = rate.xpath('ns:limit', namespaces=NS) - self.assertEqual(len(rate_limits), 1) - for j, limit in enumerate(rate_limits): - for key in ['verb', 'value', 'remaining', 'unit', - 'next-available']: - self.assertEqual( - limit.get(key), - str(fixture['limits']['rate'][i]['limit'][j][key])) - - def test_index_no_limits(self): - serializer = limits.LimitsTemplate() - - fixture = {"limits": { - "rate": [], - "absolute": {}}} - - output = serializer.serialize(fixture) - root = etree.XML(output) - xmlutil.validate_schema(root, 'limits') - - # verify absolute limits - absolutes = root.xpath('ns:absolute/ns:limit', namespaces=NS) - self.assertEqual(len(absolutes), 0) - - # verify rate limits - rates = root.xpath('ns:rates/ns:rate', namespaces=NS) - self.assertEqual(len(rates), 0) diff --git a/manila/tests/test_utils.py b/manila/tests/test_utils.py index a3d1a1bf8b..106ec41b6e 100644 --- a/manila/tests/test_utils.py +++ b/manila/tests/test_utils.py @@ -284,36 +284,6 @@ class GenericUtilsTestCase(test.TestCase): self.assertFalse(result) timeutils.utcnow.assert_called_once_with() - def test_safe_parse_xml(self): - - normal_body = ('' - 'heythere') - - def killer_body(): - return ((""" - - ]> - - - %(d)s - - """) % { - 'a': 'A' * 10, - 'b': '&a;' * 10, - 'c': '&b;' * 10, - 'd': '&c;' * 9999, - }).strip() - - dom = utils.safe_minidom_parse_string(normal_body) - # Some versions of minidom inject extra newlines so we ignore them - result = str(dom.toxml()).replace('\n', '') - self.assertEqual(normal_body, result) - - self.assertRaises(ValueError, - utils.safe_minidom_parse_string, - killer_body()) - def test_is_ipv6_configured0(self): fake_fd = mock.Mock() fake_fd.read.return_value = 'test' diff --git a/manila/utils.py b/manila/utils.py index 764b86b81e..53a98c178e 100644 --- a/manila/utils.py +++ b/manila/utils.py @@ -26,10 +26,6 @@ import shutil import socket import sys import tempfile -from xml.dom import minidom -from xml.parsers import expat -from xml import sax -from xml.sax import expatreader from eventlet import pools import netaddr @@ -191,46 +187,6 @@ class LazyPluggable(object): return getattr(backend, key) -class ProtectedExpatParser(expatreader.ExpatParser): - """An expat parser which disables DTD's and entities by default.""" - - def __init__(self, forbid_dtd=True, forbid_entities=True, - *args, **kwargs): - # Python 2.x old style class - expatreader.ExpatParser.__init__(self, *args, **kwargs) - self.forbid_dtd = forbid_dtd - self.forbid_entities = forbid_entities - - def start_doctype_decl(self, name, sysid, pubid, has_internal_subset): - raise ValueError("Inline DTD forbidden") - - def entity_decl(self, entityName, is_parameter_entity, value, base, - systemId, publicId, notationName): - raise ValueError(" forbidden") - - def unparsed_entity_decl(self, name, base, sysid, pubid, notation_name): - # expat 1.2 - raise ValueError(" forbidden") - - def reset(self): - expatreader.ExpatParser.reset(self) - if self.forbid_dtd: - self._parser.StartDoctypeDeclHandler = self.start_doctype_decl - if self.forbid_entities: - self._parser.EntityDeclHandler = self.entity_decl - self._parser.UnparsedEntityDeclHandler = self.unparsed_entity_decl - - -def safe_minidom_parse_string(xml_string): - """Parse an XML string using minidom safely. - - """ - try: - return minidom.parseString(xml_string, parser=ProtectedExpatParser()) - except sax.SAXParseException: - raise expat.ExpatError() - - def delete_if_exists(pathname): """Delete a file, but ignore file not found error."""