Merge "Add snapshot instances admin APIs"
diff --git a/manila_tempest_tests/config.py b/manila_tempest_tests/config.py
index 8a2b31a..55f2e15 100644
--- a/manila_tempest_tests/config.py
+++ b/manila_tempest_tests/config.py
@@ -56,6 +56,15 @@
help="This option used to determine backend driver type, "
"multitenant driver uses share-networks, but "
"single-tenant doesn't."),
+ cfg.BoolOpt("create_networks_when_multitenancy_enabled",
+ default=True,
+ help="This option is used only when other "
+ "'multitenancy_enabled' option is set to 'True'. "
+ "If this one is set to True, then tempest will create "
+ "neutron networks for each new manila share-network "
+ "it creates. Else it will use manila share-networks with "
+ "empty values (case of StandAloneNetworkPlugin and "
+ "NeutronSingleNetworkPlugin)."),
cfg.ListOpt("enable_protocols",
default=["nfs", "cifs"],
help="First value of list is protocol by default, "
diff --git a/manila_tempest_tests/tests/api/base.py b/manila_tempest_tests/tests/api/base.py
index dd90d8f..73fcf09 100644
--- a/manila_tempest_tests/tests/api/base.py
+++ b/manila_tempest_tests/tests/api/base.py
@@ -203,7 +203,8 @@
# Provide share network
if CONF.share.multitenancy_enabled:
- if not CONF.service_available.neutron:
+ if (not CONF.service_available.neutron and
+ CONF.share.create_networks_when_multitenancy_enabled):
raise cls.skipException("Neutron support is required")
nc = os.networks_client
share_network_id = cls.provide_share_network(client, nc, ic)
@@ -235,7 +236,8 @@
os.auth_provider)
cls.shares_v2_client = os.shares_v2_client
if CONF.share.multitenancy_enabled:
- if not CONF.service_available.neutron:
+ if (not CONF.service_available.neutron and
+ CONF.share.create_networks_when_multitenancy_enabled):
raise cls.skipException("Neutron support is required")
share_network_id = cls.provide_share_network(
cls.shares_v2_client, os.networks_client)
@@ -259,9 +261,9 @@
@classmethod
def resource_cleanup(cls):
- super(BaseSharesTest, cls).resource_cleanup()
cls.clear_resources(cls.class_resources)
cls.clear_isolated_creds(cls.class_isolated_creds)
+ super(BaseSharesTest, cls).resource_cleanup()
@classmethod
@network_synchronized
@@ -282,6 +284,8 @@
"""
sc = shares_client
+ search_word = "reusable"
+ sn_name = "autogenerated_by_tempest_%s" % search_word
if not CONF.share.multitenancy_enabled:
# Assumed usage of a single-tenant driver
@@ -289,13 +293,28 @@
elif sc.share_network_id:
# Share-network already exists, use it
share_network_id = sc.share_network_id
+ elif not CONF.share.create_networks_when_multitenancy_enabled:
+ share_network_id = None
+
+ # Try get suitable share-network
+ share_networks = sc.list_share_networks_with_detail()
+ for sn in share_networks:
+ if (sn["neutron_net_id"] is None and
+ sn["neutron_subnet_id"] is None and
+ sn["name"] and search_word in sn["name"]):
+ share_network_id = sn["id"]
+ break
+
+ # Create new share-network if one was not found
+ if share_network_id is None:
+ sn_desc = "This share-network was created by tempest"
+ sn = sc.create_share_network(name=sn_name, description=sn_desc)
+ share_network_id = sn["id"]
else:
net_id = subnet_id = share_network_id = None
if not isolated_creds_client:
# Search for networks, created in previous runs
- search_word = "reusable"
- sn_name = "autogenerated_by_tempest_%s" % search_word
service_net_name = "share-service"
networks = networks_client.list_networks()
if "networks" in networks.keys():
@@ -454,18 +473,28 @@
for d in data:
if d["available"]:
continue
+ client = d["kwargs"]["client"]
+ share_id = d["share"]["id"]
try:
- d["kwargs"]["client"].wait_for_share_status(
- d["share"]["id"], "available")
+ client.wait_for_share_status(share_id, "available")
d["available"] = True
except (share_exceptions.ShareBuildErrorException,
exceptions.TimeoutException) as e:
if CONF.share.share_creation_retry_number > d["cnt"]:
d["cnt"] += 1
msg = ("Share '%s' failed to be built. "
- "Trying create another." % d["share"]["id"])
+ "Trying create another." % share_id)
LOG.error(msg)
LOG.error(e)
+ cg_id = d["kwargs"].get("consistency_group_id")
+ if cg_id:
+ # NOTE(vponomaryov): delete errored share
+ # immediately in case share is part of CG.
+ client.delete_share(
+ share_id,
+ params={"consistency_group_id": cg_id})
+ client.wait_for_resource_deletion(
+ share_id=share_id)
d["share"] = cls._create_share(
*d["args"], **d["kwargs"])
else:
diff --git a/manila_tempest_tests/tests/api/test_shares.py b/manila_tempest_tests/tests/api/test_shares.py
index 2acd81a..7926b33 100644
--- a/manila_tempest_tests/tests/api/test_shares.py
+++ b/manila_tempest_tests/tests/api/test_shares.py
@@ -57,8 +57,10 @@
self.assertFalse(share['is_public'])
# The 'status' of the share returned by the create API must be
- # the default value - 'creating'.
- self.assertEqual('creating', share['status'])
+ # set and have value either 'creating' or
+ # 'available' (if share creation is really fast as in
+ # case of Dummy driver).
+ self.assertIn(share['status'], ('creating', 'available'))
# Get share using v 2.1 - we expect key 'snapshot_support' to be absent
share_get = self.shares_v2_client.get_share(share['id'], version='2.1')
@@ -146,8 +148,10 @@
self.protocol, snapshot_id=snap["id"], cleanup_in_class=False)
# The 'status' of the share returned by the create API must be
- # the default value - 'creating'.
- self.assertEqual('creating', s2['status'])
+ # set and have value either 'creating' or
+ # 'available' (if share creation is really fast as in
+ # case of Dummy driver).
+ self.assertIn(s2['status'], ('creating', 'available'))
# verify share, created from snapshot
get = self.shares_client.get_share(s2["id"])
@@ -176,8 +180,10 @@
self.protocol, snapshot_id=snap["id"], cleanup_in_class=False)
# The 'status' of the share returned by the create API must be
- # the default value - 'creating'.
- self.assertEqual('creating', child['status'])
+ # set and have value either 'creating' or
+ # 'available' (if share creation is really fast as in
+ # case of Dummy driver).
+ self.assertIn(child['status'], ('creating', 'available'))
# verify share, created from snapshot
get = self.shares_client.get_share(child["id"])
diff --git a/manila_tempest_tests/tests/scenario/manager_share.py b/manila_tempest_tests/tests/scenario/manager_share.py
index f2604e7..972654b 100644
--- a/manila_tempest_tests/tests/scenario/manager_share.py
+++ b/manila_tempest_tests/tests/scenario/manager_share.py
@@ -107,6 +107,7 @@
search_opts={"share_network": sn_id})
for server in servers:
client.delete_share_server(server['id'])
+ for server in servers:
client.wait_for_resource_deletion(server_id=server['id'])
def _create_share_network(self, client=None, **kwargs):
diff --git a/manila_tempest_tests/tests/scenario/test_share_basic_ops.py b/manila_tempest_tests/tests/scenario/test_share_basic_ops.py
index a3e0e1f..dbe5599 100644
--- a/manila_tempest_tests/tests/scenario/test_share_basic_ops.py
+++ b/manila_tempest_tests/tests/scenario/test_share_basic_ops.py
@@ -14,6 +14,7 @@
# under the License.
from oslo_log import log as logging
+from tempest.common import waiters
from tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib.common.utils import test_utils
@@ -65,14 +66,17 @@
'user: {ssh_user}'.format(
image=self.image_ref, flavor=self.flavor_ref,
ssh_user=self.ssh_user))
+ self.security_group = self._create_security_group()
+ if CONF.share.multitenancy_enabled:
+ self.create_share_network()
- def boot_instance(self):
+ def boot_instance(self, wait_until="ACTIVE"):
self.keypair = self.create_keypair()
security_groups = [{'name': self.security_group['name']}]
create_kwargs = {
'key_name': self.keypair['name'],
'security_groups': security_groups,
- 'wait_until': 'ACTIVE',
+ 'wait_until': wait_until,
}
if CONF.share.multitenancy_enabled:
create_kwargs['networks'] = [{'uuid': self.net['id']}, ]
@@ -152,7 +156,6 @@
'share_type_id': self._get_share_type()['id'],
}
if CONF.share.multitenancy_enabled:
- self.create_share_network()
kwargs.update({'share_network_id': self.share_net['id']})
self.share = self._create_share(**kwargs)
@@ -163,6 +166,7 @@
first_address = net_addresses.values()[0][0]
ip = first_address['addr']
except Exception:
+ LOG.debug("Instance: %s" % instance)
# In case on an error ip will be still none
LOG.exception("Instance does not have a valid IP address."
"Falling back to default")
@@ -171,12 +175,17 @@
self._allow_access(share_id, access_type='ip', access_to=ip,
cleanup=cleanup)
+ def wait_for_active_instance(self, instance_id):
+ waiters.wait_for_server_status(
+ self.manager.servers_client, instance_id, "ACTIVE")
+ return self.manager.servers_client.show_server(instance_id)["server"]
+
@test.services('compute', 'network')
@test.attr(type=[base.TAG_POSITIVE, base.TAG_BACKEND])
def test_mount_share_one_vm(self):
- self.security_group = self._create_security_group()
+ instance = self.boot_instance(wait_until="BUILD")
self.create_share()
- instance = self.boot_instance()
+ instance = self.wait_for_active_instance(instance["id"])
self.allow_access_ip(self.share['id'], instance=instance,
cleanup=False)
ssh_client = self.init_ssh(instance)
@@ -198,11 +207,15 @@
def test_read_write_two_vms(self):
"""Boots two vms and writes/reads data on it."""
test_data = "Some test data to write"
- self.security_group = self._create_security_group()
- self.create_share()
- # boot first VM and write data
- instance1 = self.boot_instance()
+ # Boot two VMs and create share
+ instance1 = self.boot_instance(wait_until="BUILD")
+ instance2 = self.boot_instance(wait_until="BUILD")
+ self.create_share()
+ instance1 = self.wait_for_active_instance(instance1["id"])
+ instance2 = self.wait_for_active_instance(instance2["id"])
+
+ # Write data to first VM
self.allow_access_ip(self.share['id'], instance=instance1,
cleanup=False)
ssh_client_inst1 = self.init_ssh(instance1)
@@ -219,9 +232,9 @@
ssh_client_inst1)
self.write_data(test_data, ssh_client_inst1)
- # boot second VM and read
- instance2 = self.boot_instance()
- self.allow_access_ip(self.share['id'], instance=instance2)
+ # Read from second VM
+ self.allow_access_ip(
+ self.share['id'], instance=instance2, cleanup=False)
ssh_client_inst2 = self.init_ssh(instance2)
self.mount_share(locations[0], ssh_client_inst2)
self.addCleanup(self.umount_share,
@@ -247,8 +260,9 @@
"are needed to run migration tests. "
"Skipping.")
- self.security_group = self._create_security_group()
+ instance = self.boot_instance(wait_until="BUILD")
self.create_share()
+ instance = self.wait_for_active_instance(instance["id"])
share = self.shares_client.get_share(self.share['id'])
dest_pool = next((x for x in pools if x['name'] != share['host']),
@@ -259,10 +273,9 @@
dest_pool = dest_pool['name']
- instance1 = self.boot_instance()
- self.allow_access_ip(self.share['id'], instance=instance1,
+ self.allow_access_ip(self.share['id'], instance=instance,
cleanup=False)
- ssh_client = self.init_ssh(instance1)
+ ssh_client = self.init_ssh(instance)
if utils.is_microversion_lt(CONF.share.max_api_microversion, "2.9"):
locations = self.share['export_locations']