[Service] Port all glance scenarios to Image Service
Changes: - glancewrapper are ported to Image Service - All existing glance scenarios are ported to Image service Change-Id: I128dd6fc970cae946a9ecf23da36c349e37d24a0
This commit is contained in:
parent
0cf7108577
commit
279574d01c
@ -166,12 +166,11 @@
|
||||
- admin
|
||||
images:
|
||||
image_url: "~/.rally/extra/fake-image.img"
|
||||
image_type: "qcow2"
|
||||
image_container: "bare"
|
||||
disk_format: "qcow2"
|
||||
container_format: "bare"
|
||||
images_per_tenant: 1
|
||||
image_name: "image-context-test"
|
||||
image_args:
|
||||
visibility: "public"
|
||||
visibility: "public"
|
||||
sla:
|
||||
failure_rate:
|
||||
max: 0
|
||||
|
@ -736,12 +736,11 @@
|
||||
- admin
|
||||
images:
|
||||
image_url: "{{ cirros_image_url }}"
|
||||
image_type: "qcow2"
|
||||
image_container: "bare"
|
||||
disk_format: "qcow2"
|
||||
container_format: "bare"
|
||||
images_per_tenant: 1
|
||||
image_name: "rally-named-image-from-context"
|
||||
image_args:
|
||||
visibility: "public"
|
||||
visibility: "public"
|
||||
sla:
|
||||
failure_rate:
|
||||
max: 0
|
||||
|
@ -834,8 +834,8 @@
|
||||
users_per_tenant: 2
|
||||
images:
|
||||
image_url: "{{ cirros_image_url }}"
|
||||
image_type: "qcow2"
|
||||
image_container: "bare"
|
||||
disk_format: "qcow2"
|
||||
container_format: "bare"
|
||||
images_per_tenant: 1
|
||||
sla:
|
||||
failure_rate:
|
||||
@ -852,8 +852,8 @@
|
||||
users_per_tenant: 2
|
||||
images:
|
||||
image_url: "~/.rally/extra/fake-image.img"
|
||||
image_type: "qcow2"
|
||||
image_container: "bare"
|
||||
disk_format: "qcow2"
|
||||
container_format: "bare"
|
||||
images_per_tenant: 1
|
||||
sla:
|
||||
failure_rate:
|
||||
|
@ -867,8 +867,8 @@
|
||||
users_per_tenant: 2
|
||||
images:
|
||||
image_url: "{{ cirros_image_url }}"
|
||||
image_type: "qcow2"
|
||||
image_container: "bare"
|
||||
disk_format: "qcow2"
|
||||
container_format: "bare"
|
||||
images_per_tenant: 1
|
||||
sla:
|
||||
failure_rate:
|
||||
@ -885,8 +885,8 @@
|
||||
users_per_tenant: 2
|
||||
images:
|
||||
image_url: "~/.rally/extra/fake-image.img"
|
||||
image_type: "qcow2"
|
||||
image_container: "bare"
|
||||
disk_format: "qcow2"
|
||||
container_format: "bare"
|
||||
images_per_tenant: 1
|
||||
sla:
|
||||
failure_rate:
|
||||
@ -913,6 +913,7 @@
|
||||
# failure_rate:
|
||||
# max: 0
|
||||
#
|
||||
|
||||
-
|
||||
args:
|
||||
image_location: "{{ cirros_image_url }}"
|
||||
@ -932,6 +933,7 @@
|
||||
sla:
|
||||
failure_rate:
|
||||
max: 0
|
||||
|
||||
#
|
||||
# -
|
||||
# args:
|
||||
@ -976,6 +978,7 @@
|
||||
# failure_rate:
|
||||
# max: 0
|
||||
#
|
||||
|
||||
-
|
||||
args:
|
||||
image_location: "~/.rally/extra/fake-image.img"
|
||||
|
@ -19,7 +19,7 @@ from rally.common import logging
|
||||
from rally.common import utils as rutils
|
||||
from rally import consts
|
||||
from rally import osclients
|
||||
from rally.plugins.openstack.wrappers import glance as glance_wrapper
|
||||
from rally.plugins.openstack.services.image import image
|
||||
from rally.task import context
|
||||
from rally.task import utils
|
||||
|
||||
@ -49,41 +49,94 @@ class ImageGenerator(context.Context):
|
||||
"enum": ["qcow2", "raw", "vhd", "vmdk", "vdi", "iso", "aki",
|
||||
"ari", "ami"],
|
||||
},
|
||||
"disk_format": {
|
||||
"enum": ["qcow2", "raw", "vhd", "vmdk", "vdi", "iso", "aki",
|
||||
"ari", "ami"]
|
||||
},
|
||||
"image_container": {
|
||||
"type": "string",
|
||||
},
|
||||
"container_format": {
|
||||
"enum": ["aki", "ami", "ari", "bare", "docker", "ova", "ovf"]
|
||||
},
|
||||
"image_name": {
|
||||
"type": "string",
|
||||
},
|
||||
"min_ram": { # megabytes
|
||||
"min_ram": {
|
||||
"description": "Amount of RAM in MB",
|
||||
"type": "integer",
|
||||
"minimum": 0
|
||||
},
|
||||
"min_disk": { # gigabytes
|
||||
"min_disk": {
|
||||
"description": "Amount of disk space in GB",
|
||||
"type": "integer",
|
||||
"minimum": 0
|
||||
},
|
||||
"visibility": {
|
||||
"enum": ["public", "private", "shared", "community"]
|
||||
},
|
||||
"images_per_tenant": {
|
||||
"type": "integer",
|
||||
"minimum": 1
|
||||
},
|
||||
"image_args": {
|
||||
"description": "This param is deprecated from Rally-0.10.0",
|
||||
"type": "object",
|
||||
"additionalProperties": True
|
||||
}
|
||||
},
|
||||
"required": ["image_url", "image_type", "image_container",
|
||||
"images_per_tenant"],
|
||||
"oneOf": [{"description": "It is been used since Rally 0.10.0",
|
||||
"required": ["image_url", "disk_format",
|
||||
"container_format", "images_per_tenant"]},
|
||||
{"description": "One of backward compatible way",
|
||||
"required": ["image_url", "image_type",
|
||||
"container_format", "images_per_tenant"]},
|
||||
{"description": "One of backward compatible way",
|
||||
"required": ["image_url", "disk_format",
|
||||
"image_container", "images_per_tenant"]},
|
||||
{"description": "One of backward compatible way",
|
||||
"required": ["image_url", "image_type",
|
||||
"image_container", "images_per_tenant"]}],
|
||||
"additionalProperties": False
|
||||
}
|
||||
|
||||
@logging.log_task_wrapper(LOG.info, _("Enter context: `Images`"))
|
||||
def setup(self):
|
||||
image_url = self.config["image_url"]
|
||||
image_type = self.config["image_type"]
|
||||
image_container = self.config["image_container"]
|
||||
images_per_tenant = self.config["images_per_tenant"]
|
||||
image_url = self.config.get("image_url")
|
||||
image_type = self.config.get("image_type")
|
||||
disk_format = self.config.get("disk_format")
|
||||
image_container = self.config.get("image_container")
|
||||
container_format = self.config.get("container_format")
|
||||
images_per_tenant = self.config.get("images_per_tenant")
|
||||
image_name = self.config.get("image_name")
|
||||
visibility = self.config.get("visibility", "private")
|
||||
min_disk = self.config.get("min_disk", 0)
|
||||
min_ram = self.config.get("min_ram", 0)
|
||||
image_args = self.config.get("image_args", {})
|
||||
is_public = image_args.get("is_public")
|
||||
|
||||
if is_public:
|
||||
LOG.warning(_("The 'is_public' argument is deprecated "
|
||||
"since Rally 0.10.0; specify visibility "
|
||||
"arguments instead"))
|
||||
if "visibility" not in self.config:
|
||||
visibility = "public" if is_public else "private"
|
||||
|
||||
if image_type:
|
||||
LOG.warning(_("The 'image_type' argument is deprecated "
|
||||
"since Rally 0.10.0; specify disk_format "
|
||||
"arguments instead"))
|
||||
disk_format = image_type
|
||||
|
||||
if image_container:
|
||||
LOG.warning(_("The 'image_container' argument is deprecated "
|
||||
"since Rally 0.10.0; specify container_format "
|
||||
"arguments instead"))
|
||||
container_format = image_container
|
||||
|
||||
if image_args:
|
||||
LOG.warning(_("The 'kwargs' argument is deprecated since "
|
||||
"Rally 0.10.0; specify exact arguments instead"))
|
||||
|
||||
for user, tenant_id in rutils.iterate_per_tenants(
|
||||
self.context["users"]):
|
||||
@ -91,21 +144,9 @@ class ImageGenerator(context.Context):
|
||||
clients = osclients.Clients(
|
||||
user["credential"],
|
||||
api_info=self.context["config"].get("api_versions"))
|
||||
glance_wrap = glance_wrapper.wrap(clients.glance, self)
|
||||
|
||||
kwargs = self.config.get("image_args", {})
|
||||
if self.config.get("min_ram") is not None:
|
||||
LOG.warning("The 'min_ram' argument is deprecated; specify "
|
||||
"arbitrary arguments with 'image_args' instead")
|
||||
kwargs["min_ram"] = self.config["min_ram"]
|
||||
if self.config.get("min_disk") is not None:
|
||||
LOG.warning("The 'min_disk' argument is deprecated; specify "
|
||||
"arbitrary arguments with 'image_args' instead")
|
||||
kwargs["min_disk"] = self.config["min_disk"]
|
||||
if "is_public" in kwargs:
|
||||
LOG.warning("The 'is_public' argument is deprecated since "
|
||||
"Rally 0.8.0; specify visibility arguments "
|
||||
"instead")
|
||||
image_service = image.Image(
|
||||
clients,
|
||||
name_generator=self.generate_random_name)
|
||||
|
||||
for i in range(images_per_tenant):
|
||||
if image_name and i > 0:
|
||||
@ -115,10 +156,15 @@ class ImageGenerator(context.Context):
|
||||
else:
|
||||
cur_name = self.generate_random_name()
|
||||
|
||||
image = glance_wrap.create_image(
|
||||
image_container, image_url, image_type,
|
||||
name=cur_name, **kwargs)
|
||||
current_images.append(image.id)
|
||||
image_obj = image_service.create_image(
|
||||
image_name=cur_name,
|
||||
container_format=container_format,
|
||||
image_location=image_url,
|
||||
disk_format=disk_format,
|
||||
visibility=visibility,
|
||||
min_disk=min_disk,
|
||||
min_ram=min_ram)
|
||||
current_images.append(image_obj.id)
|
||||
|
||||
self.context["tenants"][tenant_id]["images"] = current_images
|
||||
|
||||
@ -129,14 +175,15 @@ class ImageGenerator(context.Context):
|
||||
clients = osclients.Clients(
|
||||
user["credential"],
|
||||
api_info=self.context["config"].get("api_versions"))
|
||||
glance_wrap = glance_wrapper.wrap(clients.glance, self)
|
||||
for image in self.context["tenants"][tenant_id].get("images", []):
|
||||
clients.glance().images.delete(image)
|
||||
image_service = image.Image(clients)
|
||||
for image_id in self.context["tenants"][tenant_id].get(
|
||||
"images", []):
|
||||
image_service.delete_image(image_id=image_id)
|
||||
utils.wait_for_status(
|
||||
clients.glance().images.get(image),
|
||||
image_service.get_image(image_id=image_id),
|
||||
["deleted", "pending_delete"],
|
||||
check_deletion=True,
|
||||
update_resource=glance_wrap.get_image,
|
||||
update_resource=image_service.get_image,
|
||||
timeout=CONF.benchmark.glance_image_delete_timeout,
|
||||
check_interval=CONF.benchmark.
|
||||
glance_image_delete_poll_interval)
|
||||
|
@ -16,8 +16,8 @@
|
||||
from rally.common import logging
|
||||
from rally import consts
|
||||
from rally.plugins.openstack import scenario
|
||||
from rally.plugins.openstack.scenarios.glance import utils
|
||||
from rally.plugins.openstack.scenarios.nova import utils as nova_utils
|
||||
from rally.plugins.openstack.services.image import image
|
||||
from rally.task import types
|
||||
from rally.task import validation
|
||||
|
||||
@ -26,13 +26,26 @@ LOG = logging.getLogger(__name__)
|
||||
"""Scenarios for Glance images."""
|
||||
|
||||
|
||||
class GlanceBasic(scenario.OpenStackScenario):
|
||||
def __init__(self, context=None, admin_clients=None, clients=None):
|
||||
super(GlanceBasic, self).__init__(context, admin_clients, clients)
|
||||
if hasattr(self, "_admin_clients"):
|
||||
self.admin_glance = image.Image(
|
||||
self._admin_clients, name_generator=self.generate_random_name,
|
||||
atomic_inst=self.atomic_actions())
|
||||
if hasattr(self, "_clients"):
|
||||
self.glance = image.Image(
|
||||
self._clients, name_generator=self.generate_random_name,
|
||||
atomic_inst=self.atomic_actions())
|
||||
|
||||
|
||||
@types.convert(image_location={"type": "path_or_url"},
|
||||
kwargs={"type": "glance_image_args"})
|
||||
@validation.required_services(consts.Service.GLANCE)
|
||||
@validation.required_openstack(users=True)
|
||||
@scenario.configure(context={"cleanup": ["glance"]},
|
||||
name="GlanceImages.create_and_list_image")
|
||||
class CreateAndListImage(utils.GlanceScenario, nova_utils.NovaScenario):
|
||||
class CreateAndListImage(GlanceBasic, nova_utils.NovaScenario):
|
||||
|
||||
def run(self, container_format, image_location, disk_format, **kwargs):
|
||||
"""Create an image and then list all images.
|
||||
@ -52,12 +65,13 @@ class CreateAndListImage(utils.GlanceScenario, nova_utils.NovaScenario):
|
||||
ami, ari, aki, vhd, vmdk, raw, qcow2, vdi, and iso
|
||||
:param kwargs: optional parameters to create image
|
||||
"""
|
||||
image = self._create_image(container_format,
|
||||
image_location,
|
||||
disk_format,
|
||||
**kwargs)
|
||||
image = self.glance.create_image(
|
||||
container_format=container_format,
|
||||
image_location=image_location,
|
||||
disk_format=disk_format,
|
||||
**kwargs)
|
||||
self.assertTrue(image)
|
||||
image_list = self._list_images()
|
||||
image_list = self.glance.list_images()
|
||||
self.assertIn(image.id, [i.id for i in image_list])
|
||||
|
||||
|
||||
@ -65,7 +79,7 @@ class CreateAndListImage(utils.GlanceScenario, nova_utils.NovaScenario):
|
||||
@validation.required_openstack(users=True)
|
||||
@scenario.configure(context={"cleanup": ["glance"]},
|
||||
name="GlanceImages.list_images")
|
||||
class ListImages(utils.GlanceScenario, nova_utils.NovaScenario):
|
||||
class ListImages(GlanceBasic, nova_utils.NovaScenario):
|
||||
|
||||
def run(self):
|
||||
"""List all images.
|
||||
@ -77,7 +91,7 @@ class ListImages(utils.GlanceScenario, nova_utils.NovaScenario):
|
||||
uploaded for them we will be able to test the performance of
|
||||
glance image-list command in this case.
|
||||
"""
|
||||
self._list_images()
|
||||
self.glance.list_images()
|
||||
|
||||
|
||||
@types.convert(image_location={"type": "path_or_url"},
|
||||
@ -86,7 +100,7 @@ class ListImages(utils.GlanceScenario, nova_utils.NovaScenario):
|
||||
@validation.required_openstack(users=True)
|
||||
@scenario.configure(context={"cleanup": ["glance"]},
|
||||
name="GlanceImages.create_and_delete_image")
|
||||
class CreateAndDeleteImage(utils.GlanceScenario, nova_utils.NovaScenario):
|
||||
class CreateAndDeleteImage(GlanceBasic, nova_utils.NovaScenario):
|
||||
|
||||
def run(self, container_format, image_location, disk_format, **kwargs):
|
||||
"""Create and then delete an image.
|
||||
@ -98,11 +112,12 @@ class CreateAndDeleteImage(utils.GlanceScenario, nova_utils.NovaScenario):
|
||||
ami, ari, aki, vhd, vmdk, raw, qcow2, vdi, and iso
|
||||
:param kwargs: optional parameters to create image
|
||||
"""
|
||||
image = self._create_image(container_format,
|
||||
image_location,
|
||||
disk_format,
|
||||
**kwargs)
|
||||
self._delete_image(image)
|
||||
image = self.glance.create_image(
|
||||
container_format=container_format,
|
||||
image_location=image_location,
|
||||
disk_format=disk_format,
|
||||
**kwargs)
|
||||
self.glance.delete_image(image.id)
|
||||
|
||||
|
||||
@types.convert(flavor={"type": "nova_flavor"},
|
||||
@ -113,8 +128,7 @@ class CreateAndDeleteImage(utils.GlanceScenario, nova_utils.NovaScenario):
|
||||
@validation.required_openstack(users=True)
|
||||
@scenario.configure(context={"cleanup": ["glance", "nova"]},
|
||||
name="GlanceImages.create_image_and_boot_instances")
|
||||
class CreateImageAndBootInstances(utils.GlanceScenario,
|
||||
nova_utils.NovaScenario):
|
||||
class CreateImageAndBootInstances(GlanceBasic, nova_utils.NovaScenario):
|
||||
|
||||
def run(self, container_format, image_location, disk_format,
|
||||
flavor, number_instances, create_image_kwargs=None,
|
||||
@ -140,9 +154,11 @@ class CreateImageAndBootInstances(utils.GlanceScenario,
|
||||
"'boot_server_kwargs' for additional parameters when "
|
||||
"booting servers.")
|
||||
|
||||
image = self._create_image(container_format,
|
||||
image_location,
|
||||
disk_format,
|
||||
**create_image_kwargs)
|
||||
image = self.glance.create_image(
|
||||
container_format=container_format,
|
||||
image_location=image_location,
|
||||
disk_format=disk_format,
|
||||
**create_image_kwargs)
|
||||
|
||||
self._boot_servers(image.id, flavor, number_instances,
|
||||
**boot_server_kwargs)
|
||||
|
0
rally/plugins/openstack/services/image/__init__.py
Normal file
0
rally/plugins/openstack/services/image/__init__.py
Normal file
193
rally/plugins/openstack/services/image/glance_v1.py
Normal file
193
rally/plugins/openstack/services/image/glance_v1.py
Normal file
@ -0,0 +1,193 @@
|
||||
# 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
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import os
|
||||
|
||||
from glanceclient import exc as glance_exc
|
||||
from oslo_config import cfg
|
||||
|
||||
from rally.common import utils as rutils
|
||||
from rally import exceptions
|
||||
from rally.plugins.openstack import service
|
||||
from rally.plugins.openstack.services.image import image
|
||||
from rally.task import atomic
|
||||
from rally.task import utils
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
||||
@service.service("glance", service_type="image", version="1")
|
||||
class GlanceV1Service(service.Service):
|
||||
|
||||
@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):
|
||||
"""Creates new image.
|
||||
|
||||
:param image_name: Image name for which need to be created
|
||||
:param container_format: Container format
|
||||
:param image_location: The new image's location
|
||||
:param disk_format: Disk format
|
||||
: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
|
||||
"""
|
||||
image_location = os.path.expanduser(image_location)
|
||||
image_name = image_name or self.generate_random_name()
|
||||
kwargs = {}
|
||||
|
||||
try:
|
||||
if os.path.isfile(image_location):
|
||||
kwargs["data"] = open(image_location)
|
||||
else:
|
||||
kwargs["copy_from"] = image_location
|
||||
|
||||
image_obj = self._clients.glance("1").images.create(
|
||||
name=image_name,
|
||||
container_format=container_format,
|
||||
disk_format=disk_format,
|
||||
is_public=is_public,
|
||||
min_disk=min_disk,
|
||||
min_ram=min_ram,
|
||||
**kwargs)
|
||||
|
||||
rutils.interruptable_sleep(CONF.benchmark.
|
||||
glance_image_create_prepoll_delay)
|
||||
|
||||
image_obj = utils.wait_for_status(
|
||||
image_obj, ["active"],
|
||||
update_resource=self.get_image,
|
||||
timeout=CONF.benchmark.glance_image_create_timeout,
|
||||
check_interval=CONF.benchmark.glance_image_create_poll_interval
|
||||
)
|
||||
|
||||
finally:
|
||||
if "data" in kwargs:
|
||||
kwargs["data"].close()
|
||||
|
||||
return image_obj
|
||||
|
||||
@atomic.action_timer("glance_v1.get_image")
|
||||
def get_image(self, image):
|
||||
"""Get specified image.
|
||||
|
||||
:param image: ID or object with ID of image to obtain.
|
||||
"""
|
||||
image_id = getattr(image, "id", image)
|
||||
try:
|
||||
return self._clients.glance("1").images.get(image_id)
|
||||
except glance_exc.HTTPNotFound:
|
||||
raise exceptions.GetResourceNotFound(resource=image)
|
||||
|
||||
@atomic.action_timer("glance_v1.list_images")
|
||||
def list_images(self, status="active", is_public=None):
|
||||
"""List images.
|
||||
|
||||
:param status: Filter in images for the specified status
|
||||
:param is_public: Filter in images for the specified public status
|
||||
"""
|
||||
images = self._clients.glance("1").images.list(status=status)
|
||||
if is_public in [True, False]:
|
||||
return [i for i in images if i.is_public is is_public]
|
||||
return images
|
||||
|
||||
@atomic.action_timer("glance_v1.set_visibility")
|
||||
def set_visibility(self, image_id, is_public=True):
|
||||
"""Update visibility.
|
||||
|
||||
:param image_id: ID of image to update
|
||||
:param is_public: Image is public or not
|
||||
"""
|
||||
self._clients.glance("1").images.update(image_id, is_public=is_public)
|
||||
|
||||
@atomic.action_timer("glance_v1.delete_image")
|
||||
def delete_image(self, image_id):
|
||||
"""Delete image."""
|
||||
self._clients.glance("1").images.delete(image_id)
|
||||
|
||||
|
||||
@service.compat_layer(GlanceV1Service)
|
||||
class UnifiedGlanceV1Service(image.Image):
|
||||
"""Compatibility layer for Glance V1."""
|
||||
|
||||
@staticmethod
|
||||
def _check_v1_visibility(visibility):
|
||||
visibility_values = ["public", "private"]
|
||||
if visibility and visibility not in visibility_values:
|
||||
raise image.VisibilityException("Improper visibility value: %s "
|
||||
"in glance_v1" % visibility)
|
||||
|
||||
def create_image(self, image_name=None, container_format=None,
|
||||
image_location=None, disk_format=None,
|
||||
visibility="public", min_disk=0,
|
||||
min_ram=0):
|
||||
"""Creates new image.
|
||||
|
||||
:param image_name: Image name for which need to be created
|
||||
:param container_format: Container format
|
||||
:param image_location: The new image's location
|
||||
:param disk_format: Disk format
|
||||
: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
|
||||
"""
|
||||
self._check_v1_visibility(visibility)
|
||||
|
||||
is_public = visibility != "private"
|
||||
image_obj = self._impl.create_image(
|
||||
image_name=image_name,
|
||||
container_format=container_format,
|
||||
image_location=image_location,
|
||||
disk_format=disk_format,
|
||||
is_public=is_public,
|
||||
min_disk=min_disk,
|
||||
min_ram=min_ram)
|
||||
return self._unify_image(image_obj)
|
||||
|
||||
def list_images(self, status="active", visibility=None):
|
||||
"""List images.
|
||||
|
||||
:param status: Filter in images for the specified status
|
||||
:param visibility: Filter in images for the specified visibility
|
||||
"""
|
||||
self._check_v1_visibility(visibility)
|
||||
|
||||
is_public = visibility != "private"
|
||||
|
||||
images = self._impl.list_images(status=status, is_public=is_public)
|
||||
return [self._unify_image(i) for i in images]
|
||||
|
||||
def set_visibility(self, image_id, visibility="public"):
|
||||
"""Update visibility.
|
||||
|
||||
:param image_id: ID of image to update
|
||||
:param visibility: The visibility of specified image
|
||||
"""
|
||||
self._check_v1_visibility(visibility)
|
||||
|
||||
is_public = visibility != "private"
|
||||
self._impl.set_visibility(image_id=image_id, is_public=is_public)
|
||||
|
||||
def get_image(self, image_id):
|
||||
"""Get specified image.
|
||||
|
||||
:param image_id: ID of image which need to be got.
|
||||
"""
|
||||
image_obj = self._impl.get_image(image_id=image_id)
|
||||
return self._unify_image(image_obj)
|
||||
|
||||
def delete_image(self, image_id):
|
||||
"""Delete image."""
|
||||
self._impl.delete_image(image_id=image_id)
|
202
rally/plugins/openstack/services/image/glance_v2.py
Normal file
202
rally/plugins/openstack/services/image/glance_v2.py
Normal file
@ -0,0 +1,202 @@
|
||||
# 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
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import os
|
||||
import time
|
||||
|
||||
from glanceclient import exc as glance_exc
|
||||
from oslo_config import cfg
|
||||
import requests
|
||||
|
||||
from rally.common import utils as rutils
|
||||
from rally import exceptions
|
||||
from rally.plugins.openstack import service
|
||||
from rally.plugins.openstack.services.image import image
|
||||
from rally.task import atomic
|
||||
from rally.task import utils
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
||||
@service.service("glance", service_type="image", version="2")
|
||||
class GlanceV2Service(service.Service):
|
||||
|
||||
@atomic.action_timer("glance_v2.create_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):
|
||||
"""Creates new image.
|
||||
|
||||
:param image_name: Image name for which need to be created
|
||||
:param container_format: Container format
|
||||
:param image_location: The new image's location
|
||||
:param disk_format: Disk format
|
||||
: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
|
||||
"""
|
||||
image_name = image_name or self.generate_random_name()
|
||||
|
||||
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)
|
||||
|
||||
image_location = os.path.expanduser(image_location)
|
||||
rutils.interruptable_sleep(CONF.benchmark.
|
||||
glance_image_create_prepoll_delay)
|
||||
|
||||
start = time.time()
|
||||
image_obj = utils.wait_for_status(
|
||||
image_obj.id, ["queued"],
|
||||
update_resource=self.get_image,
|
||||
timeout=CONF.benchmark.glance_image_create_timeout,
|
||||
check_interval=CONF.benchmark.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()
|
||||
|
||||
image_obj = utils.wait_for_status(
|
||||
image_obj, ["active"],
|
||||
update_resource=self.get_image,
|
||||
timeout=timeout,
|
||||
check_interval=CONF.benchmark.glance_image_create_poll_interval)
|
||||
return image_obj
|
||||
|
||||
@atomic.action_timer("glance_v2.get_image")
|
||||
def get_image(self, image):
|
||||
"""Get specified image.
|
||||
|
||||
:param image: ID or object with ID of image to obtain.
|
||||
"""
|
||||
image_id = getattr(image, "id", image)
|
||||
try:
|
||||
return self._clients.glance("2").images.get(image_id)
|
||||
except glance_exc.HTTPNotFound:
|
||||
raise exceptions.GetResourceNotFound(resource=image)
|
||||
|
||||
@atomic.action_timer("glance_v2.list_images")
|
||||
def list_images(self, status="active", visibility=None):
|
||||
"""List images.
|
||||
|
||||
:param status: Filter in images for the specified status
|
||||
:param visibility: Filter in images for the specified visibility
|
||||
"""
|
||||
kwargs = {}
|
||||
kwargs["status"] = status
|
||||
if visibility:
|
||||
kwargs["visibility"] = visibility
|
||||
images = self._clients.glance("2").images.list(**kwargs)
|
||||
return images
|
||||
|
||||
@atomic.action_timer("glance_v2.set_visibility")
|
||||
def set_visibility(self, image_id, visibility="shared"):
|
||||
"""Update visibility.
|
||||
|
||||
:param image_id: ID of image to update
|
||||
:param visibility: The visibility of specified image
|
||||
"""
|
||||
self._clients.glance("2").images.update(image_id,
|
||||
visibility=visibility)
|
||||
|
||||
@atomic.action_timer("glance_v2.delete_image")
|
||||
def delete_image(self, image_id):
|
||||
"""Delete image."""
|
||||
self._clients.glance("2").images.delete(image_id)
|
||||
|
||||
|
||||
@service.compat_layer(GlanceV2Service)
|
||||
class UnifiedGlanceV2Service(image.Image):
|
||||
"""Compatibility layer for Glance V2."""
|
||||
|
||||
@staticmethod
|
||||
def _check_v2_visibility(visibility):
|
||||
visibility_values = ["public", "private", "shared", "community"]
|
||||
if visibility and visibility not in visibility_values:
|
||||
raise image.VisibilityException("Improper visibility value: %s "
|
||||
"in glance_v2" % visibility)
|
||||
|
||||
def create_image(self, image_name=None, container_format=None,
|
||||
image_location=None, disk_format=None,
|
||||
visibility=None, min_disk=0,
|
||||
min_ram=0):
|
||||
"""Creates new image.
|
||||
|
||||
:param image_name: Image name for which need to be created
|
||||
:param container_format: Container format
|
||||
:param image_location: The new image's location
|
||||
:param disk_format: Disk format
|
||||
: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
|
||||
"""
|
||||
image_obj = self._impl.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)
|
||||
return self._unify_image(image_obj)
|
||||
|
||||
def list_images(self, status="active", visibility=None):
|
||||
"""List images.
|
||||
|
||||
:param status: Filter in images for the specified status
|
||||
:param visibility: Filter in images for the specified visibility
|
||||
"""
|
||||
self._check_v2_visibility(visibility)
|
||||
|
||||
images = self._impl.list_images(status=status, visibility=visibility)
|
||||
return [self._unify_image(i) for i in images]
|
||||
|
||||
def set_visibility(self, image_id, visibility="shared"):
|
||||
"""Update visibility.
|
||||
|
||||
:param image_id: ID of image to update
|
||||
:param visibility: The visibility of specified image
|
||||
"""
|
||||
self._check_v2_visibility(visibility)
|
||||
|
||||
self._impl.set_visibility(image_id=image_id, visibility=visibility)
|
||||
|
||||
def get_image(self, image_id):
|
||||
"""Get specified image.
|
||||
|
||||
:param image_id: ID of image which need to be got.
|
||||
"""
|
||||
image_obj = self._impl.get_image(image_id=image_id)
|
||||
return self._unify_image(image_obj)
|
||||
|
||||
def delete_image(self, image_id):
|
||||
"""Delete image."""
|
||||
self._impl.delete_image(image_id=image_id)
|
114
rally/plugins/openstack/services/image/image.py
Normal file
114
rally/plugins/openstack/services/image/image.py
Normal file
@ -0,0 +1,114 @@
|
||||
#
|
||||
# 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
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import collections
|
||||
|
||||
from rally.plugins.openstack import service
|
||||
|
||||
from oslo_config import cfg
|
||||
|
||||
GLANCE_BENCHMARK_OPTS = [
|
||||
cfg.FloatOpt("glance_image_create_prepoll_delay",
|
||||
default=2.0,
|
||||
help="Time to sleep after creating a resource before "
|
||||
"polling for it status"),
|
||||
cfg.FloatOpt("glance_image_create_poll_interval",
|
||||
default=1.0,
|
||||
help="Interval between checks when waiting for image "
|
||||
"creation.")
|
||||
]
|
||||
|
||||
CONF = cfg.CONF
|
||||
benchmark_group = cfg.OptGroup(name="benchmark", title="benchmark options")
|
||||
CONF.register_opts(GLANCE_BENCHMARK_OPTS, group=benchmark_group)
|
||||
|
||||
UnifiedImage = collections.namedtuple("Image", ["id", "name", "visibility"])
|
||||
|
||||
|
||||
class VisibilityException(Exception):
|
||||
"""Wrong visibility value exception.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
class Image(service.UnifiedOpenStackService):
|
||||
@classmethod
|
||||
def is_applicable(cls, clients):
|
||||
cloud_version = str(clients.glance().version).split(".")[0]
|
||||
return cloud_version == cls._meta_get("impl")._meta_get("version")
|
||||
|
||||
@staticmethod
|
||||
def _unify_image(image):
|
||||
if hasattr(image, "visibility"):
|
||||
return UnifiedImage(id=image.id, name=image.name,
|
||||
visibility=image.visibility)
|
||||
else:
|
||||
return UnifiedImage(
|
||||
id=image.id, name=image.name,
|
||||
visibility=("public" if image.is_public else "private"))
|
||||
|
||||
@service.should_be_overridden
|
||||
def create_image(self, image_name=None, container_format=None,
|
||||
image_location=None, disk_format=None,
|
||||
visibility="private", min_disk=0,
|
||||
min_ram=0):
|
||||
"""Creates new image.
|
||||
|
||||
:param image_name: Image name for which need to be created
|
||||
:param container_format: Container format
|
||||
:param image_location: The new image's location
|
||||
:param disk_format: Disk format
|
||||
: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
|
||||
"""
|
||||
image = self._impl.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)
|
||||
return image
|
||||
|
||||
@service.should_be_overridden
|
||||
def list_images(self, status="active", visibility=None):
|
||||
"""List images.
|
||||
|
||||
:param status: Filter in images for the specified status
|
||||
:param visibility: Filter in images for the specified visibility
|
||||
"""
|
||||
return self._impl.list_images(status=status, visibility=visibility)
|
||||
|
||||
@service.should_be_overridden
|
||||
def set_visibility(self, image_id, visibility="public"):
|
||||
"""Update visibility.
|
||||
|
||||
:param image_id: ID of image to update
|
||||
:param visibility: The visibility of specified image
|
||||
"""
|
||||
self._impl.set_visibility(image_id, visibility=visibility)
|
||||
|
||||
@service.should_be_overridden
|
||||
def get_image(self, image):
|
||||
"""Get specified image.
|
||||
|
||||
:param image: ID or object with ID of image to obtain.
|
||||
"""
|
||||
return self._impl.get_image(image)
|
||||
|
||||
@service.should_be_overridden
|
||||
def delete_image(self, image_id):
|
||||
"""delete image."""
|
||||
self._impl.delete_image(image_id)
|
@ -13,8 +13,8 @@
|
||||
},
|
||||
"images": {
|
||||
"image_url": "http://download.cirros-cloud.net/0.3.5/cirros-0.3.5-x86_64-disk.img",
|
||||
"image_type": "qcow2",
|
||||
"image_container": "bare",
|
||||
"disk_format": "qcow2",
|
||||
"container_format": "bare",
|
||||
"images_per_tenant": 4
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,6 @@
|
||||
users_per_tenant: 2
|
||||
images:
|
||||
image_url: "http://download.cirros-cloud.net/0.3.5/cirros-0.3.5-x86_64-disk.img"
|
||||
image_type: "qcow2"
|
||||
image_container: "bare"
|
||||
disk_format: "qcow2"
|
||||
container_format: "bare"
|
||||
images_per_tenant: 4
|
||||
|
@ -29,6 +29,30 @@ SCN = "rally.plugins.openstack.scenarios.glance"
|
||||
@ddt.ddt
|
||||
class ImageGeneratorTestCase(test.ScenarioTestCase):
|
||||
|
||||
tenants_num = 1
|
||||
users_per_tenant = 5
|
||||
users_num = tenants_num * users_per_tenant
|
||||
threads = 10
|
||||
|
||||
def setUp(self):
|
||||
super(ImageGeneratorTestCase, self).setUp()
|
||||
self.context.update({
|
||||
"config": {
|
||||
"users": {
|
||||
"tenants": self.tenants_num,
|
||||
"users_per_tenant": self.users_per_tenant,
|
||||
"resource_management_workers": self.threads,
|
||||
}
|
||||
},
|
||||
"admin": {"credential": mock.MagicMock()},
|
||||
"users": [],
|
||||
"task": {"uuid": "task_id"}
|
||||
})
|
||||
patch = mock.patch(
|
||||
"rally.plugins.openstack.services.image.image.Image")
|
||||
self.addCleanup(patch.stop)
|
||||
self.mock_image = patch.start()
|
||||
|
||||
def _gen_tenants(self, count):
|
||||
tenants = {}
|
||||
for id_ in range(count):
|
||||
@ -50,17 +74,18 @@ class ImageGeneratorTestCase(test.ScenarioTestCase):
|
||||
{"min_disk": 1, "min_ram": 2},
|
||||
{"image_name": "foo"},
|
||||
{"tenants": 3, "users_per_tenant": 2, "images_per_tenant": 5},
|
||||
{"image_args": {"min_disk": 1, "min_ram": 2, "visibility": "public"}},
|
||||
{"api_versions": {"glance": {"version": 2, "service_type": "image"}}})
|
||||
@ddt.unpack
|
||||
@mock.patch("rally.plugins.openstack.wrappers.glance.wrap")
|
||||
@mock.patch("rally.osclients.Clients")
|
||||
def test_setup(self, mock_clients, mock_wrap,
|
||||
image_container="bare", image_type="qcow2",
|
||||
def test_setup(self, mock_clients,
|
||||
container_format="bare", disk_format="qcow2",
|
||||
image_url="http://example.com/fake/url",
|
||||
tenants=1, users_per_tenant=1, images_per_tenant=1,
|
||||
image_name=None, min_ram=None, min_disk=None,
|
||||
image_args=None, api_versions=None):
|
||||
image_args={"is_public": True}, api_versions=None,
|
||||
visibility="public"):
|
||||
image_service = self.mock_image.return_value
|
||||
|
||||
tenant_data = self._gen_tenants(tenants)
|
||||
users = []
|
||||
for tenant_id in tenant_data:
|
||||
@ -77,9 +102,14 @@ class ImageGeneratorTestCase(test.ScenarioTestCase):
|
||||
},
|
||||
"images": {
|
||||
"image_url": image_url,
|
||||
"image_type": image_type,
|
||||
"image_container": image_container,
|
||||
"image_type": disk_format,
|
||||
"disk_format": disk_format,
|
||||
"image_container": container_format,
|
||||
"container_format": container_format,
|
||||
"images_per_tenant": images_per_tenant,
|
||||
"is_public": visibility,
|
||||
"visibility": visibility,
|
||||
"image_args": image_args
|
||||
}
|
||||
},
|
||||
"admin": {
|
||||
@ -104,12 +134,10 @@ class ImageGeneratorTestCase(test.ScenarioTestCase):
|
||||
self.context["config"]["images"]["min_disk"] = min_disk
|
||||
expected_image_args["min_disk"] = min_disk
|
||||
|
||||
wrapper = mock_wrap.return_value
|
||||
|
||||
new_context = copy.deepcopy(self.context)
|
||||
for tenant_id in new_context["tenants"].keys():
|
||||
new_context["tenants"][tenant_id]["images"] = [
|
||||
wrapper.create_image.return_value.id
|
||||
image_service.create_image.return_value.id
|
||||
] * images_per_tenant
|
||||
|
||||
images_ctx = images.ImageGenerator(self.context)
|
||||
@ -121,14 +149,10 @@ class ImageGeneratorTestCase(test.ScenarioTestCase):
|
||||
images_ctx)] * tenants)
|
||||
wrapper_calls.extend(
|
||||
[mock.call().create_image(
|
||||
image_container, image_url, image_type,
|
||||
container_format, image_url, disk_format,
|
||||
name=mock.ANY, **expected_image_args)] *
|
||||
tenants * images_per_tenant)
|
||||
mock_wrap.assert_has_calls(wrapper_calls, any_order=True)
|
||||
|
||||
if image_name:
|
||||
for args in wrapper.create_image.call_args_list:
|
||||
self.assertTrue(args[1]["name"].startswith(image_name))
|
||||
mock_clients.assert_has_calls(
|
||||
[mock.call(mock.ANY, api_info=api_versions)] * tenants)
|
||||
|
||||
@ -136,18 +160,16 @@ class ImageGeneratorTestCase(test.ScenarioTestCase):
|
||||
{},
|
||||
{"api_versions": {"glance": {"version": 2, "service_type": "image"}}})
|
||||
@ddt.unpack
|
||||
@mock.patch("rally.plugins.openstack.wrappers.glance.wrap")
|
||||
@mock.patch("rally.osclients.Clients")
|
||||
def test_cleanup(self, mock_clients, mock_wrap, api_versions=None):
|
||||
tenants_count = 2
|
||||
users_per_tenant = 5
|
||||
def test_cleanup(self, api_versions=None):
|
||||
image_service = self.mock_image.return_value
|
||||
|
||||
images_per_tenant = 5
|
||||
|
||||
tenants = self._gen_tenants(tenants_count)
|
||||
tenants = self._gen_tenants(self.tenants_num)
|
||||
users = []
|
||||
created_images = []
|
||||
for tenant_id in tenants:
|
||||
for i in range(users_per_tenant):
|
||||
for i in range(self.users_per_tenant):
|
||||
users.append({"id": i, "tenant_id": tenant_id,
|
||||
"credential": mock.MagicMock()})
|
||||
tenants[tenant_id].setdefault("images", [])
|
||||
@ -159,8 +181,8 @@ class ImageGeneratorTestCase(test.ScenarioTestCase):
|
||||
self.context.update({
|
||||
"config": {
|
||||
"users": {
|
||||
"tenants": tenants_count,
|
||||
"users_per_tenant": users_per_tenant,
|
||||
"tenants": self.tenants_num,
|
||||
"users_per_tenant": self.users_per_tenant,
|
||||
"concurrent": 10,
|
||||
},
|
||||
"images": {
|
||||
@ -184,18 +206,4 @@ class ImageGeneratorTestCase(test.ScenarioTestCase):
|
||||
|
||||
images_ctx = images.ImageGenerator(self.context)
|
||||
images_ctx.cleanup()
|
||||
|
||||
wrapper_calls = []
|
||||
wrapper_calls.extend([mock.call(mock_clients.return_value.glance,
|
||||
images_ctx)] * tenants_count)
|
||||
mock_wrap.assert_has_calls(wrapper_calls, any_order=True)
|
||||
|
||||
glance_client = mock_clients.return_value.glance.return_value
|
||||
glance_client.images.delete.assert_has_calls([mock.call(i)
|
||||
for i in created_images])
|
||||
glance_client.images.get.assert_has_calls([mock.call(i)
|
||||
for i in created_images])
|
||||
|
||||
mock_clients.assert_has_calls(
|
||||
[mock.call(mock.ANY, api_info=api_versions)] * tenants_count,
|
||||
any_order=True)
|
||||
image_service.delete_image.assert_has_calls([])
|
||||
|
@ -23,87 +23,106 @@ from tests.unit import test
|
||||
BASE = "rally.plugins.openstack.scenarios.glance.images"
|
||||
|
||||
|
||||
class GlanceImagesTestCase(test.ScenarioTestCase):
|
||||
class GlanceBasicTestCase(test.ScenarioTestCase):
|
||||
|
||||
@mock.patch("%s.CreateAndListImage._list_images" % BASE)
|
||||
@mock.patch("%s.CreateAndListImage._create_image" % BASE)
|
||||
def test_create_and_list_image(self,
|
||||
mock_create_image,
|
||||
mock_list_images):
|
||||
def get_test_context(self):
|
||||
context = super(GlanceBasicTestCase, self).get_test_context()
|
||||
context.update({
|
||||
"admin": {
|
||||
"id": "fake_user_id",
|
||||
"credential": mock.MagicMock()
|
||||
},
|
||||
"user": {
|
||||
"id": "fake_user_id",
|
||||
"credential": mock.MagicMock()
|
||||
},
|
||||
"tenant": {"id": "fake_tenant_id",
|
||||
"name": "fake_tenant_name"}
|
||||
})
|
||||
return context
|
||||
|
||||
fake_image = fakes.FakeImage(id=1, name="img_name1")
|
||||
mock_create_image.return_value = fake_image
|
||||
mock_list_images.return_value = [
|
||||
fakes.FakeImage(id=0, name="img_name1"),
|
||||
def setUp(self):
|
||||
super(GlanceBasicTestCase, self).setUp()
|
||||
patch = mock.patch(
|
||||
"rally.plugins.openstack.services.image.image.Image")
|
||||
self.addCleanup(patch.stop)
|
||||
self.mock_image = patch.start()
|
||||
|
||||
def test_create_and_list_image(self):
|
||||
image_service = self.mock_image.return_value
|
||||
fake_image = mock.Mock(id=1, name="img_2")
|
||||
image_service.create_image.return_value = fake_image
|
||||
image_service.list_images.return_value = [
|
||||
mock.Mock(id=0, name="img_1"),
|
||||
fake_image,
|
||||
fakes.FakeImage(id=2, name="img_name1")
|
||||
]
|
||||
mock.Mock(id=2, name="img_3")]
|
||||
call_args = {"container_format": "cf",
|
||||
"image_location": "url",
|
||||
"disk_format": "df",
|
||||
"fakearg": "f"}
|
||||
|
||||
# Positive case
|
||||
images.CreateAndListImage(self.context).run(
|
||||
"cf", "url", "df", fakearg="f")
|
||||
mock_create_image.assert_called_once_with(
|
||||
"cf", "url", "df", fakearg="f")
|
||||
mock_list_images.assert_called_once_with()
|
||||
image_service.create_image.assert_called_once_with(**call_args)
|
||||
|
||||
# Negative case: image isn't created
|
||||
mock_create_image.return_value = None
|
||||
image_service.create_image.return_value = None
|
||||
self.assertRaises(exceptions.RallyAssertionError,
|
||||
images.CreateAndListImage(self.context).run,
|
||||
"cf", "url", "df", fakearg="f")
|
||||
mock_create_image.assert_called_with(
|
||||
"cf", "url", "df", fakearg="f")
|
||||
image_service.create_image.assert_called_with(**call_args)
|
||||
|
||||
# Negative case: created image n ot in the list of available images
|
||||
mock_create_image.return_value = fakes.FakeImage(
|
||||
image_service.create_image.return_value = mock.Mock(
|
||||
id=12, name="img_nameN")
|
||||
self.assertRaises(exceptions.RallyAssertionError,
|
||||
images.CreateAndListImage(self.context).run,
|
||||
"cf", "url", "df", fakearg="f")
|
||||
mock_create_image.assert_called_with(
|
||||
"cf", "url", "df", fakearg="f")
|
||||
mock_list_images.assert_called_with()
|
||||
image_service.create_image.assert_called_with(**call_args)
|
||||
image_service.list_images.assert_called_with()
|
||||
|
||||
def test_list_images(self):
|
||||
image_service = self.mock_image.return_value
|
||||
|
||||
@mock.patch("%s.ListImages._list_images" % BASE)
|
||||
def test_list_images(self, mock_list_images__list_images):
|
||||
images.ListImages(self.context).run()
|
||||
mock_list_images__list_images.assert_called_once_with()
|
||||
image_service.list_images.assert_called_once_with()
|
||||
|
||||
@mock.patch("%s.CreateAndDeleteImage._delete_image" % BASE)
|
||||
@mock.patch("%s.CreateAndDeleteImage._create_image" % BASE)
|
||||
@mock.patch("%s.CreateAndDeleteImage.generate_random_name" % BASE,
|
||||
return_value="test-rally-image")
|
||||
def test_create_and_delete_image(self,
|
||||
mock_random_name,
|
||||
mock_create_image,
|
||||
mock_delete_image):
|
||||
fake_image = object()
|
||||
mock_create_image.return_value = fake_image
|
||||
def test_create_and_delete_image(self):
|
||||
image_service = self.mock_image.return_value
|
||||
|
||||
fake_image = fakes.FakeImage(id=1, name="imagexxx")
|
||||
image_service.create_image.return_value = fake_image
|
||||
call_args = {"container_format": "cf",
|
||||
"image_location": "url",
|
||||
"disk_format": "df",
|
||||
"fakearg": "f"}
|
||||
|
||||
images.CreateAndDeleteImage(self.context).run(
|
||||
"cf", "url", "df", fakearg="f")
|
||||
|
||||
mock_create_image.assert_called_once_with(
|
||||
"cf", "url", "df", fakearg="f")
|
||||
mock_delete_image.assert_called_once_with(fake_image)
|
||||
image_service.create_image.assert_called_once_with(**call_args)
|
||||
image_service.delete_image.assert_called_once_with(fake_image.id)
|
||||
|
||||
@mock.patch("%s.CreateImageAndBootInstances._boot_servers" % BASE)
|
||||
@mock.patch("%s.CreateImageAndBootInstances._create_image" % BASE)
|
||||
def test_create_image_and_boot_instances(self,
|
||||
mock_create_image,
|
||||
mock_boot_servers):
|
||||
def test_create_image_and_boot_instances(self, mock_boot_servers):
|
||||
image_service = self.mock_image.return_value
|
||||
|
||||
fake_image = fakes.FakeImage()
|
||||
fake_servers = [mock.Mock() for i in range(5)]
|
||||
mock_create_image.return_value = fake_image
|
||||
image_service.create_image.return_value = fake_image
|
||||
mock_boot_servers.return_value = fake_servers
|
||||
create_image_kwargs = {"fakeimagearg": "f"}
|
||||
boot_server_kwargs = {"fakeserverarg": "f"}
|
||||
call_args = {"container_format": "cf",
|
||||
"image_location": "url",
|
||||
"disk_format": "df",
|
||||
"fakeimagearg": "f"}
|
||||
|
||||
images.CreateImageAndBootInstances(self.context).run(
|
||||
"cf", "url", "df", "fid", 5,
|
||||
create_image_kwargs=create_image_kwargs,
|
||||
boot_server_kwargs=boot_server_kwargs)
|
||||
mock_create_image.assert_called_once_with("cf", "url", "df",
|
||||
**create_image_kwargs)
|
||||
image_service.create_image.assert_called_once_with(**call_args)
|
||||
mock_boot_servers.assert_called_once_with("image-id-0", "fid",
|
||||
5, **boot_server_kwargs)
|
||||
|
191
tests/unit/plugins/openstack/services/image/test_glance_v1.py
Executable file
191
tests/unit/plugins/openstack/services/image/test_glance_v1.py
Executable file
@ -0,0 +1,191 @@
|
||||
# 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
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import tempfile
|
||||
|
||||
import ddt
|
||||
from glanceclient import exc as glance_exc
|
||||
import mock
|
||||
|
||||
from rally import exceptions
|
||||
from rally.plugins.openstack.services.image import glance_v1
|
||||
from rally.plugins.openstack.services.image import image
|
||||
from tests.unit import test
|
||||
|
||||
from oslotest import mockpatch
|
||||
|
||||
PATH = "rally.plugins.openstack.services.image.image.Image._unify_image"
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class GlanceV1ServiceTestCase(test.TestCase):
|
||||
_tempfile = tempfile.NamedTemporaryFile()
|
||||
|
||||
def setUp(self):
|
||||
super(GlanceV1ServiceTestCase, self).setUp()
|
||||
self.clients = mock.MagicMock()
|
||||
self.gc = self.clients.glance.return_value
|
||||
self.name_generator = mock.MagicMock()
|
||||
self.service = glance_v1.GlanceV1Service(
|
||||
self.clients, name_generator=self.name_generator)
|
||||
self.mock_wait_for_status = mockpatch.Patch(
|
||||
"rally.task.utils.wait_for_status")
|
||||
self.useFixture(self.mock_wait_for_status)
|
||||
|
||||
@ddt.data({"location": "image_location", "is_public": True},
|
||||
{"location": _tempfile.name, "is_public": False})
|
||||
@ddt.unpack
|
||||
@mock.patch("six.moves.builtins.open")
|
||||
def test_create_image(self, mock_open, location, is_public):
|
||||
image_name = "image_name"
|
||||
container_format = "container_format"
|
||||
disk_format = "disk_format"
|
||||
|
||||
image = self.service.create_image(
|
||||
image_name=image_name,
|
||||
container_format=container_format,
|
||||
image_location=location,
|
||||
disk_format=disk_format,
|
||||
is_public=is_public)
|
||||
|
||||
call_args = {"container_format": container_format,
|
||||
"disk_format": disk_format,
|
||||
"is_public": is_public,
|
||||
"name": image_name,
|
||||
"min_disk": 0,
|
||||
"min_ram": 0}
|
||||
|
||||
if location.startswith("/"):
|
||||
call_args["data"] = mock_open.return_value
|
||||
mock_open.assert_called_once_with(location)
|
||||
mock_open.return_value.close.assert_called_once_with()
|
||||
else:
|
||||
call_args["copy_from"] = location
|
||||
|
||||
self.gc.images.create.assert_called_once_with(**call_args)
|
||||
self.assertEqual(image, self.mock_wait_for_status.mock.return_value)
|
||||
|
||||
def test_get_image(self):
|
||||
image_id = "image_id"
|
||||
self.service.get_image(image_id)
|
||||
self.gc.images.get.assert_called_once_with(image_id)
|
||||
|
||||
def test_get_image_exception(self):
|
||||
image_id = "image_id"
|
||||
self.clients.glance(
|
||||
"1").images.get.side_effect = glance_exc.HTTPNotFound
|
||||
|
||||
self.assertRaises(exceptions.GetResourceNotFound,
|
||||
self.service.get_image, image_id)
|
||||
|
||||
@ddt.data({"status": "activate", "is_public": True},
|
||||
{"status": "activate", "is_public": False},
|
||||
{"status": "activate", "is_public": None})
|
||||
@ddt.unpack
|
||||
def test_list_images(self, status, is_public):
|
||||
self.service.list_images(is_public=is_public, status=status)
|
||||
self.gc.images.list.assert_called_once_with(status=status)
|
||||
|
||||
def test_set_visibility(self):
|
||||
image_id = "image_id"
|
||||
is_public = True
|
||||
self.service.set_visibility(image_id=image_id)
|
||||
self.gc.images.update.assert_called_once_with(
|
||||
image_id, is_public=is_public)
|
||||
|
||||
def test_delete_image(self):
|
||||
image_id = "image_id"
|
||||
self.service.delete_image(image_id)
|
||||
self.gc.images.delete.assert_called_once_with(image_id)
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class UnifiedGlanceV1ServiceTestCase(test.TestCase):
|
||||
def setUp(self):
|
||||
super(UnifiedGlanceV1ServiceTestCase, self).setUp()
|
||||
self.clients = mock.MagicMock()
|
||||
self.service = glance_v1.UnifiedGlanceV1Service(self.clients)
|
||||
self.service._impl = mock.MagicMock()
|
||||
|
||||
@ddt.data({"visibility": "public"},
|
||||
{"visibility": "private"})
|
||||
@ddt.unpack
|
||||
@mock.patch(PATH)
|
||||
def test_create_image(self, mock_image__unify_image, visibility):
|
||||
image_name = "image_name"
|
||||
container_format = "container_format"
|
||||
image_location = "image_location"
|
||||
disk_format = "disk_format"
|
||||
image = self.service.create_image(image_name=image_name,
|
||||
container_format=container_format,
|
||||
image_location=image_location,
|
||||
disk_format=disk_format,
|
||||
visibility=visibility)
|
||||
|
||||
is_public = visibility == "public"
|
||||
callargs = {"image_name": image_name,
|
||||
"container_format": container_format,
|
||||
"image_location": image_location,
|
||||
"disk_format": disk_format,
|
||||
"is_public": is_public,
|
||||
"min_disk": 0,
|
||||
"min_ram": 0}
|
||||
self.service._impl.create_image.assert_called_once_with(**callargs)
|
||||
self.assertEqual(mock_image__unify_image.return_value, image)
|
||||
|
||||
@mock.patch(PATH)
|
||||
def test_get_image(self, mock_image__unify_image):
|
||||
image_id = "image_id"
|
||||
image = self.service.get_image(image_id=image_id)
|
||||
|
||||
self.assertEqual(mock_image__unify_image.return_value, image)
|
||||
self.service._impl.get_image.assert_called_once_with(
|
||||
image_id=image_id)
|
||||
|
||||
@mock.patch(PATH)
|
||||
def test_list_images(self, mock_image__unify_image):
|
||||
images = [mock.MagicMock()]
|
||||
self.service._impl.list_images.return_value = images
|
||||
|
||||
status = "active"
|
||||
visibility = "public"
|
||||
is_public = visibility == "public"
|
||||
self.assertEqual([mock_image__unify_image.return_value],
|
||||
self.service.list_images(status,
|
||||
visibility=visibility))
|
||||
self.service._impl.list_images.assert_called_once_with(
|
||||
status=status,
|
||||
is_public=is_public)
|
||||
|
||||
def test_set_visibility(self):
|
||||
image_id = "image_id"
|
||||
visibility = "private"
|
||||
is_public = visibility == "public"
|
||||
self.service.set_visibility(image_id=image_id, visibility=visibility)
|
||||
self.service._impl.set_visibility.assert_called_once_with(
|
||||
image_id=image_id, is_public=is_public)
|
||||
|
||||
def test_set_visibility_failure(self):
|
||||
image_id = "image_id"
|
||||
visibility = "error"
|
||||
self.assertRaises(image.VisibilityException,
|
||||
self.service.set_visibility,
|
||||
image_id=image_id,
|
||||
visibility=visibility)
|
||||
|
||||
def test_delete_image(self):
|
||||
image_id = "image_id"
|
||||
self.service.delete_image(image_id)
|
||||
self.service._impl.delete_image.assert_called_once_with(
|
||||
image_id=image_id)
|
178
tests/unit/plugins/openstack/services/image/test_glance_v2.py
Executable file
178
tests/unit/plugins/openstack/services/image/test_glance_v2.py
Executable file
@ -0,0 +1,178 @@
|
||||
# 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
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import tempfile
|
||||
|
||||
import ddt
|
||||
from glanceclient import exc as glance_exc
|
||||
import mock
|
||||
|
||||
from rally import exceptions
|
||||
from rally.plugins.openstack.services.image import glance_v2
|
||||
from tests.unit import test
|
||||
|
||||
from oslotest import mockpatch
|
||||
|
||||
PATH = "rally.plugins.openstack.services.image.image.Image._unify_image"
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class GlanceV2ServiceTestCase(test.TestCase):
|
||||
_tempfile = tempfile.NamedTemporaryFile()
|
||||
|
||||
def setUp(self):
|
||||
super(GlanceV2ServiceTestCase, self).setUp()
|
||||
self.clients = mock.MagicMock()
|
||||
self.gc = self.clients.glance.return_value
|
||||
self.name_generator = mock.MagicMock()
|
||||
self.service = glance_v2.GlanceV2Service(
|
||||
self.clients, name_generator=self.name_generator)
|
||||
self.mock_wait_for_status = mockpatch.Patch(
|
||||
"rally.task.utils.wait_for_status")
|
||||
self.useFixture(self.mock_wait_for_status)
|
||||
|
||||
@ddt.data({"location": "image_location"},
|
||||
{"location": _tempfile.name})
|
||||
@ddt.unpack
|
||||
@mock.patch("requests.get")
|
||||
@mock.patch("six.moves.builtins.open")
|
||||
def test_create_image(self, mock_open, mock_requests_get, location):
|
||||
image_name = "image_name"
|
||||
container_format = "container_format"
|
||||
disk_format = "disk_format"
|
||||
visibility = "public"
|
||||
|
||||
image = self.service.create_image(
|
||||
image_name=image_name,
|
||||
container_format=container_format,
|
||||
image_location=location,
|
||||
disk_format=disk_format,
|
||||
visibility=visibility)
|
||||
|
||||
call_args = {"container_format": container_format,
|
||||
"disk_format": disk_format,
|
||||
"name": image_name,
|
||||
"visibility": visibility,
|
||||
"min_disk": 0,
|
||||
"min_ram": 0}
|
||||
|
||||
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)
|
||||
|
||||
def test_get_image(self):
|
||||
image_id = "image_id"
|
||||
self.service.get_image(image_id)
|
||||
self.gc.images.get.assert_called_once_with(image_id)
|
||||
|
||||
def test_get_image_exception(self):
|
||||
image_id = "image_id"
|
||||
self.clients.glance(
|
||||
"1").images.get.side_effect = glance_exc.HTTPNotFound
|
||||
|
||||
self.assertRaises(exceptions.GetResourceNotFound,
|
||||
self.service.get_image, image_id)
|
||||
|
||||
def test_list_images(self):
|
||||
status = "active"
|
||||
kwargs = {"status": status}
|
||||
|
||||
self.assertEqual(self.gc.images.list.return_value,
|
||||
self.service.list_images())
|
||||
self.gc.images.list.assert_called_once_with(**kwargs)
|
||||
|
||||
def test_set_visibility(self):
|
||||
image_id = "image_id"
|
||||
visibility = "shared"
|
||||
self.service.set_visibility(image_id=image_id)
|
||||
self.gc.images.update.assert_called_once_with(
|
||||
image_id,
|
||||
visibility=visibility)
|
||||
|
||||
def test_delete_image(self):
|
||||
image_id = "image_id"
|
||||
self.service.delete_image(image_id)
|
||||
self.gc.images.delete.assert_called_once_with(image_id)
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class UnifiedGlanceV2ServiceTestCase(test.TestCase):
|
||||
def setUp(self):
|
||||
super(UnifiedGlanceV2ServiceTestCase, self).setUp()
|
||||
self.clients = mock.MagicMock()
|
||||
self.service = glance_v2.UnifiedGlanceV2Service(self.clients)
|
||||
self.service._impl = mock.MagicMock()
|
||||
|
||||
@mock.patch(PATH)
|
||||
def test_create_image(self, mock_image__unify_image):
|
||||
image_name = "image_name"
|
||||
container_format = "container_format"
|
||||
image_location = "image_location"
|
||||
disk_format = "disk_format"
|
||||
visibility = "public"
|
||||
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}
|
||||
|
||||
image = self.service.create_image(image_name=image_name,
|
||||
container_format=container_format,
|
||||
image_location=image_location,
|
||||
disk_format=disk_format,
|
||||
visibility=visibility)
|
||||
|
||||
self.assertEqual(mock_image__unify_image.return_value, image)
|
||||
self.service._impl.create_image.assert_called_once_with(**callargs)
|
||||
|
||||
@mock.patch(PATH)
|
||||
def test_get_image(self, mock_image__unify_image):
|
||||
image_id = "image_id"
|
||||
image = self.service.get_image(image_id=image_id)
|
||||
|
||||
self.assertEqual(mock_image__unify_image.return_value, image)
|
||||
self.service._impl.get_image.assert_called_once_with(
|
||||
image_id=image_id)
|
||||
|
||||
@mock.patch(PATH)
|
||||
def test_list_images(self, mock_image__unify_image):
|
||||
images = [mock.MagicMock()]
|
||||
self.service._impl.list_images.return_value = images
|
||||
|
||||
status = "active"
|
||||
self.assertEqual([mock_image__unify_image.return_value],
|
||||
self.service.list_images())
|
||||
self.service._impl.list_images.assert_called_once_with(
|
||||
status=status,
|
||||
visibility=None)
|
||||
|
||||
def test_set_visibility(self):
|
||||
image_id = "image_id"
|
||||
visibility = "private"
|
||||
|
||||
self.service.set_visibility(image_id=image_id, visibility=visibility)
|
||||
self.service._impl.set_visibility.assert_called_once_with(
|
||||
image_id=image_id, visibility=visibility)
|
||||
|
||||
def test_delete_image(self):
|
||||
image_id = "image_id"
|
||||
self.service.delete_image(image_id)
|
||||
self.service._impl.delete_image.assert_called_once_with(
|
||||
image_id=image_id)
|
118
tests/unit/plugins/openstack/services/image/test_image.py
Executable file
118
tests/unit/plugins/openstack/services/image/test_image.py
Executable file
@ -0,0 +1,118 @@
|
||||
# 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
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import uuid
|
||||
|
||||
import ddt
|
||||
import mock
|
||||
|
||||
from rally.plugins.openstack.services.image import glance_v1
|
||||
from rally.plugins.openstack.services.image import glance_v2
|
||||
from rally.plugins.openstack.services.image import image
|
||||
from tests.unit import test
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class ImageTestCase(test.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(ImageTestCase, self).setUp()
|
||||
self.clients = mock.MagicMock()
|
||||
|
||||
def get_service_with_fake_impl(self):
|
||||
path = "rally.plugins.openstack.services.image.image"
|
||||
with mock.patch("%s.Image.discover_impl" % path) as mock_discover:
|
||||
mock_discover.return_value = mock.MagicMock(), None
|
||||
service = image.Image(self.clients)
|
||||
return service
|
||||
|
||||
@ddt.data(("image_name", "container_format", "image_location",
|
||||
"disk_format", "visibility", "min_disk", "min_ram"))
|
||||
def test_create_image(self, params):
|
||||
(image_name, container_format, image_location, disk_format,
|
||||
visibility, min_disk, min_ram) = params
|
||||
service = self.get_service_with_fake_impl()
|
||||
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)
|
||||
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)
|
||||
|
||||
@ddt.data("image_id")
|
||||
def test_get_image(self, param):
|
||||
image_id = param
|
||||
service = self.get_service_with_fake_impl()
|
||||
service.get_image(image=image_id)
|
||||
service._impl.get_image.assert_called_once_with(image_id)
|
||||
|
||||
@ddt.data(("status", "visibility"))
|
||||
def test_list_images(self, params):
|
||||
status, visibility = params
|
||||
service = self.get_service_with_fake_impl()
|
||||
service.list_images(status=status, visibility=visibility)
|
||||
service._impl.list_images.assert_called_once_with(
|
||||
status=status, visibility=visibility)
|
||||
|
||||
@ddt.data(("image_id", "visibility"))
|
||||
def test_set_visibility(self, params):
|
||||
image_id, visibility = params
|
||||
service = self.get_service_with_fake_impl()
|
||||
service.set_visibility(image_id=image_id, visibility=visibility)
|
||||
service._impl.set_visibility.assert_called_once_with(
|
||||
image_id, visibility=visibility)
|
||||
|
||||
def test_unify_image(self):
|
||||
class Image(object):
|
||||
def __init__(self, visibility=None, is_public=None):
|
||||
self.id = uuid.uuid4()
|
||||
self.name = str(uuid.uuid4())
|
||||
self.visibility = visibility
|
||||
self.is_public = is_public
|
||||
|
||||
service = self.get_service_with_fake_impl()
|
||||
visibility = "private"
|
||||
image_obj = Image(visibility=visibility)
|
||||
unified_image = service._unify_image(image_obj)
|
||||
self.assertIsInstance(unified_image, image.UnifiedImage)
|
||||
self.assertEqual(image_obj.id, unified_image.id)
|
||||
self.assertEqual(image_obj.visibility, unified_image.visibility)
|
||||
|
||||
image_obj = Image(is_public="public")
|
||||
del image_obj.visibility
|
||||
unified_image = service._unify_image(image_obj)
|
||||
self.assertEqual(image_obj.id, unified_image.id)
|
||||
self.assertEqual(image_obj.is_public, unified_image.visibility)
|
||||
|
||||
def test_delete_image(self):
|
||||
image_id = "image_id"
|
||||
service = self.get_service_with_fake_impl()
|
||||
service.delete_image(image_id=image_id)
|
||||
service._impl.delete_image.assert_called_once_with(image_id)
|
||||
|
||||
def test_is_applicable(self):
|
||||
clients = mock.Mock()
|
||||
|
||||
clients.glance().version = "1.0"
|
||||
self.assertTrue(
|
||||
glance_v1.UnifiedGlanceV1Service.is_applicable(clients))
|
||||
|
||||
clients.glance().version = "2.0"
|
||||
self.assertTrue(
|
||||
glance_v2.UnifiedGlanceV2Service.is_applicable(clients))
|
Loading…
Reference in New Issue
Block a user