From: Josh Durgin Date: Wed, 13 Feb 2013 02:18:39 +0000 (-0800) Subject: rbd: update volume<->image copying X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=029435c9288d82dee5dd1113c3553ddb5b97c740;p=openstack-build%2Fcinder-build.git rbd: update volume<->image copying Use fetch_to_raw() to convert from any format when copying an image. Fix two bugs in copy_image_to_volume(): 1) use rbd format 2 if supported 2) resize to match the expected volume size Also implement copy_volume_to_image(). Change-Id: I5589666c33ead087876e850363ad869050120882 Signed-off-by: Josh Durgin --- diff --git a/cinder/tests/test_rbd.py b/cinder/tests/test_rbd.py index 695838b4c..89059ae1b 100644 --- a/cinder/tests/test_rbd.py +++ b/cinder/tests/test_rbd.py @@ -21,6 +21,7 @@ import tempfile from cinder import db from cinder import exception +from cinder.image import image_utils from cinder.openstack.common import log as logging from cinder.openstack.common import timeutils from cinder import test @@ -41,8 +42,8 @@ class RBDTestCase(test.TestCase): def setUp(self): super(RBDTestCase, self).setUp() - def fake_execute(*args): - pass + def fake_execute(*args, **kwargs): + return '', '' self.driver = RBDDriver(execute=fake_execute) def test_good_locations(self): @@ -91,7 +92,9 @@ class RBDTestCase(test.TestCase): yield FakeTmp('test') self.stubs.Set(tempfile, 'NamedTemporaryFile', fake_temp_file) self.stubs.Set(os.path, 'exists', lambda x: True) - self.driver.copy_image_to_volume(None, {'name': 'test'}, + self.stubs.Set(image_utils, 'fetch_to_raw', lambda w, x, y, z: None) + self.driver.copy_image_to_volume(None, {'name': 'test', + 'size': 1}, FakeImageService(), None) def test_copy_image_no_volume_tmp(self): @@ -103,17 +106,8 @@ class RBDTestCase(test.TestCase): self._copy_image() -class FakeRBDDriver(RBDDriver): - - def _clone(self): - pass - - def _resize(self): - pass - - class ManagedRBDTestCase(DriverTestCase): - driver_name = "cinder.tests.test_rbd.FakeRBDDriver" + driver_name = "cinder.volume.drivers.rbd.RBDDriver" def setUp(self): super(ManagedRBDTestCase, self).setUp() @@ -124,7 +118,7 @@ class ManagedRBDTestCase(DriverTestCase): """Try to clone a volume from an image, and check the status afterwards""" def fake_clone_image(volume, image_location): - pass + return True def fake_clone_error(volume, image_location): raise exception.CinderException() diff --git a/cinder/volume/drivers/rbd.py b/cinder/volume/drivers/rbd.py index d5880b4ae..c7abd9b9c 100644 --- a/cinder/volume/drivers/rbd.py +++ b/cinder/volume/drivers/rbd.py @@ -21,8 +21,10 @@ import urllib from cinder import exception from cinder import flags +from cinder.image import image_utils from cinder.openstack.common import cfg from cinder.openstack.common import log as logging +from cinder import utils from cinder.volume import driver @@ -222,19 +224,42 @@ class RBDDriver(driver.VolumeDriver): self._resize(volume) return True + def _ensure_tmp_exists(self): + if FLAGS.volume_tmp_dir and not os.path.exists(FLAGS.volume_tmp_dir): + os.makedirs(FLAGS.volume_tmp_dir) + def copy_image_to_volume(self, context, volume, image_service, image_id): # TODO(jdurgin): replace with librbd # this is a temporary hack, since rewriting this driver # to use librbd would take too long - if FLAGS.volume_tmp_dir and not os.path.exists(FLAGS.volume_tmp_dir): - os.makedirs(FLAGS.volume_tmp_dir) + self._ensure_tmp_exists() with tempfile.NamedTemporaryFile(dir=FLAGS.volume_tmp_dir) as tmp: - image_service.download(context, image_id, tmp) + image_utils.fetch_to_raw(context, image_service, image_id, + tmp.name) # import creates the image, so we must remove it first self._try_execute('rbd', 'rm', '--pool', FLAGS.rbd_pool, volume['name']) - self._try_execute('rbd', 'import', + + args = ['rbd', 'import', + '--pool', FLAGS.rbd_pool, + tmp.name, volume['name']] + if self._supports_layering(): + args += ['--new-format'] + self._try_execute(*args) + self._resize(volume) + + def copy_volume_to_image(self, context, volume, image_service, image_meta): + self._ensure_tmp_exists() + + tmp_dir = FLAGS.volume_tmp_dir or '/tmp' + tmp_file = os.path.join(tmp_dir, + volume['name'] + '-' + image_meta['id']) + with utils.remove_path_on_error(tmp_file): + self._try_execute('rbd', 'export', '--pool', FLAGS.rbd_pool, - tmp.name, volume['name']) + volume['name'], tmp_file) + image_utils.upload_volume(context, image_service, + image_meta, tmp_file) + os.unlink(tmp_file)