diff options
Diffstat (limited to 'nova/api')
| -rw-r--r-- | nova/api/openstack/common.py | 26 | ||||
| -rw-r--r-- | nova/api/openstack/compute/contrib/floating_ip_pools.py | 37 | ||||
| -rw-r--r-- | nova/api/openstack/compute/contrib/keypairs.py | 8 | ||||
| -rw-r--r-- | nova/api/openstack/compute/contrib/zones.py | 14 | ||||
| -rw-r--r-- | nova/api/openstack/compute/extensions.py | 25 | ||||
| -rw-r--r-- | nova/api/openstack/extensions.py | 274 | ||||
| -rw-r--r-- | nova/api/openstack/volume/__init__.py | 2 | ||||
| -rw-r--r-- | nova/api/openstack/volume/extensions.py | 24 | ||||
| -rw-r--r-- | nova/api/openstack/volume/snapshots.py | 74 | ||||
| -rw-r--r-- | nova/api/openstack/volume/types.py | 51 | ||||
| -rw-r--r-- | nova/api/openstack/volume/volumes.py | 133 | ||||
| -rw-r--r-- | nova/api/openstack/wsgi.py | 217 | ||||
| -rw-r--r-- | nova/api/openstack/xmlutil.py | 42 |
13 files changed, 151 insertions, 776 deletions
diff --git a/nova/api/openstack/common.py b/nova/api/openstack/common.py index 0ac46d96e..2cc18661b 100644 --- a/nova/api/openstack/common.py +++ b/nova/api/openstack/common.py @@ -426,12 +426,6 @@ class MetadataXMLDeserializer(wsgi.XMLDeserializer): return {'body': {'meta': metadata_item}} -class MetadataHeadersSerializer(wsgi.ResponseHeadersSerializer): - - def delete(self, response, data): - response.status_int = 204 - - metadata_nsmap = {None: xmlutil.XMLNS_V11} @@ -459,26 +453,6 @@ class MetadataTemplate(xmlutil.TemplateBuilder): return xmlutil.MasterTemplate(root, 1, nsmap=metadata_nsmap) -class MetadataXMLSerializer(xmlutil.XMLTemplateSerializer): - def index(self): - return MetadataTemplate() - - def create(self): - return MetadataTemplate() - - def update_all(self): - return MetadataTemplate() - - def show(self): - return MetaItemTemplate() - - def update(self): - return MetaItemTemplate() - - def default(self): - return xmlutil.MasterTemplate(None, 1) - - def check_snapshots_enabled(f): @functools.wraps(f) def inner(*args, **kwargs): diff --git a/nova/api/openstack/compute/contrib/floating_ip_pools.py b/nova/api/openstack/compute/contrib/floating_ip_pools.py index 01b9a3645..0bf2362af 100644 --- a/nova/api/openstack/compute/contrib/floating_ip_pools.py +++ b/nova/api/openstack/compute/contrib/floating_ip_pools.py @@ -37,20 +37,6 @@ def _translate_floating_ip_pools_view(pools): } -class FloatingIPPoolsController(object): - """The Floating IP Pool API controller for the OpenStack API.""" - - def __init__(self): - self.network_api = network.API() - super(FloatingIPPoolsController, self).__init__() - - def index(self, req): - """Return a list of pools.""" - context = req.environ['nova.context'] - pools = self.network_api.get_floating_ip_pools(context) - return _translate_floating_ip_pools_view(pools) - - def make_float_ip(elem): elem.set('name') @@ -72,9 +58,19 @@ class FloatingIPPoolsTemplate(xmlutil.TemplateBuilder): return xmlutil.MasterTemplate(root, 1) -class FloatingIPPoolsSerializer(xmlutil.XMLTemplateSerializer): - def index(self): - return FloatingIPPoolsTemplate() +class FloatingIPPoolsController(object): + """The Floating IP Pool API controller for the OpenStack API.""" + + def __init__(self): + self.network_api = network.API() + super(FloatingIPPoolsController, self).__init__() + + @wsgi.serializers(xml=FloatingIPPoolsTemplate) + def index(self, req): + """Return a list of pools.""" + context = req.environ['nova.context'] + pools = self.network_api.get_floating_ip_pools(context) + return _translate_floating_ip_pools_view(pools) class Floating_ip_pools(extensions.ExtensionDescriptor): @@ -89,15 +85,8 @@ class Floating_ip_pools(extensions.ExtensionDescriptor): def get_resources(self): resources = [] - body_serializers = { - 'application/xml': FloatingIPPoolsSerializer(), - } - - serializer = wsgi.ResponseSerializer(body_serializers) - res = extensions.ResourceExtension('os-floating-ip-pools', FloatingIPPoolsController(), - serializer=serializer, member_actions={}) resources.append(res) diff --git a/nova/api/openstack/compute/contrib/keypairs.py b/nova/api/openstack/compute/contrib/keypairs.py index c09ca555f..504539d55 100644 --- a/nova/api/openstack/compute/contrib/keypairs.py +++ b/nova/api/openstack/compute/contrib/keypairs.py @@ -130,14 +130,6 @@ class KeypairController(object): return {'keypairs': rval} -class KeypairsSerializer(xmlutil.XMLTemplateSerializer): - def index(self): - return KeypairsTemplate() - - def default(self): - return KeypairTemplate() - - class Keypairs(extensions.ExtensionDescriptor): """Keypair Support""" diff --git a/nova/api/openstack/compute/contrib/zones.py b/nova/api/openstack/compute/contrib/zones.py index b68f3f4f5..539833ee2 100644 --- a/nova/api/openstack/compute/contrib/zones.py +++ b/nova/api/openstack/compute/contrib/zones.py @@ -195,20 +195,6 @@ class Controller(object): return cooked -class ZonesXMLSerializer(xmlutil.XMLTemplateSerializer): - def index(self): - return ZonesTemplate() - - def detail(self): - return ZonesTemplate() - - def select(self): - return WeightsTemplate() - - def default(self): - return ZoneTemplate() - - class Zones(extensions.ExtensionDescriptor): """Enables zones-related functionality such as adding child zones, listing child zones, getting the capabilities of the local zone, diff --git a/nova/api/openstack/compute/extensions.py b/nova/api/openstack/compute/extensions.py index 39849e802..f5ebdfee9 100644 --- a/nova/api/openstack/compute/extensions.py +++ b/nova/api/openstack/compute/extensions.py @@ -25,21 +25,20 @@ FLAGS = flags.FLAGS class ExtensionManager(base_extensions.ExtensionManager): - def __new__(cls): - if cls._ext_mgr is None: - LOG.audit(_('Initializing extension manager.')) + def __init__(self): + LOG.audit(_('Initializing extension manager.')) - cls._ext_mgr = super(ExtensionManager, cls).__new__(cls) + self.cls_list = FLAGS.osapi_compute_extension + self.extensions = {} + self._load_extensions() - cls.cls_list = FLAGS.osapi_compute_extension - cls._ext_mgr.extensions = {} - cls._ext_mgr._load_extensions() - return cls._ext_mgr +class ExtensionMiddleware(base_extensions.ExtensionMiddleware): + """Extensions middleware for WSGI. + Provided only for backwards compatibility with existing + api-paste.ini files. This middleware will be removed in future + versions of nova. + """ -class ExtensionMiddleware(base_extensions.ExtensionMiddleware): - def __init__(self, application, ext_mgr=None): - if not ext_mgr: - ext_mgr = ExtensionManager() - super(ExtensionMiddleware, self).__init__(application, ext_mgr) + pass diff --git a/nova/api/openstack/extensions.py b/nova/api/openstack/extensions.py index ce37e0a34..9a47a69d4 100644 --- a/nova/api/openstack/extensions.py +++ b/nova/api/openstack/extensions.py @@ -79,24 +79,6 @@ class ExtensionDescriptor(object): resources = [] return resources - def get_actions(self): - """List of extensions.ActionExtension extension objects. - - Actions are verbs callable from the API. - - """ - actions = [] - return actions - - def get_request_extensions(self): - """List of extensions.RequestExtension extension objects. - - Request extensions are used to handle custom request data. - - """ - request_exts = [] - return request_exts - def get_controller_extensions(self): """List of extensions.ControllerExtension extension objects. @@ -124,92 +106,6 @@ class ExtensionDescriptor(object): return '{%s}%s' % (cls.namespace, name) -class ActionExtensionController(object): - def __init__(self, application): - self.application = application - self.action_handlers = {} - - def add_action(self, action_name, handler): - self.action_handlers[action_name] = handler - - def action(self, req, id, body): - for action_name, handler in self.action_handlers.iteritems(): - if action_name in body: - return handler(body, req, id) - # no action handler found (bump to downstream application) - res = self.application - return res - - -class ActionExtensionResource(wsgi.Resource): - - def __init__(self, application): - controller = ActionExtensionController(application) - wsgi.Resource.__init__(self, controller, - serializer=wsgi.ResponseSerializer(), - deserializer=wsgi.RequestDeserializer()) - - def add_action(self, action_name, handler): - self.controller.add_action(action_name, handler) - - -class RequestExtensionController(object): - - def __init__(self, application): - self.application = application - self.handlers = [] - self.pre_handlers = [] - - def add_handler(self, handler): - self.handlers.append(handler) - - def add_pre_handler(self, pre_handler): - self.pre_handlers.append(pre_handler) - - def process(self, req, *args, **kwargs): - for pre_handler in self.pre_handlers: - pre_handler(req) - - res = req.get_response(self.application) - res.environ = req.environ - - # Don't call extensions if the main application returned an - # unsuccessful status - successful = 200 <= res.status_int < 400 - if not successful: - return res - - # Deserialize the response body, if any - body = None - if res.body: - body = utils.loads(res.body) - - # currently request handlers are un-ordered - for handler in self.handlers: - res = handler(req, res, body) - - # Reserialize the response body - if body is not None: - res.body = utils.dumps(body) - - return res - - -class RequestExtensionResource(wsgi.Resource): - - def __init__(self, application): - controller = RequestExtensionController(application) - wsgi.Resource.__init__(self, controller, - serializer=wsgi.ResponseSerializer(), - deserializer=wsgi.RequestDeserializer()) - - def add_handler(self, handler): - self.controller.add_handler(handler) - - def add_pre_handler(self, pre_handler): - self.controller.add_pre_handler(pre_handler) - - def make_ext(elem): elem.set('name') elem.set('namespace') @@ -281,106 +177,16 @@ class ExtensionsResource(wsgi.Resource): raise webob.exc.HTTPNotFound() +@utils.deprecated("The extension middleware is no longer necessary.") class ExtensionMiddleware(base_wsgi.Middleware): - """Extensions middleware for WSGI.""" - @classmethod - def factory(cls, global_config, **local_config): - """Paste factory.""" - def _factory(app): - return cls(app, **local_config) - return _factory - - def _action_ext_resources(self, application, ext_mgr, mapper): - """Return a dict of ActionExtensionResource-s by collection.""" - action_resources = {} - for action in ext_mgr.get_actions(): - if not action.collection in action_resources.keys(): - resource = ActionExtensionResource(application) - mapper.connect("/:(project_id)/%s/:(id)/action.:(format)" % - action.collection, - action='action', - controller=resource, - conditions=dict(method=['POST'])) - mapper.connect("/:(project_id)/%s/:(id)/action" % - action.collection, - action='action', - controller=resource, - conditions=dict(method=['POST'])) - action_resources[action.collection] = resource - - return action_resources - - def _request_ext_resources(self, application, ext_mgr, mapper): - """Returns a dict of RequestExtensionResource-s by collection.""" - request_ext_resources = {} - for req_ext in ext_mgr.get_request_extensions(): - if not req_ext.key in request_ext_resources.keys(): - resource = RequestExtensionResource(application) - mapper.connect(req_ext.url_route + '.:(format)', - action='process', - controller=resource, - conditions=req_ext.conditions) - - mapper.connect(req_ext.url_route, - action='process', - controller=resource, - conditions=req_ext.conditions) - request_ext_resources[req_ext.key] = resource - - return request_ext_resources - - def __init__(self, application, ext_mgr=None): - - if ext_mgr is None: - ext_mgr = ExtensionManager() - self.ext_mgr = ext_mgr - - mapper = nova.api.openstack.ProjectMapper() - - # extended actions - action_resources = self._action_ext_resources(application, ext_mgr, - mapper) - for action in ext_mgr.get_actions(): - LOG.debug(_('Extended action: %s'), action.action_name) - resource = action_resources[action.collection] - resource.add_action(action.action_name, action.handler) - - # extended requests - req_controllers = self._request_ext_resources(application, ext_mgr, - mapper) - for request_ext in ext_mgr.get_request_extensions(): - LOG.debug(_('Extended request: %s'), request_ext.key) - controller = req_controllers[request_ext.key] - if request_ext.handler: - controller.add_handler(request_ext.handler) - if request_ext.pre_handler: - controller.add_pre_handler(request_ext.pre_handler) - - self._router = routes.middleware.RoutesMiddleware(self._dispatch, - mapper) - - super(ExtensionMiddleware, self).__init__(application) - - @webob.dec.wsgify(RequestClass=wsgi.Request) - def __call__(self, req): - """Route the incoming request with router.""" - req.environ['extended.app'] = self.application - return self._router - - @staticmethod - @webob.dec.wsgify(RequestClass=wsgi.Request) - def _dispatch(req): - """Dispatch the request. - - Returns the routed WSGI app's response or defers to the extended - application. + """Extensions middleware for WSGI. - """ - match = req.environ['wsgiorg.routing_args'][1] - if not match: - return req.environ['extended.app'] - app = match['controller'] - return app + Provided only for backwards compatibility with existing + api-paste.ini files. This middleware will be removed in future + versions of nova. + """ + + pass class ExtensionManager(object): @@ -391,12 +197,6 @@ class ExtensionManager(object): """ - _ext_mgr = None - - @classmethod - def reset(cls): - cls._ext_mgr = None - def register(self, ext): # Do nothing if the extension doesn't check out if not self._check_extension(ext): @@ -425,30 +225,6 @@ class ExtensionManager(object): pass return resources - def get_actions(self): - """Returns a list of ActionExtension objects.""" - actions = [] - for ext in self.extensions.values(): - try: - actions.extend(ext.get_actions()) - except AttributeError: - # NOTE(dprince): Extension aren't required to have action - # extensions - pass - return actions - - def get_request_extensions(self): - """Returns a list of RequestExtension objects.""" - request_exts = [] - for ext in self.extensions.values(): - try: - request_exts.extend(ext.get_request_extensions()) - except AttributeError: - # NOTE(dprince): Extension aren't required to have request - # extensions - pass - return request_exts - def get_controller_extensions(self): """Returns a list of ControllerExtension objects.""" controller_exts = [] @@ -525,32 +301,6 @@ class ControllerExtension(object): self.controller = controller -@utils.deprecated("Superseded by ControllerExtension") -class RequestExtension(object): - """Extend requests and responses of core nova OpenStack API resources. - - Provide a way to add data to responses and handle custom request data - that is sent to core nova OpenStack API controllers. - - """ - def __init__(self, method, url_route, handler=None, pre_handler=None): - self.url_route = url_route - self.handler = handler - self.conditions = dict(method=[method]) - self.key = "%s-%s" % (method, url_route) - self.pre_handler = pre_handler - - -@utils.deprecated("Superseded by ControllerExtension") -class ActionExtension(object): - """Add custom actions to core nova OpenStack API resources.""" - - def __init__(self, collection, action_name, handler): - self.collection = collection - self.action_name = action_name - self.handler = handler - - class ResourceExtension(object): """Add top level resources to the OpenStack API in nova.""" @@ -570,14 +320,6 @@ class ResourceExtension(object): self.serializer = serializer -class ExtensionsXMLSerializer(xmlutil.XMLTemplateSerializer): - def index(self): - return ExtensionsTemplate() - - def show(self): - return ExtensionTemplate() - - def wrap_errors(fn): """Ensure errors are not passed along.""" def wrapped(*args, **kwargs): diff --git a/nova/api/openstack/volume/__init__.py b/nova/api/openstack/volume/__init__.py index 9e8a5d789..f8d0f28bd 100644 --- a/nova/api/openstack/volume/__init__.py +++ b/nova/api/openstack/volume/__init__.py @@ -62,8 +62,6 @@ class APIRouter(base_wsgi.Router): super(APIRouter, self).__init__(mapper) def _setup_ext_routes(self, mapper, ext_mgr): - serializer = wsgi.ResponseSerializer( - {'application/xml': wsgi.XMLDictSerializer()}) for resource in ext_mgr.get_resources(): LOG.debug(_('Extended resource: %s'), resource.collection) diff --git a/nova/api/openstack/volume/extensions.py b/nova/api/openstack/volume/extensions.py index d1007629e..eccac660e 100644 --- a/nova/api/openstack/volume/extensions.py +++ b/nova/api/openstack/volume/extensions.py @@ -25,20 +25,20 @@ FLAGS = flags.FLAGS class ExtensionManager(base_extensions.ExtensionManager): - def __new__(cls): - if cls._ext_mgr is None: - LOG.audit(_('Initializing extension manager.')) + def __init__(self): + LOG.audit(_('Initializing extension manager.')) - cls._ext_mgr = super(ExtensionManager, cls).__new__(cls) + self.cls_list = FLAGS.osapi_volume_extension + self.extensions = {} + self._load_extensions() - cls.cls_list = FLAGS.osapi_volume_extension - cls._ext_mgr.extensions = {} - cls._ext_mgr._load_extensions() - return cls._ext_mgr +class ExtensionMiddleware(base_extensions.ExtensionMiddleware): + """Extensions middleware for WSGI. + Provided only for backwards compatibility with existing + api-paste.ini files. This middleware will be removed in future + versions of nova. + """ -class ExtensionMiddleware(base_extensions.ExtensionMiddleware): - def __init__(self, application, ext_mgr=None): - ext_mgr = ExtensionManager() - super(ExtensionMiddleware, self).__init__(application, ext_mgr) + pass diff --git a/nova/api/openstack/volume/snapshots.py b/nova/api/openstack/volume/snapshots.py index ec12c052b..36687d736 100644 --- a/nova/api/openstack/volume/snapshots.py +++ b/nova/api/openstack/volume/snapshots.py @@ -57,6 +57,32 @@ def _translate_snapshot_summary_view(context, vol): return d +def make_snapshot(elem): + elem.set('id') + elem.set('status') + elem.set('size') + elem.set('createdAt') + elem.set('displayName') + elem.set('displayDescription') + elem.set('volumeId') + + +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 SnapshotsController(object): """The Volumes API controller for the OpenStack API.""" @@ -64,6 +90,7 @@ class SnapshotsController(object): self.volume_api = volume.API() super(SnapshotsController, self).__init__() + @wsgi.serializers(xml=SnapshotTemplate) def show(self, req, id): """Return data about the given snapshot.""" context = req.environ['nova.context'] @@ -88,10 +115,12 @@ class SnapshotsController(object): return exc.HTTPNotFound() return webob.Response(status_int=202) + @wsgi.serializers(xml=SnapshotsTemplate) def index(self, req): """Returns a summary list of snapshots.""" return self._items(req, entity_maker=_translate_snapshot_summary_view) + @wsgi.serializers(xml=SnapshotsTemplate) def detail(self, req): """Returns a detailed list of snapshots.""" return self._items(req, entity_maker=_translate_snapshot_detail_view) @@ -105,6 +134,7 @@ class SnapshotsController(object): res = [entity_maker(context, snapshot) for snapshot in limited_list] return {'snapshots': res} + @wsgi.serializers(xml=SnapshotTemplate) def create(self, req, body): """Creates a new snapshot.""" context = req.environ['nova.context'] @@ -135,47 +165,5 @@ class SnapshotsController(object): return {'snapshot': retval} -def make_snapshot(elem): - elem.set('id') - elem.set('status') - elem.set('size') - elem.set('createdAt') - elem.set('displayName') - elem.set('displayDescription') - elem.set('volumeId') - - -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 SnapshotSerializer(xmlutil.XMLTemplateSerializer): - def default(self): - return SnapshotTemplate() - - def index(self): - return SnapshotsTemplate() - - def detail(self): - return SnapshotsTemplate() - - def create_resource(): - body_serializers = { - 'application/xml': SnapshotSerializer(), - } - serializer = wsgi.ResponseSerializer(body_serializers) - - return wsgi.Resource(SnapshotsController(), serializer=serializer) + return wsgi.Resource(SnapshotsController()) diff --git a/nova/api/openstack/volume/types.py b/nova/api/openstack/volume/types.py index d324914a4..609a6cfc9 100644 --- a/nova/api/openstack/volume/types.py +++ b/nova/api/openstack/volume/types.py @@ -25,26 +25,6 @@ from nova import exception from nova.volume import volume_types -class VolumeTypesController(object): - """ The volume types API controller for the Openstack API """ - - def index(self, req): - """ Returns the list of volume types """ - context = req.environ['nova.context'] - return volume_types.get_all_types(context) - - def show(self, req, id): - """ Return a single volume type item """ - context = req.environ['nova.context'] - - try: - vol_type = volume_types.get_volume_type(context, id) - except exception.NotFound or exception.ApiError: - raise exc.HTTPNotFound() - - return {'volume_type': vol_type} - - def make_voltype(elem): elem.set('id') elem.set('name') @@ -68,20 +48,27 @@ class VolumeTypesTemplate(xmlutil.TemplateBuilder): return xmlutil.MasterTemplate(root, 1) -class VolumeTypesSerializer(xmlutil.XMLTemplateSerializer): - def index(self): - return VolumeTypesTemplate() +class VolumeTypesController(object): + """ The volume types API controller for the Openstack API """ - def default(self): - return VolumeTypeTemplate() + @wsgi.serializers(xml=VolumeTypesTemplate) + def index(self, req): + """ Returns the list of volume types """ + context = req.environ['nova.context'] + return volume_types.get_all_types(context) + + @wsgi.serializers(xml=VolumeTypeTemplate) + def show(self, req, id): + """ Return a single volume type item """ + context = req.environ['nova.context'] + try: + vol_type = volume_types.get_volume_type(context, id) + except exception.NotFound or exception.ApiError: + raise exc.HTTPNotFound() -def create_resource(): - body_serializers = { - 'application/xml': VolumeTypesSerializer(), - } - serializer = wsgi.ResponseSerializer(body_serializers) + return {'volume_type': vol_type} - deserializer = wsgi.RequestDeserializer() - return wsgi.Resource(VolumeTypesController(), serializer=serializer) +def create_resource(): + return wsgi.Resource(VolumeTypesController()) diff --git a/nova/api/openstack/volume/volumes.py b/nova/api/openstack/volume/volumes.py index b37a56374..397358ca1 100644 --- a/nova/api/openstack/volume/volumes.py +++ b/nova/api/openstack/volume/volumes.py @@ -109,6 +109,48 @@ def _translate_volume_summary_view(context, vol): return d +def make_attachment(elem): + elem.set('id') + elem.set('serverId') + elem.set('volumeId') + elem.set('device') + + +def make_volume(elem): + elem.set('id') + elem.set('status') + elem.set('size') + elem.set('availabilityZone') + elem.set('createdAt') + elem.set('displayName') + elem.set('displayDescription') + elem.set('volumeType') + elem.set('snapshotId') + + attachments = xmlutil.SubTemplateElement(elem, 'attachments') + attachment = xmlutil.SubTemplateElement(attachments, 'attachment', + selector='attachments') + make_attachment(attachment) + + metadata = xmlutil.make_flat_dict('metadata') + elem.append(metadata) + + +class VolumeTemplate(xmlutil.TemplateBuilder): + def construct(self): + root = xmlutil.TemplateElement('volume', selector='volume') + make_volume(root) + return xmlutil.MasterTemplate(root, 1) + + +class VolumesTemplate(xmlutil.TemplateBuilder): + def construct(self): + root = xmlutil.TemplateElement('volumes') + elem = xmlutil.SubTemplateElement(root, 'volume', selector='volumes') + make_volume(elem) + return xmlutil.MasterTemplate(root, 1) + + class VolumeController(object): """The Volumes API controller for the OpenStack API.""" @@ -116,6 +158,7 @@ class VolumeController(object): self.volume_api = volume.API() super(VolumeController, self).__init__() + @wsgi.serializers(xml=VolumeTemplate) def show(self, req, id): """Return data about the given volume.""" context = req.environ['nova.context'] @@ -140,10 +183,12 @@ class VolumeController(object): raise exc.HTTPNotFound() return webob.Response(status_int=202) + @wsgi.serializers(xml=VolumesTemplate) def index(self, req): """Returns a summary list of volumes.""" return self._items(req, entity_maker=_translate_volume_summary_view) + @wsgi.serializers(xml=VolumesTemplate) def detail(self, req): """Returns a detailed list of volumes.""" return self._items(req, entity_maker=_translate_volume_detail_view) @@ -157,6 +202,7 @@ class VolumeController(object): res = [entity_maker(context, vol) for vol in limited_list] return {'volumes': res} + @wsgi.serializers(xml=VolumeTemplate) def create(self, req, body): """Creates a new volume.""" context = req.environ['nova.context'] @@ -201,90 +247,5 @@ class VolumeController(object): return {'volume': retval} -class VolumeAttachmentTemplate(xmlutil.TemplateBuilder): - def construct(self): - root = xmlutil.TemplateElement('volumeAttachment', - selector='volumeAttachment') - make_attachment(root) - return xmlutil.MasterTemplate(root, 1) - - -class VolumeAttachmentsTemplate(xmlutil.TemplateBuilder): - def construct(self): - root = xmlutil.TemplateElement('volumeAttachments') - elem = xmlutil.SubTemplateElement(root, 'volumeAttachment', - selector='volumeAttachments') - make_attachment(elem) - return xmlutil.MasterTemplate(root, 1) - - -class VolumeAttachmentSerializer(xmlutil.XMLTemplateSerializer): - def default(self): - return VolumeAttachmentTemplate() - - def index(self): - return VolumeAttachmentsTemplate() - - -def make_attachment(elem): - elem.set('id') - elem.set('serverId') - elem.set('volumeId') - elem.set('device') - - -def make_volume(elem): - elem.set('id') - elem.set('status') - elem.set('size') - elem.set('availabilityZone') - elem.set('createdAt') - elem.set('displayName') - elem.set('displayDescription') - elem.set('volumeType') - elem.set('snapshotId') - - attachments = xmlutil.SubTemplateElement(elem, 'attachments') - attachment = xmlutil.SubTemplateElement(attachments, 'attachment', - selector='attachments') - make_attachment(attachment) - - metadata = xmlutil.make_flat_dict('metadata') - elem.append(metadata) - - -class VolumeTemplate(xmlutil.TemplateBuilder): - def construct(self): - root = xmlutil.TemplateElement('volume', selector='volume') - make_volume(root) - return xmlutil.MasterTemplate(root, 1) - - -class VolumesTemplate(xmlutil.TemplateBuilder): - def construct(self): - root = xmlutil.TemplateElement('volumes') - elem = xmlutil.SubTemplateElement(root, 'volume', selector='volumes') - make_volume(elem) - return xmlutil.MasterTemplate(root, 1) - - -class VolumeSerializer(xmlutil.XMLTemplateSerializer): - def default(self): - return VolumeTemplate() - - def index(self): - return VolumesTemplate() - - def detail(self): - return VolumesTemplate() - - def create_resource(): - body_serializers = { - 'application/xml': VolumeSerializer(), - } - serializer = wsgi.ResponseSerializer(body_serializers) - - deserializer = wsgi.RequestDeserializer() - - return wsgi.Resource(VolumeController(), serializer=serializer) + return wsgi.Resource(VolumeController()) diff --git a/nova/api/openstack/wsgi.py b/nova/api/openstack/wsgi.py index 3bf1bef00..d5a3d95b3 100644 --- a/nova/api/openstack/wsgi.py +++ b/nova/api/openstack/wsgi.py @@ -216,104 +216,6 @@ class MetadataXMLDeserializer(XMLDeserializer): return metadata -class RequestHeadersDeserializer(ActionDispatcher): - """Default request headers deserializer""" - - def deserialize(self, request, action): - return self.dispatch(request, action=action) - - def default(self, request): - return {} - - -class RequestDeserializer(object): - """Break up a Request object into more useful pieces.""" - - def __init__(self, body_deserializers=None, headers_deserializer=None): - self.body_deserializers = { - 'application/xml': XMLDeserializer(), - 'application/json': JSONDeserializer(), - } - self.body_deserializers.update(body_deserializers or {}) - - self.headers_deserializer = headers_deserializer or \ - RequestHeadersDeserializer() - - def deserialize(self, request): - """Extract necessary pieces of the request. - - :param request: Request object - :returns tuple of expected controller action name, dictionary of - keyword arguments to pass to the controller, the expected - content type of the response - - """ - action_args = self.get_action_args(request.environ) - action = action_args.pop('action', None) - - action_args.update(self.deserialize_headers(request, action)) - action_args.update(self.deserialize_body(request, action)) - - accept = self.get_expected_content_type(request) - - return (action, action_args, accept) - - def deserialize_headers(self, request, action): - return self.headers_deserializer.deserialize(request, action) - - def deserialize_body(self, request, action): - try: - content_type = request.get_content_type() - except exception.InvalidContentType: - LOG.debug(_("Unrecognized Content-Type provided in request")) - return {} - - if content_type is None: - LOG.debug(_("No Content-Type provided in request")) - return {} - - if not len(request.body) > 0: - LOG.debug(_("Empty body provided in request")) - return {} - - try: - deserializer = self.get_body_deserializer(content_type) - except exception.InvalidContentType: - LOG.debug(_("Unable to deserialize body as provided Content-Type")) - raise - - return deserializer.deserialize(request.body, action) - - def get_body_deserializer(self, content_type): - try: - ctype = _CONTENT_TYPE_MAP.get(content_type, content_type) - return self.body_deserializers[ctype] - except (KeyError, TypeError): - raise exception.InvalidContentType(content_type=content_type) - - def get_expected_content_type(self, request): - return request.best_match_content_type() - - def get_action_args(self, request_environment): - """Parse dictionary created by routes library.""" - try: - args = request_environment['wsgiorg.routing_args'][1].copy() - except Exception: - return {} - - try: - del args['controller'] - except KeyError: - pass - - try: - del args['format'] - except KeyError: - pass - - return args - - class DictSerializer(ActionDispatcher): """Default request body serialization""" @@ -435,104 +337,16 @@ class XMLDictSerializer(DictSerializer): return etree.tostring(root, encoding='UTF-8', xml_declaration=True) -class ResponseHeadersSerializer(ActionDispatcher): - """Default response headers serialization""" - - def serialize(self, response, data, action): - self.dispatch(response, data, action=action) - context = response.request.environ.get('nova.context') - if context: - response.headers['X-Compute-Request-Id'] = context.request_id - - def default(self, response, data): - response.status_int = 200 - - -class ResponseSerializer(object): - """Encode the necessary pieces into a response object""" - - def __init__(self, body_serializers=None, headers_serializer=None): - self.body_serializers = { - 'application/xml': XMLDictSerializer(), - 'application/json': JSONDictSerializer(), - } - self.body_serializers.update(body_serializers or {}) - - self.headers_serializer = headers_serializer or \ - ResponseHeadersSerializer() - - def serialize(self, request, response_data, content_type, - action='default'): - """Serialize a dict into a string and wrap in a wsgi.Request object. - - :param response_data: dict produced by the Controller - :param content_type: expected mimetype of serialized response body - - """ - response = webob.Response(request=request) - self.serialize_headers(response, response_data, action) - self.serialize_body(request, response, response_data, content_type, - action) - return response - - def serialize_headers(self, response, data, action): - self.headers_serializer.serialize(response, data, action) - - def serialize_body(self, request, response, data, content_type, action): - response.headers['Content-Type'] = content_type - if data is not None: - serializer = self.get_body_serializer(content_type) - lazy_serialize = request.environ.get('nova.lazy_serialize', False) - if lazy_serialize: - response.body = utils.dumps(data) - request.environ['nova.serializer'] = serializer - request.environ['nova.action'] = action - if (hasattr(serializer, 'get_template') and - 'nova.template' not in request.environ): - - template = serializer.get_template(action) - request.environ['nova.template'] = template - else: - response.body = serializer.serialize(data, action) - - def get_body_serializer(self, content_type): - try: - ctype = _CONTENT_TYPE_MAP.get(content_type, content_type) - return self.body_serializers[ctype] - except (KeyError, TypeError): - raise exception.InvalidContentType(content_type=content_type) +@utils.deprecated("The lazy serialization middleware is no longer necessary.") +class LazySerializationMiddleware(wsgi.Middleware): + """Lazy serialization middleware. + Provided only for backwards compatibility with existing + api-paste.ini files. This middleware will be removed in future + versions of nova. + """ -class LazySerializationMiddleware(wsgi.Middleware): - """Lazy serialization middleware.""" - @webob.dec.wsgify(RequestClass=Request) - def __call__(self, req): - # Request lazy serialization - req.environ['nova.lazy_serialize'] = True - - response = req.get_response(self.application) - - # See if we're using the simple serialization driver - simple_serial = req.environ.get('nova.simple_serial') - if simple_serial is not None: - body_obj = utils.loads(response.body) - response.body = simple_serial.serialize(body_obj) - return response - - # See if there's a serializer... - serializer = req.environ.get('nova.serializer') - if serializer is None: - return response - - # OK, build up the arguments for the serialize() method - kwargs = dict(action=req.environ['nova.action']) - if 'nova.template' in req.environ: - kwargs['template'] = req.environ['nova.template'] - - # Re-serialize the body - response.body = serializer.serialize(utils.loads(response.body), - **kwargs) - return response + pass def serializers(**serializers): @@ -698,20 +512,7 @@ class ResponseObject(object): response.headers[hdr] = value response.headers['Content-Type'] = content_type if self.obj is not None: - # TODO(Vek): When lazy serialization is retired, so can - # this inner 'if'... - lazy_serialize = request.environ.get('nova.lazy_serialize', False) - if lazy_serialize: - response.body = utils.dumps(self.obj) - request.environ['nova.simple_serial'] = serializer - # NOTE(Vek): Temporary ugly hack to support xml - # templates in extensions, until we can - # fold extensions into Resource and do away - # with lazy serialization... - if _MEDIA_TYPE_MAP.get(content_type) == 'xml': - request.environ['nova.template'] = serializer - else: - response.body = serializer.serialize(self.obj) + response.body = serializer.serialize(self.obj) return response diff --git a/nova/api/openstack/xmlutil.py b/nova/api/openstack/xmlutil.py index 4b64d4a8f..2485ef2c5 100644 --- a/nova/api/openstack/xmlutil.py +++ b/nova/api/openstack/xmlutil.py @@ -858,48 +858,6 @@ class TemplateBuilder(object): raise NotImplementedError(_("subclasses must implement construct()!")) -class XMLTemplateSerializer(wsgi.ActionDispatcher): - """Template-based XML serializer. - - Data serializer that uses templates to perform its serialization. - """ - - def get_template(self, action='default'): - """Retrieve the template to use for serialization.""" - - return self.dispatch(action=action) - - def serialize(self, data, action='default', template=None): - """Serialize data. - - :param data: The data to serialize. - :param action: The action, for identifying the template to - use. If no template is provided, - get_template() will be called with this action - to retrieve the template. - :param template: The template to use in serialization. - """ - - # No template provided, look one up - if template is None: - template = self.get_template(action) - - # Still couldn't find a template; try the base - # XMLDictSerializer - if template is None: - serial = wsgi.XMLDictSerializer() - return serial.serialize(data, action=action) - - # Serialize the template - return template.serialize(data, encoding='UTF-8', - xml_declaration=True) - - def default(self): - """Retrieve the default template to use.""" - - return None - - def make_links(parent, selector=None): """ Attach an Atom <links> element to the parent. |
