Merge "Do not set alias user_client for specific client"
diff --git a/requirements.txt b/requirements.txt
index 911f0e5..8a2fa99 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -2,7 +2,7 @@
 # of appearance. Changing the order has an impact on the overall integration
 # process, which may cause wedges in the gate later.
 pbr!=2.1.0,>=2.0.0 # Apache-2.0
-cliff>=2.8.0 # Apache-2.0
+cliff!=2.9.0,>=2.8.0 # Apache-2.0
 jsonschema<3.0.0,>=2.6.0 # MIT
 testtools>=1.4.0 # MIT
 paramiko>=2.0.0 # LGPLv2.1+
diff --git a/tempest/api/compute/admin/test_live_migration.py b/tempest/api/compute/admin/test_live_migration.py
index 14be947..411159b 100644
--- a/tempest/api/compute/admin/test_live_migration.py
+++ b/tempest/api/compute/admin/test_live_migration.py
@@ -46,6 +46,18 @@
                 "Less than 2 compute nodes, skipping migration test.")
 
     @classmethod
+    def setup_credentials(cls):
+        # These tests don't attempt any SSH validation nor do they use
+        # floating IPs on the instance, so all we need is a network and
+        # a subnet so the instance being migrated has a single port, but
+        # we need that to make sure we are properly updating the port
+        # host bindings during the live migration.
+        # TODO(mriedem): SSH validation before and after the instance is
+        # live migrated would be a nice test wrinkle addition.
+        cls.set_network_resources(network=True, subnet=True)
+        super(LiveMigrationTest, cls).setup_credentials()
+
+    @classmethod
     def setup_clients(cls):
         super(LiveMigrationTest, cls).setup_clients()
         cls.admin_migration_client = cls.os_admin.migrations_client
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index 5c4767c..5504e05 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -422,6 +422,23 @@
                                                 volume['id'], 'available')
         return volume
 
+    def _detach_volume(self, server, volume):
+        """Helper method to detach a volume.
+
+        Ignores 404 responses if the volume or server do not exist, or the
+        volume is already detached from the server.
+        """
+        try:
+            volume = self.volumes_client.show_volume(volume['id'])['volume']
+            # Check the status. You can only detach an in-use volume, otherwise
+            # the compute API will return a 400 response.
+            if volume['status'] == 'in-use':
+                self.servers_client.detach_volume(server['id'], volume['id'])
+        except exceptions.NotFound:
+            # Ignore 404s on detach in case the server is deleted or the volume
+            # is already detached.
+            pass
+
     def attach_volume(self, server, volume, device=None, check_reserved=False):
         """Attaches volume to server and waits for 'in-use' volume status.
 
@@ -449,9 +466,7 @@
                         self.volumes_client, volume['id'], 'available')
         # Ignore 404s on detach in case the server is deleted or the volume
         # is already detached.
-        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
-                        self.servers_client.detach_volume,
-                        server['id'], volume['id'])
+        self.addCleanup(self._detach_volume, server, volume)
         statuses = ['in-use']
         if check_reserved:
             statuses.append('reserved')
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index c70ab49..4f7c090 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -904,16 +904,13 @@
             self._log_net_info(e)
             raise
 
-    def _check_remote_connectivity(self, source, dest, should_succeed=True,
-                                   nic=None):
+    def check_remote_connectivity(self, source, dest, should_succeed=True,
+                                  nic=None):
         """assert ping server via source ssh connection
 
-        Note: This is an internal method.  Use check_remote_connectivity
-        instead.
-
         :param source: RemoteClient: an ssh connection from which to ping
-        :param dest: and IP to ping against
-        :param should_succeed: boolean should ping succeed or not
+        :param dest: an IP to ping against
+        :param should_succeed: boolean: should ping succeed or not
         :param nic: specific network interface to ping from
         """
         def ping_remote():
@@ -925,21 +922,8 @@
                 return not should_succeed
             return should_succeed
 
-        return test_utils.call_until_true(ping_remote,
-                                          CONF.validation.ping_timeout,
-                                          1)
-
-    def check_remote_connectivity(self, source, dest, should_succeed=True,
-                                  nic=None):
-        """assert ping server via source ssh connection
-
-        :param source: RemoteClient: an ssh connection from which to ping
-        :param dest: and IP to ping against
-        :param should_succeed: boolean should ping succeed or not
-        :param nic: specific network interface to ping from
-        """
-        result = self._check_remote_connectivity(source, dest, should_succeed,
-                                                 nic)
+        result = test_utils.call_until_true(ping_remote,
+                                            CONF.validation.ping_timeout, 1)
         source_host = source.ssh_client.host
         if should_succeed:
             msg = "Timed out waiting for %s to become reachable from %s" \
@@ -1324,14 +1308,6 @@
             for obj in not_present_obj:
                 self.assertNotIn(obj, object_list)
 
-    def change_container_acl(self, container_name, acl):
-        metadata_param = {'metadata_prefix': 'x-container-',
-                          'metadata': {'read': acl}}
-        self.container_client.create_update_or_delete_container_metadata(
-            container_name, create_update_metadata=metadata_param)
-        resp, _ = self.container_client.list_container_metadata(container_name)
-        self.assertEqual(resp['x-container-read'], acl)
-
     def download_and_verify(self, container_name, obj_name, expected_data):
         _, obj = self.object_client.get_object(container_name, obj_name)
         self.assertEqual(obj, expected_data)
diff --git a/tempest/scenario/test_object_storage_basic_ops.py b/tempest/scenario/test_object_storage_basic_ops.py
index da0b1e8..cbe321e 100644
--- a/tempest/scenario/test_object_storage_basic_ops.py
+++ b/tempest/scenario/test_object_storage_basic_ops.py
@@ -58,12 +58,18 @@
         5. Delete the object and container
         """
         container_name = self.create_container()
-        obj_name, _ = self.upload_object_to_container(container_name)
+        obj_name, obj_data = self.upload_object_to_container(container_name)
         obj_url = '%s/%s/%s' % (self.object_client.base_url,
                                 container_name, obj_name)
         resp, _ = self.object_client.raw_request(obj_url, 'GET')
         self.assertEqual(resp.status, 401)
-
-        self.change_container_acl(container_name, '.r:*')
-        resp, _ = self.object_client.raw_request(obj_url, 'GET')
+        metadata_param = {'X-Container-Read': '.r:*'}
+        self.container_client.create_update_or_delete_container_metadata(
+            container_name, create_update_metadata=metadata_param,
+            create_update_metadata_prefix='')
+        resp, _ = self.container_client.list_container_metadata(container_name)
+        self.assertEqual(metadata_param['X-Container-Read'],
+                         resp['x-container-read'])
+        resp, data = self.object_client.raw_request(obj_url, 'GET')
         self.assertEqual(resp.status, 200)
+        self.assertEqual(obj_data, data)