diff options
| author | Jenkins <jenkins@review.openstack.org> | 2012-03-30 16:38:27 +0000 |
|---|---|---|
| committer | Gerrit Code Review <review@openstack.org> | 2012-03-30 16:38:27 +0000 |
| commit | ad4e65a6688fceecac3f44f9d8eb46e35b6ed6d8 (patch) | |
| tree | 073fe7b615a5adeaf82c81adbf18aa1d11fc8ab5 | |
| parent | 0a6ffe3f2a570aa222814efa149882edf8a7b224 (diff) | |
| parent | 43c63d11417de8624d120ca78a9849d09ffa8cf6 (diff) | |
| download | nova-ad4e65a6688fceecac3f44f9d8eb46e35b6ed6d8.tar.gz nova-ad4e65a6688fceecac3f44f9d8eb46e35b6ed6d8.tar.xz nova-ad4e65a6688fceecac3f44f9d8eb46e35b6ed6d8.zip | |
Merge "Check that volume has no snapshots before deletion"
| -rw-r--r-- | nova/db/api.py | 5 | ||||
| -rw-r--r-- | nova/db/sqlalchemy/api.py | 7 | ||||
| -rw-r--r-- | nova/tests/test_volume.py | 23 | ||||
| -rw-r--r-- | nova/volume/api.py | 6 |
4 files changed, 41 insertions, 0 deletions
diff --git a/nova/db/api.py b/nova/db/api.py index 850c772c7..a7fbd34fd 100644 --- a/nova/db/api.py +++ b/nova/db/api.py @@ -1053,6 +1053,11 @@ def snapshot_get_all_by_project(context, project_id): return IMPL.snapshot_get_all_by_project(context, project_id) +def snapshot_get_all_for_volume(context, volume_id): + """Get all snapshots for a volume.""" + return IMPL.snapshot_get_all_for_volume(context, volume_id) + + def snapshot_update(context, snapshot_id, values): """Set the given properties on an snapshot and update it. diff --git a/nova/db/sqlalchemy/api.py b/nova/db/sqlalchemy/api.py index 040534a0d..2ce42e1cc 100644 --- a/nova/db/sqlalchemy/api.py +++ b/nova/db/sqlalchemy/api.py @@ -2658,6 +2658,13 @@ def snapshot_get_all(context): @require_context +def snapshot_get_all_for_volume(context, volume_id): + return model_query(context, models.Snapshot, read_deleted='no', + project_only=True).\ + filter_by(volume_id=volume_id).all() + + +@require_context def snapshot_get_all_by_project(context, project_id): authorize_project_context(context, project_id) return model_query(context, models.Snapshot).\ diff --git a/nova/tests/test_volume.py b/nova/tests/test_volume.py index caeaa7098..be589d3e2 100644 --- a/nova/tests/test_volume.py +++ b/nova/tests/test_volume.py @@ -256,6 +256,29 @@ class VolumeTestCase(test.TestCase): snapshot_id) self.volume.delete_volume(self.context, volume['id']) + def test_cant_delete_volume_with_snapshots(self): + """Test snapshot can be created and deleted.""" + volume = self._create_volume() + self.volume.create_volume(self.context, volume['id']) + snapshot_id = self._create_snapshot(volume['id']) + self.volume.create_snapshot(self.context, volume['id'], snapshot_id) + self.assertEqual(snapshot_id, + db.snapshot_get(context.get_admin_context(), + snapshot_id).id) + + volume['status'] = 'available' + volume['host'] = 'fakehost' + + volume_api = nova.volume.api.API() + + self.assertRaises(exception.InvalidVolume, + volume_api.delete, + self.context, + volume) + + self.volume.delete_snapshot(self.context, snapshot_id) + self.volume.delete_volume(self.context, volume['id']) + def test_create_snapshot_force(self): """Test snapshot in use can be created forcibly.""" diff --git a/nova/volume/api.py b/nova/volume/api.py index bf79fd119..26d56c057 100644 --- a/nova/volume/api.py +++ b/nova/volume/api.py @@ -136,6 +136,12 @@ class API(base.Base): if volume['status'] not in ["available", "error"]: msg = _("Volume status must be available or error") raise exception.InvalidVolume(reason=msg) + + snapshots = self.db.snapshot_get_all_for_volume(context, volume_id) + if len(snapshots): + msg = _("Volume still has %d dependent snapshots" % len(snapshots)) + raise exception.InvalidVolume(reason=msg) + now = utils.utcnow() self.db.volume_update(context, volume_id, {'status': 'deleting', 'terminated_at': now}) |
