Merge "Fix the docstring of skip_unless_config()"
diff --git a/HACKING.rst b/HACKING.rst
index 4095c4b..b66fa24 100644
--- a/HACKING.rst
+++ b/HACKING.rst
@@ -16,7 +16,7 @@
 - [T107] Check that a service tag isn't in the module path
 - [T108] Check no hyphen at the end of rand_name() argument
 - [T109] Cannot use testtools.skip decorator; instead use
-         decorators.skip_because from tempest-lib
+         decorators.skip_because from tempest.lib
 - [T110] Check that service client names of GET should be consistent
 - [T111] Check that service client names of DELETE should be consistent
 - [T112] Check that tempest.lib should not import local tempest code
@@ -157,33 +157,7 @@
 
 Negative Tests
 --------------
-Newly added negative tests should use the negative test framework. First step
-is to create an interface description in a python file under
-`tempest/api_schema/request/`. These descriptions consists of two important
-sections for the test (one of those is mandatory):
-
- - A resource (part of the URL of the request): Resources needed for a test
-   must be created in `setUpClass` and registered with `set_resource` e.g.:
-   `cls.set_resource("server", server['id'])`
-
- - A json schema: defines properties for a request.
-
-After that a test class must be added to automatically generate test scenarios
-out of the given interface description::
-
-    load_tests = test.NegativeAutoTest.load_tests
-
-    @test.SimpleNegativeAutoTest
-    class SampleTestNegativeTestJSON(<your base class>, test.NegativeAutoTest):
-        _service = 'compute'
-        _schema = <your schema file>
-
-The class decorator `SimpleNegativeAutoTest` will automatically generate test
-cases out of the given schema in the attribute `_schema`.
-
-All negative tests should be added into a separate negative test file.
-If such a file doesn't exist for the particular resource being tested a new
-test file should be added.
+TODO: Write the guideline related to negative tests.
 
 Test skips because of Known Bugs
 --------------------------------
@@ -333,9 +307,9 @@
         # The created server should be in the detailed list of all servers
         ...
 
-Tempest-lib includes a ``check-uuid`` tool that will test for the existence
+Tempest.lib includes a ``check-uuid`` tool that will test for the existence
 and uniqueness of idempotent_id metadata for every test. If you have
-tempest-lib installed you run the tool against Tempest by calling from the
+tempest installed you run the tool against Tempest by calling from the
 tempest repo::
 
     check-uuid
diff --git a/README.rst b/README.rst
index 7da83cd..650a1ed 100644
--- a/README.rst
+++ b/README.rst
@@ -58,7 +58,7 @@
 #. You first need to install Tempest. This is done with pip after you check out
    the Tempest repo::
 
-    $ git clone https://github.com/openstack/tempest/
+    $ git clone http://git.openstack.org/openstack/tempest
     $ pip install tempest/
 
    This can be done within a venv, but the assumption for this guide is that
@@ -71,14 +71,14 @@
    it's recommended that you copy or rename tempest.conf.sample to tempest.conf
    and make those changes to that file in /etc/tempest
 
-#. Setup a local working Tempest dir. This is done using the tempest init
+#. Setup a local working Tempest dir. This is done by using the tempest init
    command::
 
-    tempest init cloud-01
+    $ tempest init cloud-01
 
    works the same as::
 
-    mkdir cloud-01 && cd cloud-01 && tempest init
+    $ mkdir cloud-01 && cd cloud-01 && tempest init
 
    This will create a new directory for running a single Tempest configuration.
    If you'd like to run Tempest against multiple OpenStack deployments the idea
diff --git a/doc/source/configuration.rst b/doc/source/configuration.rst
index 245386b..bcb1e3e 100644
--- a/doc/source/configuration.rst
+++ b/doc/source/configuration.rst
@@ -9,23 +9,38 @@
 config file which explains the purpose of each individual option. You can see
 the sample config file here: :ref:`tempest-sampleconf`
 
-Auth/Credentials
+Test Credentials
 ----------------
 
-Tempest currently has two different ways in configuration to provide credentials
-to use when running Tempest. One is a traditional set of configuration options
-in the tempest.conf file. These options are clearly labelled in the ``identity``
-section and let you specify a set of credentials for a regular user, a global
-admin user, and an alternate user, consisting of a username, password, and
-project name.
+Tempest allows for configuring a set of admin credentials in the ``auth``
+section, via the following parameters:
 
-The other method to provide credentials is using the accounts.yaml file. This
-file is used to specify an arbitrary number of users available to run tests
-with. You can specify the location of the file in the ``auth`` section in the
+ #. ``admin_username``
+ #. ``admin_password``
+ #. ``admin_project_name``
+ #. ``admin_domain_name``
+
+Admin credentials are not mandatory to run Tempest, but when provided they
+can be used to:
+
+- Run tests for admin APIs
+- Generate test credentials on the fly (see `Dynamic Credentials`_)
+
+Tempest allows for configuring pre-provisioned test credentials as well.
+This can be done in two different ways.
+
+One is to provide credentials is using the accounts.yaml file (see
+`Pre-Provisioned Credentials`_). This file is used to specify an arbitrary
+number of users available to run tests with.
+You can specify the location of the file in the ``auth`` section in the
 tempest.conf file. To see the specific format used in the file please refer to
-the accounts.yaml.sample file included in Tempest.  Eventually the config
-options for providing credentials to Tempest will be deprecated and removed in
-favor of the accounts.yaml file.
+the accounts.yaml.sample file included in Tempest.
+
+A second way - now deprecated - is a set of configuration options in the
+tempest.conf file (see `Legacy Credentials`_). These options are clearly
+labelled in the ``identity`` section and let you specify a set of credentials
+for a regular user and an alternate user, consisting of a username, password,
+project and domain name.
 
 Keystone Connection Info
 ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -81,8 +96,9 @@
 configured to use dynamic credentials.
 
 
-Pre-Provisioned Credentials (aka accounts.yaml or accounts file)
-""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
+Pre-Provisioned Credentials
+"""""""""""""""""""""""""""
+
 For a long time using dynamic credentials was the only method available if you
 wanted to enable parallel execution of Tempest tests. However, this was
 insufficient for certain use cases because of the admin credentials requirement
@@ -116,9 +132,10 @@
 to the tests using the credentials, and failure to do this will likely cause
 unexpected failures in some tests.
 
+Pre-Provisioned Credentials are also know as accounts.yaml or accounts file.
 
-Legacy Credentials (aka credentials config options)
-"""""""""""""""""""""""""""""""""""""""""""""""""""
+Legacy Credentials
+""""""""""""""""""
 **Starting in the Liberty release this mechanism was deprecated; it will be
 removed in a future release.**
 
@@ -132,9 +149,6 @@
  #. ``username``
  #. ``password``
  #. ``project_name``
- #. ``admin_username``
- #. ``admin_password``
- #. ``admin_project_name``
  #. ``alt_username``
  #. ``alt_password``
  #. ``alt_project_name``
diff --git a/doc/source/library.rst b/doc/source/library.rst
index 64bd2c2..a89512c 100644
--- a/doc/source/library.rst
+++ b/doc/source/library.rst
@@ -7,15 +7,14 @@
 test suites an interface for reusing pieces of tempest code. Any public
 interface that lives in tempest/lib in the tempest repo is treated as a stable
 public interface and it should be safe to external consume that. Every effort
-goes into maintaining backwards compatibility with any change. Just as with
-tempest-lib the library is self contained and doesn't have any dependency on
-other tempest internals outside of lib. (including no usage of tempest
-configuration)
+goes into maintaining backwards compatibility with any change.
+The library is self contained and doesn't have any dependency on
+other tempest internals outside of lib (including no usage of tempest
+configuration).
 
 Stability
 ---------
-Just as tempest-lib before it any code that lives in tempest/lib will be treated
-as a stable interface, nothing has changed in regards to interface stability.
+Any code that lives in tempest/lib will be treated as a stable interface.
 This means that any public interface under the tempest/lib directory is
 expected to be a stable interface suitable for public consumption. However, for
 any interfaces outside of tempest/lib in the tempest tree (unless otherwise
diff --git a/doc/source/plugin.rst b/doc/source/plugin.rst
index 2622c22..ad26741 100644
--- a/doc/source/plugin.rst
+++ b/doc/source/plugin.rst
@@ -11,13 +11,13 @@
 =================
 
 Creating a plugin is fairly straightforward and doesn't require much additional
-effort on top of creating a test suite using tempest-lib. One thing to note with
+effort on top of creating a test suite using tempest.lib. One thing to note with
 doing this is that the interfaces exposed by tempest are not considered stable
 (with the exception of configuration variables which ever effort goes into
 ensuring backwards compatibility). You should not need to import anything from
 tempest itself except where explicitly noted. If there is an interface from
 tempest that you need to rely on in your plugin it likely needs to be migrated
-to tempest-lib. In that situation, file a bug, push a migration patch, etc. to
+to tempest.lib. In that situation, file a bug, push a migration patch, etc. to
 expedite providing the interface in a reliable manner.
 
 Plugin Cookiecutter
@@ -102,11 +102,6 @@
 Then you need to ensure you locally define all of the methods in the abstract
 class, you can refer to the api doc below for a reference of what that entails.
 
-Also, note eventually this abstract class will likely live in tempest-lib, when
-that migration occurs a deprecation shim will be added to tempest so as to not
-break any existing plugins. But, when that occurs migrating to using tempest-lib
-as the source for the abstract class will be prudent.
-
 Abstract Plugin Class
 ---------------------
 
diff --git a/requirements.txt b/requirements.txt
index 79ae42e..dd73257 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -3,7 +3,6 @@
 # process, which may cause wedges in the gate later.
 pbr>=1.6 # Apache-2.0
 cliff!=1.16.0,!=1.17.0,>=1.15.0 # Apache-2.0
-anyjson>=0.3.3 # BSD
 jsonschema!=2.5.0,<3.0.0,>=2.0.0 # MIT
 testtools>=1.4.0 # MIT
 paramiko>=1.16.0 # LGPL
@@ -17,7 +16,6 @@
 oslo.serialization>=1.10.0 # Apache-2.0
 oslo.utils>=3.5.0 # Apache-2.0
 six>=1.9.0 # MIT
-iso8601>=0.1.9 # MIT
 fixtures<2.0,>=1.3.1 # Apache-2.0/BSD
 testscenarios>=0.4 # Apache-2.0/BSD
 PyYAML>=3.1.0 # MIT
diff --git a/tempest/api/compute/admin/test_hosts.py b/tempest/api/compute/admin/test_hosts.py
index f6ea3a4..a9e9644 100644
--- a/tempest/api/compute/admin/test_hosts.py
+++ b/tempest/api/compute/admin/test_hosts.py
@@ -49,7 +49,7 @@
     @test.idempotent_id('c6ddbadb-c94e-4500-b12f-8ffc43843ff8')
     def test_list_hosts_with_nonexistent_zone(self):
         # If send the request with a nonexistent zone, the request will be
-        # successful and no hosts will be retured
+        # successful and no hosts will be returned
         hosts = self.client.list_hosts(zone='xxx')['hosts']
         self.assertEqual(0, len(hosts))
 
diff --git a/tempest/api/compute/admin/test_migrations.py b/tempest/api/compute/admin/test_migrations.py
index f81d665..6113c04 100644
--- a/tempest/api/compute/admin/test_migrations.py
+++ b/tempest/api/compute/admin/test_migrations.py
@@ -15,8 +15,10 @@
 import testtools
 
 from tempest.api.compute import base
+from tempest.common.utils import data_utils
 from tempest.common import waiters
 from tempest import config
+from tempest.lib import exceptions
 from tempest import test
 
 CONF = config.CONF
@@ -28,6 +30,7 @@
     def setup_clients(cls):
         super(MigrationsAdminTest, cls).setup_clients()
         cls.client = cls.os_adm.migrations_client
+        cls.flavors_admin_client = cls.os_adm.flavors_client
 
     @test.idempotent_id('75c0b83d-72a0-4cf8-a153-631e83e7d53f')
     def test_list_migrations(self):
@@ -53,3 +56,50 @@
 
         instance_uuids = [x['instance_uuid'] for x in body]
         self.assertIn(server_id, instance_uuids)
+
+    def _flavor_clean_up(self, flavor_id):
+        try:
+            self.flavors_admin_client.delete_flavor(flavor_id)
+            self.flavors_admin_client.wait_for_resource_deletion(flavor_id)
+        except exceptions.NotFound:
+            pass
+
+    @test.idempotent_id('33f1fec3-ba18-4470-8e4e-1d888e7c3593')
+    @testtools.skipUnless(CONF.compute_feature_enabled.resize,
+                          'Resize not available.')
+    def test_resize_server_revert_deleted_flavor(self):
+        # Tests that we can revert the resize on an instance whose original
+        # flavor has been deleted.
+
+        # First we have to create a flavor that we can delete so make a copy
+        # of the normal flavor from which we'd create a server.
+        flavor = self.flavors_admin_client.show_flavor(
+            self.flavor_ref)['flavor']
+        flavor = self.flavors_admin_client.create_flavor(
+            name=data_utils.rand_name('test_resize_flavor_'),
+            ram=flavor['ram'],
+            disk=flavor['disk'],
+            vcpus=flavor['vcpus']
+        )['flavor']
+        self.addCleanup(self._flavor_clean_up, flavor['id'])
+
+        # Now boot a server with the copied flavor.
+        server = self.create_test_server(
+            wait_until='ACTIVE', flavor=flavor['id'])
+
+        # Delete the flavor we used to boot the instance.
+        self._flavor_clean_up(flavor['id'])
+
+        # Now resize the server and wait for it to go into verify state.
+        self.servers_client.resize_server(server['id'], self.flavor_ref_alt)
+        waiters.wait_for_server_status(self.servers_client, server['id'],
+                                       'VERIFY_RESIZE')
+
+        # Now revert the resize, it should be OK even though the original
+        # flavor used to boot the server was deleted.
+        self.servers_client.revert_resize_server(server['id'])
+        waiters.wait_for_server_status(self.servers_client, server['id'],
+                                       'ACTIVE')
+
+        server = self.servers_client.show_server(server['id'])['server']
+        self.assertEqual(flavor['id'], server['flavor']['id'])
diff --git a/tempest/api/compute/admin/test_quotas.py b/tempest/api/compute/admin/test_quotas.py
index 2907e26..b1f0755 100644
--- a/tempest/api/compute/admin/test_quotas.py
+++ b/tempest/api/compute/admin/test_quotas.py
@@ -185,7 +185,7 @@
         # increment all of the values for updating the default quota class
         for quota, default in six.iteritems(body):
             # NOTE(sdague): we need to increment a lot, otherwise
-            # there is a real chance that we go from -1 (unlimitted)
+            # there is a real chance that we go from -1 (unlimited)
             # to a very small number which causes issues.
             body[quota] = default + 100
         LOG.debug("update limits for the default quota class set")
diff --git a/tempest/api/compute/admin/test_servers_on_multinodes.py b/tempest/api/compute/admin/test_servers_on_multinodes.py
index 814a876..1bbde98 100644
--- a/tempest/api/compute/admin/test_servers_on_multinodes.py
+++ b/tempest/api/compute/admin/test_servers_on_multinodes.py
@@ -12,6 +12,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import testtools
+
 from tempest.api.compute import base
 from tempest import config
 from tempest import test
@@ -34,6 +36,9 @@
             server_id)['server']['OS-EXT-SRV-ATTR:host']
 
     @test.idempotent_id('26a9d5df-6890-45f2-abc4-a659290cb130')
+    @testtools.skipUnless(
+        test.is_scheduler_filter_enabled("SameHostFilter"),
+        'SameHostFilter is not available.')
     def test_create_servers_on_same_host(self):
         server01 = self.create_test_server(wait_until='ACTIVE')['id']
 
@@ -45,6 +50,9 @@
         self.assertEqual(host01, host02)
 
     @test.idempotent_id('cc7ca884-6e3e-42a3-a92f-c522fcf25e8e')
+    @testtools.skipUnless(
+        test.is_scheduler_filter_enabled("DifferentHostFilter"),
+        'DifferentHostFilter is not available.')
     def test_create_servers_on_different_hosts(self):
         server01 = self.create_test_server(wait_until='ACTIVE')['id']
 
@@ -56,6 +64,9 @@
         self.assertNotEqual(host01, host02)
 
     @test.idempotent_id('7869cc84-d661-4e14-9f00-c18cdc89cf57')
+    @testtools.skipUnless(
+        test.is_scheduler_filter_enabled("DifferentHostFilter"),
+        'DifferentHostFilter is not available.')
     def test_create_servers_on_different_hosts_with_list_of_servers(self):
         server01 = self.create_test_server(wait_until='ACTIVE')['id']
 
diff --git a/tempest/api/compute/servers/test_create_server.py b/tempest/api/compute/servers/test_create_server.py
index 87f3c86..c05045e 100644
--- a/tempest/api/compute/servers/test_create_server.py
+++ b/tempest/api/compute/servers/test_create_server.py
@@ -119,7 +119,9 @@
             self.get_server_ip(self.server),
             self.ssh_user,
             self.password,
-            self.validation_resources['keypair']['private_key'])
+            self.validation_resources['keypair']['private_key'],
+            server=self.server,
+            servers_client=self.client)
         self.assertEqual(flavor['vcpus'], linux_client.get_number_of_vcpus())
 
     @test.idempotent_id('ac1ad47f-984b-4441-9274-c9079b7a0666')
@@ -131,7 +133,9 @@
             self.get_server_ip(self.server),
             self.ssh_user,
             self.password,
-            self.validation_resources['keypair']['private_key'])
+            self.validation_resources['keypair']['private_key'],
+            server=self.server,
+            servers_client=self.client)
         self.assertTrue(linux_client.hostname_equals_servername(self.name))
 
     @test.idempotent_id('ed20d3fb-9d1f-4329-b160-543fbd5d9811')
@@ -322,7 +326,9 @@
             self.get_server_ip(server_no_eph_disk),
             self.ssh_user,
             admin_pass,
-            self.validation_resources['keypair']['private_key'])
+            self.validation_resources['keypair']['private_key'],
+            server=server_no_eph_disk,
+            servers_client=self.client)
         partition_num = len(linux_client.get_partitions().split('\n'))
 
         # Explicit server deletion necessary for Juno compatibility
@@ -340,7 +346,9 @@
             self.get_server_ip(server_with_eph_disk),
             self.ssh_user,
             admin_pass,
-            self.validation_resources['keypair']['private_key'])
+            self.validation_resources['keypair']['private_key'],
+            server=server_with_eph_disk,
+            servers_client=self.client)
         partition_num_emph = len(linux_client.get_partitions().split('\n'))
         self.assertEqual(partition_num + 1, partition_num_emph)
 
diff --git a/tempest/api/compute/servers/test_server_actions.py b/tempest/api/compute/servers/test_server_actions.py
index f3aa16a..f01657b 100644
--- a/tempest/api/compute/servers/test_server_actions.py
+++ b/tempest/api/compute/servers/test_server_actions.py
@@ -91,7 +91,9 @@
             linux_client = remote_client.RemoteClient(
                 self.get_server_ip(server),
                 self.ssh_user,
-                new_password)
+                new_password,
+                server=server,
+                servers_client=self.client)
             linux_client.validate_authentication()
 
     def _test_reboot_server(self, reboot_type):
@@ -102,7 +104,9 @@
                 self.get_server_ip(server),
                 self.ssh_user,
                 self.password,
-                self.validation_resources['keypair']['private_key'])
+                self.validation_resources['keypair']['private_key'],
+                server=server,
+                servers_client=self.client)
             boot_time = linux_client.get_boot_time()
 
         self.client.reboot_server(self.server_id, type=reboot_type)
@@ -114,7 +118,9 @@
                 self.get_server_ip(server),
                 self.ssh_user,
                 self.password,
-                self.validation_resources['keypair']['private_key'])
+                self.validation_resources['keypair']['private_key'],
+                server=server,
+                servers_client=self.client)
             new_boot_time = linux_client.get_boot_time()
             self.assertTrue(new_boot_time > boot_time,
                             '%s > %s' % (new_boot_time, boot_time))
@@ -183,7 +189,9 @@
                 self.get_server_ip(rebuilt_server),
                 self.ssh_user,
                 password,
-                self.validation_resources['keypair']['private_key'])
+                self.validation_resources['keypair']['private_key'],
+                server=rebuilt_server,
+                servers_client=self.client)
             linux_client.validate_authentication()
 
     @test.idempotent_id('30449a88-5aff-4f9b-9866-6ee9b17f906d')
diff --git a/tempest/api/compute/servers/test_server_personality.py b/tempest/api/compute/servers/test_server_personality.py
index 74d34a2..baa4f9a 100644
--- a/tempest/api/compute/servers/test_server_personality.py
+++ b/tempest/api/compute/servers/test_server_personality.py
@@ -66,7 +66,9 @@
             linux_client = remote_client.RemoteClient(
                 self.get_server_ip(server),
                 self.ssh_user, password,
-                self.validation_resources['keypair']['private_key'])
+                self.validation_resources['keypair']['private_key'],
+                server=server,
+                servers_client=self.client)
             self.assertEqual(file_contents,
                              linux_client.exec_command(
                                  'sudo cat %s' % file_path))
@@ -130,7 +132,9 @@
             linux_client = remote_client.RemoteClient(
                 self.get_server_ip(server),
                 self.ssh_user, password,
-                self.validation_resources['keypair']['private_key'])
+                self.validation_resources['keypair']['private_key'],
+                server=server,
+                servers_client=self.client)
             for i in person:
                 self.assertEqual(base64.b64decode(i['contents']),
                                  linux_client.exec_command(
diff --git a/tempest/api/compute/volumes/test_attach_volume.py b/tempest/api/compute/volumes/test_attach_volume.py
index 37423a3..fa3fdfe 100644
--- a/tempest/api/compute/volumes/test_attach_volume.py
+++ b/tempest/api/compute/volumes/test_attach_volume.py
@@ -84,6 +84,19 @@
                                        self.volume['id'], 'available')
 
         if shelve_server:
+            # NOTE(andreaf) If we are going to shelve a server, we should
+            # check first whether the server is ssh-able. Otherwise we won't
+            # be able to distinguish failures introduced by shelve from
+            # pre-existing ones. Also it's good to wait for cloud-init to be
+            # done and sshd server to be running before shelving to avoid
+            # breaking the VM
+            linux_client = remote_client.RemoteClient(
+                self.get_server_ip(self.server),
+                self.image_ssh_user,
+                self.admin_pass,
+                self.validation_resources['keypair']['private_key'])
+            linux_client.validate_authentication()
+            # If validation went ok, shelve the server
             compute.shelve_server(self.servers_client, self.server['id'])
 
         # Attach the volume to the server
@@ -116,7 +129,9 @@
             self.get_server_ip(self.server),
             self.image_ssh_user,
             self.admin_pass,
-            self.validation_resources['keypair']['private_key'])
+            self.validation_resources['keypair']['private_key'],
+            server=self.server,
+            servers_client=self.servers_client)
 
         partitions = linux_client.get_partitions()
         self.assertIn(self.device, partitions)
@@ -135,7 +150,9 @@
             self.get_server_ip(self.server),
             self.image_ssh_user,
             self.admin_pass,
-            self.validation_resources['keypair']['private_key'])
+            self.validation_resources['keypair']['private_key'],
+            server=self.server,
+            servers_client=self.servers_client)
 
         partitions = linux_client.get_partitions()
         self.assertNotIn(self.device, partitions)
@@ -179,7 +196,9 @@
             self.get_server_ip(self.server['id']),
             self.image_ssh_user,
             self.admin_pass,
-            self.validation_resources['keypair']['private_key'])
+            self.validation_resources['keypair']['private_key'],
+            server=self.server,
+            servers_client=self.servers_client)
 
         command = 'grep vd /proc/partitions | wc -l'
         nb_partitions = linux_client.exec_command(command).strip()
diff --git a/tempest/api/compute/volumes/test_volumes_list.py b/tempest/api/compute/volumes/test_volumes_list.py
index 990e429..f709c91 100644
--- a/tempest/api/compute/volumes/test_volumes_list.py
+++ b/tempest/api/compute/volumes/test_volumes_list.py
@@ -27,7 +27,7 @@
     # ensure that the backing file for the volume group that Nova uses
     # has space for at least 3 1G volumes!
     # If you are running a Devstack environment, ensure that the
-    # VOLUME_BACKING_FILE_SIZE is atleast 4G in your localrc
+    # VOLUME_BACKING_FILE_SIZE is at least 4G in your localrc
 
     @classmethod
     def skip_checks(cls):
diff --git a/tempest/api/database/flavors/test_flavors.py b/tempest/api/database/flavors/test_flavors.py
index bdb4383..bb7a0a4 100644
--- a/tempest/api/database/flavors/test_flavors.py
+++ b/tempest/api/database/flavors/test_flavors.py
@@ -27,6 +27,7 @@
 
     @test.attr(type='smoke')
     @test.idempotent_id('c94b825e-0132-4686-8049-8a4a2bc09525')
+    @decorators.skip_because(bug='1567134')
     def test_get_db_flavor(self):
         # The expected flavor details should be returned
         flavor = (self.client.show_db_flavor(self.db_flavor_ref)
@@ -38,6 +39,7 @@
 
     @test.attr(type='smoke')
     @test.idempotent_id('685025d6-0cec-4673-8a8d-995cb8e0d3bb')
+    @decorators.skip_because(bug='1567134')
     def test_list_db_flavors(self):
         flavor = (self.client.show_db_flavor(self.db_flavor_ref)
                   ['flavor'])
diff --git a/tempest/api/identity/v3/test_projects.py b/tempest/api/identity/v3/test_projects.py
index 995b77e..1574ab7 100644
--- a/tempest/api/identity/v3/test_projects.py
+++ b/tempest/api/identity/v3/test_projects.py
@@ -33,7 +33,7 @@
         # user can successfully authenticate using his credentials and
         # project name from received projects list
         for project in resp['projects']:
-            # 'user_domain_id' needs to be specified otherwise tempest_lib
+            # 'user_domain_id' needs to be specified otherwise tempest.lib
             # assumes it to be 'default'
             token_id, body = self.non_admin_token.get_token(
                 username=self.os.credentials.username,
diff --git a/tempest/api/identity/v3/test_tokens.py b/tempest/api/identity/v3/test_tokens.py
index 593bf2a..d5bed96 100644
--- a/tempest/api/identity/v3/test_tokens.py
+++ b/tempest/api/identity/v3/test_tokens.py
@@ -30,7 +30,7 @@
         password = creds.password
         user_domain_id = creds.user_domain_id
 
-        # 'user_domain_id' needs to be specified otherwise tempest_lib assumes
+        # 'user_domain_id' needs to be specified otherwise tempest.lib assumes
         # it to be 'default'
         token_id, resp = self.non_admin_token.get_token(
             user_id=user_id,
diff --git a/tempest/api/network/test_routers.py b/tempest/api/network/test_routers.py
index 3654b2e..46b068b 100644
--- a/tempest/api/network/test_routers.py
+++ b/tempest/api/network/test_routers.py
@@ -364,6 +364,23 @@
         self._verify_router_interface(router['id'], subnet02['id'],
                                       interface02['port_id'])
 
+    @test.idempotent_id('96522edf-b4b5-45d9-8443-fa11c26e6eff')
+    def test_router_interface_port_update_with_fixed_ip(self):
+        network = self.create_network()
+        subnet = self.create_subnet(network)
+        router = self._create_router(data_utils.rand_name('router-'))
+        fixed_ip = [{'subnet_id': subnet['id']}]
+        interface = self._add_router_interface_with_subnet_id(router['id'],
+                                                              subnet['id'])
+        self.assertIn('port_id', interface)
+        self.assertIn('subnet_id', interface)
+        port = self.ports_client.show_port(interface['port_id'])
+        self.assertEqual(port['port']['id'], interface['port_id'])
+        router_port = self.ports_client.update_port(port['port']['id'],
+                                                    fixed_ips=fixed_ip)
+        self.assertEqual(subnet['id'],
+                         router_port['port']['fixed_ips'][0]['subnet_id'])
+
     def _verify_router_interface(self, router_id, subnet_id, port_id):
         show_port_body = self.ports_client.show_port(port_id)
         interface_port = show_port_body['port']
diff --git a/tempest/api/volume/admin/test_multi_backend.py b/tempest/api/volume/admin/test_multi_backend.py
index f19717e..00acc7d 100644
--- a/tempest/api/volume/admin/test_multi_backend.py
+++ b/tempest/api/volume/admin/test_multi_backend.py
@@ -32,14 +32,9 @@
     @classmethod
     def resource_setup(cls):
         super(VolumeMultiBackendV2Test, cls).resource_setup()
-        # support 2 backends names, deprecated_for_removal.
-        # keep support 2 backend names, in case they are not empty
-        if CONF.volume.backend1_name and CONF.volume.backend2_name:
-            cls.backend_names = {CONF.volume.backend1_name,
-                                 CONF.volume.backend2_name}
-        else:
-            # read backend name from a list .
-            cls.backend_names = set(CONF.volume.backend_names)
+
+        # read backend name from a list .
+        cls.backend_names = set(CONF.volume.backend_names)
 
         cls.name_field = cls.special_fields['name_field']
         cls.volume_type_id_list = []
diff --git a/tempest/api/volume/admin/test_volume_types.py b/tempest/api/volume/admin/test_volume_types.py
index 7202881..6fc6f1c 100644
--- a/tempest/api/volume/admin/test_volume_types.py
+++ b/tempest/api/volume/admin/test_volume_types.py
@@ -28,9 +28,6 @@
         self.volumes_client.delete_volume(volume_id)
         self.volumes_client.wait_for_resource_deletion(volume_id)
 
-    def _delete_volume_type(self, volume_type_id):
-        self.volume_types_client.delete_volume_type(volume_type_id)
-
     @test.idempotent_id('9d9b28e3-1b2e-4483-a2cc-24aa0ea1de54')
     def test_volume_type_list(self):
         # List volume types.
@@ -54,7 +51,8 @@
                 name=vol_type_name,
                 extra_specs=extra_specs)['volume_type']
             volume_types.append(vol_type)
-            self.addCleanup(self._delete_volume_type, vol_type['id'])
+            self.addCleanup(self.volume_types_client.delete_volume_type,
+                            vol_type['id'])
         params = {self.name_field: vol_name,
                   'volume_type': volume_types[0]['id']}
 
@@ -103,7 +101,8 @@
             name=name,
             extra_specs=extra_specs)['volume_type']
         self.assertIn('id', body)
-        self.addCleanup(self._delete_volume_type, body['id'])
+        self.addCleanup(self.volume_types_client.delete_volume_type,
+                        body['id'])
         self.assertIn('name', body)
         self.assertEqual(body['name'], name,
                          "The created volume_type name is not equal "
@@ -130,7 +129,8 @@
         name = data_utils.rand_name("volume-type")
         body = self.volume_types_client.create_volume_type(
             name=name)['volume_type']
-        self.addCleanup(self._delete_volume_type, body['id'])
+        self.addCleanup(self.volume_types_client.delete_volume_type,
+                        body['id'])
 
         # Create encryption type
         encryption_type = self.volume_types_client.create_encryption_type(
diff --git a/tempest/cmd/init.py b/tempest/cmd/init.py
index ac67ce4..633b9e9 100644
--- a/tempest/cmd/init.py
+++ b/tempest/cmd/init.py
@@ -54,21 +54,28 @@
     real_prefix = getattr(sys, 'real_prefix', None)
     base_prefix = getattr(sys, 'base_prefix', None)
     prefix = sys.prefix
+    global_conf_dir = '/etc/tempest'
     if (real_prefix is None and
-            (base_prefix is None or base_prefix == prefix)):
+            (base_prefix is None or base_prefix == prefix) and
+            os.path.isdir(global_conf_dir)):
         # Probably not running in a virtual environment.
         # NOTE(andreaf) we cannot distinguish this case from the case of
         # a virtual environment created with virtualenv, and running python3.
         # Also if it appears we are not in virtual env and fail to find
         # global config: '/etc/tempest', fall back to
         # '[sys.prefix]/etc/tempest'
-        global_conf_dir = '/etc/tempest'
-        if os.path.isdir(global_conf_dir):
-            return global_conf_dir
-        else:
-            return os.path.join(prefix, 'etc/tempest')
+        return global_conf_dir
     else:
-        return os.path.join(prefix, 'etc/tempest')
+        conf_dir = os.path.join(prefix, 'etc/tempest')
+        if os.path.isdir(conf_dir):
+            return conf_dir
+        else:
+            # NOTE: The prefix is gotten from the path which pyconfig.h is
+            # installed under. Some envs contain it under /usr/include, not
+            # /user/local/include. Then prefix becomes /usr on such envs.
+            # However, etc/tempest is installed under /usr/local and the bove
+            # path logic mismatches. This is a workaround for such envs.
+            return os.path.join(prefix, 'local/etc/tempest')
 
 
 class TempestInit(command.Command):
@@ -78,6 +85,10 @@
         parser = super(TempestInit, self).get_parser(prog_name)
         parser.add_argument('dir', nargs='?', default=os.getcwd())
         parser.add_argument('--config-dir', '-c', default=None)
+        parser.add_argument('--show-global-config-dir', '-s',
+                            action='store_true', dest='show_global_dir',
+                            help="Print the global config dir location, "
+                                 "then exit")
         return parser
 
     def generate_testr_conf(self, local_path):
@@ -91,8 +102,7 @@
     def update_local_conf(self, conf_path, lock_dir, log_dir):
         config_parse = moves.configparser.SafeConfigParser()
         config_parse.optionxform = str
-        with open(conf_path, 'w+') as conf_file:
-            config_parse.readfp(conf_file)
+        with open(conf_path, 'a+') as conf_file:
             # Set local lock_dir in tempest conf
             if not config_parse.has_section('oslo_concurrency'):
                 config_parse.add_section('oslo_concurrency')
@@ -101,6 +111,7 @@
             config_parse.set('DEFAULT', 'log_dir', log_dir)
             # Set default log filename to tempest.log
             config_parse.set('DEFAULT', 'log_file', 'tempest.log')
+            config_parse.write(conf_file)
 
     def copy_config(self, etc_dir, config_dir):
         shutil.copytree(config_dir, etc_dir)
@@ -149,4 +160,7 @@
 
     def take_action(self, parsed_args):
         config_dir = parsed_args.config_dir or get_tempest_default_config_dir()
+        if parsed_args.show_global_dir:
+            print("Global config dir is located at: %s" % config_dir)
+            sys.exit(0)
         self.create_working_dir(parsed_args.dir, config_dir)
diff --git a/tempest/cmd/verify_tempest_config.py b/tempest/cmd/verify_tempest_config.py
index 3ef04f5..39fed63 100644
--- a/tempest/cmd/verify_tempest_config.py
+++ b/tempest/cmd/verify_tempest_config.py
@@ -16,6 +16,7 @@
 
 import argparse
 import os
+import re
 import sys
 import traceback
 
@@ -77,9 +78,16 @@
                             not CONF.image_feature_enabled.api_v2, update)
 
 
+def _remove_version_project(url_path):
+    # The regex matches strings like /v2.0, /v3/, /v2.1/project-id/
+    return re.sub(r'/v\d+(\.\d+)?(/[^/]+)?', '', url_path)
+
+
 def _get_unversioned_endpoint(base_url):
     endpoint_parts = urlparse.urlparse(base_url)
-    endpoint = endpoint_parts.scheme + '://' + endpoint_parts.netloc
+    new_path = _remove_version_project(endpoint_parts.path)
+    endpoint_parts = endpoint_parts._replace(path=new_path)
+    endpoint = urlparse.urlunparse(endpoint_parts)
     return endpoint
 
 
@@ -89,7 +97,9 @@
         'keystone': os.identity_client,
         'cinder': os.volumes_client,
     }
-    client_dict[service].skip_path()
+    if service != 'keystone':
+        # Since keystone may be listening on a path, do not remove the path.
+        client_dict[service].skip_path()
     endpoint = _get_unversioned_endpoint(client_dict[service].base_url)
 
     http = tempest.lib.common.http.ClosingHttp(
diff --git a/tempest/common/credentials_factory.py b/tempest/common/credentials_factory.py
index 58157ef..6cb43f3 100644
--- a/tempest/common/credentials_factory.py
+++ b/tempest/common/credentials_factory.py
@@ -26,7 +26,7 @@
 
 """This module provides factories of credential and credential providers
 
-Credentials providers and clients are (going to be) part of tempest-lib,
+Credentials providers and clients are (going to be) part of tempest.lib,
 and so they may not hold any dependency to tempest configuration.
 
 Methods in this module collect the relevant configuration details and pass
@@ -133,7 +133,7 @@
     def get_creds_by_roles(self, roles, force_new=False):
         msg = "Credentials being specified through the config file can not be"\
               " used with tests that specify using credentials by roles. "\
-              "Either exclude/skip the tests doing this or use either an "\
+              "Either exclude/skip the tests doing this or use either a "\
               "test_accounts_file or dynamic credentials."
         raise exceptions.InvalidConfiguration(msg)
 
diff --git a/tempest/common/preprov_creds.py b/tempest/common/preprov_creds.py
index f3df387..51f723b 100644
--- a/tempest/common/preprov_creds.py
+++ b/tempest/common/preprov_creds.py
@@ -219,9 +219,9 @@
         else:
             hashes = self.hash_dict['creds'].keys()
         # NOTE(mtreinish): admin is a special case because of the increased
-        # privlege set which could potentially cause issues on tests where that
-        # is not expected. So unless the admin role isn't specified do not
-        # allocate admin.
+        # privilege set which could potentially cause issues on tests where
+        # that is not expected. So unless the admin role isn't specified do
+        # not allocate admin.
         admin_hashes = self.hash_dict['roles'].get(self.admin_role,
                                                    None)
         if ((not roles or self.admin_role not in roles) and
diff --git a/tempest/common/utils/linux/remote_client.py b/tempest/common/utils/linux/remote_client.py
index 3a215a0..3f573b7 100644
--- a/tempest/common/utils/linux/remote_client.py
+++ b/tempest/common/utils/linux/remote_client.py
@@ -12,6 +12,8 @@
 
 import netaddr
 import re
+import six
+import sys
 import time
 
 from oslo_log import log as logging
@@ -19,6 +21,7 @@
 from tempest import config
 from tempest import exceptions
 from tempest.lib.common import ssh
+from tempest.lib.common.utils import misc as misc_utils
 import tempest.lib.exceptions
 
 CONF = config.CONF
@@ -26,16 +29,61 @@
 LOG = logging.getLogger(__name__)
 
 
+def debug_ssh(function):
+    """Decorator to generate extra debug info in case off SSH failure"""
+    def wrapper(self, *args, **kwargs):
+        try:
+            return function(self, *args, **kwargs)
+        except tempest.lib.exceptions.SSHTimeout:
+            try:
+                original_exception = sys.exc_info()
+                caller = misc_utils.find_test_caller() or "not found"
+                if self.server:
+                    msg = 'Caller: %s. Timeout trying to ssh to server %s'
+                    LOG.debug(msg, caller, self.server)
+                    if self.log_console and self.servers_client:
+                        try:
+                            msg = 'Console log for server %s: %s'
+                            console_log = (
+                                self.servers_client.get_console_output(
+                                    self.server['id'])['output'])
+                            LOG.debug(msg, self.server['id'], console_log)
+                        except Exception:
+                            msg = 'Could not get console_log for server %s'
+                            LOG.debug(msg, self.server['id'])
+                # re-raise the original ssh timeout exception
+                six.reraise(*original_exception)
+            finally:
+                # Delete the traceback to avoid circular references
+                _, _, trace = original_exception
+                del trace
+    return wrapper
+
+
 class RemoteClient(object):
 
-    def __init__(self, ip_address, username, password=None, pkey=None):
+    def __init__(self, ip_address, username, password=None, pkey=None,
+                 server=None, servers_client=None):
+        """Executes commands in a VM over ssh
+
+        :param ip_address: IP address to ssh to
+        :param username: ssh username
+        :param password: ssh password (optional)
+        :param pkey: ssh public key (optional)
+        :param server: server dict, used for debugging purposes
+        :param servers_client: servers client, used for debugging purposes
+        """
+        self.server = server
+        self.servers_client = servers_client
         ssh_timeout = CONF.validation.ssh_timeout
         connect_timeout = CONF.validation.connect_timeout
+        self.log_console = CONF.compute_feature_enabled.console_output
 
         self.ssh_client = ssh.Client(ip_address, username, password,
                                      ssh_timeout, pkey=pkey,
                                      channel_timeout=connect_timeout)
 
+    @debug_ssh
     def exec_command(self, cmd):
         # Shell options below add more clearness on failures,
         # path is extended for some non-cirros guest oses (centos7)
@@ -43,6 +91,7 @@
         LOG.debug("Remote command: %s" % cmd)
         return self.ssh_client.exec_command(cmd)
 
+    @debug_ssh
     def validate_authentication(self):
         """Validate ssh connection and authentication
 
diff --git a/tempest/config.py b/tempest/config.py
index 3d48304..3e0f28f 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -93,7 +93,7 @@
                     "create users and projects",
                deprecated_group='identity'),
     cfg.StrOpt('admin_project_name',
-               help="Project name to use for an  administrative user. This is "
+               help="Project name to use for an administrative user. This is "
                     "needed for authenticating requests made by project "
                     "isolation to create users and projects",
                deprecated_opts=[cfg.DeprecatedOpt('admin_tenant_name',
@@ -101,7 +101,7 @@
                                 cfg.DeprecatedOpt('admin_tenant_name',
                                                   group='identity')]),
     cfg.StrOpt('admin_password',
-               help="Password to use for an  administrative user. This is "
+               help="Password to use for an administrative user. This is "
                     "needed for authenticating requests made by project "
                     "isolation to create users and projects",
                secret=True,
@@ -702,22 +702,10 @@
                choices=['public', 'admin', 'internal',
                         'publicURL', 'adminURL', 'internalURL'],
                help="The endpoint type to use for the volume service."),
-    cfg.StrOpt('backend1_name',
-               default='',
-               help='Name of the backend1 (must be declared in cinder.conf)',
-               deprecated_for_removal=True),
-    cfg.StrOpt('backend2_name',
-               default='',
-               help='Name of the backend2 (must be declared in cinder.conf)',
-               deprecated_for_removal=True),
     cfg.ListOpt('backend_names',
                 default=['BACKEND_1', 'BACKEND_2'],
                 help='A list of backend names separated by comma. '
-                     'The backend name must be declared in cinder.conf',
-                deprecated_opts=[cfg.DeprecatedOpt('BACKEND_1',
-                                                   group='volume'),
-                                 cfg.DeprecatedOpt('BACKEND_2',
-                                                   group='volume')]),
+                     'The backend name must be declared in cinder.conf'),
     cfg.StrOpt('storage_protocol',
                default='iSCSI',
                help='Backend protocol to target when creating volume types'),
@@ -1161,7 +1149,7 @@
                                     'shelve, snapshot, and suspend')
 
 
-# NOTE(deva): Ironic tests have been ported to tempest-lib. New config options
+# NOTE(deva): Ironic tests have been ported to tempest.lib. New config options
 #             should be added to ironic/ironic_tempest_plugin/config.py.
 #             However, these options need to remain here for testing stable
 #             branches until Liberty release reaches EOL.
diff --git a/tempest/exceptions.py b/tempest/exceptions.py
index b8e052f..92f335f 100644
--- a/tempest/exceptions.py
+++ b/tempest/exceptions.py
@@ -116,7 +116,7 @@
 
 
 # NOTE(andreaf) This exception is added here to facilitate the migration
-# of get_network_from_name and preprov_creds to tempest-lib, and it should
+# of get_network_from_name and preprov_creds to tempest.lib, and it should
 # be migrated along with them
 class InvalidTestResource(TempestException):
     message = "%(name) is not a valid %(type), or the name is ambiguous"
diff --git a/tempest/hacking/checks.py b/tempest/hacking/checks.py
index d0e1fcb..5943adf 100644
--- a/tempest/hacking/checks.py
+++ b/tempest/hacking/checks.py
@@ -141,7 +141,7 @@
     """
     if TESTTOOLS_SKIP_DECORATOR.match(logical_line):
         yield (0, "T109: Cannot use testtools.skip decorator; instead use "
-               "decorators.skip_because from tempest-lib")
+               "decorators.skip_because from tempest.lib")
 
 
 def _common_service_clients_check(logical_line, physical_line, filename,
diff --git a/tempest/lib/cmd/skip_tracker.py b/tempest/lib/cmd/skip_tracker.py
index b7d6a24..f35b14c 100755
--- a/tempest/lib/cmd/skip_tracker.py
+++ b/tempest/lib/cmd/skip_tracker.py
@@ -48,7 +48,7 @@
 
 
 def find_skips(start):
-    """Find the entire list of skiped tests.
+    """Find the entire list of skipped tests.
 
     Returns a list of tuples (method, bug) that represent
     test methods that have been decorated to skip because of
diff --git a/tempest/lib/common/utils/data_utils.py b/tempest/lib/common/utils/data_utils.py
index 01b6477..9605479 100644
--- a/tempest/lib/common/utils/data_utils.py
+++ b/tempest/lib/common/utils/data_utils.py
@@ -39,7 +39,7 @@
 
 
 def rand_name(name='', prefix=None):
-    """Generate a random name that inclues a random number
+    """Generate a random name that includes a random number
 
     :param str name: The name that you want to include
     :param str prefix: The prefix that you want to include
@@ -81,7 +81,7 @@
 
 
 def rand_url():
-    """Generate a random url that inclues a random number
+    """Generate a random url that includes a random number
 
     :return: a random url. The format is 'https://url-<random number>.com'.
              (e.g. 'https://url-154876201.com')
@@ -121,6 +121,18 @@
     return ':'.join(["%02x" % x for x in mac])
 
 
+def rand_infiniband_guid_address():
+    """Generate an Infiniband GUID address
+
+    :return: an random Infiniband GUID address
+    :rtype: string
+    """
+    guid = []
+    for i in range(8):
+        guid.append("%02x" % random.randint(0x00, 0xff))
+    return ':'.join(guid)
+
+
 def parse_image_id(image_ref):
     """Return the image id from a given image ref
 
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 988ee1a..956fe88 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -29,7 +29,7 @@
 from tempest import exceptions
 from tempest.lib.common.utils import misc as misc_utils
 from tempest.lib import exceptions as lib_exc
-from tempest.services.network import resources as net_resources
+from tempest.scenario import network_resources
 import tempest.test
 
 CONF = config.CONF
@@ -648,7 +648,7 @@
         """
         if CONF.validation.connect_method == 'floating':
             # The tests calling this method don't have a floating IP
-            # and can't make use of the validattion resources. So the
+            # and can't make use of the validation resources. So the
             # method is creating the floating IP there.
             return self.create_floating_ip(server)['ip']
         elif CONF.validation.connect_method == 'fixed':
@@ -697,7 +697,7 @@
             tenant_id = networks_client.tenant_id
         name = data_utils.rand_name(namestart)
         result = networks_client.create_network(name=name, tenant_id=tenant_id)
-        network = net_resources.DeletableNetwork(
+        network = network_resources.DeletableNetwork(
             networks_client=networks_client, routers_client=routers_client,
             **result['network'])
         self.assertEqual(network.name, name)
@@ -790,7 +790,7 @@
                 if not is_overlapping_cidr:
                     raise
         self.assertIsNotNone(result, 'Unable to allocate tenant network')
-        subnet = net_resources.DeletableSubnet(
+        subnet = network_resources.DeletableSubnet(
             subnets_client=subnets_client,
             routers_client=routers_client, **result['subnet'])
         self.assertEqual(subnet.cidr, str_cidr)
@@ -807,8 +807,8 @@
             network_id=network_id,
             **kwargs)
         self.assertIsNotNone(result, 'Unable to allocate port')
-        port = net_resources.DeletablePort(ports_client=client,
-                                           **result['port'])
+        port = network_resources.DeletablePort(ports_client=client,
+                                               **result['port'])
         self.addCleanup(self.delete_wrapper, port.delete)
         return port
 
@@ -838,7 +838,7 @@
         net = self._list_networks(name=network_name)
         self.assertNotEqual(len(net), 0,
                             "Unable to get network by name: %s" % network_name)
-        return net_resources.AttributeDict(net[0])
+        return network_resources.AttributeDict(net[0])
 
     def create_floating_ip(self, thing, external_network_id=None,
                            port_id=None, client=None):
@@ -857,7 +857,7 @@
             tenant_id=thing['tenant_id'],
             fixed_ip_address=ip4
         )
-        floating_ip = net_resources.DeletableFloatingIp(
+        floating_ip = network_resources.DeletableFloatingIp(
             client=client,
             **result['floatingip'])
         self.addCleanup(self.delete_wrapper, floating_ip.delete)
@@ -878,8 +878,8 @@
     def check_floating_ip_status(self, floating_ip, status):
         """Verifies floatingip reaches the given status
 
-        :param floating_ip: net_resources.DeletableFloatingIp floating IP to
-        to check status
+        :param floating_ip: network_resources.DeletableFloatingIp floating
+        IP to check status
         :param status: target status
         :raises: AssertionError if status doesn't match
         """
@@ -991,7 +991,7 @@
                        description=sg_desc)
         sg_dict['tenant_id'] = tenant_id
         result = client.create_security_group(**sg_dict)
-        secgroup = net_resources.DeletableSecurityGroup(
+        secgroup = network_resources.DeletableSecurityGroup(
             client=client, routers_client=self.routers_client,
             **result['security_group']
         )
@@ -1016,8 +1016,8 @@
         ]
         msg = "No default security group for tenant %s." % (tenant_id)
         self.assertTrue(len(sgs) > 0, msg)
-        return net_resources.DeletableSecurityGroup(client=client,
-                                                    **sgs[0])
+        return network_resources.DeletableSecurityGroup(client=client,
+                                                        **sgs[0])
 
     def _create_security_group_rule(self, secgroup=None,
                                     sec_group_rules_client=None,
@@ -1055,7 +1055,7 @@
         ruleset.update(kwargs)
 
         sg_rule = sec_group_rules_client.create_security_group_rule(**ruleset)
-        sg_rule = net_resources.DeletableSecurityGroupRule(
+        sg_rule = network_resources.DeletableSecurityGroupRule(
             client=sec_group_rules_client,
             **sg_rule['security_group_rule']
         )
@@ -1135,7 +1135,7 @@
         network_id = CONF.network.public_network_id
         if router_id:
             body = client.show_router(router_id)
-            return net_resources.AttributeDict(**body['router'])
+            return network_resources.AttributeDict(**body['router'])
         elif network_id:
             router = self._create_router(client, tenant_id)
             router.set_gateway(network_id)
@@ -1154,8 +1154,8 @@
         result = client.create_router(name=name,
                                       admin_state_up=True,
                                       tenant_id=tenant_id)
-        router = net_resources.DeletableRouter(routers_client=client,
-                                               **result['router'])
+        router = network_resources.DeletableRouter(routers_client=client,
+                                                   **result['router'])
         self.assertEqual(router.name, name)
         self.addCleanup(self.delete_wrapper, router.delete)
         return router
diff --git a/tempest/services/network/resources.py b/tempest/scenario/network_resources.py
similarity index 98%
rename from tempest/services/network/resources.py
rename to tempest/scenario/network_resources.py
index 329c54d..667476f 100644
--- a/tempest/services/network/resources.py
+++ b/tempest/scenario/network_resources.py
@@ -76,7 +76,7 @@
         """Waits for a network resource to reach a status
 
         @param fetch: the callable to be used to query the resource status
-        @type fecth: callable that takes no parameters and returns the resource
+        @type fetch: callable that takes no parameters and returns the resource
         @param status: the status that the resource has to reach
         @type status: String
         """
diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
index dfa4815..b9fdd18 100644
--- a/tempest/scenario/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -24,7 +24,7 @@
 from tempest import config
 from tempest import exceptions
 from tempest.scenario import manager
-from tempest.services.network import resources as net_resources
+from tempest.scenario import network_resources
 from tempest import test
 
 CONF = config.CONF
@@ -269,8 +269,9 @@
                 "Old port: %s. Number of new ports: %d" % (
                     CONF.network.build_timeout, old_port,
                     len(self.new_port_list)))
-        new_port = net_resources.DeletablePort(ports_client=self.ports_client,
-                                               **self.new_port_list[0])
+        new_port = network_resources.DeletablePort(
+            ports_client=self.ports_client,
+            **self.new_port_list[0])
 
         def check_new_nic():
             new_nic_list = self._get_server_nics(ssh_client)
@@ -686,8 +687,9 @@
         unschedule_router = (self.admin_manager.network_agents_client.
                              delete_router_from_l3_agent)
 
-        agent_list = set(a["id"] for a in
-                         self._list_agents(agent_type="L3 agent"))
+        agent_list_alive = set(a["id"] for a in
+                               self._list_agents(agent_type="L3 agent") if
+                               a["alive"] is True)
         self._setup_network_and_servers()
 
         # NOTE(kevinbenton): we have to use the admin credentials to check
@@ -702,7 +704,7 @@
         # remove resource from agents
         hosting_agents = set(a["id"] for a in
                              list_hosts(self.router.id)['agents'])
-        no_migration = agent_list == hosting_agents
+        no_migration = agent_list_alive == hosting_agents
         LOG.info("Router will be assigned to {mig} hosting agent".
                  format(mig="the same" if no_migration else "a new"))
 
@@ -722,7 +724,7 @@
 
         # schedule resource to new agent
         target_agent = list(hosting_agents if no_migration else
-                            agent_list - hosting_agents)[0]
+                            agent_list_alive - hosting_agents)[0]
         schedule_router(target_agent,
                         router_id=self.router['id'])
         self.assertEqual(
diff --git a/tempest/services/object_storage/object_client.py b/tempest/services/object_storage/object_client.py
index 78bda5d..0acd4ad 100644
--- a/tempest/services/object_storage/object_client.py
+++ b/tempest/services/object_storage/object_client.py
@@ -150,9 +150,6 @@
 
     def put_object_with_chunk(self, container, name, contents, chunk_size):
         """Put an object with Transfer-Encoding header"""
-        if self.base_url is None:
-            self._set_auth()
-
         headers = {'Transfer-Encoding': 'chunked'}
         if self.token:
             headers['X-Auth-Token'] = self.token
@@ -182,8 +179,6 @@
         if not data:
             headers['content-length'] = '0'
 
-        if self.base_url is None:
-            self._set_auth()
         headers['X-Auth-Token'] = self.token
 
         conn = put_object_connection(self.base_url, str(container),
diff --git a/tempest/tests/cmd/test_verify_tempest_config.py b/tempest/tests/cmd/test_verify_tempest_config.py
index 3b09673..70cbf87 100644
--- a/tempest/tests/cmd/test_verify_tempest_config.py
+++ b/tempest/tests/cmd/test_verify_tempest_config.py
@@ -12,28 +12,56 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-
 import mock
 from oslo_serialization import jsonutils as json
 from oslotest import mockpatch
 
 from tempest.cmd import verify_tempest_config
 from tempest import config
+from tempest.lib.common.utils import data_utils
 from tempest.tests import base
 from tempest.tests import fake_config
 
 
 class TestGetAPIVersions(base.TestCase):
 
+    def test_remove_version_project(self):
+        f = verify_tempest_config._remove_version_project
+        self.assertEqual('/', f('/v2.1/%s/' % data_utils.rand_uuid_hex()))
+        self.assertEqual('', f('/v2.1/tenant_id'))
+        self.assertEqual('', f('/v3'))
+        self.assertEqual('/', f('/v3/'))
+        self.assertEqual('/something/', f('/something/v2.1/tenant_id/'))
+        self.assertEqual('/something', f('/something/v2.1/tenant_id'))
+        self.assertEqual('/something', f('/something/v3'))
+        self.assertEqual('/something/', f('/something/v3/'))
+        self.assertEqual('/', f('/'))  # http://localhost/
+        self.assertEqual('', f(''))  # http://localhost
+
     def test_url_grab_versioned_nova_nossl(self):
         base_url = 'http://127.0.0.1:8774/v2/'
         endpoint = verify_tempest_config._get_unversioned_endpoint(base_url)
-        self.assertEqual('http://127.0.0.1:8774', endpoint)
+        self.assertEqual('http://127.0.0.1:8774/', endpoint)
 
     def test_url_grab_versioned_nova_ssl(self):
         base_url = 'https://127.0.0.1:8774/v3/'
         endpoint = verify_tempest_config._get_unversioned_endpoint(base_url)
-        self.assertEqual('https://127.0.0.1:8774', endpoint)
+        self.assertEqual('https://127.0.0.1:8774/', endpoint)
+
+    def test_get_unversioned_endpoint_base(self):
+        base_url = 'https://127.0.0.1:5000/'
+        endpoint = verify_tempest_config._get_unversioned_endpoint(base_url)
+        self.assertEqual('https://127.0.0.1:5000/', endpoint)
+
+    def test_get_unversioned_endpoint_subpath(self):
+        base_url = 'https://127.0.0.1/identity/v3'
+        endpoint = verify_tempest_config._get_unversioned_endpoint(base_url)
+        self.assertEqual('https://127.0.0.1/identity', endpoint)
+
+    def test_get_unversioned_endpoint_subpath_trailing_solidus(self):
+        base_url = 'https://127.0.0.1/identity/v3/'
+        endpoint = verify_tempest_config._get_unversioned_endpoint(base_url)
+        self.assertEqual('https://127.0.0.1/identity/', endpoint)
 
 
 class TestDiscovery(base.TestCase):
diff --git a/tempest/tests/common/utils/linux/test_remote_client.py b/tempest/tests/common/utils/linux/test_remote_client.py
index e9146bc..7d625cf 100644
--- a/tempest/tests/common/utils/linux/test_remote_client.py
+++ b/tempest/tests/common/utils/linux/test_remote_client.py
@@ -12,6 +12,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import fixtures
 import time
 
 from oslo_config import cfg
@@ -19,10 +20,39 @@
 
 from tempest.common.utils.linux import remote_client
 from tempest import config
+from tempest.lib import exceptions as lib_exc
 from tempest.tests import base
 from tempest.tests import fake_config
 
 
+SERVER = {
+    'id': 'server_uuid',
+    'name': 'fake_server',
+    'status': 'ACTIVE'
+}
+
+BROKEN_SERVER = {
+    'id': 'broken_server_uuid',
+    'name': 'broken_server',
+    'status': 'ERROR'
+}
+
+
+class FakeServersClient(object):
+
+    CONSOLE_OUTPUT = "Console output for %s"
+
+    def get_console_output(self, server_id):
+        status = 'ERROR'
+        for s in SERVER, BROKEN_SERVER:
+            if s['id'] == server_id:
+                status = s['status']
+        if status == 'ERROR':
+            raise lib_exc.BadRequest('Server in ERROR state')
+        else:
+            return dict(output=self.CONSOLE_OUTPUT % server_id)
+
+
 class TestRemoteClient(base.TestCase):
     def setUp(self):
         super(TestRemoteClient, self).setUp()
@@ -155,3 +185,78 @@
         self.conn.set_nic_state(nic, "down")
         self._assert_exec_called_with(
             'sudo ip link set %s down' % nic)
+
+
+class TestRemoteClientWithServer(base.TestCase):
+
+    server = SERVER
+
+    def setUp(self):
+        super(TestRemoteClientWithServer, self).setUp()
+        self.useFixture(fake_config.ConfigFixture())
+        self.patchobject(config, 'TempestConfigPrivate',
+                         fake_config.FakePrivate)
+        cfg.CONF.set_default('ip_version_for_ssh', 4, group='validation')
+        cfg.CONF.set_default('network_for_ssh', 'public',
+                             group='validation')
+        cfg.CONF.set_default('connect_timeout', 1, group='validation')
+        cfg.CONF.set_default('console_output', True,
+                             group='compute-feature-enabled')
+
+        self.conn = remote_client.RemoteClient(
+            '127.0.0.1', 'user', 'pass',
+            server=self.server, servers_client=FakeServersClient())
+        self.useFixture(fixtures.MockPatch(
+            'tempest.lib.common.ssh.Client._get_ssh_connection',
+            side_effect=lib_exc.SSHTimeout(host='127.0.0.1',
+                                           user='user',
+                                           password='pass')))
+        self.log = self.useFixture(fixtures.FakeLogger(
+            name='tempest.common.utils.linux.remote_client',
+            level='DEBUG'))
+
+    def test_validate_debug_ssh_console(self):
+        self.assertRaises(lib_exc.SSHTimeout,
+                          self.conn.validate_authentication)
+        msg = 'Caller: %s. Timeout trying to ssh to server %s' % (
+            'TestRemoteClientWithServer:test_validate_debug_ssh_console',
+            self.server)
+        self.assertIn(msg, self.log.output)
+        self.assertIn('Console output for', self.log.output)
+
+    def test_exec_command_debug_ssh_console(self):
+        self.assertRaises(lib_exc.SSHTimeout,
+                          self.conn.exec_command, 'fake command')
+        self.assertIn('fake command', self.log.output)
+        msg = 'Caller: %s. Timeout trying to ssh to server %s' % (
+            'TestRemoteClientWithServer:test_exec_command_debug_ssh_console',
+            self.server)
+        self.assertIn(msg, self.log.output)
+        self.assertIn('Console output for', self.log.output)
+
+
+class TestRemoteClientWithBrokenServer(TestRemoteClientWithServer):
+
+    server = BROKEN_SERVER
+
+    def test_validate_debug_ssh_console(self):
+        self.assertRaises(lib_exc.SSHTimeout,
+                          self.conn.validate_authentication)
+        msg = 'Caller: %s. Timeout trying to ssh to server %s' % (
+            'TestRemoteClientWithBrokenServer:test_validate_debug_ssh_console',
+            self.server)
+        self.assertIn(msg, self.log.output)
+        msg = 'Could not get console_log for server %s' % self.server['id']
+        self.assertIn(msg, self.log.output)
+
+    def test_exec_command_debug_ssh_console(self):
+        self.assertRaises(lib_exc.SSHTimeout,
+                          self.conn.exec_command, 'fake command')
+        self.assertIn('fake command', self.log.output)
+        caller = ":".join(['TestRemoteClientWithBrokenServer',
+                           'test_exec_command_debug_ssh_console'])
+        msg = 'Caller: %s. Timeout trying to ssh to server %s' % (
+            caller, self.server)
+        self.assertIn(msg, self.log.output)
+        msg = 'Could not get console_log for server %s' % self.server['id']
+        self.assertIn(msg, self.log.output)
diff --git a/tempest/tests/lib/common/utils/test_data_utils.py b/tempest/tests/lib/common/utils/test_data_utils.py
index f435461..f9e1f44 100644
--- a/tempest/tests/lib/common/utils/test_data_utils.py
+++ b/tempest/tests/lib/common/utils/test_data_utils.py
@@ -93,6 +93,15 @@
         actual2 = data_utils.rand_int_id()
         self.assertNotEqual(actual, actual2)
 
+    def test_rand_infiniband_guid_address(self):
+        actual = data_utils.rand_infiniband_guid_address()
+        self.assertIsInstance(actual, str)
+        self.assertRegex(actual, "^([0-9a-f][0-9a-f]:){7}"
+                         "[0-9a-f][0-9a-f]$")
+
+        actual2 = data_utils.rand_infiniband_guid_address()
+        self.assertNotEqual(actual, actual2)
+
     def test_rand_mac_address(self):
         actual = data_utils.rand_mac_address()
         self.assertIsInstance(actual, str)
diff --git a/tox.ini b/tox.ini
index e371406..44162fd 100644
--- a/tox.ini
+++ b/tox.ini
@@ -35,6 +35,7 @@
 commands = python setup.py testr --coverage --testr-arg='tempest\.tests {posargs}'
 
 [testenv:all]
+envdir = .tox/tempest
 sitepackages = {[tempestenv]sitepackages}
 # 'all' includes slow tests
 setenv =
@@ -68,6 +69,7 @@
     bash tools/pretty_tox.sh '{posargs}'
 
 [testenv:full]
+envdir = .tox/tempest
 sitepackages = {[tempestenv]sitepackages}
 setenv = {[tempestenv]setenv}
 deps = {[tempestenv]deps}
@@ -78,6 +80,7 @@
     bash tools/pretty_tox.sh '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario|thirdparty)) {posargs}'
 
 [testenv:full-serial]
+envdir = .tox/tempest
 sitepackages = {[tempestenv]sitepackages}
 setenv = {[tempestenv]setenv}
 deps = {[tempestenv]deps}
@@ -88,6 +91,7 @@
     bash tools/pretty_tox_serial.sh '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario|thirdparty)) {posargs}'
 
 [testenv:smoke]
+envdir = .tox/tempest
 sitepackages = {[tempestenv]sitepackages}
 setenv = {[tempestenv]setenv}
 deps = {[tempestenv]deps}
@@ -96,6 +100,7 @@
     bash tools/pretty_tox.sh '\[.*\bsmoke\b.*\] {posargs}'
 
 [testenv:smoke-serial]
+envdir = .tox/tempest
 sitepackages = {[tempestenv]sitepackages}
 setenv = {[tempestenv]setenv}
 deps = {[tempestenv]deps}
@@ -107,6 +112,7 @@
     bash tools/pretty_tox_serial.sh '\[.*\bsmoke\b.*\] {posargs}'
 
 [testenv:stress]
+envdir = .tox/tempest
 sitepackages = {[tempestenv]sitepackages}
 setenv = {[tempestenv]setenv}
 deps = {[tempestenv]deps}
@@ -116,6 +122,13 @@
 [testenv:venv]
 commands = {posargs}
 
+[testenv:venv-tempest]
+envdir = .tox/tempest
+sitepackages = {[tempestenv]sitepackages}
+setenv = {[tempestenv]setenv}
+deps = {[tempestenv]deps}
+commands = {posargs}
+
 [testenv:docs]
 commands =
     python setup.py build_sphinx {posargs}