Merge "Set default value for tox tasks"
diff --git a/.zuul.yaml b/.zuul.yaml
index 0d2005b..462501e 100644
--- a/.zuul.yaml
+++ b/.zuul.yaml
@@ -613,8 +613,6 @@
             irrelevant-files: *tempest-irrelevant-files
         - neutron-tempest-dvr-ha-multinode-full:
             irrelevant-files: *tempest-irrelevant-files
-        - nova-cells-v1:
-            irrelevant-files: *tempest-irrelevant-files
         - nova-tempest-v2-api:
             irrelevant-files: *tempest-irrelevant-files
         - legacy-tempest-dsvm-lvm-multibackend:
diff --git a/HACKING.rst b/HACKING.rst
index 1559fc6..204b3c7 100644
--- a/HACKING.rst
+++ b/HACKING.rst
@@ -457,7 +457,7 @@
 by modifying Tempest's `lib installation script`_ for previous branches
 (because DevStack is branched).
 
-.. _lib installation script: https://git.openstack.org/cgit/openstack-dev/devstack/tree/lib/tempest
+.. _lib installation script: https://opendev.org/openstack/devstack/src/branch/master/lib/tempest
 
 2. Bug fix on core project needing Tempest changes
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/README.rst b/README.rst
index 73930f1..841fae6 100644
--- a/README.rst
+++ b/README.rst
@@ -61,7 +61,7 @@
 #. You first need to install Tempest. This is done with pip after you check out
    the Tempest repo::
 
-    $ git clone https://git.openstack.org/openstack/tempest
+    $ git clone https://opendev.org/openstack/tempest
     $ pip install tempest/
 
    This can be done within a venv, but the assumption for this guide is that
@@ -119,6 +119,17 @@
    will run the same set of tests as the default gate jobs. Or you can
    use `unittest`_ compatible test runners such as `testr`_, `pytest`_ etc.
 
+   Tox also contains several existing job configurations. For example::
+
+    $ tox -e full
+
+   which will run the same set of tests as the OpenStack gate. (it's exactly how
+   the gate invokes Tempest) Or::
+
+    $ tox -e smoke
+
+   to run the tests tagged as smoke.
+
 .. _unittest: https://docs.python.org/3/library/unittest.html
 .. _testr: https://testrepository.readthedocs.org/en/latest/MANUAL.html
 .. _stestr: https://stestr.readthedocs.org/en/latest/MANUAL.html
@@ -270,14 +281,3 @@
 To run one single test serially ::
 
     $ testr run tempest.api.compute.servers.test_servers_negative.ServersNegativeTestJSON.test_reboot_non_existent_server
-
-Tox also contains several existing job configurations. For example::
-
-    $ tox -e full
-
-which will run the same set of tests as the OpenStack gate. (it's exactly how
-the gate invokes Tempest) Or::
-
-    $ tox -e smoke
-
-to run the tests tagged as smoke.
diff --git a/REVIEWING.rst b/REVIEWING.rst
index 31fedce..498ce66 100644
--- a/REVIEWING.rst
+++ b/REVIEWING.rst
@@ -187,4 +187,4 @@
   Note that such a policy should be used judiciously, as we should strive to
   have two +2's on each patch set, prior to approval.
 
-.. _example: https://review.openstack.org/#/c/611032/
+.. _example: https://review.opendev.org/#/c/611032/
diff --git a/doc/source/microversion_testing.rst b/doc/source/microversion_testing.rst
index 4b1c145..b4f06e3 100644
--- a/doc/source/microversion_testing.rst
+++ b/doc/source/microversion_testing.rst
@@ -406,6 +406,14 @@
 
   .. _2.63: https://docs.openstack.org/nova/latest/reference/api-microversion-history.html#id57
 
+  * `2.70`_
+
+  .. _2.70: https://docs.openstack.org/nova/latest/reference/api-microversion-history.html#id63
+
+  * `2.71`_
+
+  .. _2.71: https://docs.openstack.org/nova/latest/reference/api-microversion-history.html#id64
+
 * Volume
 
   * `3.3`_
diff --git a/doc/source/plugin.rst b/doc/source/plugin.rst
index dc0e94c..a9e2059 100644
--- a/doc/source/plugin.rst
+++ b/doc/source/plugin.rst
@@ -43,7 +43,7 @@
 In order to create the basic structure with base classes and test directories
 you can use the tempest-plugin-cookiecutter project::
 
-  > pip install -U cookiecutter && cookiecutter https://git.openstack.org/openstack/tempest-plugin-cookiecutter
+  > pip install -U cookiecutter && cookiecutter https://opendev.org/openstack/tempest-plugin-cookiecutter
 
   Cloning into 'tempest-plugin-cookiecutter'...
   remote: Counting objects: 17, done.
diff --git a/releasenotes/notes/QoS-client-for-placement-based-minimum-bw-allocation-8e5854d5754cec68.yaml b/releasenotes/notes/QoS-client-for-placement-based-minimum-bw-allocation-8e5854d5754cec68.yaml
new file mode 100644
index 0000000..b66ea3a
--- /dev/null
+++ b/releasenotes/notes/QoS-client-for-placement-based-minimum-bw-allocation-8e5854d5754cec68.yaml
@@ -0,0 +1,25 @@
+---
+features:
+  - |
+    Add ``qos-policies`` and ``qos-minimum-bandwidth-rule`` clients
+    to Tempest to make possible the testing of the placement based
+    bandwidth allocation feature.
+    The following API calls are available for tempest from now:
+
+    ``QoS policies`` client:
+
+    * GET /qos/policies
+    * POST /qos/policies
+    * GET /qos/policies/{policy_id}
+    * PUT /qos/policies/{policy_id}
+    * DELETE /qos/policies/{policy_id}
+
+
+    ``QoS minimum bandwidth rules`` client:
+
+    * GET qos/policies/{policy_id}/minimum_bandwidth_rules
+    * POST /qos/policies/{policy_id}/minimum_bandwidth_rules
+    * GET qos/policies/{policy_id}/minimum_bandwidth_rules/{rule_id}
+    * PUT qos/policies/{policy_id}/minimum_bandwidth_rules/{rule_id}
+    * DELETE /qos/policies/{policy_id}/minimum_bandwidth_rules/{rule_id}
+
diff --git a/releasenotes/notes/correct-port-profile-config-option-d67f5cb31f1bc34c.yaml b/releasenotes/notes/correct-port-profile-config-option-d67f5cb31f1bc34c.yaml
index 7510d47..2830aa2 100644
--- a/releasenotes/notes/correct-port-profile-config-option-d67f5cb31f1bc34c.yaml
+++ b/releasenotes/notes/correct-port-profile-config-option-d67f5cb31f1bc34c.yaml
@@ -1,7 +1,7 @@
 ---
 fixes:
   - |
-    Patch https://review.openstack.org/#/c/499575/ introduced
+    Patch https://review.opendev.org/#/c/499575/ introduced
     support creating Neutron port with certain capabilities.
     Currently capabilities list interpreted as string this change
     fix it.
diff --git a/releasenotes/notes/lib_api_microversion_fixture-f52308fc6b6b89f2.yaml b/releasenotes/notes/lib_api_microversion_fixture-f52308fc6b6b89f2.yaml
new file mode 100644
index 0000000..d707fc7
--- /dev/null
+++ b/releasenotes/notes/lib_api_microversion_fixture-f52308fc6b6b89f2.yaml
@@ -0,0 +1,7 @@
+---
+features:
+  - |
+    New library interface to set the API microversion on Service Clients.
+    ``APIMicroversionFixture,`` can be used to set the API microversion
+    on multiple services. This Fixture will take care of reseting the service
+    microversion to None once test is finished.
diff --git a/releasenotes/notes/remove-some-deprecated-auth-and-identity-options-xa1xd9b8fb948g4f.yaml b/releasenotes/notes/remove-some-deprecated-auth-and-identity-options-xa1xd9b8fb948g4f.yaml
new file mode 100644
index 0000000..fa21afd
--- /dev/null
+++ b/releasenotes/notes/remove-some-deprecated-auth-and-identity-options-xa1xd9b8fb948g4f.yaml
@@ -0,0 +1,8 @@
+upgrade:
+  - |
+    Remove deprecated config option ``endpoint_type`` from
+    ``identity`` group. Use ``v2_public_endpoint_type`` from
+    ``identity`` group instead.
+    Remove deprecated config option ``tenant_isolation_domain_name``
+    from ``auth`` group. Use ``default_credentials_domain_name`` from
+    ``auth`` group instead.
diff --git a/releasenotes/notes/remove-some-deprecated-identity-options-0ffxd1b8db928e43.yaml b/releasenotes/notes/remove-some-deprecated-identity-options-0ffxd1b8db928e43.yaml
new file mode 100644
index 0000000..e9e9444
--- /dev/null
+++ b/releasenotes/notes/remove-some-deprecated-identity-options-0ffxd1b8db928e43.yaml
@@ -0,0 +1,11 @@
+upgrade:
+  - |
+    Remove deprecated config option ``admin_username`` from
+    ``identity`` groups. Use ``admin_username`` from ``auth`` instead.
+    Remove deprecated config option ``admin_tenant_name`` from
+    ``auth`` and ``identity`` groups. Use ``admin_project_name`` from
+    ``auth`` instead.
+    Remove deprecated config option ``admin_password`` from
+    ``identity`` groups. Use ``admin_password`` from ``auth`` instead.
+    Remove deprecated config option ``admin_domain_name`` from
+    ``identity`` groups. Use ``admin_domain_name`` from ``auth`` instead.
\ No newline at end of file
diff --git a/releasenotes/notes/support-microversion-in-scenario-test-b4fbfdd3a977fc58.yaml b/releasenotes/notes/support-microversion-in-scenario-test-b4fbfdd3a977fc58.yaml
new file mode 100644
index 0000000..4d0a3dd
--- /dev/null
+++ b/releasenotes/notes/support-microversion-in-scenario-test-b4fbfdd3a977fc58.yaml
@@ -0,0 +1,14 @@
+---
+features:
+  - |
+    Add microversion support for scenario tests. Scenario test calls
+    multiple service API within same test and many services like compute,
+    volume and placement etc support API microversion. With microversion
+    support in scenario test, we can call different service API with
+    different microvesion. Which means we can implement scenario tests
+    for microversion also.
+    Currently Scenario manager support below services microversion:
+
+    * Compute
+    * Volume
+    * Placement
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index 624a99e..e71e642 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -17,11 +17,11 @@
 
 from oslo_log import log as logging
 
-from tempest.api.compute import api_microversion_fixture
 from tempest.common import compute
 from tempest.common import waiters
 from tempest import config
 from tempest import exceptions
+from tempest.lib.common import api_microversion_fixture
 from tempest.lib.common import api_version_request
 from tempest.lib.common import api_version_utils
 from tempest.lib.common.utils import data_utils
@@ -470,7 +470,7 @@
     def setUp(self):
         super(BaseV2ComputeTest, self).setUp()
         self.useFixture(api_microversion_fixture.APIMicroversionFixture(
-            self.request_microversion))
+            compute_microversion=self.request_microversion))
 
     @classmethod
     def create_volume(cls, image_ref=None, **kwargs):
diff --git a/tempest/api/compute/test_extensions.py b/tempest/api/compute/test_extensions.py
index 34faf5f..12e7fea 100644
--- a/tempest/api/compute/test_extensions.py
+++ b/tempest/api/compute/test_extensions.py
@@ -37,7 +37,7 @@
         ext = CONF.compute_feature_enabled.api_extensions[0]
 
         # Log extensions list
-        extension_list = map(lambda x: x['alias'], extensions)
+        extension_list = [x['alias'] for x in extensions]
         LOG.debug("Nova extensions: %s", ','.join(extension_list))
 
         if ext == 'all':
diff --git a/tempest/api/identity/v2/test_users.py b/tempest/api/identity/v2/test_users.py
index 158dfb3..2eea860 100644
--- a/tempest/api/identity/v2/test_users.py
+++ b/tempest/api/identity/v2/test_users.py
@@ -15,6 +15,8 @@
 
 import time
 
+import testtools
+
 from tempest.api.identity import base
 from tempest import config
 from tempest.lib.common.utils import data_utils
@@ -78,6 +80,10 @@
         self.non_admin_users_client.auth_provider.set_auth()
 
     @decorators.idempotent_id('165859c9-277f-4124-9479-a7d1627b0ca7')
+    @testtools.skipIf(CONF.identity_feature_enabled.immutable_user_source,
+                      'Skipped because environment has an '
+                      'immutable user source and solely '
+                      'provides read-only access to users.')
     def test_user_update_own_password(self):
         old_pass = self.creds.password
         old_token = self.non_admin_users_client.token
diff --git a/tempest/api/identity/v3/test_catalog.py b/tempest/api/identity/v3/test_catalog.py
index deec2dc..bc95f0d 100644
--- a/tempest/api/identity/v3/test_catalog.py
+++ b/tempest/api/identity/v3/test_catalog.py
@@ -22,8 +22,8 @@
 
     @decorators.idempotent_id('56b57ced-22b8-4127-9b8a-565dfb0207e2')
     def test_catalog_standardization(self):
-        # http://git.openstack.org/cgit/openstack/service-types-authority
-        # /tree/service-types.yaml
+        # https://opendev.org/openstack/service-types-authority
+        # /src/branch/master/service-types.yaml
         standard_service_values = [{'name': 'keystone', 'type': 'identity'},
                                    {'name': 'nova', 'type': 'compute'},
                                    {'name': 'glance', 'type': 'image'},
diff --git a/tempest/api/identity/v3/test_users.py b/tempest/api/identity/v3/test_users.py
index 13b5161..d4e7612 100644
--- a/tempest/api/identity/v3/test_users.py
+++ b/tempest/api/identity/v3/test_users.py
@@ -77,6 +77,10 @@
         self.non_admin_users_client.auth_provider.set_auth()
 
     @decorators.idempotent_id('ad71bd23-12ad-426b-bb8b-195d2b635f27')
+    @testtools.skipIf(CONF.identity_feature_enabled.immutable_user_source,
+                      'Skipped because environment has an '
+                      'immutable user source and solely '
+                      'provides read-only access to users.')
     def test_user_update_own_password(self):
         old_pass = self.creds.password
         old_token = self.non_admin_client.token
@@ -102,6 +106,10 @@
     @testtools.skipUnless(CONF.identity_feature_enabled.security_compliance,
                           'Security compliance not available.')
     @decorators.idempotent_id('941784ee-5342-4571-959b-b80dd2cea516')
+    @testtools.skipIf(CONF.identity_feature_enabled.immutable_user_source,
+                      'Skipped because environment has an '
+                      'immutable user source and solely '
+                      'provides read-only access to users.')
     def test_password_history_check_self_service_api(self):
         old_pass = self.creds.password
         new_pass1 = data_utils.rand_password()
diff --git a/tempest/api/network/admin/test_external_network_extension.py b/tempest/api/network/admin/test_external_network_extension.py
index 7e8cc8e..5bd3fce 100644
--- a/tempest/api/network/admin/test_external_network_extension.py
+++ b/tempest/api/network/admin/test_external_network_extension.py
@@ -36,6 +36,7 @@
         body = self.admin_networks_client.create_network(**post_body)
         network = body['network']
         self.addCleanup(
+            test_utils.call_and_ignore_notfound_exc,
             self.admin_networks_client.delete_network, network['id'])
         return network
 
diff --git a/tempest/api/network/admin/test_floating_ips_admin_actions.py b/tempest/api/network/admin/test_floating_ips_admin_actions.py
index be0c4c6..adc4dda 100644
--- a/tempest/api/network/admin/test_floating_ips_admin_actions.py
+++ b/tempest/api/network/admin/test_floating_ips_admin_actions.py
@@ -16,6 +16,7 @@
 from tempest.api.network import base
 from tempest.common import utils
 from tempest import config
+from tempest.lib.common.utils import test_utils
 from tempest.lib import decorators
 
 CONF = config.CONF
@@ -57,14 +58,18 @@
         # Create floating ip from admin user
         floating_ip_admin = self.admin_floating_ips_client.create_floatingip(
             floating_network_id=self.ext_net_id)
-        self.addCleanup(self.admin_floating_ips_client.delete_floatingip,
-                        floating_ip_admin['floatingip']['id'])
+        self.addCleanup(
+            test_utils.call_and_ignore_notfound_exc,
+            self.admin_floating_ips_client.delete_floatingip,
+            floating_ip_admin['floatingip']['id'])
         # Create floating ip from alt user
         body = self.alt_floating_ips_client.create_floatingip(
             floating_network_id=self.ext_net_id)
         floating_ip_alt = body['floatingip']
-        self.addCleanup(self.alt_floating_ips_client.delete_floatingip,
-                        floating_ip_alt['id'])
+        self.addCleanup(
+            test_utils.call_and_ignore_notfound_exc,
+            self.alt_floating_ips_client.delete_floatingip,
+            floating_ip_alt['id'])
         # List floating ips from admin
         body = self.admin_floating_ips_client.list_floatingips()
         floating_ip_ids_admin = [f['id'] for f in body['floatingips']]
@@ -91,8 +96,10 @@
             tenant_id=self.network['tenant_id'],
             port_id=self.port['id'])
         created_floating_ip = body['floatingip']
-        self.addCleanup(self.floating_ips_client.delete_floatingip,
-                        created_floating_ip['id'])
+        self.addCleanup(
+            test_utils.call_and_ignore_notfound_exc,
+            self.floating_ips_client.delete_floatingip,
+            created_floating_ip['id'])
         self.assertIsNotNone(created_floating_ip['id'])
         self.assertIsNotNone(created_floating_ip['tenant_id'])
         self.assertIsNotNone(created_floating_ip['floating_ip_address'])
diff --git a/tempest/api/network/admin/test_negative_quotas.py b/tempest/api/network/admin/test_negative_quotas.py
index 9d1e2a7..0db038d 100644
--- a/tempest/api/network/admin/test_negative_quotas.py
+++ b/tempest/api/network/admin/test_negative_quotas.py
@@ -17,6 +17,7 @@
 from tempest.common import identity
 from tempest.common import utils
 from tempest.lib.common.utils import data_utils
+from tempest.lib.common.utils import test_utils
 from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
 
@@ -58,11 +59,13 @@
         # Create two networks
         n1 = self.admin_networks_client.create_network(
             tenant_id=self.project['id'])
-        self.addCleanup(self.admin_networks_client.delete_network,
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.admin_networks_client.delete_network,
                         n1['network']['id'])
         n2 = self.admin_networks_client.create_network(
             tenant_id=self.project['id'])
-        self.addCleanup(self.admin_networks_client.delete_network,
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.admin_networks_client.delete_network,
                         n2['network']['id'])
 
         # Try to create a third network while the quota is two
@@ -71,5 +74,6 @@
                 r"Quota exceeded for resources: \['network'\].*"):
             n3 = self.admin_networks_client.create_network(
                 tenant_id=self.project['id'])
-            self.addCleanup(self.admin_networks_client.delete_network,
+            self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                            self.admin_networks_client.delete_network,
                             n3['network']['id'])
diff --git a/tempest/api/network/admin/test_ports.py b/tempest/api/network/admin/test_ports.py
index 05363db..edfda6e 100644
--- a/tempest/api/network/admin/test_ports.py
+++ b/tempest/api/network/admin/test_ports.py
@@ -14,6 +14,7 @@
 #    under the License.
 
 from tempest.api.network import base
+from tempest.lib.common.utils import test_utils
 from tempest.lib import decorators
 
 
@@ -37,7 +38,9 @@
                      "binding:host_id": self.host_id}
         body = self.admin_ports_client.create_port(**post_body)
         port = body['port']
-        self.addCleanup(self.admin_ports_client.delete_port, port['id'])
+        self.addCleanup(
+            test_utils.call_and_ignore_notfound_exc,
+            self.admin_ports_client.delete_port, port['id'])
         host_id = port['binding:host_id']
         self.assertIsNotNone(host_id)
         self.assertEqual(self.host_id, host_id)
@@ -47,7 +50,9 @@
         post_body = {"network_id": self.network['id']}
         body = self.admin_ports_client.create_port(**post_body)
         port = body['port']
-        self.addCleanup(self.admin_ports_client.delete_port, port['id'])
+        self.addCleanup(
+            test_utils.call_and_ignore_notfound_exc,
+            self.admin_ports_client.delete_port, port['id'])
         update_body = {"binding:host_id": self.host_id}
         body = self.admin_ports_client.update_port(port['id'], **update_body)
         updated_port = body['port']
@@ -61,7 +66,9 @@
         post_body = {"network_id": self.network['id']}
         body = self.admin_ports_client.create_port(**post_body)
         port = body['port']
-        self.addCleanup(self.admin_ports_client.delete_port, port['id'])
+        self.addCleanup(
+            test_utils.call_and_ignore_notfound_exc,
+            self.admin_ports_client.delete_port, port['id'])
 
         # Update the port's binding attributes so that is now 'bound'
         # to a host
@@ -85,7 +92,8 @@
         body = self.admin_ports_client.create_port(
             network_id=self.network['id'])
         port = body['port']
-        self.addCleanup(self.admin_ports_client.delete_port, port['id'])
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.admin_ports_client.delete_port, port['id'])
         body = self.admin_ports_client.show_port(port['id'])
         show_port = body['port']
         self.assertEqual(port['binding:host_id'],
diff --git a/tempest/api/network/admin/test_routers.py b/tempest/api/network/admin/test_routers.py
index 6ce86fb..a4a057c 100644
--- a/tempest/api/network/admin/test_routers.py
+++ b/tempest/api/network/admin/test_routers.py
@@ -20,6 +20,7 @@
 from tempest.common import utils
 from tempest import config
 from tempest.lib.common.utils import data_utils
+from tempest.lib.common.utils import test_utils
 from tempest.lib import decorators
 
 CONF = config.CONF
@@ -38,7 +39,8 @@
         # associate a cleanup with created routers to avoid quota limits
         router = self.create_router(name, admin_state_up,
                                     external_network_id, enable_snat)
-        self.addCleanup(self._cleanup_router, router)
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self._cleanup_router, router)
         return router
 
     @classmethod
@@ -62,7 +64,8 @@
         name = data_utils.rand_name('router-')
         create_body = self.admin_routers_client.create_router(
             name=name, tenant_id=project_id)
-        self.addCleanup(self.admin_routers_client.delete_router,
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.admin_routers_client.delete_router,
                         create_body['router']['id'])
         self.assertEqual(project_id, create_body['router']['tenant_id'])
 
@@ -92,7 +95,8 @@
                 'enable_snat': enable_snat}
             create_body = self.admin_routers_client.create_router(
                 name=name, external_gateway_info=external_gateway_info)
-            self.addCleanup(self.admin_routers_client.delete_router,
+            self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                            self.admin_routers_client.delete_router,
                             create_body['router']['id'])
             # Verify snat attributes after router creation
             self._verify_router_gateway(create_body['router']['id'],
diff --git a/tempest/api/network/admin/test_routers_dvr.py b/tempest/api/network/admin/test_routers_dvr.py
index 93478e6..270f802 100644
--- a/tempest/api/network/admin/test_routers_dvr.py
+++ b/tempest/api/network/admin/test_routers_dvr.py
@@ -18,6 +18,7 @@
 from tempest.api.network import base
 from tempest.common import utils
 from tempest.lib.common.utils import data_utils
+from tempest.lib.common.utils import test_utils
 from tempest.lib import decorators
 
 
@@ -62,7 +63,8 @@
         name = data_utils.rand_name('router')
         router = self.admin_routers_client.create_router(name=name,
                                                          distributed=True)
-        self.addCleanup(self.admin_routers_client.delete_router,
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.admin_routers_client.delete_router,
                         router['router']['id'])
         self.assertTrue(router['router']['distributed'])
 
@@ -82,7 +84,8 @@
         name = data_utils.rand_name('router')
         router = self.admin_routers_client.create_router(name=name,
                                                          distributed=False)
-        self.addCleanup(self.admin_routers_client.delete_router,
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.admin_routers_client.delete_router,
                         router['router']['id'])
         self.assertFalse(router['router']['distributed'])
 
@@ -112,8 +115,8 @@
                                                          ha=False,
                                                          tenant_id=tenant_id)
         router_id = router['router']['id']
-        self.addCleanup(self.admin_routers_client.delete_router,
-                        router_id)
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.admin_routers_client.delete_router, router_id)
         self.assertFalse(router['router']['distributed'])
         router = self.admin_routers_client.update_router(
             router_id, distributed=True)
diff --git a/tempest/api/network/admin/test_routers_negative.py b/tempest/api/network/admin/test_routers_negative.py
index 9356bcc..fdcc977 100644
--- a/tempest/api/network/admin/test_routers_negative.py
+++ b/tempest/api/network/admin/test_routers_negative.py
@@ -18,6 +18,7 @@
 from tempest.api.network import base
 from tempest.common import utils
 from tempest import config
+from tempest.lib.common.utils import test_utils
 from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
 
@@ -42,7 +43,8 @@
         # At first create a address from public_network_id
         port = self.admin_ports_client.create_port(
             network_id=CONF.network.public_network_id)['port']
-        self.addCleanup(self.admin_ports_client.delete_port,
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.admin_ports_client.delete_port,
                         port_id=port['id'])
         # Add used ip and subnet_id in external_fixed_ips
         fixed_ip = {
diff --git a/tempest/api/network/base_security_groups.py b/tempest/api/network/base_security_groups.py
index b8d677a..32f2cdd 100644
--- a/tempest/api/network/base_security_groups.py
+++ b/tempest/api/network/base_security_groups.py
@@ -15,6 +15,7 @@
 
 from tempest.api.network import base
 from tempest.lib.common.utils import data_utils
+from tempest.lib.common.utils import test_utils
 
 
 class BaseSecGroupTest(base.BaseNetworkTest):
@@ -24,7 +25,8 @@
         name = data_utils.rand_name('secgroup-')
         group_create_body = (
             self.security_groups_client.create_security_group(name=name))
-        self.addCleanup(self._delete_security_group,
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self._delete_security_group,
                         group_create_body['security_group']['id'])
         self.assertEqual(group_create_body['security_group']['name'], name)
         return group_create_body, name
diff --git a/tempest/api/network/test_allowed_address_pair.py b/tempest/api/network/test_allowed_address_pair.py
index dec3413..d393207 100644
--- a/tempest/api/network/test_allowed_address_pair.py
+++ b/tempest/api/network/test_allowed_address_pair.py
@@ -17,6 +17,7 @@
 
 from tempest.api.network import base
 from tempest.common import utils
+from tempest.lib.common.utils import test_utils
 from tempest.lib import decorators
 
 
@@ -62,7 +63,8 @@
             network_id=self.network['id'],
             allowed_address_pairs=allowed_address_pairs)
         port_id = body['port']['id']
-        self.addCleanup(self.ports_client.delete_port, port_id)
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.ports_client.delete_port, port_id)
 
         # Confirm port was created with allowed address pair attribute
         body = self.ports_client.list_ports()
@@ -76,7 +78,8 @@
         # Create a port without allowed address pair
         body = self.ports_client.create_port(network_id=self.network['id'])
         port_id = body['port']['id']
-        self.addCleanup(self.ports_client.delete_port, port_id)
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.ports_client.delete_port, port_id)
         if mac_address is None:
             mac_address = self.mac_address
 
@@ -106,7 +109,8 @@
         # Create an ip _address and mac_address through port create
         resp = self.ports_client.create_port(network_id=self.network['id'])
         newportid = resp['port']['id']
-        self.addCleanup(self.ports_client.delete_port, newportid)
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.ports_client.delete_port, newportid)
         ipaddress = resp['port']['fixed_ips'][0]['ip_address']
         macaddress = resp['port']['mac_address']
 
diff --git a/tempest/api/network/test_extra_dhcp_options.py b/tempest/api/network/test_extra_dhcp_options.py
index 0d42033..8e94429 100644
--- a/tempest/api/network/test_extra_dhcp_options.py
+++ b/tempest/api/network/test_extra_dhcp_options.py
@@ -16,6 +16,7 @@
 from tempest.api.network import base
 from tempest.common import utils
 from tempest.lib.common.utils import data_utils
+from tempest.lib.common.utils import test_utils
 from tempest.lib import decorators
 
 
@@ -62,7 +63,8 @@
             network_id=self.network['id'],
             extra_dhcp_opts=self.extra_dhcp_opts)
         port_id = body['port']['id']
-        self.addCleanup(self.ports_client.delete_port, port_id)
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.ports_client.delete_port, port_id)
 
         # Confirm port created has Extra DHCP Options
         body = self.ports_client.list_ports()
diff --git a/tempest/api/network/test_floating_ips.py b/tempest/api/network/test_floating_ips.py
index 504bfa8..9704c73 100644
--- a/tempest/api/network/test_floating_ips.py
+++ b/tempest/api/network/test_floating_ips.py
@@ -18,6 +18,7 @@
 from tempest.common.utils import data_utils
 from tempest.common.utils import net_utils
 from tempest import config
+from tempest.lib.common.utils import test_utils
 from tempest.lib import decorators
 
 CONF = config.CONF
@@ -77,8 +78,10 @@
             floating_network_id=self.ext_net_id,
             port_id=self.ports[0]['id'])
         created_floating_ip = body['floatingip']
-        self.addCleanup(self.floating_ips_client.delete_floatingip,
-                        created_floating_ip['id'])
+        self.addCleanup(
+            test_utils.call_and_ignore_notfound_exc,
+            self.floating_ips_client.delete_floatingip,
+            created_floating_ip['id'])
         self.assertIsNotNone(created_floating_ip['id'])
         self.assertIsNotNone(created_floating_ip['tenant_id'])
         self.assertIsNotNone(created_floating_ip['floating_ip_address'])
@@ -125,14 +128,19 @@
         self.assertIsNone(updated_floating_ip['fixed_ip_address'])
         self.assertIsNone(updated_floating_ip['router_id'])
 
+        # Explicity test deletion of floating IP
+        self.floating_ips_client.delete_floatingip(created_floating_ip['id'])
+
     @decorators.idempotent_id('e1f6bffd-442f-4668-b30e-df13f2705e77')
     def test_floating_ip_delete_port(self):
         # Create a floating IP
         body = self.floating_ips_client.create_floatingip(
             floating_network_id=self.ext_net_id)
         created_floating_ip = body['floatingip']
-        self.addCleanup(self.floating_ips_client.delete_floatingip,
-                        created_floating_ip['id'])
+        self.addCleanup(
+            test_utils.call_and_ignore_notfound_exc,
+            self.floating_ips_client.delete_floatingip,
+            created_floating_ip['id'])
         # Create a port
         port = self.ports_client.create_port(network_id=self.network['id'])
         created_port = port['port']
@@ -158,24 +166,36 @@
             floating_network_id=self.ext_net_id,
             port_id=self.ports[1]['id'])
         created_floating_ip = body['floatingip']
-        self.addCleanup(self.floating_ips_client.delete_floatingip,
-                        created_floating_ip['id'])
+        self.addCleanup(
+            test_utils.call_and_ignore_notfound_exc,
+            self.floating_ips_client.delete_floatingip,
+            created_floating_ip['id'])
         self.assertEqual(created_floating_ip['router_id'], self.router['id'])
         network_name = data_utils.rand_name(self.__class__.__name__)
         network2 = self.networks_client.create_network(
             name=network_name)['network']
-        self.addCleanup(self.networks_client.delete_network,
-                        network2['id'])
+        self.addCleanup(
+            test_utils.call_and_ignore_notfound_exc,
+            self.networks_client.delete_network,
+            network2['id'])
         subnet2 = self.create_subnet(network2)
-        self.addCleanup(self.subnets_client.delete_subnet, subnet2['id'])
+        self.addCleanup(
+            test_utils.call_and_ignore_notfound_exc,
+            self.subnets_client.delete_subnet, subnet2['id'])
         router2 = self.create_router(external_network_id=self.ext_net_id)
-        self.addCleanup(self.routers_client.delete_router, router2['id'])
+        self.addCleanup(
+            test_utils.call_and_ignore_notfound_exc,
+            self.routers_client.delete_router, router2['id'])
         self.create_router_interface(router2['id'], subnet2['id'])
-        self.addCleanup(self.routers_client.remove_router_interface,
-                        router2['id'], subnet_id=subnet2['id'])
+        self.addCleanup(
+            test_utils.call_and_ignore_notfound_exc,
+            self.routers_client.remove_router_interface,
+            router2['id'], subnet_id=subnet2['id'])
         port_other_router = self.create_port(network2)
-        self.addCleanup(self.ports_client.delete_port,
-                        port_other_router['id'])
+        self.addCleanup(
+            test_utils.call_and_ignore_notfound_exc,
+            self.ports_client.delete_port,
+            port_other_router['id'])
         # Associate floating IP to the other port on another router
         floating_ip = self.floating_ips_client.update_floatingip(
             created_floating_ip['id'],
@@ -194,8 +214,10 @@
             port_id=self.ports[1]['id'],
             fixed_ip_address=self.ports[1]['fixed_ips'][0]['ip_address'])
         created_floating_ip = body['floatingip']
-        self.addCleanup(self.floating_ips_client.delete_floatingip,
-                        created_floating_ip['id'])
+        self.addCleanup(
+            test_utils.call_and_ignore_notfound_exc,
+            self.floating_ips_client.delete_floatingip,
+            created_floating_ip['id'])
         self.assertIsNotNone(created_floating_ip['id'])
         self.assertEqual(created_floating_ip['fixed_ip_address'],
                          self.ports[1]['fixed_ips'][0]['ip_address'])
@@ -218,14 +240,16 @@
         body = self.ports_client.create_port(network_id=self.network['id'],
                                              fixed_ips=fixed_ips)
         port = body['port']
-        self.addCleanup(self.ports_client.delete_port, port['id'])
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.ports_client.delete_port, port['id'])
         # Create floating ip
         body = self.floating_ips_client.create_floatingip(
             floating_network_id=self.ext_net_id,
             port_id=port['id'],
             fixed_ip_address=list_ips[0])
         floating_ip = body['floatingip']
-        self.addCleanup(self.floating_ips_client.delete_floatingip,
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.floating_ips_client.delete_floatingip,
                         floating_ip['id'])
         self.assertIsNotNone(floating_ip['id'])
         self.assertEqual(floating_ip['fixed_ip_address'], list_ips[0])
diff --git a/tempest/api/network/test_floating_ips_negative.py b/tempest/api/network/test_floating_ips_negative.py
index e904a81..1688c9d 100644
--- a/tempest/api/network/test_floating_ips_negative.py
+++ b/tempest/api/network/test_floating_ips_negative.py
@@ -17,6 +17,7 @@
 from tempest.api.network import base
 from tempest.common import utils
 from tempest import config
+from tempest.lib.common.utils import test_utils
 from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
 
@@ -81,6 +82,7 @@
             floating_network_id=self.ext_net_id)
         floating_ip = body['floatingip']
         self.addCleanup(
+            test_utils.call_and_ignore_notfound_exc,
             self.floating_ips_client.delete_floatingip, floating_ip['id'])
         # Associate floating IP to the other port
         self.assertRaises(
diff --git a/tempest/api/network/test_networks.py b/tempest/api/network/test_networks.py
index ed8eb52..eba1f6c 100644
--- a/tempest/api/network/test_networks.py
+++ b/tempest/api/network/test_networks.py
@@ -160,7 +160,8 @@
     def test_create_update_delete_network_subnet(self):
         # Create a network
         network = self.create_network()
-        self.addCleanup(self.networks_client.delete_network, network['id'])
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.networks_client.delete_network, network['id'])
         net_id = network['id']
         self.assertEqual('ACTIVE', network['status'])
         # Verify network update
@@ -176,6 +177,8 @@
         body = self.subnets_client.update_subnet(subnet_id, name=new_name)
         updated_subnet = body['subnet']
         self.assertEqual(updated_subnet['name'], new_name)
+        # Verify network delete
+        self.networks_client.delete_network(network['id'])
 
     @decorators.attr(type='smoke')
     @decorators.idempotent_id('2bf13842-c93f-4a69-83ed-717d2ec3b44e')
@@ -313,7 +316,8 @@
     @decorators.idempotent_id('3d3852eb-3009-49ec-97ac-5ce83b73010a')
     def test_update_subnet_gw_dns_host_routes_dhcp(self):
         network = self.create_network()
-        self.addCleanup(self.networks_client.delete_network, network['id'])
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.networks_client.delete_network, network['id'])
 
         subnet = self.create_subnet(
             network, **self.subnet_dict(['gateway', 'host_routes',
diff --git a/tempest/api/network/test_ports.py b/tempest/api/network/test_ports.py
index 25976ce..93a4631 100644
--- a/tempest/api/network/test_ports.py
+++ b/tempest/api/network/test_ports.py
@@ -23,6 +23,7 @@
 from tempest.common import custom_matchers
 from tempest.common import utils
 from tempest.lib.common.utils import data_utils
+from tempest.lib.common.utils import test_utils
 from tempest.lib import decorators
 from tempest.lib import exceptions
 
@@ -52,7 +53,8 @@
     def _create_subnet(self, network, gateway='',
                        cidr=None, mask_bits=None, **kwargs):
         subnet = self.create_subnet(network, gateway, cidr, mask_bits)
-        self.addCleanup(self.subnets_client.delete_subnet, subnet['id'])
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.subnets_client.delete_subnet, subnet['id'])
         return subnet
 
     def _create_network(self, network_name=None, **kwargs):
@@ -60,7 +62,8 @@
             self.__class__.__name__)
         network = self.networks_client.create_network(
             name=network_name, **kwargs)['network']
-        self.addCleanup(self.networks_client.delete_network,
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.networks_client.delete_network,
                         network['id'])
         return network
 
@@ -116,13 +119,15 @@
                             mask_bits=address.prefixlen,
                             **allocation_pools)
         body = self.ports_client.create_port(network_id=net_id)
-        self.addCleanup(self.ports_client.delete_port, body['port']['id'])
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.ports_client.delete_port, body['port']['id'])
         port = body['port']
         ip_address = port['fixed_ips'][0]['ip_address']
         start_ip_address = allocation_pools['allocation_pools'][0]['start']
         end_ip_address = allocation_pools['allocation_pools'][0]['end']
         ip_range = netaddr.IPRange(start_ip_address, end_ip_address)
         self.assertIn(ip_address, ip_range)
+        self.ports_client.delete_port(port['id'])
 
     @decorators.attr(type='smoke')
     @decorators.idempotent_id('c9a685bd-e83f-499c-939f-9f7863ca259f')
@@ -168,9 +173,11 @@
         self._create_subnet(network)
         # Create two ports
         port_1 = self.ports_client.create_port(network_id=network['id'])
-        self.addCleanup(self.ports_client.delete_port, port_1['port']['id'])
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.ports_client.delete_port, port_1['port']['id'])
         port_2 = self.ports_client.create_port(network_id=network['id'])
-        self.addCleanup(self.ports_client.delete_port, port_2['port']['id'])
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.ports_client.delete_port, port_2['port']['id'])
         # List ports filtered by fixed_ips
         port_1_fixed_ip = port_1['port']['fixed_ips'][0]['ip_address']
         fixed_ips = 'ip_address=' + port_1_fixed_ip
@@ -219,11 +226,13 @@
         fixed_ips = [{'subnet_id': subnet['id'], 'ip_address': ip_address_1}]
         port_1 = self.ports_client.create_port(network_id=network['id'],
                                                fixed_ips=fixed_ips)
-        self.addCleanup(self.ports_client.delete_port, port_1['port']['id'])
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.ports_client.delete_port, port_1['port']['id'])
         fixed_ips = [{'subnet_id': subnet['id'], 'ip_address': ip_address_2}]
         port_2 = self.ports_client.create_port(network_id=network['id'],
                                                fixed_ips=fixed_ips)
-        self.addCleanup(self.ports_client.delete_port, port_2['port']['id'])
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.ports_client.delete_port, port_2['port']['id'])
 
         # Scenario 1: List port1 (port2 is filtered out)
         if ip_address_1[:-1] != ip_address_2[:-1]:
@@ -272,12 +281,14 @@
         network = self._create_network()
         self._create_subnet(network)
         router = self.create_router()
-        self.addCleanup(self.routers_client.delete_router, router['id'])
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.routers_client.delete_router, router['id'])
         port = self.ports_client.create_port(network_id=network['id'])
         # Add router interface to port created above
         self.routers_client.add_router_interface(router['id'],
                                                  port_id=port['port']['id'])
-        self.addCleanup(self.routers_client.remove_router_interface,
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.routers_client.remove_router_interface,
                         router['id'], port_id=port['port']['id'])
         # List ports filtered by router_id
         port_list = self.ports_client.list_ports(device_id=router['id'])
@@ -311,7 +322,8 @@
         # Create a port with multiple IP addresses
         port = self.create_port(network,
                                 fixed_ips=fixed_ips)
-        self.addCleanup(self.ports_client.delete_port, port['id'])
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.ports_client.delete_port, port['id'])
         self.assertEqual(2, len(port['fixed_ips']))
         check_fixed_ips = [subnet_1['id'], subnet_2['id']]
         for item in port['fixed_ips']:
@@ -334,7 +346,8 @@
         for name in security_groups_names:
             group_create_body = sec_grps_client.create_security_group(
                 name=name)
-            self.addCleanup(self.security_groups_client.delete_security_group,
+            self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                            self.security_groups_client.delete_security_group,
                             group_create_body['security_group']['id'])
             security_groups_list.append(group_create_body['security_group']
                                         ['id'])
@@ -342,7 +355,8 @@
         sec_grp_name = data_utils.rand_name('secgroup')
         security_group = sec_grps_client.create_security_group(
             name=sec_grp_name)
-        self.addCleanup(self.security_groups_client.delete_security_group,
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.security_groups_client.delete_security_group,
                         security_group['security_group']['id'])
         post_body = {
             "name": data_utils.rand_name('port-'),
@@ -351,7 +365,8 @@
             "admin_state_up": True,
             "fixed_ips": fixed_ip_1}
         body = self.ports_client.create_port(**post_body)
-        self.addCleanup(self.ports_client.delete_port, body['port']['id'])
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.ports_client.delete_port, body['port']['id'])
         port = body['port']
 
         # Update the port with security groups
@@ -402,7 +417,8 @@
         # Create a new port with user defined mac
         body = self.ports_client.create_port(network_id=self.network['id'],
                                              mac_address=free_mac_address)
-        self.addCleanup(self.ports_client.delete_port, body['port']['id'])
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.ports_client.delete_port, body['port']['id'])
         port = body['port']
         body = self.ports_client.show_port(port['id'])
         show_port = body['port']
@@ -418,7 +434,8 @@
         network = self._create_network()
         self._create_subnet(network)
         port = self.create_port(network, security_groups=[])
-        self.addCleanup(self.ports_client.delete_port, port['id'])
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.ports_client.delete_port, port['id'])
         self.assertIsNotNone(port['security_groups'])
         self.assertEmpty(port['security_groups'])
 
diff --git a/tempest/api/network/test_routers.py b/tempest/api/network/test_routers.py
index be3cf65..f223fa4 100644
--- a/tempest/api/network/test_routers.py
+++ b/tempest/api/network/test_routers.py
@@ -20,6 +20,7 @@
 from tempest.common import utils
 from tempest import config
 from tempest.lib.common.utils import data_utils
+from tempest.lib.common.utils import test_utils
 from tempest.lib import decorators
 
 CONF = config.CONF
@@ -89,10 +90,11 @@
         network_name = data_utils.rand_name(self.__class__.__name__)
         network = self.networks_client.create_network(
             name=network_name)['network']
-        self.addCleanup(self.networks_client.delete_network,
-                        network['id'])
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.networks_client.delete_network, network['id'])
         subnet = self.create_subnet(network)
-        self.addCleanup(self.subnets_client.delete_subnet, subnet['id'])
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.subnets_client.delete_subnet, subnet['id'])
         router = self.create_router()
         self.addCleanup(self.delete_router, router)
         # Add router interface with subnet id
@@ -114,8 +116,8 @@
         network_name = data_utils.rand_name(self.__class__.__name__)
         network = self.networks_client.create_network(
             name=network_name)['network']
-        self.addCleanup(self.networks_client.delete_network,
-                        network['id'])
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.networks_client.delete_network, network['id'])
         subnet = self.create_subnet(network)
         self.addCleanup(self.subnets_client.delete_subnet, subnet['id'])
         router = self.create_router()
@@ -126,7 +128,8 @@
         interface = self.routers_client.add_router_interface(
             router['id'],
             port_id=port_body['port']['id'])
-        self.addCleanup(self.routers_client.remove_router_interface,
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.routers_client.remove_router_interface,
                         router['id'], port_id=port_body['port']['id'])
         self.assertIn('subnet_id', interface.keys())
         self.assertIn('port_id', interface.keys())
@@ -135,6 +138,8 @@
             interface['port_id'])
         self.assertEqual(show_port_body['port']['device_id'],
                          router['id'])
+        self.routers_client.remove_router_interface(
+            router['id'], port_id=port_body['port']['id'])
 
     @decorators.idempotent_id('cbe42f84-04c2-11e7-8adb-fa163e4fa634')
     @utils.requires_ext(extension='ext-gw-mode', service='network')
@@ -160,7 +165,8 @@
         # Create a router and set gateway to fixed_ip
         router = self.admin_routers_client.create_router(
             external_gateway_info=external_gateway_info)['router']
-        self.addCleanup(self.admin_routers_client.delete_router,
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.admin_routers_client.delete_router,
                         router_id=router['id'])
         # Examine router's gateway is equal to fixed_ip
         self.assertEqual(router['external_gateway_info'][
@@ -188,10 +194,12 @@
             network_name = data_utils.rand_name(self.__class__.__name__)
             network = self.networks_client.create_network(
                 name=network_name)['network']
-            self.addCleanup(self.networks_client.delete_network,
+            self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                            self.networks_client.delete_network,
                             network['id'])
             subnet = self.create_subnet(network, cidr=next_cidr)
-            self.addCleanup(self.subnets_client.delete_subnet, subnet['id'])
+            self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                            self.subnets_client.delete_subnet, subnet['id'])
             next_cidr = next_cidr.next()
 
             # Add router interface with subnet id
@@ -254,18 +262,20 @@
         network_name = data_utils.rand_name(self.__class__.__name__)
         network01 = self.networks_client.create_network(
             name=network_name)['network']
-        self.addCleanup(self.networks_client.delete_network,
-                        network01['id'])
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.networks_client.delete_network, network01['id'])
         network_name = data_utils.rand_name(self.__class__.__name__)
         network02 = self.networks_client.create_network(
             name=network_name)['network']
-        self.addCleanup(self.networks_client.delete_network,
-                        network02['id'])
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.networks_client.delete_network, network02['id'])
         subnet01 = self.create_subnet(network01)
-        self.addCleanup(self.subnets_client.delete_subnet, subnet01['id'])
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.subnets_client.delete_subnet, subnet01['id'])
         sub02_cidr = self.cidr.next()
         subnet02 = self.create_subnet(network02, cidr=sub02_cidr)
-        self.addCleanup(self.subnets_client.delete_subnet, subnet02['id'])
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.subnets_client.delete_subnet, subnet02['id'])
         router = self.create_router()
         self.addCleanup(self.delete_router, router)
         interface01 = self._add_router_interface_with_subnet_id(router['id'],
@@ -282,10 +292,11 @@
         network_name = data_utils.rand_name(self.__class__.__name__)
         network = self.networks_client.create_network(
             name=network_name)['network']
-        self.addCleanup(self.networks_client.delete_network,
-                        network['id'])
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.networks_client.delete_network, network['id'])
         subnet = self.create_subnet(network)
-        self.addCleanup(self.subnets_client.delete_subnet, subnet['id'])
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.subnets_client.delete_subnet, subnet['id'])
         router = self.create_router()
         self.addCleanup(self.delete_router, router)
         fixed_ip = [{'subnet_id': subnet['id']}]
diff --git a/tempest/api/network/test_security_groups.py b/tempest/api/network/test_security_groups.py
index ffc1fca..ef19122 100644
--- a/tempest/api/network/test_security_groups.py
+++ b/tempest/api/network/test_security_groups.py
@@ -16,6 +16,7 @@
 from tempest.api.network import base_security_groups as base
 from tempest.common import utils
 from tempest.lib.common.utils import data_utils
+from tempest.lib.common.utils import test_utils
 from tempest.lib import decorators
 
 
@@ -49,8 +50,8 @@
         )
 
         sec_group_rule = rule_create_body['security_group_rule']
-        self.addCleanup(self._delete_security_group_rule,
-                        sec_group_rule['id'])
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self._delete_security_group_rule, sec_group_rule['id'])
 
         expected = {'direction': direction, 'protocol': protocol,
                     'ethertype': ethertype, 'port_range_min': port_range_min,
@@ -104,6 +105,8 @@
         self.assertEqual(show_body['security_group']['name'], new_name)
         self.assertEqual(show_body['security_group']['description'],
                          new_description)
+        # Delete security group
+        self._delete_security_group(group_create_body['security_group']['id'])
 
     @decorators.attr(type='smoke')
     @decorators.idempotent_id('cfb99e0e-7410-4a3d-8a0c-959a63ee77e9')
@@ -138,6 +141,8 @@
                          for rule in rule_list_body['security_group_rules']]
             self.assertIn(rule_create_body['security_group_rule']['id'],
                           rule_list)
+            self._delete_security_group_rule(
+                rule_create_body['security_group_rule']['id'])
 
     @decorators.idempotent_id('87dfbcf9-1849-43ea-b1e4-efa3eeae9f71')
     def test_create_security_group_rule_with_additional_args(self):
@@ -170,7 +175,14 @@
 
         sg_id = group_create_body['security_group']['id']
         direction = 'ingress'
-        protocol = 'icmp'
+        # The Neutron API accepts 'icmp', 'icmpv6' and 'ipv6-icmp' for
+        # IPv6 ICMP protocol names, but the latter is preferred and the
+        # others considered "legacy".  Use 'ipv6-icmp' as the API could
+        # change to return only that value, see
+        # https://review.opendev.org/#/c/453346/
+        # The neutron-tempest-plugin API tests pass all three and verify
+        # the output, so there is no need to duplicate that here.
+        protocol = 'ipv6-icmp' if self._ip_version == 6 else 'icmp'
         icmp_type_codes = [(3, 2), (3, 0), (8, 0), (0, 0), (11, None)]
         for icmp_type, icmp_code in icmp_type_codes:
             self._create_verify_security_group_rule(sg_id, direction,
diff --git a/tempest/api/volume/test_volumes_extend.py b/tempest/api/volume/test_volumes_extend.py
index ac9a9c7..c3f44e2 100644
--- a/tempest/api/volume/test_volumes_extend.py
+++ b/tempest/api/volume/test_volumes_extend.py
@@ -32,7 +32,7 @@
     @decorators.idempotent_id('9a36df71-a257-43a5-9555-dc7c88e66e0e')
     def test_volume_extend(self):
         # Extend Volume Test.
-        volume = self.create_volume(image_ref=self.image_ref)
+        volume = self.create_volume(imageRef=self.image_ref)
         extend_size = volume['size'] * 2
         self.volumes_client.extend_volume(volume['id'],
                                           new_size=extend_size)
diff --git a/tempest/api/volume/test_volumes_snapshots.py b/tempest/api/volume/test_volumes_snapshots.py
index 1855386..72e7290 100644
--- a/tempest/api/volume/test_volumes_snapshots.py
+++ b/tempest/api/volume/test_volumes_snapshots.py
@@ -44,7 +44,7 @@
         server = self.create_server()
         # NOTE(zhufl) Here we create volume from self.image_ref for adding
         # coverage for "creating snapshot from non-blank volume".
-        volume = self.create_volume(image_ref=self.image_ref)
+        volume = self.create_volume(imageRef=self.image_ref)
         self.attach_volume(server['id'], volume['id'])
 
         # Snapshot a volume which attached to an instance with force=False
diff --git a/tempest/clients.py b/tempest/clients.py
index 0506646..f7a83be 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -69,6 +69,8 @@
         self.network_versions_client = self.network.NetworkVersionsClient()
         self.service_providers_client = self.network.ServiceProvidersClient()
         self.tags_client = self.network.TagsClient()
+        self.qos_client = self.network.QosClient()
+        self.qos_min_bw_client = self.network.QosMinimumBandwidthRulesClient()
 
     def _set_image_clients(self):
         if CONF.service_available.glance:
diff --git a/tempest/common/utils/linux/remote_client.py b/tempest/common/utils/linux/remote_client.py
index 49d9742..d76a323 100644
--- a/tempest/common/utils/linux/remote_client.py
+++ b/tempest/common/utils/linux/remote_client.py
@@ -156,3 +156,53 @@
             cmd_why = 'sudo ls -lR /dev'
             LOG.info("Contents of /dev: %s", self.exec_command(cmd_why))
             raise
+
+    def nc_listen_host(self, port=80, protocol='tcp'):
+        """Creates persistent nc server listening on the given TCP / UDP port
+
+        :port: the port to start listening on.
+        :protocol: the protocol used by the server. TCP by default.
+        """
+        udp = '-u' if protocol.lower() == 'udp' else ''
+        cmd = "sudo nc %(udp)s -p %(port)s -lk -e echo foolish &" % {
+            'udp': udp, 'port': port}
+        return self.exec_command(cmd)
+
+    def nc_host(self, host, port=80, protocol='tcp', expected_response=None):
+        """Check connectivity to TCP / UDP port at host via nc
+
+        :host: an IP against which the connectivity will be tested.
+        :port: the port to check connectivity against.
+        :protocol: the protocol used by nc to send packets. TCP by default.
+        :expected_response: string representing the expected response
+            from server.
+        :raises SSHExecCommandFailed: if an expected response is given and it
+            does not match the actual server response.
+        """
+        udp = '-u' if protocol.lower() == 'udp' else ''
+        cmd = 'echo "bar" | nc -w 1 %(udp)s %(host)s %(port)s' % {
+            'udp': udp, 'host': host, 'port': port}
+        response = self.exec_command(cmd)
+
+        # sending an UDP packet will always succeed. we need to check
+        # the response.
+        if (expected_response is not None and
+                expected_response != response.strip()):
+            raise tempest.lib.exceptions.SSHExecCommandFailed(
+                command=cmd, exit_status=0, stdout=response, stderr='')
+        return response
+
+    def icmp_check(self, host, nic=None):
+        """Wrapper for icmp connectivity checks"""
+        return self.ping_host(host, nic=nic)
+
+    def udp_check(self, host, **kwargs):
+        """Wrapper for udp connectivity checks."""
+        kwargs.pop('nic', None)
+        return self.nc_host(host, protocol='udp', expected_response='foolish',
+                            **kwargs)
+
+    def tcp_check(self, host, **kwargs):
+        """Wrapper for tcp connectivity checks."""
+        kwargs.pop('nic', None)
+        return self.nc_host(host, **kwargs)
diff --git a/tempest/common/waiters.py b/tempest/common/waiters.py
old mode 100644
new mode 100755
index 77ec0f8..e1b8cf5
--- a/tempest/common/waiters.py
+++ b/tempest/common/waiters.py
@@ -202,6 +202,8 @@
                 resource_name=resource_name, resource_id=resource_id)
         if resource_name == 'volume' and resource_status == 'error_restoring':
             raise exceptions.VolumeRestoreErrorException(volume_id=resource_id)
+        if resource_status == 'error_extending' and resource_status != status:
+            raise exceptions.VolumeExtendErrorException(volume_id=resource_id)
 
         if int(time.time()) - start >= client.build_timeout:
             message = ('%s %s failed to reach %s status (current %s) '
diff --git a/tempest/config.py b/tempest/config.py
index f692a4b..9e4718b 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -69,10 +69,7 @@
     cfg.StrOpt('default_credentials_domain_name',
                default='Default',
                help="Default domain used when getting v3 credentials. "
-                    "This is the name keystone uses for v2 compatibility.",
-               deprecated_opts=[cfg.DeprecatedOpt(
-                                'tenant_isolation_domain_name',
-                                group='auth')]),
+                    "This is the name keystone uses for v2 compatibility."),
     cfg.BoolOpt('create_isolated_networks',
                 default=True,
                 help="If use_dynamic_credentials is set to True and Neutron "
@@ -84,27 +81,20 @@
     cfg.StrOpt('admin_username',
                help="Username for an administrative user. This is needed for "
                     "authenticating requests made by project isolation to "
-                    "create users and projects",
-               deprecated_group='identity'),
+                    "create users and projects"),
     cfg.StrOpt('admin_project_name',
                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',
-                                                  group='auth'),
-                                cfg.DeprecatedOpt('admin_tenant_name',
-                                                  group='identity')]),
+                    "isolation to create users and projects"),
     cfg.StrOpt('admin_password',
                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,
-               deprecated_group='identity'),
+               secret=True),
     cfg.StrOpt('admin_domain_name',
                default='Default',
                help="Admin domain name for authentication (Keystone V3). "
-                    "The same domain applies to user and project",
-               deprecated_group='identity'),
+                    "The same domain applies to user and project"),
 ]
 
 identity_group = cfg.OptGroup(name='identity',
@@ -146,9 +136,7 @@
                choices=['public', 'admin', 'internal',
                         'publicURL', 'adminURL', 'internalURL'],
                help="The public endpoint type to use for OpenStack Identity "
-                    "(Keystone) API v2",
-               deprecated_opts=[cfg.DeprecatedOpt('endpoint_type',
-                                                  group='identity')]),
+                    "(Keystone) API v2"),
     cfg.StrOpt('v3_endpoint_type',
                default='adminURL',
                choices=['public', 'admin', 'internal',
@@ -1052,7 +1040,12 @@
                choices=["udhcpc", "dhclient", ""],
                help='DHCP client used by images to renew DCHP lease. '
                     'If left empty, update operation will be skipped. '
-                    'Supported clients: "udhcpc", "dhclient"')
+                    'Supported clients: "udhcpc", "dhclient"'),
+    cfg.StrOpt('protocol',
+               default='icmp',
+               choices=('icmp', 'tcp', 'udp'),
+               help='The protocol used in security groups tests to check '
+                    'connectivity.'),
 ]
 
 
diff --git a/tempest/exceptions.py b/tempest/exceptions.py
old mode 100644
new mode 100755
index a430d5d..c05e7a6
--- a/tempest/exceptions.py
+++ b/tempest/exceptions.py
@@ -42,6 +42,11 @@
     message = "Volume %(volume_id)s failed to restore and is in ERROR status"
 
 
+class VolumeExtendErrorException(exceptions.TempestException):
+    message = ("Volume %(volume_id)s failed to extend and "
+               "is in error_extending status")
+
+
 class StackBuildErrorException(exceptions.TempestException):
     message = ("Stack %(stack_identifier)s is in %(stack_status)s status "
                "due to '%(stack_status_reason)s'")
diff --git a/tempest/lib/api_schema/response/compute/v2_16/servers.py b/tempest/lib/api_schema/response/compute/v2_16/servers.py
index 72b84f5..fc81ff7 100644
--- a/tempest/lib/api_schema/response/compute/v2_16/servers.py
+++ b/tempest/lib/api_schema/response/compute/v2_16/servers.py
@@ -168,3 +168,6 @@
     servers.rebuild_server_with_admin_pass)
 show_server_diagnostics = copy.deepcopy(servers.show_server_diagnostics)
 get_remote_consoles = copy.deepcopy(servers.get_remote_consoles)
+attach_volume = copy.deepcopy(servers.attach_volume)
+show_volume_attachment = copy.deepcopy(servers.show_volume_attachment)
+list_volume_attachments = copy.deepcopy(servers.list_volume_attachments)
diff --git a/tempest/lib/api_schema/response/compute/v2_19/servers.py b/tempest/lib/api_schema/response/compute/v2_19/servers.py
index e3e8ad1..b6c3c14 100644
--- a/tempest/lib/api_schema/response/compute/v2_19/servers.py
+++ b/tempest/lib/api_schema/response/compute/v2_19/servers.py
@@ -58,3 +58,6 @@
 list_servers = copy.deepcopy(serversv216.list_servers)
 show_server_diagnostics = copy.deepcopy(serversv216.show_server_diagnostics)
 get_remote_consoles = copy.deepcopy(serversv216.get_remote_consoles)
+attach_volume = copy.deepcopy(serversv216.attach_volume)
+show_volume_attachment = copy.deepcopy(serversv216.show_volume_attachment)
+list_volume_attachments = copy.deepcopy(serversv216.list_volume_attachments)
diff --git a/tempest/lib/api_schema/response/compute/v2_26/servers.py b/tempest/lib/api_schema/response/compute/v2_26/servers.py
index 8e62dc3..5a0f987 100644
--- a/tempest/lib/api_schema/response/compute/v2_26/servers.py
+++ b/tempest/lib/api_schema/response/compute/v2_26/servers.py
@@ -101,3 +101,6 @@
 list_servers = copy.deepcopy(servers219.list_servers)
 show_server_diagnostics = copy.deepcopy(servers219.show_server_diagnostics)
 get_remote_consoles = copy.deepcopy(servers219.get_remote_consoles)
+attach_volume = copy.deepcopy(servers219.attach_volume)
+show_volume_attachment = copy.deepcopy(servers219.show_volume_attachment)
+list_volume_attachments = copy.deepcopy(servers219.list_volume_attachments)
diff --git a/tempest/lib/api_schema/response/compute/v2_3/servers.py b/tempest/lib/api_schema/response/compute/v2_3/servers.py
index 18fb352..1674c1b 100644
--- a/tempest/lib/api_schema/response/compute/v2_3/servers.py
+++ b/tempest/lib/api_schema/response/compute/v2_3/servers.py
@@ -173,3 +173,6 @@
 rebuild_server_with_admin_pass = copy.deepcopy(
     servers.rebuild_server_with_admin_pass)
 show_server_diagnostics = copy.deepcopy(servers.show_server_diagnostics)
+attach_volume = copy.deepcopy(servers.attach_volume)
+show_volume_attachment = copy.deepcopy(servers.show_volume_attachment)
+list_volume_attachments = copy.deepcopy(servers.list_volume_attachments)
diff --git a/tempest/lib/api_schema/response/compute/v2_47/servers.py b/tempest/lib/api_schema/response/compute/v2_47/servers.py
index 0fbacd3..d580f2c 100644
--- a/tempest/lib/api_schema/response/compute/v2_47/servers.py
+++ b/tempest/lib/api_schema/response/compute/v2_47/servers.py
@@ -66,3 +66,6 @@
 update_tag = copy.deepcopy(servers226.update_tag)
 delete_tag = copy.deepcopy(servers226.delete_tag)
 list_servers = copy.deepcopy(servers226.list_servers)
+attach_volume = copy.deepcopy(servers226.attach_volume)
+show_volume_attachment = copy.deepcopy(servers226.show_volume_attachment)
+list_volume_attachments = copy.deepcopy(servers226.list_volume_attachments)
diff --git a/tempest/lib/api_schema/response/compute/v2_48/servers.py b/tempest/lib/api_schema/response/compute/v2_48/servers.py
index 84b5a2a..e2e45bc 100644
--- a/tempest/lib/api_schema/response/compute/v2_48/servers.py
+++ b/tempest/lib/api_schema/response/compute/v2_48/servers.py
@@ -129,3 +129,6 @@
 rebuild_server = copy.deepcopy(servers247.rebuild_server)
 rebuild_server_with_admin_pass = copy.deepcopy(
     servers247.rebuild_server_with_admin_pass)
+attach_volume = copy.deepcopy(servers247.attach_volume)
+show_volume_attachment = copy.deepcopy(servers247.show_volume_attachment)
+list_volume_attachments = copy.deepcopy(servers247.list_volume_attachments)
diff --git a/tempest/lib/api_schema/response/compute/v2_54/servers.py b/tempest/lib/api_schema/response/compute/v2_54/servers.py
index 099e1b8..2c2bff0 100644
--- a/tempest/lib/api_schema/response/compute/v2_54/servers.py
+++ b/tempest/lib/api_schema/response/compute/v2_54/servers.py
@@ -55,3 +55,6 @@
 check_tag_existence = copy.deepcopy(servers248.check_tag_existence)
 update_tag = copy.deepcopy(servers248.update_tag)
 delete_tag = copy.deepcopy(servers248.delete_tag)
+attach_volume = copy.deepcopy(servers248.attach_volume)
+show_volume_attachment = copy.deepcopy(servers248.show_volume_attachment)
+list_volume_attachments = copy.deepcopy(servers248.list_volume_attachments)
diff --git a/tempest/lib/api_schema/response/compute/v2_57/servers.py b/tempest/lib/api_schema/response/compute/v2_57/servers.py
index 0099a2b..aa57d25 100644
--- a/tempest/lib/api_schema/response/compute/v2_57/servers.py
+++ b/tempest/lib/api_schema/response/compute/v2_57/servers.py
@@ -59,3 +59,6 @@
 check_tag_existence = copy.deepcopy(servers254.check_tag_existence)
 update_tag = copy.deepcopy(servers254.update_tag)
 delete_tag = copy.deepcopy(servers254.delete_tag)
+attach_volume = copy.deepcopy(servers254.attach_volume)
+show_volume_attachment = copy.deepcopy(servers254.show_volume_attachment)
+list_volume_attachments = copy.deepcopy(servers254.list_volume_attachments)
diff --git a/tempest/lib/api_schema/response/compute/v2_6/servers.py b/tempest/lib/api_schema/response/compute/v2_6/servers.py
index d5774de..922bf79 100644
--- a/tempest/lib/api_schema/response/compute/v2_6/servers.py
+++ b/tempest/lib/api_schema/response/compute/v2_6/servers.py
@@ -28,6 +28,9 @@
 rebuild_server_with_admin_pass = copy.deepcopy(
     servers.rebuild_server_with_admin_pass)
 show_server_diagnostics = copy.deepcopy(servers.show_server_diagnostics)
+attach_volume = copy.deepcopy(servers.attach_volume)
+show_volume_attachment = copy.deepcopy(servers.show_volume_attachment)
+list_volume_attachments = copy.deepcopy(servers.list_volume_attachments)
 
 # NOTE: The consolidated remote console API got introduced with v2.6
 # with bp/consolidate-console-api. See Nova commit 578bafeda
diff --git a/tempest/lib/api_schema/response/compute/v2_63/servers.py b/tempest/lib/api_schema/response/compute/v2_63/servers.py
index 3c3d41c..01910aa 100644
--- a/tempest/lib/api_schema/response/compute/v2_63/servers.py
+++ b/tempest/lib/api_schema/response/compute/v2_63/servers.py
@@ -73,3 +73,6 @@
 check_tag_existence = copy.deepcopy(servers257.check_tag_existence)
 update_tag = copy.deepcopy(servers257.update_tag)
 delete_tag = copy.deepcopy(servers257.delete_tag)
+attach_volume = copy.deepcopy(servers257.attach_volume)
+show_volume_attachment = copy.deepcopy(servers257.show_volume_attachment)
+list_volume_attachments = copy.deepcopy(servers257.list_volume_attachments)
diff --git a/tempest/lib/api_schema/response/compute/v2_70/__init__.py b/tempest/lib/api_schema/response/compute/v2_70/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_70/__init__.py
diff --git a/tempest/lib/api_schema/response/compute/v2_70/servers.py b/tempest/lib/api_schema/response/compute/v2_70/servers.py
new file mode 100644
index 0000000..5ca4cc8
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_70/servers.py
@@ -0,0 +1,80 @@
+#    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.
+
+import copy
+
+from tempest.lib.api_schema.response.compute.v2_1 import servers as servers2_1
+from tempest.lib.api_schema.response.compute.v2_63 import servers as servers263
+
+
+###########################################################################
+#
+# 2.70:
+#
+# Exposes virtual device tags for volume attachments and virtual interfaces
+# (ports). A tag parameter is added to the response body for the following
+# APIs:
+#
+# Volumes
+#
+# - GET /servers/{server_id}/os-volume_attachments (list)
+# - GET /servers/{server_id}/os-volume_attachments/{volume_id} (show)
+# - POST /servers/{server_id}/os-volume_attachments (attach)
+#
+# Ports
+#
+# - GET /servers/{server_id}/os-interface (list)
+# - GET /servers/{server_id}/os-interface/{port_id} (show)
+# - POST /servers/{server_id}/os-interface (attach)
+#
+###########################################################################
+
+attach_volume = copy.deepcopy(servers2_1.attach_volume)
+attach_volume['response_body']['properties']['volumeAttachment'][
+    'properties'].update({'tag': {'type': ['string', 'null']}})
+attach_volume['response_body']['properties']['volumeAttachment'][
+    'required'].append('tag')
+
+show_volume_attachment = copy.deepcopy(servers2_1.show_volume_attachment)
+show_volume_attachment['response_body']['properties']['volumeAttachment'][
+    'properties'].update({'tag': {'type': ['string', 'null']}})
+show_volume_attachment['response_body']['properties'][
+    'volumeAttachment']['required'].append('tag')
+
+list_volume_attachments = copy.deepcopy(servers2_1.list_volume_attachments)
+list_volume_attachments['response_body']['properties']['volumeAttachments'][
+    'items']['properties'].update({'tag': {'type': ['string', 'null']}})
+list_volume_attachments['response_body']['properties'][
+    'volumeAttachments']['items']['required'].append('tag')
+
+# TODO(mriedem): Handle the os-interface changes when there is a test that
+# needs them from this microversion onward.
+
+# NOTE(lajoskatona): Below are the unchanged schema in this microversion. We
+# need to keep this schema in this file to have the generic way to select the
+# right schema based on self.schema_versions_info mapping in service client.
+# ****** Schemas unchanged since microversion 2.63 ***
+list_servers_detail = copy.deepcopy(servers263.list_servers_detail)
+rebuild_server = copy.deepcopy(servers263.rebuild_server)
+rebuild_server_with_admin_pass = copy.deepcopy(
+    servers263.rebuild_server_with_admin_pass)
+update_server = copy.deepcopy(servers263.update_server)
+get_server = copy.deepcopy(servers263.get_server)
+list_servers = copy.deepcopy(servers263.list_servers)
+show_server_diagnostics = copy.deepcopy(servers263.show_server_diagnostics)
+get_remote_consoles = copy.deepcopy(servers263.get_remote_consoles)
+list_tags = copy.deepcopy(servers263.list_tags)
+update_all_tags = copy.deepcopy(servers263.update_all_tags)
+delete_all_tags = copy.deepcopy(servers263.delete_all_tags)
+check_tag_existence = copy.deepcopy(servers263.check_tag_existence)
+update_tag = copy.deepcopy(servers263.update_tag)
+delete_tag = copy.deepcopy(servers263.delete_tag)
diff --git a/tempest/lib/api_schema/response/compute/v2_71/__init__.py b/tempest/lib/api_schema/response/compute/v2_71/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_71/__init__.py
diff --git a/tempest/lib/api_schema/response/compute/v2_71/servers.py b/tempest/lib/api_schema/response/compute/v2_71/servers.py
new file mode 100644
index 0000000..0c526fb
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_71/servers.py
@@ -0,0 +1,81 @@
+#    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.
+
+import copy
+
+from tempest.lib.api_schema.response.compute.v2_70 import servers as servers270
+
+
+###########################################################################
+#
+# 2.71:
+#
+# The server_groups parameter will be in the response body of the following
+# APIs to list the server groups to which the server belongs:
+#
+# - GET /servers/{server_id} (show)
+# - PUT /servers/{server_id} (update)
+# - POST /servers/{server_id}/action (rebuild)
+#
+###########################################################################
+
+# The "server_groups" parameter will always be present and contain at most one
+# UUID entry.
+server_groups = {
+    'type': 'array',
+    'minItems': 0,
+    'maxItems': 1,
+    'items': {
+        'type': 'string',
+        'format': 'uuid'
+    }
+}
+
+rebuild_server = copy.deepcopy(servers270.rebuild_server)
+rebuild_server['response_body']['properties']['server'][
+    'properties'].update({'server_groups': server_groups})
+rebuild_server['response_body']['properties']['server'][
+    'required'].append('server_groups')
+
+rebuild_server_with_admin_pass = copy.deepcopy(
+    servers270.rebuild_server_with_admin_pass)
+rebuild_server_with_admin_pass['response_body']['properties']['server'][
+    'properties'].update({'server_groups': server_groups})
+rebuild_server_with_admin_pass['response_body']['properties']['server'][
+    'required'].append('server_groups')
+
+update_server = copy.deepcopy(servers270.update_server)
+update_server['response_body']['properties']['server'][
+    'properties'].update({'server_groups': server_groups})
+update_server['response_body']['properties']['server'][
+    'required'].append('server_groups')
+
+get_server = copy.deepcopy(servers270.get_server)
+get_server['response_body']['properties']['server'][
+    'properties'].update({'server_groups': server_groups})
+get_server['response_body']['properties']['server'][
+    'required'].append('server_groups')
+
+# NOTE(lajoskatona): Below are the unchanged schema in this microversion. We
+# need to keep this schema in this file to have the generic way to select the
+# right schema based on self.schema_versions_info mapping in service client.
+# ****** Schemas unchanged since microversion 2.70 ***
+list_servers_details = copy.deepcopy(servers270.list_servers_detail)
+list_servers = copy.deepcopy(servers270.list_servers)
+show_server_diagnostics = copy.deepcopy(servers270.show_server_diagnostics)
+get_remote_consoles = copy.deepcopy(servers270.get_remote_consoles)
+list_tags = copy.deepcopy(servers270.list_tags)
+update_all_tags = copy.deepcopy(servers270.update_all_tags)
+delete_all_tags = copy.deepcopy(servers270.delete_all_tags)
+check_tag_existence = copy.deepcopy(servers270.check_tag_existence)
+update_tag = copy.deepcopy(servers270.update_tag)
+delete_tag = copy.deepcopy(servers270.delete_tag)
diff --git a/tempest/lib/api_schema/response/compute/v2_8/servers.py b/tempest/lib/api_schema/response/compute/v2_8/servers.py
index df7847f..3dbab3f 100644
--- a/tempest/lib/api_schema/response/compute/v2_8/servers.py
+++ b/tempest/lib/api_schema/response/compute/v2_8/servers.py
@@ -35,3 +35,6 @@
 rebuild_server_with_admin_pass = copy.deepcopy(
     servers.rebuild_server_with_admin_pass)
 show_server_diagnostics = copy.deepcopy(servers.show_server_diagnostics)
+attach_volume = copy.deepcopy(servers.attach_volume)
+show_volume_attachment = copy.deepcopy(servers.show_volume_attachment)
+list_volume_attachments = copy.deepcopy(servers.list_volume_attachments)
diff --git a/tempest/lib/api_schema/response/compute/v2_9/servers.py b/tempest/lib/api_schema/response/compute/v2_9/servers.py
index 55f8e75..ee0313d 100644
--- a/tempest/lib/api_schema/response/compute/v2_9/servers.py
+++ b/tempest/lib/api_schema/response/compute/v2_9/servers.py
@@ -54,3 +54,6 @@
 list_servers = copy.deepcopy(servers.list_servers)
 show_server_diagnostics = copy.deepcopy(servers.show_server_diagnostics)
 get_remote_consoles = copy.deepcopy(servers.get_remote_consoles)
+attach_volume = copy.deepcopy(servers.attach_volume)
+show_volume_attachment = copy.deepcopy(servers.show_volume_attachment)
+list_volume_attachments = copy.deepcopy(servers.list_volume_attachments)
diff --git a/tempest/lib/common/api_microversion_fixture.py b/tempest/lib/common/api_microversion_fixture.py
new file mode 100644
index 0000000..3837138
--- /dev/null
+++ b/tempest/lib/common/api_microversion_fixture.py
@@ -0,0 +1,82 @@
+# Copyright 2019 NEC 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.
+
+import fixtures
+
+from tempest.lib.services.compute import base_compute_client
+from tempest.lib.services.placement import base_placement_client
+from tempest.lib.services.volume import base_client as base_volume_client
+
+
+class APIMicroversionFixture(fixtures.Fixture):
+    """API Microversion Fixture to set service microversion.
+
+    This class provides the fixture to set and reset the microversion
+    on service client. Service client has global variable to set the
+    microversion for that service API request.
+    For example: base_compute_client.COMPUTE_MICROVERSION
+    Global variable is always risky to set directly which can affect the
+    other test's API request also. This class provides a way to reset the
+    service microversion once test finish the API request.
+    This class can be used with useFixture: Example::
+
+        def setUp(self):
+            super(BaseV2ComputeTest, self).setUp()
+            self.useFixture(api_microversion_fixture.APIMicroversionFixture(
+                compute_microversion=self.compute_request_microversion))
+
+    Or you can set microversion on multiple services together::
+
+        def setUp(self):
+            super(ScenarioTest, self).setUp()
+            self.useFixture(api_microversion_fixture.APIMicroversionFixture(
+                compute_microversion=self.compute_request_microversion,
+                volume_microversion=self.volume_request_microversion))
+
+    Current supported services:
+    - Compute
+    - Volume
+    - Placement
+
+    :param str compute_microversion: microvesion to be set on compute
+                                     service clients
+    :param str volume_microversion: microvesion to be set on volume
+                                    service clients
+    :param str placement_microversion: microvesion to be set on placement
+                                       service clients
+    """
+
+    def __init__(self, compute_microversion=None, volume_microversion=None,
+                 placement_microversion=None):
+        self.compute_microversion = compute_microversion
+        self.volume_microversion = volume_microversion
+        self.placement_microversion = placement_microversion
+
+    def _setUp(self):
+        super(APIMicroversionFixture, self)._setUp()
+        if self.compute_microversion:
+            base_compute_client.COMPUTE_MICROVERSION = (
+                self.compute_microversion)
+        if self.volume_microversion:
+            base_volume_client.VOLUME_MICROVERSION = self.volume_microversion
+        if self.placement_microversion:
+            base_placement_client.PLACEMENT_MICROVERSION = (
+                self.placement_microversion)
+
+        self.addCleanup(self._reset_microversion)
+
+    def _reset_microversion(self):
+        base_compute_client.COMPUTE_MICROVERSION = None
+        base_volume_client.VOLUME_MICROVERSION = None
+        base_placement_client.PLACEMENT_MICROVERSION = None
diff --git a/tempest/lib/services/compute/servers_client.py b/tempest/lib/services/compute/servers_client.py
index 18e08cc..f2270f8 100644
--- a/tempest/lib/services/compute/servers_client.py
+++ b/tempest/lib/services/compute/servers_client.py
@@ -33,6 +33,8 @@
 from tempest.lib.api_schema.response.compute.v2_57 import servers as schemav257
 from tempest.lib.api_schema.response.compute.v2_6 import servers as schemav26
 from tempest.lib.api_schema.response.compute.v2_63 import servers as schemav263
+from tempest.lib.api_schema.response.compute.v2_70 import servers as schemav270
+from tempest.lib.api_schema.response.compute.v2_71 import servers as schemav271
 from tempest.lib.api_schema.response.compute.v2_8 import servers as schemav28
 from tempest.lib.api_schema.response.compute.v2_9 import servers as schemav29
 from tempest.lib.common import rest_client
@@ -55,7 +57,9 @@
         {'min': '2.48', 'max': '2.53', 'schema': schemav248},
         {'min': '2.54', 'max': '2.56', 'schema': schemav254},
         {'min': '2.57', 'max': '2.62', 'schema': schemav257},
-        {'min': '2.63', 'max': None, 'schema': schemav263}]
+        {'min': '2.63', 'max': '2.69', 'schema': schemav263},
+        {'min': '2.70', 'max': '2.70', 'schema': schemav270},
+        {'min': '2.71', 'max': None, 'schema': schemav271}]
 
     def __init__(self, auth_provider, service, region,
                  enable_instance_password=True, **kwargs):
@@ -426,6 +430,7 @@
         resp, body = self.post('servers/%s/os-volume_attachments' % server_id,
                                post_body)
         body = json.loads(body)
+        schema = self.get_schema(self.schema_versions_info)
         self.validate_response(schema.attach_volume, resp, body)
         return rest_client.ResponseBody(resp, body)
 
@@ -460,6 +465,7 @@
         resp, body = self.get('servers/%s/os-volume_attachments/%s' % (
             server_id, volume_id))
         body = json.loads(body)
+        schema = self.get_schema(self.schema_versions_info)
         self.validate_response(schema.show_volume_attachment, resp, body)
         return rest_client.ResponseBody(resp, body)
 
@@ -473,6 +479,7 @@
         resp, body = self.get('servers/%s/os-volume_attachments' % (
             server_id))
         body = json.loads(body)
+        schema = self.get_schema(self.schema_versions_info)
         self.validate_response(schema.list_volume_attachments, resp, body)
         return rest_client.ResponseBody(resp, body)
 
diff --git a/tempest/lib/services/network/__init__.py b/tempest/lib/services/network/__init__.py
index 419e593..69f178e 100644
--- a/tempest/lib/services/network/__init__.py
+++ b/tempest/lib/services/network/__init__.py
@@ -21,6 +21,9 @@
     MeteringLabelsClient
 from tempest.lib.services.network.networks_client import NetworksClient
 from tempest.lib.services.network.ports_client import PortsClient
+from tempest.lib.services.network.qos_client import QosClient
+from tempest.lib.services.network.qos_minimum_bandwidth_rules_client import \
+    QosMinimumBandwidthRulesClient
 from tempest.lib.services.network.quotas_client import QuotasClient
 from tempest.lib.services.network.routers_client import RoutersClient
 from tempest.lib.services.network.security_group_rules_client import \
@@ -37,6 +40,7 @@
 __all__ = ['AgentsClient', 'ExtensionsClient', 'FloatingIPsClient',
            'MeteringLabelRulesClient', 'MeteringLabelsClient',
            'NetworksClient', 'NetworkVersionsClient', 'PortsClient',
-           'QuotasClient', 'RoutersClient', 'SecurityGroupRulesClient',
-           'SecurityGroupsClient', 'ServiceProvidersClient',
-           'SubnetpoolsClient', 'SubnetsClient', 'TagsClient']
+           'QosClient', 'QosMinimumBandwidthRulesClient', 'QuotasClient',
+           'RoutersClient', 'SecurityGroupRulesClient', 'SecurityGroupsClient',
+           'ServiceProvidersClient', 'SubnetpoolsClient', 'SubnetsClient',
+           'TagsClient']
diff --git a/tempest/lib/services/network/qos_client.py b/tempest/lib/services/network/qos_client.py
new file mode 100644
index 0000000..bcd1066
--- /dev/null
+++ b/tempest/lib/services/network/qos_client.py
@@ -0,0 +1,70 @@
+# Copyright (c) 2019 Ericsson
+#
+#    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.
+
+from tempest.lib.services.network import base
+
+
+class QosClient(base.BaseNetworkClient):
+
+    def create_qos_policy(self, **kwargs):
+        """Creates a QoS policy.
+
+        For full list of available parameters, please refer to the official
+        API reference:
+        https://developer.openstack.org/api-ref/network/v2/index.html#create-qos-policy
+        """
+        uri = '/qos/policies'
+        post_data = {'policy': kwargs}
+        return self.create_resource(uri, post_data)
+
+    def update_qos_policy(self, qos_policy_id, **kwargs):
+        """Updates a QoS policy.
+
+        For full list of available parameters, please refer to the official
+        API reference:
+        https://developer.openstack.org/api-ref/network/v2/index.html#update-qos-policy
+        """
+        uri = '/qos/policies/%s' % qos_policy_id
+        post_data = {'policy': kwargs}
+        return self.update_resource(uri, post_data)
+
+    def show_qos_policy(self, qos_policy_id, **fields):
+        """Show details of a QoS policy.
+
+        For full list of available parameters, please refer to the official
+        API reference:
+        https://developer.openstack.org/api-ref/network/v2/index.html#show-qos-policy-details
+        """
+        uri = '/qos/policies/%s' % qos_policy_id
+        return self.show_resource(uri, **fields)
+
+    def delete_qos_policy(self, qos_policy_id):
+        """Deletes a QoS policy.
+
+        For full list of available parameters, please refer to the official
+        API reference:
+        https://developer.openstack.org/api-ref/network/v2/index.html#delete-qos-policy
+        """
+        uri = '/qos/policies/%s' % qos_policy_id
+        return self.delete_resource(uri)
+
+    def list_qos_policies(self, **filters):
+        """Lists QoS policies.
+
+        For full list of available parameters, please refer to the official
+        API reference:
+        https://developer.openstack.org/api-ref/network/v2/index.html#list-qos-policies
+        """
+        uri = '/qos/policies'
+        return self.list_resources(uri, **filters)
diff --git a/tempest/lib/services/network/qos_minimum_bandwidth_rules_client.py b/tempest/lib/services/network/qos_minimum_bandwidth_rules_client.py
new file mode 100644
index 0000000..4f4ee3f
--- /dev/null
+++ b/tempest/lib/services/network/qos_minimum_bandwidth_rules_client.py
@@ -0,0 +1,73 @@
+# Copyright (c) 2019 Ericsson
+#
+#    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.
+
+from tempest.lib.services.network import base
+
+
+class QosMinimumBandwidthRulesClient(base.BaseNetworkClient):
+
+    def create_minimum_bandwidth_rule(self, qos_policy_id, **kwargs):
+        """Creates a minimum bandwidth rule for a QoS policy.
+
+        For full list of available parameters, please refer to the official
+        API reference:
+        https://developer.openstack.org/api-ref/network/v2/index.html#create-minimum-bandwidth-rule
+        """
+        uri = '/qos/policies/%s/minimum_bandwidth_rules' % qos_policy_id
+        post_data = {'minimum_bandwidth_rule': kwargs}
+        return self.create_resource(uri, post_data)
+
+    def update_minimum_bandwidth_rule(self, qos_policy_id, rule_id, **kwargs):
+        """Updates a minimum bandwidth rule.
+
+        For full list of available parameters, please refer to the official
+        API reference:
+        https://developer.openstack.org/api-ref/network/v2/index.html#update-minimum-bandwidth-rule
+        """
+        uri = '/qos/policies/%s/minimum_bandwidth_rules/%s' % (
+            qos_policy_id, rule_id)
+        post_data = {'minimum_bandwidth_rule': kwargs}
+        return self.update_resource(uri, post_data)
+
+    def show_minimum_bandwidth_rule(self, qos_policy_id, rule_id, **fields):
+        """Show details of a minimum bandwidth rule.
+
+        For full list of available parameters, please refer to the official
+        API reference:
+        https://developer.openstack.org/api-ref/network/v2/index.html#show-minimum-bandwidth-rule-details
+        """
+        uri = '/qos/policies/%s/minimum_bandwidth_rules/%s' % (
+            qos_policy_id, rule_id)
+        return self.show_resource(uri, **fields)
+
+    def delete_minimum_bandwidth_rule(self, qos_policy_id, rule_id):
+        """Deletes a minimum bandwidth rule for a QoS policy.
+
+        For full list of available parameters, please refer to the official
+        API reference:
+        https://developer.openstack.org/api-ref/network/v2/index.html#delete-minimum-bandwidth-rule
+        """
+        uri = '/qos/policies/%s/minimum_bandwidth_rules/%s' % (
+            qos_policy_id, rule_id)
+        return self.delete_resource(uri)
+
+    def list_minimum_bandwidth_rules(self, qos_policy_id, **filters):
+        """Lists all minimum bandwidth rules for a QoS policy.
+
+        For full list of available parameters, please refer to the official
+        API reference:
+        https://developer.openstack.org/api-ref/network/v2/index.html#list-minimum-bandwidth-rules-for-qos-policy
+        """
+        uri = '/qos/policies/%s/minimum_bandwidth_rules' % qos_policy_id
+        return self.list_resources(uri, **filters)
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 86d37f1..87d7e76 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -28,6 +28,8 @@
 from tempest.common import waiters
 from tempest import config
 from tempest import exceptions
+from tempest.lib.common import api_microversion_fixture
+from tempest.lib.common import api_version_utils
 from tempest.lib.common.utils import data_utils
 from tempest.lib.common.utils import test_utils
 from tempest.lib import exceptions as lib_exc
@@ -37,12 +39,57 @@
 
 LOG = log.getLogger(__name__)
 
+LATEST_MICROVERSION = 'latest'
+
 
 class ScenarioTest(tempest.test.BaseTestCase):
     """Base class for scenario tests. Uses tempest own clients. """
 
     credentials = ['primary']
 
+    compute_min_microversion = None
+    compute_max_microversion = LATEST_MICROVERSION
+    volume_min_microversion = None
+    volume_max_microversion = LATEST_MICROVERSION
+    placement_min_microversion = None
+    placement_max_microversion = LATEST_MICROVERSION
+
+    @classmethod
+    def skip_checks(cls):
+        super(ScenarioTest, cls).skip_checks()
+        api_version_utils.check_skip_with_microversion(
+            cls.compute_min_microversion, cls.compute_max_microversion,
+            CONF.compute.min_microversion, CONF.compute.max_microversion)
+        api_version_utils.check_skip_with_microversion(
+            cls.volume_min_microversion, cls.volume_max_microversion,
+            CONF.volume.min_microversion, CONF.volume.max_microversion)
+        api_version_utils.check_skip_with_microversion(
+            cls.placement_min_microversion, cls.placement_max_microversion,
+            CONF.placement.min_microversion, CONF.placement.max_microversion)
+
+    @classmethod
+    def resource_setup(cls):
+        super(ScenarioTest, cls).resource_setup()
+        cls.compute_request_microversion = (
+            api_version_utils.select_request_microversion(
+                cls.compute_min_microversion,
+                CONF.compute.min_microversion))
+        cls.volume_request_microversion = (
+            api_version_utils.select_request_microversion(
+                cls.volume_min_microversion,
+                CONF.volume.min_microversion))
+        cls.placement_request_microversion = (
+            api_version_utils.select_request_microversion(
+                cls.placement_min_microversion,
+                CONF.placement.min_microversion))
+
+    def setUp(self):
+        super(ScenarioTest, self).setUp()
+        self.useFixture(api_microversion_fixture.APIMicroversionFixture(
+            compute_microversion=self.compute_request_microversion,
+            volume_microversion=self.volume_request_microversion,
+            placement_microversion=self.placement_request_microversion))
+
     @classmethod
     def setup_clients(cls):
         super(ScenarioTest, cls).setup_clients()
@@ -979,24 +1026,33 @@
             raise
 
     def check_remote_connectivity(self, source, dest, should_succeed=True,
-                                  nic=None):
-        """assert ping server via source ssh connection
+                                  nic=None, protocol='icmp'):
+        """check server connectivity via source ssh connection
 
-        :param source: RemoteClient: an ssh connection from which to ping
-        :param dest: an IP to ping against
-        :param should_succeed: boolean: should ping succeed or not
-        :param nic: specific network interface to ping from
+        :param source: RemoteClient: an ssh connection from which to execute
+            the check
+        :param dest: an IP to check connectivity against
+        :param should_succeed: boolean should connection succeed or not
+        :param nic: specific network interface to test connectivity from
+        :param protocol: the protocol used to test connectivity with.
+        :returns: True, if the connection succeeded and it was expected to
+            succeed. False otherwise.
         """
-        def ping_remote():
+        method_name = '%s_check' % protocol
+        connectivity_checker = getattr(source, method_name)
+
+        def connect_remote():
             try:
-                source.ping_host(dest, nic=nic)
+                connectivity_checker(dest, nic=nic)
             except lib_exc.SSHExecCommandFailed:
-                LOG.warning('Failed to ping IP: %s via a ssh connection '
-                            'from: %s.', dest, source.ssh_client.host)
+                LOG.warning('Failed to check %(protocol)s connectivity for '
+                            'IP %(dest)s via a ssh connection from: %(src)s.',
+                            dict(protocol=protocol, dest=dest,
+                                 src=source.ssh_client.host))
                 return not should_succeed
             return should_succeed
 
-        result = test_utils.call_until_true(ping_remote,
+        result = test_utils.call_until_true(connect_remote,
                                             CONF.validation.ping_timeout, 1)
         if result:
             return
diff --git a/tempest/scenario/test_network_v6.py b/tempest/scenario/test_network_v6.py
index 438ee01..8de6614 100644
--- a/tempest/scenario/test_network_v6.py
+++ b/tempest/scenario/test_network_v6.py
@@ -166,9 +166,10 @@
         if self._sysconfig_network_scripts_dir_exists(ssh):
             try:
                 ssh.exec_command(
-                    'echo -e "DEVICE=%(nic)s\\nIPV6INIT=yes" | '
+                    'echo -e "DEVICE=%(nic)s\\nNAME=%(nic)s\\nIPV6INIT=yes" | '
                     'sudo tee /etc/sysconfig/network-scripts/ifcfg-%(nic)s; '
-                    'sudo /sbin/service network restart' % {'nic': nic})
+                    'sudo nmcli connection reload' % {'nic': nic})
+                ssh.exec_command('sudo nmcli connection up %s' % nic)
             except exceptions.SSHExecCommandFailed as e:
                 # NOTE(slaweq): Sometimes it can happen that this SSH command
                 # will fail because of some error from network manager in
diff --git a/tempest/scenario/test_security_groups_basic_ops.py b/tempest/scenario/test_security_groups_basic_ops.py
index 2b7926a..9cbd831 100644
--- a/tempest/scenario/test_security_groups_basic_ops.py
+++ b/tempest/scenario/test_security_groups_basic_ops.py
@@ -395,24 +395,22 @@
             self.check_remote_connectivity(source=access_point_ssh,
                                            dest=self._get_server_ip(server))
 
-    def _test_cross_tenant_block(self, source_tenant, dest_tenant):
+    def _test_cross_tenant_block(self, source_tenant, dest_tenant, ruleset):
         # if public router isn't defined, then dest_tenant access is via
         # floating-ip
+        protocol = ruleset['protocol']
         access_point_ssh = self._connect_to_access_point(source_tenant)
         ip = self._get_server_ip(dest_tenant.access_point,
                                  floating=self.floating_ip_access)
         self.check_remote_connectivity(source=access_point_ssh, dest=ip,
-                                       should_succeed=False)
+                                       should_succeed=False, protocol=protocol)
 
-    def _test_cross_tenant_allow(self, source_tenant, dest_tenant):
+    def _test_cross_tenant_allow(self, source_tenant, dest_tenant, ruleset):
         """check for each direction:
 
         creating rule for tenant incoming traffic enables only 1way traffic
         """
-        ruleset = dict(
-            protocol='icmp',
-            direction='ingress'
-        )
+        protocol = ruleset['protocol']
         sec_group_rules_client = (
             dest_tenant.manager.security_group_rules_client)
         self._create_security_group_rule(
@@ -423,10 +421,10 @@
         access_point_ssh = self._connect_to_access_point(source_tenant)
         ip = self._get_server_ip(dest_tenant.access_point,
                                  floating=self.floating_ip_access)
-        self.check_remote_connectivity(access_point_ssh, ip)
+        self.check_remote_connectivity(access_point_ssh, ip, protocol=protocol)
 
         # test that reverse traffic is still blocked
-        self._test_cross_tenant_block(dest_tenant, source_tenant)
+        self._test_cross_tenant_block(dest_tenant, source_tenant, ruleset)
 
         # allow reverse traffic and check
         sec_group_rules_client = (
@@ -440,7 +438,8 @@
         access_point_ssh_2 = self._connect_to_access_point(dest_tenant)
         ip = self._get_server_ip(source_tenant.access_point,
                                  floating=self.floating_ip_access)
-        self.check_remote_connectivity(access_point_ssh_2, ip)
+        self.check_remote_connectivity(access_point_ssh_2, ip,
+                                       protocol=protocol)
 
     def _verify_mac_addr(self, tenant):
         """Verify that VM has the same ip, mac as listed in port"""
@@ -470,6 +469,17 @@
                 self._log_console_output(
                     servers=[tenant.access_point], client=client)
 
+    def _create_protocol_ruleset(self, protocol, port=80):
+        if protocol == 'icmp':
+            ruleset = dict(protocol='icmp',
+                           direction='ingress')
+        else:
+            ruleset = dict(protocol=protocol,
+                           port_range_min=port,
+                           port_range_max=port,
+                           direction='ingress')
+        return ruleset
+
     @decorators.idempotent_id('e79f879e-debb-440c-a7e4-efeda05b6848')
     @utils.services('compute', 'network')
     def test_cross_tenant_traffic(self):
@@ -484,8 +494,18 @@
             # cross tenant check
             source_tenant = self.primary_tenant
             dest_tenant = self.alt_tenant
-            self._test_cross_tenant_block(source_tenant, dest_tenant)
-            self._test_cross_tenant_allow(source_tenant, dest_tenant)
+
+            protocol = CONF.scenario.protocol
+            LOG.debug("Testing cross tenant traffic for %s protocol",
+                      protocol)
+            if protocol in ['udp', 'tcp']:
+                for tenant in [source_tenant, dest_tenant]:
+                    access_point = self._connect_to_access_point(tenant)
+                    access_point.nc_listen_host(protocol=protocol)
+
+            ruleset = self._create_protocol_ruleset(protocol)
+            self._test_cross_tenant_block(source_tenant, dest_tenant, ruleset)
+            self._test_cross_tenant_allow(source_tenant, dest_tenant, ruleset)
         except Exception:
             self._log_console_output_for_all_tenants()
             raise
diff --git a/tempest/tests/common/test_waiters.py b/tempest/tests/common/test_waiters.py
old mode 100644
new mode 100755
index d56e8a4..02e1c99
--- a/tempest/tests/common/test_waiters.py
+++ b/tempest/tests/common/test_waiters.py
@@ -73,6 +73,25 @@
                                     mock.call(volume_id)])
         mock_sleep.assert_called_once_with(1)
 
+    @mock.patch.object(time, 'sleep')
+    def test_wait_for_volume_status_error_extending(self, mock_sleep):
+        # Tests that the wait method raises VolumeExtendErrorException if
+        # the volume status is 'error_extending'.
+        client = mock.Mock(spec=volumes_client.VolumesClient,
+                           resource_type="volume",
+                           build_interval=1)
+        volume1 = {'volume': {'status': 'extending'}}
+        volume2 = {'volume': {'status': 'error_extending'}}
+        mock_show = mock.Mock(side_effect=(volume1, volume2))
+        client.show_volume = mock_show
+        volume_id = '7532b91e-aa0a-4e06-b3e5-20c0c5ee1caa'
+        self.assertRaises(exceptions.VolumeExtendErrorException,
+                          waiters.wait_for_volume_resource_status,
+                          client, volume_id, 'available')
+        mock_show.assert_has_calls([mock.call(volume_id),
+                                    mock.call(volume_id)])
+        mock_sleep.assert_called_once_with(1)
+
 
 class TestInterfaceWaiters(base.TestCase):
 
diff --git a/tempest/tests/lib/services/network/test_qos_client.py b/tempest/tests/lib/services/network/test_qos_client.py
new file mode 100644
index 0000000..b04b847
--- /dev/null
+++ b/tempest/tests/lib/services/network/test_qos_client.py
@@ -0,0 +1,139 @@
+# Copyright (c) 2019 Ericsson
+#
+#    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.
+
+import copy
+
+from tempest.lib.services.network import qos_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestQosClient(base.BaseServiceTest):
+
+    FAKE_QOS_POLICY_ID = "f1011b08-1297-11e9-a1e7-c7e6825a2616"
+
+    FAKE_QOS_POLICY_REQUEST = {
+        'name': 'foo',
+        'shared': True
+    }
+
+    FAKE_QOS_POLICY_RESPONSE = {
+        'policy': {
+            "name": "10Mbit",
+            "description": "This policy limits the ports to 10Mbit max.",
+            "rules": [],
+            "id": FAKE_QOS_POLICY_ID,
+            "is_default": False,
+            "project_id": "8d4c70a21fed4aeba121a1a429ba0d04",
+            "revision_number": 1,
+            "tenant_id": "8d4c70a21fed4aeba121a1a429ba0d04",
+            "created_at": "2018-04-03T21:26:39Z",
+            "updated_at": "2018-04-03T21:26:39Z",
+            "shared": False,
+            "tags": ["tag1,tag2"]
+        }
+    }
+
+    FAKE_QOS_POLICIES = {
+        'policies': [
+            FAKE_QOS_POLICY_RESPONSE['policy']
+        ]
+    }
+
+    def setUp(self):
+        super(TestQosClient, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.qos_client = qos_client.QosClient(
+            fake_auth, "network", "regionOne")
+
+    def _test_create_qos_policy(self, bytes_body=False):
+        self.check_service_client_function(
+            self.qos_client.create_qos_policy,
+            "tempest.lib.common.rest_client.RestClient.post",
+            self.FAKE_QOS_POLICY_RESPONSE,
+            bytes_body,
+            201,
+            **self.FAKE_QOS_POLICY_REQUEST)
+
+    def _test_list_qos_policies(self, bytes_body=False):
+        self.check_service_client_function(
+            self.qos_client.list_qos_policies,
+            "tempest.lib.common.rest_client.RestClient.get",
+            self.FAKE_QOS_POLICIES,
+            bytes_body,
+            200)
+
+    def _test_show_qos_policy(self, bytes_body=False):
+        self.check_service_client_function(
+            self.qos_client.show_qos_policy,
+            "tempest.lib.common.rest_client.RestClient.get",
+            self.FAKE_QOS_POLICY_RESPONSE,
+            bytes_body,
+            200,
+            qos_policy_id=self.FAKE_QOS_POLICY_ID)
+
+    def _test_update_qos_polcy(self, bytes_body=False):
+        update_kwargs = {
+            "name": "100Mbit",
+            "description": "This policy limits the ports to 100Mbit max.",
+            "shared": True
+        }
+
+        resp_body = {
+            "policy": copy.deepcopy(
+                self.FAKE_QOS_POLICY_RESPONSE['policy']
+            )
+        }
+        resp_body["policy"].update(update_kwargs)
+
+        self.check_service_client_function(
+            self.qos_client.update_qos_policy,
+            "tempest.lib.common.rest_client.RestClient.put",
+            resp_body,
+            bytes_body,
+            200,
+            qos_policy_id=self.FAKE_QOS_POLICY_ID,
+            **update_kwargs)
+
+    def test_create_qos_policy_with_str_body(self):
+        self._test_create_qos_policy()
+
+    def test_create_qos_policy_with_bytes_body(self):
+        self._test_create_qos_policy(bytes_body=True)
+
+    def test_update_qos_policy_with_str_body(self):
+        self._test_update_qos_polcy()
+
+    def test_update_qos_policy_with_bytes_body(self):
+        self._test_update_qos_polcy(bytes_body=True)
+
+    def test_show_qos_policy_with_str_body(self):
+        self._test_show_qos_policy()
+
+    def test_show_qos_policy_with_bytes_body(self):
+        self._test_show_qos_policy(bytes_body=True)
+
+    def test_delete_qos_policy(self):
+        self.check_service_client_function(
+            self.qos_client.delete_qos_policy,
+            "tempest.lib.common.rest_client.RestClient.delete",
+            {},
+            status=204,
+            qos_policy_id=self.FAKE_QOS_POLICY_ID)
+
+    def test_list_qos_policies_with_str_body(self):
+        self._test_list_qos_policies()
+
+    def test_list_qos_policies_with_bytes_body(self):
+        self._test_list_qos_policies(bytes_body=True)
diff --git a/tempest/tests/lib/services/network/test_qos_minimum_bandwidth_rules_client.py b/tempest/tests/lib/services/network/test_qos_minimum_bandwidth_rules_client.py
new file mode 100644
index 0000000..8234dda
--- /dev/null
+++ b/tempest/tests/lib/services/network/test_qos_minimum_bandwidth_rules_client.py
@@ -0,0 +1,137 @@
+# Copyright (c) 2019 Ericsson
+#
+#    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.
+
+import copy
+
+from tempest.lib.services.network import qos_minimum_bandwidth_rules_client
+from tempest.tests.lib import fake_auth_provider
+from tempest.tests.lib.services import base
+
+
+class TestQosMinimumBandwidthRulesClient(base.BaseServiceTest):
+
+    FAKE_QOS_POLICY_ID = "f1011b08-1297-11e9-a1e7-c7e6825a2616"
+    FAKE_MIN_BW_RULE_ID = "e758c89e-1297-11e9-a6cf-cf46a71e6699"
+
+    FAKE_MIN_BW_RULE_REQUEST = {
+        'qos_policy_id': FAKE_QOS_POLICY_ID,
+        'min_kbps': 1000,
+        'direction': 'ingress'
+    }
+
+    FAKE_MIN_BW_RULE_RESPONSE = {
+        'minimum_bandwidth_rule': {
+            'id': FAKE_MIN_BW_RULE_ID,
+            'min_kbps': 10000,
+            'direction': 'egress'
+        }
+    }
+
+    FAKE_MIN_BW_RULES = {
+        'bandwidth_limit_rules': [
+            FAKE_MIN_BW_RULE_RESPONSE['minimum_bandwidth_rule']
+        ]
+    }
+
+    def setUp(self):
+        super(TestQosMinimumBandwidthRulesClient, self).setUp()
+        fake_auth = fake_auth_provider.FakeAuthProvider()
+        self.qos_min_bw_client = qos_minimum_bandwidth_rules_client.\
+            QosMinimumBandwidthRulesClient(fake_auth, "network", "regionOne")
+
+    def _test_create_minimum_bandwidth_rule(self, bytes_body=False):
+        self.check_service_client_function(
+            self.qos_min_bw_client.create_minimum_bandwidth_rule,
+            "tempest.lib.common.rest_client.RestClient.post",
+            self.FAKE_MIN_BW_RULE_RESPONSE,
+            bytes_body,
+            201,
+            **self.FAKE_MIN_BW_RULE_REQUEST
+        )
+
+    def _test_list_minimum_bandwidth_rules(self, bytes_body=False):
+        self.check_service_client_function(
+            self.qos_min_bw_client.list_minimum_bandwidth_rules,
+            "tempest.lib.common.rest_client.RestClient.get",
+            self.FAKE_MIN_BW_RULES,
+            bytes_body,
+            200,
+            qos_policy_id=self.FAKE_QOS_POLICY_ID
+        )
+
+    def _test_show_minimum_bandwidth_rule(self, bytes_body=False):
+        self.check_service_client_function(
+            self.qos_min_bw_client.show_minimum_bandwidth_rule,
+            "tempest.lib.common.rest_client.RestClient.get",
+            self.FAKE_MIN_BW_RULE_RESPONSE,
+            bytes_body,
+            200,
+            qos_policy_id=self.FAKE_QOS_POLICY_ID,
+            rule_id=self.FAKE_MIN_BW_RULE_ID
+        )
+
+    def _test_update_qos_polcy(self, bytes_body=False):
+        update_kwargs = {
+            "min_kbps": "20000"
+        }
+
+        resp_body = {
+            "minimum_bandwidth_rule": copy.deepcopy(
+                self.FAKE_MIN_BW_RULE_RESPONSE['minimum_bandwidth_rule']
+            )
+        }
+        resp_body["minimum_bandwidth_rule"].update(update_kwargs)
+
+        self.check_service_client_function(
+            self.qos_min_bw_client.update_minimum_bandwidth_rule,
+            "tempest.lib.common.rest_client.RestClient.put",
+            resp_body,
+            bytes_body,
+            200,
+            qos_policy_id=self.FAKE_QOS_POLICY_ID,
+            rule_id=self.FAKE_MIN_BW_RULE_ID,
+            **update_kwargs)
+
+    def test_create_minimum_bandwidth_rule_with_str_body(self):
+        self._test_create_minimum_bandwidth_rule()
+
+    def test_create_minimum_bandwidth_rule_with_bytes_body(self):
+        self._test_create_minimum_bandwidth_rule(bytes_body=True)
+
+    def test_update_minimum_bandwidth_rule_with_str_body(self):
+        self._test_update_qos_polcy()
+
+    def test_update_minimum_bandwidth_rule_with_bytes_body(self):
+        self._test_update_qos_polcy(bytes_body=True)
+
+    def test_show_minimum_bandwidth_rule_with_str_body(self):
+        self._test_show_minimum_bandwidth_rule()
+
+    def test_show_minimum_bandwidth_rule_with_bytes_body(self):
+        self._test_show_minimum_bandwidth_rule(bytes_body=True)
+
+    def test_delete_minimum_bandwidth_rule(self):
+        self.check_service_client_function(
+            self.qos_min_bw_client.delete_minimum_bandwidth_rule,
+            "tempest.lib.common.rest_client.RestClient.delete",
+            {},
+            status=204,
+            qos_policy_id=self.FAKE_QOS_POLICY_ID,
+            rule_id=self.FAKE_MIN_BW_RULE_ID)
+
+    def test_list_minimum_bandwidth_rule_with_str_body(self):
+        self._test_list_minimum_bandwidth_rules()
+
+    def test_list_minimum_bandwidth_rule_with_bytes_body(self):
+        self._test_list_minimum_bandwidth_rules(bytes_body=True)
diff --git a/tempest/tests/lib/test_api_microversion_fixture.py b/tempest/tests/lib/test_api_microversion_fixture.py
new file mode 100644
index 0000000..ad98ed0
--- /dev/null
+++ b/tempest/tests/lib/test_api_microversion_fixture.py
@@ -0,0 +1,58 @@
+# Copyright 2019 NEC Corporation.
+#
+#    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.
+
+from tempest.lib.common import api_microversion_fixture
+from tempest.lib.services.compute import base_compute_client
+from tempest.lib.services.placement import base_placement_client
+from tempest.lib.services.volume import base_client
+from tempest.tests import base
+
+
+class TestAPIMicroversionFixture(base.TestCase):
+    def setUp(self):
+        super(TestAPIMicroversionFixture, self).setUp()
+        # Verify that all the microversion are reset back to None
+        # by Fixture.
+        self.assertIsNone(base_compute_client.COMPUTE_MICROVERSION)
+        self.assertIsNone(base_client.VOLUME_MICROVERSION)
+        self.assertIsNone(base_placement_client.PLACEMENT_MICROVERSION)
+
+    def test_compute_microversion(self):
+        self.useFixture(api_microversion_fixture.APIMicroversionFixture(
+            compute_microversion='2.10'))
+        self.assertEqual('2.10', base_compute_client.COMPUTE_MICROVERSION)
+        self.assertIsNone(base_client.VOLUME_MICROVERSION)
+        self.assertIsNone(base_placement_client.PLACEMENT_MICROVERSION)
+
+    def test_volume_microversion(self):
+        self.useFixture(api_microversion_fixture.APIMicroversionFixture(
+            volume_microversion='3.10'))
+        self.assertIsNone(base_compute_client.COMPUTE_MICROVERSION)
+        self.assertEqual('3.10', base_client.VOLUME_MICROVERSION)
+        self.assertIsNone(base_placement_client.PLACEMENT_MICROVERSION)
+
+    def test_placement_microversion(self):
+        self.useFixture(api_microversion_fixture.APIMicroversionFixture(
+            placement_microversion='1.10'))
+        self.assertIsNone(base_compute_client.COMPUTE_MICROVERSION)
+        self.assertIsNone(base_client.VOLUME_MICROVERSION)
+        self.assertEqual('1.10', base_placement_client.PLACEMENT_MICROVERSION)
+
+    def test_multiple_service_microversion(self):
+        self.useFixture(api_microversion_fixture.APIMicroversionFixture(
+            compute_microversion='2.10', volume_microversion='3.10',
+            placement_microversion='1.10'))
+        self.assertEqual('2.10', base_compute_client.COMPUTE_MICROVERSION)
+        self.assertEqual('3.10', base_client.VOLUME_MICROVERSION)
+        self.assertEqual('1.10', base_placement_client.PLACEMENT_MICROVERSION)
diff --git a/tools/generate-tempest-plugins-list.py b/tools/generate-tempest-plugins-list.py
index 3772774..746cb34 100644
--- a/tools/generate-tempest-plugins-list.py
+++ b/tools/generate-tempest-plugins-list.py
@@ -19,9 +19,9 @@
 #
 # In order to function correctly, the environment in which the
 # script runs must have
-#   * network access to the review.openstack.org Gerrit API
+#   * network access to the review.opendev.org Gerrit API
 #     working directory
-#   * network access to https://git.openstack.org/cgit
+#   * network access to https://opendev.org/openstack
 
 import json
 import re
@@ -36,7 +36,7 @@
     from urllib2 import HTTPError
 
 
-url = 'https://review.openstack.org/projects/'
+url = 'https://review.opendev.org/projects/'
 
 # This is what a project looks like
 '''
@@ -59,7 +59,8 @@
 def has_tempest_plugin(proj):
     try:
         r = urllib.urlopen(
-            "https://git.openstack.org/cgit/%s/plain/setup.cfg" % proj)
+            "https://opendev.org/%s/raw/branch/"
+            "master/setup.cfg" % proj)
     except HTTPError as err:
         if err.code == 404:
             return False
diff --git a/tools/generate-tempest-plugins-list.sh b/tools/generate-tempest-plugins-list.sh
index 17a4059..b4e5430 100755
--- a/tools/generate-tempest-plugins-list.sh
+++ b/tools/generate-tempest-plugins-list.sh
@@ -28,9 +28,9 @@
 #   * the environment variable git_dir pointing to the location
 #   * of said git repositories
 #   ) OR (
-#   * network access to the review.openstack.org Gerrit API
+#   * network access to the review.opendev.org Gerrit API
 #     working directory
-#   * network access to https://git.openstack.org/cgit
+#   * network access to https://opendev.org/openstack
 #   ))
 #
 # If a file named doc/source/data/tempest-plugins-registry.header or
@@ -69,8 +69,8 @@
 i=0
 for plugin in ${sorted_plugins}; do
     i=$((i+1))
-    giturl="https://git.openstack.org/openstack/${plugin}"
-    gitlink="https://git.openstack.org/cgit/openstack/${plugin}"
+    giturl="https://opendev.org/openstack/${plugin}"
+    gitlink="https://opendev.org/openstack/${plugin}"
     printf "%-3s %-${name_col_len}s %s\n" "$i" "${plugin}" "\`${giturl} <${gitlink}>\`__"
 done
 
diff --git a/tools/tempest-plugin-sanity.sh b/tools/tempest-plugin-sanity.sh
index 6bb87c5..47a9ac9 100644
--- a/tools/tempest-plugin-sanity.sh
+++ b/tools/tempest-plugin-sanity.sh
@@ -46,20 +46,20 @@
 # List of projects having tempest plugin stale or unmaintained for a long time
 # (6 months or more)
 # TODO(masayukig): Some of these can be removed from BLACKLIST in the future.
-# barbican-tempest-plugin: https://review.openstack.org/#/c/634631/
+# barbican-tempest-plugin: https://review.opendev.org/#/c/634631/
 # cyborg-tempest-plugin: https://review.opendev.org/659687
-# intel-nfv-ci-tests: https://review.openstack.org/#/c/634640/
-# networking-ansible: https://review.openstack.org/#/c/634647/
-# networking-generic-switch: https://review.openstack.org/#/c/634846/
-# networking-l2gw-tempest-plugin: https://review.openstack.org/#/c/635093/
-# networking-midonet: https://review.openstack.org/#/c/635096/
-# networking-plumgrid: https://review.openstack.org/#/c/635096/
-# networking-spp: https://review.openstack.org/#/c/635098/
-# neutron-dynamic-routing: https://review.openstack.org/#/c/637718/
-# neutron-vpnaas: https://review.openstack.org/#/c/637719/
-# nova-lxd: https://review.openstack.org/#/c/638334/
-# valet: https://review.openstack.org/#/c/638339/
-# vitrage-tempest-plugin: https://review.openstack.org/#/c/639003/
+# intel-nfv-ci-tests: https://review.opendev.org/#/c/634640/
+# networking-ansible: https://review.opendev.org/#/c/634647/
+# networking-generic-switch: https://review.opendev.org/#/c/634846/
+# networking-l2gw-tempest-plugin: https://review.opendev.org/#/c/635093/
+# networking-midonet: https://review.opendev.org/#/c/635096/
+# networking-plumgrid: https://review.opendev.org/#/c/635096/
+# networking-spp: https://review.opendev.org/#/c/635098/
+# neutron-dynamic-routing: https://review.opendev.org/#/c/637718/
+# neutron-vpnaas: https://review.opendev.org/#/c/637719/
+# nova-lxd: https://review.opendev.org/#/c/638334/
+# valet: https://review.opendev.org/#/c/638339/
+
 BLACKLIST="
 barbican-tempest-plugin
 cyborg-tempest-plugin
@@ -74,18 +74,17 @@
 neutron-vpnaas
 nova-lxd
 valet
-vitrage-tempest-plugin
 "
 
 # Function to clone project using zuul-cloner or from git
 function clone_project() {
     if [ -e /usr/zuul-env/bin/zuul-cloner ]; then
         /usr/zuul-env/bin/zuul-cloner --cache-dir /opt/git \
-        https://git.openstack.org \
+        https://opendev.org \
         openstack/"$1"
 
     elif [ -e /usr/bin/git ]; then
-        /usr/bin/git clone https://git.openstack.org/openstack/"$1" \
+        /usr/bin/git clone https://opendev.org/openstack/"$1" \
         openstack/"$1"
 
     fi
@@ -152,8 +151,10 @@
     fi
 done
 
+echo "Passed Plugins: $passed_plugin"
+echo "Failed Plugins: $failed_plugin"
+
 # Check for failed status
 if [[ -n $failed_plugin ]]; then
-    echo "Failed Plugins: $failed_plugin"
     exit 1
 fi
diff --git a/tox.ini b/tox.ini
index 92a5562..291d899 100644
--- a/tox.ini
+++ b/tox.ini
@@ -9,7 +9,7 @@
     VIRTUAL_ENV={envdir}
     OS_TEST_PATH=./tempest/test_discover
 deps =
-    -c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt}
+    -c{env:UPPER_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master}
     -r{toxinidir}/requirements.txt
 
 [testenv]
@@ -25,7 +25,7 @@
 install_command = pip install {opts} {packages}
 whitelist_externals = *
 deps =
-    -c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt}
+    -c{env:UPPER_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master}
     -r{toxinidir}/requirements.txt
     -r{toxinidir}/test-requirements.txt
 commands =
@@ -173,7 +173,7 @@
 
 [testenv:venv]
 deps =
-  -c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt}
+  -c{env:UPPER_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master}
   -r{toxinidir}/requirements.txt
   -r{toxinidir}/doc/requirements.txt
 commands = {posargs}
@@ -188,7 +188,7 @@
 [testenv:docs]
 basepython = python3
 deps =
-  -c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt}
+  -c{env:UPPER_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master}
   -r{toxinidir}/requirements.txt
   -r{toxinidir}/doc/requirements.txt
 commands =
@@ -221,7 +221,7 @@
 import_exceptions = tempest.services
 
 [flake8]
-# E125 is a won't fix until https://github.com/jcrocholl/pep8/issues/126 is resolved.  For further detail see https://review.openstack.org/#/c/36788/
+# E125 is a won't fix until https://github.com/jcrocholl/pep8/issues/126 is resolved.  For further detail see https://review.opendev.org/#/c/36788/
 # E123 skipped because it is ignored by default in the default pep8
 # E129 skipped because it is too limiting when combined with other rules
 # W504 skipped because it is overeager and unnecessary
@@ -234,7 +234,7 @@
 [testenv:releasenotes]
 basepython = python3
 deps =
-  -c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt}
+  -c{env:UPPER_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master}
   -r{toxinidir}/requirements.txt
   -r{toxinidir}/doc/requirements.txt
 commands =