Fix CinderVolumes.create_volume_and_clone

1:Add nested_level argument for nested cloning volume to new volume.
2:Fix the bug that new volume assiged size is possibly less than
source volume size when setting size argument "min: 1, max: 5".

Change-Id: I18ae333189423461bca52f783311bcf43354ccab
This commit is contained in:
chenhb-zte 2016-05-19 17:29:33 -04:00
parent 3cf581d58b
commit ffcd50452e
5 changed files with 60 additions and 29 deletions
rally-jobs
rally/plugins/openstack/scenarios/cinder
samples/tasks/scenarios/cinder
tests/unit/plugins/openstack/scenarios/cinder

17
rally-jobs/cinder.yaml Normal file → Executable file

@ -666,3 +666,20 @@
sla:
failure_rate:
max: 0
-
args:
size:
min: 1
max: 1
nested_level: 2
runner:
type: "constant"
times: 1
concurrency: 1
context:
users:
tenants: 2
users_per_tenant: 2
sla:
failure_rate:
max: 0

22
rally/plugins/openstack/scenarios/cinder/volumes.py Normal file → Executable file

@ -551,22 +551,34 @@ class CinderVolumes(cinder_utils.CinderScenario,
@validation.required_services(consts.Service.CINDER)
@validation.required_openstack(users=True)
@scenario.configure(context={"cleanup": ["cinder"]})
def create_volume_and_clone(self, size, image=None, **kwargs):
def create_volume_and_clone(self, size, image=None, nested_level=1,
**kwargs):
"""Create a volume, then clone it to another volume.
This creates a volume, then clone it to anothor volume,
and then clone the new volume to next volume...
1. create source volume (from image)
2. clone source volume to volume1
3. clone volume1 to volume2
4. clone volume2 to volume3
5. ...
:param size: volume size (integer, in GB) or
dictionary, must contain two values:
min - minimum size volumes will be created as;
max - maximum size volumes will be created as.
:param image: image to be used to create initial volume
:param nested_level: amount of nested levels
:param kwargs: optional args to create volumes
"""
if image:
kwargs["imageRef"] = image
vol1 = self._create_volume(size, **kwargs)
source_vol = self._create_volume(size, **kwargs)
kwargs.pop("imageRef", None)
with atomic.ActionTimer(self, "cinder.clone_volume"):
self._create_volume(size, source_volid=vol1.id,
atomic_action=False, **kwargs)
for i in range(nested_level):
with atomic.ActionTimer(self, "cinder.clone_volume"):
source_vol = self._create_volume(source_vol.size,
source_volid=source_vol.id,
atomic_action=False, **kwargs)

@ -21,7 +21,8 @@
"size": {
"min": 1,
"max": 5
}
},
"nested_level": 3
},
"runner": {
"type": "constant",

@ -16,6 +16,7 @@
size:
min: 1
max: 5
nested_level: 3
runner:
type: "constant"
times: 3

@ -13,6 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
import ddt
import mock
from rally.plugins.openstack.scenarios.cinder import volumes
@ -26,6 +27,7 @@ class fake_type(object):
name = "fake"
@ddt.ddt
class CinderServersTestCase(test.ScenarioTestCase):
def _get_context(self):
@ -495,30 +497,28 @@ class CinderServersTestCase(test.ScenarioTestCase):
self.assertFalse(scenario._delete_volume.called)
self.assertFalse(scenario._delete_backup.called)
def test_create_volume_and_clone(self):
fake_volumes = [mock.Mock(), mock.Mock()]
@ddt.data({},
{"nested_level": 2},
{"image": "img"})
@ddt.unpack
def test_create_volume_and_clone(self, nested_level=1,
image=None):
create_volumes_count = nested_level + 1
fake_volumes = [mock.Mock(size=1) for i in range(create_volumes_count)]
scenario = volumes.CinderVolumes(self.context)
scenario._create_volume = mock.MagicMock(side_effect=fake_volumes)
scenario.create_volume_and_clone(1, fakearg="fake")
scenario._create_volume.assert_has_calls([
mock.call(1, fakearg="fake"),
mock.call(1, source_volid=fake_volumes[0].id, atomic_action=False,
fakearg="fake")])
scenario.create_volume_and_clone(1, image=image,
nested_level=nested_level,
fakearg="fake")
self._test_atomic_action_timer(scenario.atomic_actions(),
"cinder.clone_volume")
def test_create_volume_and_clone_from_image(self):
fake_volumes = [mock.Mock(), mock.Mock()]
scenario = volumes.CinderVolumes(self.context)
scenario._create_volume = mock.MagicMock(side_effect=fake_volumes)
scenario.create_volume_and_clone(1, image="image_id", fakearg="fake")
scenario._create_volume.assert_has_calls([
mock.call(1, fakearg="fake", imageRef="image_id"),
mock.call(1, source_volid=fake_volumes[0].id, atomic_action=False,
fakearg="fake")])
self._test_atomic_action_timer(scenario.atomic_actions(),
"cinder.clone_volume")
expected = [mock.call(1, imageRef=image, fakearg="fake")
if image else mock.call(1, fakearg="fake")]
for i in range(nested_level):
expected.append(mock.call(fake_volumes[i].size,
source_volid=fake_volumes[i].id,
atomic_action=False, fakearg="fake")
)
self._test_atomic_action_timer(scenario.atomic_actions(),
"cinder.clone_volume")
scenario._create_volume.assert_has_calls(expected)