Replace glance create image with shade client. 43/59143/1
authorShobhi Jain <shobhi.jain@intel.com>
Wed, 11 Apr 2018 08:34:22 +0000 (09:34 +0100)
committerEmma Foley <emma.l.foley@intel.com>
Wed, 27 Jun 2018 16:27:36 +0000 (17:27 +0100)
Function create_image now uses shade client.

JIRA: YARDSTICK-892

Change-Id: Ia41d9ce702a1f24031080f8a365c1b2bd9ac9faa
Signed-off-by: Shobhi Jain <shobhi.jain@intel.com>
(cherry picked from commit c31edc5ab9013d93ffd32ed72adb14740e43b24a)

yardstick/benchmark/scenarios/lib/create_image.py
yardstick/common/exceptions.py
yardstick/common/openstack_utils.py
yardstick/tests/unit/benchmark/scenarios/lib/test_create_image.py
yardstick/tests/unit/common/test_openstack_utils.py

index bcffc74..d057894 100644 (file)
@@ -6,14 +6,11 @@
 # which accompanies this distribution, and is available at
 # http://www.apache.org/licenses/LICENSE-2.0
 ##############################################################################
-
-from __future__ import print_function
-from __future__ import absolute_import
-
 import logging
 
 from yardstick.benchmark.scenarios import base
-import yardstick.common.openstack_utils as op_utils
+from yardstick.common import openstack_utils
+from yardstick.common import exceptions
 
 LOG = logging.getLogger(__name__)
 
@@ -26,20 +23,23 @@ class CreateImage(base.Scenario):
     def __init__(self, scenario_cfg, context_cfg):
         self.scenario_cfg = scenario_cfg
         self.context_cfg = context_cfg
-        self.options = self.scenario_cfg['options']
-
-        self.image_name = self.options.get("image_name", "TestImage")
-        self.file_path = self.options.get("file_path", None)
-        self.disk_format = self.options.get("disk_format", "qcow2")
-        self.container_format = self.options.get("container_format", "bare")
-        self.min_disk = self.options.get("min_disk", 0)
-        self.min_ram = self.options.get("min_ram", 0)
-        self.protected = self.options.get("protected", False)
-        self.public = self.options.get("public", "public")
-        self.tags = self.options.get("tags", [])
-        self.custom_property = self.options.get("property", {})
-
-        self.glance_client = op_utils.get_glance_client()
+        self.options = self.scenario_cfg["options"]
+
+        self.name = self.options["image_name"]
+        self.file_name = self.options.get("file_name")
+        self.container = self.options.get("container", 'images')
+        self.md5 = self.options.get("md5")
+        self.sha256 = self.options.get("sha256")
+        self.disk_format = self.options.get("disk_format")
+        self.container_format = self.options.get("container_format",)
+        self.disable_vendor_agent = self.options.get("disable_vendor_agent", True)
+        self.wait = self.options.get("wait", True)
+        self.timeout = self.options.get("timeout", 3600)
+        self.allow_duplicates = self.options.get("allow_duplicates", False)
+        self.meta = self.options.get("meta")
+        self.volume = self.options.get("volume")
+
+        self.shade_client = openstack_utils.get_shade_client()
 
         self.setup_done = False
 
@@ -54,19 +54,22 @@ class CreateImage(base.Scenario):
         if not self.setup_done:
             self.setup()
 
-        image_id = op_utils.create_image(self.glance_client, self.image_name,
-                                         self.file_path, self.disk_format,
-                                         self.container_format, self.min_disk,
-                                         self.min_ram, self.protected, self.tags,
-                                         self.public, **self.custom_property)
-
-        if image_id:
-            LOG.info("Create image successful!")
-            values = [image_id]
-
-        else:
-            LOG.info("Create image failed!")
-            values = []
-
-        keys = self.scenario_cfg.get('output', '').split()
+        image_id = openstack_utils.create_image(
+            self.shade_client, self.name, filename=self.file_name,
+            container=self.container, md5=self.md5, sha256=self.sha256,
+            disk_format=self.disk_format,
+            container_format=self.container_format,
+            disable_vendor_agent=self.disable_vendor_agent, wait=self.wait,
+            timeout=self.timeout, allow_duplicates=self.allow_duplicates,
+            meta=self.meta, volume=self.volume)
+
+        if not image_id:
+            result.update({"image_create": 0})
+            LOG.error("Create image failed!")
+            raise exceptions.ScenarioCreateImageError
+
+        result.update({"image_create": 1})
+        LOG.info("Create image successful!")
+        keys = self.scenario_cfg.get("output", '').split()
+        values = [image_id]
         return self._push_to_outputs(keys, values)
index 39a3d20..faa8688 100644 (file)
@@ -270,6 +270,10 @@ class UpdateOpenrcError(ApiServerError):
     message = 'Update openrc ERROR!'
 
 
+class ScenarioCreateImageError(YardstickException):
+    message = 'Glance Create Image Scenario failed'
+
+
 class IxNetworkClientNotConnected(YardstickException):
     message = 'IxNetwork client not connected to a TCL server'
 
index a2b75e0..56cd495 100644 (file)
@@ -714,32 +714,62 @@ def get_image_id(glance_client, image_name):    # pragma: no cover
     return next((i.id for i in images if i.name == image_name), None)
 
 
-def create_image(glance_client, image_name, file_path, disk_format,
-                 container_format, min_disk, min_ram, protected, tag,
-                 public, **kwargs):    # pragma: no cover
-    if not os.path.isfile(file_path):
-        log.error("Error: file %s does not exist.", file_path)
-        return None
+def create_image(shade_client, name, filename=None, container='images',
+                 md5=None, sha256=None, disk_format=None,
+                 container_format=None, disable_vendor_agent=True,
+                 wait=False, timeout=3600, allow_duplicates=False, meta=None,
+                 volume=None, **kwargs):
+    """Upload an image.
+
+    :param name:(str) Name of the image to create. If it is a pathname of an
+                image, the name will be constructed from the extensionless
+                basename of the path.
+    :param filename:(str) The path to the file to upload, if needed.
+    :param container:(str) Name of the container in swift where images should
+                     be uploaded for import if the cloud requires such a thing.
+    :param md5:(str) md5 sum of the image file. If not given, an md5 will
+            be calculated.
+    :param sha256:(str) sha256 sum of the image file. If not given, an md5
+                  will be calculated.
+    :param disk_format:(str) The disk format the image is in.
+    :param container_format:(str) The container format the image is in.
+    :param disable_vendor_agent:(bool) Whether or not to append metadata
+                                flags to the image to inform the cloud in
+                                question to not expect a vendor agent to be running.
+    :param wait:(bool) If true, waits for image to be created.
+    :param timeout:(str) Seconds to wait for image creation.
+    :param allow_duplicates:(bool) If true, skips checks that enforce unique
+                            image name.
+    :param meta:(dict) A dict of key/value pairs to use for metadata that
+                bypasses automatic type conversion.
+    :param volume:(str) Name or ID or volume object of a volume to create an
+                  image from.
+    Additional kwargs will be passed to the image creation as additional
+    metadata for the image and will have all values converted to string
+    except for min_disk, min_ram, size and virtual_size which will be
+    converted to int.
+    If you are sure you have all of your data types correct or have an
+    advanced need to be explicit, use meta. If you are just a normal
+    consumer, using kwargs is likely the right choice.
+    If a value is in meta and kwargs, meta wins.
+    :returns: Image id
+    """
     try:
-        image_id = get_image_id(glance_client, image_name)
+        image_id = shade_client.get_image_id(name)
         if image_id is not None:
-            log.info("Image %s already exists.", image_name)
-        else:
-            log.info("Creating image '%s' from '%s'...", image_name, file_path)
-
-            image = glance_client.images.create(
-                name=image_name, visibility=public, disk_format=disk_format,
-                container_format=container_format, min_disk=min_disk,
-                min_ram=min_ram, tags=tag, protected=protected, **kwargs)
-            image_id = image.id
-            with open(file_path) as image_data:
-                glance_client.images.upload(image_id, image_data)
+            log.info("Image %s already exists.", name)
+            return image_id
+        log.info("Creating image '%s'", name)
+        image = shade_client.create_image(
+            name, filename=filename, container=container, md5=md5, sha256=sha256,
+            disk_format=disk_format, container_format=container_format,
+            disable_vendor_agent=disable_vendor_agent, wait=wait, timeout=timeout,
+            allow_duplicates=allow_duplicates, meta=meta, volume=volume, **kwargs)
+        image_id = image["id"]
         return image_id
-    except Exception:  # pylint: disable=broad-except
-        log.error(
-            "Error [create_glance_image(glance_client, '%s', '%s', '%s')]",
-            image_name, file_path, public)
-        return None
+    except exc.OpenStackCloudException as op_exc:
+        log.error("Failed to create_image(shade_client). "
+                  "Exception message: %s", op_exc.orig_message)
 
 
 def delete_image(glance_client, image_id):    # pragma: no cover
index 639cf29..aebd1df 100644 (file)
@@ -6,30 +6,50 @@
 # which accompanies this distribution, and is available at
 # http://www.apache.org/licenses/LICENSE-2.0
 ##############################################################################
-import unittest
+
 import mock
+from oslo_utils import uuidutils
+import unittest
 
-from yardstick.benchmark.scenarios.lib import create_image
 from yardstick.common import openstack_utils
+from yardstick.common import exceptions
+from yardstick.benchmark.scenarios.lib import create_image
+
 
-# NOTE(elfoley): There should be more tests here.
 class CreateImageTestCase(unittest.TestCase):
 
-    @mock.patch.object(openstack_utils, 'create_image')
-    @mock.patch.object(openstack_utils, 'get_glance_client')
-    def test_create_image(self, mock_get_glance_client, mock_create_image):
-        options = {
-            'image_name': 'yardstick_test_image_01',
-            'disk_format': 'qcow2',
-            'container_format': 'bare',
-            'min_disk': '1',
-            'min_ram': '512',
-            'protected': 'False',
-            'tags': '["yardstick automatic test image"]',
-            'file_path': '/home/opnfv/images/cirros-0.3.5-x86_64-disk.img'
-        }
-        args = {"options": options}
-        obj = create_image.CreateImage(args, {})
-        obj.run({})
-        mock_create_image.assert_called_once()
-        mock_get_glance_client.assert_called_once()
+    def setUp(self):
+        self._mock_create_image = mock.patch.object(
+            openstack_utils, 'create_image')
+        self.mock_create_image = (
+            self._mock_create_image.start())
+        self._mock_get_shade_client = mock.patch.object(
+            openstack_utils, 'get_shade_client')
+        self.mock_get_shade_client = self._mock_get_shade_client.start()
+        self._mock_log = mock.patch.object(create_image, 'LOG')
+        self.mock_log = self._mock_log.start()
+        self.args = {'options': {'image_name': 'yardstick_image'}}
+        self.result = {}
+        self.cimage_obj = create_image.CreateImage(self.args, mock.ANY)
+        self.addCleanup(self._stop_mock)
+
+    def _stop_mock(self):
+        self._mock_create_image.stop()
+        self._mock_get_shade_client.stop()
+        self._mock_log.stop()
+
+    def test_run(self):
+        _uuid = uuidutils.generate_uuid()
+        self.cimage_obj.scenario_cfg = {'output': 'id'}
+        self.mock_create_image.return_value = _uuid
+        output = self.cimage_obj.run(self.result)
+        self.assertEqual({'image_create': 1}, self.result)
+        self.assertEqual({'id': _uuid}, output)
+        self.mock_log.info.asset_called_once_with('Create image successful!')
+
+    def test_run_fail(self):
+        self.mock_create_image.return_value = None
+        with self.assertRaises(exceptions.ScenarioCreateImageError):
+            self.cimage_obj.run(self.result)
+        self.assertEqual({'image_create': 0}, self.result)
+        self.mock_log.error.assert_called_once_with('Create image failed!')
index d1d91e2..9b23c65 100644 (file)
@@ -631,3 +631,39 @@ class DetachVolumeTestCase(unittest.TestCase):
                                                'volume_name_or_id')
         mock_logger.error.assert_called_once()
         self.assertFalse(output)
+
+
+# *********************************************
+#   GLANCE
+# *********************************************
+
+class CreateImageTestCase(unittest.TestCase):
+
+    def setUp(self):
+        self.mock_shade_client = mock.Mock()
+        self._uuid = uuidutils.generate_uuid()
+        self.name = 'image_name'
+
+    @mock.patch.object(openstack_utils, 'log')
+    def test_create_image_already_exit(self, mock_logger):
+        self.mock_shade_client.get_image_id.return_value = self._uuid
+        output = openstack_utils.create_image(self.mock_shade_client, self.name)
+        mock_logger.info.assert_called_once()
+        self.assertEqual(self._uuid, output)
+
+    def test_create_image(self):
+        self.mock_shade_client.get_image_id.return_value = None
+        self.mock_shade_client.create_image.return_value = {'id': self._uuid}
+        output = openstack_utils.create_image(self.mock_shade_client, self.name)
+        self.assertEqual(self._uuid, output)
+
+    @mock.patch.object(openstack_utils, 'log')
+    def test_create_image_exception(self, mock_logger):
+        self.mock_shade_client.get_image_id.return_value = None
+        self.mock_shade_client.create_image.side_effect = (
+            exc.OpenStackCloudException('error message'))
+
+        output = openstack_utils.create_image(self.mock_shade_client,
+                                              self.name)
+        mock_logger.error.assert_called_once()
+        self.assertIsNone(output)