diff options
| author | Kevin L. Mitchell <kevin.mitchell@rackspace.com> | 2012-01-16 11:31:56 -0600 |
|---|---|---|
| committer | Kevin L. Mitchell <kevin.mitchell@rackspace.com> | 2012-01-16 11:31:56 -0600 |
| commit | e022ea9bb44cd49b45e6d4b82dd168000988dc20 (patch) | |
| tree | 9bba4ee2fb791fe123dc9d5013403b4c760f35be /nova/api | |
| parent | 312caea8ab278882552cf9006653de97ced88ef8 (diff) | |
| download | nova-e022ea9bb44cd49b45e6d4b82dd168000988dc20.tar.gz nova-e022ea9bb44cd49b45e6d4b82dd168000988dc20.tar.xz nova-e022ea9bb44cd49b45e6d4b82dd168000988dc20.zip | |
Update some extensions (2)
Updates the extended_status (ExtendedStatus) extension to conform to
the new extension interface. Related to blueprint extension-refactor.
Change-Id: Ie00968c4cdcd67a2cf659a2b8c2ca2b31e8dcc9d
Diffstat (limited to 'nova/api')
| -rw-r--r-- | nova/api/openstack/compute/contrib/extended_status.py | 142 | ||||
| -rw-r--r-- | nova/api/openstack/wsgi.py | 45 |
2 files changed, 110 insertions, 77 deletions
diff --git a/nova/api/openstack/compute/contrib/extended_status.py b/nova/api/openstack/compute/contrib/extended_status.py index 7f9301b93..7479d6f00 100644 --- a/nova/api/openstack/compute/contrib/extended_status.py +++ b/nova/api/openstack/compute/contrib/extended_status.py @@ -17,6 +17,7 @@ from webob import exc from nova.api.openstack import extensions +from nova.api.openstack import wsgi from nova.api.openstack import xmlutil from nova import compute from nova import exception @@ -28,6 +29,55 @@ FLAGS = flags.FLAGS LOG = logging.getLogger("nova.api.openstack.compute.contrib.extendedstatus") +class ExtendedStatusController(wsgi.Controller): + def __init__(self, *args, **kwargs): + super(ExtendedStatusController, self).__init__(*args, **kwargs) + self.compute_api = compute.API() + + def _get_and_extend_one(self, context, server_id, body): + try: + inst_ref = self.compute_api.routing_get(context, server_id) + except exception.NotFound: + LOG.warn("Instance %s not found" % server_id) + raise + + for state in ['task_state', 'vm_state', 'power_state']: + key = "%s:%s" % (Extended_status.alias, state) + body[key] = inst_ref[state] + + @wsgi.extends + def show(self, req, resp_obj, id): + context = req.environ['nova.context'] + + # Attach our slave template to the response object + resp_obj.attach(xml=ExtendedStatusTemplate()) + + try: + self._get_and_extend_one(context, id, resp_obj.obj['server']) + except exception.NotFound: + explanation = _("Server not found.") + raise exc.HTTPNotFound(explanation=explanation) + + @wsgi.extends + def detail(self, req, resp_obj): + context = req.environ['nova.context'] + + # Attach our slave template to the response object + resp_obj.attach(xml=ExtendedStatusesTemplate()) + + for server in list(resp_obj.obj['servers']): + try: + self._get_and_extend_one(context, server['id'], server) + except exception.NotFound: + # NOTE(dtroyer): A NotFound exception at this point + # happens because a delete was in progress and the + # server that was present in the original call to + # compute.api.get_all() is no longer present. + # Delete it from the response and move on. + resp_obj.obj['servers'].remove(server) + continue + + class Extended_status(extensions.ExtensionDescriptor): """Extended Status support""" @@ -38,79 +88,33 @@ class Extended_status(extensions.ExtensionDescriptor): updated = "2011-11-03T00:00:00+00:00" admin_only = True - def get_request_extensions(self): - request_extensions = [] + def get_controller_extensions(self): + controller = ExtendedStatusController() + extension = extensions.ControllerExtension(self, 'servers', controller) + return [extension] - def _get_and_extend_one(context, server_id, body): - compute_api = compute.API() - try: - inst_ref = compute_api.routing_get(context, server_id) - except exception.NotFound: - LOG.warn("Instance %s not found (one)" % server_id) - explanation = _("Server not found.") - raise exc.HTTPNotFound(explanation=explanation) - - for state in ['task_state', 'vm_state', 'power_state']: - key = "%s:%s" % (Extended_status.alias, state) - body['server'][key] = inst_ref[state] - - def _get_and_extend_all(context, body): - # TODO(mdietz): This is a brilliant argument for this to *not* - # be an extension. The problem is we either have to 1) duplicate - # the logic from the servers controller or 2) do what we did - # and iterate over the list of potentially sorted, limited - # and whatever else elements and find each individual. - compute_api = compute.API() - - for server in list(body['servers']): - try: - inst_ref = compute_api.routing_get(context, server['id']) - except exception.NotFound: - # NOTE(dtroyer): A NotFound exception at this point - # happens because a delete was in progress and the - # server that was present in the original call to - # compute.api.get_all() is no longer present. - # Delete it from the response and move on. - LOG.warn("Instance %s not found (all)" % server['id']) - body['servers'].remove(server) - continue - - #TODO(bcwaldon): these attributes should be prefixed with - # something specific to this extension - for state in ['task_state', 'vm_state', 'power_state']: - key = "%s:%s" % (Extended_status.alias, state) - server[key] = inst_ref[state] - - def _extended_status_handler(req, res, body): - context = req.environ['nova.context'] - server_id = req.environ['wsgiorg.routing_args'][1].get('id') - - if 'nova.template' in req.environ: - tmpl = req.environ['nova.template'] - tmpl.attach(ExtendedStatusTemplate()) - - if server_id: - _get_and_extend_one(context, server_id, body) - else: - _get_and_extend_all(context, body) - return res - - req_ext = extensions.RequestExtension('GET', - '/:(project_id)/servers/:(id)', - _extended_status_handler) - request_extensions.append(req_ext) - - return request_extensions + +def make_server(elem): + elem.set('{%s}task_state' % Extended_status.namespace, + '%s:task_state' % Extended_status.alias) + elem.set('{%s}power_state' % Extended_status.namespace, + '%s:power_state' % Extended_status.alias) + elem.set('{%s}vm_state' % Extended_status.namespace, + '%s:vm_state' % Extended_status.alias) class ExtendedStatusTemplate(xmlutil.TemplateBuilder): def construct(self): - root = xmlutil.TemplateElement('server') - root.set('{%s}task_state' % Extended_status.namespace, - '%s:task_state' % Extended_status.alias) - root.set('{%s}power_state' % Extended_status.namespace, - '%s:power_state' % Extended_status.alias) - root.set('{%s}vm_state' % Extended_status.namespace, - '%s:vm_state' % Extended_status.alias) + root = xmlutil.TemplateElement('server', selector='server') + make_server(root) + return xmlutil.SlaveTemplate(root, 1, nsmap={ + Extended_status.alias: Extended_status.namespace}) + + +class ExtendedStatusesTemplate(xmlutil.TemplateBuilder): + def construct(self): + root = xmlutil.TemplateElement('servers') + elem = xmlutil.SubTemplateElement(root, 'server', selector='servers') + make_server(elem) return xmlutil.SlaveTemplate(root, 1, nsmap={ Extended_status.alias: Extended_status.namespace}) diff --git a/nova/api/openstack/wsgi.py b/nova/api/openstack/wsgi.py index defb26e6e..3bf1bef00 100644 --- a/nova/api/openstack/wsgi.py +++ b/nova/api/openstack/wsgi.py @@ -603,6 +603,8 @@ class ResponseObject(object): self._default_code = 200 self._code = code self._headers = {} + self.serializer = None + self.media_type = None def __getitem__(self, key): """Retrieves a header with the given name.""" @@ -651,12 +653,31 @@ class ResponseObject(object): try: mtype = _MEDIA_TYPE_MAP.get(content_type, content_type) if mtype in self.serializers: - return self.serializers[mtype] + return mtype, self.serializers[mtype] else: - return default_serializers[mtype] + return mtype, default_serializers[mtype] except (KeyError, TypeError): raise exception.InvalidContentType(content_type=content_type) + def preserialize(self, content_type, default_serializers=None): + """Prepares the serializer that will be used to serialize. + + Determines the serializer that will be used and prepares an + instance of it for later call. This allows the serializer to + be accessed by extensions for, e.g., template extension. + """ + + mtype, serializer = self.get_serializer(content_type, + default_serializers) + self.media_type = mtype + self.serializer = serializer() + + def attach(self, **kwargs): + """Attach slave templates to serializers.""" + + if self.media_type in kwargs: + self.serializer.attach(kwargs[self.media_type]) + def serialize(self, request, content_type, default_serializers=None): """Serializes the wrapped object. @@ -664,7 +685,12 @@ class ResponseObject(object): webob.Response object. """ - serializer = self.get_serializer(content_type, default_serializers)() + if self.serializer: + serializer = self.serializer + else: + _mtype, _serializer = self.get_serializer(content_type, + default_serializers) + serializer = _serializer() response = webob.Response() response.status_int = self.code @@ -1030,6 +1056,14 @@ class Resource(wsgi.Application): # Run post-processing extensions if resp_obj: + # Do a preserialize to set up the response object + serializers = getattr(meth, 'wsgi_serializers', {}) + resp_obj._bind_method_serializers(serializers) + if hasattr(meth, 'wsgi_code'): + resp_obj._default_code = meth.wsgi_code + resp_obj.preserialize(accept, self.default_serializers) + + # Process post-processing extensions response = self.post_process_extensions(post, resp_obj, request, action_args) @@ -1040,11 +1074,6 @@ class Resource(wsgi.Application): accept, action=action) else: - serializers = getattr(meth, 'wsgi_serializers', {}) - resp_obj._bind_method_serializers(serializers) - if hasattr(meth, 'wsgi_code'): - resp_obj._default_code = meth.wsgi_code - response = resp_obj.serialize(request, accept, self.default_serializers) |
