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']