Merge "Update README for run-tempest role"
diff --git a/.zuul.yaml b/.zuul.yaml
index f749b74..70f582e 100644
--- a/.zuul.yaml
+++ b/.zuul.yaml
@@ -80,6 +80,7 @@
       Integration test of IPv6-only deployments. This job runs
       smoke and IPv6 relates tests only. Basic idea is to test
       whether OpenStack Services listen on IPv6 addrress or not.
+    timeout: 10800
     vars:
       tox_envlist: ipv6-only
 
@@ -100,6 +101,7 @@
       devstack_localrc:
         ENABLE_FILE_INJECTION: true
         ENABLE_VOLUME_MULTIATTACH: true
+        USE_PYTHON3: False
       devstack_services:
         # NOTE(mriedem): Disable the cinder-backup service from tempest-full
         # since tempest-full is in the integrated-gate project template but
@@ -138,6 +140,9 @@
       - opendev.org/openstack/oslo.utils
       - opendev.org/openstack/oslo.versionedobjects
       - opendev.org/openstack/oslo.vmware
+    vars:
+      devstack_localrc:
+        USE_PYTHON3: True
 
 - job:
     name: tempest-full-parallel
@@ -146,11 +151,13 @@
     branches:
       - master
     description: |
-      Base integration test with Neutron networking and py27.
+      Base integration test with Neutron networking.
       It includes all scenarios as it was in the past.
       This job runs all scenario tests in parallel!
     vars:
       tox_envlist: full-parallel
+      devstack_localrc:
+        USE_PYTHON3: True
 
 - job:
     name: tempest-full-py3
@@ -345,6 +352,13 @@
       - stable/pike
       - stable/queens
       - stable/rocky
+    vars:
+      devstack_localrc:
+        USE_PYTHON3: False
+    group-vars:
+      subnode:
+        devstack_localrc:
+          USE_PYTHON3: False
 
 - job:
     name: tempest-multinode-full-py3
@@ -426,32 +440,16 @@
           USE_PYTHON3: true
 
 - job:
-    name: tempest-full-train
-    parent: tempest-full
-    override-checkout: stable/train
-
-- job:
     name: tempest-full-train-py3
     parent: tempest-full-py3
     override-checkout: stable/train
 
 - job:
-    name: tempest-full-stein
-    parent: tempest-full
-    override-checkout: stable/stein
-
-- job:
     name: tempest-full-stein-py3
     parent: tempest-full-py3
     override-checkout: stable/stein
 
 - job:
-    name: tempest-full-rocky
-    parent: tempest-full
-    nodeset: openstack-single-node-xenial
-    override-checkout: stable/rocky
-
-- job:
     name: tempest-full-rocky-py3
     parent: tempest-full-py3
     nodeset: openstack-single-node-xenial
@@ -511,12 +509,13 @@
     name: tempest-pg-full
     parent: tempest-full
     description: |
-      Base integration test with Neutron networking and py27 and PostgreSQL.
+      Base integration test with Neutron networking and PostgreSQL.
       Former name for this job was legacy-tempest-dsvm-neutron-pg-full.
     vars:
       devstack_localrc:
         ENABLE_FILE_INJECTION: true
         DATABASE_TYPE: postgresql
+        USE_PYTHON3: True
 
 - project-template:
     name: integrated-gate-networking
@@ -600,10 +599,9 @@
 - project:
     templates:
       - check-requirements
-      - integrated-gate
       - integrated-gate-py3
       - openstack-cover-jobs
-      - openstack-python3-train-jobs
+      - openstack-python3-ussuri-jobs
       - publish-openstack-docs-pti
       - release-notes-jobs-python3
     check:
@@ -639,22 +637,12 @@
         - tempest-full-py3-ipv6:
             voting: false
             irrelevant-files: *tempest-irrelevant-files
-        - tempest-full-train:
-            irrelevant-files: *tempest-irrelevant-files
         - tempest-full-train-py3:
             irrelevant-files: *tempest-irrelevant-files
-        - tempest-full-stein:
-            irrelevant-files: *tempest-irrelevant-files
         - tempest-full-stein-py3:
             irrelevant-files: *tempest-irrelevant-files
-        - tempest-full-rocky:
-            irrelevant-files: *tempest-irrelevant-files
-            voting: false
         - tempest-full-rocky-py3:
             irrelevant-files: *tempest-irrelevant-files
-            voting: false
-        - tempest-multinode-full:
-            irrelevant-files: *tempest-irrelevant-files
         - tempest-multinode-full-py3:
             irrelevant-files: *tempest-irrelevant-files
         - tempest-tox-plugin-sanity-check:
@@ -673,20 +661,18 @@
               # tools/ is not here since this relies on a script in tools/.
         - tempest-ipv6-only:
             irrelevant-files: *tempest-irrelevant-files-2
-        - tempest-slow:
-            irrelevant-files: *tempest-irrelevant-files
         - tempest-slow-py3:
             irrelevant-files: *tempest-irrelevant-files
         - nova-live-migration:
             voting: false
             irrelevant-files: *tempest-irrelevant-files
+        - devstack-plugin-ceph-tempest-py3:
+            voting: false
+            irrelevant-files: *tempest-irrelevant-files
         - neutron-grenade-multinode:
             irrelevant-files: *tempest-irrelevant-files
         - grenade-py3:
             irrelevant-files: *tempest-irrelevant-files
-        - devstack-plugin-ceph-tempest:
-            voting: false
-            irrelevant-files: *tempest-irrelevant-files
         - puppet-openstack-integration-4-scenario001-tempest-centos-7:
             voting: false
             irrelevant-files: *tempest-irrelevant-files
@@ -701,8 +687,6 @@
             irrelevant-files: *tempest-irrelevant-files
         - neutron-tempest-dvr:
             irrelevant-files: *tempest-irrelevant-files
-        - tempest-full:
-            irrelevant-files: *tempest-irrelevant-files
         - interop-tempest-consistency:
             irrelevant-files: *tempest-irrelevant-files
         - tempest-full-test-account-py3:
@@ -719,7 +703,7 @@
             irrelevant-files: *tempest-irrelevant-files
         - neutron-grenade-multinode:
             irrelevant-files: *tempest-irrelevant-files
-        - tempest-full:
+        - tempest-full-py3:
             irrelevant-files: *tempest-irrelevant-files
         - grenade-py3:
             irrelevant-files: *tempest-irrelevant-files
@@ -739,19 +723,14 @@
             irrelevant-files: *tempest-irrelevant-files
         - legacy-tempest-dsvm-lvm-multibackend:
             irrelevant-files: *tempest-irrelevant-files
-        - devstack-plugin-ceph-tempest-py3:
-            irrelevant-files: *tempest-irrelevant-files
         - tempest-pg-full:
             irrelevant-files: *tempest-irrelevant-files
         - tempest-full-py3-opensuse15:
             irrelevant-files: *tempest-irrelevant-files
     periodic-stable:
       jobs:
-        - tempest-full-train
         - tempest-full-train-py3
-        - tempest-full-stein
         - tempest-full-stein-py3
-        - tempest-full-rocky
         - tempest-full-rocky-py3
     periodic:
       jobs:
diff --git a/doc/requirements.txt b/doc/requirements.txt
index 2194dc4..9f38ada 100644
--- a/doc/requirements.txt
+++ b/doc/requirements.txt
@@ -3,6 +3,5 @@
 # process, which may cause wedges in the gate later.
 openstackdocstheme>=1.20.0 # Apache-2.0
 reno>=2.5.0 # Apache-2.0
-sphinx!=1.6.6,!=1.6.7,>=1.6.2,<2.0.0;python_version=='2.7' # BSD
-sphinx!=1.6.6,!=1.6.7,!=2.1.0,>=1.6.2;python_version>='3.4' # BSD
+sphinx!=1.6.6,!=1.6.7,!=2.1.0,>=1.6.2 # BSD
 sphinxcontrib-svg2pdfconverter>=0.1.0 # BSD
diff --git a/doc/source/supported_version.rst b/doc/source/supported_version.rst
index a97ec5b..4f65fd4 100644
--- a/doc/source/supported_version.rst
+++ b/doc/source/supported_version.rst
@@ -1,7 +1,7 @@
 Supported OpenStack Releases and Python Versions
 ================================================
 
-This Document list the officially supported OpenStack releases
+This document lists the officially supported OpenStack releases
 and python versions by Tempest.
 
 Compatible OpenStack Releases
@@ -24,13 +24,13 @@
 * https://releases.openstack.org/stein/index.html#stein-tempest
 
 How to use Tempest tag on Extended Maintenance stable branch:
-* https://review.opendev.org/#/c/681950/
+
+* https://review.opendev.org/#/c/705098/
 
 Supported Python Versions
 -------------------------
 
 Tempest master supports the below python versions:
 
-* Python 2.7
 * Python 3.6
 * Python 3.7
diff --git a/releasenotes/notes/deprecate-compute-feature-enabled-block-migrate-cinder-iscsi-fcda802d774dfeec.yaml b/releasenotes/notes/deprecate-compute-feature-enabled-block-migrate-cinder-iscsi-fcda802d774dfeec.yaml
new file mode 100644
index 0000000..6bbb381
--- /dev/null
+++ b/releasenotes/notes/deprecate-compute-feature-enabled-block-migrate-cinder-iscsi-fcda802d774dfeec.yaml
@@ -0,0 +1,8 @@
+---
+deprecations:
+  - |
+    The ``[compute-feature-enabled]/block_migrate_cinder_iscsi`` is deprecated
+    ahead of removal in a future release. Once removed the
+    ``[compute-feature-enabled]/block_migration_for_live_migration``
+    configurable will then be used to determine when to run block migration
+    based tests during live migration.
diff --git a/releasenotes/notes/deprecate-spice-rdp-console-config-f2af173552axfb72.yaml b/releasenotes/notes/deprecate-spice-rdp-console-config-f2af173552axfb72.yaml
new file mode 100644
index 0000000..58b161f
--- /dev/null
+++ b/releasenotes/notes/deprecate-spice-rdp-console-config-f2af173552axfb72.yaml
@@ -0,0 +1,6 @@
+---
+deprecations:
+  - |
+    The config options ``CONF.compute.spice_console`` and ``CONF.compute.rdp_console``
+    are deprecated because test cases using them are removed.
+    We can add them back when adding the test cases again.
diff --git a/releasenotes/notes/drop-py-2-7-730baf411876d5d8.yaml b/releasenotes/notes/drop-py-2-7-730baf411876d5d8.yaml
new file mode 100644
index 0000000..a0ac244
--- /dev/null
+++ b/releasenotes/notes/drop-py-2-7-730baf411876d5d8.yaml
@@ -0,0 +1,6 @@
+---
+upgrade:
+  - |
+    Python 2.7 support has been dropped. Last release of Tempest
+    to support python 2.7 is Temepst 23.0.0. The minimum version of Python now
+    supported by Tempest is Python 3.6.
diff --git a/releasenotes/notes/intermediate-ussuri-release-8aebeca312a6718c.yaml b/releasenotes/notes/intermediate-ussuri-release-8aebeca312a6718c.yaml
index 6caeacd..56f160a 100644
--- a/releasenotes/notes/intermediate-ussuri-release-8aebeca312a6718c.yaml
+++ b/releasenotes/notes/intermediate-ussuri-release-8aebeca312a6718c.yaml
@@ -1,12 +1,12 @@
 ---
-prelude: >
+prelude: |
     This is an intermediate release during the Ussuri development cycle to
     mark the end of support for EM Queens in Tempest.
     After this release, Tempest will support below OpenStack Releases:
 
-      * Train
-      * Stein
-      * Rocky
+    * Train
+    * Stein
+    * Rocky
 
     Current development of Tempest is for OpenStack Ussuri development
     cycle.
diff --git a/releasenotes/notes/os_tenant_name-3ee175763bff455b.yaml b/releasenotes/notes/os_tenant_name-3ee175763bff455b.yaml
new file mode 100644
index 0000000..936bf1f
--- /dev/null
+++ b/releasenotes/notes/os_tenant_name-3ee175763bff455b.yaml
@@ -0,0 +1,5 @@
+---
+upgrade:
+  - |
+    Remove the deprecated argument ``os-tenant-name`` or ``OS_TENANT_NAME`` in favour of
+    ``os-project-name`` argument.
diff --git a/releasenotes/notes/verify-tempest-command-8e88452c7a08dd77.yaml b/releasenotes/notes/verify-tempest-command-8e88452c7a08dd77.yaml
new file mode 100644
index 0000000..ce401ff
--- /dev/null
+++ b/releasenotes/notes/verify-tempest-command-8e88452c7a08dd77.yaml
@@ -0,0 +1,7 @@
+---
+upgrade:
+  - |
+    Remove the deprecated CLI ``verify-tempest-config`` in favour of
+    ``tempest verify-config`` command.
+    You can use ``tempest verify-config`` CLI to verify the tempest
+    conf file.
diff --git a/setup.cfg b/setup.cfg
index dd30069..d246c68 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -6,6 +6,7 @@
 author = OpenStack
 author-email = openstack-discuss@lists.openstack.org
 home-page = https://docs.openstack.org/tempest/latest/
+requires-python = >=3.6
 classifier =
     Intended Audience :: Information Technology
     Intended Audience :: System Administrators
@@ -13,11 +14,11 @@
     License :: OSI Approved :: Apache Software License
     Operating System :: POSIX :: Linux
     Programming Language :: Python
-    Programming Language :: Python :: 2
-    Programming Language :: Python :: 2.7
     Programming Language :: Python :: 3
     Programming Language :: Python :: 3.6
     Programming Language :: Python :: 3.7
+    Programming Language :: Python :: 3 :: Only
+    Programming Language :: Python :: Implementation :: CPython
 
 [files]
 packages =
@@ -27,7 +28,6 @@
 
 [entry_points]
 console_scripts =
-    verify-tempest-config = tempest.cmd.verify_tempest_config:main
     tempest-account-generator = tempest.cmd.account_generator:main
     tempest = tempest.cmd.main:main
     skip-tracker = tempest.lib.cmd.skip_tracker:main
diff --git a/setup.py b/setup.py
index 566d844..f63cc23 100644
--- a/setup.py
+++ b/setup.py
@@ -16,14 +16,6 @@
 # THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT
 import setuptools
 
-# In python < 2.7.4, a lazy loading of package `pbr` will break
-# setuptools if some other modules registered functions in `atexit`.
-# solution from: http://bugs.python.org/issue15881#msg170215
-try:
-    import multiprocessing  # noqa
-except ImportError:
-    pass
-
 setuptools.setup(
     setup_requires=['pbr>=2.0.0'],
     pbr=True)
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index dd6d593..8d0962d 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -555,11 +555,17 @@
 
         attachment = self.servers_client.attach_volume(
             server['id'], **attach_kwargs)['volumeAttachment']
-        # On teardown detach the volume and wait for it to be available. This
-        # is so we don't error out when trying to delete the volume during
-        # teardown.
-        self.addCleanup(waiters.wait_for_volume_resource_status,
-                        self.volumes_client, volume['id'], 'available')
+        # On teardown detach the volume and for multiattach volumes wait for
+        # the attachment to be removed. For non-multiattach volumes wait for
+        # the state of the volume to change to available. This is so we don't
+        # error out when trying to delete the volume during teardown.
+        if volume['multiattach']:
+            self.addCleanup(waiters.wait_for_volume_attachment_remove,
+                            self.volumes_client, volume['id'],
+                            attachment['id'])
+        else:
+            self.addCleanup(waiters.wait_for_volume_resource_status,
+                            self.volumes_client, volume['id'], 'available')
         # Ignore 404s on detach in case the server is deleted or the volume
         # is already detached.
         self.addCleanup(self._detach_volume, server, volume)
@@ -625,8 +631,14 @@
 
         svcs = self.os_admin.services_client.list_services(
             binary='nova-compute')['services']
-        hosts = [svc['host'] for svc in svcs
-                 if svc['state'] == 'up' and svc['status'] == 'enabled']
+        hosts = []
+        for svc in svcs:
+            if svc['state'] == 'up' and svc['status'] == 'enabled':
+                if CONF.compute.compute_volume_common_az:
+                    if svc['zone'] == CONF.compute.compute_volume_common_az:
+                        hosts.append(svc['host'])
+                else:
+                    hosts.append(svc['host'])
 
         for target_host in hosts:
             if source_host != target_host:
diff --git a/tempest/api/compute/images/test_images.py b/tempest/api/compute/images/test_images.py
index 7cf26fb..eef2781 100644
--- a/tempest/api/compute/images/test_images.py
+++ b/tempest/api/compute/images/test_images.py
@@ -12,12 +12,14 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import testtools
+
 from tempest.api.compute import base
 from tempest.common import waiters
 from tempest import config
 from tempest.lib.common.utils import data_utils
 from tempest.lib import decorators
-import testtools
+from tempest.lib import exceptions as lib_exceptions
 
 CONF = config.CONF
 
@@ -51,12 +53,23 @@
         # in task_state image_snapshot
         self.addCleanup(waiters.wait_for_server_status, self.servers_client,
                         server['id'], 'ACTIVE')
-        image = self.create_image_from_server(server['id'],
-                                              wait_until='SAVING')
-        self.client.delete_image(image['id'])
-        msg = ('The image with ID {image_id} failed to be deleted'
-               .format(image_id=image['id']))
-        self.assertTrue(self.client.is_resource_deleted(image['id']), msg)
+        snapshot_name = data_utils.rand_name('test-snap')
+        try:
+            image = self.create_image_from_server(server['id'],
+                                                  name=snapshot_name,
+                                                  wait_until='SAVING')
+            self.client.delete_image(image['id'])
+            msg = ('The image with ID {image_id} failed to be deleted'
+                   .format(image_id=image['id']))
+            self.assertTrue(self.client.is_resource_deleted(image['id']),
+                            msg)
+            self.assertEqual(snapshot_name, image['name'])
+        except lib_exceptions.TimeoutException as ex:
+            # If timeout is reached, we don't need to check state,
+            # since, it wouldn't be a 'SAVING' state atleast and apart from
+            # it, this testcase doesn't have scope for other state transition
+            # Hence, skip the test.
+            raise self.skipException("This test is skipped because " + str(ex))
 
     @decorators.idempotent_id('aaacd1d0-55a2-4ce8-818a-b5439df8adc9')
     def test_create_image_from_stopped_server(self):
diff --git a/tempest/api/compute/servers/test_device_tagging.py b/tempest/api/compute/servers/test_device_tagging.py
index 8aab574..1f7eb7b 100644
--- a/tempest/api/compute/servers/test_device_tagging.py
+++ b/tempest/api/compute/servers/test_device_tagging.py
@@ -358,7 +358,8 @@
             validation_resources=validation_resources,
             config_drive=config_drive_enabled,
             name=data_utils.rand_name('device-tagging-server'),
-            networks=[{'uuid': self.get_tenant_network()['id']}])
+            networks=[{'uuid': self.get_tenant_network()['id']}],
+            wait_until='ACTIVE')
         self.addCleanup(self.delete_server, server['id'])
 
         # NOTE(mgoddard): Get detailed server to ensure addresses are present
diff --git a/tempest/api/compute/servers/test_server_actions.py b/tempest/api/compute/servers/test_server_actions.py
index ff50836..d477be0 100644
--- a/tempest/api/compute/servers/test_server_actions.py
+++ b/tempest/api/compute/servers/test_server_actions.py
@@ -343,20 +343,27 @@
     def test_resize_volume_backed_server_confirm(self):
         # We have to create a new server that is volume-backed since the one
         # from setUp is not volume-backed.
-        server = self.create_test_server(
-            volume_backed=True, wait_until='ACTIVE')
+        kwargs = {'volume_backed': True,
+                  'wait_until': 'ACTIVE'}
+        if CONF.validation.run_validation:
+            validation_resources = self.get_test_validation_resources(
+                self.os_primary)
+            kwargs.update({'validatable': True,
+                           'validation_resources': validation_resources})
+        server = self.create_test_server(**kwargs)
+
         # NOTE(mgoddard): Get detailed server to ensure addresses are present
         # in fixed IP case.
         server = self.servers_client.show_server(server['id'])['server']
+
         self._test_resize_server_confirm(server['id'])
+
         if CONF.compute_feature_enabled.console_output:
             # Now do something interactive with the guest like get its console
             # output; we don't actually care about the output,
             # just that it doesn't raise an error.
             self.client.get_console_output(server['id'])
         if CONF.validation.run_validation:
-            validation_resources = self.get_class_validation_resources(
-                self.os_primary)
             linux_client = remote_client.RemoteClient(
                 self.get_server_ip(server, validation_resources),
                 self.ssh_user,
diff --git a/tempest/api/volume/admin/test_volume_quota_classes.py b/tempest/api/volume/admin/test_volume_quota_classes.py
index 75dca41..ee52354 100644
--- a/tempest/api/volume/admin/test_volume_quota_classes.py
+++ b/tempest/api/volume/admin/test_volume_quota_classes.py
@@ -44,12 +44,10 @@
 
     @decorators.idempotent_id('abb9198e-67d0-4b09-859f-4f4a1418f176')
     def test_show_default_quota(self):
+        # response body is validated by schema
         default_quotas = self.admin_quota_classes_client.show_quota_class_set(
             'default')['quota_class_set']
-        self.assertIn('id', default_quotas)
         self.assertEqual('default', default_quotas.pop('id'))
-        for key in QUOTA_KEYS:
-            self.assertIn(key, default_quotas)
 
     @decorators.idempotent_id('a7644c63-2669-467a-b00e-452dd5c5397b')
     def test_update_default_quota(self):
diff --git a/tempest/api/volume/admin/test_volume_types.py b/tempest/api/volume/admin/test_volume_types.py
index 9e24176..c1ceeb7 100644
--- a/tempest/api/volume/admin/test_volume_types.py
+++ b/tempest/api/volume/admin/test_volume_types.py
@@ -92,15 +92,12 @@
                   'extra_specs': extra_specs,
                   'os-volume-type-access:is_public': True}
         body = self.create_volume_type(**params)
-        self.assertIn('name', body)
         self.assertEqual(name, body['name'],
                          "The created volume_type name is not equal "
                          "to the requested name")
         self.assertEqual(description, body['description'],
                          "The created volume_type_description name is "
                          "not equal to the requested name")
-        self.assertIsNotNone(body['id'],
-                             "Field volume_type id is empty or not found.")
         fetched_volume_type = self.admin_volume_types_client.show_volume_type(
             body['id'])['volume_type']
         self.assertEqual(name, fetched_volume_type['name'],
diff --git a/tempest/cmd/account_generator.py b/tempest/cmd/account_generator.py
index 7ea0099..1535786 100755
--- a/tempest/cmd/account_generator.py
+++ b/tempest/cmd/account_generator.py
@@ -46,7 +46,6 @@
 Username ``--os-username``            OS_USERNAME
 Password ``--os-password``            OS_PASSWORD
 Project  ``--os-project-name``        OS_PROJECT_NAME
-Tenant   ``--os-tenant-name`` (depr.) OS_TENANT_NAME
 Domain   ``--os-domain-name``         OS_DOMAIN_NAME
 ======== ============================ ====================
 
@@ -75,9 +74,6 @@
 * ``--os-project-name <auth-project-name>`` (Optional) Project to request
   authorization on. Defaults to env[OS_PROJECT_NAME].
 
-* ``--os-tenant-name <auth-tenant-name>`` (Optional, deprecated) Tenant to
-  request authorization on. Defaults to env[OS_TENANT_NAME].
-
 * ``--os-domain-name <auth-domain-name>`` (Optional) Domain the user and
   project belong to. Defaults to env[OS_DOMAIN_NAME].
 
@@ -139,7 +135,7 @@
                          'dhcp': True}
     admin_creds_dict = {'username': opts.os_username,
                         'password': opts.os_password}
-    _project_name = opts.os_project_name or opts.os_tenant_name
+    _project_name = opts.os_project_name
     if opts.identity_version == 3:
         admin_creds_dict['project_name'] = _project_name
         admin_creds_dict['domain_name'] = opts.os_domain_name or 'Default'
@@ -221,10 +217,6 @@
                         metavar='<auth-project-name>',
                         default=os.environ.get('OS_PROJECT_NAME'),
                         help='Defaults to env[OS_PROJECT_NAME].')
-    parser.add_argument('--os-tenant-name',
-                        metavar='<auth-tenant-name>',
-                        default=os.environ.get('OS_TENANT_NAME'),
-                        help='Defaults to env[OS_TENANT_NAME].')
     parser.add_argument('--os-domain-name',
                         metavar='<auth-domain-name>',
                         default=os.environ.get('OS_DOMAIN_NAME'),
@@ -301,10 +293,6 @@
     if log_warning:
         LOG.warning("Use of: 'tempest-account-generator' is deprecated, "
                     "please use: 'tempest account-generator'")
-    if opts.os_tenant_name:
-        LOG.warning("'os-tenant-name' and 'OS_TENANT_NAME' are both "
-                    "deprecated, please use 'os-project-name' or "
-                    "'OS_PROJECT_NAME' instead")
     resources = []
     for count in range(opts.concurrency):
         # Use N different cred_providers to obtain different sets of creds
diff --git a/tempest/cmd/cleanup_service.py b/tempest/cmd/cleanup_service.py
index 2b35ebf..5b3b72a 100644
--- a/tempest/cmd/cleanup_service.py
+++ b/tempest/cmd/cleanup_service.py
@@ -362,6 +362,25 @@
         self.data['compute_quotas'] = quotas['absolute']
 
 
+class NetworkQuotaService(BaseService):
+    def __init__(self, manager, **kwargs):
+        super(NetworkQuotaService, self).__init__(kwargs)
+        self.client = manager.network_quotas_client
+
+    def delete(self):
+        client = self.client
+        try:
+            client.reset_quotas(self.project_id)
+        except Exception:
+            LOG.exception("Delete Network Quotas exception for 'project %s'.",
+                          self.project_id)
+
+    def dry_run(self):
+        resp = [quota for quota in self.client.list_quotas()['quotas']
+                if quota['project_id'] == self.project_id]
+        self.data['network_quotas'] = resp
+
+
 # Begin network service classes
 class BaseNetworkService(BaseService):
     def __init__(self, manager, **kwargs):
@@ -1048,6 +1067,7 @@
         resource_cleanup_services.append(NetworkService)
         resource_cleanup_services.append(NetworkSecGroupService)
         resource_cleanup_services.append(NetworkSubnetPoolsService)
+        resource_cleanup_services.append(NetworkQuotaService)
     if IS_CINDER:
         resource_cleanup_services.append(SnapshotService)
         resource_cleanup_services.append(VolumeService)
diff --git a/tempest/cmd/verify_tempest_config.py b/tempest/cmd/verify_tempest_config.py
index d25d3ca..8d5bdbd 100644
--- a/tempest/cmd/verify_tempest_config.py
+++ b/tempest/cmd/verify_tempest_config.py
@@ -433,11 +433,6 @@
 
 
 def main(opts=None):
-    print('Running config verification...')
-    if opts is None:
-        print("Use of: 'verify-tempest-config' is deprecated, "
-              "please use: 'tempest verify-config'")
-        opts = parse_args()
     update = opts.update
     replace = opts.replace_ext
     global CONF_PARSER
@@ -497,7 +492,3 @@
             LOG.exception("Failure verifying configuration.")
             traceback.print_exc()
             raise
-
-
-if __name__ == "__main__":
-    main()
diff --git a/tempest/common/waiters.py b/tempest/common/waiters.py
index 11f3bf9..b547cc6 100644
--- a/tempest/common/waiters.py
+++ b/tempest/common/waiters.py
@@ -217,6 +217,22 @@
              resource_name, resource_id, status, time.time() - start)
 
 
+def wait_for_volume_attachment_remove(client, volume_id, attachment_id):
+    """Waits for a volume attachment to be removed from a given volume."""
+    start = int(time.time())
+    attachments = client.show_volume(volume_id)['volume']['attachments']
+    while any(attachment_id == a['attachment_id'] for a in attachments):
+        time.sleep(client.build_interval)
+        if int(time.time()) - start >= client.build_timeout:
+            message = ('Failed to remove attachment %s from volume %s'
+                       'within the required time (%s s).' %
+                       (attachment_id, volume_id, client.build_timeout))
+            raise lib_exc.TimeoutException(message)
+        attachments = client.show_volume(volume_id)['volume']['attachments']
+    LOG.info('Attachment %s removed from volume %s after waiting for %f '
+             'seconds', attachment_id, volume_id, time.time() - start)
+
+
 def wait_for_volume_migration(client, volume_id, new_host):
     """Waits for a Volume to move to a new host."""
     body = client.show_volume(volume_id)['volume']
diff --git a/tempest/config.py b/tempest/config.py
index 4e08a11..5a2d722 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -475,7 +475,14 @@
                 default=False,
                 help="Does the test environment support block migration with "
                 "Cinder iSCSI volumes. Note: libvirt >= 1.2.17 is required "
-                "to support this if using the libvirt compute driver."),
+                "to support this if using the libvirt compute driver.",
+                deprecated_for_removal=True,
+                deprecated_reason='This option duplicates the more generic '
+                                  '[compute-feature-enabled]/block_migration '
+                                  '_for_live_migration now that '
+                                  'MIN_LIBVIRT_VERSION is >= 1.2.17 on all '
+                                  'branches from stable/rocky and will be '
+                                  'removed in a future release.'),
     cfg.BoolOpt('vnc_console',
                 default=False,
                 help='Enable VNC console. This configuration value should '
@@ -492,11 +499,19 @@
     cfg.BoolOpt('spice_console',
                 default=False,
                 help='Enable Spice console. This configuration value should '
-                     'be same as nova.conf: spice.enabled'),
+                     'be same as nova.conf: spice.enabled',
+                deprecated_for_removal=True,
+                deprecated_reason="This config option is not being used "
+                                  "in Tempest, we can add it back when "
+                                  "adding the test cases."),
     cfg.BoolOpt('rdp_console',
                 default=False,
                 help='Enable RDP console. This configuration value should '
-                     'be same as nova.conf: rdp.enabled'),
+                     'be same as nova.conf: rdp.enabled',
+                deprecated_for_removal=True,
+                deprecated_reason="This config option is not being used "
+                                  "in Tempest, we can add it back when "
+                                  "adding the test cases."),
     cfg.BoolOpt('serial_console',
                 default=False,
                 help='Enable serial console. This configuration value '
diff --git a/tempest/lib/api_schema/response/volume/quota_classes.py b/tempest/lib/api_schema/response/volume/quota_classes.py
new file mode 100644
index 0000000..1a575d2
--- /dev/null
+++ b/tempest/lib/api_schema/response/volume/quota_classes.py
@@ -0,0 +1,68 @@
+# Copyright 2018 ZTE Corporation.  All rights reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+show_quota_classes = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'quota_class_set': {
+                'type': 'object',
+                'properties': {
+                    'id': {'type': 'string', 'format': 'uuid'},
+                    'volumes': {'type': 'integer'},
+                    'snapshots': {'type': 'integer'},
+                    'backups': {'type': 'integer'},
+                    'groups': {'type': 'integer'},
+                    'per_volume_gigabytes': {'type': 'integer'},
+                    'gigabytes': {'type': 'integer'},
+                    'backup_gigabytes': {'type': 'integer'},
+                },
+                # for volumes_{volume_type}, etc
+                "additionalProperties": {'type': 'integer'},
+                'required': ['id', 'volumes', 'snapshots', 'backups',
+                             'per_volume_gigabytes', 'gigabytes',
+                             'backup_gigabytes'],
+            }
+        },
+        'required': ['quota_class_set']
+    }
+}
+
+update_quota_classes = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'quota_class_set': {
+                'type': 'object',
+                'properties': {
+                    'volumes': {'type': 'integer'},
+                    'snapshots': {'type': 'integer'},
+                    'backups': {'type': 'integer'},
+                    'groups': {'type': 'integer'},
+                    'per_volume_gigabytes': {'type': 'integer'},
+                    'gigabytes': {'type': 'integer'},
+                    'backup_gigabytes': {'type': 'integer'},
+                },
+                # for volumes_{volume_type}, etc
+                "additionalProperties": {'type': 'integer'},
+                'required': ['volumes', 'snapshots', 'backups',
+                             'per_volume_gigabytes', 'gigabytes',
+                             'backup_gigabytes'],
+            }
+        },
+        'required': ['quota_class_set']
+    }
+}
diff --git a/tempest/lib/api_schema/response/volume/volume_types.py b/tempest/lib/api_schema/response/volume/volume_types.py
new file mode 100644
index 0000000..51b3a72
--- /dev/null
+++ b/tempest/lib/api_schema/response/volume/volume_types.py
@@ -0,0 +1,176 @@
+# Copyright 2018 ZTE Corporation.  All rights reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+extra_specs_info = {
+    'type': 'object',
+    'patternProperties': {
+        '^.+$': {'type': 'string'}
+    }
+}
+
+common_show_volume_type = {
+    'type': 'object',
+    'properties': {
+        'extra_specs': extra_specs_info,
+        'name': {'type': 'string'},
+        'is_public': {'type': 'boolean'},
+        'description': {'type': ['string', 'null']},
+        'id': {'type': 'string', 'format': 'uuid'},
+        'os-volume-type-access:is_public': {'type': 'boolean'},
+        'qos_specs_id': {'type': ['string', 'null'], 'format': 'uuid'}
+    },
+    'additionalProperties': False,
+    'required': ['name', 'is_public', 'description', 'id',
+                 'os-volume-type-access:is_public']
+}
+
+show_volume_type = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'volume_type': common_show_volume_type,
+        },
+        'additionalProperties': False,
+        'required': ['volume_type']
+    }
+}
+
+delete_volume_type = {'status_code': [202]}
+
+create_volume_type = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'volume_type': {
+                'type': 'object',
+                'properties': {
+                    'extra_specs': extra_specs_info,
+                    'name': {'type': 'string'},
+                    'is_public': {'type': 'boolean'},
+                    'description': {'type': ['string', 'null']},
+                    'id': {'type': 'string', 'format': 'uuid'},
+                    'os-volume-type-access:is_public': {'type': 'boolean'}
+                },
+                'additionalProperties': False,
+                'required': ['name', 'is_public', 'id',
+                             'description', 'os-volume-type-access:is_public']
+            },
+        },
+        'additionalProperties': False,
+        'required': ['volume_type']
+    }
+}
+
+list_volume_types = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'volume_types': {
+                'type': 'array',
+                'items': common_show_volume_type
+            }
+        },
+        'additionalProperties': False,
+        'required': ['volume_types']
+    }
+}
+
+list_volume_types_extra_specs = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'extra_specs': extra_specs_info
+        },
+        'additionalProperties': False,
+        'required': ['extra_specs']
+    }
+}
+
+show_volume_types_extra_specs = {
+    'status_code': [200],
+    'response_body': extra_specs_info
+}
+
+create_volume_types_extra_specs = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'extra_specs': extra_specs_info
+        },
+        'additionalProperties': False,
+        'required': ['extra_specs']
+    }
+}
+
+delete_volume_types_extra_specs = {'status_code': [202]}
+
+update_volume_types = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'volume_type': {
+                'type': 'object',
+                'properties': {
+                    'extra_specs': extra_specs_info,
+                    'name': {'type': 'string'},
+                    'is_public': {'type': 'boolean'},
+                    'description': {'type': ['string', 'null']},
+                    'id': {'type': 'string', 'format': 'uuid'}
+                },
+                'additionalProperties': False,
+                'required': ['name', 'is_public', 'description', 'id']
+            },
+        },
+        'additionalProperties': False,
+        'required': ['volume_type']
+    }
+}
+
+update_volume_type_extra_specs = {
+    'status_code': [200],
+    'response_body': extra_specs_info
+}
+
+add_type_access = {'status_code': [202]}
+
+remove_type_access = {'status_code': [202]}
+
+list_type_access = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'volume_type_access': {
+                'type': 'array',
+                'items': {
+                    'type': 'object',
+                    'properties': {
+                        'volume_type_id': {'type': 'string', 'format': 'uuid'},
+                        'project_id': {'type': 'string', 'format': 'uuid'},
+                    },
+                    'additionalProperties': False,
+                    'required': ['volume_type_id', 'project_id']
+                }
+            }
+        },
+        'additionalProperties': False,
+        'required': ['volume_type_access']
+    }
+}
diff --git a/tempest/lib/common/ssh.py b/tempest/lib/common/ssh.py
index 2ac1605..3a05f27 100644
--- a/tempest/lib/common/ssh.py
+++ b/tempest/lib/common/ssh.py
@@ -75,6 +75,11 @@
         self.channel_timeout = float(channel_timeout)
         self.buf_size = 1024
         self.proxy_client = proxy_client
+        if (self.proxy_client and self.proxy_client.host == self.host and
+                self.proxy_client.port == self.port and
+                self.proxy_client.username == self.username):
+            raise exceptions.SSHClientProxyClientLoop(
+                host=self.host, port=self.port, username=self.username)
         self._proxy_conn = None
 
     def _get_ssh_connection(self, sleep=1.5, backoff=1):
@@ -114,8 +119,10 @@
                 ssh.close()
                 if self._is_timed_out(_start_time):
                     LOG.exception("Failed to establish authenticated ssh"
-                                  " connection to %s@%s after %d attempts",
-                                  self.username, self.host, attempts)
+                                  " connection to %s@%s after %d attempts. "
+                                  "Proxy client: %s",
+                                  self.username, self.host, attempts,
+                                  self._get_proxy_client_info())
                     raise exceptions.SSHTimeout(host=self.host,
                                                 user=self.username,
                                                 password=self.password)
@@ -219,3 +226,13 @@
         cmd = 'nc %s %s' % (self.host, self.port)
         chan.exec_command(cmd)
         return chan
+
+    def _get_proxy_client_info(self):
+        if not self.proxy_client:
+            return 'no proxy client'
+        nested_pclient = self.proxy_client._get_proxy_client_info()
+        return ('%(username)s@%(host)s:%(port)s, nested proxy client: '
+                '%(nested_pclient)s' % {'username': self.proxy_client.username,
+                                        'host': self.proxy_client.host,
+                                        'port': self.proxy_client.port,
+                                        'nested_pclient': nested_pclient})
diff --git a/tempest/lib/exceptions.py b/tempest/lib/exceptions.py
index b25b4b2..84b7ee6 100644
--- a/tempest/lib/exceptions.py
+++ b/tempest/lib/exceptions.py
@@ -251,6 +251,11 @@
                "stdout:\n%(stdout)s")
 
 
+class SSHClientProxyClientLoop(TempestException):
+    message = ("SSH client proxy client has same host: %(host)s, port: "
+               "%(port)s and username: %(username)s as parent")
+
+
 class UnknownServiceClient(TempestException):
     message = "Service clients named %(services)s are not known"
 
diff --git a/tempest/lib/services/image/v2/namespace_tags_client.py b/tempest/lib/services/image/v2/namespace_tags_client.py
index cf63e50..4315f16 100644
--- a/tempest/lib/services/image/v2/namespace_tags_client.py
+++ b/tempest/lib/services/image/v2/namespace_tags_client.py
@@ -116,10 +116,6 @@
         url = 'metadefs/namespaces/%s/tags' % namespace
         resp, _ = self.delete(url)
 
-        # NOTE(rosmaita): Bug 1656183 fixed the success response code for
-        # this call to make it consistent with the other metadefs delete
-        # calls.  Accept both codes in case tempest is being run against
-        # an old Glance.
-        self.expected_success([200, 204], resp.status)
+        self.expected_success(204, resp.status)
 
         return rest_client.ResponseBody(resp)
diff --git a/tempest/lib/services/volume/v3/quota_classes_client.py b/tempest/lib/services/volume/v3/quota_classes_client.py
index cf03918..ff62f0c 100644
--- a/tempest/lib/services/volume/v3/quota_classes_client.py
+++ b/tempest/lib/services/volume/v3/quota_classes_client.py
@@ -15,6 +15,7 @@
 
 from oslo_serialization import jsonutils as json
 
+from tempest.lib.api_schema.response.volume import quota_classes as schema
 from tempest.lib.common import rest_client
 
 
@@ -30,8 +31,8 @@
         """
         url = 'os-quota-class-sets/%s' % quota_class_id
         resp, body = self.get(url)
-        self.expected_success(200, resp.status)
         body = json.loads(body)
+        self.validate_response(schema.show_quota_classes, resp, body)
         return rest_client.ResponseBody(resp, body)
 
     def update_quota_class_set(self, quota_class_id, **kwargs):
@@ -44,6 +45,6 @@
         url = 'os-quota-class-sets/%s' % quota_class_id
         put_body = json.dumps({'quota_class_set': kwargs})
         resp, body = self.put(url, put_body)
-        self.expected_success(200, resp.status)
         body = json.loads(body)
+        self.validate_response(schema.update_quota_classes, resp, body)
         return rest_client.ResponseBody(resp, body)
diff --git a/tempest/lib/services/volume/v3/types_client.py b/tempest/lib/services/volume/v3/types_client.py
index 705d319..7fa24a4 100644
--- a/tempest/lib/services/volume/v3/types_client.py
+++ b/tempest/lib/services/volume/v3/types_client.py
@@ -16,6 +16,7 @@
 from oslo_serialization import jsonutils as json
 from six.moves.urllib import parse as urllib
 
+from tempest.lib.api_schema.response.volume import volume_types as schema
 from tempest.lib.common import rest_client
 from tempest.lib import exceptions as lib_exc
 
@@ -48,7 +49,7 @@
 
         resp, body = self.get(url)
         body = json.loads(body)
-        self.expected_success(200, resp.status)
+        self.validate_response(schema.list_volume_types, resp, body)
         return rest_client.ResponseBody(resp, body)
 
     def show_volume_type(self, volume_type_id):
@@ -61,7 +62,7 @@
         url = "types/%s" % volume_type_id
         resp, body = self.get(url)
         body = json.loads(body)
-        self.expected_success(200, resp.status)
+        self.validate_response(schema.show_volume_type, resp, body)
         return rest_client.ResponseBody(resp, body)
 
     def create_volume_type(self, **kwargs):
@@ -74,7 +75,7 @@
         post_body = json.dumps({'volume_type': kwargs})
         resp, body = self.post('types', post_body)
         body = json.loads(body)
-        self.expected_success(200, resp.status)
+        self.validate_response(schema.create_volume_type, resp, body)
         return rest_client.ResponseBody(resp, body)
 
     def delete_volume_type(self, volume_type_id):
@@ -85,7 +86,7 @@
         https://docs.openstack.org/api-ref/block-storage/v3/index.html#delete-a-volume-type
         """
         resp, body = self.delete("types/%s" % volume_type_id)
-        self.expected_success(202, resp.status)
+        self.validate_response(schema.delete_volume_type, resp, body)
         return rest_client.ResponseBody(resp, body)
 
     def list_volume_types_extra_specs(self, volume_type_id, **params):
@@ -101,7 +102,8 @@
 
         resp, body = self.get(url)
         body = json.loads(body)
-        self.expected_success(200, resp.status)
+        self.validate_response(
+            schema.list_volume_types_extra_specs, resp, body)
         return rest_client.ResponseBody(resp, body)
 
     def show_volume_type_extra_specs(self, volume_type_id, extra_specs_name):
@@ -109,7 +111,8 @@
         url = "types/%s/extra_specs/%s" % (volume_type_id, extra_specs_name)
         resp, body = self.get(url)
         body = json.loads(body)
-        self.expected_success(200, resp.status)
+        self.validate_response(
+            schema.show_volume_types_extra_specs, resp, body)
         return rest_client.ResponseBody(resp, body)
 
     def create_volume_type_extra_specs(self, volume_type_id, extra_specs):
@@ -122,14 +125,16 @@
         post_body = json.dumps({'extra_specs': extra_specs})
         resp, body = self.post(url, post_body)
         body = json.loads(body)
-        self.expected_success(200, resp.status)
+        self.validate_response(
+            schema.create_volume_types_extra_specs, resp, body)
         return rest_client.ResponseBody(resp, body)
 
     def delete_volume_type_extra_specs(self, volume_type_id, extra_spec_name):
         """Deletes the specified volume type extra spec."""
         resp, body = self.delete("types/%s/extra_specs/%s" % (
             volume_type_id, extra_spec_name))
-        self.expected_success(202, resp.status)
+        self.validate_response(
+            schema.delete_volume_types_extra_specs, resp, body)
         return rest_client.ResponseBody(resp, body)
 
     def update_volume_type(self, volume_type_id, **kwargs):
@@ -142,7 +147,7 @@
         put_body = json.dumps({'volume_type': kwargs})
         resp, body = self.put('types/%s' % volume_type_id, put_body)
         body = json.loads(body)
-        self.expected_success(200, resp.status)
+        self.validate_response(schema.update_volume_types, resp, body)
         return rest_client.ResponseBody(resp, body)
 
     def update_volume_type_extra_specs(self, volume_type_id, extra_spec_name,
@@ -162,7 +167,8 @@
         put_body = json.dumps(extra_specs)
         resp, body = self.put(url, put_body)
         body = json.loads(body)
-        self.expected_success(200, resp.status)
+        self.validate_response(
+            schema.update_volume_type_extra_specs, resp, body)
         return rest_client.ResponseBody(resp, body)
 
     def add_type_access(self, volume_type_id, **kwargs):
@@ -175,7 +181,7 @@
         post_body = json.dumps({'addProjectAccess': kwargs})
         url = 'types/%s/action' % volume_type_id
         resp, body = self.post(url, post_body)
-        self.expected_success(202, resp.status)
+        self.validate_response(schema.add_type_access, resp, body)
         return rest_client.ResponseBody(resp, body)
 
     def remove_type_access(self, volume_type_id, **kwargs):
@@ -188,7 +194,7 @@
         post_body = json.dumps({'removeProjectAccess': kwargs})
         url = 'types/%s/action' % volume_type_id
         resp, body = self.post(url, post_body)
-        self.expected_success(202, resp.status)
+        self.validate_response(schema.remove_type_access, resp, body)
         return rest_client.ResponseBody(resp, body)
 
     def list_type_access(self, volume_type_id):
@@ -201,5 +207,5 @@
         url = 'types/%s/os-volume-type-access' % volume_type_id
         resp, body = self.get(url)
         body = json.loads(body)
-        self.expected_success(200, resp.status)
+        self.validate_response(schema.list_type_access, resp, body)
         return rest_client.ResponseBody(resp, body)
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index db8da84..cb7acbf 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -810,6 +810,42 @@
         server_details = cls.os_admin.servers_client.show_server(server_id)
         return server_details['server']['OS-EXT-SRV-ATTR:host']
 
+    def _get_bdm(self, source_id, source_type, delete_on_termination=False):
+        bd_map_v2 = [{
+            'uuid': source_id,
+            'source_type': source_type,
+            'destination_type': 'volume',
+            'boot_index': 0,
+            'delete_on_termination': delete_on_termination}]
+        return {'block_device_mapping_v2': bd_map_v2}
+
+    def boot_instance_from_resource(self, source_id,
+                                    source_type,
+                                    keypair=None,
+                                    security_group=None,
+                                    delete_on_termination=False,
+                                    name=None):
+        create_kwargs = dict()
+        if keypair:
+            create_kwargs['key_name'] = keypair['name']
+        if security_group:
+            create_kwargs['security_groups'] = [
+                {'name': security_group['name']}]
+        create_kwargs.update(self._get_bdm(
+            source_id,
+            source_type,
+            delete_on_termination=delete_on_termination))
+        if name:
+            create_kwargs['name'] = name
+
+        return self.create_server(image_id='', **create_kwargs)
+
+    def create_volume_from_image(self):
+        img_uuid = CONF.compute.image_ref
+        vol_name = data_utils.rand_name(
+            self.__class__.__name__ + '-volume-origin')
+        return self.create_volume(name=vol_name, imageRef=img_uuid)
+
 
 class NetworkScenarioTest(ScenarioTest):
     """Base class for network scenario tests.
diff --git a/tempest/scenario/test_minimum_basic.py b/tempest/scenario/test_minimum_basic.py
index cee543b..4cd860d 100644
--- a/tempest/scenario/test_minimum_basic.py
+++ b/tempest/scenario/test_minimum_basic.py
@@ -61,7 +61,11 @@
 
     def cinder_show(self, volume):
         got_volume = self.volumes_client.show_volume(volume['id'])['volume']
-        self.assertEqual(volume, got_volume)
+        # Exclude updated_at because of bug 1838202.
+        excluded_keys = ['updated_at']
+        self.assertThat(
+            volume, custom_matchers.MatchesDictExceptForKeys(
+                got_volume, excluded_keys=excluded_keys))
 
     def nova_reboot(self, server):
         self.servers_client.reboot_server(server['id'], type='SOFT')
diff --git a/tempest/scenario/test_volume_boot_pattern.py b/tempest/scenario/test_volume_boot_pattern.py
index 6ed7e30..0782389 100644
--- a/tempest/scenario/test_volume_boot_pattern.py
+++ b/tempest/scenario/test_volume_boot_pattern.py
@@ -31,42 +31,6 @@
     # breathing room to get through deletes in the time allotted.
     TIMEOUT_SCALING_FACTOR = 2
 
-    def _create_volume_from_image(self):
-        img_uuid = CONF.compute.image_ref
-        vol_name = data_utils.rand_name(
-            self.__class__.__name__ + '-volume-origin')
-        return self.create_volume(name=vol_name, imageRef=img_uuid)
-
-    def _get_bdm(self, source_id, source_type, delete_on_termination=False):
-        bd_map_v2 = [{
-            'uuid': source_id,
-            'source_type': source_type,
-            'destination_type': 'volume',
-            'boot_index': 0,
-            'delete_on_termination': delete_on_termination}]
-        return {'block_device_mapping_v2': bd_map_v2}
-
-    def _boot_instance_from_resource(self, source_id,
-                                     source_type,
-                                     keypair=None,
-                                     security_group=None,
-                                     delete_on_termination=False,
-                                     name=None):
-        create_kwargs = dict()
-        if keypair:
-            create_kwargs['key_name'] = keypair['name']
-        if security_group:
-            create_kwargs['security_groups'] = [
-                {'name': security_group['name']}]
-        create_kwargs.update(self._get_bdm(
-            source_id,
-            source_type,
-            delete_on_termination=delete_on_termination))
-        if name:
-            create_kwargs['name'] = name
-
-        return self.create_server(image_id='', **create_kwargs)
-
     def _delete_server(self, server):
         self.servers_client.delete_server(server['id'])
         waiters.wait_for_server_termination(self.servers_client, server['id'])
@@ -104,8 +68,8 @@
 
         # create an instance from volume
         LOG.info("Booting instance 1 from volume")
-        volume_origin = self._create_volume_from_image()
-        instance_1st = self._boot_instance_from_resource(
+        volume_origin = self.create_volume_from_image()
+        instance_1st = self.boot_instance_from_resource(
             source_id=volume_origin['id'],
             source_type='volume',
             keypair=keypair,
@@ -124,7 +88,7 @@
         self._delete_server(instance_1st)
 
         # create a 2nd instance from volume
-        instance_2nd = self._boot_instance_from_resource(
+        instance_2nd = self.boot_instance_from_resource(
             source_id=volume_origin['id'],
             source_type='volume',
             keypair=keypair,
@@ -149,10 +113,10 @@
                                     size=snapshot['size'])
         LOG.info("Booting third instance from snapshot")
         server_from_snapshot = (
-            self._boot_instance_from_resource(source_id=volume['id'],
-                                              source_type='volume',
-                                              keypair=keypair,
-                                              security_group=security_group))
+            self.boot_instance_from_resource(source_id=volume['id'],
+                                             source_type='volume',
+                                             keypair=keypair,
+                                             security_group=security_group))
         LOG.info("Booted third instance %s", server_from_snapshot)
 
         # check the content of written file
@@ -171,13 +135,13 @@
     @utils.services('compute', 'image', 'volume')
     def test_create_server_from_volume_snapshot(self):
         # Create a volume from an image
-        boot_volume = self._create_volume_from_image()
+        boot_volume = self.create_volume_from_image()
 
         # Create a snapshot
         boot_snapshot = self.create_volume_snapshot(boot_volume['id'])
 
         # Create a server from a volume snapshot
-        server = self._boot_instance_from_resource(
+        server = self.boot_instance_from_resource(
             source_id=boot_snapshot['id'],
             source_type='snapshot',
             delete_on_termination=True)
@@ -203,16 +167,23 @@
         self.assertEqual(created_volume[0]['id'],
                          created_volume_info['attachments'][0]['volume_id'])
 
+        # Delete the server and wait
+        self._delete_server(server)
+
+        # Assert that the underlying volume is gone before class tearDown
+        # to prevent snapshot deletion from failing
+        self.volumes_client.wait_for_resource_deletion(created_volume[0]['id'])
+
     @decorators.idempotent_id('36c34c67-7b54-4b59-b188-02a2f458a63b')
     @testtools.skipUnless(CONF.volume_feature_enabled.snapshot,
                           'Cinder volume snapshots are disabled')
     @utils.services('compute', 'volume', 'image')
     def test_image_defined_boot_from_volume(self):
         # create an instance from image-backed volume
-        volume_origin = self._create_volume_from_image()
+        volume_origin = self.create_volume_from_image()
         name = data_utils.rand_name(self.__class__.__name__ +
                                     '-volume-backed-server')
-        instance1 = self._boot_instance_from_resource(
+        instance1 = self.boot_instance_from_resource(
             source_id=volume_origin['id'],
             source_type='volume',
             delete_on_termination=True,
@@ -288,7 +259,7 @@
         self.volumes_client.set_bootable_volume(volume['id'], bootable=True)
 
         # Boot a server from the encrypted volume
-        server = self._boot_instance_from_resource(
+        server = self.boot_instance_from_resource(
             source_id=volume['id'],
             source_type='volume',
             delete_on_termination=False)
diff --git a/tempest/tests/cmd/test_account_generator.py b/tempest/tests/cmd/test_account_generator.py
index b349bba..a962e37 100644
--- a/tempest/tests/cmd/test_account_generator.py
+++ b/tempest/tests/cmd/test_account_generator.py
@@ -28,7 +28,6 @@
         self.os_username = 'fake_user'
         self.os_password = 'fake_password'
         self.os_project_name = 'fake_project_name'
-        self.os_tenant_name = None
         self.os_domain_name = 'fake_domain'
         self.tag = 'fake'
         self.concurrency = 2
@@ -100,15 +99,6 @@
         self.assertEqual(self.opts.os_password, admin_creds.password)
         self.assertFalse(hasattr(admin_creds, 'domain_name'))
 
-    def test_get_credential_provider_with_tenant(self):
-        self.opts.os_project_name = None
-        self.opts.os_tenant_name = 'fake_tenant'
-        cp = account_generator.get_credential_provider(self.opts)
-        admin_creds = cp.default_admin_creds
-        self.assertEqual(self.opts.os_tenant_name, admin_creds.tenant_name)
-        self.assertEqual(self.opts.os_username, admin_creds.username)
-        self.assertEqual(self.opts.os_password, admin_creds.password)
-
 
 class TestAccountGeneratorV3(TestAccountGeneratorV2):
 
diff --git a/tempest/tests/cmd/test_cleanup_services.py b/tempest/tests/cmd/test_cleanup_services.py
index ae08d02..8366290 100644
--- a/tempest/tests/cmd/test_cleanup_services.py
+++ b/tempest/tests/cmd/test_cleanup_services.py
@@ -196,6 +196,7 @@
             is_save_state=is_save_state,
             is_preserve=is_preserve,
             is_dry_run=is_dry_run,
+            project_id='b8e3ece07bb049138d224436756e3b57',
             data={},
             saved_state_json=self.saved_state
             )
@@ -533,6 +534,135 @@
         self._test_saved_state_true([(self.get_method, self.response, 200)])
 
 
+class TestVolumeQuotaService(BaseCmdServiceTests):
+
+    service_class = 'VolumeQuotaService'
+    service_name = 'volume_quota_service'
+    response = {
+        "quota_set": {
+            "groups":
+                {"reserved": 0, "limit": 10, "in_use": 0},
+            "per_volume_gigabytes":
+                {"reserved": 0, "limit": -1, "in_use": 0},
+            "volumes":
+                {"reserved": 0, "limit": 10, "in_use": 0},
+            "gigabytes":
+                {"reserved": 0, "limit": 1000, "in_use": 0},
+            "backup_gigabytes":
+                {"reserved": 0, "limit": 1000, "in_use": 0},
+            "snapshots":
+                {"reserved": 0, "limit": 10, "in_use": 0},
+            "volumes_iscsi":
+                {"reserved": 0, "limit": -1, "in_use": 0},
+            "snapshots_iscsi":
+                {"reserved": 0, "limit": -1, "in_use": 0},
+            "backups":
+                {"reserved": 0, "limit": 10, "in_use": 0},
+            "gigabytes_iscsi":
+                {"reserved": 0, "limit": -1, "in_use": 0},
+            "id": "b8e3ece07bb049138d224436756e3b57"
+                }
+        }
+
+    def test_delete_fail(self):
+        delete_mock = [(self.delete_method, 'error', None),
+                       (self.log_method, 'exception', None)]
+        self._test_delete(delete_mock, fail=True)
+
+    def test_delete_pass(self):
+        delete_mock = [(self.delete_method, None, 200),
+                       (self.log_method, 'exception', None)]
+        self._test_delete(delete_mock)
+
+    def test_dry_run(self):
+        dry_mock = [(self.get_method, self.response, 200),
+                    (self.delete_method, "delete", None)]
+        self._test_dry_run_true(dry_mock)
+
+
+class TestNovaQuotaService(BaseCmdServiceTests):
+
+    service_class = 'NovaQuotaService'
+    service_name = 'nova_quota_service'
+    response = {
+        "limits": {
+            "rate": [],
+            "absolute": {
+                "maxServerMeta": 128,
+                "maxPersonality": 5,
+                "totalServerGroupsUsed": 0,
+                "maxImageMeta": 128,
+                "maxPersonalitySize": 10240,
+                "maxTotalKeypairs": 100,
+                "maxSecurityGroupRules": 20,
+                "maxServerGroups": 10,
+                "totalCoresUsed": 0,
+                "totalRAMUsed": 0,
+                "totalInstancesUsed": 0,
+                "maxSecurityGroups": 10,
+                "totalFloatingIpsUsed": 0,
+                "maxTotalCores": 20,
+                "maxServerGroupMembers": 10,
+                "maxTotalFloatingIps": 10,
+                "totalSecurityGroupsUsed": 0,
+                "maxTotalInstances": 10,
+                "maxTotalRAMSize": 51200
+                }
+            }
+        }
+
+    def test_delete_fail(self):
+        delete_mock = [(self.delete_method, 'error', None),
+                       (self.log_method, 'exception', None)]
+        self._test_delete(delete_mock, fail=True)
+
+    def test_delete_pass(self):
+        delete_mock = [(self.delete_method, None, 202),
+                       (self.log_method, 'exception', None)]
+        self._test_delete(delete_mock)
+
+    def test_dry_run(self):
+        dry_mock = [(self.get_method, self.response, 200),
+                    (self.delete_method, "delete", None)]
+        self._test_dry_run_true(dry_mock)
+
+
+class TestNetworkQuotaService(BaseCmdServiceTests):
+
+    service_class = 'NetworkQuotaService'
+    service_name = 'network_quota_service'
+    response = {
+        "quotas": [{
+            "subnet": 110,
+            "network": 100,
+            "floatingip": 50,
+            "tenant_id": "81e8490db559474dacb2212fca9cca2d",
+            "subnetpool": -1,
+            "security_group_rule": 100,
+            "trunk": -1,
+            "security_group": 10,
+            "router": 10,
+            "rbac_policy": 10, "project_id":
+            "81e8490db559474dacb2212fca9cca2d", "port": 500
+            }]
+    }
+
+    def test_delete_fail(self):
+        delete_mock = [(self.delete_method, 'error', None),
+                       (self.log_method, 'exception', None)]
+        self._test_delete(delete_mock, fail=True)
+
+    def test_delete_pass(self):
+        delete_mock = [(self.delete_method, None, 204),
+                       (self.log_method, 'exception', None)]
+        self._test_delete(delete_mock)
+
+    def test_dry_run(self):
+        dry_mock = [(self.get_method, self.response, 200),
+                    (self.delete_method, "delete", None)]
+        self._test_dry_run_true(dry_mock)
+
+
 # Begin network service classes
 class TestNetworkService(BaseCmdServiceTests):
 
diff --git a/tempest/tests/common/test_waiters.py b/tempest/tests/common/test_waiters.py
index 6275f22..e3bb836 100755
--- a/tempest/tests/common/test_waiters.py
+++ b/tempest/tests/common/test_waiters.py
@@ -15,6 +15,7 @@
 import time
 
 import mock
+from oslo_utils.fixture import uuidsentinel as uuids
 
 from tempest.common import waiters
 from tempest import exceptions
@@ -232,3 +233,51 @@
         mock_show.assert_has_calls([mock.call(volume_id),
                                     mock.call(volume_id)])
         mock_sleep.assert_called_once_with(1)
+
+    def test_wait_for_volume_attachment(self):
+        vol_detached = {'volume': {'attachments': []}}
+        vol_attached = {'volume': {'attachments': [
+                       {'attachment_id': uuids.attachment_id}]}}
+        show_volume = mock.MagicMock(side_effect=[
+            vol_attached, vol_attached, vol_detached])
+        client = mock.Mock(spec=volumes_client.VolumesClient,
+                           build_interval=1,
+                           build_timeout=5,
+                           show_volume=show_volume)
+        self.patch('time.time')
+        self.patch('time.sleep')
+        waiters.wait_for_volume_attachment_remove(client, uuids.volume_id,
+                                                  uuids.attachment_id)
+        # Assert that show volume is called until the attachment is removed.
+        show_volume.assert_has_calls = [mock.call(uuids.volume_id),
+                                        mock.call(uuids.volume_id),
+                                        mock.call(uuids.volume_id)]
+
+    def test_wait_for_volume_attachment_timeout(self):
+        show_volume = mock.MagicMock(return_value={
+            'volume': {'attachments': [
+                {'attachment_id': uuids.attachment_id}]}})
+        client = mock.Mock(spec=volumes_client.VolumesClient,
+                           build_interval=1,
+                           build_timeout=1,
+                           show_volume=show_volume)
+        self.patch('time.time', side_effect=[0., client.build_timeout + 1.])
+        self.patch('time.sleep')
+        # Assert that a timeout is raised if the attachment remains.
+        self.assertRaises(lib_exc.TimeoutException,
+                          waiters.wait_for_volume_attachment_remove,
+                          client, uuids.volume_id, uuids.attachment_id)
+
+    def test_wait_for_volume_attachment_not_present(self):
+        show_volume = mock.MagicMock(return_value={
+            'volume': {'attachments': []}})
+        client = mock.Mock(spec=volumes_client.VolumesClient,
+                           build_interval=1,
+                           build_timeout=1,
+                           show_volume=show_volume)
+        self.patch('time.time', side_effect=[0., client.build_timeout + 1.])
+        self.patch('time.sleep')
+        waiters.wait_for_volume_attachment_remove(client, uuids.volume_id,
+                                                  uuids.attachment_id)
+        # Assert that show volume is only called once before we return
+        show_volume.assert_called_once_with(uuids.volume_id)
diff --git a/tempest/tests/lib/services/identity/v3/test_groups_client.py b/tempest/tests/lib/services/identity/v3/test_groups_client.py
index 38cf3ae..e3c9851 100644
--- a/tempest/tests/lib/services/identity/v3/test_groups_client.py
+++ b/tempest/tests/lib/services/identity/v3/test_groups_client.py
@@ -211,3 +211,13 @@
             group_id='6e13e2068cf9466e98950595baf6bb35',
             user_id='642688fa65a84217b86cef3c063de2b9',
         )
+
+    def test_delete_group_user(self):
+        self.check_service_client_function(
+            self.client.delete_group_user,
+            'tempest.lib.common.rest_client.RestClient.delete',
+            {},
+            status=204,
+            group_id='6e13e2068cf9466e98950595baf6bb35',
+            user_id='642688fa65a84217b86cef3c063de2b9',
+        )
diff --git a/tempest/tests/lib/services/image/v2/test_namespace_tags_client.py b/tempest/tests/lib/services/image/v2/test_namespace_tags_client.py
index 2faa5be..6b282f4 100644
--- a/tempest/tests/lib/services/image/v2/test_namespace_tags_client.py
+++ b/tempest/tests/lib/services/image/v2/test_namespace_tags_client.py
@@ -118,9 +118,17 @@
     def test_show_namespace_tag_with_bytes_body(self):
         self._test_show_namespace_tag_definition(bytes_body=True)
 
+    def test_delete_namespace_tag_definition(self):
+        self.check_service_client_function(
+            self.client.delete_namespace_tag,
+            'tempest.lib.common.rest_client.RestClient.delete',
+            {}, status=204,
+            namespace="OS::Compute::Hypervisor",
+            tag_name="added-sample-tag")
+
     def test_delete_all_namespace_tags(self):
         self.check_service_client_function(
             self.client.delete_namespace_tags,
             'tempest.lib.common.rest_client.RestClient.delete',
-            {}, status=200,
+            {}, status=204,
             namespace="OS::Compute::Hypervisor")
diff --git a/tempest/tests/lib/services/network/test_agents_client.py b/tempest/tests/lib/services/network/test_agents_client.py
index aabc6ce..8904882 100644
--- a/tempest/tests/lib/services/network/test_agents_client.py
+++ b/tempest/tests/lib/services/network/test_agents_client.py
@@ -22,12 +22,145 @@
 
     FAKE_AGENT_ID = "d32019d3-bc6e-4319-9c1d-6123f4135a88"
 
+    FAKE_LIST_DATA = {
+        "agents": [
+            {
+                "binary": "neutron-dhcp-agent",
+                "description": None,
+                "availability_zone": "nova",
+                "heartbeat_timestamp": "2017-09-12 19:39:56",
+                "admin_state_up": True,
+                "alive": True,
+                "id": "840d5d68-5759-4e9e-812f",
+                "topic": "dhcp_agent",
+                "host": "agenthost1",
+                "agent_type": "DHCP agent",
+                "started_at": "2017-09-12 19:35:36",
+                "created_at": "2017-09-12 19:35:36",
+                "resources_synced": None,
+                "configurations": {
+                    "subnets": 2,
+                    "dhcp_lease_duration": 86400,
+                    "dhcp_driver": "neutron.agent",
+                    "networks": 1,
+                    "log_agent_heartbeats": False,
+                    "ports": 3
+                }
+            }
+        ]
+    }
+
+    FAKE_SHOW_DATA = {
+        "agent": {
+            "binary": "neutron-openvswitch-agent",
+            "description": None,
+            "availability_zone": None,
+            "heartbeat_timestamp": "2017-09-12 19:40:38",
+            "admin_state_up": True,
+            "alive": True,
+            "id": "04c62b91-b799-48b7-9cd5-2982db6df9c6",
+            "topic": "N/A",
+            "host": "agenthost1",
+            "agent_type": "Open vSwitch agent",
+            "started_at": "2017-09-12 19:35:38",
+            "created_at": "2017-09-12 19:35:38",
+            "resources_synced": True,
+            "configurations": {
+                "ovs_hybrid_plug": True,
+                "in_distributed_mode": False,
+                "datapath_type": "system",
+                "vhostuser_socket_dir": "/var/run/openvswitch",
+                "tunneling_ip": "172.16.78.191",
+                "arp_responder_enabled": False,
+                "devices": 0,
+                "ovs_capabilities": {
+                    "datapath_types": [
+                        "netdev",
+                        "system"
+                    ],
+                    "iface_types": [
+                        "geneve",
+                        "gre",
+                        "internal",
+                        "ipsec_gre",
+                        "lisp",
+                        "patch",
+                        "stt",
+                        "system",
+                        "tap",
+                        "vxlan"
+                    ]
+                },
+                "log_agent_heartbeats": False,
+                "l2_population": False,
+                "tunnel_types": [
+                    "vxlan"
+                ],
+                "extensions": [],
+                "enable_distributed_routing": False,
+                "bridge_mappings": {
+                    "public": "br-ex"
+                }
+            }
+        }
+    }
+
+    FAKE_UPDATE_DATA = {
+        "agent": {
+            "description": "My OVS agent for OpenStack"
+        }
+    }
+
     def setUp(self):
         super(TestAgentsClient, self).setUp()
         fake_auth = fake_auth_provider.FakeAuthProvider()
         self.agents_client = agents_client.AgentsClient(
             fake_auth, "network", "regionOne")
 
+    def _test_show_agent(self, bytes_body=False):
+        self.check_service_client_function(
+            self.agents_client.show_agent,
+            "tempest.lib.common.rest_client.RestClient.get",
+            self.FAKE_SHOW_DATA,
+            bytes_body,
+            status=200,
+            agent_id=self.FAKE_AGENT_ID)
+
+    def _test_update_agent(self, bytes_body=False):
+        self.check_service_client_function(
+            self.agents_client.update_agent,
+            "tempest.lib.common.rest_client.RestClient.put",
+            self.FAKE_UPDATE_DATA,
+            bytes_body,
+            status=200,
+            agent_id=self.FAKE_AGENT_ID)
+
+    def _test_list_agents(self, bytes_body=False):
+        self.check_service_client_function(
+            self.agents_client.list_agents,
+            "tempest.lib.common.rest_client.RestClient.get",
+            self.FAKE_LIST_DATA,
+            bytes_body,
+            status=200)
+
+    def test_show_agent_with_str_body(self):
+        self._test_show_agent()
+
+    def test_show_agent_with_bytes_body(self):
+        self._test_show_agent(bytes_body=True)
+
+    def test_update_agent_with_str_body(self):
+        self._test_update_agent()
+
+    def test_update_agent_with_bytes_body(self):
+        self._test_update_agent(bytes_body=True)
+
+    def test_list_agent_with_str_body(self):
+        self._test_list_agents()
+
+    def test_list_agent_with_bytes_body(self):
+        self._test_list_agents(bytes_body=True)
+
     def test_delete_agent(self):
         self.check_service_client_function(
             self.agents_client.delete_agent,
diff --git a/tempest/tests/lib/services/network/test_routers_client.py b/tempest/tests/lib/services/network/test_routers_client.py
index 2fa5993..f5dcc7d 100644
--- a/tempest/tests/lib/services/network/test_routers_client.py
+++ b/tempest/tests/lib/services/network/test_routers_client.py
@@ -20,37 +20,78 @@
 class TestRoutersClient(base.BaseServiceTest):
     FAKE_CREATE_ROUTER = {
         "router": {
-            "name": u'\u2740(*\xb4\u25e1`*)\u2740',
+            "admin_state_up": True,
+            "availability_zone_hints": [],
+            "availability_zones": [
+                "nova"
+            ],
+            "created_at": "2018-03-19T19:17:04Z",
+            "description": "",
+            "distributed": False,
             "external_gateway_info": {
-                "network_id": "8ca37218-28ff-41cb-9b10-039601ea7e6b",
                 "enable_snat": True,
                 "external_fixed_ips": [
                     {
-                        "subnet_id": "255.255.255.0",
-                        "ip": "192.168.10.1"
+                        "ip_address": "172.24.4.6",
+                        "subnet_id": "b930d7f6-ceb7-40a0-8b81-a425dd994ccf"
                     }
-                ]
+                ],
+                "network_id": "ae34051f-aa6c-4c75-abf5-50dc9ac99ef3"
             },
-            "admin_state_up": True,
-            "id": "8604a0de-7f6b-409a-a47c-a1cc7bc77b2e"
+            "flavor_id": "f7b14d9a-b0dc-4fbe-bb14-a0f4970a69e0",
+            "ha": False,
+            "id": "f8a44de0-fc8e-45df-93c7-f79bf3b01c95",
+            "name": "router1",
+            "routes": [],
+            "revision_number": 1,
+            "status": "ACTIVE",
+            "updated_at": "2018-03-19T19:17:22Z",
+            "project_id": "0bd18306d801447bb457a46252d82d13",
+            "tenant_id": "0bd18306d801447bb457a46252d82d13",
+            "service_type_id": None,
+            "tags": ["tag1,tag2"],
+            "conntrack_helpers": []
         }
     }
 
     FAKE_UPDATE_ROUTER = {
         "router": {
-            "name": u'\u2740(*\xb4\u25e1`*)\u2740',
+            "admin_state_up": True,
+            "availability_zone_hints": [],
+            "availability_zones": [
+                "nova"
+            ],
+            "created_at": "2018-03-19T19:17:04Z",
+            "description": "",
+            "distributed": False,
             "external_gateway_info": {
-                "network_id": "8ca37218-28ff-41cb-9b10-039601ea7e6b",
                 "enable_snat": True,
                 "external_fixed_ips": [
                     {
-                        "subnet_id": "255.255.255.0",
-                        "ip": "192.168.10.1"
+                        "ip_address": "172.24.4.6",
+                        "subnet_id": "b930d7f6-ceb7-40a0-8b81-a425dd994ccf"
                     }
-                ]
+                ],
+                "network_id": "ae34051f-aa6c-4c75-abf5-50dc9ac99ef3"
             },
-            "admin_state_up": False,
-            "id": "8604a0de-7f6b-409a-a47c-a1cc7bc77b2e"
+            "flavor_id": "f7b14d9a-b0dc-4fbe-bb14-a0f4970a69e0",
+            "ha": False,
+            "id": "f8a44de0-fc8e-45df-93c7-f79bf3b01c95",
+            "name": "router1",
+            "revision_number": 3,
+            "routes": [
+                {
+                    "destination": "179.24.1.0/24",
+                    "nexthop": "172.24.3.99"
+                }
+            ],
+            "status": "ACTIVE",
+            "updated_at": "2018-03-19T19:17:22Z",
+            "project_id": "0bd18306d801447bb457a46252d82d13",
+            "tenant_id": "0bd18306d801447bb457a46252d82d13",
+            "service_type_id": None,
+            "tags": ["tag1,tag2"],
+            "conntrack_helpers": []
         }
     }
 
diff --git a/tempest/tests/lib/services/volume/v3/test_snapshots_client.py b/tempest/tests/lib/services/volume/v3/test_snapshots_client.py
index 2efd2e6..1ea4c65 100644
--- a/tempest/tests/lib/services/volume/v3/test_snapshots_client.py
+++ b/tempest/tests/lib/services/volume/v3/test_snapshots_client.py
@@ -20,61 +20,85 @@
 class TestSnapshotsClient(base.BaseServiceTest):
     FAKE_CREATE_SNAPSHOT = {
         "snapshot": {
-            "display_name": "snap-001",
-            "display_description": "Daily backup",
-            "volume_id": "521752a6-acf6-4b2d-bc7a-119f9148cd8c",
-            "force": True
+            "created_at": "2019-03-11T16:24:34.469003",
+            "description": "Daily backup",
+            "id": "b36476e5-d18b-47f9-ac69-4818cb43ee21",
+            "metadata": {
+                "key": "v3"
+            },
+            "name": "snap-001",
+            "size": 10,
+            "status": "creating",
+            "updated_at": None,
+            "volume_id": "d291b81c-6e40-4525-8231-90aa1588121e"
         }
     }
 
-    FAKE_UPDATE_SNAPSHOT_REQUEST = {
-        "metadata": {
-            "key": "v1"
+    FAKE_UPDATE_SNAPSHOT_RESPONSE = {
+        "snapshot": {
+            "created_at": "2019-03-12T04:53:53.426591",
+            "description": "This is yet, another snapshot.",
+            "id": "4a584cae-e4ce-429b-9154-d4c9eb8fda4c",
+            "metadata": {
+                "key": "v3"
+            },
+            "name": "snap-002",
+            "size": 10,
+            "status": "creating",
+            "updated_at": None,
+            "volume_id": "070c942d-9909-42e9-a467-7a781f150c58"
         }
     }
 
     FAKE_INFO_SNAPSHOT = {
         "snapshot": {
-            "id": "3fbbcccf-d058-4502-8844-6feeffdf4cb5",
-            "display_name": "snap-001",
-            "display_description": "Daily backup",
-            "volume_id": "521752a6-acf6-4b2d-bc7a-119f9148cd8c",
-            "status": "available",
-            "size": 30,
-            "created_at": "2012-02-29T03:50:07Z"
+            "created_at": "2019-03-12T04:42:00.809352",
+            "description": "Daily backup",
+            "id": "4a584cae-e4ce-429b-9154-d4c9eb8fda4c",
+            "metadata": {
+                "key": "v3"
+            },
+            "name": "snap-001",
+            "os-extended-snapshot-attributes:progress": "0%",
+            "os-extended-snapshot-attributes:project_id":
+                "89afd400-b646-4bbc-b12b-c0a4d63e5bd3",
+            "size": 10,
+            "status": "creating",
+            "updated_at": None,
+            "volume_id": "b72c48f1-64b7-4cd8-9745-b12e0be82d37"
         }
     }
 
     FAKE_LIST_SNAPSHOTS = {
         "snapshots": [
             {
-                "id": "3fbbcccf-d058-4502-8844-6feeffdf4cb5",
-                "display_name": "snap-001",
-                "display_description": "Daily backup",
-                "volume_id": "521752a6-acf6-4b2d-bc7a-119f9148cd8c",
-                "status": "available",
-                "size": 30,
-                "created_at": "2012-02-29T03:50:07Z",
+                "created_at": "2019-03-11T16:24:36.464445",
+                "description": "Daily backup",
+                "id": "d0083dc5-8795-4c1a-bc9c-74f70006c205",
                 "metadata": {
-                    "contents": "junk"
-                }
-            },
-            {
-                "id": "e479997c-650b-40a4-9dfe-77655818b0d2",
-                "display_name": "snap-002",
-                "display_description": "Weekly backup",
-                "volume_id": "76b8950a-8594-4e5b-8dce-0dfa9c696358",
-                "status": "available",
-                "size": 25,
-                "created_at": "2012-03-19T01:52:47Z",
-                "metadata": {}
+                    "key": "v3"
+                },
+                "name": "snap-001",
+                "os-extended-snapshot-attributes:progress": "0%",
+                "os-extended-snapshot-attributes:project_id":
+                    "89afd400-b646-4bbc-b12b-c0a4d63e5bd3",
+                "size": 10,
+                "status": "creating",
+                "updated_at": None,
+                "volume_id": "7acd675e-4e06-4653-af9f-2ecd546342d6"
             }
         ]
     }
 
     FAKE_SNAPSHOT_METADATA_ITEM = {
+        "metadata": {
+            "key": "value"
+        }
+    }
+
+    FAKE_SNAPSHOT_KEY = {
         "meta": {
-            "key1": "value1"
+            "key": "new_value"
         }
     }
 
@@ -99,7 +123,7 @@
             'tempest.lib.common.rest_client.RestClient.get',
             self.FAKE_INFO_SNAPSHOT,
             bytes_body,
-            snapshot_id="3fbbcccf-d058-4502-8844-6feeffdf4cb5")
+            snapshot_id="4a584cae-e4ce-429b-9154-d4c9eb8fda4c")
 
     def _test_list_snapshots(self, bytes_body=False):
         self.check_service_client_function(
@@ -113,48 +137,48 @@
         self.check_service_client_function(
             self.client.create_snapshot_metadata,
             'tempest.lib.common.rest_client.RestClient.post',
-            self.FAKE_INFO_SNAPSHOT,
+            self.FAKE_SNAPSHOT_METADATA_ITEM,
             bytes_body,
-            snapshot_id="3fbbcccf-d058-4502-8844-6feeffdf4cb5",
-            metadata={"key": "v1"})
+            snapshot_id="4a584cae-e4ce-429b-9154-d4c9eb8fda4c",
+            metadata={"key": "value"})
 
     def _test_update_snapshot(self, bytes_body=False):
         self.check_service_client_function(
             self.client.update_snapshot,
             'tempest.lib.common.rest_client.RestClient.put',
-            self.FAKE_UPDATE_SNAPSHOT_REQUEST,
+            self.FAKE_UPDATE_SNAPSHOT_RESPONSE,
             bytes_body,
-            snapshot_id="3fbbcccf-d058-4502-8844-6feeffdf4cb5")
+            snapshot_id="4a584cae-e4ce-429b-9154-d4c9eb8fda4c")
 
     def _test_show_snapshot_metadata(self, bytes_body=False):
         self.check_service_client_function(
             self.client.show_snapshot_metadata,
             'tempest.lib.common.rest_client.RestClient.get',
-            self.FAKE_UPDATE_SNAPSHOT_REQUEST,
+            self.FAKE_SNAPSHOT_METADATA_ITEM,
             bytes_body,
-            snapshot_id="3fbbcccf-d058-4502-8844-6feeffdf4cb5")
+            snapshot_id="4a584cae-e4ce-429b-9154-d4c9eb8fda4c")
 
     def _test_update_snapshot_metadata(self, bytes_body=False):
         self.check_service_client_function(
             self.client.update_snapshot_metadata,
             'tempest.lib.common.rest_client.RestClient.put',
-            self.FAKE_UPDATE_SNAPSHOT_REQUEST,
-            bytes_body, snapshot_id="cbc36478b0bd8e67e89")
+            self.FAKE_SNAPSHOT_METADATA_ITEM,
+            bytes_body, snapshot_id="4a584cae-e4ce-429b-9154-d4c9eb8fda4c")
 
     def _test_update_snapshot_metadata_item(self, bytes_body=False):
         self.check_service_client_function(
             self.client.update_snapshot_metadata_item,
             'tempest.lib.common.rest_client.RestClient.put',
-            self.FAKE_INFO_SNAPSHOT,
+            self.FAKE_SNAPSHOT_KEY,
             bytes_body, volume_type_id="cbc36478b0bd8e67e89")
 
     def _test_show_snapshot_metadata_item(self, bytes_body=False):
         self.check_service_client_function(
             self.client.show_snapshot_metadata_item,
             'tempest.lib.common.rest_client.RestClient.get',
-            self.FAKE_SNAPSHOT_METADATA_ITEM,
+            self.FAKE_SNAPSHOT_KEY,
             bytes_body,
-            snapshot_id="3fbbcccf-d058-4502-8844-6feeffdf4cb5",
+            snapshot_id="4a584cae-e4ce-429b-9154-d4c9eb8fda4c",
             id="key1")
 
     def test_create_snapshot_with_str_body(self):
diff --git a/tox.ini b/tox.ini
index 401bbfe..64921ef 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,5 +1,5 @@
 [tox]
-envlist = pep8,py36,py37,py27,bashate,pip-check-reqs
+envlist = pep8,py36,py37,bashate,pip-check-reqs
 minversion = 3.1.1
 skipsdist = True
 ignore_basepython_conflict = True