From f8842781cdc7a7a2a82333f3f728e0dfac30a501 Mon Sep 17 00:00:00 2001 From: John Griffith Date: Mon, 4 Feb 2013 17:54:56 -0700 Subject: [PATCH] Copy glance_image_metadata when cloning volumes. When cloning a volume we were not capturing/copying the glance_image_metadata from the source volume. This change implements a copy_image_metadata_from_vol_to_vol. So now we can clone bootable volumes without going back to glance or messing with them otherwise, they're just ready to be booted. Fixes bug: 1115634 Change-Id: I859bb2550267c6a5142e85ec89f1c7ff885588ac --- cinder/db/api.py | 13 ++++++++++ cinder/db/sqlalchemy/api.py | 27 +++++++++++++++++++++ cinder/tests/test_volume_glance_metadata.py | 16 ++++++++++++ cinder/volume/manager.py | 12 +++------ 4 files changed, 60 insertions(+), 8 deletions(-) diff --git a/cinder/db/api.py b/cinder/db/api.py index 0b2ab8d88..065083e17 100644 --- a/cinder/db/api.py +++ b/cinder/db/api.py @@ -441,6 +441,19 @@ def volume_glance_metadata_delete_by_snapshot(context, snapshot_id): return IMPL.volume_glance_metadata_delete_by_snapshot(context, snapshot_id) +def volume_glance_metadata_copy_from_volume_to_volume(context, + src_volume_id, + volume_id): + """ + Update the Glance metadata for a volume by copying all of the key:value + pairs from the originating volume. This is so that a volume created from + the volume (clone) will retain the original metadata. + """ + return IMPL.volume_glance_metadata_copy_from_volume_to_volume( + context, + src_volume_id, + volume_id) + ################### diff --git a/cinder/db/sqlalchemy/api.py b/cinder/db/sqlalchemy/api.py index ddce45db6..1818b96b4 100644 --- a/cinder/db/sqlalchemy/api.py +++ b/cinder/db/sqlalchemy/api.py @@ -1597,6 +1597,33 @@ def volume_glance_metadata_copy_to_snapshot(context, snapshot_id, volume_id, vol_glance_metadata.save(session=session) +@require_context +@require_volume_exists +def volume_glance_metadata_copy_from_volume_to_volume(context, + src_volume_id, + volume_id, + session=None): + """ + Update the Glance metadata for a volume by copying all of the key:value + pairs from the originating volume. This is so that a volume created from + the volume (clone) will retain the original metadata. + """ + if session is None: + session = get_session() + + metadata = volume_glance_metadata_get(context, + src_volume_id, + session=session) + with session.begin(): + for meta in metadata: + vol_glance_metadata = models.VolumeGlanceMetadata() + vol_glance_metadata.volume_id = volume_id + vol_glance_metadata.key = meta['key'] + vol_glance_metadata.value = meta['value'] + + vol_glance_metadata.save(session=session) + + @require_context @require_volume_exists def volume_glance_metadata_copy_to_volume(context, volume_id, snapshot_id, diff --git a/cinder/tests/test_volume_glance_metadata.py b/cinder/tests/test_volume_glance_metadata.py index f1a36d2ac..5aa42d8b1 100644 --- a/cinder/tests/test_volume_glance_metadata.py +++ b/cinder/tests/test_volume_glance_metadata.py @@ -113,3 +113,19 @@ class VolumeGlanceMetadataTestCase(test.TestCase): for meta in db.volume_snapshot_glance_metadata_get(ctxt, 100): for (key, value) in expected_meta.items(): self.assertEquals(meta[key], value) + + def test_vol_glance_metadata_copy_to_volume(self): + ctxt = context.get_admin_context() + db.volume_create(ctxt, {'id': 1}) + db.volume_create(ctxt, {'id': 100, 'source_volid': 1}) + vol_meta = db.volume_glance_metadata_create(ctxt, 1, 'key1', + 'value1') + db.volume_glance_metadata_copy_from_volume_to_volume(ctxt, 100, 1) + + expected_meta = {'id': '100', + 'key': 'key1', + 'value': 'value1'} + + for meta in db.volume_glance_metadata_get(ctxt, 100): + for (key, value) in expected_meta.items(): + self.assertEquals(meta[key], value) diff --git a/cinder/volume/manager.py b/cinder/volume/manager.py index 40dfafe03..6ad70fb18 100644 --- a/cinder/volume/manager.py +++ b/cinder/volume/manager.py @@ -176,12 +176,12 @@ class VolumeManager(manager.SchedulerDependentManager): snapshot_ref) elif source_volid is not None: src_vref = self.db.volume_get(context, source_volid) - self.db.volume_update(context, src_vref['id'], - {'status': 'in use'}) model_update = self.driver.create_cloned_volume(volume_ref, src_vref) - self.db.volume_update(context, src_vref['id'], - {'status': src_vref['status']}) + self.db.volume_glance_metadata_copy_from_volume_to_volume( + context, + source_volid, + volume_id) else: # create the volume from an image image_service, image_id = \ @@ -221,10 +221,6 @@ class VolumeManager(manager.SchedulerDependentManager): self._reset_stats() if image_id and not cloned: - # NOTE(jdg): Our current ref hasn't been updated since - # the create, need to update ref to get provider_location - # before trying to perform the copy operation - volume_ref = self.db.volume_get(context, volume_id) if image_meta: # Copy all of the Glance image properties to the # volume_glance_metadata table for future reference. -- 2.45.2