Allow passing image properties to image creation scenarios

2a3d89f added the ability to pass arbitrary kwargs, but that was
removed in 41e33c0, which made it impossible to pass image metadata
properties.

Change-Id: I1baf963a2c374e29bbd3a96c3f3f72ab1107afee
This commit is contained in:
Chris St. Pierre 2017-08-04 14:33:31 -05:00
parent b0e11debcc
commit b957fc301a
9 changed files with 104 additions and 44 deletions

View File

@ -590,6 +590,9 @@
flavor:
name: "m1.tiny"
number_instances: 2
create_image_kwargs:
properties:
hw_video_model: vga
runner:
type: "constant"
times: 1

View File

@ -54,7 +54,7 @@ class GlanceBasic(scenario.OpenStackScenario):
class CreateAndListImage(GlanceBasic):
def run(self, container_format, image_location, disk_format,
visibility="private", min_disk=0, min_ram=0):
visibility="private", min_disk=0, min_ram=0, properties=None):
"""Create an image and then list all images.
Measure the "glance image-list" command performance.
@ -73,6 +73,8 @@ class CreateAndListImage(GlanceBasic):
:param visibility: The access permission for the created image
:param min_disk: The min disk of created images
:param min_ram: The min ram of created images
:param properties: A dict of image metadata properties to set
on the image
"""
image = self.glance.create_image(
container_format=container_format,
@ -80,7 +82,8 @@ class CreateAndListImage(GlanceBasic):
disk_format=disk_format,
visibility=visibility,
min_disk=min_disk,
min_ram=min_ram)
min_ram=min_ram,
properties=properties)
self.assertTrue(image)
image_list = self.glance.list_images()
self.assertIn(image.id, [i.id for i in image_list])
@ -101,7 +104,7 @@ class CreateAndListImage(GlanceBasic):
class CreateAndGetImage(GlanceBasic):
def run(self, container_format, image_location, disk_format,
visibility="private", min_disk=0, min_ram=0):
visibility="private", min_disk=0, min_ram=0, properties=None):
"""Create and get detailed information of an image.
:param container_format: container format of image. Acceptable
@ -112,6 +115,8 @@ class CreateAndGetImage(GlanceBasic):
:param visibility: The access permission for the created image
:param min_disk: The min disk of created images
:param min_ram: The min ram of created images
:param properties: A dict of image metadata properties to set
on the image
"""
image = self.glance.create_image(
container_format=container_format,
@ -119,7 +124,8 @@ class CreateAndGetImage(GlanceBasic):
disk_format=disk_format,
visibility=visibility,
min_disk=min_disk,
min_ram=min_ram)
min_ram=min_ram,
properties=properties)
self.assertTrue(image)
image_info = self.glance.get_image(image)
self.assertEqual(image.id, image_info.id)
@ -159,7 +165,7 @@ class ListImages(GlanceBasic):
class CreateAndDeleteImage(GlanceBasic):
def run(self, container_format, image_location, disk_format,
visibility="private", min_disk=0, min_ram=0):
visibility="private", min_disk=0, min_ram=0, properties=None):
"""Create and then delete an image.
:param container_format: container format of image. Acceptable
@ -170,6 +176,8 @@ class CreateAndDeleteImage(GlanceBasic):
:param visibility: The access permission for the created image
:param min_disk: The min disk of created images
:param min_ram: The min ram of created images
:param properties: A dict of image metadata properties to set
on the image
"""
image = self.glance.create_image(
container_format=container_format,
@ -177,7 +185,8 @@ class CreateAndDeleteImage(GlanceBasic):
disk_format=disk_format,
visibility=visibility,
min_disk=min_disk,
min_ram=min_ram)
min_ram=min_ram,
properties=properties)
self.glance.delete_image(image.id)
@ -201,7 +210,7 @@ class CreateImageAndBootInstances(GlanceBasic, nova_utils.NovaScenario):
def run(self, container_format, image_location, disk_format,
flavor, number_instances, visibility="private", min_disk=0,
min_ram=0, boot_server_kwargs=None, **kwargs):
min_ram=0, properties=None, boot_server_kwargs=None, **kwargs):
"""Create an image and boot several instances from it.
:param container_format: container format of image. Acceptable
@ -212,9 +221,10 @@ class CreateImageAndBootInstances(GlanceBasic, nova_utils.NovaScenario):
:param visibility: The access permission for the created image
:param min_disk: The min disk of created images
:param min_ram: The min ram of created images
:param properties: A dict of image metadata properties to set
on the image
:param flavor: Nova flavor to be used to launch an instance
:param number_instances: number of Nova servers to boot
:param create_image_kwargs: optional parameters to create image
:param boot_server_kwargs: optional parameters to boot server
:param kwargs: optional parameters to create server (deprecated)
"""
@ -231,7 +241,8 @@ class CreateImageAndBootInstances(GlanceBasic, nova_utils.NovaScenario):
disk_format=disk_format,
visibility=visibility,
min_disk=min_disk,
min_ram=min_ram)
min_ram=min_ram,
properties=properties)
self._boot_servers(image.id, flavor, number_instances,
**boot_server_kwargs)
@ -253,7 +264,8 @@ class CreateAndUpdateImage(GlanceBasic):
def run(self, container_format, image_location, disk_format,
remove_props=None, visibility="private", create_min_disk=0,
create_min_ram=0, update_min_disk=0, update_min_ram=0):
create_min_ram=0, create_properties=None,
update_min_disk=0, update_min_ram=0):
"""Create an image then update it.
Measure the "glance image-create" and "glance image-update" commands
@ -269,6 +281,8 @@ class CreateAndUpdateImage(GlanceBasic):
:param visibility: The access permission for the created image
:param create_min_disk: The min disk of created images
:param create_min_ram: The min ram of created images
:param create_properties: A dict of image metadata properties to set
on the created image
:param update_min_disk: The min disk of updated images
:param update_min_ram: The min ram of updated images
"""
@ -278,7 +292,8 @@ class CreateAndUpdateImage(GlanceBasic):
disk_format=disk_format,
visibility=visibility,
min_disk=create_min_disk,
min_ram=create_min_ram)
min_ram=create_min_ram,
properties=create_properties)
self.glance.update_image(image.id,
min_disk=update_min_disk,

View File

@ -32,7 +32,8 @@ class GlanceV1Service(service.Service, glance_common.GlanceMixin):
@atomic.action_timer("glance_v1.create_image")
def create_image(self, image_name=None, container_format=None,
image_location=None, disk_format=None,
is_public=True, min_disk=0, min_ram=0):
is_public=True, min_disk=0, min_ram=0,
properties=None):
"""Creates new image.
:param image_name: Image name for which need to be created
@ -42,6 +43,7 @@ class GlanceV1Service(service.Service, glance_common.GlanceMixin):
:param is_public: The created image's public status
:param min_disk: The min disk of created images
:param min_ram: The min ram of created images
:param properties: Dict of image properties
"""
image_location = os.path.expanduser(image_location)
image_name = image_name or self.generate_random_name()
@ -60,6 +62,7 @@ class GlanceV1Service(service.Service, glance_common.GlanceMixin):
is_public=is_public,
min_disk=min_disk,
min_ram=min_ram,
properties=properties,
**kwargs)
rutils.interruptable_sleep(CONF.benchmark.
@ -134,7 +137,7 @@ class UnifiedGlanceV1Service(glance_common.UnifiedGlanceMixin, image.Image):
def create_image(self, image_name=None, container_format=None,
image_location=None, disk_format=None,
visibility="public", min_disk=0,
min_ram=0):
min_ram=0, properties=None):
"""Creates new image.
:param image_name: Image name for which need to be created
@ -144,6 +147,7 @@ class UnifiedGlanceV1Service(glance_common.UnifiedGlanceMixin, image.Image):
:param visibility: The created image's visible status
:param min_disk: The min disk of created images
:param min_ram: The min ram of created images
:param properties: Dict of image properties
"""
self._check_v1_visibility(visibility)
@ -155,7 +159,8 @@ class UnifiedGlanceV1Service(glance_common.UnifiedGlanceMixin, image.Image):
disk_format=disk_format,
is_public=is_public,
min_disk=min_disk,
min_ram=min_ram)
min_ram=min_ram,
properties=properties)
return self._unify_image(image_obj)
def update_image(self, image_id, image_name=None, min_disk=0,

View File

@ -35,7 +35,7 @@ class GlanceV2Service(service.Service, glance_common.GlanceMixin):
def create_image(self, image_name=None, container_format=None,
image_location=None, disk_format=None,
visibility=None, min_disk=0,
min_ram=0):
min_ram=0, properties=None):
"""Creates new image.
:param image_name: Image name for which need to be created
@ -45,16 +45,19 @@ class GlanceV2Service(service.Service, glance_common.GlanceMixin):
:param visibility: The created image's visible status.
:param min_disk: The min disk of created images
:param min_ram: The min ram of created images
:param properties: Dict of image properties
"""
image_name = image_name or self.generate_random_name()
properties = properties or {}
image_obj = self._clients.glance("2").images.create(
name=image_name,
container_format=container_format,
disk_format=disk_format,
visibility=visibility,
min_disk=min_disk,
min_ram=min_ram)
min_ram=min_ram,
**properties)
image_location = os.path.expanduser(image_location)
rutils.interruptable_sleep(CONF.benchmark.
@ -153,7 +156,7 @@ class UnifiedGlanceV2Service(glance_common.UnifiedGlanceMixin, image.Image):
def create_image(self, image_name=None, container_format=None,
image_location=None, disk_format=None,
visibility=None, min_disk=0,
min_ram=0):
min_ram=0, properties=None):
"""Creates new image.
:param image_name: Image name for which need to be created
@ -163,6 +166,7 @@ class UnifiedGlanceV2Service(glance_common.UnifiedGlanceMixin, image.Image):
:param visibility: The access permission for the created image.
:param min_disk: The min disk of created images
:param min_ram: The min ram of created images
:param properties: Dict of image properties
"""
image_obj = self._impl.create_image(
image_name=image_name,
@ -171,7 +175,8 @@ class UnifiedGlanceV2Service(glance_common.UnifiedGlanceMixin, image.Image):
disk_format=disk_format,
visibility=visibility,
min_disk=min_disk,
min_ram=min_ram)
min_ram=min_ram,
properties=properties)
return self._unify_image(image_obj)
def update_image(self, image_id, image_name=None, min_disk=0,

View File

@ -48,7 +48,7 @@ class Image(service.UnifiedService):
def create_image(self, image_name=None, container_format=None,
image_location=None, disk_format=None,
visibility="private", min_disk=0,
min_ram=0):
min_ram=0, properties=None):
"""Creates new image.
:param image_name: Image name for which need to be created
@ -58,7 +58,9 @@ class Image(service.UnifiedService):
:param visibility: The access permission for the created image.
:param min_disk: The min disk of created images
:param min_ram: The min ram of created images
:param properties: Dict of image properties
"""
properties = properties or {}
image = self._impl.create_image(
image_name=image_name,
container_format=container_format,
@ -66,7 +68,8 @@ class Image(service.UnifiedService):
disk_format=disk_format,
visibility=visibility,
min_disk=min_disk,
min_ram=min_ram)
min_ram=min_ram,
properties=properties)
return image
@service.should_be_overridden

View File

@ -56,22 +56,24 @@ class GlanceBasicTestCase(test.ScenarioTestCase):
mock.Mock(id=0, name="img_1"),
fake_image,
mock.Mock(id=2, name="img_3")]
properties = {"fakeprop": "fake"}
call_args = {"container_format": "cf",
"image_location": "url",
"disk_format": "df",
"visibility": "vs",
"min_disk": 0,
"min_ram": 0}
"min_ram": 0,
"properties": properties}
# Positive case
images.CreateAndListImage(self.context).run(
"cf", "url", "df", "vs", 0, 0)
"cf", "url", "df", "vs", 0, 0, properties)
image_service.create_image.assert_called_once_with(**call_args)
# Negative case: image isn't created
image_service.create_image.return_value = None
self.assertRaises(exceptions.RallyAssertionError,
images.CreateAndListImage(self.context).run,
"cf", "url", "df", "vs", 0, 0)
"cf", "url", "df", "vs", 0, 0, properties)
image_service.create_image.assert_called_with(**call_args)
# Negative case: created image n ot in the list of available images
@ -79,7 +81,7 @@ class GlanceBasicTestCase(test.ScenarioTestCase):
id=12, name="img_nameN")
self.assertRaises(exceptions.RallyAssertionError,
images.CreateAndListImage(self.context).run,
"cf", "url", "df", "vs", 0, 0)
"cf", "url", "df", "vs", 0, 0, properties)
image_service.create_image.assert_called_with(**call_args)
image_service.list_images.assert_called_with()
@ -94,15 +96,17 @@ class GlanceBasicTestCase(test.ScenarioTestCase):
fake_image = fakes.FakeImage(id=1, name="imagexxx")
image_service.create_image.return_value = fake_image
properties = {"fakeprop": "fake"}
call_args = {"container_format": "cf",
"image_location": "url",
"disk_format": "df",
"visibility": "vs",
"min_disk": 0,
"min_ram": 0}
"min_ram": 0,
"properties": properties}
images.CreateAndDeleteImage(self.context).run(
"cf", "url", "df", "vs", 0, 0)
"cf", "url", "df", "vs", 0, 0, properties)
image_service.create_image.assert_called_once_with(**call_args)
image_service.delete_image.assert_called_once_with(fake_image.id)
@ -115,16 +119,18 @@ class GlanceBasicTestCase(test.ScenarioTestCase):
fake_image_info = fakes.FakeImage(id=1, name="img_name1",
status="active")
image_service.get_image.return_value = fake_image_info
properties = {"fakeprop": "fake"}
call_args = {"container_format": "cf",
"image_location": "url",
"disk_format": "df",
"visibility": "vs",
"min_disk": 0,
"min_ram": 0}
"min_ram": 0,
"properties": properties}
# Positive case
images.CreateAndGetImage(self.context).run(
"cf", "url", "df", "vs", 0, 0)
"cf", "url", "df", "vs", 0, 0, properties)
image_service.create_image.assert_called_once_with(**call_args)
image_service.get_image.assert_called_once_with(fake_image)
@ -133,7 +139,7 @@ class GlanceBasicTestCase(test.ScenarioTestCase):
image_service.create_image.return_value = None
self.assertRaises(exceptions.RallyAssertionError,
images.CreateAndGetImage(self.context).run,
"cf", "url", "df", "vs", 0, 0)
"cf", "url", "df", "vs", 0, 0, properties)
image_service.create_image.assert_called_with(**call_args)
# Negative case: image obtained in _get_image not the created image
@ -143,7 +149,7 @@ class GlanceBasicTestCase(test.ScenarioTestCase):
id=12, name="img_nameN")
self.assertRaises(exceptions.RallyAssertionError,
images.CreateAndGetImage(self.context).run,
"cf", "url", "df", "vs", 0, 0)
"cf", "url", "df", "vs", 0, 0, properties)
image_service.create_image.assert_called_with(**call_args)
image_service.get_image.assert_called_with(
image_service.create_image.return_value)
@ -157,15 +163,18 @@ class GlanceBasicTestCase(test.ScenarioTestCase):
image_service.create_image.return_value = fake_image
mock_boot_servers.return_value = fake_servers
boot_server_kwargs = {"fakeserverarg": "f"}
properties = {"fakeprop": "fake"}
call_args = {"container_format": "cf",
"image_location": "url",
"disk_format": "df",
"visibility": "vs",
"min_disk": 0,
"min_ram": 0}
"min_ram": 0,
"properties": properties}
images.CreateImageAndBootInstances(self.context).run(
"cf", "url", "df", "fid", 5, "vs", 0, 0,
"cf", "url", "df", "fid", 5, visibility="vs", min_disk=0,
min_ram=0, properties=properties,
boot_server_kwargs=boot_server_kwargs)
image_service.create_image.assert_called_once_with(**call_args)
mock_boot_servers.assert_called_once_with("image-id-0", "fid",
@ -176,15 +185,17 @@ class GlanceBasicTestCase(test.ScenarioTestCase):
fake_image = fakes.FakeImage(id=1, name="imagexxx")
image_service.create_image.return_value = fake_image
properties = {"fakeprop": "fake"}
create_args = {"container_format": "cf",
"image_location": "url",
"disk_format": "df",
"visibility": "vs",
"min_disk": 0,
"min_ram": 0}
"min_ram": 0,
"properties": properties}
images.CreateAndUpdateImage(self.context).run(
"cf", "url", "df", None, "vs", 0, 0, 0, 0)
"cf", "url", "df", None, "vs", 0, 0, properties, 0, 0)
image_service.create_image.assert_called_once_with(**create_args)
image_service.update_image.assert_called_once_with(

View File

@ -50,20 +50,23 @@ class GlanceV1ServiceTestCase(test.TestCase):
image_name = "image_name"
container_format = "container_format"
disk_format = "disk_format"
properties = {"fakeprop": "fake"}
image = self.service.create_image(
image_name=image_name,
container_format=container_format,
image_location=location,
disk_format=disk_format,
is_public=is_public)
is_public=is_public,
properties=properties)
call_args = {"container_format": container_format,
"disk_format": disk_format,
"is_public": is_public,
"name": image_name,
"min_disk": 0,
"min_ram": 0}
"min_ram": 0,
"properties": properties}
if location.startswith("/"):
call_args["data"] = mock_open.return_value
@ -141,11 +144,14 @@ class UnifiedGlanceV1ServiceTestCase(test.TestCase):
container_format = "container_format"
image_location = "image_location"
disk_format = "disk_format"
properties = {"fakeprop": "fake"}
image = self.service.create_image(image_name=image_name,
container_format=container_format,
image_location=image_location,
disk_format=disk_format,
visibility=visibility)
visibility=visibility,
properties=properties)
is_public = visibility == "public"
callargs = {"image_name": image_name,
@ -154,7 +160,8 @@ class UnifiedGlanceV1ServiceTestCase(test.TestCase):
"disk_format": disk_format,
"is_public": is_public,
"min_disk": 0,
"min_ram": 0}
"min_ram": 0,
"properties": properties}
self.service._impl.create_image.assert_called_once_with(**callargs)
self.assertEqual(mock_image__unify_image.return_value, image)

View File

@ -51,20 +51,23 @@ class GlanceV2ServiceTestCase(test.TestCase):
container_format = "container_format"
disk_format = "disk_format"
visibility = "public"
properties = {"fakeprop": "fake"}
image = self.service.create_image(
image_name=image_name,
container_format=container_format,
image_location=location,
disk_format=disk_format,
visibility=visibility)
visibility=visibility,
properties=properties)
call_args = {"container_format": container_format,
"disk_format": disk_format,
"name": image_name,
"visibility": visibility,
"min_disk": 0,
"min_ram": 0}
"min_ram": 0,
"fakeprop": "fake"}
if location.startswith("/"):
mock_open.assert_called_once_with(location)
@ -143,19 +146,22 @@ class UnifiedGlanceV2ServiceTestCase(test.TestCase):
image_location = "image_location"
disk_format = "disk_format"
visibility = "public"
properties = {"fakeprop": "fake"}
callargs = {"image_name": image_name,
"container_format": container_format,
"image_location": image_location,
"disk_format": disk_format,
"visibility": visibility,
"min_disk": 0,
"min_ram": 0}
"min_ram": 0,
"properties": properties}
image = self.service.create_image(image_name=image_name,
container_format=container_format,
image_location=image_location,
disk_format=disk_format,
visibility=visibility)
visibility=visibility,
properties=properties)
self.assertEqual(mock_image__unify_image.return_value, image)
self.service._impl.create_image.assert_called_once_with(**callargs)

View File

@ -41,17 +41,22 @@ class ImageTestCase(test.TestCase):
(image_name, container_format, image_location, disk_format,
visibility, min_disk, min_ram) = params
service = self.get_service_with_fake_impl()
properties = {"fakeprop": "fake"}
service.create_image(image_name=image_name,
container_format=container_format,
image_location=image_location,
disk_format=disk_format,
visibility=visibility,
min_disk=min_disk,
min_ram=min_ram)
min_ram=min_ram,
properties=properties)
service._impl.create_image.assert_called_once_with(
image_name=image_name, container_format=container_format,
image_location=image_location, disk_format=disk_format,
visibility=visibility, min_disk=min_disk, min_ram=min_ram)
visibility=visibility, min_disk=min_disk, min_ram=min_ram,
properties=properties)
@ddt.data(("image_id", "image_name", "min_disk", "min_ram",
"remove_props"))