Snapshots/backups can no longer happen simultaneously. Tests included.
Implemented exception.InstanceBusy when attempting to snapshot/backup an instance which is already snapshotting or being currently backed up. Fixes bug 727502. (Patch Set 2) 3 new exceptions: InstanceBusy, InstanceSnapshotting, and InstanceBackingUp (Patch Set 3) Oops. New exceptions now inherit from InstanceBusy (Patch Set 4) Tests now tear down created instances Change-Id: I9614740bba26c04e64b0e27c24fbace12334f4d1
This commit is contained in:
@@ -130,10 +130,15 @@ class ControllerV10(Controller):
|
||||
|
||||
context = req.environ["nova.context"]
|
||||
props = {'instance_id': instance_id}
|
||||
image = self._compute_service.snapshot(context,
|
||||
instance_id,
|
||||
image_name,
|
||||
extra_properties=props)
|
||||
|
||||
try:
|
||||
image = self._compute_service.snapshot(context,
|
||||
instance_id,
|
||||
image_name,
|
||||
extra_properties=props)
|
||||
except exception.InstanceBusy:
|
||||
msg = _("Server is currently creating an image. Please wait.")
|
||||
raise webob.exc.HTTPConflict(explanation=msg)
|
||||
|
||||
return dict(image=self.get_builder(req).build(image, detail=True))
|
||||
|
||||
|
||||
@@ -1246,10 +1246,14 @@ class ControllerV11(Controller):
|
||||
msg = _("Invalid metadata")
|
||||
raise exc.HTTPBadRequest(explanation=msg)
|
||||
|
||||
image = self.compute_api.snapshot(context,
|
||||
instance_id,
|
||||
image_name,
|
||||
extra_properties=props)
|
||||
try:
|
||||
image = self.compute_api.snapshot(context,
|
||||
instance_id,
|
||||
image_name,
|
||||
extra_properties=props)
|
||||
except exception.InstanceBusy:
|
||||
msg = _("Server is currently creating an image. Please wait.")
|
||||
raise webob.exc.HTTPConflict(explanation=msg)
|
||||
|
||||
# build location of newly-created image entity
|
||||
image_id = str(image['id'])
|
||||
|
||||
@@ -1117,6 +1117,14 @@ class API(base.Base):
|
||||
|
||||
"""
|
||||
instance = self.db.instance_get(context, instance_id)
|
||||
task_state = instance["task_state"]
|
||||
|
||||
if task_state == task_states.IMAGE_BACKUP:
|
||||
raise exception.InstanceBackingUp(instance_id=instance_id)
|
||||
|
||||
if task_state == task_states.IMAGE_SNAPSHOT:
|
||||
raise exception.InstanceSnapshotting(instance_id=instance_id)
|
||||
|
||||
properties = {'instance_uuid': instance['uuid'],
|
||||
'user_id': str(context.user_id),
|
||||
'image_state': 'creating',
|
||||
|
||||
@@ -175,6 +175,18 @@ class AdminRequired(NotAuthorized):
|
||||
message = _("User does not have admin privileges")
|
||||
|
||||
|
||||
class InstanceBusy(NovaException):
|
||||
message = _("Instance %(instance_id)s is busy. (%(task_state)s)")
|
||||
|
||||
|
||||
class InstanceSnapshotting(InstanceBusy):
|
||||
message = _("Instance %(instance_id)s is currently snapshotting.")
|
||||
|
||||
|
||||
class InstanceBackingUp(InstanceBusy):
|
||||
message = _("Instance %(instance_id)s is currently being backed up.")
|
||||
|
||||
|
||||
class Invalid(NovaException):
|
||||
message = _("Unacceptable parameters.")
|
||||
|
||||
|
||||
@@ -1826,6 +1826,23 @@ class ServersTest(test.TestCase):
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 400)
|
||||
|
||||
def test_create_image_conflict_snapshot_v1_1(self):
|
||||
"""Attempt to create image when image is already being created."""
|
||||
def snapshot(*args, **kwargs):
|
||||
raise exception.InstanceSnapshotting
|
||||
self.stubs.Set(nova.compute.API, 'snapshot', snapshot)
|
||||
|
||||
req = webob.Request.blank('/v1.1/fakes/servers/1/action')
|
||||
req.method = 'POST'
|
||||
req.body = json.dumps({
|
||||
"createImage": {
|
||||
"name": "test_snapshot",
|
||||
},
|
||||
})
|
||||
req.headers["content-type"] = "application/json"
|
||||
res = req.get_response(fakes.wsgi_app())
|
||||
self.assertEqual(res.status_int, 409)
|
||||
|
||||
def test_create_instance_nonstring_name(self):
|
||||
self._setup_for_create_instance()
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ from nova import utils
|
||||
from nova.compute import instance_types
|
||||
from nova.compute import manager as compute_manager
|
||||
from nova.compute import power_state
|
||||
from nova.compute import task_states
|
||||
from nova.compute import vm_states
|
||||
from nova.db.sqlalchemy import models
|
||||
from nova.image import fake as fake_image
|
||||
@@ -401,6 +402,36 @@ class ComputeTestCase(test.TestCase):
|
||||
self.compute.snapshot_instance(self.context, instance_id, name)
|
||||
self.compute.terminate_instance(self.context, instance_id)
|
||||
|
||||
def test_snapshot_conflict_backup(self):
|
||||
"""Can't backup an instance which is already being backed up."""
|
||||
instance_id = self._create_instance()
|
||||
instance_values = {'task_state': task_states.IMAGE_BACKUP}
|
||||
db.instance_update(self.context, instance_id, instance_values)
|
||||
|
||||
self.assertRaises(exception.InstanceBackingUp,
|
||||
self.compute_api.backup,
|
||||
self.context,
|
||||
instance_id,
|
||||
None,
|
||||
None,
|
||||
None)
|
||||
|
||||
db.instance_destroy(self.context, instance_id)
|
||||
|
||||
def test_snapshot_conflict_snapshot(self):
|
||||
"""Can't snapshot an instance which is already being snapshotted."""
|
||||
instance_id = self._create_instance()
|
||||
instance_values = {'task_state': task_states.IMAGE_SNAPSHOT}
|
||||
db.instance_update(self.context, instance_id, instance_values)
|
||||
|
||||
self.assertRaises(exception.InstanceSnapshotting,
|
||||
self.compute_api.snapshot,
|
||||
self.context,
|
||||
instance_id,
|
||||
None)
|
||||
|
||||
db.instance_destroy(self.context, instance_id)
|
||||
|
||||
def test_console_output(self):
|
||||
"""Make sure we can get console output from instance"""
|
||||
instance_id = self._create_instance()
|
||||
|
||||
Reference in New Issue
Block a user