]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
rbd: update volume<->image copying
authorJosh Durgin <josh.durgin@inktank.com>
Wed, 13 Feb 2013 02:18:39 +0000 (18:18 -0800)
committerJosh Durgin <josh.durgin@inktank.com>
Wed, 13 Feb 2013 19:13:29 +0000 (11:13 -0800)
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 <josh.durgin@inktank.com>
cinder/tests/test_rbd.py
cinder/volume/drivers/rbd.py

index 695838b4c9fa86ebce16946c7105c1331d5c00bf..89059ae1bf37ae3a908b21836651cbeb2c71e1db 100644 (file)
@@ -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()
index d5880b4aec83796661420a2383ee59154cf1691d..c7abd9b9c7e7724a7dcc926f95a3b8a7a0654584 100644 (file)
@@ -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)