Add nova.BootServerAttachVolumeAndListAttachemnt

Create a VM, attach N volume to it and list server's
attachemnt.

Measure the "nova volume-attachments" command performance.

Change-Id: Iff7b7aad66b16138beb723ca20d0a7bae7bb24d8
This commit is contained in:
zhangzhang 2017-01-10 10:45:45 -05:00 committed by zhangzhihui
parent df0d4d25a2
commit 485cf7b07f
7 changed files with 242 additions and 0 deletions

View File

@ -1329,3 +1329,26 @@
sla:
failure_rate:
max: 0
NovaServers.boot_server_attach_volume_and_list_attachments:
-
args:
flavor:
name: {{flavor_name}}
image:
name: {{image_name}}
volume_size: 1
volume_num: 2
boot_server_kwargs: {}
create_volume_kwargs: {}
runner:
type: "constant"
times: 2
concurrency: 2
context:
users:
tenants: 1
users_per_tenant: 1
sla:
failure_rate:
max: 0

View File

@ -483,6 +483,55 @@ class BootServerAttachCreatedVolumeAndResize(utils.NovaScenario,
self._delete_server(server, force=force_delete)
@validation.add("number", param_name="volume_num", minval=1,
integer_only=True)
@validation.add("number", param_name="volume_size", minval=1,
integer_only=True)
@types.convert(image={"type": "glance_image"},
flavor={"type": "nova_flavor"})
@validation.add("image_valid_on_flavor", flavor_param="flavor",
image_param="image", validate_disk=False)
@validation.add("required_services", services=[consts.Service.NOVA,
consts.Service.CINDER])
@validation.add("required_platform", platform="openstack", users=True)
@scenario.configure(context={"cleanup": ["cinder", "nova"]},
name=("NovaServers.boot_server"
"_attach_volume_and_list_attachments"))
class BootServerAttachVolumeAndListAttachments(utils.NovaScenario,
cinder_utils.CinderBasic):
def run(self, image, flavor, volume_size=1, volume_num=2,
boot_server_kwargs=None, create_volume_kwargs=None):
"""Create a VM, attach N volume to it and list server's attachemnt.
Measure the "nova volume-attachments" command performance.
:param image: Glance image name to use for the VM
:param flavor: VM flavor name
:param volume_size: volume size (in GB), default 1G
:param volume_num: the num of attached volume
:param boot_server_kwargs: optional arguments for VM creation
:param create_volume_kwargs: optional arguments for volume creation
"""
boot_server_kwargs = boot_server_kwargs or {}
create_volume_kwargs = create_volume_kwargs or {}
server = self._boot_server(image, flavor, **boot_server_kwargs)
attachments = []
for i in range(volume_num):
volume = self.cinder.create_volume(volume_size,
**create_volume_kwargs)
attachments.append(self._attach_volume(server, volume))
list_attachments = self._list_attachments(server.id)
for attachment in attachments:
msg = ("attachment not included into list of available"
"attachments\n attachment: {}\n"
"list attachments: {}").format(attachment, list_attachments)
self.assertIn(attachment, list_attachments, err_msg=msg)
@types.convert(image={"type": "glance_image"},
flavor={"type": "nova_flavor"},
to_flavor={"type": "nova_flavor"})

View File

@ -682,6 +682,15 @@ class NovaScenario(scenario.OpenStackScenario):
)
return attachment
@atomic.action_timer("nova.list_attachments")
def _list_attachments(self, server_id):
"""Get a list of all the attached volumes for the given server ID.
:param server_id: The ID of the server
:rtype: list of :class:`Volume`
"""
return self.clients("nova").volumes.get_server_volumes(server_id)
@atomic.action_timer("nova.detach_volume")
def _detach_volume(self, server, volume, attachment=None):
server_id = server.id

View File

@ -0,0 +1,36 @@
{% set flavor_name = flavor_name or "m1.tiny" %}
{% set image_name = "^(cirros.*-disk|TestVM)$" %}
{
"NovaServers.boot_server_attach_volume_and_list_attachments": [
{
"args": {
"flavor": {
"name": "{{flavor_name}}"
},
"image": {
"name": "{{image_name}}"
},
"volume_size": 1,
"volume_num": 2,
"boot_server_kwargs": {},
"create_volume_kwargs": {}
},
"runner": {
"type": "constant",
"times": 5,
"concurrency": 2
},
"context": {
"users": {
"tenants": 2,
"users_per_tenant": 2
}
},
"sla": {
"failure_rate": {
"max": 0
}
}
}
]
}

View File

@ -0,0 +1,25 @@
{% set flavor_name = flavor_name or "m1.tiny" %}
{% set image_name = "^(cirros.*-disk|TestVM)$" %}
---
NovaServers.boot_server_attach_volume_and_list_attachments:
-
args:
flavor:
name: "{{flavor_name}}"
image:
name: "{{image_name}}"
volume_size: 1
volume_num: 2
boot_server_kwargs: {}
create_volume_kwargs: {}
runner:
type: "constant"
times: 5
concurrency: 2
context:
users:
tenants: 2
users_per_tenant: 2
sla:
failure_rate:
max: 0

View File

@ -559,6 +559,94 @@ class NovaServersTestCase(test.ScenarioTestCase):
scenario._delete_server.assert_called_once_with(fake_server,
force=False)
@mock.patch("rally.plugins.openstack.services.storage.block.BlockStorage")
def test_list_attachments(self, mock_block_storage):
mock_volume_service = mock_block_storage.return_value
fake_volume = mock.MagicMock()
fake_server = mock.MagicMock()
flavor = mock.MagicMock()
fake_attachment = mock.MagicMock()
list_attachments = [mock.MagicMock(),
fake_attachment,
mock.MagicMock()]
context = self.context
context.update({
"admin": {
"id": "fake_user_id",
"credential": mock.MagicMock()
},
"user": {"id": "fake_user_id",
"credential": mock.MagicMock()},
"tenant": {"id": "fake", "name": "fake",
"volumes": [{"id": "uuid", "size": 1}],
"servers": [1]}})
scenario = servers.BootServerAttachVolumeAndListAttachments(
context)
scenario._boot_server = mock.MagicMock(return_value=fake_server)
scenario._attach_volume = mock.MagicMock()
scenario._list_attachments = mock.MagicMock()
mock_volume_service.create_volume.return_value = fake_volume
scenario._list_attachments.return_value = list_attachments
img_name = "img"
volume_size = 10
volume_num = 1
scenario._attach_volume.return_value = fake_attachment
scenario.run(img_name, flavor, volume_size, volume_num)
scenario._boot_server.assert_called_once_with(img_name, flavor)
mock_volume_service.create_volume.assert_called_once_with(volume_size)
scenario._attach_volume.assert_called_once_with(fake_server,
fake_volume)
scenario._list_attachments.assert_called_once_with(fake_server.id)
@mock.patch("rally.plugins.openstack.services.storage.block.BlockStorage")
def test_list_attachments_fails(self, mock_block_storage):
mock_volume_service = mock_block_storage.return_value
fake_volume = mock.MagicMock()
fake_server = mock.MagicMock()
flavor = mock.MagicMock()
fake_attachment = mock.MagicMock()
list_attachments = [mock.MagicMock(),
mock.MagicMock(),
mock.MagicMock()]
context = self.context
context.update({
"admin": {
"id": "fake_user_id",
"credential": mock.MagicMock()
},
"user": {"id": "fake_user_id",
"credential": mock.MagicMock()},
"tenant": {"id": "fake", "name": "fake",
"volumes": [{"id": "uuid", "size": 1}],
"servers": [1]}})
scenario = servers.BootServerAttachVolumeAndListAttachments(
context)
scenario._boot_server = mock.MagicMock(return_value=fake_server)
mock_volume_service.create_volume.return_value = fake_volume
scenario._attach_volume = mock.MagicMock()
scenario._list_attachments = mock.MagicMock()
scenario._attach_volume.return_value = fake_attachment
scenario._list_attachments.return_value = list_attachments
img_name = "img"
volume_size = 10
# Negative case: attachment not included into list of
# available attachments
self.assertRaises(rally_exceptions.RallyAssertionError,
scenario.run,
img_name, flavor, volume_size)
scenario._boot_server.assert_called_with(img_name, flavor)
mock_volume_service.create_volume.assert_called_with(volume_size)
scenario._attach_volume.assert_called_with(fake_server,
fake_volume)
scenario._list_attachments.assert_called_with(fake_server.id)
@ddt.data({"confirm": True, "do_delete": True},
{"confirm": False, "do_delete": True})
@ddt.unpack

View File

@ -610,6 +610,18 @@ class NovaScenarioTestCase(test.ScenarioTestCase):
self._test_atomic_action_timer(nova_scenario.atomic_actions(),
"nova.attach_volume")
def test__list_attachments(self):
expect_attachments = [mock.MagicMock()]
(self.clients("nova").volumes.get_server_volumes
.return_value) = expect_attachments
nova_scenario = utils.NovaScenario(context=self.context)
list_attachments = nova_scenario._list_attachments(self.server.id)
self.assertEqual(expect_attachments, list_attachments)
(self.clients("nova").volumes.get_server_volumes
.assert_called_once_with(self.server.id))
self._test_atomic_action_timer(nova_scenario.atomic_actions(),
"nova.list_attachments")
def test__detach_volume(self):
attach = mock.MagicMock(id="attach_id")
self.clients("nova").volumes.delete_server_volume.return_value = None