diff --git a/rally/plugins/openstack/services/image/glance_v2.py b/rally/plugins/openstack/services/image/glance_v2.py index 3fa7ac3a..fcd4d0d0 100644 --- a/rally/plugins/openstack/services/image/glance_v2.py +++ b/rally/plugins/openstack/services/image/glance_v2.py @@ -31,6 +31,29 @@ CONF = cfg.CONF @service.service("glance", service_type="image", version="2") class GlanceV2Service(service.Service, glance_common.GlanceMixin): + @atomic.action_timer("glance_v2.upload_data") + def upload_data(self, image_id, image_location): + """Upload the data for an image. + + :param image_id: Image ID to upload data to. + :param image_location: Location of the data to upload to. + """ + image_location = os.path.expanduser(image_location) + image_data = None + response = None + try: + if os.path.isfile(image_location): + image_data = open(image_location) + else: + response = requests.get(image_location, stream=True) + image_data = response.raw + self._clients.glance("2").images.upload(image_id, image_data) + finally: + if image_data is not None: + image_data.close() + if response is not None: + response.close() + @atomic.action_timer("glance_v2.create_image") def create_image(self, image_name=None, container_format=None, image_location=None, disk_format=None, @@ -59,7 +82,6 @@ class GlanceV2Service(service.Service, glance_common.GlanceMixin): min_ram=min_ram, **properties) - image_location = os.path.expanduser(image_location) rutils.interruptable_sleep(CONF.openstack. glance_image_create_prepoll_delay) @@ -71,20 +93,7 @@ class GlanceV2Service(service.Service, glance_common.GlanceMixin): check_interval=CONF.openstack.glance_image_create_poll_interval) timeout = time.time() - start - image_data = None - response = None - try: - if os.path.isfile(image_location): - image_data = open(image_location) - else: - response = requests.get(image_location, stream=True) - image_data = response.raw - self._clients.glance("2").images.upload(image_obj.id, image_data) - finally: - if image_data is not None: - image_data.close() - if response is not None: - response.close() + self.upload_data(image_obj.id, image_location=image_location) image_obj = utils.wait_for_status( image_obj, ["active"], diff --git a/tests/unit/plugins/openstack/services/image/test_glance_v2.py b/tests/unit/plugins/openstack/services/image/test_glance_v2.py index dc8fcf72..bd135806 100755 --- a/tests/unit/plugins/openstack/services/image/test_glance_v2.py +++ b/tests/unit/plugins/openstack/services/image/test_glance_v2.py @@ -22,8 +22,7 @@ from rally.plugins.openstack.services.image import glance_v2 from tests.unit import test -PATH = ("rally.plugins.openstack.services.image.glance_common." - "UnifiedGlanceMixin._unify_image") +PATH = "rally.plugins.openstack.services.image" @ddt.ddt @@ -46,12 +45,29 @@ class GlanceV2ServiceTestCase(test.TestCase): @ddt.unpack @mock.patch("requests.get") @mock.patch("six.moves.builtins.open") - def test_create_image(self, mock_open, mock_requests_get, location): + def test_upload(self, mock_open, mock_requests_get, location): + image_id = "foo" + + self.service.upload_data(image_id, image_location=location) + + if location.startswith("/"): + mock_open.assert_called_once_with(location) + mock_open.return_value.close.assert_called_once_with() + self.gc.images.upload.assert_called_once_with( + image_id, mock_open.return_value) + else: + mock_requests_get.assert_called_once_with(location, stream=True) + self.gc.images.upload.assert_called_once_with( + image_id, mock_requests_get.return_value.raw) + + @mock.patch("%s.glance_v2.GlanceV2Service.upload_data" % PATH) + def test_create_image(self, mock_upload_data): image_name = "image_name" container_format = "container_format" disk_format = "disk_format" visibility = "public" properties = {"fakeprop": "fake"} + location = "location" image = self.service.create_image( image_name=image_name, @@ -68,14 +84,11 @@ class GlanceV2ServiceTestCase(test.TestCase): "min_disk": 0, "min_ram": 0, "fakeprop": "fake"} - - if location.startswith("/"): - mock_open.assert_called_once_with(location) - mock_open.return_value.close.assert_called_once_with() - else: - mock_requests_get.assert_called_once_with(location, stream=True) self.gc.images.create.assert_called_once_with(**call_args) self.assertEqual(image, self.mock_wait_for_status.mock.return_value) + mock_upload_data.assert_called_once_with( + self.mock_wait_for_status.mock.return_value.id, + image_location=location) def test_update_image(self): image_id = "image_id" @@ -149,7 +162,7 @@ class UnifiedGlanceV2ServiceTestCase(test.TestCase): self.service = glance_v2.UnifiedGlanceV2Service(self.clients) self.service._impl = mock.create_autospec(self.service._impl) - @mock.patch(PATH) + @mock.patch("%s.glance_common.UnifiedGlanceMixin._unify_image" % PATH) def test_create_image(self, mock_image__unify_image): image_name = "image_name" container_format = "container_format" @@ -176,7 +189,7 @@ class UnifiedGlanceV2ServiceTestCase(test.TestCase): self.assertEqual(mock_image__unify_image.return_value, image) self.service._impl.create_image.assert_called_once_with(**callargs) - @mock.patch(PATH) + @mock.patch("%s.glance_common.UnifiedGlanceMixin._unify_image" % PATH) def test_update_image(self, mock_image__unify_image): image_id = "image_id" image_name = "image_name" @@ -192,7 +205,7 @@ class UnifiedGlanceV2ServiceTestCase(test.TestCase): self.assertEqual(mock_image__unify_image.return_value, image) self.service._impl.update_image.assert_called_once_with(**callargs) - @mock.patch(PATH) + @mock.patch("%s.glance_common.UnifiedGlanceMixin._unify_image" % PATH) def test_list_images(self, mock_image__unify_image): images = [mock.MagicMock()] self.service._impl.list_images.return_value = images