[Manila] Add share-network autocreation context support

For the moment, it is impossible to test Manila setup
autocreating share-networks on-fly. So, add its support.

Change-Id: I6b18b2b5dca7603113d0d69206829fc1fc7b7f3d
This commit is contained in:
Valeriy Ponomaryov 2016-06-14 18:28:48 +03:00
parent 777720fc2c
commit a14e816064
7 changed files with 462 additions and 53 deletions

View File

@ -34,6 +34,36 @@
failure_rate:
max: 0
ManilaShares.create_and_delete_share:
-
args:
share_proto: "nfs"
size: 1
min_sleep: 1
max_sleep: 2
runner:
type: "constant"
times: 4
concurrency: 4
context:
quotas:
manila:
shares: -1
gigabytes: -1
share_networks: -1
users:
tenants: 2
users_per_tenant: 1
user_choice_method: "round_robin"
network:
networks_per_tenant: 2
start_cidr: "99.0.0.0/24"
manila_share_networks:
use_share_networks: True
sla:
failure_rate:
max: 0
ManilaShares.create_share_network_and_delete:
-
args:

View File

@ -23,6 +23,7 @@ from rally import exceptions
from rally.plugins.openstack.context.manila import consts
from rally.plugins.openstack.scenarios.manila import utils as manila_utils
from rally.task import context
from rally.task import utils as bench_utils
CONF = cfg.CONF
LOG = logging.getLogger(__name__)
@ -31,7 +32,7 @@ CONTEXT_NAME = consts.SHARE_NETWORKS_CONTEXT_NAME
@context.configure(name=CONTEXT_NAME, order=450)
class ManilaShareNetworks(context.Context):
class ShareNetworks(context.Context):
"""This context creates resources specific for Manila project."""
CONFIG_SCHEMA = {
"type": "object",
@ -42,9 +43,12 @@ class ManilaShareNetworks(context.Context):
"use_share_networks": {"type": "boolean"},
# NOTE(vponomaryov): this context arg will be used only when
# context arg "use_share_networks" is set to True and context
# 'existing_users' is not empty, considering usage of existing
# users.
# context arg "use_share_networks" is set to True.
# If context arg 'share_networks' has values
# then they will be used else share networks will be autocreated -
# one for each tenant network. If networks do not exist then will
# be created one share network for each tenant without network
# data.
# Expected value is dict of lists where tenant Name or ID is key
# and list of share_network Names or IDs is value. Example:
# "context": {
@ -103,8 +107,12 @@ class ManilaShareNetworks(context.Context):
self.context["tenants"][tenant_id][CONTEXT_NAME][
"share_networks"] = []
manila_scenario = manila_utils.ManilaScenario(
{"user": existing_user})
manila_scenario = manila_utils.ManilaScenario({
"user": existing_user,
"config": {
"api_versions": self.context["config"].get(
"api_versions", [])}
})
existing_sns = manila_scenario._list_share_networks(
detailed=False, search_opts={"project_id": tenant_id})
@ -122,26 +130,137 @@ class ManilaShareNetworks(context.Context):
# Set share network for project
self.context["tenants"][tenant_id][CONTEXT_NAME][
"share_networks"].append(sn)
"share_networks"].append(sn.to_dict())
# Add shared integer var per project that will be used as index
# for list with share networks. It is required for balancing.
self.context["tenants"][tenant_id][CONTEXT_NAME]["sn_iterator"] = (
utils.RAMInt())
def _setup_for_autocreated_users(self):
# Create share network for each network of tenant
for user, tenant_id in (utils.iterate_per_tenants(
self.context.get("users", []))):
networks = self.context["tenants"][tenant_id].get("networks")
manila_scenario = manila_utils.ManilaScenario({
"task": self.task,
"user": user,
"config": {
"api_versions": self.context["config"].get(
"api_versions", [])}
})
self.context["tenants"][tenant_id][CONTEXT_NAME] = {
"share_networks": []}
data = {}
def _setup_share_network(tenant_id, data):
share_network = manila_scenario._create_share_network(
**data).to_dict()
self.context["tenants"][tenant_id][CONTEXT_NAME][
"share_networks"].append(share_network)
if networks:
for network in networks:
if network.get("cidr"):
data["nova_net_id"] = network["id"]
elif network.get("subnets"):
data["neutron_net_id"] = network["id"]
data["neutron_subnet_id"] = network["subnets"][0]
else:
LOG.warning(_(
"Can not determine network service provider. "
"Share network will have no data."))
_setup_share_network(tenant_id, data)
else:
_setup_share_network(tenant_id, data)
@logging.log_task_wrapper(LOG.info, _("Enter context: `%s`")
% CONTEXT_NAME)
def setup(self):
self.context[CONTEXT_NAME] = {}
if not self.config["use_share_networks"]:
return
self.context[CONTEXT_NAME]["delete_share_networks"] = False
elif self.context["config"].get("existing_users"):
self._setup_for_existing_users()
else:
# TODO(vponomaryov): add support of autocreated resources
pass
self._setup_for_autocreated_users()
def _cleanup_tenant_resources(self, resources_plural_name,
resources_singular_name):
"""Cleans up tenant resources.
:param resources_plural_name: plural name for resources
:param resources_singular_name: singular name for resource. Expected
to be part of resource deletion method name (obj._delete_%s)
"""
for user, tenant_id in (utils.iterate_per_tenants(
self.context.get("users", []))):
manila_scenario = manila_utils.ManilaScenario({
"user": user,
"config": {
"api_versions": self.context["config"].get(
"api_versions", [])}
})
resources = self.context["tenants"][tenant_id][CONTEXT_NAME].get(
resources_plural_name, [])
for resource in resources:
logger = logging.ExceptionLogger(
LOG,
_("Failed to delete %(name)s %(id)s for tenant %(t)s.") % {
"id": resource, "t": tenant_id,
"name": resources_singular_name})
with logger:
delete_func = getattr(
manila_scenario,
"_delete_%s" % resources_singular_name)
delete_func(resource)
def _wait_for_cleanup_of_share_networks(self):
"""Waits for deletion of Manila service resources."""
for user, tenant_id in (utils.iterate_per_tenants(
self.context.get("users", []))):
self._wait_for_resources_deletion(
self.context["tenants"][tenant_id][CONTEXT_NAME].get("shares"))
manila_scenario = manila_utils.ManilaScenario({
"user": user,
"admin": self.context["admin"],
"config": {
"api_versions": self.context["config"].get(
"api_versions", [])}
})
for sn in self.context["tenants"][tenant_id][CONTEXT_NAME][
"share_networks"]:
share_servers = manila_scenario._list_share_servers(
search_opts={"share_network": sn["id"]})
self._wait_for_resources_deletion(share_servers)
def _wait_for_resources_deletion(self, resources):
"""Waiter for resources deletion.
:param resources: resource or list of resources for deletion
verification
"""
if not resources:
return
if not isinstance(resources, list):
resources = [resources]
for resource in resources:
bench_utils.wait_for_status(
resource,
ready_statuses=["deleted"],
check_deletion=True,
update_resource=bench_utils.get_from_manager(),
timeout=CONF.benchmark.manila_share_delete_timeout,
check_interval=(
CONF.benchmark.manila_share_delete_poll_interval))
@logging.log_task_wrapper(LOG.info, _("Exit context: `%s`") % CONTEXT_NAME)
def cleanup(self):
# TODO(vponomaryov): add cleanup for autocreated resources when appear.
return
if self.context[CONTEXT_NAME].get("delete_share_networks", True):
# NOTE(vponomaryov): Schedule 'share networks' deletion.
self._cleanup_tenant_resources("share_networks", "share_network")
# NOTE(vponomaryov): Share network deletion schedules deletion of
# share servers. So, we should wait for its deletion too to avoid
# further failures of network resources release.
# Use separate cycle to make share servers be deleted in parallel.
self._wait_for_cleanup_of_share_networks()
else:
# NOTE(vponomaryov): assume that share networks were not created
# by test run.
return

View File

@ -78,16 +78,15 @@ class ManilaScenario(scenario.OpenStackScenario):
consts.SHARE_NETWORKS_CONTEXT_NAME, {}).get(
"share_networks", [])
if share_networks and not kwargs.get("share_network"):
index = next(self.context.get("tenant", {}).get(
consts.SHARE_NETWORKS_CONTEXT_NAME, {}).get(
"sn_iterator")) % len(share_networks)
kwargs["share_network"] = share_networks[index]
kwargs["share_network"] = share_networks[
self.context["iteration"] % len(share_networks)]["id"]
if not kwargs.get("name"):
kwargs["name"] = self.generate_random_name()
share = self.clients("manila").shares.create(
share_proto, size, **kwargs)
time.sleep(CONF.benchmark.manila_share_create_prepoll_delay)
share = utils.wait_for(
share,

View File

@ -0,0 +1,38 @@
{
"ManilaShares.create_and_delete_share": [
{
"args": {
"share_proto": "nfs",
"size": 1,
"min_sleep": 1,
"max_sleep": 2
},
"runner": {
"type": "constant",
"times": 2,
"concurrency": 2
},
"context": {
"quotas": {
"manila": {
"shares": -1,
"gigabytes": -1,
"share_networks": -1
}
},
"users": {
"tenants": 2,
"users_per_tenant": 1,
"user_choice_method": "round_robin"
},
"network": {
"networks_per_tenant": 1,
"start_cidr": "99.0.0.0/24"
},
"manila_share_networks": {
"use_share_networks": true
}
}
}
]
}

View File

@ -0,0 +1,27 @@
---
ManilaShares.create_and_delete_share:
-
args:
share_proto: "nfs"
size: 1
min_sleep: 1
max_sleep: 2
runner:
type: "constant"
times: 2
concurrency: 2
context:
quotas:
manila:
shares: -1
gigabytes: -1
share_networks: -1
users:
tenants: 2
users_per_tenant: 1
user_choice_method: "round_robin"
network:
networks_per_tenant: 1
start_cidr: "99.0.0.0/24"
manila_share_networks:
use_share_networks: True

View File

@ -15,9 +15,10 @@
import copy
import ddt
import mock
import six
from rally.common import utils
from rally import consts as rally_consts
from rally import exceptions
from rally.plugins.openstack.context.manila import consts
@ -28,9 +29,78 @@ MANILA_UTILS_PATH = ("rally.plugins.openstack.scenarios.manila.utils."
"ManilaScenario.")
class ManilaSampleGeneratorTestCase(test.TestCase):
class Fake(object):
def __init__(self, **kwargs):
for k, v in kwargs.items():
setattr(self, k, v)
def __getitem__(self, item):
return getattr(self, item)
def to_dict(self):
return self.__dict__
@ddt.ddt
class ShareNetworksTestCase(test.TestCase):
TENANTS_AMOUNT = 3
USERS_PER_TENANT = 4
SECURITY_SERVICES = [
{"type": ss_type,
"dns_ip": "fake_dns_ip_%s" % ss_type,
"server": "fake_server_%s" % ss_type,
"domain": "fake_domain_%s" % ss_type,
"user": "fake_user_%s" % ss_type,
"password": "fake_password_%s" % ss_type,
"name": "fake_optional_name_%s" % ss_type}
for ss_type in ("ldap", "kerberos", "active_directory")
]
def _get_context(self, networks_per_tenant=2,
neutron_network_provider=True):
tenants = {}
for t_id in range(self.TENANTS_AMOUNT):
tenants[six.text_type(t_id)] = {"name": six.text_type(t_id)}
tenants[six.text_type(t_id)]["networks"] = []
for i in range(networks_per_tenant):
network = {"id": "fake_net_id_%s" % i}
if neutron_network_provider:
network["subnets"] = ["fake_subnet_id_of_net_%s" % i]
else:
network["cidr"] = "101.0.5.0/24"
tenants[six.text_type(t_id)]["networks"].append(network)
users = []
for t_id in tenants.keys():
for i in range(self.USERS_PER_TENANT):
users.append(
{"id": i, "tenant_id": t_id, "credential": "fake"})
context = {
"config": {
"users": {
"tenants": self.TENANTS_AMOUNT,
"users_per_tenant": self.USERS_PER_TENANT,
"random_user_choice": False,
},
consts.SHARE_NETWORKS_CONTEXT_NAME: {
"use_share_networks": True,
"share_networks": [],
},
"network": {
"networks_per_tenant": networks_per_tenant,
"start_cidr": "101.0.5.0/24",
},
},
"admin": {
"credential": mock.MagicMock(),
},
"task": mock.MagicMock(),
"users": users,
"tenants": tenants,
}
return context
def setUp(self):
super(ManilaSampleGeneratorTestCase, self).setUp()
super(self.__class__, self).setUp()
self.ctxt_use_existing = {
"task": mock.MagicMock(),
"config": {
@ -53,9 +123,7 @@ class ManilaSampleGeneratorTestCase(test.TestCase):
],
}
self.existing_sns = [
type("ShareNetwork", (object, ), {
"id": "sn_%s_id" % i, "name": "sn_%s_name" % i})()
for i in range(1, 6)
Fake(id="sn_%s_id" % i, name="sn_%s_name" % i) for i in range(1, 6)
]
def test_init(self):
@ -67,7 +135,7 @@ class ManilaSampleGeneratorTestCase(test.TestCase):
},
}
inst = manila_share_networks.ManilaShareNetworks(context)
inst = manila_share_networks.ShareNetworks(context)
self.assertEqual(
{"foo": "bar", "share_networks": {}, "use_share_networks": False},
@ -92,9 +160,11 @@ class ManilaSampleGeneratorTestCase(test.TestCase):
"use_share_networks": False,
},
},
consts.SHARE_NETWORKS_CONTEXT_NAME: {},
consts.SHARE_NETWORKS_CONTEXT_NAME: {
"delete_share_networks": False,
},
}
inst = manila_share_networks.ManilaShareNetworks(ctxt)
inst = manila_share_networks.ShareNetworks(ctxt)
expected_ctxt = copy.deepcopy(inst.context)
@ -108,8 +178,7 @@ class ManilaSampleGeneratorTestCase(test.TestCase):
self, mock_manila_scenario__list_share_networks, mock_clients):
existing_sns = self.existing_sns
expected_ctxt = copy.deepcopy(self.ctxt_use_existing)
inst = manila_share_networks.ManilaShareNetworks(
self.ctxt_use_existing)
inst = manila_share_networks.ShareNetworks(self.ctxt_use_existing)
mock_manila_scenario__list_share_networks.return_value = (
self.existing_sns)
expected_ctxt.update({
@ -119,16 +188,16 @@ class ManilaSampleGeneratorTestCase(test.TestCase):
"id": "tenant_1_id",
"name": "tenant_1_name",
consts.SHARE_NETWORKS_CONTEXT_NAME: {
"share_networks": [sn for sn in existing_sns[0:2]],
"sn_iterator": mock.ANY,
"share_networks": [
sn.to_dict() for sn in existing_sns[0:2]],
},
},
"tenant_2_id": {
"id": "tenant_2_id",
"name": "tenant_2_name",
consts.SHARE_NETWORKS_CONTEXT_NAME: {
"share_networks": [sn for sn in existing_sns[2:5]],
"sn_iterator": mock.ANY,
"share_networks": [
sn.to_dict() for sn in existing_sns[2:5]],
},
},
}
@ -144,21 +213,11 @@ class ManilaSampleGeneratorTestCase(test.TestCase):
inst.context.get(consts.SHARE_NETWORKS_CONTEXT_NAME, {}).get(
"delete_share_networks"))
self.assertEqual(expected_ctxt["tenants"], inst.context.get("tenants"))
for i, sns in ((1, existing_sns[0:2]), (2, existing_sns[2:5])):
self.assertIsInstance(
inst.context["tenants"]["tenant_%s_id" % i][
consts.SHARE_NETWORKS_CONTEXT_NAME]["sn_iterator"],
utils.RAMInt)
for j in range(12):
self.assertEqual(
j,
next(inst.context["tenants"]["tenant_%s_id" % i][
consts.SHARE_NETWORKS_CONTEXT_NAME]["sn_iterator"]))
def test_setup_use_existing_share_networks_tenant_not_found(self):
ctxt = copy.deepcopy(self.ctxt_use_existing)
ctxt.update({"tenants": {}})
inst = manila_share_networks.ManilaShareNetworks(ctxt)
inst = manila_share_networks.ShareNetworks(ctxt)
self.assertRaises(exceptions.ContextSetupFailure, inst.setup)
@ -169,7 +228,7 @@ class ManilaSampleGeneratorTestCase(test.TestCase):
ctxt = copy.deepcopy(self.ctxt_use_existing)
ctxt["config"][consts.SHARE_NETWORKS_CONTEXT_NAME][
"share_networks"] = {"tenant_1_id": ["foo"]}
inst = manila_share_networks.ManilaShareNetworks(ctxt)
inst = manila_share_networks.ShareNetworks(ctxt)
mock_manila_scenario__list_share_networks.return_value = (
self.existing_sns)
@ -179,6 +238,144 @@ class ManilaSampleGeneratorTestCase(test.TestCase):
ctxt = copy.deepcopy(self.ctxt_use_existing)
ctxt["config"][consts.SHARE_NETWORKS_CONTEXT_NAME][
"share_networks"] = {}
inst = manila_share_networks.ManilaShareNetworks(ctxt)
inst = manila_share_networks.ShareNetworks(ctxt)
self.assertRaises(exceptions.ContextSetupFailure, inst.setup)
@ddt.data(True, False)
@mock.patch("rally.osclients.Clients")
@mock.patch(MANILA_UTILS_PATH + "_create_share_network")
@mock.patch(MANILA_UTILS_PATH + "_add_security_service_to_share_network")
def test_setup_autocreate_share_networks_wo_security_services(
self,
neutron,
mock_manila_scenario__add_security_service_to_share_network,
mock_manila_scenario__create_share_network,
mock_clients):
networks_per_tenant = 2
ctxt = self._get_context(
networks_per_tenant=networks_per_tenant,
neutron_network_provider=neutron,
)
inst = manila_share_networks.ShareNetworks(ctxt)
inst.setup()
self.assertEqual(ctxt["task"], inst.context.get("task"))
self.assertEqual(ctxt["config"], inst.context.get("config"))
self.assertEqual(ctxt["users"], inst.context.get("users"))
self.assertEqual(ctxt["tenants"], inst.context.get("tenants"))
self.assertFalse(
mock_manila_scenario__add_security_service_to_share_network.called)
if neutron:
sn_args = {
"neutron_net_id": mock.ANY,
"neutron_subnet_id": mock.ANY,
}
else:
sn_args = {"nova_net_id": mock.ANY}
expected_calls = [mock.call(**sn_args), mock.call().to_dict()]
mock_manila_scenario__create_share_network.assert_has_calls(
expected_calls * (self.TENANTS_AMOUNT * networks_per_tenant))
mock_clients.assert_has_calls([
mock.call("fake", {}) for i in range(self.TENANTS_AMOUNT)])
@mock.patch("rally.osclients.Clients")
@mock.patch(MANILA_UTILS_PATH + "_create_share_network")
@mock.patch(MANILA_UTILS_PATH + "_add_security_service_to_share_network")
def test_setup_autocreate_share_networks_wo_networks(
self,
mock_manila_scenario__add_security_service_to_share_network,
mock_manila_scenario__create_share_network,
mock_clients):
ctxt = self._get_context(networks_per_tenant=0)
inst = manila_share_networks.ShareNetworks(ctxt)
inst.setup()
self.assertEqual(ctxt["task"], inst.context.get("task"))
self.assertEqual(ctxt["config"], inst.context.get("config"))
self.assertEqual(ctxt["users"], inst.context.get("users"))
self.assertEqual(ctxt["tenants"], inst.context.get("tenants"))
self.assertFalse(
mock_manila_scenario__add_security_service_to_share_network.called)
expected_calls = [mock.call(), mock.call().to_dict()]
mock_manila_scenario__create_share_network.assert_has_calls(
expected_calls * self.TENANTS_AMOUNT)
mock_clients.assert_has_calls([
mock.call("fake", {}) for i in range(self.TENANTS_AMOUNT)])
@mock.patch("rally.osclients.Clients")
@mock.patch(MANILA_UTILS_PATH + "_delete_share_network")
@mock.patch(MANILA_UTILS_PATH + "_list_share_servers")
@mock.patch(MANILA_UTILS_PATH + "_list_share_networks")
def test_cleanup_used_existing_share_networks(
self,
mock_manila_scenario__list_share_networks,
mock_manila_scenario__list_share_servers,
mock_manila_scenario__delete_share_network,
mock_clients):
inst = manila_share_networks.ShareNetworks(self.ctxt_use_existing)
mock_manila_scenario__list_share_networks.return_value = (
self.existing_sns)
inst.setup()
inst.cleanup()
self.assertFalse(mock_manila_scenario__list_share_servers.called)
self.assertFalse(mock_manila_scenario__delete_share_network.called)
self.assertEqual(2, mock_clients.call_count)
for user in self.ctxt_use_existing["users"]:
self.assertIn(mock.call(user["credential"], {}),
mock_clients.mock_calls)
@mock.patch("rally.task.utils.wait_for_status")
@mock.patch("rally.osclients.Clients")
@mock.patch(MANILA_UTILS_PATH + "_delete_share_network")
@mock.patch(MANILA_UTILS_PATH + "_create_share_network")
@mock.patch(MANILA_UTILS_PATH + "_add_security_service_to_share_network")
@mock.patch(MANILA_UTILS_PATH + "_list_share_servers")
def test_cleanup_autocreated_share_networks(
self,
mock_manila_scenario__list_share_servers,
mock_manila_scenario__add_security_service_to_share_network,
mock_manila_scenario__create_share_network,
mock_manila_scenario__delete_share_network,
mock_clients,
mock_wait_for_status):
fake_share_servers = ["fake_share_server"]
mock_manila_scenario__list_share_servers.return_value = (
fake_share_servers)
networks_per_tenant = 2
ctxt = self._get_context(
networks_per_tenant=networks_per_tenant,
)
inst = manila_share_networks.ShareNetworks(ctxt)
inst.setup()
mock_clients.assert_has_calls([
mock.call("fake", {}) for i in range(self.TENANTS_AMOUNT)])
inst.cleanup()
self.assertEqual(self.TENANTS_AMOUNT * 4, mock_clients.call_count)
self.assertEqual(
self.TENANTS_AMOUNT * networks_per_tenant,
mock_manila_scenario__list_share_servers.call_count)
mock_manila_scenario__list_share_servers.assert_has_calls(
[mock.call(search_opts=mock.ANY)])
self.assertEqual(
self.TENANTS_AMOUNT * networks_per_tenant,
mock_manila_scenario__delete_share_network.call_count)
self.assertEqual(
self.TENANTS_AMOUNT * networks_per_tenant,
mock_wait_for_status.call_count)
mock_wait_for_status.assert_has_calls([
mock.call(
fake_share_servers[0],
ready_statuses=["deleted"],
check_deletion=True,
update_resource=mock.ANY,
timeout=180,
check_interval=2),
])

View File

@ -36,12 +36,11 @@ class ManilaScenarioTestCase(test.ScenarioTestCase):
self.scenario.context = {
"tenant": {
consts.SHARE_NETWORKS_CONTEXT_NAME: {
"share_networks": ["sn_1_id", "sn_2_id", ],
"share_networks": [{"id": "sn_1_id"}, {"id": "sn_2_id"}],
}
}
},
"iteration": 0,
}
self.scenario.context["tenant"][consts.SHARE_NETWORKS_CONTEXT_NAME][
"sn_iterator"] = iter((0, ))
self.scenario.generate_random_name = mock.Mock()
self.scenario._create_share("nfs")
@ -49,7 +48,7 @@ class ManilaScenarioTestCase(test.ScenarioTestCase):
self.clients("manila").shares.create.assert_called_once_with(
"nfs", 1, name=self.scenario.generate_random_name.return_value,
share_network=self.scenario.context["tenant"][
consts.SHARE_NETWORKS_CONTEXT_NAME]["share_networks"][0])
consts.SHARE_NETWORKS_CONTEXT_NAME]["share_networks"][0]["id"])
self.mock_wait_for.mock.assert_called_once_with(
fake_share,