Use wsgi.response for v2.1 API

Now a decorator @wsgi.response() can be used for specifying success
status code. Most v2.1 APIs use the decorator and it makes the code
more readable. This patch replaces webob.Response with the decorator
for the other APIs.
In addition, this patch changes some orders of decorators for showing
success code and expected error codes clearly.

Even if applying this patch, some webob.Response() calls still exist
under the path nova/api/openstack/compute/plugins/v3/ because these
cases need to contain some information in a response header.

Partially implements blueprint v2-on-v3-api

Change-Id: I419819b8e55427979e8d82b972cd237952a5b06b
This commit is contained in:
Ken'ichi Ohmichi 2014-10-21 02:44:13 +00:00
parent 8d8aee74b1
commit e73cb83f9e
24 changed files with 118 additions and 81 deletions

View File

@ -12,7 +12,6 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import webob
from webob import exc from webob import exc
from nova.api.openstack import common from nova.api.openstack import common
@ -42,6 +41,7 @@ class AdminActionsController(wsgi.Controller):
super(AdminActionsController, self).__init__(*args, **kwargs) super(AdminActionsController, self).__init__(*args, **kwargs)
self.compute_api = compute.API() self.compute_api = compute.API()
@wsgi.response(202)
@extensions.expected_errors((404, 409)) @extensions.expected_errors((404, 409))
@wsgi.action('resetNetwork') @wsgi.action('resetNetwork')
def _reset_network(self, req, id, body): def _reset_network(self, req, id, body):
@ -54,8 +54,8 @@ class AdminActionsController(wsgi.Controller):
self.compute_api.reset_network(context, instance) self.compute_api.reset_network(context, instance)
except exception.InstanceIsLocked as e: except exception.InstanceIsLocked as e:
raise exc.HTTPConflict(explanation=e.format_message()) raise exc.HTTPConflict(explanation=e.format_message())
return webob.Response(status_int=202)
@wsgi.response(202)
@extensions.expected_errors((404, 409)) @extensions.expected_errors((404, 409))
@wsgi.action('injectNetworkInfo') @wsgi.action('injectNetworkInfo')
def _inject_network_info(self, req, id, body): def _inject_network_info(self, req, id, body):
@ -68,8 +68,8 @@ class AdminActionsController(wsgi.Controller):
self.compute_api.inject_network_info(context, instance) self.compute_api.inject_network_info(context, instance)
except exception.InstanceIsLocked as e: except exception.InstanceIsLocked as e:
raise exc.HTTPConflict(explanation=e.format_message()) raise exc.HTTPConflict(explanation=e.format_message())
return webob.Response(status_int=202)
@wsgi.response(202)
@extensions.expected_errors((400, 404)) @extensions.expected_errors((400, 404))
@wsgi.action('os-resetState') @wsgi.action('os-resetState')
@validation.schema(reset_server_state.reset_state) @validation.schema(reset_server_state.reset_state)
@ -86,7 +86,6 @@ class AdminActionsController(wsgi.Controller):
instance.vm_state = state instance.vm_state = state
instance.task_state = None instance.task_state = None
instance.save(admin_state_reset=True) instance.save(admin_state_reset=True)
return webob.Response(status_int=202)
class AdminActions(extensions.V3APIExtensionBase): class AdminActions(extensions.V3APIExtensionBase):

View File

@ -21,6 +21,7 @@ from webob import exc
from nova.api.openstack import common from nova.api.openstack import common
from nova.api.openstack.compute.schemas.v3 import attach_interfaces from nova.api.openstack.compute.schemas.v3 import attach_interfaces
from nova.api.openstack import extensions from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api import validation from nova.api import validation
from nova import compute from nova import compute
from nova import exception from nova import exception
@ -137,6 +138,7 @@ class InterfaceAttachmentController(object):
return self.show(req, server_id, vif['id']) return self.show(req, server_id, vif['id'])
@wsgi.response(202)
@extensions.expected_errors((404, 409, 501)) @extensions.expected_errors((404, 409, 501))
def delete(self, req, server_id, id): def delete(self, req, server_id, id):
"""Detach an interface from an instance.""" """Detach an interface from an instance."""
@ -160,8 +162,6 @@ class InterfaceAttachmentController(object):
common.raise_http_conflict_for_instance_invalid_state(state_error, common.raise_http_conflict_for_instance_invalid_state(state_error,
'detach_interface', server_id) 'detach_interface', server_id)
return webob.Response(status_int=202)
def _items(self, req, server_id, entity_maker): def _items(self, req, server_id, entity_maker):
"""Returns a list of attachments, transformed through entity_maker.""" """Returns a list of attachments, transformed through entity_maker."""
context = req.environ['nova.context'] context = req.environ['nova.context']

View File

@ -13,7 +13,6 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import webob
from webob import exc from webob import exc
from nova.api.openstack import extensions from nova.api.openstack import extensions
@ -81,6 +80,7 @@ class ConsolesController(object):
raise exc.HTTPNotFound(explanation=e.format_message()) raise exc.HTTPNotFound(explanation=e.format_message())
return _translate_detail_keys(console) return _translate_detail_keys(console)
@wsgi.response(202)
@extensions.expected_errors(404) @extensions.expected_errors(404)
def delete(self, req, server_id, id): def delete(self, req, server_id, id):
"""Deletes a console.""" """Deletes a console."""
@ -90,7 +90,6 @@ class ConsolesController(object):
int(id)) int(id))
except exception.ConsoleNotFound as e: except exception.ConsoleNotFound as e:
raise exc.HTTPNotFound(explanation=e.format_message()) raise exc.HTTPNotFound(explanation=e.format_message())
return webob.Response(status_int=202)
class Consoles(extensions.V3APIExtensionBase): class Consoles(extensions.V3APIExtensionBase):

View File

@ -33,6 +33,7 @@ class DeferredDeleteController(wsgi.Controller):
super(DeferredDeleteController, self).__init__(*args, **kwargs) super(DeferredDeleteController, self).__init__(*args, **kwargs)
self.compute_api = compute.API() self.compute_api = compute.API()
@wsgi.response(202)
@extensions.expected_errors((404, 409, 403)) @extensions.expected_errors((404, 409, 403))
@wsgi.action('restore') @wsgi.action('restore')
def _restore(self, req, id, body): def _restore(self, req, id, body):
@ -48,8 +49,8 @@ class DeferredDeleteController(wsgi.Controller):
except exception.InstanceInvalidState as state_error: except exception.InstanceInvalidState as state_error:
common.raise_http_conflict_for_instance_invalid_state(state_error, common.raise_http_conflict_for_instance_invalid_state(state_error,
'restore', id) 'restore', id)
return webob.Response(status_int=202)
@wsgi.response(202)
@extensions.expected_errors((404, 409)) @extensions.expected_errors((404, 409))
@wsgi.action('forceDelete') @wsgi.action('forceDelete')
def _force_delete(self, req, id, body): def _force_delete(self, req, id, body):
@ -62,7 +63,6 @@ class DeferredDeleteController(wsgi.Controller):
self.compute_api.force_delete(context, instance) self.compute_api.force_delete(context, instance)
except exception.InstanceIsLocked as e: except exception.InstanceIsLocked as e:
raise webob.exc.HTTPConflict(explanation=e.format_message()) raise webob.exc.HTTPConflict(explanation=e.format_message())
return webob.Response(status_int=202)
class DeferredDelete(extensions.V3APIExtensionBase): class DeferredDelete(extensions.V3APIExtensionBase):

View File

@ -13,7 +13,6 @@
# under the License. # under the License.
"""The Extended Volumes API extension.""" """The Extended Volumes API extension."""
import webob
from webob import exc from webob import exc
from nova.api.openstack import common from nova.api.openstack import common
@ -52,6 +51,7 @@ class ExtendedVolumesController(wsgi.Controller):
key = "%s:volumes_attached" % ExtendedVolumes.alias key = "%s:volumes_attached" % ExtendedVolumes.alias
server[key] = [{'id': volume_id} for volume_id in volume_ids] server[key] = [{'id': volume_id} for volume_id in volume_ids]
@wsgi.response(202)
@extensions.expected_errors((400, 404, 409)) @extensions.expected_errors((400, 404, 409))
@wsgi.action('swap_volume_attachment') @wsgi.action('swap_volume_attachment')
@validation.schema(extended_volumes.swap_volume_attachment) @validation.schema(extended_volumes.swap_volume_attachment)
@ -99,8 +99,6 @@ class ExtendedVolumesController(wsgi.Controller):
msg = _("The volume was either invalid or not attached to the " msg = _("The volume was either invalid or not attached to the "
"instance.") "instance.")
raise exc.HTTPNotFound(explanation=msg) raise exc.HTTPNotFound(explanation=msg)
else:
return webob.Response(status_int=202)
@wsgi.extends @wsgi.extends
def show(self, req, resp_obj, id): def show(self, req, resp_obj, id):

View File

@ -32,8 +32,12 @@ class FlavorManageController(wsgi.Controller):
def __init__(self): def __init__(self):
super(FlavorManageController, self).__init__() super(FlavorManageController, self).__init__()
@wsgi.action("delete") # NOTE(oomichi): Return 202 for backwards compatibility but should be
# 204 as this operation complete the deletion of aggregate resource and
# return no response body.
@wsgi.response(202)
@extensions.expected_errors((404)) @extensions.expected_errors((404))
@wsgi.action("delete")
def _delete(self, req, id): def _delete(self, req, id):
context = req.environ['nova.context'] context = req.environ['nova.context']
authorize(context) authorize(context)
@ -46,11 +50,6 @@ class FlavorManageController(wsgi.Controller):
flavors.destroy(flavor['name']) flavors.destroy(flavor['name'])
# NOTE(oomichi): Return 202 for backwards compatibility but should be
# 204 as this operation complete the deletion of aggregate resource and
# return no response body.
return webob.Response(status_int=202)
# NOTE(oomichi): Return 200 for backwards compatibility but should be 201 # NOTE(oomichi): Return 200 for backwards compatibility but should be 201
# as this operation complete the creation of flavor resource. # as this operation complete the creation of flavor resource.
@wsgi.action("create") @wsgi.action("create")

View File

@ -13,8 +13,6 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import webob
from nova.api.openstack import common from nova.api.openstack import common
from nova.api.openstack import extensions from nova.api.openstack import extensions
from nova.api.openstack import wsgi from nova.api.openstack import wsgi
@ -33,6 +31,7 @@ class LockServerController(wsgi.Controller):
super(LockServerController, self).__init__(*args, **kwargs) super(LockServerController, self).__init__(*args, **kwargs)
self.compute_api = compute.API() self.compute_api = compute.API()
@wsgi.response(202)
@extensions.expected_errors(404) @extensions.expected_errors(404)
@wsgi.action('lock') @wsgi.action('lock')
def _lock(self, req, id, body): def _lock(self, req, id, body):
@ -42,8 +41,8 @@ class LockServerController(wsgi.Controller):
instance = common.get_instance(self.compute_api, context, id, instance = common.get_instance(self.compute_api, context, id,
want_objects=True) want_objects=True)
self.compute_api.lock(context, instance) self.compute_api.lock(context, instance)
return webob.Response(status_int=202)
@wsgi.response(202)
@extensions.expected_errors(404) @extensions.expected_errors(404)
@wsgi.action('unlock') @wsgi.action('unlock')
def _unlock(self, req, id, body): def _unlock(self, req, id, body):
@ -53,7 +52,6 @@ class LockServerController(wsgi.Controller):
instance = common.get_instance(self.compute_api, context, id, instance = common.get_instance(self.compute_api, context, id,
want_objects=True) want_objects=True)
self.compute_api.unlock(context, instance) self.compute_api.unlock(context, instance)
return webob.Response(status_int=202)
class LockServer(extensions.V3APIExtensionBase): class LockServer(extensions.V3APIExtensionBase):

View File

@ -14,7 +14,6 @@
# under the License. # under the License.
from oslo.utils import strutils from oslo.utils import strutils
import webob
from webob import exc from webob import exc
from nova.api.openstack import common from nova.api.openstack import common
@ -38,6 +37,7 @@ class MigrateServerController(wsgi.Controller):
super(MigrateServerController, self).__init__(*args, **kwargs) super(MigrateServerController, self).__init__(*args, **kwargs)
self.compute_api = compute.API() self.compute_api = compute.API()
@wsgi.response(202)
@extensions.expected_errors((400, 403, 404, 409)) @extensions.expected_errors((400, 403, 404, 409))
@wsgi.action('migrate') @wsgi.action('migrate')
def _migrate(self, req, id, body): def _migrate(self, req, id, body):
@ -61,8 +61,7 @@ class MigrateServerController(wsgi.Controller):
except exception.NoValidHost as e: except exception.NoValidHost as e:
raise exc.HTTPBadRequest(explanation=e.format_message()) raise exc.HTTPBadRequest(explanation=e.format_message())
return webob.Response(status_int=202) @wsgi.response(202)
@extensions.expected_errors((400, 404, 409)) @extensions.expected_errors((400, 404, 409))
@wsgi.action('os-migrateLive') @wsgi.action('os-migrateLive')
@validation.schema(migrate_server.migrate_live) @validation.schema(migrate_server.migrate_live)
@ -102,7 +101,6 @@ class MigrateServerController(wsgi.Controller):
except exception.InstanceInvalidState as state_error: except exception.InstanceInvalidState as state_error:
common.raise_http_conflict_for_instance_invalid_state(state_error, common.raise_http_conflict_for_instance_invalid_state(state_error,
'os-migrateLive', id) 'os-migrateLive', id)
return webob.Response(status_int=202)
class MigrateServer(extensions.V3APIExtensionBase): class MigrateServer(extensions.V3APIExtensionBase):

View File

@ -15,7 +15,6 @@
"""The multinic extension.""" """The multinic extension."""
import webob
from webob import exc from webob import exc
from nova.api.openstack import common from nova.api.openstack import common
@ -36,6 +35,7 @@ class MultinicController(wsgi.Controller):
super(MultinicController, self).__init__(*args, **kwargs) super(MultinicController, self).__init__(*args, **kwargs)
self.compute_api = compute.API() self.compute_api = compute.API()
@wsgi.response(202)
@wsgi.action('addFixedIp') @wsgi.action('addFixedIp')
@extensions.expected_errors((400, 404)) @extensions.expected_errors((400, 404))
@validation.schema(multinic.add_fixed_ip) @validation.schema(multinic.add_fixed_ip)
@ -52,8 +52,7 @@ class MultinicController(wsgi.Controller):
except exception.NoMoreFixedIps as e: except exception.NoMoreFixedIps as e:
raise exc.HTTPBadRequest(explanation=e.format_message()) raise exc.HTTPBadRequest(explanation=e.format_message())
return webob.Response(status_int=202) @wsgi.response(202)
@wsgi.action('removeFixedIp') @wsgi.action('removeFixedIp')
@extensions.expected_errors((400, 404)) @extensions.expected_errors((400, 404))
@validation.schema(multinic.remove_fixed_ip) @validation.schema(multinic.remove_fixed_ip)
@ -71,8 +70,6 @@ class MultinicController(wsgi.Controller):
except exception.FixedIpNotFoundForSpecificInstance as e: except exception.FixedIpNotFoundForSpecificInstance as e:
raise exc.HTTPBadRequest(explanation=e.format_message()) raise exc.HTTPBadRequest(explanation=e.format_message())
return webob.Response(status_int=202)
# Note: The class name is as it has to be for this to be loaded as an # Note: The class name is as it has to be for this to be loaded as an
# extension--only first character capitalized. # extension--only first character capitalized.

View File

@ -15,7 +15,6 @@
# under the License. # under the License.
import netaddr import netaddr
import webob
from webob import exc from webob import exc
from nova.api.openstack import extensions from nova.api.openstack import extensions
@ -88,9 +87,9 @@ class NetworkController(wsgi.Controller):
result = [network_dict(context, net_ref) for net_ref in networks] result = [network_dict(context, net_ref) for net_ref in networks]
return {'networks': result} return {'networks': result}
@wsgi.response(202)
@extensions.expected_errors((404, 501)) @extensions.expected_errors((404, 501))
@wsgi.action("disassociate") @wsgi.action("disassociate")
@wsgi.response(202)
def _disassociate_host_and_project(self, req, id, body): def _disassociate_host_and_project(self, req, id, body):
context = req.environ['nova.context'] context = req.environ['nova.context']
authorize(context) authorize(context)
@ -117,6 +116,7 @@ class NetworkController(wsgi.Controller):
raise exc.HTTPNotFound(explanation=msg) raise exc.HTTPNotFound(explanation=msg)
return {'network': network_dict(context, network)} return {'network': network_dict(context, network)}
@wsgi.response(202)
@extensions.expected_errors((404, 409)) @extensions.expected_errors((404, 409))
def delete(self, req, id): def delete(self, req, id):
context = req.environ['nova.context'] context = req.environ['nova.context']
@ -129,7 +129,6 @@ class NetworkController(wsgi.Controller):
except exception.NetworkNotFound: except exception.NetworkNotFound:
msg = _("Network not found") msg = _("Network not found")
raise exc.HTTPNotFound(explanation=msg) raise exc.HTTPNotFound(explanation=msg)
return webob.Response(status_int=202)
@extensions.expected_errors((400, 409, 501)) @extensions.expected_errors((400, 409, 501))
def create(self, req, body): def create(self, req, body):
@ -171,8 +170,8 @@ class NetworkController(wsgi.Controller):
raise exc.HTTPConflict(explanation=ex.format_message()) raise exc.HTTPConflict(explanation=ex.format_message())
return {"network": network_dict(context, network)} return {"network": network_dict(context, network)}
@extensions.expected_errors((400, 409, 501))
@wsgi.response(202) @wsgi.response(202)
@extensions.expected_errors((400, 409, 501))
def add(self, req, body): def add(self, req, body):
context = req.environ['nova.context'] context = req.environ['nova.context']
authorize(context) authorize(context)

View File

@ -13,7 +13,6 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import webob
from webob import exc from webob import exc
from nova.api.openstack import common from nova.api.openstack import common
@ -36,6 +35,7 @@ class PauseServerController(wsgi.Controller):
super(PauseServerController, self).__init__(*args, **kwargs) super(PauseServerController, self).__init__(*args, **kwargs)
self.compute_api = compute.API() self.compute_api = compute.API()
@wsgi.response(202)
@extensions.expected_errors((404, 409, 501)) @extensions.expected_errors((404, 409, 501))
@wsgi.action('pause') @wsgi.action('pause')
def _pause(self, req, id, body): def _pause(self, req, id, body):
@ -56,8 +56,8 @@ class PauseServerController(wsgi.Controller):
except NotImplementedError: except NotImplementedError:
msg = _("Virt driver does not implement pause function.") msg = _("Virt driver does not implement pause function.")
raise exc.HTTPNotImplemented(explanation=msg) raise exc.HTTPNotImplemented(explanation=msg)
return webob.Response(status_int=202)
@wsgi.response(202)
@extensions.expected_errors((404, 409, 501)) @extensions.expected_errors((404, 409, 501))
@wsgi.action('unpause') @wsgi.action('unpause')
def _unpause(self, req, id, body): def _unpause(self, req, id, body):
@ -78,7 +78,6 @@ class PauseServerController(wsgi.Controller):
except NotImplementedError: except NotImplementedError:
msg = _("Virt driver does not implement pause function.") msg = _("Virt driver does not implement pause function.")
raise exc.HTTPNotImplemented(explanation=msg) raise exc.HTTPNotImplemented(explanation=msg)
return webob.Response(status_int=202)
class PauseServer(extensions.V3APIExtensionBase): class PauseServer(extensions.V3APIExtensionBase):

View File

@ -136,6 +136,7 @@ class ServerGroupController(wsgi.Controller):
raise webob.exc.HTTPNotFound(explanation=e.format_message()) raise webob.exc.HTTPNotFound(explanation=e.format_message())
return {'server_group': self._format_server_group(context, sg)} return {'server_group': self._format_server_group(context, sg)}
@wsgi.response(204)
@extensions.expected_errors(404) @extensions.expected_errors(404)
def delete(self, req, id): def delete(self, req, id):
"""Delete an server group.""" """Delete an server group."""
@ -167,8 +168,6 @@ class ServerGroupController(wsgi.Controller):
if quotas: if quotas:
quotas.commit() quotas.commit()
return webob.Response(status_int=204)
@extensions.expected_errors(()) @extensions.expected_errors(())
def index(self, req): def index(self, req):
"""Returns a list of server groups.""" """Returns a list of server groups."""

View File

@ -453,8 +453,8 @@ class ServersController(wsgi.Controller):
req.cache_db_instance(instance) req.cache_db_instance(instance)
return self._view_builder.show(req, instance) return self._view_builder.show(req, instance)
@extensions.expected_errors((400, 403, 409, 413))
@wsgi.response(202) @wsgi.response(202)
@extensions.expected_errors((400, 403, 409, 413))
@validation.schema(schema_server_create) @validation.schema(schema_server_create)
def create(self, req, body): def create(self, req, body):
"""Creates a new server for a given user.""" """Creates a new server for a given user."""
@ -700,8 +700,8 @@ class ServersController(wsgi.Controller):
# NOTE(gmann): Returns 204 for backwards compatibility but should be 202 # NOTE(gmann): Returns 204 for backwards compatibility but should be 202
# for representing async API as this API just accepts the request and # for representing async API as this API just accepts the request and
# request hypervisor driver to complete the same in async mode. # request hypervisor driver to complete the same in async mode.
@extensions.expected_errors((400, 404, 409))
@wsgi.response(204) @wsgi.response(204)
@extensions.expected_errors((400, 404, 409))
@wsgi.action('confirmResize') @wsgi.action('confirmResize')
def _action_confirm_resize(self, req, id, body): def _action_confirm_resize(self, req, id, body):
context = req.environ['nova.context'] context = req.environ['nova.context']
@ -717,8 +717,8 @@ class ServersController(wsgi.Controller):
common.raise_http_conflict_for_instance_invalid_state(state_error, common.raise_http_conflict_for_instance_invalid_state(state_error,
'confirmResize', id) 'confirmResize', id)
@extensions.expected_errors((400, 404, 409))
@wsgi.response(202) @wsgi.response(202)
@extensions.expected_errors((400, 404, 409))
@wsgi.action('revertResize') @wsgi.action('revertResize')
def _action_revert_resize(self, req, id, body): def _action_revert_resize(self, req, id, body):
context = req.environ['nova.context'] context = req.environ['nova.context']
@ -736,10 +736,9 @@ class ServersController(wsgi.Controller):
except exception.InstanceInvalidState as state_error: except exception.InstanceInvalidState as state_error:
common.raise_http_conflict_for_instance_invalid_state(state_error, common.raise_http_conflict_for_instance_invalid_state(state_error,
'revertResize', id) 'revertResize', id)
return webob.Response(status_int=202)
@extensions.expected_errors((400, 404, 409))
@wsgi.response(202) @wsgi.response(202)
@extensions.expected_errors((400, 404, 409))
@wsgi.action('reboot') @wsgi.action('reboot')
def _action_reboot(self, req, id, body): def _action_reboot(self, req, id, body):
if 'reboot' in body and 'type' in body['reboot']: if 'reboot' in body and 'type' in body['reboot']:
@ -768,7 +767,6 @@ class ServersController(wsgi.Controller):
except exception.InstanceInvalidState as state_error: except exception.InstanceInvalidState as state_error:
common.raise_http_conflict_for_instance_invalid_state(state_error, common.raise_http_conflict_for_instance_invalid_state(state_error,
'reboot', id) 'reboot', id)
return webob.Response(status_int=202)
def _resize(self, req, instance_id, flavor_id, **kwargs): def _resize(self, req, instance_id, flavor_id, **kwargs):
"""Begin the resize process with given instance/flavor.""" """Begin the resize process with given instance/flavor."""
@ -810,10 +808,8 @@ class ServersController(wsgi.Controller):
msg = _("Invalid instance image.") msg = _("Invalid instance image.")
raise exc.HTTPBadRequest(explanation=msg) raise exc.HTTPBadRequest(explanation=msg)
return webob.Response(status_int=202)
@extensions.expected_errors((404, 409))
@wsgi.response(204) @wsgi.response(204)
@extensions.expected_errors((404, 409))
def delete(self, req, id): def delete(self, req, id):
"""Destroys a server.""" """Destroys a server."""
try: try:
@ -859,8 +855,8 @@ class ServersController(wsgi.Controller):
flavor_ref = data['server']['flavorRef'] flavor_ref = data['server']['flavorRef']
return common.get_id_from_href(flavor_ref) return common.get_id_from_href(flavor_ref)
@extensions.expected_errors((400, 401, 403, 404, 409))
@wsgi.response(202) @wsgi.response(202)
@extensions.expected_errors((400, 401, 403, 404, 409))
@wsgi.action('resize') @wsgi.action('resize')
def _action_resize(self, req, id, body): def _action_resize(self, req, id, body):
"""Resizes a given instance to the flavor size requested.""" """Resizes a given instance to the flavor size requested."""
@ -880,10 +876,10 @@ class ServersController(wsgi.Controller):
self.resize_extension_manager.map(self._resize_extension_point, self.resize_extension_manager.map(self._resize_extension_point,
resize_dict, resize_kwargs) resize_dict, resize_kwargs)
return self._resize(req, id, flavor_ref, **resize_kwargs) self._resize(req, id, flavor_ref, **resize_kwargs)
@extensions.expected_errors((400, 403, 404, 409, 413))
@wsgi.response(202) @wsgi.response(202)
@extensions.expected_errors((400, 403, 404, 409, 413))
@wsgi.action('rebuild') @wsgi.action('rebuild')
@validation.schema(schema_server_rebuild) @validation.schema(schema_server_rebuild)
def _action_rebuild(self, req, id, body): def _action_rebuild(self, req, id, body):
@ -958,8 +954,8 @@ class ServersController(wsgi.Controller):
robj = wsgi.ResponseObject(view) robj = wsgi.ResponseObject(view)
return self._add_location(robj) return self._add_location(robj)
@extensions.expected_errors((400, 403, 404, 409))
@wsgi.response(202) @wsgi.response(202)
@extensions.expected_errors((400, 403, 404, 409))
@wsgi.action('createImage') @wsgi.action('createImage')
@common.check_snapshots_enabled @common.check_snapshots_enabled
def _action_create_image(self, req, id, body): def _action_create_image(self, req, id, body):
@ -1045,6 +1041,7 @@ class ServersController(wsgi.Controller):
except exception.InstanceNotFound as e: except exception.InstanceNotFound as e:
raise webob.exc.HTTPNotFound(explanation=e.format_message()) raise webob.exc.HTTPNotFound(explanation=e.format_message())
@wsgi.response(202)
@extensions.expected_errors((404, 409)) @extensions.expected_errors((404, 409))
@wsgi.action('os-start') @wsgi.action('os-start')
def _start_server(self, req, id, body): def _start_server(self, req, id, body):
@ -1058,8 +1055,8 @@ class ServersController(wsgi.Controller):
except (exception.InstanceNotReady, exception.InstanceIsLocked, except (exception.InstanceNotReady, exception.InstanceIsLocked,
exception.InstanceInvalidState) as e: exception.InstanceInvalidState) as e:
raise webob.exc.HTTPConflict(explanation=e.format_message()) raise webob.exc.HTTPConflict(explanation=e.format_message())
return webob.Response(status_int=202)
@wsgi.response(202)
@extensions.expected_errors((404, 409)) @extensions.expected_errors((404, 409))
@wsgi.action('os-stop') @wsgi.action('os-stop')
def _stop_server(self, req, id, body): def _stop_server(self, req, id, body):
@ -1073,7 +1070,6 @@ class ServersController(wsgi.Controller):
except (exception.InstanceNotReady, exception.InstanceIsLocked, except (exception.InstanceNotReady, exception.InstanceIsLocked,
exception.InstanceInvalidState) as e: exception.InstanceInvalidState) as e:
raise webob.exc.HTTPConflict(explanation=e.format_message()) raise webob.exc.HTTPConflict(explanation=e.format_message())
return webob.Response(status_int=202)
def remove_invalid_options(context, search_options, allowed_search_options): def remove_invalid_options(context, search_options, allowed_search_options):

View File

@ -14,7 +14,6 @@
"""The shelved mode extension.""" """The shelved mode extension."""
import webob
from webob import exc from webob import exc
from nova.api.openstack import common from nova.api.openstack import common
@ -36,6 +35,7 @@ class ShelveController(wsgi.Controller):
super(ShelveController, self).__init__(*args, **kwargs) super(ShelveController, self).__init__(*args, **kwargs)
self.compute_api = compute.API() self.compute_api = compute.API()
@wsgi.response(202)
@exts.expected_errors((404, 409)) @exts.expected_errors((404, 409))
@wsgi.action('shelve') @wsgi.action('shelve')
def _shelve(self, req, id, body): def _shelve(self, req, id, body):
@ -53,8 +53,7 @@ class ShelveController(wsgi.Controller):
common.raise_http_conflict_for_instance_invalid_state(state_error, common.raise_http_conflict_for_instance_invalid_state(state_error,
'shelve', id) 'shelve', id)
return webob.Response(status_int=202) @wsgi.response(202)
@exts.expected_errors((404, 409)) @exts.expected_errors((404, 409))
@wsgi.action('shelveOffload') @wsgi.action('shelveOffload')
def _shelve_offload(self, req, id, body): def _shelve_offload(self, req, id, body):
@ -73,8 +72,7 @@ class ShelveController(wsgi.Controller):
'shelveOffload', 'shelveOffload',
id) id)
return webob.Response(status_int=202) @wsgi.response(202)
@exts.expected_errors((404, 409)) @exts.expected_errors((404, 409))
@wsgi.action('unshelve') @wsgi.action('unshelve')
def _unshelve(self, req, id, body): def _unshelve(self, req, id, body):
@ -91,7 +89,6 @@ class ShelveController(wsgi.Controller):
common.raise_http_conflict_for_instance_invalid_state(state_error, common.raise_http_conflict_for_instance_invalid_state(state_error,
'unshelve', 'unshelve',
id) id)
return webob.Response(status_int=202)
class Shelve(exts.V3APIExtensionBase): class Shelve(exts.V3APIExtensionBase):

View File

@ -12,7 +12,6 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import webob
from webob import exc from webob import exc
from nova.api.openstack import common from nova.api.openstack import common
@ -36,6 +35,7 @@ class SuspendServerController(wsgi.Controller):
super(SuspendServerController, self).__init__(*args, **kwargs) super(SuspendServerController, self).__init__(*args, **kwargs)
self.compute_api = compute.API() self.compute_api = compute.API()
@wsgi.response(202)
@extensions.expected_errors((404, 409)) @extensions.expected_errors((404, 409))
@wsgi.action('suspend') @wsgi.action('suspend')
def _suspend(self, req, id, body): def _suspend(self, req, id, body):
@ -51,8 +51,8 @@ class SuspendServerController(wsgi.Controller):
except exception.InstanceInvalidState as state_error: except exception.InstanceInvalidState as state_error:
common.raise_http_conflict_for_instance_invalid_state(state_error, common.raise_http_conflict_for_instance_invalid_state(state_error,
'suspend', id) 'suspend', id)
return webob.Response(status_int=202)
@wsgi.response(202)
@extensions.expected_errors((404, 409)) @extensions.expected_errors((404, 409))
@wsgi.action('resume') @wsgi.action('resume')
def _resume(self, req, id, body): def _resume(self, req, id, body):
@ -68,7 +68,6 @@ class SuspendServerController(wsgi.Controller):
except exception.InstanceInvalidState as state_error: except exception.InstanceInvalidState as state_error:
common.raise_http_conflict_for_instance_invalid_state(state_error, common.raise_http_conflict_for_instance_invalid_state(state_error,
'resume', id) 'resume', id)
return webob.Response(status_int=202)
class SuspendServer(extensions.V3APIExtensionBase): class SuspendServer(extensions.V3APIExtensionBase):

View File

@ -16,7 +16,6 @@
"""The volumes extension.""" """The volumes extension."""
from oslo.utils import strutils from oslo.utils import strutils
import webob
from webob import exc from webob import exc
from nova.api.openstack import common from nova.api.openstack import common
@ -98,6 +97,7 @@ class VolumeController(wsgi.Controller):
return {'volume': _translate_volume_detail_view(context, vol)} return {'volume': _translate_volume_detail_view(context, vol)}
@wsgi.response(202)
@extensions.expected_errors(404) @extensions.expected_errors(404)
def delete(self, req, id): def delete(self, req, id):
"""Delete a volume.""" """Delete a volume."""
@ -110,7 +110,6 @@ class VolumeController(wsgi.Controller):
self.volume_api.delete(context, id) self.volume_api.delete(context, id)
except exception.NotFound as e: except exception.NotFound as e:
raise exc.HTTPNotFound(explanation=e.format_message()) raise exc.HTTPNotFound(explanation=e.format_message())
return webob.Response(status_int=202)
@extensions.expected_errors(()) @extensions.expected_errors(())
def index(self, req): def index(self, req):
@ -257,6 +256,7 @@ class SnapshotController(wsgi.Controller):
return {'snapshot': _translate_snapshot_detail_view(context, vol)} return {'snapshot': _translate_snapshot_detail_view(context, vol)}
@wsgi.response(202)
@extensions.expected_errors(404) @extensions.expected_errors(404)
def delete(self, req, id): def delete(self, req, id):
"""Delete a snapshot.""" """Delete a snapshot."""
@ -269,7 +269,6 @@ class SnapshotController(wsgi.Controller):
self.volume_api.delete_snapshot(context, id) self.volume_api.delete_snapshot(context, id)
except exception.NotFound as e: except exception.NotFound as e:
raise exc.HTTPNotFound(explanation=e.format_message()) raise exc.HTTPNotFound(explanation=e.format_message())
return webob.Response(status_int=202)
@extensions.expected_errors(()) @extensions.expected_errors(())
def index(self, req): def index(self, req):

View File

@ -702,8 +702,14 @@ class ResetStateTestsV21(test.NoDBTestCase):
body = {"os-resetState": {"state": "active"}} body = {"os-resetState": {"state": "active"}}
result = self.admin_api._reset_state(self.request, self.uuid, result = self.admin_api._reset_state(self.request, self.uuid,
body=body) body=body)
# NOTE: on v2.1, http status code is set as wsgi_code of API
self.assertEqual(result.status_int, 202) # method instead of status_int in a response object.
if isinstance(self.admin_api,
admin_actions_v21.AdminActionsController):
status_int = self.admin_api._reset_state.wsgi_code
else:
status_int = result.status_int
self.assertEqual(202, status_int)
def test_reset_error(self): def test_reset_error(self):
self._setup_mock(dict(vm_state=vm_states.ERROR, self._setup_mock(dict(vm_state=vm_states.ERROR,
@ -712,8 +718,14 @@ class ResetStateTestsV21(test.NoDBTestCase):
body = {"os-resetState": {"state": "error"}} body = {"os-resetState": {"state": "error"}}
result = self.admin_api._reset_state(self.request, self.uuid, result = self.admin_api._reset_state(self.request, self.uuid,
body=body) body=body)
# NOTE: on v2.1, http status code is set as wsgi_code of API
self.assertEqual(result.status_int, 202) # method instead of status_int in a response object.
if isinstance(self.admin_api,
admin_actions_v21.AdminActionsController):
status_int = self.admin_api._reset_state.wsgi_code
else:
status_int = result.status_int
self.assertEqual(202, status_int)
class ResetStateTestsV2(ResetStateTestsV21): class ResetStateTestsV2(ResetStateTestsV21):

View File

@ -221,7 +221,14 @@ class InterfaceAttachTestsV21(test.NoDBTestCase):
req.environ['nova.context'] = self.context req.environ['nova.context'] = self.context
result = self.attachments.delete(req, FAKE_UUID1, FAKE_PORT_ID1) result = self.attachments.delete(req, FAKE_UUID1, FAKE_PORT_ID1)
self.assertEqual('202 Accepted', result.status) # NOTE: on v2.1, http status code is set as wsgi_code of API
# method instead of status_int in a response object.
if isinstance(self.attachments,
attach_interfaces_v3.InterfaceAttachmentController):
status_int = self.attachments.delete.wsgi_code
else:
status_int = result.status_int
self.assertEqual(202, status_int)
def test_detach_interface_instance_locked(self): def test_detach_interface_instance_locked(self):
def fake_detach_interface_from_locked_server(self, context, def fake_detach_interface_from_locked_server(self, context,

View File

@ -55,7 +55,13 @@ class DeferredDeleteExtensionTestV21(test.NoDBTestCase):
self.mox.ReplayAll() self.mox.ReplayAll()
res = self.extension._force_delete(self.fake_req, self.fake_uuid, res = self.extension._force_delete(self.fake_req, self.fake_uuid,
self.fake_input_dict) self.fake_input_dict)
self.assertEqual(res.status_int, 202) # NOTE: on v2.1, http status code is set as wsgi_code of API
# method instead of status_int in a response object.
if isinstance(self.extension, dd_v21.DeferredDeleteController):
status_int = self.extension._force_delete.wsgi_code
else:
status_int = res.status_int
self.assertEqual(202, status_int)
def test_force_delete_instance_not_found(self): def test_force_delete_instance_not_found(self):
self.mox.StubOutWithMock(compute_api.API, 'get') self.mox.StubOutWithMock(compute_api.API, 'get')
@ -97,7 +103,13 @@ class DeferredDeleteExtensionTestV21(test.NoDBTestCase):
self.mox.ReplayAll() self.mox.ReplayAll()
res = self.extension._restore(self.fake_req, self.fake_uuid, res = self.extension._restore(self.fake_req, self.fake_uuid,
self.fake_input_dict) self.fake_input_dict)
self.assertEqual(res.status_int, 202) # NOTE: on v2.1, http status code is set as wsgi_code of API
# method instead of status_int in a response object.
if isinstance(self.extension, dd_v21.DeferredDeleteController):
status_int = self.extension._restore.wsgi_code
else:
status_int = res.status_int
self.assertEqual(202, status_int)
def test_restore_instance_not_found(self): def test_restore_instance_not_found(self):
self.mox.StubOutWithMock(compute_api.API, 'get') self.mox.StubOutWithMock(compute_api.API, 'get')

View File

@ -130,7 +130,15 @@ class FlavorManageTestV21(test.NoDBTestCase):
def test_delete(self): def test_delete(self):
req = fakes.HTTPRequest.blank(self.base_url + '/1234') req = fakes.HTTPRequest.blank(self.base_url + '/1234')
res = self.controller._delete(req, 1234) res = self.controller._delete(req, 1234)
self.assertEqual(res.status_int, 202)
# NOTE: on v2.1, http status code is set as wsgi_code of API
# method instead of status_int in a response object.
if isinstance(self.controller,
flavormanage_v21.FlavorManageController):
status_int = self.controller._delete.wsgi_code
else:
status_int = res.status_int
self.assertEqual(202, status_int)
# subsequent delete should fail # subsequent delete should fail
self.assertRaises(webob.exc.HTTPNotFound, self.assertRaises(webob.exc.HTTPNotFound,

View File

@ -163,7 +163,14 @@ class ServerGroupQuotasTestV21(test.TestCase):
req = fakes.HTTPRequest.blank('/v2/fake/os-server-groups/123') req = fakes.HTTPRequest.blank('/v2/fake/os-server-groups/123')
resp = self.controller.delete(req, '123') resp = self.controller.delete(req, '123')
self.assertTrue(self.called) self.assertTrue(self.called)
self.assertEqual(resp.status_int, 204)
# NOTE: on v2.1, http status code is set as wsgi_code of API
# method instead of status_int in a response object.
if isinstance(self.controller, sg_v3.ServerGroupController):
status_int = self.controller.delete.wsgi_code
else:
status_int = resp.status_int
self.assertEqual(204, status_int)
class ServerGroupQuotasTestV2(ServerGroupQuotasTestV21): class ServerGroupQuotasTestV2(ServerGroupQuotasTestV21):

View File

@ -354,7 +354,14 @@ class ServerGroupTestV21(test.TestCase):
'/os-server-groups/123') '/os-server-groups/123')
resp = self.controller.delete(req, '123') resp = self.controller.delete(req, '123')
self.assertTrue(self.called) self.assertTrue(self.called)
self.assertEqual(resp.status_int, 204)
# NOTE: on v2.1, http status code is set as wsgi_code of API
# method instead of status_int in a response object.
if isinstance(self.controller, sg_v3.ServerGroupController):
status_int = self.controller.delete.wsgi_code
else:
status_int = resp.status_int
self.assertEqual(204, status_int)
def test_delete_non_existing_server_group(self): def test_delete_non_existing_server_group(self):
req = fakes.HTTPRequest.blank(self._get_url() + req = fakes.HTTPRequest.blank(self._get_url() +

View File

@ -1006,7 +1006,14 @@ class DeleteSnapshotTestCaseV21(test.TestCase):
self.req.method = 'DELETE' self.req.method = 'DELETE'
result = self.controller.delete(self.req, result['snapshot']['id']) result = self.controller.delete(self.req, result['snapshot']['id'])
self.assertEqual(result.status_int, 202)
# NOTE: on v2.1, http status code is set as wsgi_code of API
# method instead of status_int in a response object.
if isinstance(self.controller, volumes_v3.SnapshotController):
status_int = self.controller.delete.wsgi_code
else:
status_int = result.status_int
self.assertEqual(202, status_int)
def test_delete_snapshot_not_exists(self): def test_delete_snapshot_not_exists(self):
def fake_delete_snapshot_not_exist(self, context, snapshot_id): def fake_delete_snapshot_not_exist(self, context, snapshot_id):

View File

@ -327,8 +327,9 @@ class ExtendedVolumesTest(test.TestCase):
def test_swap_volume(self): def test_swap_volume(self):
self.stubs.Set(compute.api.API, 'swap_volume', fake_swap_volume) self.stubs.Set(compute.api.API, 'swap_volume', fake_swap_volume)
result = self._test_swap() # Check any exceptions don't happen and status code
self.assertEqual('202 Accepted', result.status) self._test_swap()
self.assertEqual(202, self.Controller.swap.wsgi_code)
def test_swap_volume_for_locked_server(self): def test_swap_volume_for_locked_server(self):
def fake_swap_volume_for_locked_server(self, context, instance, def fake_swap_volume_for_locked_server(self, context, instance,