]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
Add support to import images into sheepdog volumes.
authorWenhao Xu <wenhao@zelin.io>
Wed, 6 Mar 2013 08:51:33 +0000 (16:51 +0800)
committerWenhao Xu <wenhao@zelin.io>
Thu, 11 Jul 2013 07:48:25 +0000 (15:48 +0800)
Supporting import images from glance to sheepdog volumes.
Unit test framework for sheepdog is added too.

Fix Bug #1148784

Change-Id: I8ffd1bc1b2d719aed27ce0d98eaa41fef8027ca2

cinder/image/image_utils.py
cinder/tests/test_sheepdog.py
cinder/volume/drivers/sheepdog.py

index b5f67ffda300618103db4dbd8e1f21653a805781..af6f887daf9b72809db959701d6d68e4f7c5ed53 100644 (file)
@@ -211,6 +211,27 @@ def fetch(context, image_service, image_id, path, _user_id, _project_id):
             image_service.download(context, image_id, image_file)
 
 
+def fetch_verify_image(context, image_service, image_id, dest,
+                       user_id=None, project_id=None):
+    fetch(context, image_service, image_id, dest,
+          None, None)
+
+    with fileutils.remove_path_on_error(dest):
+        data = qemu_img_info(dest)
+        fmt = data.file_format
+        if fmt is None:
+            raise exception.ImageUnacceptable(
+                reason=_("'qemu-img info' parsing failed."),
+                image_id=image_id)
+
+        backing_file = data.backing_file
+        if backing_file is not None:
+            raise exception.ImageUnacceptable(
+                image_id=image_id,
+                reason=_("fmt=%(fmt)s backed by:"
+                         "%(backing_file)s") % locals())
+
+
 def fetch_to_raw(context, image_service,
                  image_id, dest,
                  user_id=None, project_id=None):
index 7fe3862dacf144a4ea4ca41b233aad9d3c350ec8..b533516c94e97e03719aff96c42c5796fcb6e87f 100644 (file)
@@ -1,6 +1,6 @@
 # vim: tabstop=4 shiftwidth=4 softtabstop=4
 
-# Copyright 2013 Wenhao Xu
+# Copyright (c) 2013 Zelin.io
 # All Rights Reserved.
 #
 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+
+import contextlib
+import os
+import tempfile
+
 from cinder import exception
+from cinder.image import image_utils
 from cinder import test
 from cinder.volume.drivers.sheepdog import SheepdogDriver
 
+
 COLLIE_NODE_INFO = """
 0 107287605248 3623897354 3%
 Total 107287605248 3623897354 3% 54760833024
@@ -43,8 +50,12 @@ Epoch Time           Version
 """
 
 
-class SheepdogTestCase(test.TestCase):
+class FakeImageService:
+    def download(self, context, image_id, path):
+        pass
 
+
+class SheepdogTestCase(test.TestCase):
     def setUp(self):
         super(SheepdogTestCase, self).setUp()
         self.driver = SheepdogDriver()
@@ -92,3 +103,25 @@ class SheepdogTestCase(test.TestCase):
             return COLLIE_CLUSTER_INFO_0_6, ''
         self.stubs.Set(self.driver, '_execute', fake_stats)
         self.driver.check_for_setup_error()
+
+    def test_copy_image_to_volume(self):
+        @contextlib.contextmanager
+        def fake_temp_file(dir):
+            class FakeTmp:
+                def __init__(self, name):
+                    self.name = name
+            yield FakeTmp('test')
+
+        def fake_try_execute(obj, *command, **kwargs):
+            return True
+
+        self.stubs.Set(tempfile, 'NamedTemporaryFile', fake_temp_file)
+        self.stubs.Set(os.path, 'exists', lambda x: True)
+        self.stubs.Set(image_utils, 'fetch_verify_image',
+                       lambda w, x, y, z: None)
+        self.stubs.Set(image_utils, 'convert_image',
+                       lambda x, y, z: None)
+        self.stubs.Set(SheepdogDriver, '_try_execute', fake_try_execute)
+        self.driver.copy_image_to_volume(None, {'name': 'test',
+                                                'size': 1},
+                                         FakeImageService(), None)
index db3b64c4a1fbf9d3cfdb5ec58ab94f173ba823f7..cbca091a833329ad38909d9463ac384fddff09d2 100644 (file)
@@ -1,4 +1,6 @@
 #    Copyright 2012 OpenStack LLC
+#    Copyright (c) 2013 Zelin.io
+#    All Rights Reserved.
 #
 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
 #    not use this file except in compliance with the License. You may obtain
 SheepDog Volume Driver.
 
 """
+import os
 import re
+import tempfile
 
 from oslo.config import cfg
 
 from cinder import exception
+from cinder.image import image_utils
 from cinder.openstack.common import log as logging
 from cinder.volume import driver
 
 
 LOG = logging.getLogger(__name__)
 
+CONF = cfg.CONF
+CONF.import_opt("image_conversion_dir", "cinder.image.image_utils")
+
 
 class SheepdogDriver(driver.VolumeDriver):
     """Executes commands relating to Sheepdog Volumes"""
@@ -70,7 +78,37 @@ class SheepdogDriver(driver.VolumeDriver):
 
     def delete_volume(self, volume):
         """Deletes a logical volume"""
-        self._try_execute('collie', 'vdi', 'delete', volume['name'])
+        self._delete(volume)
+
+    def _ensure_dir_exists(self, tmp_dir):
+        if tmp_dir and not os.path.exists(tmp_dir):
+            os.makedirs(tmp_dir)
+
+    def _resize(self, volume):
+        size = int(volume['size']) * (1024 ** 3)
+        self._try_execute('collie', 'vdi', 'resize',
+                          volume['name'], size)
+
+    def _delete(self, volume):
+        self._try_execute('collie', 'vdi', 'delete',
+                          volume['name'])
+
+    def copy_image_to_volume(self, context, volume, image_service, image_id):
+        # use the image_conversion_dir as a temporary place to save the image
+        conversion_dir = CONF.image_conversion_dir
+        self._ensure_dir_exists(conversion_dir)
+        with tempfile.NamedTemporaryFile(dir=conversion_dir) as tmp:
+            # (wenhao): we don't need to convert to raw for sheepdog.
+            image_utils.fetch_verify_image(context, image_service,
+                                           image_id, tmp.name)
+
+            # remove the image created by import before this function.
+            # see volume/drivers/manager.py:_create_volume
+            self._delete(volume)
+            # convert and store into sheepdog
+            image_utils.convert_image(tmp, 'sheepdog:%s' % volume['name'],
+                                      'raw')
+            self._resize(volume)
 
     def create_snapshot(self, snapshot):
         """Creates a sheepdog snapshot"""