Merge "Remove nova-cells-v1 job from experimental queue"
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..e8206ee 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
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/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/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/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/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..ea68005 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):
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/config.py b/tempest/config.py
index f692a4b..e3ac47c 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -1052,7 +1052,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/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/scenario/manager.py b/tempest/scenario/manager.py
index 86d37f1..aa06fd0 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -979,24 +979,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/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..b291fcc 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
diff --git a/tox.ini b/tox.ini
index 9bee3dd..48a2baa 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 =