Merge "Make BaseV2MemeberImageTest inherits from BaseV2ImageTest"
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index 7c604be..b216c5c 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -427,7 +427,7 @@
 # (string value)
 #alt_password=<None>
 
-# Administrative Username to use forKeystone API requests.
+# Administrative Username to use for Keystone API requests.
 # (string value)
 #admin_username=admin
 
diff --git a/run_tests.sh b/run_tests.sh
index 285b372..3f00453 100755
--- a/run_tests.sh
+++ b/run_tests.sh
@@ -126,7 +126,7 @@
     exit
 fi
 
-if [$coverage -eq 1] ; then
+if [ $coverage -eq 1 ]; then
     $testrargs = "--coverage $testrargs"
 fi
 
diff --git a/tempest/api/compute/admin/test_hosts_negative.py b/tempest/api/compute/admin/test_hosts_negative.py
index dbf7967..a1afe0e 100644
--- a/tempest/api/compute/admin/test_hosts_negative.py
+++ b/tempest/api/compute/admin/test_hosts_negative.py
@@ -66,7 +66,9 @@
 
         self.assertRaises(exceptions.Unauthorized,
                           self.non_admin_client.update_host,
-                          hostname)
+                          hostname,
+                          status='enable',
+                          maintenance_mode='enable')
 
     @test.skip_because(bug="1261964", interface="xml")
     @test.attr(type=['negative', 'gate'])
diff --git a/tempest/api/compute/v3/admin/test_hosts_negative.py b/tempest/api/compute/v3/admin/test_hosts_negative.py
index 755fa2b..598a1d3 100644
--- a/tempest/api/compute/v3/admin/test_hosts_negative.py
+++ b/tempest/api/compute/v3/admin/test_hosts_negative.py
@@ -66,7 +66,9 @@
 
         self.assertRaises(exceptions.Unauthorized,
                           self.non_admin_client.update_host,
-                          hostname)
+                          hostname,
+                          status='enable',
+                          maintenance_mode='enable')
 
     @test.attr(type=['negative', 'gate'])
     def test_update_host_with_extra_param(self):
diff --git a/tempest/api/image/base.py b/tempest/api/image/base.py
index 1e6d63b..b521bce 100644
--- a/tempest/api/image/base.py
+++ b/tempest/api/image/base.py
@@ -34,7 +34,8 @@
         super(BaseImageTest, cls).setUpClass()
         cls.created_images = []
         cls._interface = 'json'
-        cls.isolated_creds = isolated_creds.IsolatedCreds(cls.__name__)
+        cls.isolated_creds = isolated_creds.IsolatedCreds(
+            cls.__name__, network_resources=cls.network_resources)
         if not cls.config.service_available.glance:
             skip_msg = ("%s skipped as glance is not available" % cls.__name__)
             raise cls.skipException(skip_msg)
diff --git a/tempest/api/network/test_security_groups.py b/tempest/api/network/test_security_groups.py
index 9b0a3de..37b1f2c 100644
--- a/tempest/api/network/test_security_groups.py
+++ b/tempest/api/network/test_security_groups.py
@@ -82,6 +82,36 @@
                      for rule in rule_list_body['security_group_rules']]
         self.assertIn(rule_create_body['security_group_rule']['id'], rule_list)
 
+    @attr(type='smoke')
+    def test_create_security_group_rule_with_additional_args(self):
+        # Verify creating security group rule with the following
+        # arguments works: "protocol": "tcp", "port_range_max": 77,
+        # "port_range_min": 77, "direction":"ingress".
+        group_create_body, _ = self._create_security_group()
+
+        direction = 'ingress'
+        protocol = 'tcp'
+        port_range_min = 77
+        port_range_max = 77
+        resp, rule_create_body = self.client.create_security_group_rule(
+            group_create_body['security_group']['id'],
+            direction=direction,
+            protocol=protocol,
+            port_range_min=port_range_min,
+            port_range_max=port_range_max
+        )
+
+        self.assertEqual('201', resp['status'])
+        sec_group_rule = rule_create_body['security_group_rule']
+        self.addCleanup(self._delete_security_group_rule,
+                        sec_group_rule['id']
+                        )
+
+        self.assertEqual(sec_group_rule['direction'], direction)
+        self.assertEqual(sec_group_rule['protocol'], protocol)
+        self.assertEqual(int(sec_group_rule['port_range_min']), port_range_min)
+        self.assertEqual(int(sec_group_rule['port_range_max']), port_range_max)
+
 
 class SecGroupTestXML(SecGroupTest):
     _interface = 'xml'
diff --git a/tempest/api/object_storage/base.py b/tempest/api/object_storage/base.py
index 47d8cca..b4928dd 100644
--- a/tempest/api/object_storage/base.py
+++ b/tempest/api/object_storage/base.py
@@ -32,7 +32,8 @@
         if not cls.config.service_available.swift:
             skip_msg = ("%s skipped as swift is not available" % cls.__name__)
             raise cls.skipException(skip_msg)
-        cls.isolated_creds = isolated_creds.IsolatedCreds(cls.__name__)
+        cls.isolated_creds = isolated_creds.IsolatedCreds(
+            cls.__name__, network_resources=cls.network_resources)
         if cls.config.compute.allow_tenant_isolation:
             # Get isolated creds for normal user
             creds = cls.isolated_creds.get_primary_creds()
diff --git a/tempest/common/isolated_creds.py b/tempest/common/isolated_creds.py
index da60318..9c0d7f6 100644
--- a/tempest/common/isolated_creds.py
+++ b/tempest/common/isolated_creds.py
@@ -32,7 +32,8 @@
 class IsolatedCreds(object):
 
     def __init__(self, name, tempest_client=True, interface='json',
-                 password='pass'):
+                 password='pass', network_resources=None):
+        self.network_resources = network_resources
         self.isolated_creds = {}
         self.isolated_net_resources = {}
         self.ports = []
@@ -198,15 +199,33 @@
         network = None
         subnet = None
         router = None
+        # Make sure settings
+        if self.network_resources:
+            if self.network_resources['router']:
+                if (not self.network_resources['subnet'] or
+                    not self.network_resources['network']):
+                    raise exceptions.InvalidConfiguration(
+                        'A router requires a subnet and network')
+            elif self.network_resources['subnet']:
+                if not self.network_resources['network']:
+                    raise exceptions.InvalidConfiguration(
+                        'A subnet requires a network')
+            elif self.network_resources['dhcp']:
+                raise exceptions.InvalidConfiguration('DHCP requires a subnet')
+
         data_utils.rand_name_root = data_utils.rand_name(self.name)
-        network_name = data_utils.rand_name_root + "-network"
-        network = self._create_network(network_name, tenant_id)
+        if not self.network_resources or self.network_resources['network']:
+            network_name = data_utils.rand_name_root + "-network"
+            network = self._create_network(network_name, tenant_id)
         try:
-            subnet_name = data_utils.rand_name_root + "-subnet"
-            subnet = self._create_subnet(subnet_name, tenant_id, network['id'])
-            router_name = data_utils.rand_name_root + "-router"
-            router = self._create_router(router_name, tenant_id)
-            self._add_router_interface(router['id'], subnet['id'])
+            if not self.network_resources or self.network_resources['subnet']:
+                subnet_name = data_utils.rand_name_root + "-subnet"
+                subnet = self._create_subnet(subnet_name, tenant_id,
+                                             network['id'])
+            if not self.network_resources or self.network_resources['router']:
+                router_name = data_utils.rand_name_root + "-router"
+                router = self._create_router(router_name, tenant_id)
+                self._add_router_interface(router['id'], subnet['id'])
         except Exception:
             if router:
                 self._clear_isolated_router(router['id'], router['name'])
@@ -230,14 +249,25 @@
         if not self.tempest_client:
             body = {'subnet': {'name': subnet_name, 'tenant_id': tenant_id,
                                'network_id': network_id, 'ip_version': 4}}
+            if self.network_resources:
+                body['enable_dhcp'] = self.network_resources['dhcp']
         base_cidr = netaddr.IPNetwork(CONF.network.tenant_network_cidr)
         mask_bits = CONF.network.tenant_network_mask_bits
         for subnet_cidr in base_cidr.subnet(mask_bits):
             try:
                 if self.tempest_client:
-                    resp, resp_body = self.network_admin_client.create_subnet(
-                        network_id, str(subnet_cidr), name=subnet_name,
-                        tenant_id=tenant_id)
+                    if self.network_resources:
+                        resp, resp_body = self.network_admin_client.\
+                            create_subnet(
+                                network_id, str(subnet_cidr),
+                                name=subnet_name,
+                                tenant_id=tenant_id,
+                                enable_dhcp=self.network_resources['dhcp'])
+                    else:
+                        resp, resp_body = self.network_admin_client.\
+                            create_subnet(network_id, str(subnet_cidr),
+                                          name=subnet_name,
+                                          tenant_id=tenant_id)
                 else:
                     body['subnet']['cidr'] = str(subnet_cidr)
                     resp_body = self.network_admin_client.create_subnet(body)
@@ -431,26 +461,27 @@
         net_client = self.network_admin_client
         for cred in self.isolated_net_resources:
             network, subnet, router = self.isolated_net_resources.get(cred)
-            try:
-                if self.tempest_client:
-                    net_client.remove_router_interface_with_subnet_id(
-                        router['id'], subnet['id'])
-                else:
-                    body = {'subnet_id': subnet['id']}
-                    net_client.remove_interface_router(router['id'], body)
-            except exceptions.NotFound:
-                LOG.warn('router with name: %s not found for delete' %
-                         router['name'])
-                pass
-            self._clear_isolated_router(router['id'], router['name'])
-            # TODO(mlavalle) This method call will be removed once patch
-            # https://review.openstack.org/#/c/46563/ merges in Neutron
-            self._cleanup_ports(network['id'])
-            self._clear_isolated_subnet(subnet['id'], subnet['name'])
-            self._clear_isolated_network(network['id'], network['name'])
-            LOG.info("Cleared isolated network resources: \n"
-                     + " network: %s, subnet: %s, router: %s"
-                     % (network['name'], subnet['name'], router['name']))
+            if self.network_resources.get('router'):
+                try:
+                    if self.tempest_client:
+                        net_client.remove_router_interface_with_subnet_id(
+                            router['id'], subnet['id'])
+                    else:
+                        body = {'subnet_id': subnet['id']}
+                        net_client.remove_interface_router(router['id'], body)
+                except exceptions.NotFound:
+                    LOG.warn('router with name: %s not found for delete' %
+                             router['name'])
+                    pass
+                self._clear_isolated_router(router['id'], router['name'])
+            if self.network_resources.get('network'):
+                # TODO(mlavalle) This method call will be removed once patch
+                # https://review.openstack.org/#/c/46563/ merges in Neutron
+                self._cleanup_ports(network['id'])
+            if self.network_resources.get('subnet'):
+                self._clear_isolated_subnet(subnet['id'], subnet['name'])
+            if self.network_resources.get('network'):
+                self._clear_isolated_network(network['id'], network['name'])
 
     def clear_isolated_creds(self):
         if not self.isolated_creds:
diff --git a/tempest/config.py b/tempest/config.py
index 0342380..c346aef 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -78,7 +78,7 @@
                secret=True),
     cfg.StrOpt('admin_username',
                default='admin',
-               help="Administrative Username to use for"
+               help="Administrative Username to use for "
                     "Keystone API requests."),
     cfg.StrOpt('admin_tenant_name',
                default='admin',
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 409fcc2..ecb55f9 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -235,7 +235,8 @@
     def setUpClass(cls):
         super(OfficialClientTest, cls).setUpClass()
         cls.isolated_creds = isolated_creds.IsolatedCreds(
-            __name__, tempest_client=False)
+            __name__, tempest_client=False,
+            network_resources=cls.network_resources)
 
         username, password, tenant_name = cls.credentials()
 
@@ -527,6 +528,13 @@
             private_key = self.keypair.private_key
         return RemoteClient(ip, username, pkey=private_key)
 
+    def _log_console_output(self, servers=None):
+        if not servers:
+            servers = self.compute_client.servers.list()
+        for server in servers:
+            LOG.debug('Console output for %s', server.id)
+            LOG.debug(server.get_console_output())
+
 
 class NetworkScenarioTest(OfficialClientTest):
     """
diff --git a/tempest/scenario/test_aggregates_basic_ops.py b/tempest/scenario/test_aggregates_basic_ops.py
new file mode 100644
index 0000000..3ae9567
--- /dev/null
+++ b/tempest/scenario/test_aggregates_basic_ops.py
@@ -0,0 +1,133 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 IBM Corp.
+# 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.common import tempest_fixtures as fixtures
+from tempest.common.utils.data_utils import rand_name
+from tempest.openstack.common import log as logging
+from tempest.scenario import manager
+from tempest import test
+
+
+LOG = logging.getLogger(__name__)
+
+
+class TestAggregatesBasicOps(manager.OfficialClientTest):
+    """
+    Creates an aggregate within an availability zone
+    Adds a host to the aggregate
+    Checks aggregate details
+    Updates aggregate's name
+    Removes host from aggregate
+    Deletes aggregate
+    """
+    @classmethod
+    def credentials(cls):
+        return cls.admin_credentials()
+
+    def _create_aggregate(self, aggregate_name, availability_zone=None):
+        aggregate = self.compute_client.aggregates.create(aggregate_name,
+                                                          availability_zone)
+        self.assertEqual(aggregate.name, aggregate_name)
+        self.assertEqual(aggregate.availability_zone, availability_zone)
+        self.set_resource(aggregate.id, aggregate)
+        LOG.debug("Aggregate %s created." % (aggregate.name))
+        return aggregate
+
+    def _delete_aggregate(self, aggregate):
+        self.compute_client.aggregates.delete(aggregate.id)
+        self.remove_resource(aggregate.id)
+        LOG.debug("Aggregate %s deleted. " % (aggregate.name))
+
+    def _get_host_name(self):
+        hosts = self.compute_client.hosts.list()
+        self.assertTrue(len(hosts) >= 1)
+        hostname = hosts[0].host_name
+        return hostname
+
+    def _add_host(self, aggregate_name, host):
+        aggregate = self.compute_client.aggregates.add_host(aggregate_name,
+                                                            host)
+        self.assertIn(host, aggregate.hosts)
+        LOG.debug("Host %s added to Aggregate %s." % (host, aggregate.name))
+
+    def _remove_host(self, aggregate_name, host):
+        aggregate = self.compute_client.aggregates.remove_host(aggregate_name,
+                                                               host)
+        self.assertNotIn(host, aggregate.hosts)
+        LOG.debug("Host %s removed to Aggregate %s." % (host, aggregate.name))
+
+    def _check_aggregate_details(self, aggregate, aggregate_name, azone,
+                                 hosts, metadata):
+        aggregate = self.compute_client.aggregates.get(aggregate.id)
+        self.assertEqual(aggregate_name, aggregate.name)
+        self.assertEqual(azone, aggregate.availability_zone)
+        self.assertEqual(aggregate.hosts, hosts)
+        for meta_key in metadata.keys():
+            self.assertIn(meta_key, aggregate.metadata)
+            self.assertEqual(metadata[meta_key], aggregate.metadata[meta_key])
+        LOG.debug("Aggregate %s details match." % aggregate.name)
+
+    def _set_aggregate_metadata(self, aggregate, meta):
+        aggregate = self.compute_client.aggregates.set_metadata(aggregate.id,
+                                                                meta)
+
+        for key, value in meta.items():
+            self.assertEqual(meta[key], aggregate.metadata[key])
+        LOG.debug("Aggregate %s metadata updated successfully." %
+                  aggregate.name)
+
+    def _update_aggregate(self, aggregate, aggregate_name,
+                          availability_zone):
+        values = {}
+        if aggregate_name:
+            values.update({'name': aggregate_name})
+        if availability_zone:
+            values.update({'availability_zone': availability_zone})
+        if values.keys():
+            aggregate = self.compute_client.aggregates.update(aggregate.id,
+                                                              values)
+            for key, values in values.items():
+                self.assertEqual(getattr(aggregate, key), values)
+        return aggregate
+
+    @test.services('compute')
+    def test_aggregate_basic_ops(self):
+        self.useFixture(fixtures.LockFixture('availability_zone'))
+        az = 'foo_zone'
+        aggregate_name = rand_name('aggregate-scenario')
+        aggregate = self._create_aggregate(aggregate_name, az)
+
+        metadata = {'meta_key': 'meta_value'}
+        self._set_aggregate_metadata(aggregate, metadata)
+
+        host = self._get_host_name()
+        self._add_host(aggregate, host)
+        self._check_aggregate_details(aggregate, aggregate_name, az, [host],
+                                      metadata)
+
+        aggregate_name = rand_name('renamed-aggregate-scenario')
+        aggregate = self._update_aggregate(aggregate, aggregate_name, None)
+
+        additional_metadata = {'foo': 'bar'}
+        self._set_aggregate_metadata(aggregate, additional_metadata)
+
+        metadata.update(additional_metadata)
+        self._check_aggregate_details(aggregate, aggregate.name, az, [host],
+                                      metadata)
+
+        self._remove_host(aggregate, host)
+        self._delete_aggregate(aggregate)
diff --git a/tempest/scenario/test_cross_tenant_connectivity.py b/tempest/scenario/test_cross_tenant_connectivity.py
index faba987..a269017 100644
--- a/tempest/scenario/test_cross_tenant_connectivity.py
+++ b/tempest/scenario/test_cross_tenant_connectivity.py
@@ -371,6 +371,7 @@
                             msg)
         except Exception:
             debug.log_ip_ns()
+            self._log_console_output(servers=self.servers)
             raise
 
     def _test_in_tenant_block(self, tenant):
diff --git a/tempest/scenario/test_minimum_basic.py b/tempest/scenario/test_minimum_basic.py
index 8a51cd1..890d00f 100644
--- a/tempest/scenario/test_minimum_basic.py
+++ b/tempest/scenario/test_minimum_basic.py
@@ -131,7 +131,12 @@
         self.server.add_floating_ip(self.floating_ip)
 
     def ssh_to_server(self):
-        self.linux_client = self.get_remote_client(self.floating_ip.ip)
+        try:
+            self.linux_client = self.get_remote_client(self.floating_ip.ip)
+        except Exception:
+            LOG.exception('ssh to server failed')
+            self._log_console_output()
+            raise
 
     def check_partitions(self):
         partitions = self.linux_client.get_partitions()
diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
index 52a36e6..94e0f81 100644
--- a/tempest/scenario/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -213,11 +213,6 @@
             name = data_utils.rand_name('server-smoke-%d-' % i)
             self._create_server(name, network)
 
-    def _log_console_output(self):
-        for server, key in self.servers.items():
-            LOG.debug('Console output for %s', server.id)
-            LOG.debug(server.get_console_output())
-
     def _check_tenant_network_connectivity(self):
         if not CONF.network.tenant_networks_reachable:
             msg = 'Tenant networks not configured to be reachable.'
@@ -234,7 +229,8 @@
                                                     key.private_key)
         except Exception:
             LOG.exception('Tenant connectivity check failed')
-            self._log_console_output()
+            self._log_console_output(
+                servers=[server for server, _key in self.servers])
             debug.log_ip_ns()
             raise
 
@@ -272,7 +268,8 @@
                                             should_connect=should_connect)
         except Exception:
             LOG.exception('Public network connectivity check failed')
-            self._log_console_output()
+            self._log_console_output(
+                servers=[server for server, _key in self.servers])
             debug.log_ip_ns()
             raise
 
diff --git a/tempest/scenario/test_network_quotas.py b/tempest/scenario/test_network_quotas.py
deleted file mode 100644
index cb7aa0b..0000000
--- a/tempest/scenario/test_network_quotas.py
+++ /dev/null
@@ -1,131 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2013 Hewlett-Packard Development Company, L.P.
-# 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 neutronclient.common import exceptions as exc
-
-from tempest.scenario.manager import NetworkScenarioTest
-from tempest.test import services
-
-
-class TestNetworkQuotaBasic(NetworkScenarioTest):
-    """
-    This test suite contains tests that each loop trying to grab a
-    particular resource until a quota limit is hit.
-    For sanity, there is a maximum number of iterations - if this is hit
-    the test fails. Covers network, subnet, port.
-    """
-
-    @classmethod
-    def check_preconditions(cls):
-        super(TestNetworkQuotaBasic, cls).check_preconditions()
-
-    @classmethod
-    def setUpClass(cls):
-        super(TestNetworkQuotaBasic, cls).setUpClass()
-        cls.check_preconditions()
-        cls.networks = []
-        cls.subnets = []
-        cls.ports = []
-
-    @services('network')
-    def test_create_network_until_quota_hit(self):
-        hit_limit = False
-        networknum = self._get_tenant_own_network_num(self.tenant_id)
-        max = self._show_quota_network(self.tenant_id) - networknum
-        for n in xrange(max):
-            try:
-                self.networks.append(
-                    self._create_network(self.tenant_id,
-                                         namestart='network-quotatest-'))
-            except exc.NeutronClientException as e:
-                if (e.status_code != 409):
-                    raise
-                hit_limit = True
-                break
-        self.assertFalse(hit_limit, "Failed: Hit quota limit !")
-
-        try:
-            self.networks.append(
-                self._create_network(self.tenant_id,
-                                     namestart='network-quotatest-'))
-        except exc.NeutronClientException as e:
-            if (e.status_code != 409):
-                raise
-            hit_limit = True
-        self.assertTrue(hit_limit, "Failed: Did not hit quota limit !")
-
-    @services('network')
-    def test_create_subnet_until_quota_hit(self):
-        if not self.networks:
-            self.networks.append(
-                self._create_network(self.tenant_id,
-                                     namestart='network-quotatest-'))
-        hit_limit = False
-        subnetnum = self._get_tenant_own_subnet_num(self.tenant_id)
-        max = self._show_quota_subnet(self.tenant_id) - subnetnum
-        for n in xrange(max):
-            try:
-                self.subnets.append(
-                    self._create_subnet(self.networks[0],
-                                        namestart='subnet-quotatest-'))
-            except exc.NeutronClientException as e:
-                if (e.status_code != 409):
-                    raise
-                hit_limit = True
-                break
-        self.assertFalse(hit_limit, "Failed: Hit quota limit !")
-
-        try:
-            self.subnets.append(
-                self._create_subnet(self.networks[0],
-                                    namestart='subnet-quotatest-'))
-        except exc.NeutronClientException as e:
-            if (e.status_code != 409):
-                raise
-            hit_limit = True
-        self.assertTrue(hit_limit, "Failed: Did not hit quota limit !")
-
-    @services('network')
-    def test_create_ports_until_quota_hit(self):
-        if not self.networks:
-            self.networks.append(
-                self._create_network(self.tenant_id,
-                                     namestart='network-quotatest-'))
-        hit_limit = False
-        portnum = self._get_tenant_own_port_num(self.tenant_id)
-        max = self._show_quota_port(self.tenant_id) - portnum
-        for n in xrange(max):
-            try:
-                self.ports.append(
-                    self._create_port(self.networks[0],
-                                      namestart='port-quotatest-'))
-            except exc.NeutronClientException as e:
-                if (e.status_code != 409):
-                    raise
-                hit_limit = True
-                break
-        self.assertFalse(hit_limit, "Failed: Hit quota limit !")
-
-        try:
-            self.ports.append(
-                self._create_port(self.networks[0],
-                                  namestart='port-quotatest-'))
-        except exc.NeutronClientException as e:
-            if (e.status_code != 409):
-                raise
-            hit_limit = True
-        self.assertTrue(hit_limit, "Failed: Did not hit quota limit !")
diff --git a/tempest/scenario/test_server_basic_ops.py b/tempest/scenario/test_server_basic_ops.py
index ca3035d..279b80e 100644
--- a/tempest/scenario/test_server_basic_ops.py
+++ b/tempest/scenario/test_server_basic_ops.py
@@ -151,10 +151,15 @@
             instance = self.get_resource('instance')
             instance.add_floating_ip(floating_ip)
             # Check ssh
-            self.get_remote_client(
-                server_or_ip=floating_ip.ip,
-                username=self.image_utils.ssh_user(self.image_ref),
-                private_key=self.keypair.private)
+            try:
+                self.get_remote_client(
+                    server_or_ip=floating_ip.ip,
+                    username=self.image_utils.ssh_user(self.image_ref),
+                    private_key=self.keypair.private)
+            except Exception:
+                LOG.exception('ssh to server failed')
+                self._log_console_output()
+                raise
 
     @services('compute', 'network')
     def test_server_basicops(self):
diff --git a/tempest/scenario/test_snapshot_pattern.py b/tempest/scenario/test_snapshot_pattern.py
index 00139f0..874bc60 100644
--- a/tempest/scenario/test_snapshot_pattern.py
+++ b/tempest/scenario/test_snapshot_pattern.py
@@ -15,10 +15,14 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from tempest.openstack.common import log
 from tempest.scenario import manager
 from tempest.test import services
 
 
+LOG = log.getLogger(__name__)
+
+
 class TestSnapshotPattern(manager.OfficialClientTest):
     """
     This test is for snapshotting an instance and booting with it.
@@ -40,7 +44,11 @@
         self.keypair = self.create_keypair()
 
     def _ssh_to_server(self, server_or_ip):
-        linux_client = self.get_remote_client(server_or_ip)
+        try:
+            linux_client = self.get_remote_client(server_or_ip)
+        except Exception:
+            LOG.exception()
+            self._log_console_output()
         return linux_client.ssh_client
 
     def _write_timestamp(self, server_or_ip):
diff --git a/tempest/scenario/test_volume_boot_pattern.py b/tempest/scenario/test_volume_boot_pattern.py
index fa9a228..2a2b527 100644
--- a/tempest/scenario/test_volume_boot_pattern.py
+++ b/tempest/scenario/test_volume_boot_pattern.py
@@ -13,10 +13,14 @@
 #    under the License.
 
 from tempest.common.utils import data_utils
+from tempest.openstack.common import log
 from tempest.scenario import manager
 from tempest.test import services
 
 
+LOG = log.getLogger(__name__)
+
+
 class TestVolumeBootPattern(manager.OfficialClientTest):
 
     """
@@ -96,8 +100,14 @@
             network_name_for_ssh = self.config.compute.network_for_ssh
             ip = server.networks[network_name_for_ssh][0]
 
-        client = self.get_remote_client(ip,
-                                        private_key=keypair.private_key)
+        try:
+            client = self.get_remote_client(
+                ip,
+                private_key=keypair.private_key)
+        except Exception:
+            LOG.exception('ssh to server failed')
+            self._log_console_output()
+            raise
         return client.ssh_client
 
     def _get_content(self, ssh_client):
diff --git a/tempest/services/compute/v3/json/flavors_client.py b/tempest/services/compute/v3/json/flavors_client.py
index e99ac91..a790c40 100644
--- a/tempest/services/compute/v3/json/flavors_client.py
+++ b/tempest/services/compute/v3/json/flavors_client.py
@@ -61,7 +61,7 @@
             'id': flavor_id,
         }
         if kwargs.get('ephemeral'):
-            post_body['OS-FLV-EXT-DATA:ephemeral'] = kwargs.get('ephemeral')
+            post_body['ephemeral'] = kwargs.get('ephemeral')
         if kwargs.get('swap'):
             post_body['swap'] = kwargs.get('swap')
         if kwargs.get('rxtx'):
diff --git a/tempest/test.py b/tempest/test.py
index d57ed83..83a4319 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -230,6 +230,8 @@
 
     setUpClassCalled = False
 
+    network_resources = {}
+
     @classmethod
     def setUpClass(cls):
         if hasattr(super(BaseTestCase, cls), 'setUpClass'):
@@ -277,7 +279,8 @@
         """
         Returns an Openstack client manager
         """
-        cls.isolated_creds = isolated_creds.IsolatedCreds(cls.__name__)
+        cls.isolated_creds = isolated_creds.IsolatedCreds(
+            cls.__name__, network_resources=cls.network_resources)
 
         force_tenant_isolation = getattr(cls, 'force_tenant_isolation', None)
         if (cls.config.compute.allow_tenant_isolation or
@@ -319,6 +322,23 @@
             cls.config.identity.uri
         )
 
+    @classmethod
+    def set_network_resources(self, network=False, router=False, subnet=False,
+                              dhcp=False):
+        """Specify which network resources should be created
+
+        @param network
+        @param router
+        @param subnet
+        @param dhcp
+        """
+        self.network_resources = {
+            'network': network,
+            'router': router,
+            'subnet': subnet,
+            'dhcp': dhcp,
+        }
+
 
 def call_until_true(func, duration, sleep_for):
     """
diff --git a/test-requirements.txt b/test-requirements.txt
index 9486244..d7340f3 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -6,3 +6,4 @@
 oslo.sphinx
 mox>=0.5.3
 mock>=1.0
+coverage>=3.6
diff --git a/tox.ini b/tox.ini
index 6d596e3..88f2537 100644
--- a/tox.ini
+++ b/tox.ini
@@ -25,6 +25,10 @@
 setenv = OS_TEST_PATH=./tempest/tests
 commands = python setup.py test --slowest --testr-arg='tempest\.tests {posargs}'
 
+[testenv:cover]
+setenv = OS_TEST_PATH=./tempest/tests
+commands = python setup.py testr --coverage --testr-arg='tempest\.tests {posargs}'
+
 [testenv:all]
 setenv = VIRTUAL_ENV={envdir}
 commands =