Add possibility to create lots of shares in parallel for tempest

Test suite located in module
contrib/tempest/tempest/api/share/admin/test_multi_backend.py
creates 2 shares without waiting for "available" status and then waits for
status. In this case "retry" functionality is not used.

Add method 'create_shares' to base class that does parallel share
creation with recreation as it is done with single request. And use this
method in mentioned test module.

Change-Id: I1314c9494a547314cd9bb9b03323470d58956fac
Closes-Bug: #1406770
This commit is contained in:
Valeriy Ponomaryov 2014-12-31 17:06:24 +02:00 committed by vponomaryov
parent 0dd28ab401
commit a52d1b49a6
2 changed files with 81 additions and 35 deletions

View File

@ -36,6 +36,7 @@ class ShareMultiBackendTest(base.BaseSharesAdminTest):
"Skipping.") "Skipping.")
cls.vts = [] cls.vts = []
cls.shares = [] cls.shares = []
share_data_list = []
# Create volume types # Create volume types
for i in [0, 1]: for i in [0, 1]:
@ -46,16 +47,10 @@ class ShareMultiBackendTest(base.BaseSharesAdminTest):
__, vt = cls.create_volume_type(name=vt_name, __, vt = cls.create_volume_type(name=vt_name,
extra_specs=extra_specs) extra_specs=extra_specs)
cls.vts.append(vt) cls.vts.append(vt)
share_data_list.append({"kwargs": {"volume_type_id": vt["id"]}})
# Create shares # Create shares using precreated volume types
for vt in cls.vts: cls.shares = cls.create_shares(share_data_list)
__, share = cls.create_share(volume_type_id=vt["id"],
wait_for_active=False)
cls.shares.append(share)
# Wait for active statuses of shares
for share in cls.shares:
cls.shares_client.wait_for_share_status(share["id"], "available")
@test.attr(type=["gate", "smoke", ]) @test.attr(type=["gate", "smoke", ])
def test_share_backend_name_reporting(self): def test_share_backend_name_reporting(self):

View File

@ -13,6 +13,7 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import copy
import inspect import inspect
from tempest import clients_share as clients from tempest import clients_share as clients
@ -227,15 +228,15 @@ class BaseSharesTest(test.BaseTestCase):
return share_network_id return share_network_id
@classmethod @classmethod
def create_share(cls, share_protocol=None, size=1, name=None, def _create_share(cls, share_protocol=None, size=1, name=None,
snapshot_id=None, description=None, metadata={}, snapshot_id=None, description=None, metadata=None,
share_network_id=None, volume_type_id=None, share_network_id=None, volume_type_id=None,
client=None, cleanup_in_class=True, client=None, cleanup_in_class=True):
wait_for_active=True):
client = client or cls.shares_client client = client or cls.shares_client
description = description or "Tempest's share" description = description or "Tempest's share"
share_network_id = share_network_id or client.share_network_id or None share_network_id = share_network_id or client.share_network_id or None
kw = { metadata = metadata or {}
kwargs = {
'share_protocol': share_protocol, 'share_protocol': share_protocol,
'size': size, 'size': size,
'name': name, 'name': name,
@ -245,33 +246,83 @@ class BaseSharesTest(test.BaseTestCase):
'share_network_id': share_network_id, 'share_network_id': share_network_id,
'volume_type_id': volume_type_id, 'volume_type_id': volume_type_id,
} }
resp, share = client.create_share(**kwargs)
resource = {"type": "share", "id": share["id"], "client": client}
cleanup_list = (cls.class_resources if cleanup_in_class else
cls.method_resources)
cleanup_list.insert(0, resource)
return resp, share
def _create_share(**kwargs): @classmethod
resp, share = client.create_share(**kwargs) def create_share(cls, *args, **kwargs):
resource = {"type": "share", "id": share["id"], "client": client} """Create one share and wait for available state. Retry if allowed."""
cleanup_list = (cls.class_resources if cleanup_in_class else result = cls.create_shares(
cls.method_resources) [{"args": args, "kwargs": kwargs}], with_resp=True)
cleanup_list.insert(0, resource) return result[0]
return resp, share
resp, share = _create_share(**kw) @classmethod
if wait_for_active: def create_shares(cls, share_data_list, with_resp=False):
cnt = 0 """Creates several shares in parallel with retries.
while True:
if cnt > 0: Use this method when you want to create more than one share at same
resp, share = _create_share(**kw) time. Especially if config option 'share.share_creation_retry_number'
has value more than zero (0).
All shares will be expected to have 'available' status with or without
recreation else error will be raised.
:param share_data_list: list -- list of dictionaries with 'args' and
'kwargs' for '_create_share' method of this base class.
example of data:
share_data_list=[{'args': ['quuz'], 'kwargs': {'foo': 'bar'}}}]
:param with_resp: boolean -- whether to return list of
tuples (resp, share) or just list of shares.
:returns: list -- list of shares created using provided data.
"""
data = [copy.deepcopy(d) for d in share_data_list]
for d in data:
if not isinstance(d, dict):
raise exceptions.TempestException(
"Expected 'dict', got '%s'" % type(d))
if "args" not in d:
d["args"] = []
if "kwargs" not in d:
d["kwargs"] = {}
if len(d) > 2:
raise exceptions.TempestException(
"Expected only 'args' and 'kwargs' keys. "
"Provided %s" % list(d))
d["kwargs"]["client"] = d["kwargs"].get(
"client", cls.shares_client)
d["resp"], d["share"] = cls._create_share(
*d["args"], **d["kwargs"])
d["cnt"] = 0
d["available"] = False
while not all(d["available"] for d in data):
for d in data:
if d["available"]:
continue
try: try:
client.wait_for_share_status(share["id"], "available") d["kwargs"]["client"].wait_for_share_status(
d["share"]["id"], "available")
d["available"] = True
except (share_exceptions.ShareBuildErrorException, except (share_exceptions.ShareBuildErrorException,
exceptions.TimeoutException) as e: exceptions.TimeoutException) as e:
if CONF.share.share_creation_retry_number > cnt: if CONF.share.share_creation_retry_number > d["cnt"]:
cnt += 1 d["cnt"] += 1
continue msg = ("Share '%(id)s' failed to be built. "
"Trying create another." % d["share"]["id"])
LOG.error(msg)
LOG.error(e)
d["resp"], d["share"] = cls._create_share(
*d["args"], **d["kwargs"])
else: else:
raise e raise e
else:
break if with_resp:
return resp, share return [(d["resp"], d["share"]) for d in data]
return [d["share"] for d in data]
@classmethod @classmethod
def create_snapshot_wait_for_active(cls, share_id, name=None, def create_snapshot_wait_for_active(cls, share_id, name=None,