add manila+VM test
create NFS share and access it from VM Change-Id: I588251b032ce3f283626b4ca8032b517920d7e83
This commit is contained in:
parent
771c922af5
commit
93ee1c074f
@ -14,16 +14,22 @@
|
||||
# under the License.
|
||||
|
||||
from rally.common import logging
|
||||
from rally import exceptions
|
||||
from rally.task import types
|
||||
from rally.task import utils as rally_utils
|
||||
from rally.task import validation
|
||||
|
||||
from rally_openstack.common import consts
|
||||
from rally_openstack.task.contexts.manila import consts as manila_consts
|
||||
from rally_openstack.task import scenario
|
||||
from rally_openstack.task.scenarios.manila import utils
|
||||
from rally_openstack.task.scenarios.vm import utils as vm_utils
|
||||
|
||||
|
||||
"""Scenarios for Manila shares."""
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@validation.add("enum", param_name="share_proto",
|
||||
values=["NFS", "CIFS", "GLUSTERFS", "HDFS", "CEPHFS"],
|
||||
@ -56,6 +62,113 @@ class CreateAndDeleteShare(utils.ManilaScenario):
|
||||
self.sleep_between(min_sleep, max_sleep)
|
||||
self._delete_share(share)
|
||||
|
||||
@types.convert(image={"type": "glance_image"},
|
||||
flavor={"type": "nova_flavor"})
|
||||
@validation.add("image_valid_on_flavor", flavor_param="flavor",
|
||||
image_param="image", fail_on_404_image=False)
|
||||
@validation.add("number", param_name="port", minval=1, maxval=65535,
|
||||
nullable=True, integer_only=True)
|
||||
@validation.add("external_network_exists", param_name="floating_network")
|
||||
@validation.add("required_services", services=[consts.Service.MANILA,
|
||||
consts.Service.NOVA])
|
||||
@validation.add("required_platform", platform="openstack", users=True)
|
||||
@scenario.configure(context={"cleanup@openstack": ["manila", "nova"],
|
||||
"keypair@openstack": {},
|
||||
"allow_ssh@openstack": None},
|
||||
name="ManilaShares.create_share_and_access_from_vm",
|
||||
platform="openstack")
|
||||
class CreateShareAndAccessFromVM(utils.ManilaScenario, vm_utils.VMScenario):
|
||||
def run(self, image, flavor, username, size=1, password=None,
|
||||
floating_network=None, port=22,
|
||||
use_floating_ip=True, force_delete=False, max_log_length=None,
|
||||
**kwargs):
|
||||
"""Create a share and access it from a VM.
|
||||
|
||||
- create NFS share
|
||||
- launch VM
|
||||
- authorize VM's fip to access the share
|
||||
- mount share iside the VM
|
||||
- write to share
|
||||
- delete VM
|
||||
- delete share
|
||||
|
||||
:param size: share size in GB, should be greater than 0
|
||||
|
||||
:param image: glance image name to use for the vm
|
||||
:param flavor: VM flavor name
|
||||
:param username: ssh username on server
|
||||
:param password: Password on SSH authentication
|
||||
:param floating_network: external network name, for floating ip
|
||||
:param port: ssh port for SSH connection
|
||||
:param use_floating_ip: bool, floating or fixed IP for SSH connection
|
||||
:param force_delete: whether to use force_delete for servers
|
||||
:param max_log_length: The number of tail nova console-log lines user
|
||||
would like to retrieve
|
||||
|
||||
|
||||
:param kwargs: optional args to create a share or a VM
|
||||
"""
|
||||
share_proto = "nfs"
|
||||
share = self._create_share(
|
||||
share_proto=share_proto,
|
||||
size=size,
|
||||
**kwargs)
|
||||
location = self._export_location(share)
|
||||
|
||||
server, fip = self._boot_server_with_fip(
|
||||
image, flavor, use_floating_ip=use_floating_ip,
|
||||
floating_network=floating_network,
|
||||
key_name=self.context["user"]["keypair"]["name"],
|
||||
userdata="#cloud-config\npackages:\n - nfs-common",
|
||||
**kwargs)
|
||||
self._allow_access_share(share, "ip", fip["ip"], "rw")
|
||||
mount_opt = "-t nfs -o nfsvers=4.1,proto=tcp"
|
||||
script = f"cloud-init status -w;" \
|
||||
f"sudo mount {mount_opt} {location[0]} /mnt || exit 1;" \
|
||||
f"sudo touch /mnt/testfile || exit 2"
|
||||
|
||||
command = {
|
||||
"script_inline": script,
|
||||
"interpreter": "/bin/bash"
|
||||
}
|
||||
try:
|
||||
rally_utils.wait_for_status(
|
||||
server,
|
||||
ready_statuses=["ACTIVE"],
|
||||
update_resource=rally_utils.get_from_manager(),
|
||||
)
|
||||
|
||||
code, out, err = self._run_command(
|
||||
fip["ip"], port, username, password, command=command)
|
||||
if code:
|
||||
raise exceptions.ScriptError(
|
||||
"Error running command %(command)s. "
|
||||
"Error %(code)s: %(error)s" % {
|
||||
"command": command, "code": code, "error": err})
|
||||
except (exceptions.TimeoutException,
|
||||
exceptions.SSHTimeout):
|
||||
console_logs = self._get_server_console_output(server,
|
||||
max_log_length)
|
||||
LOG.debug("VM console logs:\n%s" % console_logs)
|
||||
raise
|
||||
|
||||
finally:
|
||||
self._delete_server_with_fip(server, fip,
|
||||
force_delete=force_delete)
|
||||
self._delete_share(share)
|
||||
|
||||
self.add_output(complete={
|
||||
"title": "Script StdOut",
|
||||
"chart_plugin": "TextArea",
|
||||
"data": str(out).split("\n")
|
||||
})
|
||||
if err:
|
||||
self.add_output(complete={
|
||||
"title": "Script StdErr",
|
||||
"chart_plugin": "TextArea",
|
||||
"data": err.split("\n")
|
||||
})
|
||||
|
||||
|
||||
@validation.add("required_services", services=[consts.Service.MANILA])
|
||||
@validation.add("required_platform", platform="openstack", users=True)
|
||||
@ -242,9 +355,9 @@ class ListShareServers(utils.ManilaScenario):
|
||||
self._list_share_servers(search_opts=search_opts)
|
||||
|
||||
|
||||
@validation.add("enum", param_name="share_proto", values=["nfs", "cephfs",
|
||||
"cifs", "glusterfs", "hdfs"], missed=False,
|
||||
case_insensitive=True)
|
||||
@validation.add("enum", param_name="share_proto",
|
||||
values=["nfs", "cephfs", "cifs", "glusterfs", "hdfs"],
|
||||
missed=False, case_insensitive=True)
|
||||
@validation.add("required_services", services=[consts.Service.MANILA])
|
||||
@validation.add("required_platform", platform="openstack", users=True)
|
||||
@scenario.configure(
|
||||
|
@ -86,6 +86,14 @@ class ManilaScenario(scenario.OpenStackScenario):
|
||||
timeout=CONF.openstack.manila_share_delete_timeout,
|
||||
check_interval=CONF.openstack.manila_share_delete_poll_interval)
|
||||
|
||||
def _export_location(self, share):
|
||||
"""Export share location.
|
||||
|
||||
:param share: :class:`Share`
|
||||
"""
|
||||
location = share.export_locations
|
||||
return location
|
||||
|
||||
def _get_access_from_share(self, share, access_id):
|
||||
"""Get access from share
|
||||
|
||||
|
@ -0,0 +1,44 @@
|
||||
{
|
||||
"ManilaShares.create_share_and_access_from_vm": [
|
||||
{
|
||||
"args": {
|
||||
"size": 1,
|
||||
"share_type": "CephNFStype",
|
||||
"flavor": {
|
||||
"name": "m1.tiny"
|
||||
},
|
||||
"image": {
|
||||
"name": "^cirros.*-disk$"
|
||||
},
|
||||
"username": "ubuntu"
|
||||
},
|
||||
"runner": {
|
||||
"type": "constant",
|
||||
"times": 2,
|
||||
"concurrency": 2
|
||||
},
|
||||
"context": {
|
||||
"quotas": {
|
||||
"manila": {
|
||||
"shares": -1,
|
||||
"gigabytes": -1
|
||||
}
|
||||
},
|
||||
"users": {
|
||||
"tenants": 2,
|
||||
"users_per_tenant": 1
|
||||
},
|
||||
"network": {
|
||||
"dns_nameservers": [
|
||||
"9.9.9.9"
|
||||
]
|
||||
}
|
||||
},
|
||||
"sla": {
|
||||
"failure_rate": {
|
||||
"max": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
ManilaShares.create_share_and_access_from_vm:
|
||||
-
|
||||
args:
|
||||
size: 1
|
||||
share_type: "CephNFStype"
|
||||
flavor:
|
||||
name: "m1.tiny"
|
||||
image:
|
||||
name: "^cirros.*-disk$"
|
||||
username: "ubuntu"
|
||||
runner:
|
||||
type: "constant"
|
||||
times: 2
|
||||
concurrency: 2
|
||||
context:
|
||||
quotas:
|
||||
manila:
|
||||
shares: -1
|
||||
gigabytes: -1
|
||||
users:
|
||||
tenants: 2
|
||||
users_per_tenant: 1
|
||||
network:
|
||||
dns_nameservers:
|
||||
- "9.9.9.9"
|
||||
sla:
|
||||
failure_rate:
|
||||
max: 0
|
@ -17,6 +17,7 @@ from unittest import mock
|
||||
|
||||
import ddt
|
||||
|
||||
from rally import exceptions
|
||||
from rally_openstack.task.scenarios.manila import shares
|
||||
from tests.unit import test
|
||||
|
||||
@ -42,6 +43,164 @@ class ManilaSharesTestCase(test.ScenarioTestCase):
|
||||
scenario.sleep_between.assert_called_once_with(3, 4)
|
||||
scenario._delete_share.assert_called_once_with(fake_share)
|
||||
|
||||
def create_env(self, scenario):
|
||||
fake_share = mock.MagicMock()
|
||||
scenario = shares.CreateShareAndAccessFromVM(self.context)
|
||||
self.ip = {"id": "foo_id", "ip": "foo_ip", "is_floating": True}
|
||||
scenario._boot_server_with_fip = mock.Mock(
|
||||
return_value=("foo_server", self.ip))
|
||||
scenario._delete_server_with_fip = mock.Mock()
|
||||
scenario._run_command = mock.MagicMock(
|
||||
return_value=(0, "{\"foo\": 42}", "foo_err"))
|
||||
scenario.add_output = mock.Mock()
|
||||
self.context.update({"user": {"keypair": {"name": "keypair_name"},
|
||||
"credential": mock.MagicMock()}})
|
||||
scenario._create_share = mock.MagicMock(return_value=fake_share)
|
||||
scenario._delete_share = mock.MagicMock()
|
||||
scenario._export_location = mock.MagicMock(return_value="fake")
|
||||
scenario._allow_access_share = mock.MagicMock()
|
||||
|
||||
return scenario, fake_share
|
||||
|
||||
@ddt.data(
|
||||
{"image": "some_image",
|
||||
"flavor": "m1.small", "username": "chuck norris"}
|
||||
)
|
||||
@mock.patch("rally.task.utils.get_from_manager")
|
||||
@mock.patch("rally.task.utils.wait_for_status")
|
||||
def test_create_share_and_access_from_vm(
|
||||
self,
|
||||
params,
|
||||
mock_rally_task_utils_wait_for_status,
|
||||
mock_rally_task_utils_get_from_manager):
|
||||
scenario, fake_share = self.create_env(
|
||||
shares.CreateShareAndAccessFromVM(self.context))
|
||||
scenario.run(**params)
|
||||
|
||||
scenario._create_share.assert_called_once_with(
|
||||
share_proto="nfs", size=1)
|
||||
scenario._delete_share.assert_called_once_with(fake_share)
|
||||
scenario._allow_access_share.assert_called_once_with(
|
||||
fake_share, "ip", "foo_ip", "rw")
|
||||
scenario._export_location.assert_called_once_with(fake_share)
|
||||
scenario._boot_server_with_fip.assert_called_once_with(
|
||||
"some_image", "m1.small", use_floating_ip=True,
|
||||
floating_network=None, key_name="keypair_name",
|
||||
userdata="#cloud-config\npackages:\n - nfs-common")
|
||||
mock_rally_task_utils_wait_for_status.assert_called_once_with(
|
||||
"foo_server", ready_statuses=["ACTIVE"], update_resource=mock.ANY)
|
||||
scenario._delete_server_with_fip.assert_called_once_with(
|
||||
"foo_server", {"id": "foo_id", "ip": "foo_ip",
|
||||
"is_floating": True},
|
||||
force_delete=False)
|
||||
scenario.add_output.assert_called_with(
|
||||
complete={"chart_plugin": "TextArea",
|
||||
"data": [
|
||||
"foo_err"],
|
||||
"title": "Script StdErr"})
|
||||
|
||||
@ddt.data(
|
||||
{"image": "some_image",
|
||||
"flavor": "m1.small", "username": "chuck norris"}
|
||||
)
|
||||
@mock.patch("rally.task.utils.get_from_manager")
|
||||
@mock.patch("rally.task.utils.wait_for_status")
|
||||
def test_create_share_and_access_from_vm_command_timeout(
|
||||
self,
|
||||
params,
|
||||
mock_rally_task_utils_wait_for_status,
|
||||
mock_rally_task_utils_get_from_manager):
|
||||
scenario, fake_share = self.create_env(
|
||||
shares.CreateShareAndAccessFromVM(self.context))
|
||||
|
||||
scenario._run_command.side_effect = exceptions.SSHTimeout()
|
||||
self.assertRaises(exceptions.SSHTimeout,
|
||||
scenario.run,
|
||||
"foo_flavor", "foo_image", "foo_interpreter",
|
||||
"foo_script", "foo_username")
|
||||
scenario._delete_server_with_fip.assert_called_once_with(
|
||||
"foo_server", self.ip, force_delete=False)
|
||||
self.assertFalse(scenario.add_output.called)
|
||||
scenario._delete_share.assert_called_once_with(fake_share)
|
||||
|
||||
@ddt.data(
|
||||
{"image": "some_image",
|
||||
"flavor": "m1.small", "username": "chuck norris"}
|
||||
)
|
||||
@mock.patch("rally.task.utils.get_from_manager")
|
||||
@mock.patch("rally.task.utils.wait_for_status")
|
||||
def test_create_share_and_access_from_vm_wait_timeout(
|
||||
self,
|
||||
params,
|
||||
mock_rally_task_utils_wait_for_status,
|
||||
mock_rally_task_utils_get_from_manager):
|
||||
scenario, fake_share = self.create_env(
|
||||
shares.CreateShareAndAccessFromVM(self.context))
|
||||
|
||||
mock_rally_task_utils_wait_for_status.side_effect = \
|
||||
exceptions.TimeoutException(
|
||||
resource_type="foo_resource",
|
||||
resource_name="foo_name",
|
||||
resource_id="foo_id",
|
||||
desired_status="foo_desired_status",
|
||||
resource_status="foo_resource_status",
|
||||
timeout=2)
|
||||
self.assertRaises(exceptions.TimeoutException,
|
||||
scenario.run,
|
||||
"foo_flavor", "foo_image", "foo_interpreter",
|
||||
"foo_script", "foo_username")
|
||||
scenario._delete_server_with_fip.assert_called_once_with(
|
||||
"foo_server", self.ip, force_delete=False)
|
||||
self.assertFalse(scenario.add_output.called)
|
||||
scenario._delete_share.assert_called_once_with(fake_share)
|
||||
|
||||
@ddt.data(
|
||||
{"output": (0, "", ""),
|
||||
"expected": [{"complete": {"chart_plugin": "TextArea",
|
||||
"data": [""],
|
||||
"title": "Script StdOut"}}]},
|
||||
{"output": (1, "x y z", "error message"),
|
||||
"raises": exceptions.ScriptError},
|
||||
{"output": (0, "[1, 2, 3, 4]", ""), "expected": []}
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_create_share_and_access_from_vm_add_output(self, output,
|
||||
expected=None,
|
||||
raises=None):
|
||||
scenario, fake_share = self.create_env(
|
||||
shares.CreateShareAndAccessFromVM(self.context))
|
||||
|
||||
scenario._run_command.return_value = output
|
||||
kwargs = {"flavor": "foo_flavor",
|
||||
"image": "foo_image",
|
||||
"username": "foo_username",
|
||||
"password": "foo_password",
|
||||
"use_floating_ip": "use_fip",
|
||||
"floating_network": "ext_network",
|
||||
"force_delete": "foo_force"}
|
||||
if raises:
|
||||
self.assertRaises(raises, scenario.run, **kwargs)
|
||||
self.assertFalse(scenario.add_output.called)
|
||||
else:
|
||||
scenario.run(**kwargs)
|
||||
calls = [mock.call(**kw) for kw in expected]
|
||||
scenario.add_output.assert_has_calls(calls, any_order=True)
|
||||
|
||||
scenario._create_share.assert_called_once_with(
|
||||
share_proto="nfs", size=1)
|
||||
scenario._delete_share.assert_called_once_with(fake_share)
|
||||
scenario._allow_access_share.assert_called_once_with(
|
||||
fake_share, "ip", "foo_ip", "rw")
|
||||
scenario._export_location.assert_called_once_with(fake_share)
|
||||
scenario._boot_server_with_fip.assert_called_once_with(
|
||||
"foo_image", "foo_flavor", use_floating_ip="use_fip",
|
||||
floating_network="ext_network", key_name="keypair_name",
|
||||
userdata="#cloud-config\npackages:\n - nfs-common")
|
||||
scenario._delete_server_with_fip.assert_called_once_with(
|
||||
"foo_server",
|
||||
{"id": "foo_id", "ip": "foo_ip", "is_floating": True},
|
||||
force_delete="foo_force")
|
||||
|
||||
@ddt.data(
|
||||
{},
|
||||
{"detailed": True},
|
||||
|
@ -77,6 +77,12 @@ class ManilaScenarioTestCase(test.ScenarioTestCase):
|
||||
self.mock_get_from_manager.mock.assert_called_once_with(
|
||||
("error_deleting", ))
|
||||
|
||||
def test_export_location(self):
|
||||
fake_share = mock.MagicMock()
|
||||
fake_share.export_locations = "fake_location"
|
||||
result = self.scenario._export_location(fake_share)
|
||||
self.assertEqual(result, "fake_location")
|
||||
|
||||
@ddt.data(
|
||||
{},
|
||||
{"detailed": False, "search_opts": None},
|
||||
|
Loading…
Reference in New Issue
Block a user