summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Behrens <cbehrens@codestud.com>2012-01-11 20:25:23 -0800
committerChris Behrens <cbehrens@codestud.com>2012-01-12 01:28:01 -0800
commit475691a4bd5795feb50b5c9ccfe98e6487390e58 (patch)
treeb1143ca2ef62f961b0f2bc490a057e60dfbdfffc
parent6ece432be0cfb7356636806ab3c046eff17d494b (diff)
catch InstanceInvalidState in more places
Further fixes to bug 911879 500s or 400s are returned in the OS API when actions are denied due to being in an invalid state. 409 should be returned, instead. A previous review (2846) fixed the delete case and this fixes more. When writing tests, I found a number of exceptions that are not raised anymore, and they were being incorrectly used in tests still. I fixed those up. Change-Id: I0d5b1ed52e0cc9766be8e2a7de84c8601f4bdf26
-rw-r--r--nova/api/openstack/common.py15
-rw-r--r--nova/api/openstack/v2/contrib/admin_actions.py27
-rw-r--r--nova/api/openstack/v2/contrib/deferred_delete.py14
-rw-r--r--nova/api/openstack/v2/servers.py30
-rw-r--r--nova/api/openstack/wsgi.py2
-rw-r--r--nova/exception.py16
-rw-r--r--nova/tests/api/openstack/test_common.py33
-rw-r--r--nova/tests/api/openstack/v2/contrib/test_admin_actions.py52
-rw-r--r--nova/tests/api/openstack/v2/contrib/test_deferred_delete.py120
-rw-r--r--nova/tests/api/openstack/v2/test_server_actions.py59
10 files changed, 324 insertions, 44 deletions
diff --git a/nova/api/openstack/common.py b/nova/api/openstack/common.py
index e96c42ac9..5c2fe8b9b 100644
--- a/nova/api/openstack/common.py
+++ b/nova/api/openstack/common.py
@@ -334,6 +334,21 @@ def get_networks_for_instance(context, instance):
return networks
+def raise_http_conflict_for_instance_invalid_state(exc, action):
+ """Return a webob.exc.HTTPConflict instance containing a message
+ appropriate to return via the API based on the original
+ InstanceInvalidState exception.
+ """
+ attr = exc.kwargs.get('attr')
+ state = exc.kwargs.get('state')
+ if attr and state:
+ msg = _("Cannot '%(action)s' while instance is in %(attr)s %(state)s")
+ else:
+ # At least give some meaningful message
+ msg = _("Instance is in an invalid state for '%(action)s'")
+ raise webob.exc.HTTPConflict(explanation=msg % locals())
+
+
class MetadataDeserializer(wsgi.MetadataXMLDeserializer):
def deserialize(self, text):
dom = minidom.parseString(text)
diff --git a/nova/api/openstack/v2/contrib/admin_actions.py b/nova/api/openstack/v2/contrib/admin_actions.py
index f4207354c..5479f88c4 100644
--- a/nova/api/openstack/v2/contrib/admin_actions.py
+++ b/nova/api/openstack/v2/contrib/admin_actions.py
@@ -56,6 +56,9 @@ class Admin_actions(extensions.ExtensionDescriptor):
try:
server = self.compute_api.get(ctxt, id)
self.compute_api.pause(ctxt, server)
+ except exception.InstanceInvalidState as state_error:
+ common.raise_http_conflict_for_instance_invalid_state(state_error,
+ 'pause')
except Exception:
readable = traceback.format_exc()
LOG.exception(_("Compute.api::pause %s"), readable)
@@ -70,6 +73,9 @@ class Admin_actions(extensions.ExtensionDescriptor):
try:
server = self.compute_api.get(ctxt, id)
self.compute_api.unpause(ctxt, server)
+ except exception.InstanceInvalidState as state_error:
+ common.raise_http_conflict_for_instance_invalid_state(state_error,
+ 'unpause')
except Exception:
readable = traceback.format_exc()
LOG.exception(_("Compute.api::unpause %s"), readable)
@@ -84,6 +90,9 @@ class Admin_actions(extensions.ExtensionDescriptor):
try:
server = self.compute_api.get(context, id)
self.compute_api.suspend(context, server)
+ except exception.InstanceInvalidState as state_error:
+ common.raise_http_conflict_for_instance_invalid_state(state_error,
+ 'suspend')
except Exception:
readable = traceback.format_exc()
LOG.exception(_("compute.api::suspend %s"), readable)
@@ -98,6 +107,9 @@ class Admin_actions(extensions.ExtensionDescriptor):
try:
server = self.compute_api.get(context, id)
self.compute_api.resume(context, server)
+ except exception.InstanceInvalidState as state_error:
+ common.raise_http_conflict_for_instance_invalid_state(state_error,
+ 'resume')
except Exception:
readable = traceback.format_exc()
LOG.exception(_("compute.api::resume %s"), readable)
@@ -112,6 +124,9 @@ class Admin_actions(extensions.ExtensionDescriptor):
try:
instance = self.compute_api.get(context, id)
self.compute_api.resize(req.environ['nova.context'], instance)
+ except exception.InstanceInvalidState as state_error:
+ common.raise_http_conflict_for_instance_invalid_state(state_error,
+ 'migrate')
except Exception, e:
LOG.exception(_("Error in migrate %s"), e)
raise exc.HTTPBadRequest()
@@ -233,12 +248,12 @@ class Admin_actions(extensions.ExtensionDescriptor):
except exception.NotFound:
raise exc.HTTPNotFound(_("Instance not found"))
- image = self.compute_api.backup(context,
- instance,
- image_name,
- backup_type,
- rotation,
- extra_properties=props)
+ try:
+ image = self.compute_api.backup(context, instance, image_name,
+ backup_type, rotation, extra_properties=props)
+ except exception.InstanceInvalidState as state_error:
+ common.raise_http_conflict_for_instance_invalid_state(state_error,
+ 'createBackup')
# build location of newly-created image entity
image_id = str(image['id'])
diff --git a/nova/api/openstack/v2/contrib/deferred_delete.py b/nova/api/openstack/v2/contrib/deferred_delete.py
index 7ae435a8e..0b7c60073 100644
--- a/nova/api/openstack/v2/contrib/deferred_delete.py
+++ b/nova/api/openstack/v2/contrib/deferred_delete.py
@@ -17,9 +17,11 @@
import webob
+from nova.api.openstack import common
from nova.api.openstack.v2 import extensions
from nova.api.openstack.v2 import servers
from nova import compute
+from nova import exception
from nova import log as logging
@@ -44,7 +46,11 @@ class Deferred_delete(extensions.ExtensionDescriptor):
context = req.environ["nova.context"]
instance = self.compute_api.get(context, instance_id)
- self.compute_api.restore(context, instance)
+ try:
+ self.compute_api.restore(context, instance)
+ except exception.InstanceInvalidState as state_error:
+ common.raise_http_conflict_for_instance_invalid_state(state_error,
+ 'restore')
return webob.Response(status_int=202)
def _force_delete(self, input_dict, req, instance_id):
@@ -52,7 +58,11 @@ class Deferred_delete(extensions.ExtensionDescriptor):
context = req.environ["nova.context"]
instance = self.compute_api.get(context, instance_id)
- self.compute_api.force_delete(context, instance)
+ try:
+ self.compute_api.force_delete(context, instance)
+ except exception.InstanceInvalidState as state_error:
+ common.raise_http_conflict_for_instance_invalid_state(state_error,
+ 'forceDelete')
return webob.Response(status_int=202)
def get_actions(self):
diff --git a/nova/api/openstack/v2/servers.py b/nova/api/openstack/v2/servers.py
index ac8dd457a..98f9e0686 100644
--- a/nova/api/openstack/v2/servers.py
+++ b/nova/api/openstack/v2/servers.py
@@ -826,6 +826,9 @@ class Controller(wsgi.Controller):
except exception.MigrationNotFound:
msg = _("Instance has not been resized.")
raise exc.HTTPBadRequest(explanation=msg)
+ except exception.InstanceInvalidState as state_error:
+ common.raise_http_conflict_for_instance_invalid_state(state_error,
+ 'confirmResize')
except Exception, e:
LOG.exception(_("Error in confirm-resize %s"), e)
raise exc.HTTPBadRequest()
@@ -839,6 +842,9 @@ class Controller(wsgi.Controller):
except exception.MigrationNotFound:
msg = _("Instance has not been resized.")
raise exc.HTTPBadRequest(explanation=msg)
+ except exception.InstanceInvalidState as state_error:
+ common.raise_http_conflict_for_instance_invalid_state(state_error,
+ 'revertResize')
except Exception, e:
LOG.exception(_("Error in revert-resize %s"), e)
raise exc.HTTPBadRequest()
@@ -862,6 +868,9 @@ class Controller(wsgi.Controller):
try:
self.compute_api.reboot(context, instance, reboot_type)
+ except exception.InstanceInvalidState as state_error:
+ common.raise_http_conflict_for_instance_invalid_state(state_error,
+ 'reboot')
except Exception, e:
LOG.exception(_("Error in reboot %s"), e)
raise exc.HTTPUnprocessableEntity()
@@ -880,6 +889,9 @@ class Controller(wsgi.Controller):
except exception.CannotResizeToSameSize:
msg = _("Resize requires a change in size.")
raise exc.HTTPBadRequest(explanation=msg)
+ except exception.InstanceInvalidState as state_error:
+ common.raise_http_conflict_for_instance_invalid_state(state_error,
+ 'resize')
return webob.Response(status_int=202)
@@ -893,9 +905,8 @@ class Controller(wsgi.Controller):
except exception.NotFound:
raise exc.HTTPNotFound()
except exception.InstanceInvalidState as state_error:
- state = state_error.kwargs.get("state")
- msg = _("Unable to delete instance when %s") % state
- raise exc.HTTPConflict(explanation=msg)
+ common.raise_http_conflict_for_instance_invalid_state(state_error,
+ 'delete')
def _get_key_name(self, req, body):
if 'server' in body:
@@ -1009,10 +1020,9 @@ class Controller(wsgi.Controller):
image_href,
password,
**kwargs)
-
- except exception.RebuildRequiresActiveInstance:
- msg = _("Instance must be active to rebuild.")
- raise exc.HTTPConflict(explanation=msg)
+ except exception.InstanceInvalidState as state_error:
+ common.raise_http_conflict_for_instance_invalid_state(state_error,
+ 'rebuild')
except exception.InstanceNotFound:
msg = _("Instance could not be found")
raise exc.HTTPNotFound(explanation=msg)
@@ -1064,9 +1074,9 @@ class Controller(wsgi.Controller):
instance,
image_name,
extra_properties=props)
- except exception.InstanceBusy:
- msg = _("Server is currently creating an image. Please wait.")
- raise webob.exc.HTTPConflict(explanation=msg)
+ except exception.InstanceInvalidState as state_error:
+ common.raise_http_conflict_for_instance_invalid_state(state_error,
+ 'createImage')
# build location of newly-created image entity
image_id = str(image['id'])
diff --git a/nova/api/openstack/wsgi.py b/nova/api/openstack/wsgi.py
index 2f6533dc4..2bd6fa817 100644
--- a/nova/api/openstack/wsgi.py
+++ b/nova/api/openstack/wsgi.py
@@ -919,7 +919,7 @@ class Fault(webob.exc.HTTPException):
403: "resizeNotAllowed",
404: "itemNotFound",
405: "badMethod",
- 409: "inProgress",
+ 409: "inProgress", # FIXME(comstud): This doesn't seem right
413: "overLimit",
415: "badMediaType",
501: "notImplemented",
diff --git a/nova/exception.py b/nova/exception.py
index 8ec942a76..f763d205b 100644
--- a/nova/exception.py
+++ b/nova/exception.py
@@ -91,10 +91,6 @@ class ApiError(Error):
super(ApiError, self).__init__(outstr)
-class RebuildRequiresActiveInstance(Error):
- pass
-
-
class DBError(Error):
"""Wraps an implementation specific exception."""
def __init__(self, inner_exception=None):
@@ -211,18 +207,6 @@ class PolicyNotAllowed(NotAuthorized):
message = _("Policy Doesn't allow %(action)s to be performed.")
-class InstanceBusy(NovaException):
- message = _("Instance %(instance_id)s is busy. (%(task_state)s)")
-
-
-class InstanceSnapshotting(InstanceBusy):
- message = _("Instance %(instance_uuid)s is currently snapshotting.")
-
-
-class InstanceBackingUp(InstanceBusy):
- message = _("Instance %(instance_uuid)s is currently being backed up.")
-
-
class Invalid(NovaException):
message = _("Unacceptable parameters.")
diff --git a/nova/tests/api/openstack/test_common.py b/nova/tests/api/openstack/test_common.py
index 4175a2666..cd85208b9 100644
--- a/nova/tests/api/openstack/test_common.py
+++ b/nova/tests/api/openstack/test_common.py
@@ -21,10 +21,11 @@ Test suites for 'common' code used throughout the OpenStack HTTP API.
from lxml import etree
import webob.exc
-import xml.dom.minidom as minidom
-
+# FIXME(comstud): Don't import classes (HACKING)
from webob import Request
+import xml.dom.minidom as minidom
+from nova import exception
from nova import test
from nova.api.openstack import common
from nova.api.openstack import xmlutil
@@ -299,6 +300,34 @@ class MiscFunctionsTest(test.TestCase):
actual = common.get_version_from_href(fixture)
self.assertEqual(actual, expected)
+ def test_raise_http_conflict_for_instance_invalid_state(self):
+ # Correct args
+ exc = exception.InstanceInvalidState(attr='fake_attr',
+ state='fake_state', method='fake_method')
+ try:
+ common.raise_http_conflict_for_instance_invalid_state(exc,
+ 'meow')
+ except Exception, e:
+ self.assertTrue(isinstance(e, webob.exc.HTTPConflict))
+ msg = str(e)
+ self.assertEqual(msg,
+ "Cannot 'meow' while instance is in fake_attr fake_state")
+ else:
+ self.fail("webob.exc.HTTPConflict was not raised")
+
+ # Incorrect args
+ exc = exception.InstanceInvalidState()
+ try:
+ common.raise_http_conflict_for_instance_invalid_state(exc,
+ 'meow')
+ except Exception, e:
+ self.assertTrue(isinstance(e, webob.exc.HTTPConflict))
+ msg = str(e)
+ self.assertEqual(msg,
+ "Instance is in an invalid state for 'meow'")
+ else:
+ self.fail("webob.exc.HTTPConflict was not raised")
+
class MetadataXMLDeserializationTest(test.TestCase):
diff --git a/nova/tests/api/openstack/v2/contrib/test_admin_actions.py b/nova/tests/api/openstack/v2/contrib/test_admin_actions.py
index 53016636d..e3c5e6b08 100644
--- a/nova/tests/api/openstack/v2/contrib/test_admin_actions.py
+++ b/nova/tests/api/openstack/v2/contrib/test_admin_actions.py
@@ -21,6 +21,7 @@ from nova.api.openstack import v2
from nova.api.openstack.v2 import extensions
from nova.api.openstack import wsgi
from nova import compute
+from nova import exception
from nova import flags
from nova import test
from nova import utils
@@ -46,10 +47,14 @@ INSTANCE = {
}
-def fake_compute_api(cls, req, id):
+def fake_compute_api(*args, **kwargs):
return True
+def fake_compute_api_raises_invalid_state(*args, **kwargs):
+ raise exception.InstanceInvalidState
+
+
def fake_compute_api_get(self, context, instance_id):
return {'id': 1, 'uuid': instance_id}
@@ -62,6 +67,14 @@ class AdminActionsTest(test.TestCase):
_methods = ('pause', 'unpause', 'suspend', 'resume', 'resize',
'reset_network', 'inject_network_info', 'lock', 'unlock')
+ _actions_that_check_state = (
+ # action, method
+ ('pause', 'pause'),
+ ('unpause', 'unpause'),
+ ('suspend', 'suspend'),
+ ('resume', 'resume'),
+ ('migrate', 'resize'))
+
def setUp(self):
super(AdminActionsTest, self).setUp()
self.stubs.Set(compute.API, 'get', fake_compute_api_get)
@@ -74,13 +87,32 @@ class AdminActionsTest(test.TestCase):
self.maxDiff = None
app = fakes.wsgi_app()
for _action in self._actions:
- req = webob.Request.blank('/v2/fake/servers/%s/action' % self.UUID)
+ req = webob.Request.blank('/v2/fake/servers/%s/action' %
+ self.UUID)
req.method = 'POST'
req.body = json.dumps({_action: None})
req.content_type = 'application/json'
res = req.get_response(app)
self.assertEqual(res.status_int, 202)
+ def test_admin_api_actions_raise_conflict_on_invalid_state(self):
+ self.maxDiff = None
+ app = fakes.wsgi_app()
+
+ for _action, _method in self._actions_that_check_state:
+ self.stubs.Set(compute.API, _method,
+ fake_compute_api_raises_invalid_state)
+
+ req = webob.Request.blank('/v2/fake/servers/%s/action' %
+ self.UUID)
+ req.method = 'POST'
+ req.body = json.dumps({_action: None})
+ req.content_type = 'application/json'
+ res = req.get_response(app)
+ self.assertEqual(res.status_int, 409)
+ self.assertIn("invalid state for '%(_action)s'" % locals(),
+ res.body)
+
class CreateBackupTests(test.TestCase):
@@ -200,3 +232,19 @@ class CreateBackupTests(test.TestCase):
instance_ref = self.backup_stubs.extra_props_last_call['instance_ref']
expected_server_location = 'http://localhost/v2/servers/%s' % self.uuid
self.assertEqual(expected_server_location, instance_ref)
+
+ def test_create_backup_raises_conflict_on_invalid_state(self):
+ body = {
+ 'createBackup': {
+ 'name': 'Backup 1',
+ 'backup_type': 'daily',
+ 'rotation': 1,
+ },
+ }
+
+ self.stubs.Set(compute.API, 'backup',
+ fake_compute_api_raises_invalid_state)
+
+ request = self._get_request(body)
+ response = request.get_response(self.app)
+ self.assertEqual(response.status_int, 409)
diff --git a/nova/tests/api/openstack/v2/contrib/test_deferred_delete.py b/nova/tests/api/openstack/v2/contrib/test_deferred_delete.py
new file mode 100644
index 000000000..222e62577
--- /dev/null
+++ b/nova/tests/api/openstack/v2/contrib/test_deferred_delete.py
@@ -0,0 +1,120 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# 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 mox
+import webob
+
+from nova.api.openstack.v2.contrib import deferred_delete
+from nova import compute
+from nova import exception
+from nova import test
+
+
+class FakeExtensionDescriptor(object):
+ def register(*args, **kwargs):
+ pass
+
+
+class FakeRequest(object):
+ def __init__(self, context):
+ self.environ = {'nova.context': context}
+
+
+class DeferredDeleteExtensionTest(test.TestCase):
+ def setUp(self):
+ super(DeferredDeleteExtensionTest, self).setUp()
+ self.extension = deferred_delete.Deferred_delete(
+ FakeExtensionDescriptor())
+ self.fake_input_dict = {}
+ self.fake_uuid = 'fake_uuid'
+ self.fake_context = 'fake_context'
+ self.fake_req = FakeRequest(self.fake_context)
+
+ def test_force_delete(self):
+ self.mox.StubOutWithMock(compute.API, 'get')
+ self.mox.StubOutWithMock(compute.API, 'force_delete')
+
+ fake_instance = 'fake_instance'
+
+ compute.API.get(self.fake_context, self.fake_uuid).AndReturn(
+ fake_instance)
+ compute.API.force_delete(self.fake_context, fake_instance)
+
+ self.mox.ReplayAll()
+ res = self.extension._force_delete(self.fake_input_dict,
+ self.fake_req, self.fake_uuid)
+ self.mox.VerifyAll()
+ self.assertEqual(res.status_int, 202)
+
+ def test_force_delete_raises_conflict_on_invalid_state(self):
+ self.mox.StubOutWithMock(compute.API, 'get')
+ self.mox.StubOutWithMock(compute.API, 'force_delete')
+
+ fake_instance = 'fake_instance'
+
+ compute.API.get(self.fake_context, self.fake_uuid).AndReturn(
+ fake_instance)
+ compute.API.force_delete(self.fake_context, fake_instance).AndRaise(
+ exception.InstanceInvalidState)
+
+ self.mox.ReplayAll()
+ self.assertRaises(webob.exc.HTTPConflict,
+ self.extension._force_delete, self.fake_input_dict,
+ self.fake_req, self.fake_uuid)
+ self.mox.VerifyAll()
+
+ def test_restore(self):
+ self.mox.StubOutWithMock(compute.API, 'get')
+ self.mox.StubOutWithMock(compute.API, 'restore')
+
+ fake_instance = 'fake_instance'
+
+ compute.API.get(self.fake_context, self.fake_uuid).AndReturn(
+ fake_instance)
+ compute.API.restore(self.fake_context, fake_instance)
+
+ self.mox.ReplayAll()
+ res = self.extension._restore(self.fake_input_dict,
+ self.fake_req, self.fake_uuid)
+ self.mox.VerifyAll()
+ self.assertEqual(res.status_int, 202)
+
+ def test_restore_raises_conflict_on_invalid_state(self):
+ self.mox.StubOutWithMock(compute.API, 'get')
+ self.mox.StubOutWithMock(compute.API, 'restore')
+
+ fake_instance = 'fake_instance'
+
+ compute.API.get(self.fake_context, self.fake_uuid).AndReturn(
+ fake_instance)
+ compute.API.restore(self.fake_context, fake_instance).AndRaise(
+ exception.InstanceInvalidState)
+
+ self.mox.ReplayAll()
+ self.assertRaises(webob.exc.HTTPConflict, self.extension._restore,
+ self.fake_input_dict, self.fake_req, self.fake_uuid)
+ self.mox.VerifyAll()
+
+ def test_get_actions(self):
+ result = self.extension.get_actions()
+ self.assertEqual(len(result), 2)
+
+ action_and_methods = [(x.action_name, x.handler) for x in result]
+ self.assertIn(('restore', self.extension._restore),
+ action_and_methods)
+ self.assertIn(('forceDelete', self.extension._force_delete),
+ action_and_methods)
diff --git a/nova/tests/api/openstack/v2/test_server_actions.py b/nova/tests/api/openstack/v2/test_server_actions.py
index 781c5b4e8..d2958e3b2 100644
--- a/nova/tests/api/openstack/v2/test_server_actions.py
+++ b/nova/tests/api/openstack/v2/test_server_actions.py
@@ -254,6 +254,18 @@ class ServerActionsControllerTest(test.TestCase):
self.assertRaises(webob.exc.HTTPNotFound, self.controller.action,
req, str(utils.gen_uuid()), body)
+ def test_reboot_raises_conflict_on_invalid_state(self):
+ body = dict(reboot=dict(type="HARD"))
+
+ def fake_reboot(*args, **kwargs):
+ raise exception.InstanceInvalidState
+
+ self.stubs.Set(nova.compute.api.API, 'reboot', fake_reboot)
+
+ req = fakes.HTTPRequest.blank(self.url)
+ self.assertRaises(webob.exc.HTTPConflict, self.controller.action,
+ req, FAKE_UUID, body)
+
def test_rebuild_accepted_minimum(self):
new_return_server = return_server_with_attributes(image_ref='2')
self.stubs.Set(nova.db, 'instance_get', new_return_server)
@@ -274,7 +286,7 @@ class ServerActionsControllerTest(test.TestCase):
FLAGS.password_length)
self.assertEqual(robj['location'], self_href)
- def test_rebuild_rejected_when_building(self):
+ def test_rebuild_raises_conflict_on_invalid_state(self):
body = {
"rebuild": {
"imageRef": "http://localhost/images/2",
@@ -282,7 +294,7 @@ class ServerActionsControllerTest(test.TestCase):
}
def fake_rebuild(*args, **kwargs):
- raise exception.RebuildRequiresActiveInstance
+ raise exception.InstanceInvalidState
self.stubs.Set(nova.compute.api.API, 'rebuild', fake_rebuild)
@@ -451,6 +463,18 @@ class ServerActionsControllerTest(test.TestCase):
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.action, req, FAKE_UUID, body)
+ def test_resize_raises_conflict_on_invalid_state(self):
+ body = dict(resize=dict(flavorRef="http://localhost/3"))
+
+ def fake_resize(*args, **kwargs):
+ raise exception.InstanceInvalidState
+
+ self.stubs.Set(nova.compute.api.API, 'resize', fake_resize)
+
+ req = fakes.HTTPRequest.blank(self.url)
+ self.assertRaises(webob.exc.HTTPConflict, self.controller.action,
+ req, FAKE_UUID, body)
+
def test_confirm_resize_server(self):
body = dict(confirmResize=None)
@@ -481,6 +505,19 @@ class ServerActionsControllerTest(test.TestCase):
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.action, req, FAKE_UUID, body)
+ def test_confirm_resize_raises_conflict_on_invalid_state(self):
+ body = dict(confirmResize=None)
+
+ def fake_confirm_resize(*args, **kwargs):
+ raise exception.InstanceInvalidState
+
+ self.stubs.Set(nova.compute.api.API, 'confirm_resize',
+ fake_confirm_resize)
+
+ req = fakes.HTTPRequest.blank(self.url)
+ self.assertRaises(webob.exc.HTTPConflict, self.controller.action,
+ req, FAKE_UUID, body)
+
def test_revert_resize_migration_not_found(self):
body = dict(revertResize=None)
@@ -511,6 +548,19 @@ class ServerActionsControllerTest(test.TestCase):
self.assertEqual(self.revert_resize_called, True)
+ def test_revert_resize_raises_conflict_on_invalid_state(self):
+ body = dict(revertResize=None)
+
+ def fake_revert_resize(*args, **kwargs):
+ raise exception.InstanceInvalidState
+
+ self.stubs.Set(nova.compute.api.API, 'revert_resize',
+ fake_revert_resize)
+
+ req = fakes.HTTPRequest.blank(self.url)
+ self.assertRaises(webob.exc.HTTPConflict, self.controller.action,
+ req, FAKE_UUID, body)
+
def test_create_image(self):
body = {
'createImage': {
@@ -588,10 +638,9 @@ class ServerActionsControllerTest(test.TestCase):
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.action, req, FAKE_UUID, body)
- def test_create_image_conflict_snapshot(self):
- """Attempt to create image when image is already being created."""
+ def test_create_image_raises_conflict_on_invalid_state(self):
def snapshot(*args, **kwargs):
- raise exception.InstanceSnapshotting
+ raise exception.InstanceInvalidState
self.stubs.Set(nova.compute.API, 'snapshot', snapshot)
body = {