Merge "Cleanup _interface class variables in compute"
diff --git a/tempest/api/compute/servers/test_delete_server.py b/tempest/api/compute/servers/test_delete_server.py
index 9772059..5e011dd 100644
--- a/tempest/api/compute/servers/test_delete_server.py
+++ b/tempest/api/compute/servers/test_delete_server.py
@@ -13,6 +13,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import testtools
+
 from tempest.api.compute import base
 from tempest import config
 from tempest import test
@@ -84,6 +86,19 @@
         self.assertEqual('204', resp['status'])
         self.client.wait_for_server_termination(server['id'])
 
+    @testtools.skipIf(not CONF.compute_feature_enabled.resize,
+                      'Resize not available.')
+    @test.attr(type='gate')
+    def test_delete_server_while_in_verify_resize_state(self):
+        # Delete a server while it's VM state is VERIFY_RESIZE
+        resp, server = self.create_test_server(wait_until='ACTIVE')
+        resp, body = self.client.resize(server['id'], self.flavor_ref_alt)
+        self.assertEqual(202, resp.status)
+        self.client.wait_for_server_status(server['id'], 'VERIFY_RESIZE')
+        resp, _ = self.client.delete_server(server['id'])
+        self.assertEqual('204', resp['status'])
+        self.client.wait_for_server_termination(server['id'])
+
 
 class DeleteServersAdminTestJSON(base.BaseV2ComputeAdminTest):
     # NOTE: Server creations of each test class should be under 10
diff --git a/tempest/api/compute/servers/test_list_servers_negative.py b/tempest/api/compute/servers/test_list_servers_negative.py
index 97f16cc..26c5887 100644
--- a/tempest/api/compute/servers/test_list_servers_negative.py
+++ b/tempest/api/compute/servers/test_list_servers_negative.py
@@ -15,6 +15,8 @@
 
 import datetime
 
+from six import moves
+
 from tempest.api.compute import base
 from tempest import exceptions
 from tempest.test import attr
@@ -35,7 +37,7 @@
         cls.existing_fixtures = []
         cls.deleted_fixtures = []
         cls.start_time = datetime.datetime.utcnow()
-        for x in xrange(2):
+        for x in moves.xrange(2):
             resp, srv = cls.create_test_server()
             cls.existing_fixtures.append(srv)
 
diff --git a/tempest/api/compute/v3/servers/test_delete_server.py b/tempest/api/compute/v3/servers/test_delete_server.py
index 4b11335..d694a33 100644
--- a/tempest/api/compute/v3/servers/test_delete_server.py
+++ b/tempest/api/compute/v3/servers/test_delete_server.py
@@ -12,6 +12,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import testtools
+
 from tempest.api.compute import base
 from tempest import config
 from tempest import test
@@ -84,6 +86,19 @@
         self.assertEqual('204', resp['status'])
         self.client.wait_for_server_termination(server['id'])
 
+    @testtools.skipIf(not CONF.compute_feature_enabled.resize,
+                      'Resize not available.')
+    @test.attr(type='gate')
+    def test_delete_server_while_in_verify_resize_state(self):
+        # Delete a server while it's VM state is VERIFY_RESIZE
+        resp, server = self.create_test_server(wait_until='ACTIVE')
+        resp, body = self.client.resize(server['id'], self.flavor_ref_alt)
+        self.assertEqual(202, resp.status)
+        self.client.wait_for_server_status(server['id'], 'VERIFY_RESIZE')
+        resp, _ = self.client.delete_server(server['id'])
+        self.assertEqual('204', resp['status'])
+        self.client.wait_for_server_termination(server['id'])
+
 
 class DeleteServersAdminV3Test(base.BaseV3ComputeAdminTest):
     # NOTE: Server creations of each test class should be under 10
diff --git a/tempest/api/compute/v3/servers/test_list_servers_negative.py b/tempest/api/compute/v3/servers/test_list_servers_negative.py
index 9a46193..92f44fe 100644
--- a/tempest/api/compute/v3/servers/test_list_servers_negative.py
+++ b/tempest/api/compute/v3/servers/test_list_servers_negative.py
@@ -15,6 +15,8 @@
 
 import datetime
 
+from six import moves
+
 from tempest.api.compute import base
 from tempest import exceptions
 from tempest.test import attr
@@ -35,7 +37,7 @@
         cls.existing_fixtures = []
         cls.deleted_fixtures = []
         cls.start_time = datetime.datetime.utcnow()
-        for x in xrange(2):
+        for x in moves.xrange(2):
             resp, srv = cls.create_test_server()
             cls.existing_fixtures.append(srv)
 
diff --git a/tempest/api/compute/v3/servers/test_server_addresses.py b/tempest/api/compute/v3/servers/test_server_addresses.py
index 335bd3d..efd7500 100644
--- a/tempest/api/compute/v3/servers/test_server_addresses.py
+++ b/tempest/api/compute/v3/servers/test_server_addresses.py
@@ -15,7 +15,6 @@
 
 from tempest.api.compute import base
 from tempest import config
-from tempest import exceptions
 from tempest import test
 
 CONF = config.CONF
@@ -32,19 +31,6 @@
 
         resp, cls.server = cls.create_test_server(wait_until='ACTIVE')
 
-    @test.attr(type=['negative', 'gate'])
-    def test_list_server_addresses_invalid_server_id(self):
-        # List addresses request should fail if server id not in system
-        self.assertRaises(exceptions.NotFound, self.client.list_addresses,
-                          '999')
-
-    @test.attr(type=['negative', 'gate'])
-    def test_list_server_addresses_by_network_neg(self):
-        # List addresses by network should fail if network name not valid
-        self.assertRaises(exceptions.NotFound,
-                          self.client.list_addresses_by_network,
-                          self.server['id'], 'invalid')
-
     @test.skip_because(bug="1210483",
                        condition=CONF.service_available.neutron)
     @test.attr(type='smoke')
diff --git a/tempest/api/compute/v3/servers/test_server_addresses_negative.py b/tempest/api/compute/v3/servers/test_server_addresses_negative.py
new file mode 100644
index 0000000..8a9877b
--- /dev/null
+++ b/tempest/api/compute/v3/servers/test_server_addresses_negative.py
@@ -0,0 +1,46 @@
+# Copyright 2012 OpenStack Foundation
+# 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.
+
+from tempest.api.compute import base
+from tempest.common.utils import data_utils
+from tempest import exceptions
+from tempest import test
+
+
+class ServerAddressesV3NegativeTest(base.BaseV3ComputeTest):
+    _interface = 'json'
+
+    @classmethod
+    def setUpClass(cls):
+        # This test module might use a network and a subnet
+        cls.set_network_resources(network=True, subnet=True)
+        super(ServerAddressesV3NegativeTest, cls).setUpClass()
+        cls.client = cls.servers_client
+
+        resp, cls.server = cls.create_test_server(wait_until='ACTIVE')
+
+    @test.attr(type=['negative', 'gate'])
+    def test_list_server_addresses_nonexistent_server_id(self):
+        # List addresses request should fail if server id not in system
+        non_existent_server_id = data_utils.rand_uuid()
+        self.assertRaises(exceptions.NotFound, self.client.list_addresses,
+                          non_existent_server_id)
+
+    @test.attr(type=['negative', 'gate'])
+    def test_list_server_addresses_by_network_neg(self):
+        # List addresses by network should fail if network name not valid
+        self.assertRaises(exceptions.NotFound,
+                          self.client.list_addresses_by_network,
+                          self.server['id'], 'invalid')
diff --git a/tempest/api/identity/admin/test_roles.py b/tempest/api/identity/admin/test_roles.py
index aa64969..5e78cce 100644
--- a/tempest/api/identity/admin/test_roles.py
+++ b/tempest/api/identity/admin/test_roles.py
@@ -13,6 +13,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from six import moves
+
 from tempest.api.identity import base
 from tempest.common.utils import data_utils
 from tempest.test import attr
@@ -24,7 +26,7 @@
     @classmethod
     def setUpClass(cls):
         super(RolesTestJSON, cls).setUpClass()
-        for _ in xrange(5):
+        for _ in moves.xrange(5):
             role_name = data_utils.rand_name(name='role-')
             resp, role = cls.client.create_role(role_name)
             cls.data.roles.append(role)
diff --git a/tempest/api/identity/admin/test_services.py b/tempest/api/identity/admin/test_services.py
index cbf6b58..459c44c 100644
--- a/tempest/api/identity/admin/test_services.py
+++ b/tempest/api/identity/admin/test_services.py
@@ -13,6 +13,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from six import moves
 
 from tempest.api.identity import base
 from tempest.common.utils import data_utils
@@ -69,7 +70,7 @@
     def test_list_services(self):
         # Create, List, Verify and Delete Services
         services = []
-        for _ in xrange(3):
+        for _ in moves.xrange(3):
             name = data_utils.rand_name('service-')
             type = data_utils.rand_name('type--')
             description = data_utils.rand_name('description-')
diff --git a/tempest/api/identity/admin/test_tenants.py b/tempest/api/identity/admin/test_tenants.py
index c7cacb4..257a6d7 100644
--- a/tempest/api/identity/admin/test_tenants.py
+++ b/tempest/api/identity/admin/test_tenants.py
@@ -13,6 +13,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from six import moves
+
 from tempest.api.identity import base
 from tempest.common.utils import data_utils
 from tempest.test import attr
@@ -25,7 +27,7 @@
     def test_tenant_list_delete(self):
         # Create several tenants and delete them
         tenants = []
-        for _ in xrange(3):
+        for _ in moves.xrange(3):
             tenant_name = data_utils.rand_name(name='tenant-new')
             resp, tenant = self.client.create_tenant(tenant_name)
             self.assertEqual(200, resp.status)
diff --git a/tempest/api/identity/admin/v3/test_projects.py b/tempest/api/identity/admin/v3/test_projects.py
index be03a03..31a0ddd 100644
--- a/tempest/api/identity/admin/v3/test_projects.py
+++ b/tempest/api/identity/admin/v3/test_projects.py
@@ -13,6 +13,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from six import moves
+
 from tempest.api.identity import base
 from tempest.common.utils import data_utils
 from tempest import exceptions
@@ -31,7 +33,7 @@
     @test.attr(type='gate')
     def test_project_list_delete(self):
         # Create several projects and delete them
-        for _ in xrange(3):
+        for _ in moves.xrange(3):
             resp, project = self.client.create_project(
                 data_utils.rand_name('project-new'))
             self.addCleanup(self._delete_project, project['id'])
diff --git a/tempest/api/object_storage/test_account_services.py b/tempest/api/object_storage/test_account_services.py
index 5456768..7542ea1 100644
--- a/tempest/api/object_storage/test_account_services.py
+++ b/tempest/api/object_storage/test_account_services.py
@@ -15,6 +15,8 @@
 
 import random
 
+from six import moves
+
 from tempest.api.object_storage import base
 from tempest.common import custom_matchers
 from tempest.common.utils import data_utils
@@ -26,7 +28,7 @@
     def setUpClass(cls):
         super(AccountTest, cls).setUpClass()
         cls.containers = []
-        for i in xrange(ord('a'), ord('f') + 1):
+        for i in moves.xrange(ord('a'), ord('f') + 1):
             name = data_utils.rand_name(name='%s-' % chr(i))
             cls.container_client.create_container(name)
             cls.containers.append(name)
diff --git a/tempest/api/object_storage/test_object_services.py b/tempest/api/object_storage/test_object_services.py
index 33f3299..91df292 100644
--- a/tempest/api/object_storage/test_object_services.py
+++ b/tempest/api/object_storage/test_object_services.py
@@ -14,6 +14,7 @@
 #    under the License.
 
 import hashlib
+from six import moves
 
 from tempest.api.object_storage import base
 from tempest.common import custom_matchers
@@ -242,9 +243,9 @@
         object_name = data_utils.rand_name(name='LObject')
         data = data_utils.arbitrary_string()
         segments = 10
-        data_segments = [data + str(i) for i in xrange(segments)]
+        data_segments = [data + str(i) for i in moves.xrange(segments)]
         # uploading segments
-        for i in xrange(segments):
+        for i in moves.xrange(segments):
             resp, _ = self.object_client.create_object_segments(
                 self.container_name, object_name, i, data_segments[i])
             self.assertEqual(resp['status'], '201')
diff --git a/tempest/common/generate_sample_tempest.py b/tempest/common/generate_sample_tempest.py
index e1213db..ceb3394 100644
--- a/tempest/common/generate_sample_tempest.py
+++ b/tempest/common/generate_sample_tempest.py
@@ -31,5 +31,5 @@
 
 
 if __name__ == "__main__":
-    CONF = tempest.config.TempestConfigPrivate(False)
+    tempest.config.register_opts()
     generator.generate(sys.argv[1:])
diff --git a/tempest/common/glance_http.py b/tempest/common/glance_http.py
index 4503f13..b4ba933 100644
--- a/tempest/common/glance_http.py
+++ b/tempest/common/glance_http.py
@@ -21,6 +21,7 @@
 import json
 import posixpath
 import re
+from six import moves
 import socket
 import StringIO
 import struct
@@ -264,7 +265,7 @@
 
         # Also try Subject Alternative Names for a match
         san_list = None
-        for i in xrange(x509.get_extension_count()):
+        for i in moves.xrange(x509.get_extension_count()):
             ext = x509.get_extension(i)
             if ext.get_short_name() == 'subjectAltName':
                 san_list = str(ext)
diff --git a/tempest/common/ssh.py b/tempest/common/ssh.py
index b6fa0a0..531887c 100644
--- a/tempest/common/ssh.py
+++ b/tempest/common/ssh.py
@@ -16,6 +16,7 @@
 
 import cStringIO
 import select
+import six
 import socket
 import time
 import warnings
@@ -39,7 +40,7 @@
         self.host = host
         self.username = username
         self.password = password
-        if isinstance(pkey, basestring):
+        if isinstance(pkey, six.string_types):
             pkey = paramiko.RSAKey.from_private_key(
                 cStringIO.StringIO(str(pkey)))
         self.pkey = pkey
diff --git a/tempest/common/utils/linux/remote_client.py b/tempest/common/utils/linux/remote_client.py
index 94fc23c..8420ad0 100644
--- a/tempest/common/utils/linux/remote_client.py
+++ b/tempest/common/utils/linux/remote_client.py
@@ -11,6 +11,7 @@
 #    under the License.
 
 import re
+import six
 import time
 
 from tempest.common import ssh
@@ -28,7 +29,7 @@
         network = CONF.compute.network_for_ssh
         ip_version = CONF.compute.ip_version_for_ssh
         ssh_channel_timeout = CONF.compute.ssh_channel_timeout
-        if isinstance(server, basestring):
+        if isinstance(server, six.string_types):
             ip_address = server
         else:
             addresses = server['addresses'][network]
@@ -93,3 +94,18 @@
     def get_mac_address(self):
         cmd = "/sbin/ifconfig | awk '/HWaddr/ {print $5}'"
         return self.ssh_client.exec_command(cmd)
+
+    def get_ip_list(self):
+        cmd = "/bin/ip address"
+        return self.ssh_client.exec_command(cmd)
+
+    def assign_static_ip(self, nic, addr):
+        cmd = "sudo /bin/ip addr add {ip}/{mask} dev {nic}".format(
+            ip=addr, mask=CONF.network.tenant_network_mask_bits,
+            nic=nic
+        )
+        return self.ssh_client.exec_command(cmd)
+
+    def turn_nic_on(self, nic):
+        cmd = "sudo /bin/ip link set {nic} up".format(nic=nic)
+        return self.ssh_client.exec_command(cmd)
diff --git a/tempest/config.py b/tempest/config.py
index 887bac3..0f5e23c 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -807,6 +807,41 @@
 ]
 
 
+def register_opts():
+    register_opt_group(cfg.CONF, compute_group, ComputeGroup)
+    register_opt_group(cfg.CONF, compute_features_group,
+                       ComputeFeaturesGroup)
+    register_opt_group(cfg.CONF, identity_group, IdentityGroup)
+    register_opt_group(cfg.CONF, identity_feature_group,
+                       IdentityFeatureGroup)
+    register_opt_group(cfg.CONF, image_group, ImageGroup)
+    register_opt_group(cfg.CONF, image_feature_group, ImageFeaturesGroup)
+    register_opt_group(cfg.CONF, network_group, NetworkGroup)
+    register_opt_group(cfg.CONF, network_feature_group,
+                       NetworkFeaturesGroup)
+    register_opt_group(cfg.CONF, volume_group, VolumeGroup)
+    register_opt_group(cfg.CONF, volume_feature_group,
+                       VolumeFeaturesGroup)
+    register_opt_group(cfg.CONF, object_storage_group, ObjectStoreGroup)
+    register_opt_group(cfg.CONF, object_storage_feature_group,
+                       ObjectStoreFeaturesGroup)
+    register_opt_group(cfg.CONF, orchestration_group, OrchestrationGroup)
+    register_opt_group(cfg.CONF, telemetry_group, TelemetryGroup)
+    register_opt_group(cfg.CONF, dashboard_group, DashboardGroup)
+    register_opt_group(cfg.CONF, data_processing_group,
+                       DataProcessingGroup)
+    register_opt_group(cfg.CONF, boto_group, BotoGroup)
+    register_opt_group(cfg.CONF, compute_admin_group, ComputeAdminGroup)
+    register_opt_group(cfg.CONF, stress_group, StressGroup)
+    register_opt_group(cfg.CONF, scenario_group, ScenarioGroup)
+    register_opt_group(cfg.CONF, service_available_group,
+                       ServiceAvailableGroup)
+    register_opt_group(cfg.CONF, debug_group, DebugGroup)
+    register_opt_group(cfg.CONF, baremetal_group, BaremetalGroup)
+    register_opt_group(cfg.CONF, input_scenario_group, InputScenarioGroup)
+    register_opt_group(cfg.CONF, cli_group, CLIGroup)
+
+
 # this should never be called outside of this class
 class TempestConfigPrivate(object):
     """Provides OpenStack configuration information."""
@@ -817,64 +852,7 @@
 
     DEFAULT_CONFIG_FILE = "tempest.conf"
 
-    def __init__(self, parse_conf=True):
-        """Initialize a configuration from a conf directory and conf file."""
-        super(TempestConfigPrivate, self).__init__()
-        config_files = []
-        failsafe_path = "/etc/tempest/" + self.DEFAULT_CONFIG_FILE
-
-        # Environment variables override defaults...
-        conf_dir = os.environ.get('TEMPEST_CONFIG_DIR',
-                                  self.DEFAULT_CONFIG_DIR)
-        conf_file = os.environ.get('TEMPEST_CONFIG', self.DEFAULT_CONFIG_FILE)
-
-        path = os.path.join(conf_dir, conf_file)
-
-        if not os.path.isfile(path):
-            path = failsafe_path
-
-        # only parse the config file if we expect one to exist. This is needed
-        # to remove an issue with the config file up to date checker.
-        if parse_conf:
-            config_files.append(path)
-
-        cfg.CONF([], project='tempest', default_config_files=config_files)
-        logging.setup('tempest')
-        LOG = logging.getLogger('tempest')
-        LOG.info("Using tempest config file %s" % path)
-
-        register_opt_group(cfg.CONF, compute_group, ComputeGroup)
-        register_opt_group(cfg.CONF, compute_features_group,
-                           ComputeFeaturesGroup)
-        register_opt_group(cfg.CONF, identity_group, IdentityGroup)
-        register_opt_group(cfg.CONF, identity_feature_group,
-                           IdentityFeatureGroup)
-        register_opt_group(cfg.CONF, image_group, ImageGroup)
-        register_opt_group(cfg.CONF, image_feature_group, ImageFeaturesGroup)
-        register_opt_group(cfg.CONF, network_group, NetworkGroup)
-        register_opt_group(cfg.CONF, network_feature_group,
-                           NetworkFeaturesGroup)
-        register_opt_group(cfg.CONF, volume_group, VolumeGroup)
-        register_opt_group(cfg.CONF, volume_feature_group,
-                           VolumeFeaturesGroup)
-        register_opt_group(cfg.CONF, object_storage_group, ObjectStoreGroup)
-        register_opt_group(cfg.CONF, object_storage_feature_group,
-                           ObjectStoreFeaturesGroup)
-        register_opt_group(cfg.CONF, orchestration_group, OrchestrationGroup)
-        register_opt_group(cfg.CONF, telemetry_group, TelemetryGroup)
-        register_opt_group(cfg.CONF, dashboard_group, DashboardGroup)
-        register_opt_group(cfg.CONF, data_processing_group,
-                           DataProcessingGroup)
-        register_opt_group(cfg.CONF, boto_group, BotoGroup)
-        register_opt_group(cfg.CONF, compute_admin_group, ComputeAdminGroup)
-        register_opt_group(cfg.CONF, stress_group, StressGroup)
-        register_opt_group(cfg.CONF, scenario_group, ScenarioGroup)
-        register_opt_group(cfg.CONF, service_available_group,
-                           ServiceAvailableGroup)
-        register_opt_group(cfg.CONF, debug_group, DebugGroup)
-        register_opt_group(cfg.CONF, baremetal_group, BaremetalGroup)
-        register_opt_group(cfg.CONF, input_scenario_group, InputScenarioGroup)
-        register_opt_group(cfg.CONF, cli_group, CLIGroup)
+    def _set_attrs(self):
         self.compute = cfg.CONF.compute
         self.compute_feature_enabled = cfg.CONF['compute-feature-enabled']
         self.identity = cfg.CONF.identity
@@ -906,6 +884,33 @@
             self.compute_admin.password = self.identity.admin_password
             self.compute_admin.tenant_name = self.identity.admin_tenant_name
 
+    def __init__(self, parse_conf=True):
+        """Initialize a configuration from a conf directory and conf file."""
+        super(TempestConfigPrivate, self).__init__()
+        config_files = []
+        failsafe_path = "/etc/tempest/" + self.DEFAULT_CONFIG_FILE
+
+        # Environment variables override defaults...
+        conf_dir = os.environ.get('TEMPEST_CONFIG_DIR',
+                                  self.DEFAULT_CONFIG_DIR)
+        conf_file = os.environ.get('TEMPEST_CONFIG', self.DEFAULT_CONFIG_FILE)
+
+        path = os.path.join(conf_dir, conf_file)
+
+        if not os.path.isfile(path):
+            path = failsafe_path
+
+        # only parse the config file if we expect one to exist. This is needed
+        # to remove an issue with the config file up to date checker.
+        if parse_conf:
+            config_files.append(path)
+
+        cfg.CONF([], project='tempest', default_config_files=config_files)
+        logging.setup('tempest')
+        LOG = logging.getLogger('tempest')
+        LOG.info("Using tempest config file %s" % path)
+        register_opts()
+        self._set_attrs()
         if parse_conf:
             cfg.CONF.log_opt_values(LOG, std_logging.DEBUG)
 
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 1b1ddab..f06a850 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -16,6 +16,7 @@
 
 import logging
 import os
+import six
 import subprocess
 
 import netaddr
@@ -371,7 +372,7 @@
         return keypair
 
     def get_remote_client(self, server_or_ip, username=None, private_key=None):
-        if isinstance(server_or_ip, basestring):
+        if isinstance(server_or_ip, six.string_types):
             ip = server_or_ip
         else:
             network_name_for_ssh = CONF.compute.network_for_ssh
@@ -512,7 +513,7 @@
         ports = self._list_ports(tenant_id=tenant_id)
         return len(ports)
 
-    def _create_subnet(self, network, namestart='subnet-smoke-'):
+    def _create_subnet(self, network, namestart='subnet-smoke-', **kwargs):
         """
         Create a subnet for the given network within the cidr block
         configured for tenant networks.
@@ -545,6 +546,7 @@
                     cidr=str_cidr,
                 ),
             )
+            body['subnet'].update(kwargs)
             try:
                 result = self.network_client.create_subnet(body=body)
                 break
@@ -702,6 +704,28 @@
                                                   private_key)
             linux_client.validate_authentication()
 
+    def _check_remote_connectivity(self, source, dest, should_succeed=True):
+        """
+        check ping server via source ssh connection
+
+        :param source: RemoteClient: an ssh connection from which to ping
+        :param dest: and IP to ping against
+        :param should_succeed: boolean should ping succeed or not
+        :returns: boolean -- should_succeed == ping
+        :returns: ping is false if ping failed
+        """
+        def ping_remote():
+            try:
+                source.ping_host(dest)
+            except exceptions.SSHExecCommandFailed:
+                LOG.exception('Failed to ping host via ssh connection')
+                return not should_succeed
+            return should_succeed
+
+        return tempest.test.call_until_true(ping_remote,
+                                            CONF.compute.ping_timeout,
+                                            1)
+
     def _create_security_group_nova(self, client=None,
                                     namestart='secgroup-smoke-',
                                     tenant_id=None):
diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
index 998a474..e441415 100644
--- a/tempest/scenario/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -15,6 +15,9 @@
 #    under the License.
 import collections
 
+import re
+
+from tempest.api.network import common as net_common
 from tempest.common import debug
 from tempest.common.utils import data_utils
 from tempest import config
@@ -36,36 +39,6 @@
     boot VM's with Neutron-managed networking, and attempts to
     verify network connectivity as follows:
 
-     * For a freshly-booted VM with an IP address ("port") on a given network:
-
-       - the Tempest host can ping the IP address.  This implies, but
-         does not guarantee (see the ssh check that follows), that the
-         VM has been assigned the correct IP address and has
-         connectivity to the Tempest host.
-
-       - the Tempest host can perform key-based authentication to an
-         ssh server hosted at the IP address.  This check guarantees
-         that the IP address is associated with the target VM.
-
-       - detach the floating-ip from the VM and verify that it becomes
-       unreachable
-
-       - associate detached floating ip to a new VM and verify connectivity.
-       VMs are created with unique keypair so connectivity also asserts that
-       floating IP is associated with the new VM instead of the old one
-
-       # TODO(mnewby) - Need to implement the following:
-       - the Tempest host can ssh into the VM via the IP address and
-         successfully execute the following:
-
-         - ping an external IP address, implying external connectivity.
-
-         - ping an external hostname, implying that dns is correctly
-           configured.
-
-         - ping an internal IP address, implying connectivity to another
-           VM on the same network.
-
      There are presumed to be two types of networks: tenant and
      public.  A tenant network may or may not be reachable from the
      Tempest host.  A public network is assumed to be reachable from
@@ -250,9 +223,125 @@
         self.floating_ip_tuple = Floating_IP_tuple(
             floating_ip, serv_dict['server'])
 
+    def _create_new_network(self):
+        self.new_net = self._create_network(self.tenant_id)
+        self.addCleanup(self.cleanup_wrapper, self.new_net)
+        self.new_subnet = self._create_subnet(
+            network=self.new_net,
+            gateway_ip=None)
+        self.addCleanup(self.cleanup_wrapper, self.new_subnet)
+
+    def _hotplug_server(self):
+        old_floating_ip, server = self.floating_ip_tuple
+        ip_address = old_floating_ip.floating_ip_address
+        private_key = self.servers[server].private_key
+        ssh_client = self.get_remote_client(ip_address,
+                                            private_key=private_key)
+        old_nic_list = self._get_server_nics(ssh_client)
+        # get a port from a list of one item
+        port_list = self._list_ports(device_id=server.id)
+        self.assertEqual(1, len(port_list))
+        old_port = port_list[0]
+        self.compute_client.servers.interface_attach(server=server,
+                                                     net_id=self.new_net.id,
+                                                     port_id=None,
+                                                     fixed_ip=None)
+        # move server to the head of the cleanup list
+        self.addCleanup(self.cleanup_wrapper, server)
+
+        def check_ports():
+            port_list = [port for port in
+                         self._list_ports(device_id=server.id)
+                         if port != old_port]
+            return len(port_list) == 1
+
+        test.call_until_true(check_ports, 60, 1)
+        new_port_list = [p for p in
+                         self._list_ports(device_id=server.id)
+                         if p != old_port]
+        self.assertEqual(1, len(new_port_list))
+        new_port = new_port_list[0]
+        new_port = net_common.DeletablePort(client=self.network_client,
+                                            **new_port)
+        new_nic_list = self._get_server_nics(ssh_client)
+        diff_list = [n for n in new_nic_list if n not in old_nic_list]
+        self.assertEqual(1, len(diff_list))
+        num, new_nic = diff_list[0]
+        ssh_client.assign_static_ip(nic=new_nic,
+                                    addr=new_port.fixed_ips[0]['ip_address'])
+        ssh_client.turn_nic_on(nic=new_nic)
+
+    def _get_server_nics(self, ssh_client):
+        reg = re.compile(r'(?P<num>\d+): (?P<nic_name>\w+):')
+        ipatxt = ssh_client.get_ip_list()
+        return reg.findall(ipatxt)
+
+    def _check_network_internal_connectivity(self):
+        """
+        via ssh check VM internal connectivity:
+        - ping internal DHCP port, implying in-tenant connectivty
+        """
+        floating_ip, server = self.floating_ip_tuple
+        # get internal ports' ips:
+        # get all network ports in the new network
+        internal_ips = (p['fixed_ips'][0]['ip_address'] for p in
+                        self._list_ports(tenant_id=server.tenant_id,
+                                         network_id=self.new_net.id)
+                        if p['device_owner'].startswith('network'))
+
+        ip_address = floating_ip.floating_ip_address
+        private_key = self.servers[server].private_key
+        ssh_source = self._ssh_to_server(ip_address, private_key)
+
+        for remote_ip in internal_ips:
+            try:
+                self.assertTrue(self._check_remote_connectivity(ssh_source,
+                                                                remote_ip),
+                                "Timed out waiting for %s to become "
+                                "reachable" % remote_ip)
+            except Exception:
+                LOG.exception("Unable to access {dest} via ssh to "
+                              "floating-ip {src}".format(dest=remote_ip,
+                                                         src=floating_ip))
+                debug.log_ip_ns()
+                raise
+
     @test.attr(type='smoke')
     @test.services('compute', 'network')
     def test_network_basic_ops(self):
+        """
+        For a freshly-booted VM with an IP address ("port") on a given
+            network:
+
+        - the Tempest host can ping the IP address.  This implies, but
+         does not guarantee (see the ssh check that follows), that the
+         VM has been assigned the correct IP address and has
+         connectivity to the Tempest host.
+
+        - the Tempest host can perform key-based authentication to an
+         ssh server hosted at the IP address.  This check guarantees
+         that the IP address is associated with the target VM.
+
+        - detach the floating-ip from the VM and verify that it becomes
+        unreachable
+
+        - associate detached floating ip to a new VM and verify connectivity.
+        VMs are created with unique keypair so connectivity also asserts that
+        floating IP is associated with the new VM instead of the old one
+
+        # TODO(mnewby) - Need to implement the following:
+        - the Tempest host can ssh into the VM via the IP address and
+         successfully execute the following:
+
+         - ping an external IP address, implying external connectivity.
+
+         - ping an external hostname, implying that dns is correctly
+           configured.
+
+         - ping an internal IP address, implying connectivity to another
+           VM on the same network.
+
+        """
         self._check_public_network_connectivity(should_connect=True)
         self._disassociate_floating_ips()
         self._check_public_network_connectivity(should_connect=False,
@@ -262,3 +351,20 @@
         self._check_public_network_connectivity(should_connect=True,
                                                 msg="after re-associate "
                                                     "floating ip")
+
+    @test.attr(type='smoke')
+    @test.services('compute', 'network')
+    def test_hotplug_nic(self):
+        """
+        1. create a new network, with no gateway (to prevent overwriting VM's
+            gateway)
+        2. connect VM to new network
+        3. set static ip and bring new nic up
+        4. check VM can ping new network dhcp port
+
+        """
+
+        self._check_public_network_connectivity(should_connect=True)
+        self._create_new_network()
+        self._hotplug_server()
+        self._check_network_internal_connectivity()
diff --git a/tempest/scenario/test_security_groups_basic_ops.py b/tempest/scenario/test_security_groups_basic_ops.py
index a26e0cf..d404dd1 100644
--- a/tempest/scenario/test_security_groups_basic_ops.py
+++ b/tempest/scenario/test_security_groups_basic_ops.py
@@ -17,7 +17,6 @@
 from tempest.common import debug
 from tempest.common.utils import data_utils
 from tempest import config
-from tempest import exceptions
 from tempest.openstack.common import log as logging
 from tempest.scenario import manager
 from tempest import test
@@ -332,28 +331,6 @@
                                                private_key=private_key)
         return access_point_ssh
 
-    def _test_remote_connectivity(self, source, dest, should_succeed=True):
-        """
-        check ping server via source ssh connection
-
-        :param source: RemoteClient: an ssh connection from which to ping
-        :param dest: and IP to ping against
-        :param should_succeed: boolean should ping succeed or not
-        :returns: boolean -- should_succeed == ping
-        :returns: ping is false if ping failed
-        """
-        def ping_remote():
-            try:
-                source.ping_host(dest)
-            except exceptions.SSHExecCommandFailed as ex:
-                LOG.debug(ex)
-                return not should_succeed
-            return should_succeed
-
-        return test.call_until_true(ping_remote,
-                                    CONF.compute.ping_timeout,
-                                    1)
-
     def _check_connectivity(self, access_point, ip, should_succeed=True):
         if should_succeed:
             msg = "Timed out waiting for %s to become reachable" % ip
@@ -362,8 +339,8 @@
             return True
             msg = "%s is reachable" % ip
         try:
-            self.assertTrue(self._test_remote_connectivity(access_point, ip,
-                                                           should_succeed),
+            self.assertTrue(self._check_remote_connectivity(access_point, ip,
+                                                            should_succeed),
                             msg)
         except Exception:
             debug.log_ip_ns()
diff --git a/tempest/services/compute/json/aggregates_client.py b/tempest/services/compute/json/aggregates_client.py
index e26f570..700a29b 100644
--- a/tempest/services/compute/json/aggregates_client.py
+++ b/tempest/services/compute/json/aggregates_client.py
@@ -15,14 +15,14 @@
 
 import json
 
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
 from tempest import config
 from tempest import exceptions
 
 CONF = config.CONF
 
 
-class AggregatesClientJSON(RestClient):
+class AggregatesClientJSON(rest_client.RestClient):
 
     def __init__(self, auth_provider):
         super(AggregatesClientJSON, self).__init__(auth_provider)
diff --git a/tempest/services/compute/json/availability_zone_client.py b/tempest/services/compute/json/availability_zone_client.py
index ea4e95e..9278d5b 100644
--- a/tempest/services/compute/json/availability_zone_client.py
+++ b/tempest/services/compute/json/availability_zone_client.py
@@ -15,13 +15,13 @@
 
 import json
 
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
 from tempest import config
 
 CONF = config.CONF
 
 
-class AvailabilityZoneClientJSON(RestClient):
+class AvailabilityZoneClientJSON(rest_client.RestClient):
 
     def __init__(self, auth_provider):
         super(AvailabilityZoneClientJSON, self).__init__(
diff --git a/tempest/services/compute/json/certificates_client.py b/tempest/services/compute/json/certificates_client.py
index de0f1a8..c05e352 100644
--- a/tempest/services/compute/json/certificates_client.py
+++ b/tempest/services/compute/json/certificates_client.py
@@ -15,13 +15,13 @@
 
 import json
 
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
 from tempest import config
 
 CONF = config.CONF
 
 
-class CertificatesClientJSON(RestClient):
+class CertificatesClientJSON(rest_client.RestClient):
 
     def __init__(self, auth_provider):
         super(CertificatesClientJSON, self).__init__(auth_provider)
diff --git a/tempest/services/compute/json/extensions_client.py b/tempest/services/compute/json/extensions_client.py
index f7e2737..5ad8b98 100644
--- a/tempest/services/compute/json/extensions_client.py
+++ b/tempest/services/compute/json/extensions_client.py
@@ -15,13 +15,13 @@
 
 import json
 
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
 from tempest import config
 
 CONF = config.CONF
 
 
-class ExtensionsClientJSON(RestClient):
+class ExtensionsClientJSON(rest_client.RestClient):
 
     def __init__(self, auth_provider):
         super(ExtensionsClientJSON, self).__init__(auth_provider)
diff --git a/tempest/services/compute/json/fixed_ips_client.py b/tempest/services/compute/json/fixed_ips_client.py
index af750a3..8b2c6c9 100644
--- a/tempest/services/compute/json/fixed_ips_client.py
+++ b/tempest/services/compute/json/fixed_ips_client.py
@@ -15,13 +15,13 @@
 
 import json
 
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
 from tempest import config
 
 CONF = config.CONF
 
 
-class FixedIPsClientJSON(RestClient):
+class FixedIPsClientJSON(rest_client.RestClient):
 
     def __init__(self, auth_provider):
         super(FixedIPsClientJSON, self).__init__(auth_provider)
diff --git a/tempest/services/compute/json/flavors_client.py b/tempest/services/compute/json/flavors_client.py
index 289b09e..a8111af 100644
--- a/tempest/services/compute/json/flavors_client.py
+++ b/tempest/services/compute/json/flavors_client.py
@@ -16,13 +16,13 @@
 import json
 import urllib
 
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
 from tempest import config
 
 CONF = config.CONF
 
 
-class FlavorsClientJSON(RestClient):
+class FlavorsClientJSON(rest_client.RestClient):
 
     def __init__(self, auth_provider):
         super(FlavorsClientJSON, self).__init__(auth_provider)
diff --git a/tempest/services/compute/json/floating_ips_client.py b/tempest/services/compute/json/floating_ips_client.py
index 0385160..42487c3 100644
--- a/tempest/services/compute/json/floating_ips_client.py
+++ b/tempest/services/compute/json/floating_ips_client.py
@@ -16,14 +16,14 @@
 import json
 import urllib
 
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
 from tempest import config
 from tempest import exceptions
 
 CONF = config.CONF
 
 
-class FloatingIPsClientJSON(RestClient):
+class FloatingIPsClientJSON(rest_client.RestClient):
     def __init__(self, auth_provider):
         super(FloatingIPsClientJSON, self).__init__(auth_provider)
         self.service = CONF.compute.catalog_type
diff --git a/tempest/services/compute/json/hosts_client.py b/tempest/services/compute/json/hosts_client.py
index d826a78..fb45997 100644
--- a/tempest/services/compute/json/hosts_client.py
+++ b/tempest/services/compute/json/hosts_client.py
@@ -15,13 +15,13 @@
 import json
 import urllib
 
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
 from tempest import config
 
 CONF = config.CONF
 
 
-class HostsClientJSON(RestClient):
+class HostsClientJSON(rest_client.RestClient):
 
     def __init__(self, auth_provider):
         super(HostsClientJSON, self).__init__(auth_provider)
diff --git a/tempest/services/compute/json/hypervisor_client.py b/tempest/services/compute/json/hypervisor_client.py
index 74844dc..c6b13b0 100644
--- a/tempest/services/compute/json/hypervisor_client.py
+++ b/tempest/services/compute/json/hypervisor_client.py
@@ -15,13 +15,13 @@
 
 import json
 
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
 from tempest import config
 
 CONF = config.CONF
 
 
-class HypervisorClientJSON(RestClient):
+class HypervisorClientJSON(rest_client.RestClient):
 
     def __init__(self, auth_provider):
         super(HypervisorClientJSON, self).__init__(auth_provider)
diff --git a/tempest/services/compute/json/images_client.py b/tempest/services/compute/json/images_client.py
index b3d8c35..5a79a29 100644
--- a/tempest/services/compute/json/images_client.py
+++ b/tempest/services/compute/json/images_client.py
@@ -16,7 +16,7 @@
 import json
 import urllib
 
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
 from tempest.common import waiters
 from tempest import config
 from tempest import exceptions
@@ -24,7 +24,7 @@
 CONF = config.CONF
 
 
-class ImagesClientJSON(RestClient):
+class ImagesClientJSON(rest_client.RestClient):
 
     def __init__(self, auth_provider):
         super(ImagesClientJSON, self).__init__(auth_provider)
diff --git a/tempest/services/compute/json/instance_usage_audit_log_client.py b/tempest/services/compute/json/instance_usage_audit_log_client.py
index 27930f2..1f6e988 100644
--- a/tempest/services/compute/json/instance_usage_audit_log_client.py
+++ b/tempest/services/compute/json/instance_usage_audit_log_client.py
@@ -15,13 +15,13 @@
 
 import json
 
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
 from tempest import config
 
 CONF = config.CONF
 
 
-class InstanceUsagesAuditLogClientJSON(RestClient):
+class InstanceUsagesAuditLogClientJSON(rest_client.RestClient):
 
     def __init__(self, auth_provider):
         super(InstanceUsagesAuditLogClientJSON, self).__init__(
diff --git a/tempest/services/compute/json/interfaces_client.py b/tempest/services/compute/json/interfaces_client.py
index de3aa19..9928b94 100644
--- a/tempest/services/compute/json/interfaces_client.py
+++ b/tempest/services/compute/json/interfaces_client.py
@@ -16,14 +16,14 @@
 import json
 import time
 
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
 from tempest import config
 from tempest import exceptions
 
 CONF = config.CONF
 
 
-class InterfacesClientJSON(RestClient):
+class InterfacesClientJSON(rest_client.RestClient):
 
     def __init__(self, auth_provider):
         super(InterfacesClientJSON, self).__init__(auth_provider)
diff --git a/tempest/services/compute/json/keypairs_client.py b/tempest/services/compute/json/keypairs_client.py
index 356c2e6..28f3c31 100644
--- a/tempest/services/compute/json/keypairs_client.py
+++ b/tempest/services/compute/json/keypairs_client.py
@@ -15,13 +15,13 @@
 
 import json
 
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
 from tempest import config
 
 CONF = config.CONF
 
 
-class KeyPairsClientJSON(RestClient):
+class KeyPairsClientJSON(rest_client.RestClient):
 
     def __init__(self, auth_provider):
         super(KeyPairsClientJSON, self).__init__(auth_provider)
diff --git a/tempest/services/compute/json/limits_client.py b/tempest/services/compute/json/limits_client.py
index 765ba79..1493718 100644
--- a/tempest/services/compute/json/limits_client.py
+++ b/tempest/services/compute/json/limits_client.py
@@ -15,13 +15,13 @@
 
 import json
 
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
 from tempest import config
 
 CONF = config.CONF
 
 
-class LimitsClientJSON(RestClient):
+class LimitsClientJSON(rest_client.RestClient):
 
     def __init__(self, auth_provider):
         super(LimitsClientJSON, self).__init__(auth_provider)
diff --git a/tempest/services/compute/json/quotas_client.py b/tempest/services/compute/json/quotas_client.py
index 7607cc0..459ab6d 100644
--- a/tempest/services/compute/json/quotas_client.py
+++ b/tempest/services/compute/json/quotas_client.py
@@ -15,13 +15,13 @@
 
 import json
 
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
 from tempest import config
 
 CONF = config.CONF
 
 
-class QuotasClientJSON(RestClient):
+class QuotasClientJSON(rest_client.RestClient):
 
     def __init__(self, auth_provider):
         super(QuotasClientJSON, self).__init__(auth_provider)
diff --git a/tempest/services/compute/json/security_groups_client.py b/tempest/services/compute/json/security_groups_client.py
index 2cd2d2e..899d4ef 100644
--- a/tempest/services/compute/json/security_groups_client.py
+++ b/tempest/services/compute/json/security_groups_client.py
@@ -16,14 +16,14 @@
 import json
 import urllib
 
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
 from tempest import config
 from tempest import exceptions
 
 CONF = config.CONF
 
 
-class SecurityGroupsClientJSON(RestClient):
+class SecurityGroupsClientJSON(rest_client.RestClient):
 
     def __init__(self, auth_provider):
         super(SecurityGroupsClientJSON, self).__init__(auth_provider)
diff --git a/tempest/services/compute/json/servers_client.py b/tempest/services/compute/json/servers_client.py
index deb78ee..623bf42 100644
--- a/tempest/services/compute/json/servers_client.py
+++ b/tempest/services/compute/json/servers_client.py
@@ -18,7 +18,7 @@
 import time
 import urllib
 
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
 from tempest.common import waiters
 from tempest import config
 from tempest import exceptions
@@ -26,7 +26,7 @@
 CONF = config.CONF
 
 
-class ServersClientJSON(RestClient):
+class ServersClientJSON(rest_client.RestClient):
 
     def __init__(self, auth_provider):
         super(ServersClientJSON, self).__init__(auth_provider)
diff --git a/tempest/services/compute/json/services_client.py b/tempest/services/compute/json/services_client.py
index 8380dc2..1ab25ec 100644
--- a/tempest/services/compute/json/services_client.py
+++ b/tempest/services/compute/json/services_client.py
@@ -17,13 +17,13 @@
 import json
 import urllib
 
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
 from tempest import config
 
 CONF = config.CONF
 
 
-class ServicesClientJSON(RestClient):
+class ServicesClientJSON(rest_client.RestClient):
 
     def __init__(self, auth_provider):
         super(ServicesClientJSON, self).__init__(auth_provider)
diff --git a/tempest/services/compute/json/tenant_usages_client.py b/tempest/services/compute/json/tenant_usages_client.py
index b14fa9b..f3a67dd 100644
--- a/tempest/services/compute/json/tenant_usages_client.py
+++ b/tempest/services/compute/json/tenant_usages_client.py
@@ -16,13 +16,13 @@
 import json
 import urllib
 
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
 from tempest import config
 
 CONF = config.CONF
 
 
-class TenantUsagesClientJSON(RestClient):
+class TenantUsagesClientJSON(rest_client.RestClient):
 
     def __init__(self, auth_provider):
         super(TenantUsagesClientJSON, self).__init__(auth_provider)
diff --git a/tempest/services/compute/json/volumes_extensions_client.py b/tempest/services/compute/json/volumes_extensions_client.py
index 4b9dc0b..5ef11ed 100644
--- a/tempest/services/compute/json/volumes_extensions_client.py
+++ b/tempest/services/compute/json/volumes_extensions_client.py
@@ -17,14 +17,14 @@
 import time
 import urllib
 
-from tempest.common.rest_client import RestClient
+from tempest.common import rest_client
 from tempest import config
 from tempest import exceptions
 
 CONF = config.CONF
 
 
-class VolumesExtensionsClientJSON(RestClient):
+class VolumesExtensionsClientJSON(rest_client.RestClient):
 
     def __init__(self, auth_provider):
         super(VolumesExtensionsClientJSON, self).__init__(
diff --git a/tempest/services/compute/xml/common.py b/tempest/services/compute/xml/common.py
index 4def19f..b29b932 100644
--- a/tempest/services/compute/xml/common.py
+++ b/tempest/services/compute/xml/common.py
@@ -18,6 +18,11 @@
 XMLNS_11 = "http://docs.openstack.org/compute/api/v1.1"
 XMLNS_V3 = "http://docs.openstack.org/compute/api/v1.1"
 
+NEUTRON_NAMESPACES = {
+    'router': "http://docs.openstack.org/ext/neutron/router/api/v1.0",
+    'provider': 'http://docs.openstack.org/ext/provider/api/v1.0',
+}
+
 
 # NOTE(danms): This is just a silly implementation to help make generating
 # XML faster for prototyping. Could be replaced with proper etree gorp
@@ -137,6 +142,9 @@
         tag = child.tag
         if tag.startswith("{"):
             ns, tag = tag.split("}", 1)
+            for key, uri in NEUTRON_NAMESPACES.iteritems():
+                if uri == ns[1:]:
+                    tag = key + ":" + tag
         if plurals is not None and tag in plurals:
                 json[tag] = parse_array(child, plurals)
         else:
diff --git a/tempest/services/network/xml/network_client.py b/tempest/services/network/xml/network_client.py
index c520018..8152d71 100644
--- a/tempest/services/network/xml/network_client.py
+++ b/tempest/services/network/xml/network_client.py
@@ -43,9 +43,14 @@
         post_body = common.Element(root)
         post_body.add_attr('xmlns:xsi',
                            'http://www.w3.org/2001/XMLSchema-instance')
+        elements = set()
         for name, attr in body[root].items():
             elt = self._get_element(name, attr)
             post_body.append(elt)
+            if ":" in name:
+                elements.add(name.split(":")[0])
+        if elements:
+            self._add_namespaces(post_body, elements)
         return str(common.Document(post_body))
 
     def serialize_list(self, body, root_name=None, item_name=None):
@@ -82,6 +87,11 @@
         else:
             return common.Element(name, value)
 
+    def _add_namespaces(self, root, elements):
+        for element in elements:
+            root.add_attr('xmlns:%s' % element,
+                          common.NEUTRON_NAMESPACES[element])
+
     def create_member(self, address, protocol_port, pool_id):
         uri = '%s/lb/members' % (self.uri_prefix)
         post_body = common.Element("member")
diff --git a/tempest/stress/driver.py b/tempest/stress/driver.py
index 3715636..9660081 100644
--- a/tempest/stress/driver.py
+++ b/tempest/stress/driver.py
@@ -17,6 +17,8 @@
 import signal
 import time
 
+from six import moves
+
 from tempest import clients
 from tempest.common import ssh
 from tempest.common.utils import data_utils
@@ -128,7 +130,7 @@
             manager = admin_manager
         else:
             manager = clients.Manager()
-        for p_number in xrange(test.get('threads', default_thread_num)):
+        for p_number in moves.xrange(test.get('threads', default_thread_num)):
             if test.get('use_isolated_tenants', False):
                 username = data_utils.rand_name("stress_user")
                 tenant_name = data_utils.rand_name("stress_tenant")
diff --git a/tempest/tests/fake_identity.py b/tempest/tests/fake_identity.py
index ea2bd44..058c9c2 100644
--- a/tempest/tests/fake_identity.py
+++ b/tempest/tests/fake_identity.py
@@ -25,16 +25,16 @@
 COMPUTE_ENDPOINTS_V2 = {
     "endpoints": [
         {
-            "adminURL": "http://fake_url/api/admin",
+            "adminURL": "http://fake_url/v2/first_endpoint/admin",
             "region": "NoMatchRegion",
-            "internalURL": "http://fake_url/api/internal",
-            "publicURL": "http://fake_url/api/public"
+            "internalURL": "http://fake_url/v2/first_endpoint/internal",
+            "publicURL": "http://fake_url/v2/first_endpoint/public"
         },
         {
-            "adminURL": "http://fake_url/api/admin",
+            "adminURL": "http://fake_url/v2/second_endpoint/admin",
             "region": "FakeRegion",
-            "internalURL": "http://fake_url/api/internal",
-            "publicURL": "http://fake_url/api/public"
+            "internalURL": "http://fake_url/v2/second_endpoint/internal",
+            "publicURL": "http://fake_url/v2/second_endpoint/public"
         },
     ],
     "type": "compute",
@@ -79,17 +79,24 @@
 COMPUTE_ENDPOINTS_V3 = {
     "endpoints": [
         {
-            "id": "fake_service",
+            "id": "first_compute_fake_service",
             "interface": "public",
             "region": "NoMatchRegion",
-            "url": "http://fake_url/v3"
+            "url": "http://fake_url/v3/first_endpoint/api"
         },
         {
-            "id": "another_fake_service",
+            "id": "second_fake_service",
             "interface": "public",
             "region": "FakeRegion",
-            "url": "http://fake_url/v3"
+            "url": "http://fake_url/v3/second_endpoint/api"
+        },
+        {
+            "id": "third_fake_service",
+            "interface": "admin",
+            "region": "MiddleEarthRegion",
+            "url": "http://fake_url/v3/third_endpoint/api"
         }
+
     ],
     "type": "compute",
     "id": "fake_compute_endpoint"
diff --git a/tempest/tests/test_auth.py b/tempest/tests/test_auth.py
index 5346052..df04d65 100644
--- a/tempest/tests/test_auth.py
+++ b/tempest/tests/test_auth.py
@@ -100,6 +100,7 @@
 
 
 class TestKeystoneV2AuthProvider(BaseAuthTestsSetUp):
+    _endpoints = fake_identity.IDENTITY_V2_RESPONSE['access']['serviceCatalog']
     _auth_provider_class = auth.KeystoneV2AuthProvider
 
     def setUp(self):
@@ -111,41 +112,71 @@
     def _get_fake_alt_identity(self):
         return fake_identity.ALT_IDENTITY_V2_RESPONSE['access']
 
-    def _get_result_url_from_fake_identity(self):
-        return fake_identity.COMPUTE_ENDPOINTS_V2['endpoints'][1]['publicURL']
+    def _get_result_url_from_endpoint(self, ep, endpoint_type='publicURL',
+                                      replacement=None):
+        if replacement:
+            return ep[endpoint_type].replace('v2', replacement)
+        return ep[endpoint_type]
 
     def _get_token_from_fake_identity(self):
         return fake_identity.TOKEN
 
-    def _test_request_helper(self):
+    def _test_request_helper(self, filters, expected):
+        url, headers, body = self.auth_provider.auth_request('GET',
+                                                             self.target_url,
+                                                             filters=filters)
+
+        self.assertEqual(expected['url'], url)
+        self.assertEqual(expected['token'], headers['X-Auth-Token'])
+        self.assertEqual(expected['body'], body)
+
+    def test_request(self):
+        filters = {
+            'service': 'compute',
+            'endpoint_type': 'publicURL',
+            'region': 'FakeRegion'
+        }
+
+        url = self._get_result_url_from_endpoint(
+            self._endpoints[0]['endpoints'][1]) + '/' + self.target_url
+
+        expected = {
+            'body': None,
+            'url': url,
+            'token': self._get_token_from_fake_identity(),
+        }
+        self._test_request_helper(filters, expected)
+
+    def test_request_with_alt_auth_cleans_alt(self):
+        self.auth_provider.set_alt_auth_data(
+            'body',
+            (fake_identity.ALT_TOKEN, self._get_fake_alt_identity()))
+        self.test_request()
+        # Assert alt auth data is clear after it
+        self.assertIsNone(self.auth_provider.alt_part)
+        self.assertIsNone(self.auth_provider.alt_auth_data)
+
+    def test_request_with_alt_part_without_alt_data(self):
+        """
+        Assert that when alt_part is defined, the corresponding original
+        request element is kept the same.
+        """
         filters = {
             'service': 'compute',
             'endpoint_type': 'publicURL',
             'region': 'fakeRegion'
         }
+        self.auth_provider.set_alt_auth_data('url', None)
 
         url, headers, body = self.auth_provider.auth_request('GET',
                                                              self.target_url,
                                                              filters=filters)
 
-        result_url = self._get_result_url_from_fake_identity()
-        self.assertEqual(url, result_url + '/' + self.target_url)
+        self.assertEqual(url, self.target_url)
         self.assertEqual(self._get_token_from_fake_identity(),
                          headers['X-Auth-Token'])
         self.assertEqual(body, None)
 
-    def test_request(self):
-        self._test_request_helper()
-
-    def test_request_with_alt_auth(self):
-        self.auth_provider.set_alt_auth_data(
-            'body',
-            (fake_identity.ALT_TOKEN, self._get_fake_alt_identity()))
-        self._test_request_helper()
-        # Assert alt auth data is clear after it
-        self.assertIsNone(self.auth_provider.alt_part)
-        self.assertIsNone(self.auth_provider.alt_auth_data)
-
     def test_request_with_bad_service(self):
         filters = {
             'service': 'BAD_SERVICE',
@@ -154,7 +185,7 @@
         }
         self.assertRaises(exceptions.EndpointNotFound,
                           self.auth_provider.auth_request, 'GET',
-                          'http://fakeurl.com/fake_api', filters=filters)
+                          self.target_url, filters=filters)
 
     def test_request_without_service(self):
         filters = {
@@ -164,7 +195,7 @@
         }
         self.assertRaises(exceptions.EndpointNotFound,
                           self.auth_provider.auth_request, 'GET',
-                          'http://fakeurl.com/fake_api', filters=filters)
+                          self.target_url, filters=filters)
 
     def test_check_credentials_missing_attribute(self):
         for attr in ['username', 'password']:
@@ -183,8 +214,86 @@
         del cred['tenant_name']
         self.assertFalse(self.auth_provider.check_credentials(cred))
 
+    def _test_base_url_helper(self, expected_url, filters,
+                              auth_data=None):
+
+        url = self.auth_provider.base_url(filters, auth_data)
+        self.assertEqual(url, expected_url)
+
+    def test_base_url(self):
+        self.filters = {
+            'service': 'compute',
+            'endpoint_type': 'publicURL',
+            'region': 'FakeRegion'
+        }
+        expected = self._get_result_url_from_endpoint(
+            self._endpoints[0]['endpoints'][1])
+        self._test_base_url_helper(expected, self.filters)
+
+    def test_base_url_to_get_admin_endpoint(self):
+        self.filters = {
+            'service': 'compute',
+            'endpoint_type': 'adminURL',
+            'region': 'FakeRegion'
+        }
+        expected = self._get_result_url_from_endpoint(
+            self._endpoints[0]['endpoints'][1], endpoint_type='adminURL')
+        self._test_base_url_helper(expected, self.filters)
+
+    def test_base_url_unknown_region(self):
+        """
+        Assure that if the region is unknow the first endpoint is returned.
+        """
+        self.filters = {
+            'service': 'compute',
+            'endpoint_type': 'publicURL',
+            'region': 'AintNoBodyKnowThisRegion'
+        }
+        expected = self._get_result_url_from_endpoint(
+            self._endpoints[0]['endpoints'][0])
+        self._test_base_url_helper(expected, self.filters)
+
+    def test_base_url_with_non_existent_service(self):
+        self.filters = {
+            'service': 'BAD_SERVICE',
+            'endpoint_type': 'publicURL',
+            'region': 'FakeRegion'
+        }
+        self.assertRaises(exceptions.EndpointNotFound,
+                          self._test_base_url_helper, None, self.filters)
+
+    def test_base_url_without_service(self):
+        self.filters = {
+            'endpoint_type': 'publicURL',
+            'region': 'FakeRegion'
+        }
+        self.assertRaises(exceptions.EndpointNotFound,
+                          self._test_base_url_helper, None, self.filters)
+
+    def test_base_url_with_api_version_filter(self):
+        self.filters = {
+            'service': 'compute',
+            'endpoint_type': 'publicURL',
+            'region': 'FakeRegion',
+            'api_version': 'v12'
+        }
+        expected = self._get_result_url_from_endpoint(
+            self._endpoints[0]['endpoints'][1], replacement='v12')
+        self._test_base_url_helper(expected, self.filters)
+
+    def test_base_url_with_skip_path_filter(self):
+        self.filters = {
+            'service': 'compute',
+            'endpoint_type': 'publicURL',
+            'region': 'FakeRegion',
+            'skip_path': True
+        }
+        expected = 'http://fake_url/'
+        self._test_base_url_helper(expected, self.filters)
+
 
 class TestKeystoneV3AuthProvider(TestKeystoneV2AuthProvider):
+    _endpoints = fake_identity.IDENTITY_V3_RESPONSE['token']['catalog']
     _auth_provider_class = auth.KeystoneV3AuthProvider
     credentials = {
         'username': 'fake_user',
@@ -201,10 +310,23 @@
     def _get_fake_alt_identity(self):
         return fake_identity.ALT_IDENTITY_V3['token']
 
-    def _get_result_url_from_fake_identity(self):
-        return fake_identity.COMPUTE_ENDPOINTS_V3['endpoints'][1]['url']
+    def _get_result_url_from_endpoint(self, ep, replacement=None):
+        if replacement:
+            return ep['url'].replace('v3', replacement)
+        return ep['url']
 
     def test_check_credentials_missing_tenant_name(self):
         cred = copy.copy(self.credentials)
         del cred['domain_name']
         self.assertFalse(self.auth_provider.check_credentials(cred))
+
+    # Overwrites v2 test
+    def test_base_url_to_get_admin_endpoint(self):
+        self.filters = {
+            'service': 'compute',
+            'endpoint_type': 'admin',
+            'region': 'MiddleEarthRegion'
+        }
+        expected = self._get_result_url_from_endpoint(
+            self._endpoints[0]['endpoints'][2])
+        self._test_base_url_helper(expected, self.filters)
diff --git a/tempest/thirdparty/boto/test.py b/tempest/thirdparty/boto/test.py
index 6a9836b..10d421e 100644
--- a/tempest/thirdparty/boto/test.py
+++ b/tempest/thirdparty/boto/test.py
@@ -17,6 +17,7 @@
 import logging as orig_logging
 import os
 import re
+import six
 import urlparse
 
 import boto
@@ -134,7 +135,7 @@
         The not leaf elements does wildcard match
     """
     # in error_code just literal and '.' characters expected
-    if not isinstance(error_data, basestring):
+    if not isinstance(error_data, six.string_types):
         (error_code, status_code) = map(str, error_data)
     else:
         status_code = None
@@ -144,7 +145,7 @@
     num_parts = len(parts)
     max_index = num_parts - 1
     add_cls = error_cls
-    for i_part in xrange(num_parts):
+    for i_part in six.moves.xrange(num_parts):
         part = parts[i_part]
         leaf = i_part == max_index
         if not leaf: