Implement create_and_upload_volume_to_image scenario for Cinder

The `create_and_upload_volume_to_image' sceanario can not be run
on the DSVM gate with the default settings because it uses 1GB
Swift backend for Glance image store.

Change-Id: I41e1b391c560c7b9156e68c640531942cc8bf34c
This commit is contained in:
Ivan Kolodyazhny 2015-02-03 22:29:58 +02:00
parent f41531e60c
commit 8afb31c2dc
7 changed files with 178 additions and 1 deletions

View File

@ -258,3 +258,19 @@
sla: sla:
failure_rate: failure_rate:
max: 0 max: 0
CinderVolumes.create_and_upload_volume_to_image:
-
args:
size: 1
runner:
type: "constant"
times: 1
concurrency: 1
context:
users:
tenants: 1
users_per_tenant: 1
sla:
failure_rate:
max: 0

View File

@ -125,6 +125,46 @@ class CinderScenario(base.Scenario):
check_interval=CONF.benchmark.cinder_volume_create_poll_interval check_interval=CONF.benchmark.cinder_volume_create_poll_interval
) )
@base.atomic_action_timer("cinder.upload_volume_to_image")
def _upload_volume_to_image(self, volume, force=False,
container_format="bare", disk_format="raw"):
"""Upload the given volume to image.
Returns created image.
:param volume: volume object
:param force: flag to indicate whether to snapshot a volume even if
it's attached to an instance
:param container_format: container format of image. Acceptable
formats: ami, ari, aki, bare, and ovf
:param: disk_format: disk format of image. Acceptable formats:
ami, ari, aki, vhd, vmdk, raw, qcow2, vdi
and iso
:returns: Returns created image object
"""
resp, img = volume.upload_to_image(force, self._generate_random_name(),
container_format, disk_format)
# NOTE (e0ne): upload_to_image changes volume status to uploading so
# we need to wait until it will be available.
volume = bench_utils.wait_for(
volume,
is_ready=bench_utils.resource_is("available"),
update_resource=bench_utils.get_from_manager(),
timeout=CONF.benchmark.cinder_volume_create_timeout,
check_interval=CONF.benchmark.cinder_volume_create_poll_interval
)
image_id = img["os-volume_upload_image"]["image_id"]
image = self.clients("glance").images.get(image_id)
image = bench_utils.wait_for(
image,
is_ready=bench_utils.resource_is("active"),
update_resource=bench_utils.get_from_manager(),
timeout=CONF.benchmark.glance_image_create_prepoll_delay,
check_interval=CONF.benchmark.glance_image_create_poll_interval
)
return image
@base.atomic_action_timer("cinder.create_snapshot") @base.atomic_action_timer("cinder.create_snapshot")
def _create_snapshot(self, volume_id, force=False, **kwargs): def _create_snapshot(self, volume_id, force=False, **kwargs):
"""Create one snapshot. """Create one snapshot.

View File

@ -15,6 +15,7 @@
from rally.benchmark.scenarios import base from rally.benchmark.scenarios import base
from rally.benchmark.scenarios.cinder import utils from rally.benchmark.scenarios.cinder import utils
from rally.benchmark.scenarios.glance import utils as glance_utils
from rally.benchmark.scenarios.nova import utils as nova_utils from rally.benchmark.scenarios.nova import utils as nova_utils
from rally.benchmark import types as types from rally.benchmark import types as types
from rally.benchmark import validation from rally.benchmark import validation
@ -27,7 +28,8 @@ LOG = logging.getLogger(__name__)
class CinderVolumes(utils.CinderScenario, class CinderVolumes(utils.CinderScenario,
nova_utils.NovaScenario): nova_utils.NovaScenario,
glance_utils.GlanceScenario):
"""Benchmark scenarios for Cinder Volumes.""" """Benchmark scenarios for Cinder Volumes."""
@types.set(image=types.ImageResourceType) @types.set(image=types.ImageResourceType)
@ -359,3 +361,30 @@ class CinderVolumes(utils.CinderScenario,
volume = random.choice(self.context["tenant"]["volumes"]) volume = random.choice(self.context["tenant"]["volumes"])
self._create_snapshot(volume["id"], force=force, **kwargs) self._create_snapshot(volume["id"], force=force, **kwargs)
self._list_snapshots(detailed) self._list_snapshots(detailed)
@validation.required_services(consts.Service.CINDER, consts.Service.GLANCE)
@validation.required_openstack(users=True)
@validation.required_parameters("size")
@base.scenario(context={"cleanup": ["cinder", "glance"]})
def create_and_upload_volume_to_image(self, size, force=False,
container_format="bare",
disk_format="raw",
do_delete=True,
**kwargs):
"""Create and upload a volume to image.
:param size: volume size (integers, in GB)
:param force: when set to True volume that is attached to an instance
could be uploaded to image
:param container_format: image container format
:param disk_format: disk format for image
:param do_delete: deletes image and volume after uploading if True
:param kwargs: optional args to create a volume
"""
volume = self._create_volume(size, **kwargs)
image = self._upload_volume_to_image(volume, force, container_format,
disk_format)
if do_delete:
self._delete_volume(volume)
self._delete_image(image)

View File

@ -0,0 +1,24 @@
{
"CinderVolumes.create_and_upload_volume_to_image": [
{
"args": {
"size": 1,
"force": false,
"container_format": "bare",
"disk_format": "raw",
"do_delete": true
},
"runner": {
"type": "constant",
"times": 3,
"concurrency": 2
},
"context": {
"users": {
"tenants": 2,
"users_per_tenant": 2
}
}
}
]
}

View File

@ -0,0 +1,17 @@
---
CinderVolumes.create_and_upload_volume_to_image:
-
args:
size: 1
force: false
container_format: "bare"
disk_format: "raw"
do_delete: true
runner:
type: "constant"
times: 3
concurrency: 2
context:
users:
tenants: 2
users_per_tenant: 2

View File

@ -107,6 +107,23 @@ class CinderScenarioTestCase(test.TestCase):
self._test_atomic_action_timer(self.scenario.atomic_actions(), self._test_atomic_action_timer(self.scenario.atomic_actions(),
"cinder.extend_volume") "cinder.extend_volume")
@mock.patch(CINDER_UTILS + ".CinderScenario.clients")
def test__upload_volume_to_image(self, mock_clients):
volume = mock.Mock()
image = {"os-volume_upload_image": {"image_id": 1}}
volume.upload_to_image.return_value = (None, image)
mock_clients("cinder").images.get.return_value = image
self.scenario._generate_random_name = mock.Mock(
return_value="test_vol")
self.scenario._upload_volume_to_image(volume, False,
"container", "disk")
volume.upload_to_image.assert_called_once_with(False, "test_vol",
"container", "disk")
self.assertTrue(self.wait_for.mock.called)
self.assertEqual(2, self.wait_for.mock.call_count)
@mock.patch(CINDER_UTILS + ".CinderScenario.clients") @mock.patch(CINDER_UTILS + ".CinderScenario.clients")
def test__create_snapshot(self, mock_clients): def test__create_snapshot(self, mock_clients):
snapshot = mock.Mock() snapshot = mock.Mock()

View File

@ -180,6 +180,40 @@ class CinderServersTestCase(test.TestCase):
scenario._delete_volume.assert_called_once_with(fake_volume) scenario._delete_volume.assert_called_once_with(fake_volume)
scenario._delete_server.assert_called_once_with(fake_server) scenario._delete_server.assert_called_once_with(fake_server)
def test_create_and_upload_volume_to_image(self):
fake_volume = mock.Mock()
fake_image = mock.Mock()
scenario = volumes.CinderVolumes()
scenario._create_volume = mock.MagicMock(return_value=fake_volume)
scenario._upload_volume_to_image = mock.MagicMock(
return_value=fake_image)
scenario._delete_volume = mock.MagicMock()
scenario._delete_image = mock.MagicMock()
scenario.create_and_upload_volume_to_image(2,
container_format="fake",
disk_format="disk",
do_delete=False)
scenario._create_volume.assert_called_once_with(2)
scenario._upload_volume_to_image.assert_called_once_with(fake_volume,
False,
"fake",
"disk")
scenario._create_volume.reset_mock()
scenario._upload_volume_to_image.reset_mock()
scenario.create_and_upload_volume_to_image(1, do_delete=True)
scenario._create_volume.assert_called_once_with(1)
scenario._upload_volume_to_image.assert_called_once_with(fake_volume,
False,
"bare",
"raw")
scenario._delete_volume.assert_called_once_with(fake_volume)
scenario._delete_image.assert_called_once_with(fake_image)
def test_create_snapshot_and_attach_volume(self): def test_create_snapshot_and_attach_volume(self):
fake_volume = mock.MagicMock() fake_volume = mock.MagicMock()
fake_snapshot = mock.MagicMock() fake_snapshot = mock.MagicMock()