Merge "Separate negative tests for list_floating_ips"
diff --git a/.testr.conf b/.testr.conf
index 05b12c4..c25ebec 100644
--- a/.testr.conf
+++ b/.testr.conf
@@ -2,7 +2,8 @@
 test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} \
              OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} \
              OS_TEST_TIMEOUT=${OS_TEST_TIMEOUT:-500} \
-             ${PYTHON:-python} -m subunit.run discover -t ./ ./tempest $LISTOPT $IDOPTION
+             OS_TEST_PATH=${OS_TEST_PATH:-./tempest} \
+             ${PYTHON:-python} -m subunit.run discover -t ./ $OS_TEST_PATH $LISTOPT $IDOPTION
 test_id_option=--load-list $IDFILE
 test_list_option=--list
 group_regex=([^\.]*\.)*
diff --git a/HACKING.rst b/HACKING.rst
index a74ff73..3fa1ff5 100644
--- a/HACKING.rst
+++ b/HACKING.rst
@@ -9,8 +9,8 @@
 ------------------------------
 
 - [T102] Cannot import OpenStack python clients in tempest/api tests
-- [T103] tempest/tests is deprecated
 - [T104] Scenario tests require a services decorator
+- [T105] Unit tests cannot use setUpClass
 
 Test Data/Configuration
 -----------------------
@@ -39,7 +39,7 @@
 when the additional operations leads to another exception.
 
 Just letting an exception to propagate, is not bad idea in a test case,
- at all.
+at all.
 
 Try to avoid using any exception handling construct which can hide the errors
 origin.
@@ -53,10 +53,10 @@
 test fails part way through.
 
 Use the ``self.assert*`` methods provided by the unit test framework
- the signal failures early.
+the signal failures early.
 
 Avoid using the ``self.fail`` alone, it's stack trace will signal
- the ``self.fail`` line as the origin of the error.
+the ``self.fail`` line as the origin of the error.
 
 Avoid constructing complex boolean expressions for assertion.
 The ``self.assertTrue`` or ``self.assertFalse`` without a ``msg`` argument,
@@ -192,3 +192,15 @@
 The sample config file is autogenerated using a script. If any changes are made
 to the config variables in tempest then the sample config file must be
 regenerated. This can be done running the script: tools/generate_sample.sh
+
+Unit Tests
+----------
+Unit tests are a separate class of tests in tempest. They verify tempest
+itself, and thus have a different set of guidelines around them:
+
+1. They can not require anything running externally. All you should need to
+   run the unit tests is the git tree, python and the dependencies installed.
+   This includes running services, a config file, etc.
+
+2. The unit tests cannot use setUpClass, instead fixtures and testresources
+   should be used for shared state between tests.
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index 8742b67..1080ddf 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -43,7 +43,7 @@
 #logging_exception_prefix=%(asctime)s.%(msecs)03d %(process)d TRACE %(name)s %(instance)s
 
 # list of logger=LEVEL pairs (list value)
-#default_log_levels=amqplib=WARN,sqlalchemy=WARN,boto=WARN,suds=INFO,keystone=INFO
+#default_log_levels=amqplib=WARN,sqlalchemy=WARN,boto=WARN,suds=INFO,keystone=INFO,paramiko=INFO
 
 # publish error events (boolean value)
 #publish_errors=false
@@ -220,14 +220,6 @@
 # admin credentials are known. (boolean value)
 #allow_tenant_isolation=false
 
-# If allow_tenant_isolation is True and a tenant that would be
-# created for a given test already exists (such as from a
-# previously-failed run), re-use that tenant instead of
-# failing because of the conflict. Note that this would result
-# in the tenant being deleted at the end of a subsequent
-# successful run. (boolean value)
-#allow_tenant_reuse=true
-
 # Valid secondary image reference to be used in tests. (string
 # value)
 #image_ref={$IMAGE_ID}
@@ -532,6 +524,16 @@
 #disk_format=raw
 
 
+[debug]
+
+#
+# Options defined in tempest.config
+#
+
+# Enable diagnostic commands (boolean value)
+#enable=true
+
+
 [dashboard]
 
 #
@@ -618,14 +620,15 @@
 #operator_role=Member
 
 
-[debug]
+[network-feature-enabled]
 
 #
 # Options defined in tempest.config
 #
 
-# Enable diagnostic commands (boolean value)
-#enable=true
+# A list of enabled extensions with a special entry all which
+# indicates every extension is enabled (list value)
+#api_extensions=all
 
 
 [service_available]
@@ -679,8 +682,13 @@
 # If false, skip disk config tests (boolean value)
 #disk_config=true
 
-# If false, skip flavor extra data test (boolean value)
-#flavor_extra=true
+# A list of enabled extensions with a special entry all which
+# indicates every extension is enabled (list value)
+#api_extensions=all
+
+# A list of enabled v3 extensions with a special entry all
+# which indicates every extension is enabled (list value)
+#api_v3_extensions=all
 
 # Does the test environment support changing the admin
 # password? (boolean value)
@@ -738,4 +746,8 @@
 # (boolean value)
 #multi_backend=false
 
+# A list of enabled extensions with a special entry all which
+# indicates every extension is enabled (list value)
+#api_extensions=all
+
 
diff --git a/etc/whitelist.yaml b/etc/whitelist.yaml
index e5a0d4d..a8c5276 100644
--- a/etc/whitelist.yaml
+++ b/etc/whitelist.yaml
@@ -160,14 +160,6 @@
     - module: "cinder.brick.local_dev.lvm"
       message: "Can't remove open logical volume"
 
-q-dhpc:
-    - module: "neutron.common.legacy"
-      message: "Skipping unknown group key: firewall_driver"
-    - module: "neutron.agent.dhcp_agent"
-      message: "Unable to enable dhcp"
-    - module: "neutron.agent.dhcp_agent"
-      message: " Network .* RPC info call failed"
-
 ceilometer-collector:
     - module: "stevedore.extension"
       message: ".*"
@@ -226,3 +218,6 @@
     - module: ".*"
       message: ".*"
 
+s-proxy:
+    - module: "proxy-server"
+      message: "Timeout talking to memcached"
diff --git a/requirements.txt b/requirements.txt
index 4f6a1d3..cd11aa7 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -5,9 +5,9 @@
 jsonschema>=1.3.0,!=1.4.0
 testtools>=0.9.32
 lxml>=2.3
-boto>=2.4.0,!=2.13.0
+boto>=2.12.0,!=2.13.0
 paramiko>=1.8.0
-netaddr
+netaddr>=0.7.6
 python-glanceclient>=0.9.0
 python-keystoneclient>=0.4.1
 python-novaclient>=2.15.0
@@ -20,5 +20,5 @@
 oslo.config>=1.2.0
 eventlet>=0.13.0
 six>=1.4.1
-iso8601>=0.1.4
+iso8601>=0.1.8
 fixtures>=0.3.14
diff --git a/run_tests.sh b/run_tests.sh
index 5c8ce7d..3c9c051 100755
--- a/run_tests.sh
+++ b/run_tests.sh
@@ -11,7 +11,6 @@
   echo "  -u, --update             Update the virtual environment with any newer package versions"
   echo "  -s, --smoke              Only run smoke tests"
   echo "  -t, --serial             Run testr serially"
-  echo "  -c, --nova-coverage      Enable Nova coverage collection"
   echo "  -C, --config             Config file location"
   echo "  -p, --pep8               Just run pep8"
   echo "  -h, --help               Print this usage message"
@@ -31,13 +30,12 @@
 no_site_packages=0
 force=0
 wrapper=""
-nova_coverage=0
 config_file=""
 update=0
 logging=0
 logging_config=etc/logging.conf
 
-if ! options=$(getopt -o VNnfustcphdC:lL: -l virtual-env,no-virtual-env,no-site-packages,force,update,smoke,serial,nova-coverage,pep8,help,debug,config:,logging,logging-config: -- "$@")
+if ! options=$(getopt -o VNnfustphdC:lL: -l virtual-env,no-virtual-env,no-site-packages,force,update,smoke,serial,pep8,help,debug,config:,logging,logging-config: -- "$@")
 then
     # parse error
     usage
@@ -55,7 +53,6 @@
     -f|--force) force=1;;
     -u|--update) update=1;;
     -d|--debug) set -o xtrace;;
-    -c|--nova-coverage) let nova_coverage=1;;
     -C|--config) config_file=$2; shift;;
     -p|--pep8) let just_pep8=1;;
     -s|--smoke) testrargs+="smoke"; noseargs+="--attr=type=smoke";;
@@ -131,16 +128,6 @@
   ${wrapper} flake8
 }
 
-function run_coverage_start {
-  echo "Starting nova-coverage"
-  ${wrapper} python tools/tempest_coverage.py -c start
-}
-
-function run_coverage_report {
-  echo "Generating nova-coverage report"
-  ${wrapper} python tools/tempest_coverage.py -c report
-}
-
 if [ $never_venv -eq 0 ]
 then
   # Remove the virtual environment if --force used
@@ -176,11 +163,6 @@
     exit
 fi
 
-if [ $nova_coverage -eq 1 ]; then
-    run_coverage_start
-fi
-
-
 py_version=`${wrapper} python --version 2>&1`
 if [[ $py_version =~ "2.6" ]] ; then
     run_tests_nose
@@ -189,10 +171,6 @@
 fi
 retval=$?
 
-if [ $nova_coverage -eq 1 ]; then
-    run_coverage_report
-fi
-
 if [ -z "$testrargs" ]; then
     run_pep8
 fi
diff --git a/tempest/api/compute/__init__.py b/tempest/api/compute/__init__.py
index a528754..d20068e 100644
--- a/tempest/api/compute/__init__.py
+++ b/tempest/api/compute/__init__.py
@@ -16,7 +16,6 @@
 #    under the License.
 
 from tempest import config
-from tempest.exceptions import InvalidConfiguration
 from tempest.openstack.common import log as logging
 
 LOG = logging.getLogger(__name__)
@@ -26,30 +25,3 @@
 RESIZE_AVAILABLE = CONFIG.compute_feature_enabled.resize
 CHANGE_PASSWORD_AVAILABLE = CONFIG.compute_feature_enabled.change_password
 DISK_CONFIG_ENABLED = CONFIG.compute_feature_enabled.disk_config
-FLAVOR_EXTRA_DATA_ENABLED = CONFIG.compute_feature_enabled.flavor_extra
-MULTI_USER = True
-
-
-# All compute tests -- single setup function
-def generic_setup_package():
-    LOG.debug("Entering tempest.api.compute.setup_package")
-
-    global MULTI_USER
-
-    # Determine if there are two regular users that can be
-    # used in testing. If the test cases are allowed to create
-    # users (config.compute.allow_tenant_isolation is true,
-    # then we allow multi-user.
-    if not CONFIG.compute.allow_tenant_isolation:
-        user1 = CONFIG.identity.username
-        user2 = CONFIG.identity.alt_username
-        if not user2 or user1 == user2:
-            MULTI_USER = False
-        else:
-            user2_password = CONFIG.identity.alt_password
-            user2_tenant_name = CONFIG.identity.alt_tenant_name
-            if not user2_password or not user2_tenant_name:
-                msg = ("Alternate user specified but not alternate "
-                       "tenant or password: alt_tenant_name=%s alt_password=%s"
-                       % (user2_tenant_name, user2_password))
-                raise InvalidConfiguration(msg)
diff --git a/tempest/api/compute/admin/test_aggregates.py b/tempest/api/compute/admin/test_aggregates.py
index 467a6f9..609d2c6 100644
--- a/tempest/api/compute/admin/test_aggregates.py
+++ b/tempest/api/compute/admin/test_aggregates.py
@@ -18,7 +18,6 @@
 from tempest.api.compute import base
 from tempest.common import tempest_fixtures as fixtures
 from tempest.common.utils import data_utils
-from tempest import exceptions
 from tempest.test import attr
 
 
@@ -35,7 +34,6 @@
     def setUpClass(cls):
         super(AggregatesAdminTestJSON, cls).setUpClass()
         cls.client = cls.os_adm.aggregates_client
-        cls.user_client = cls.aggregates_client
         cls.aggregate_name_prefix = 'test_aggregate_'
         cls.az_name_prefix = 'test_az_'
 
@@ -141,54 +139,6 @@
                          (x['id'], x['name'], x['availability_zone']),
                           aggregates))
 
-    @attr(type=['negative', 'gate'])
-    def test_aggregate_create_as_user(self):
-        # Regular user is not allowed to create an aggregate.
-        aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
-        self.assertRaises(exceptions.Unauthorized,
-                          self.user_client.create_aggregate,
-                          aggregate_name)
-
-    @attr(type=['negative', 'gate'])
-    def test_aggregate_delete_as_user(self):
-        # Regular user is not allowed to delete an aggregate.
-        aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
-        resp, aggregate = self.client.create_aggregate(aggregate_name)
-        self.addCleanup(self.client.delete_aggregate, aggregate['id'])
-
-        self.assertRaises(exceptions.Unauthorized,
-                          self.user_client.delete_aggregate,
-                          aggregate['id'])
-
-    @attr(type=['negative', 'gate'])
-    def test_aggregate_list_as_user(self):
-        # Regular user is not allowed to list aggregates.
-        self.assertRaises(exceptions.Unauthorized,
-                          self.user_client.list_aggregates)
-
-    @attr(type=['negative', 'gate'])
-    def test_aggregate_get_details_as_user(self):
-        # Regular user is not allowed to get aggregate details.
-        aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
-        resp, aggregate = self.client.create_aggregate(aggregate_name)
-        self.addCleanup(self.client.delete_aggregate, aggregate['id'])
-
-        self.assertRaises(exceptions.Unauthorized,
-                          self.user_client.get_aggregate,
-                          aggregate['id'])
-
-    @attr(type=['negative', 'gate'])
-    def test_aggregate_delete_with_invalid_id(self):
-        # Delete an aggregate with invalid id should raise exceptions.
-        self.assertRaises(exceptions.NotFound,
-                          self.client.delete_aggregate, -1)
-
-    @attr(type=['negative', 'gate'])
-    def test_aggregate_get_details_with_invalid_id(self):
-        # Get aggregate details with invalid id should raise exceptions.
-        self.assertRaises(exceptions.NotFound,
-                          self.client.get_aggregate, -1)
-
     @attr(type='gate')
     def test_aggregate_add_remove_host(self):
         # Add an host to the given aggregate and remove.
@@ -262,48 +212,6 @@
         resp, body = admin_servers_client.get_server(server['id'])
         self.assertEqual(self.host, body[self._host_key])
 
-    @attr(type=['negative', 'gate'])
-    def test_aggregate_add_non_exist_host(self):
-        # Adding a non-exist host to an aggregate should raise exceptions.
-        resp, hosts_all = self.os_adm.hosts_client.list_hosts()
-        hosts = map(lambda x: x['host_name'], hosts_all)
-        while True:
-            non_exist_host = data_utils.rand_name('nonexist_host_')
-            if non_exist_host not in hosts:
-                break
-
-        aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
-        resp, aggregate = self.client.create_aggregate(aggregate_name)
-        self.addCleanup(self.client.delete_aggregate, aggregate['id'])
-
-        self.assertRaises(exceptions.NotFound, self.client.add_host,
-                          aggregate['id'], non_exist_host)
-
-    @attr(type=['negative', 'gate'])
-    def test_aggregate_add_host_as_user(self):
-        # Regular user is not allowed to add a host to an aggregate.
-        aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
-        resp, aggregate = self.client.create_aggregate(aggregate_name)
-        self.addCleanup(self.client.delete_aggregate, aggregate['id'])
-
-        self.assertRaises(exceptions.Unauthorized,
-                          self.user_client.add_host,
-                          aggregate['id'], self.host)
-
-    @attr(type=['negative', 'gate'])
-    def test_aggregate_remove_host_as_user(self):
-        # Regular user is not allowed to remove a host from an aggregate.
-        self.useFixture(fixtures.LockFixture('availability_zone'))
-        aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
-        resp, aggregate = self.client.create_aggregate(aggregate_name)
-        self.addCleanup(self.client.delete_aggregate, aggregate['id'])
-        self.client.add_host(aggregate['id'], self.host)
-        self.addCleanup(self.client.remove_host, aggregate['id'], self.host)
-
-        self.assertRaises(exceptions.Unauthorized,
-                          self.user_client.remove_host,
-                          aggregate['id'], self.host)
-
 
 class AggregatesAdminTestXML(AggregatesAdminTestJSON):
     _host_key = (
diff --git a/tempest/api/compute/admin/test_aggregates_negative.py b/tempest/api/compute/admin/test_aggregates_negative.py
new file mode 100644
index 0000000..8506206
--- /dev/null
+++ b/tempest/api/compute/admin/test_aggregates_negative.py
@@ -0,0 +1,196 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 Huawei Technologies Co.,LTD.
+# 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 import tempest_fixtures as fixtures
+from tempest.common.utils import data_utils
+from tempest import exceptions
+from tempest.test import attr
+
+
+class AggregatesAdminNegativeTestJSON(base.BaseV2ComputeAdminTest):
+
+    """
+    Tests Aggregates API that require admin privileges
+    """
+
+    _interface = 'json'
+
+    @classmethod
+    def setUpClass(cls):
+        super(AggregatesAdminNegativeTestJSON, cls).setUpClass()
+        cls.client = cls.os_adm.aggregates_client
+        cls.user_client = cls.aggregates_client
+        cls.aggregate_name_prefix = 'test_aggregate_'
+        cls.az_name_prefix = 'test_az_'
+
+        resp, hosts_all = cls.os_adm.hosts_client.list_hosts()
+        hosts = map(lambda x: x['host_name'],
+                    filter(lambda y: y['service'] == 'compute', hosts_all))
+        cls.host = hosts[0]
+
+    @attr(type=['negative', 'gate'])
+    def test_aggregate_create_as_user(self):
+        # Regular user is not allowed to create an aggregate.
+        aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
+        self.assertRaises(exceptions.Unauthorized,
+                          self.user_client.create_aggregate,
+                          aggregate_name)
+
+    @attr(type=['negative', 'gate'])
+    def test_aggregate_create_aggregate_name_length_less_than_1(self):
+        # the length of aggregate name should >= 1 and <=255
+        self.assertRaises(exceptions.BadRequest,
+                          self.client.create_aggregate,
+                          '')
+
+    @attr(type=['negative', 'gate'])
+    def test_aggregate_create_aggregate_name_length_exceeds_255(self):
+        # the length of aggregate name should >= 1 and <=255
+        aggregate_name = 'a' * 256
+        self.assertRaises(exceptions.BadRequest,
+                          self.client.create_aggregate,
+                          aggregate_name)
+
+    @attr(type=['negative', 'gate'])
+    def test_aggregate_create_with_existent_aggregate_name(self):
+        # creating an aggregate with existent aggregate name is forbidden
+        aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
+        resp, aggregate = self.client.create_aggregate(aggregate_name)
+        self.assertEqual(200, resp.status)
+        self.addCleanup(self.client.delete_aggregate, aggregate['id'])
+
+        self.assertRaises(exceptions.Conflict,
+                          self.client.create_aggregate,
+                          aggregate_name)
+
+    @attr(type=['negative', 'gate'])
+    def test_aggregate_delete_as_user(self):
+        # Regular user is not allowed to delete an aggregate.
+        aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
+        resp, aggregate = self.client.create_aggregate(aggregate_name)
+        self.assertEqual(200, resp.status)
+        self.addCleanup(self.client.delete_aggregate, aggregate['id'])
+
+        self.assertRaises(exceptions.Unauthorized,
+                          self.user_client.delete_aggregate,
+                          aggregate['id'])
+
+    @attr(type=['negative', 'gate'])
+    def test_aggregate_list_as_user(self):
+        # Regular user is not allowed to list aggregates.
+        self.assertRaises(exceptions.Unauthorized,
+                          self.user_client.list_aggregates)
+
+    @attr(type=['negative', 'gate'])
+    def test_aggregate_get_details_as_user(self):
+        # Regular user is not allowed to get aggregate details.
+        aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
+        resp, aggregate = self.client.create_aggregate(aggregate_name)
+        self.assertEqual(200, resp.status)
+        self.addCleanup(self.client.delete_aggregate, aggregate['id'])
+
+        self.assertRaises(exceptions.Unauthorized,
+                          self.user_client.get_aggregate,
+                          aggregate['id'])
+
+    @attr(type=['negative', 'gate'])
+    def test_aggregate_delete_with_invalid_id(self):
+        # Delete an aggregate with invalid id should raise exceptions.
+        self.assertRaises(exceptions.NotFound,
+                          self.client.delete_aggregate, -1)
+
+    @attr(type=['negative', 'gate'])
+    def test_aggregate_get_details_with_invalid_id(self):
+        # Get aggregate details with invalid id should raise exceptions.
+        self.assertRaises(exceptions.NotFound,
+                          self.client.get_aggregate, -1)
+
+    @attr(type=['negative', 'gate'])
+    def test_aggregate_add_non_exist_host(self):
+        # Adding a non-exist host to an aggregate should raise exceptions.
+        resp, hosts_all = self.os_adm.hosts_client.list_hosts()
+        hosts = map(lambda x: x['host_name'], hosts_all)
+        while True:
+            non_exist_host = data_utils.rand_name('nonexist_host_')
+            if non_exist_host not in hosts:
+                break
+
+        aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
+        resp, aggregate = self.client.create_aggregate(aggregate_name)
+        self.addCleanup(self.client.delete_aggregate, aggregate['id'])
+
+        self.assertRaises(exceptions.NotFound, self.client.add_host,
+                          aggregate['id'], non_exist_host)
+
+    @attr(type=['negative', 'gate'])
+    def test_aggregate_add_host_as_user(self):
+        # Regular user is not allowed to add a host to an aggregate.
+        aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
+        resp, aggregate = self.client.create_aggregate(aggregate_name)
+        self.assertEqual(200, resp.status)
+        self.addCleanup(self.client.delete_aggregate, aggregate['id'])
+
+        self.assertRaises(exceptions.Unauthorized,
+                          self.user_client.add_host,
+                          aggregate['id'], self.host)
+
+    @attr(type=['negative', 'gate'])
+    def test_aggregate_add_existent_host(self):
+        self.useFixture(fixtures.LockFixture('availability_zone'))
+        aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
+        resp, aggregate = self.client.create_aggregate(aggregate_name)
+        self.assertEqual(200, resp.status)
+        self.addCleanup(self.client.delete_aggregate, aggregate['id'])
+
+        resp, body = self.client.add_host(aggregate['id'], self.host)
+        self.assertEqual(200, resp.status)
+        self.addCleanup(self.client.remove_host, aggregate['id'], self.host)
+
+        self.assertRaises(exceptions.Conflict, self.client.add_host,
+                          aggregate['id'], self.host)
+
+    @attr(type=['negative', 'gate'])
+    def test_aggregate_remove_host_as_user(self):
+        # Regular user is not allowed to remove a host from an aggregate.
+        self.useFixture(fixtures.LockFixture('availability_zone'))
+        aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
+        resp, aggregate = self.client.create_aggregate(aggregate_name)
+        self.assertEqual(200, resp.status)
+        self.addCleanup(self.client.delete_aggregate, aggregate['id'])
+        resp, body = self.client.add_host(aggregate['id'], self.host)
+        self.assertEqual(200, resp.status)
+        self.addCleanup(self.client.remove_host, aggregate['id'], self.host)
+
+        self.assertRaises(exceptions.Unauthorized,
+                          self.user_client.remove_host,
+                          aggregate['id'], self.host)
+
+    @attr(type=['negative', 'gate'])
+    def test_aggregate_remove_nonexistent_host(self):
+        non_exist_host = data_utils.rand_name('nonexist_host_')
+        aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
+        resp, aggregate = self.client.create_aggregate(aggregate_name)
+        self.assertEqual(200, resp.status)
+        self.addCleanup(self.client.delete_aggregate, aggregate['id'])
+
+        self.assertRaises(exceptions.NotFound, self.client.remove_host,
+                          aggregate['id'], non_exist_host)
+
+
+class AggregatesAdminNegativeTestXML(AggregatesAdminNegativeTestJSON):
+    _interface = 'xml'
diff --git a/tempest/api/compute/admin/test_availability_zone.py b/tempest/api/compute/admin/test_availability_zone.py
index d6488c4..e1a1a5d 100644
--- a/tempest/api/compute/admin/test_availability_zone.py
+++ b/tempest/api/compute/admin/test_availability_zone.py
@@ -16,21 +16,20 @@
 #    under the License.
 
 from tempest.api.compute import base
-from tempest import exceptions
 from tempest.test import attr
 
 
-class AvailabilityZoneAdminTestJSON(base.BaseV2ComputeAdminTest):
+class AZAdminTestJSON(base.BaseV2ComputeAdminTest):
 
     """
-    Tests Availability Zone API List that require admin privileges
+    Tests Availability Zone API List
     """
 
     _interface = 'json'
 
     @classmethod
     def setUpClass(cls):
-        super(AvailabilityZoneAdminTestJSON, cls).setUpClass()
+        super(AZAdminTestJSON, cls).setUpClass()
         cls.client = cls.os_adm.availability_zone_client
         cls.non_adm_client = cls.availability_zone_client
 
@@ -57,14 +56,6 @@
         self.assertEqual(200, resp.status)
         self.assertTrue(len(availability_zone) > 0)
 
-    @attr(type=['negative', 'gate'])
-    def test_get_availability_zone_list_detail_with_non_admin_user(self):
-        # List of availability zones and available services with
-        # non-administrator user
-        self.assertRaises(
-            exceptions.Unauthorized,
-            self.non_adm_client.get_availability_zone_list_detail)
 
-
-class AvailabilityZoneAdminTestXML(AvailabilityZoneAdminTestJSON):
+class AZAdminTestXML(AZAdminTestJSON):
     _interface = 'xml'
diff --git a/tempest/api/compute/admin/test_availability_zone_negative.py b/tempest/api/compute/admin/test_availability_zone_negative.py
new file mode 100644
index 0000000..6ba8d58
--- /dev/null
+++ b/tempest/api/compute/admin/test_availability_zone_negative.py
@@ -0,0 +1,45 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+#
+# Copyright 2013 NEC Corporation.  All rights reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.api.compute import base
+from tempest import exceptions
+from tempest.test import attr
+
+
+class AZAdminNegativeTestJSON(base.BaseV2ComputeAdminTest):
+
+    """
+    Tests Availability Zone API List
+    """
+
+    _interface = 'json'
+
+    @classmethod
+    def setUpClass(cls):
+        super(AZAdminNegativeTestJSON, cls).setUpClass()
+        cls.non_adm_client = cls.availability_zone_client
+
+    @attr(type=['negative', 'gate'])
+    def test_get_availability_zone_list_detail_with_non_admin_user(self):
+        # List of availability zones and available services with
+        # non-administrator user
+        self.assertRaises(
+            exceptions.Unauthorized,
+            self.non_adm_client.get_availability_zone_list_detail)
+
+
+class AZAdminNegativeTestXML(AZAdminNegativeTestJSON):
+    _interface = 'xml'
diff --git a/tempest/api/compute/admin/test_flavors.py b/tempest/api/compute/admin/test_flavors.py
index c5a8772..0fb9460 100644
--- a/tempest/api/compute/admin/test_flavors.py
+++ b/tempest/api/compute/admin/test_flavors.py
@@ -17,12 +17,10 @@
 
 import uuid
 
-from tempest.api import compute
 from tempest.api.compute import base
 from tempest.common.utils import data_utils
 from tempest import exceptions
-from tempest.test import attr
-from tempest.test import skip_because
+from tempest import test
 
 
 class FlavorsAdminTestJSON(base.BaseV2ComputeAdminTest):
@@ -36,7 +34,7 @@
     @classmethod
     def setUpClass(cls):
         super(FlavorsAdminTestJSON, cls).setUpClass()
-        if not compute.FLAVOR_EXTRA_DATA_ENABLED:
+        if not test.is_extension_enabled('FlavorExtraData', 'compute'):
             msg = "FlavorExtraData extension not enabled."
             raise cls.skipException(msg)
 
@@ -87,19 +85,19 @@
 
         return flavor['id']
 
-    @attr(type='gate')
+    @test.attr(type='gate')
     def test_create_flavor_with_int_id(self):
         flavor_id = data_utils.rand_int_id(start=1000)
         new_flavor_id = self._create_flavor(flavor_id)
         self.assertEqual(new_flavor_id, str(flavor_id))
 
-    @attr(type='gate')
+    @test.attr(type='gate')
     def test_create_flavor_with_uuid_id(self):
         flavor_id = str(uuid.uuid4())
         new_flavor_id = self._create_flavor(flavor_id)
         self.assertEqual(new_flavor_id, flavor_id)
 
-    @attr(type='gate')
+    @test.attr(type='gate')
     def test_create_flavor_with_none_id(self):
         # If nova receives a request with None as flavor_id,
         # nova generates flavor_id of uuid.
@@ -107,7 +105,7 @@
         new_flavor_id = self._create_flavor(flavor_id)
         self.assertEqual(new_flavor_id, str(uuid.UUID(new_flavor_id)))
 
-    @attr(type='gate')
+    @test.attr(type='gate')
     def test_create_flavor_verify_entry_in_list_details(self):
         # Create a flavor and ensure it's details are listed
         # This operation requires the user to have 'admin' role
@@ -132,41 +130,7 @@
                 flag = True
         self.assertTrue(flag)
 
-    @attr(type=['negative', 'gate'])
-    def test_get_flavor_details_for_deleted_flavor(self):
-        # Delete a flavor and ensure it is not listed
-        # Create a test flavor
-        flavor_name = data_utils.rand_name(self.flavor_name_prefix)
-        new_flavor_id = data_utils.rand_int_id(start=1000)
-
-        resp, flavor = self.client.create_flavor(flavor_name,
-                                                 self.ram,
-                                                 self.vcpus, self.disk,
-                                                 new_flavor_id,
-                                                 ephemeral=self.ephemeral,
-                                                 swap=self.swap,
-                                                 rxtx=self.rxtx)
-        # Delete the flavor
-        new_flavor_id = flavor['id']
-        resp_delete, body = self.client.delete_flavor(new_flavor_id)
-        self.assertEqual(200, resp.status)
-        self.assertEqual(202, resp_delete.status)
-
-        # Deleted flavors can be seen via detailed GET
-        resp, flavor = self.client.get_flavor_details(new_flavor_id)
-        self.assertEqual(resp.status, 200)
-        self.assertEqual(flavor['name'], flavor_name)
-
-        # Deleted flavors should not show up in a list however
-        resp, flavors = self.client.list_flavors_with_detail()
-        self.assertEqual(resp.status, 200)
-        flag = True
-        for flavor in flavors:
-            if flavor['name'] == flavor_name:
-                flag = False
-        self.assertTrue(flag)
-
-    @attr(type='gate')
+    @test.attr(type='gate')
     def test_create_list_flavor_without_extra_data(self):
         # Create a flavor and ensure it is listed
         # This operation requires the user to have 'admin' role
@@ -210,8 +174,8 @@
                 flag = True
         self.assertTrue(flag)
 
-    @skip_because(bug="1209101")
-    @attr(type='gate')
+    @test.skip_because(bug="1209101")
+    @test.attr(type='gate')
     def test_list_non_public_flavor(self):
         # Create a flavor with os-flavor-access:is_public false should
         # be present in list_details.
@@ -244,7 +208,7 @@
                 flag = True
         self.assertFalse(flag)
 
-    @attr(type='gate')
+    @test.attr(type='gate')
     def test_create_server_with_non_public_flavor(self):
         # Create a flavor with os-flavor-access:is_public false
         flavor_name = data_utils.rand_name(self.flavor_name_prefix)
@@ -264,7 +228,7 @@
                           self.os.servers_client.create_server,
                           'test', self.image_ref, flavor['id'])
 
-    @attr(type='gate')
+    @test.attr(type='gate')
     def test_list_public_flavor_with_other_user(self):
         # Create a Flavor with public access.
         # Try to List/Get flavor with another user
@@ -288,7 +252,7 @@
                 flag = True
         self.assertTrue(flag)
 
-    @attr(type='gate')
+    @test.attr(type='gate')
     def test_is_public_string_variations(self):
         flavor_id_not_public = data_utils.rand_int_id(start=1000)
         flavor_name_not_public = data_utils.rand_name(self.flavor_name_prefix)
@@ -331,7 +295,7 @@
         _test_string_variations(['t', 'true', 'yes', '1'],
                                 flavor_name_public)
 
-    @attr(type='gate')
+    @test.attr(type='gate')
     def test_create_flavor_using_string_ram(self):
         flavor_name = data_utils.rand_name(self.flavor_name_prefix)
         new_flavor_id = data_utils.rand_int_id(start=1000)
@@ -349,49 +313,6 @@
         self.assertEqual(flavor['ram'], int(ram))
         self.assertEqual(int(flavor['id']), new_flavor_id)
 
-    @attr(type=['negative', 'gate'])
-    def test_invalid_is_public_string(self):
-        self.assertRaises(exceptions.BadRequest,
-                          self.client.list_flavors_with_detail,
-                          {'is_public': 'invalid'})
-
-    @attr(type=['negative', 'gate'])
-    def test_create_flavor_as_user(self):
-        flavor_name = data_utils.rand_name(self.flavor_name_prefix)
-        new_flavor_id = data_utils.rand_int_id(start=1000)
-
-        self.assertRaises(exceptions.Unauthorized,
-                          self.user_client.create_flavor,
-                          flavor_name, self.ram, self.vcpus, self.disk,
-                          new_flavor_id, ephemeral=self.ephemeral,
-                          swap=self.swap, rxtx=self.rxtx)
-
-    @attr(type=['negative', 'gate'])
-    def test_delete_flavor_as_user(self):
-        self.assertRaises(exceptions.Unauthorized,
-                          self.user_client.delete_flavor,
-                          self.flavor_ref_alt)
-
-    @attr(type=['negative', 'gate'])
-    def test_create_flavor_using_invalid_ram(self):
-        flavor_name = data_utils.rand_name(self.flavor_name_prefix)
-        new_flavor_id = data_utils.rand_int_id(start=1000)
-
-        self.assertRaises(exceptions.BadRequest,
-                          self.client.create_flavor,
-                          flavor_name, -1, self.vcpus,
-                          self.disk, new_flavor_id)
-
-    @attr(type=['negative', 'gate'])
-    def test_create_flavor_using_invalid_vcpus(self):
-        flavor_name = data_utils.rand_name(self.flavor_name_prefix)
-        new_flavor_id = data_utils.rand_int_id(start=1000)
-
-        self.assertRaises(exceptions.BadRequest,
-                          self.client.create_flavor,
-                          flavor_name, self.ram, 0,
-                          self.disk, new_flavor_id)
-
 
 class FlavorsAdminTestXML(FlavorsAdminTestJSON):
     _interface = 'xml'
diff --git a/tempest/api/compute/admin/test_flavors_access.py b/tempest/api/compute/admin/test_flavors_access.py
index b866db1..048312b 100644
--- a/tempest/api/compute/admin/test_flavors_access.py
+++ b/tempest/api/compute/admin/test_flavors_access.py
@@ -15,10 +15,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest.api import compute
 from tempest.api.compute import base
 from tempest.common.utils import data_utils
-from tempest.test import attr
+from tempest import test
 
 
 class FlavorsAccessTestJSON(base.BaseV2ComputeAdminTest):
@@ -33,7 +32,7 @@
     @classmethod
     def setUpClass(cls):
         super(FlavorsAccessTestJSON, cls).setUpClass()
-        if not compute.FLAVOR_EXTRA_DATA_ENABLED:
+        if not test.is_extension_enabled('FlavorExtraData', 'compute'):
             msg = "FlavorExtraData extension not enabled."
             raise cls.skipException(msg)
 
@@ -51,7 +50,7 @@
         cls.vcpus = 1
         cls.disk = 10
 
-    @attr(type='gate')
+    @test.attr(type='gate')
     def test_flavor_access_list_with_private_flavor(self):
         # Test to list flavor access successfully by querying private flavor
         flavor_name = data_utils.rand_name(self.flavor_name_prefix)
@@ -70,7 +69,7 @@
         self.assertEqual(str(new_flavor_id), str(first_flavor['flavor_id']))
         self.assertEqual(self.adm_tenant_id, first_flavor['tenant_id'])
 
-    @attr(type='gate')
+    @test.attr(type='gate')
     def test_flavor_access_add_remove(self):
         # Test to add and remove flavor access to a given tenant.
         flavor_name = data_utils.rand_name(self.flavor_name_prefix)
diff --git a/tempest/api/compute/admin/test_flavors_access_negative.py b/tempest/api/compute/admin/test_flavors_access_negative.py
index 340c1c7..976124e 100644
--- a/tempest/api/compute/admin/test_flavors_access_negative.py
+++ b/tempest/api/compute/admin/test_flavors_access_negative.py
@@ -17,11 +17,10 @@
 
 import uuid
 
-from tempest.api import compute
 from tempest.api.compute import base
 from tempest.common.utils import data_utils
 from tempest import exceptions
-from tempest.test import attr
+from tempest import test
 
 
 class FlavorsAccessNegativeTestJSON(base.BaseV2ComputeAdminTest):
@@ -36,7 +35,7 @@
     @classmethod
     def setUpClass(cls):
         super(FlavorsAccessNegativeTestJSON, cls).setUpClass()
-        if not compute.FLAVOR_EXTRA_DATA_ENABLED:
+        if not test.is_extension_enabled('FlavorExtraData', 'compute'):
             msg = "FlavorExtraData extension not enabled."
             raise cls.skipException(msg)
 
@@ -54,7 +53,7 @@
         cls.vcpus = 1
         cls.disk = 10
 
-    @attr(type=['negative', 'gate'])
+    @test.attr(type=['negative', 'gate'])
     def test_flavor_access_list_with_public_flavor(self):
         # Test to list flavor access with exceptions by querying public flavor
         flavor_name = data_utils.rand_name(self.flavor_name_prefix)
@@ -70,7 +69,7 @@
                           self.client.list_flavor_access,
                           new_flavor_id)
 
-    @attr(type=['negative', 'gate'])
+    @test.attr(type=['negative', 'gate'])
     def test_flavor_non_admin_add(self):
         # Test to add flavor access as a user without admin privileges.
         flavor_name = data_utils.rand_name(self.flavor_name_prefix)
@@ -86,7 +85,7 @@
                           new_flavor['id'],
                           self.tenant_id)
 
-    @attr(type=['negative', 'gate'])
+    @test.attr(type=['negative', 'gate'])
     def test_flavor_non_admin_remove(self):
         # Test to remove flavor access as a user without admin privileges.
         flavor_name = data_utils.rand_name(self.flavor_name_prefix)
@@ -106,7 +105,7 @@
                           new_flavor['id'],
                           self.tenant_id)
 
-    @attr(type=['negative', 'gate'])
+    @test.attr(type=['negative', 'gate'])
     def test_add_flavor_access_duplicate(self):
         # Create a new flavor.
         flavor_name = data_utils.rand_name(self.flavor_name_prefix)
@@ -130,7 +129,7 @@
                           new_flavor['id'],
                           self.tenant_id)
 
-    @attr(type=['negative', 'gate'])
+    @test.attr(type=['negative', 'gate'])
     def test_remove_flavor_access_not_found(self):
         # Create a new flavor.
         flavor_name = data_utils.rand_name(self.flavor_name_prefix)
diff --git a/tempest/api/compute/admin/test_flavors_extra_specs.py b/tempest/api/compute/admin/test_flavors_extra_specs.py
index 49b0429..875f742 100644
--- a/tempest/api/compute/admin/test_flavors_extra_specs.py
+++ b/tempest/api/compute/admin/test_flavors_extra_specs.py
@@ -15,10 +15,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest.api import compute
 from tempest.api.compute import base
 from tempest.common.utils import data_utils
-from tempest.test import attr
+from tempest import test
 
 
 class FlavorsExtraSpecsTestJSON(base.BaseV2ComputeAdminTest):
@@ -34,7 +33,7 @@
     @classmethod
     def setUpClass(cls):
         super(FlavorsExtraSpecsTestJSON, cls).setUpClass()
-        if not compute.FLAVOR_EXTRA_DATA_ENABLED:
+        if not test.is_extension_enabled('FlavorExtraData', 'compute'):
             msg = "FlavorExtraData extension not enabled."
             raise cls.skipException(msg)
 
@@ -61,7 +60,7 @@
         cls.client.wait_for_resource_deletion(cls.flavor['id'])
         super(FlavorsExtraSpecsTestJSON, cls).tearDownClass()
 
-    @attr(type='gate')
+    @test.attr(type='gate')
     def test_flavor_set_get_update_show_unset_keys(self):
         # Test to SET, GET, UPDATE, SHOW, UNSET flavor extra
         # spec as a user with admin privileges.
@@ -101,7 +100,7 @@
             self.client.unset_flavor_extra_spec(self.flavor['id'], "key2")
         self.assertEqual(unset_resp.status, 200)
 
-    @attr(type='gate')
+    @test.attr(type='gate')
     def test_flavor_non_admin_get_all_keys(self):
         specs = {"key1": "value1", "key2": "value2"}
         set_resp, set_body = self.client.set_flavor_extra_spec(
@@ -113,7 +112,7 @@
         for key in specs:
             self.assertEqual(body[key], specs[key])
 
-    @attr(type='gate')
+    @test.attr(type='gate')
     def test_flavor_non_admin_get_specific_key(self):
         specs = {"key1": "value1", "key2": "value2"}
         resp, body = self.client.set_flavor_extra_spec(
diff --git a/tempest/api/compute/admin/test_flavors_extra_specs_negative.py b/tempest/api/compute/admin/test_flavors_extra_specs_negative.py
index d7e1f9f..fb09a63 100644
--- a/tempest/api/compute/admin/test_flavors_extra_specs_negative.py
+++ b/tempest/api/compute/admin/test_flavors_extra_specs_negative.py
@@ -16,11 +16,10 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest.api import compute
 from tempest.api.compute import base
 from tempest.common.utils import data_utils
 from tempest import exceptions
-from tempest.test import attr
+from tempest import test
 
 
 class FlavorsExtraSpecsNegativeTestJSON(base.BaseV2ComputeAdminTest):
@@ -35,7 +34,7 @@
     @classmethod
     def setUpClass(cls):
         super(FlavorsExtraSpecsNegativeTestJSON, cls).setUpClass()
-        if not compute.FLAVOR_EXTRA_DATA_ENABLED:
+        if not test.is_extension_enabled('FlavorExtraData', 'compute'):
             msg = "FlavorExtraData extension not enabled."
             raise cls.skipException(msg)
 
@@ -62,7 +61,7 @@
         cls.client.wait_for_resource_deletion(cls.flavor['id'])
         super(FlavorsExtraSpecsNegativeTestJSON, cls).tearDownClass()
 
-    @attr(type=['negative', 'gate'])
+    @test.attr(type=['negative', 'gate'])
     def test_flavor_non_admin_set_keys(self):
         # Test to SET flavor extra spec as a user without admin privileges.
         specs = {"key1": "value1", "key2": "value2"}
@@ -71,7 +70,7 @@
                           self.flavor['id'],
                           specs)
 
-    @attr(type=['negative', 'gate'])
+    @test.attr(type=['negative', 'gate'])
     def test_flavor_non_admin_update_specific_key(self):
         # non admin user is not allowed to update flavor extra spec
         specs = {"key1": "value1", "key2": "value2"}
@@ -86,7 +85,7 @@
                           'key1',
                           key1='value1_new')
 
-    @attr(type=['negative', 'gate'])
+    @test.attr(type=['negative', 'gate'])
     def test_flavor_non_admin_unset_keys(self):
         specs = {"key1": "value1", "key2": "value2"}
         set_resp, set_body = self.client.set_flavor_extra_spec(
@@ -97,7 +96,7 @@
                           self.flavor['id'],
                           'key1')
 
-    @attr(type=['negative', 'gate'])
+    @test.attr(type=['negative', 'gate'])
     def test_flavor_unset_nonexistent_key(self):
         nonexistent_key = data_utils.rand_name('flavor_key')
         self.assertRaises(exceptions.NotFound,
@@ -105,14 +104,14 @@
                           self.flavor['id'],
                           nonexistent_key)
 
-    @attr(type=['negative', 'gate'])
+    @test.attr(type=['negative', 'gate'])
     def test_flavor_get_nonexistent_key(self):
         self.assertRaises(exceptions.NotFound,
                           self.flavors_client.get_flavor_extra_spec_with_key,
                           self.flavor['id'],
                           "nonexistent_key")
 
-    @attr(type=['negative', 'gate'])
+    @test.attr(type=['negative', 'gate'])
     def test_flavor_update_mismatch_key(self):
         # the key will be updated should be match the key in the body
         self.assertRaises(exceptions.BadRequest,
@@ -121,7 +120,7 @@
                           "key2",
                           key1="value")
 
-    @attr(type=['negative', 'gate'])
+    @test.attr(type=['negative', 'gate'])
     def test_flavor_update_more_key(self):
         # there should be just one item in the request body
         self.assertRaises(exceptions.BadRequest,
diff --git a/tempest/api/compute/admin/test_flavors_negative.py b/tempest/api/compute/admin/test_flavors_negative.py
new file mode 100644
index 0000000..1d9198a
--- /dev/null
+++ b/tempest/api/compute/admin/test_flavors_negative.py
@@ -0,0 +1,344 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# 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.
+
+import uuid
+
+from tempest.api.compute import base
+from tempest.common.utils import data_utils
+from tempest import exceptions
+from tempest import test
+
+
+class FlavorsAdminNegativeTestJSON(base.BaseV2ComputeAdminTest):
+
+    """
+    Tests Flavors API Create and Delete that require admin privileges
+    """
+
+    _interface = 'json'
+
+    @classmethod
+    def setUpClass(cls):
+        super(FlavorsAdminNegativeTestJSON, cls).setUpClass()
+        if not test.is_extension_enabled('FlavorExtraData', 'compute'):
+            msg = "FlavorExtraData extension not enabled."
+            raise cls.skipException(msg)
+
+        cls.client = cls.os_adm.flavors_client
+        cls.user_client = cls.os.flavors_client
+        cls.flavor_name_prefix = 'test_flavor_'
+        cls.ram = 512
+        cls.vcpus = 1
+        cls.disk = 10
+        cls.ephemeral = 10
+        cls.swap = 1024
+        cls.rxtx = 2
+
+    def flavor_clean_up(self, flavor_id):
+        resp, body = self.client.delete_flavor(flavor_id)
+        self.assertEqual(resp.status, 202)
+        self.client.wait_for_resource_deletion(flavor_id)
+
+    @test.attr(type=['negative', 'gate'])
+    def test_get_flavor_details_for_deleted_flavor(self):
+        # Delete a flavor and ensure it is not listed
+        # Create a test flavor
+        flavor_name = data_utils.rand_name(self.flavor_name_prefix)
+
+        # no need to specify flavor_id, we can get the flavor_id from a
+        # response of create_flavor() call.
+        resp, flavor = self.client.create_flavor(flavor_name,
+                                                 self.ram,
+                                                 self.vcpus, self.disk,
+                                                 '',
+                                                 ephemeral=self.ephemeral,
+                                                 swap=self.swap,
+                                                 rxtx=self.rxtx)
+        # Delete the flavor
+        new_flavor_id = flavor['id']
+        resp_delete, body = self.client.delete_flavor(new_flavor_id)
+        self.assertEqual(200, resp.status)
+        self.assertEqual(202, resp_delete.status)
+
+        # Deleted flavors can be seen via detailed GET
+        resp, flavor = self.client.get_flavor_details(new_flavor_id)
+        self.assertEqual(resp.status, 200)
+        self.assertEqual(flavor['name'], flavor_name)
+
+        # Deleted flavors should not show up in a list however
+        resp, flavors = self.client.list_flavors_with_detail()
+        self.assertEqual(resp.status, 200)
+        flag = True
+        for flavor in flavors:
+            if flavor['name'] == flavor_name:
+                flag = False
+        self.assertTrue(flag)
+
+    @test.attr(type=['negative', 'gate'])
+    def test_invalid_is_public_string(self):
+        # the 'is_public' parameter can be 'none/true/false' if it exists
+        self.assertRaises(exceptions.BadRequest,
+                          self.client.list_flavors_with_detail,
+                          {'is_public': 'invalid'})
+
+    @test.attr(type=['negative', 'gate'])
+    def test_create_flavor_as_user(self):
+        # only admin user can create a flavor
+        flavor_name = data_utils.rand_name(self.flavor_name_prefix)
+        new_flavor_id = str(uuid.uuid4())
+
+        self.assertRaises(exceptions.Unauthorized,
+                          self.user_client.create_flavor,
+                          flavor_name, self.ram, self.vcpus, self.disk,
+                          new_flavor_id, ephemeral=self.ephemeral,
+                          swap=self.swap, rxtx=self.rxtx)
+
+    @test.attr(type=['negative', 'gate'])
+    def test_delete_flavor_as_user(self):
+        # only admin user can delete a flavor
+        self.assertRaises(exceptions.Unauthorized,
+                          self.user_client.delete_flavor,
+                          self.flavor_ref_alt)
+
+    @test.attr(type=['negative', 'gate'])
+    def test_create_flavor_using_invalid_ram(self):
+        # the 'ram' attribute must be positive integer
+        flavor_name = data_utils.rand_name(self.flavor_name_prefix)
+        new_flavor_id = str(uuid.uuid4())
+
+        self.assertRaises(exceptions.BadRequest,
+                          self.client.create_flavor,
+                          flavor_name, -1, self.vcpus,
+                          self.disk, new_flavor_id)
+
+    @test.attr(type=['negative', 'gate'])
+    def test_create_flavor_using_invalid_vcpus(self):
+        # the 'vcpu' attribute must be positive integer
+        flavor_name = data_utils.rand_name(self.flavor_name_prefix)
+        new_flavor_id = str(uuid.uuid4())
+
+        self.assertRaises(exceptions.BadRequest,
+                          self.client.create_flavor,
+                          flavor_name, self.ram, -1,
+                          self.disk, new_flavor_id)
+
+    @test.attr(type=['negative', 'gate'])
+    def test_create_flavor_with_name_length_less_than_1(self):
+        # ensure name length >= 1
+        new_flavor_id = str(uuid.uuid4())
+
+        self.assertRaises(exceptions.BadRequest,
+                          self.client.create_flavor,
+                          '',
+                          self.ram, self.vcpus,
+                          self.disk,
+                          new_flavor_id,
+                          ephemeral=self.ephemeral,
+                          swap=self.swap,
+                          rxtx=self.rxtx,
+                          is_public='False')
+
+    @test.attr(type=['negative', 'gate'])
+    def test_create_flavor_with_name_length_exceeds_255(self):
+        # ensure name do not exceed 255 characters
+        new_flavor_name = 'a' * 256
+        new_flavor_id = str(uuid.uuid4())
+
+        self.assertRaises(exceptions.BadRequest,
+                          self.client.create_flavor,
+                          new_flavor_name,
+                          self.ram, self.vcpus,
+                          self.disk,
+                          new_flavor_id,
+                          ephemeral=self.ephemeral,
+                          swap=self.swap,
+                          rxtx=self.rxtx,
+                          is_public='False')
+
+    @test.attr(type=['negative', 'gate'])
+    def test_create_flavor_with_invalid_name(self):
+        # the regex of flavor_name is '^[\w\.\- ]*$'
+        invalid_flavor_name = data_utils.rand_name('invalid-!@#$%-')
+        new_flavor_id = str(uuid.uuid4())
+
+        self.assertRaises(exceptions.BadRequest,
+                          self.client.create_flavor,
+                          invalid_flavor_name,
+                          self.ram, self.vcpus,
+                          self.disk,
+                          new_flavor_id,
+                          ephemeral=self.ephemeral,
+                          swap=self.swap,
+                          rxtx=self.rxtx,
+                          is_public='False')
+
+    @test.attr(type=['negative', 'gate'])
+    def test_create_flavor_with_invalid_flavor_id(self):
+        # the regex of flavor_id is '^[\w\.\- ]*$', and it cannot contain
+        # leading and/or trailing whitespace
+        new_flavor_name = data_utils.rand_name(self.flavor_name_prefix)
+        invalid_flavor_id = '!@#$%'
+
+        self.assertRaises(exceptions.BadRequest,
+                          self.client.create_flavor,
+                          new_flavor_name,
+                          self.ram, self.vcpus,
+                          self.disk,
+                          invalid_flavor_id,
+                          ephemeral=self.ephemeral,
+                          swap=self.swap,
+                          rxtx=self.rxtx,
+                          is_public='False')
+
+    @test.attr(type=['negative', 'gate'])
+    def test_create_flavor_with_id_length_exceeds_255(self):
+        # the length of flavor_id should not exceed 255 characters
+        new_flavor_name = data_utils.rand_name(self.flavor_name_prefix)
+        invalid_flavor_id = 'a' * 256
+
+        self.assertRaises(exceptions.BadRequest,
+                          self.client.create_flavor,
+                          new_flavor_name,
+                          self.ram, self.vcpus,
+                          self.disk,
+                          invalid_flavor_id,
+                          ephemeral=self.ephemeral,
+                          swap=self.swap,
+                          rxtx=self.rxtx,
+                          is_public='False')
+
+    @test.attr(type=['negative', 'gate'])
+    def test_create_flavor_with_invalid_root_gb(self):
+        # root_gb attribute should be non-negative ( >= 0) integer
+        new_flavor_name = data_utils.rand_name(self.flavor_name_prefix)
+        new_flavor_id = str(uuid.uuid4())
+
+        self.assertRaises(exceptions.BadRequest,
+                          self.client.create_flavor,
+                          new_flavor_name,
+                          self.ram, self.vcpus,
+                          -1,
+                          new_flavor_id,
+                          ephemeral=self.ephemeral,
+                          swap=self.swap,
+                          rxtx=self.rxtx,
+                          is_public='False')
+
+    @test.attr(type=['negative', 'gate'])
+    def test_create_flavor_with_invalid_ephemeral_gb(self):
+        # ephemeral_gb attribute should be non-negative ( >= 0) integer
+        new_flavor_name = data_utils.rand_name(self.flavor_name_prefix)
+        new_flavor_id = str(uuid.uuid4())
+
+        self.assertRaises(exceptions.BadRequest,
+                          self.client.create_flavor,
+                          new_flavor_name,
+                          self.ram, self.vcpus,
+                          self.disk,
+                          new_flavor_id,
+                          ephemeral=-1,
+                          swap=self.swap,
+                          rxtx=self.rxtx,
+                          is_public='False')
+
+    @test.attr(type=['negative', 'gate'])
+    def test_create_flavor_with_invalid_swap(self):
+        # swap attribute should be non-negative ( >= 0) integer
+        new_flavor_name = data_utils.rand_name(self.flavor_name_prefix)
+        new_flavor_id = str(uuid.uuid4())
+
+        self.assertRaises(exceptions.BadRequest,
+                          self.client.create_flavor,
+                          new_flavor_name,
+                          self.ram, self.vcpus,
+                          self.disk,
+                          new_flavor_id,
+                          ephemeral=self.ephemeral,
+                          swap=-1,
+                          rxtx=self.rxtx,
+                          is_public='False')
+
+    @test.attr(type=['negative', 'gate'])
+    def test_create_flavor_with_invalid_rxtx_factor(self):
+        # rxtx_factor attribute should be a positive float
+        new_flavor_name = data_utils.rand_name(self.flavor_name_prefix)
+        new_flavor_id = str(uuid.uuid4())
+
+        self.assertRaises(exceptions.BadRequest,
+                          self.client.create_flavor,
+                          new_flavor_name,
+                          self.ram, self.vcpus,
+                          self.disk,
+                          new_flavor_id,
+                          ephemeral=self.ephemeral,
+                          swap=self.swap,
+                          rxtx=-1.5,
+                          is_public='False')
+
+    @test.attr(type=['negative', 'gate'])
+    def test_create_flavor_with_invalid_is_public(self):
+        # is_public attribute should be boolean
+        new_flavor_name = data_utils.rand_name(self.flavor_name_prefix)
+        new_flavor_id = str(uuid.uuid4())
+
+        self.assertRaises(exceptions.BadRequest,
+                          self.client.create_flavor,
+                          new_flavor_name,
+                          self.ram, self.vcpus,
+                          self.disk,
+                          new_flavor_id,
+                          ephemeral=self.ephemeral,
+                          swap=self.swap,
+                          rxtx=self.rxtx,
+                          is_public='Invalid')
+
+    @test.attr(type=['negative', 'gate'])
+    def test_create_flavor_already_exists(self):
+        flavor_name = data_utils.rand_name(self.flavor_name_prefix)
+        new_flavor_id = str(uuid.uuid4())
+
+        resp, flavor = self.client.create_flavor(flavor_name,
+                                                 self.ram, self.vcpus,
+                                                 self.disk,
+                                                 new_flavor_id,
+                                                 ephemeral=self.ephemeral,
+                                                 swap=self.swap,
+                                                 rxtx=self.rxtx)
+        self.assertEqual(200, resp.status)
+        self.addCleanup(self.flavor_clean_up, flavor['id'])
+
+        self.assertRaises(exceptions.Conflict,
+                          self.client.create_flavor,
+                          flavor_name,
+                          self.ram, self.vcpus,
+                          self.disk,
+                          new_flavor_id,
+                          ephemeral=self.ephemeral,
+                          swap=self.swap,
+                          rxtx=self.rxtx)
+
+    @test.attr(type=['negative', 'gate'])
+    def test_delete_nonexistent_flavor(self):
+        nonexistent_flavor_id = str(uuid.uuid4())
+
+        self.assertRaises(exceptions.NotFound,
+                          self.client.delete_flavor,
+                          nonexistent_flavor_id)
+
+
+class FlavorsAdminNegativeTestXML(FlavorsAdminNegativeTestJSON):
+    _interface = 'xml'
diff --git a/tempest/api/compute/admin/test_security_groups.py b/tempest/api/compute/admin/test_security_groups.py
new file mode 100644
index 0000000..5ed4823
--- /dev/null
+++ b/tempest/api/compute/admin/test_security_groups.py
@@ -0,0 +1,96 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 NTT Data
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import testtools
+
+from tempest.api.compute import base
+from tempest.common.utils import data_utils
+from tempest import config
+from tempest.test import attr
+
+
+class SecurityGroupsTestAdminJSON(base.BaseV2ComputeAdminTest):
+    _interface = 'json'
+
+    @classmethod
+    def setUpClass(cls):
+        super(SecurityGroupsTestAdminJSON, cls).setUpClass()
+        cls.adm_client = cls.os_adm.security_groups_client
+        cls.client = cls.security_groups_client
+
+    def _delete_security_group(self, securitygroup_id, admin=True):
+        if admin:
+            resp, _ = self.adm_client.delete_security_group(securitygroup_id)
+        else:
+            resp, _ = self.client.delete_security_group(securitygroup_id)
+
+        self.assertEqual(202, resp.status)
+
+    @testtools.skipIf(config.TempestConfig().service_available.neutron,
+                      "Skipped because neutron do not support all_tenants"
+                      "search filter.")
+    @attr(type='smoke')
+    def test_list_security_groups_list_all_tenants_filter(self):
+        # Admin can list security groups of all tenants
+        # List of all security groups created
+        security_group_list = []
+        # Create two security groups for a non-admin tenant
+        for i in range(2):
+            name = data_utils.rand_name('securitygroup-')
+            description = data_utils.rand_name('description-')
+            resp, securitygroup = (self.client
+                                   .create_security_group(name, description))
+            self.assertEqual(200, resp.status)
+            self.addCleanup(self._delete_security_group,
+                            securitygroup['id'], admin=False)
+            security_group_list.append(securitygroup)
+
+        client_tenant_id = securitygroup['tenant_id']
+        # Create two security groups for admin tenant
+        for i in range(2):
+            name = data_utils.rand_name('securitygroup-')
+            description = data_utils.rand_name('description-')
+            resp, adm_securitygroup = (self.adm_client
+                                       .create_security_group(name,
+                                                              description))
+            self.assertEqual(200, resp.status)
+            self.addCleanup(self._delete_security_group,
+                            adm_securitygroup['id'])
+            security_group_list.append(adm_securitygroup)
+
+        # Fetch all security groups based on 'all_tenants' search filter
+        param = {'all_tenants': 'true'}
+        resp, fetched_list = self.adm_client.list_security_groups(params=param)
+        self.assertEqual(200, resp.status)
+        sec_group_id_list = map(lambda sg: sg['id'], fetched_list)
+        # Now check if all created Security Groups are present in fetched list
+        for sec_group in security_group_list:
+            self.assertIn(sec_group['id'], sec_group_id_list)
+
+        # Fetch all security groups for non-admin user with 'all_tenants'
+        # search filter
+        resp, fetched_list = self.client.list_security_groups(params=param)
+        self.assertEqual(200, resp.status)
+        # Now check if all created Security Groups are present in fetched list
+        for sec_group in fetched_list:
+            self.assertEqual(sec_group['tenant_id'], client_tenant_id,
+                             "Failed to get all security groups for "
+                             "non admin user.")
+
+
+class SecurityGroupsTestAdminXML(SecurityGroupsTestAdminJSON):
+    _interface = 'xml'
diff --git a/tempest/api/compute/admin/test_servers.py b/tempest/api/compute/admin/test_servers.py
index 5028cad..6fe3186 100644
--- a/tempest/api/compute/admin/test_servers.py
+++ b/tempest/api/compute/admin/test_servers.py
@@ -33,11 +33,8 @@
     def setUpClass(cls):
         super(ServersAdminTestJSON, cls).setUpClass()
         cls.client = cls.os_adm.servers_client
+        cls.non_admin_client = cls.servers_client
         cls.flavors_client = cls.os_adm.flavors_client
-        cls.identity_client = cls._get_identity_admin_client()
-        tenant = cls.identity_client.get_tenant_by_name(
-            cls.client.tenant_name)
-        cls.tenant_id = tenant['id']
 
         cls.s1_name = data_utils.rand_name('server')
         resp, server = cls.create_test_server(name=cls.s1_name,
@@ -116,6 +113,34 @@
         for key in basic_attrs:
             self.assertIn(key, str(diagnostic.keys()))
 
+    @attr(type='gate')
+    def test_rebuild_server_in_error_state(self):
+        # The server in error state should be rebuilt using the provided
+        # image and changed to ACTIVE state
+
+        # resetting vm state require admin priviledge
+        resp, server = self.client.reset_state(self.s1_id, state='error')
+        self.assertEqual(202, resp.status)
+        resp, rebuilt_server = self.non_admin_client.rebuild(
+            self.s1_id, self.image_ref_alt)
+        self.addCleanup(self.non_admin_client.wait_for_server_status,
+                        self.s1_id, 'ACTIVE')
+        self.addCleanup(self.non_admin_client.rebuild, self.s1_id,
+                        self.image_ref)
+
+        # Verify the properties in the initial response are correct
+        self.assertEqual(self.s1_id, rebuilt_server['id'])
+        rebuilt_image_id = rebuilt_server['image']['id']
+        self.assertEqual(self.image_ref_alt, rebuilt_image_id)
+        self.assertEqual(self.flavor_ref, rebuilt_server['flavor']['id'])
+        self.non_admin_client.wait_for_server_status(rebuilt_server['id'],
+                                                     'ACTIVE',
+                                                     raise_on_error=False)
+        # Verify the server properties after rebuilding
+        resp, server = self.non_admin_client.get_server(rebuilt_server['id'])
+        rebuilt_image_id = server['image']['id']
+        self.assertEqual(self.image_ref_alt, rebuilt_image_id)
+
 
 class ServersAdminTestXML(ServersAdminTestJSON):
     _interface = 'xml'
diff --git a/tempest/api/compute/admin/test_services.py b/tempest/api/compute/admin/test_services.py
index 327d8b8..6122758 100644
--- a/tempest/api/compute/admin/test_services.py
+++ b/tempest/api/compute/admin/test_services.py
@@ -17,7 +17,6 @@
 #    under the License.
 
 from tempest.api.compute import base
-from tempest import exceptions
 from tempest.test import attr
 
 
@@ -41,11 +40,6 @@
         self.assertEqual(200, resp.status)
         self.assertNotEqual(0, len(services))
 
-    @attr(type=['negative', 'gate'])
-    def test_list_services_with_non_admin_user(self):
-        self.assertRaises(exceptions.Unauthorized,
-                          self.non_admin_client.list_services)
-
     @attr(type='gate')
     def test_get_service_by_service_binary_name(self):
         binary_name = 'nova-compute'
@@ -74,15 +68,6 @@
         # on order.
         self.assertEqual(sorted(s1), sorted(s2))
 
-    @attr(type=['negative', 'gate'])
-    def test_get_service_by_invalid_params(self):
-        # return all services if send the request with invalid parameter
-        resp, services = self.client.list_services()
-        params = {'xxx': 'nova-compute'}
-        resp, services_xxx = self.client.list_services(params)
-        self.assertEqual(200, resp.status)
-        self.assertEqual(len(services), len(services_xxx))
-
     @attr(type='gate')
     def test_get_service_by_service_and_host_name(self):
         resp, services = self.client.list_services()
@@ -95,41 +80,6 @@
         self.assertEqual(host_name, services[0]['host'])
         self.assertEqual(binary_name, services[0]['binary'])
 
-    @attr(type=['negative', 'gate'])
-    def test_get_service_by_invalid_service_and_valid_host(self):
-        resp, services = self.client.list_services()
-        host_name = services[0]['host']
-        params = {'host': host_name, 'binary': 'xxx'}
-        resp, services = self.client.list_services(params)
-        self.assertEqual(200, resp.status)
-        self.assertEqual(0, len(services))
-
-    @attr(type=['negative', 'gate'])
-    def test_get_service_with_valid_service_and_invalid_host(self):
-        resp, services = self.client.list_services()
-        binary_name = services[0]['binary']
-        params = {'host': 'xxx', 'binary': binary_name}
-        resp, services = self.client.list_services(params)
-        self.assertEqual(200, resp.status)
-        self.assertEqual(0, len(services))
-
-    @attr(type='gate')
-    def test_service_enable_disable(self):
-        resp, services = self.client.list_services()
-        host_name = services[0]['host']
-        binary_name = services[0]['binary']
-
-        resp, service = self.client.disable_service(host_name, binary_name)
-        self.assertEqual(200, resp.status)
-        params = {'host': host_name, 'binary': binary_name}
-        resp, services = self.client.list_services(params)
-        self.assertEqual('disabled', services[0]['status'])
-
-        resp, service = self.client.enable_service(host_name, binary_name)
-        self.assertEqual(200, resp.status)
-        resp, services = self.client.list_services(params)
-        self.assertEqual('enabled', services[0]['status'])
-
 
 class ServicesAdminTestXML(ServicesAdminTestJSON):
     _interface = 'xml'
diff --git a/tempest/api/compute/admin/test_services_negative.py b/tempest/api/compute/admin/test_services_negative.py
new file mode 100644
index 0000000..da1482e
--- /dev/null
+++ b/tempest/api/compute/admin/test_services_negative.py
@@ -0,0 +1,70 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+#
+# Copyright 2013 NEC Corporation.  All rights reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.api.compute import base
+from tempest import exceptions
+from tempest.test import attr
+
+
+class ServicesAdminNegativeTestJSON(base.BaseV2ComputeAdminTest):
+
+    """
+    Tests Services API. List and Enable/Disable require admin privileges.
+    """
+
+    _interface = 'json'
+
+    @classmethod
+    def setUpClass(cls):
+        super(ServicesAdminNegativeTestJSON, cls).setUpClass()
+        cls.client = cls.os_adm.services_client
+        cls.non_admin_client = cls.services_client
+
+    @attr(type=['negative', 'gate'])
+    def test_list_services_with_non_admin_user(self):
+        self.assertRaises(exceptions.Unauthorized,
+                          self.non_admin_client.list_services)
+
+    @attr(type=['negative', 'gate'])
+    def test_get_service_by_invalid_params(self):
+        # return all services if send the request with invalid parameter
+        resp, services = self.client.list_services()
+        params = {'xxx': 'nova-compute'}
+        resp, services_xxx = self.client.list_services(params)
+        self.assertEqual(200, resp.status)
+        self.assertEqual(len(services), len(services_xxx))
+
+    @attr(type=['negative', 'gate'])
+    def test_get_service_by_invalid_service_and_valid_host(self):
+        resp, services = self.client.list_services()
+        host_name = services[0]['host']
+        params = {'host': host_name, 'binary': 'xxx'}
+        resp, services = self.client.list_services(params)
+        self.assertEqual(200, resp.status)
+        self.assertEqual(0, len(services))
+
+    @attr(type=['negative', 'gate'])
+    def test_get_service_with_valid_service_and_invalid_host(self):
+        resp, services = self.client.list_services()
+        binary_name = services[0]['binary']
+        params = {'host': 'xxx', 'binary': binary_name}
+        resp, services = self.client.list_services(params)
+        self.assertEqual(200, resp.status)
+        self.assertEqual(0, len(services))
+
+
+class ServicesAdminNegativeTestXML(ServicesAdminNegativeTestJSON):
+    _interface = 'xml'
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index 7ef5466..d18b749 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -17,7 +17,6 @@
 
 import time
 
-from tempest.api import compute
 from tempest import clients
 from tempest.common.utils import data_utils
 from tempest import exceptions
@@ -31,7 +30,6 @@
 class BaseComputeTest(tempest.test.BaseTestCase):
     """Base test case class for all Compute API tests."""
 
-    conclusion = compute.generic_setup_package()
     force_tenant_isolation = False
 
     @classmethod
@@ -55,6 +53,30 @@
         cls.image_ssh_password = cls.config.compute.image_ssh_password
         cls.servers = []
         cls.images = []
+        cls.multi_user = cls.get_multi_user()
+
+    @classmethod
+    def get_multi_user(cls):
+        multi_user = True
+        # Determine if there are two regular users that can be
+        # used in testing. If the test cases are allowed to create
+        # users (config.compute.allow_tenant_isolation is true,
+        # then we allow multi-user.
+        if not cls.config.compute.allow_tenant_isolation:
+            user1 = cls.config.identity.username
+            user2 = cls.config.identity.alt_username
+            if not user2 or user1 == user2:
+                multi_user = False
+            else:
+                user2_password = cls.config.identity.alt_password
+                user2_tenant_name = cls.config.identity.alt_tenant_name
+                if not user2_password or not user2_tenant_name:
+                    msg = ("Alternate user specified but not alternate "
+                           "tenant or password: alt_tenant_name=%s "
+                           "alt_password=%s"
+                           % (user2_tenant_name, user2_password))
+                    raise exceptions.InvalidConfiguration(msg)
+        return multi_user
 
     @classmethod
     def clear_servers(cls):
@@ -178,20 +200,26 @@
                                                     kwargs['wait_until'])
             resp, image = cls.images_client.get_image(image_id)
 
+            if kwargs['wait_until'] == 'ACTIVE':
+                if kwargs.get('wait_for_server', True):
+                    cls.servers_client.wait_for_server_status(server_id,
+                                                              'ACTIVE')
+
         return resp, image
 
     @classmethod
-    def rebuild_server(cls, **kwargs):
+    def rebuild_server(cls, server_id, **kwargs):
         # Destroy an existing server and creates a new one
-        try:
-            cls.servers_client.delete_server(cls.server_id)
-            cls.servers_client.wait_for_server_termination(cls.server_id)
-        except Exception as exc:
-            LOG.exception(exc)
-            pass
+        if server_id:
+            try:
+                cls.servers_client.delete_server(server_id)
+                cls.servers_client.wait_for_server_termination(server_id)
+            except Exception as exc:
+                LOG.exception(exc)
+                pass
         resp, server = cls.create_test_server(wait_until='ACTIVE', **kwargs)
-        cls.server_id = server['id']
         cls.password = server['adminPass']
+        return server['id']
 
 
 class BaseV2ComputeAdminTest(BaseV2ComputeTest):
@@ -237,6 +265,8 @@
         cls.availability_zone_client = cls.os.availability_zone_v3_client
         cls.interfaces_client = cls.os.interfaces_v3_client
         cls.hypervisor_client = cls.os.hypervisor_v3_client
+        cls.tenant_usages_client = cls.os.tenant_usages_v3_client
+        cls.volumes_client = cls.os.volumes_client
 
     @classmethod
     def create_image_from_server(cls, server_id, **kwargs):
@@ -258,17 +288,17 @@
         return resp, image
 
     @classmethod
-    def rebuild_server(cls, **kwargs):
+    def rebuild_server(cls, server_id, **kwargs):
         # Destroy an existing server and creates a new one
         try:
-            cls.servers_client.delete_server(cls.server_id)
-            cls.servers_client.wait_for_server_termination(cls.server_id)
+            cls.servers_client.delete_server(server_id)
+            cls.servers_client.wait_for_server_termination(server_id)
         except Exception as exc:
             LOG.exception(exc)
             pass
         resp, server = cls.create_test_server(wait_until='ACTIVE', **kwargs)
-        cls.server_id = server['id']
         cls.password = server['admin_password']
+        return server['id']
 
 
 class BaseV3ComputeAdminTest(BaseV3ComputeTest):
@@ -300,3 +330,4 @@
         cls.availability_zone_admin_client = \
             cls.os_adm.availability_zone_v3_client
         cls.hypervisor_admin_client = cls.os_adm.hypervisor_v3_client
+        cls.tenant_usages_admin_client = cls.os_adm.tenant_usages_v3_client
diff --git a/tempest/api/compute/flavors/test_flavors.py b/tempest/api/compute/flavors/test_flavors.py
index fa99422..092fd65 100644
--- a/tempest/api/compute/flavors/test_flavors.py
+++ b/tempest/api/compute/flavors/test_flavors.py
@@ -16,7 +16,6 @@
 #    under the License.
 
 from tempest.api.compute import base
-from tempest import exceptions
 from tempest.test import attr
 
 
@@ -50,12 +49,6 @@
         resp, flavor = self.client.get_flavor_details(self.flavor_ref)
         self.assertEqual(self.flavor_ref, flavor['id'])
 
-    @attr(type=['negative', 'gate'])
-    def test_get_non_existant_flavor(self):
-        # flavor details are not returned for non-existent flavors
-        self.assertRaises(exceptions.NotFound, self.client.get_flavor_details,
-                          999)
-
     @attr(type='gate')
     def test_list_flavors_limit_results(self):
         # Only the expected number of flavors should be returned
@@ -136,24 +129,6 @@
         resp, flavors = self.client.list_flavors(params)
         self.assertFalse(any([i for i in flavors if i['id'] == flavor_id]))
 
-    @attr(type=['negative', 'gate'])
-    def test_invalid_minRam_filter(self):
-        self.assertRaises(exceptions.BadRequest,
-                          self.client.list_flavors_with_detail,
-                          {'minRam': 'invalid'})
-
-    @attr(type=['negative', 'gate'])
-    def test_invalid_minDisk_filter(self):
-        self.assertRaises(exceptions.BadRequest,
-                          self.client.list_flavors_with_detail,
-                          {'minDisk': 'invalid'})
-
-    @attr(type=['negative', 'gate'])
-    def test_get_flavor_details_for_invalid_flavor_id(self):
-        # Ensure 404 returned for non-existent flavor ID
-        self.assertRaises(exceptions.NotFound, self.client.get_flavor_details,
-                          9999)
-
 
 class FlavorsTestXML(FlavorsTestJSON):
     _interface = 'xml'
diff --git a/tempest/api/compute/flavors/test_flavors_negative.py b/tempest/api/compute/flavors/test_flavors_negative.py
new file mode 100644
index 0000000..0b20e90
--- /dev/null
+++ b/tempest/api/compute/flavors/test_flavors_negative.py
@@ -0,0 +1,54 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 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.
+
+import uuid
+
+from tempest.api.compute import base
+from tempest import exceptions
+from tempest.test import attr
+
+
+class FlavorsNegativeTestJSON(base.BaseV2ComputeTest):
+    _interface = 'json'
+
+    @classmethod
+    def setUpClass(cls):
+        super(FlavorsNegativeTestJSON, cls).setUpClass()
+        cls.client = cls.flavors_client
+
+    @attr(type=['negative', 'gate'])
+    def test_invalid_minRam_filter(self):
+        self.assertRaises(exceptions.BadRequest,
+                          self.client.list_flavors_with_detail,
+                          {'minRam': 'invalid'})
+
+    @attr(type=['negative', 'gate'])
+    def test_invalid_minDisk_filter(self):
+        self.assertRaises(exceptions.BadRequest,
+                          self.client.list_flavors_with_detail,
+                          {'minDisk': 'invalid'})
+
+    @attr(type=['negative', 'gate'])
+    def test_non_existent_flavor_id(self):
+        # flavor details are not returned for non-existent flavors
+        nonexistent_flavor_id = str(uuid.uuid4())
+        self.assertRaises(exceptions.NotFound, self.client.get_flavor_details,
+                          nonexistent_flavor_id)
+
+
+class FlavorsNegativeTestXML(FlavorsNegativeTestJSON):
+    _interface = 'xml'
diff --git a/tempest/api/compute/floating_ips/test_floating_ips_actions.py b/tempest/api/compute/floating_ips/test_floating_ips_actions.py
index a06309a..f4ad449 100644
--- a/tempest/api/compute/floating_ips/test_floating_ips_actions.py
+++ b/tempest/api/compute/floating_ips/test_floating_ips_actions.py
@@ -15,10 +15,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import uuid
-
 from tempest.api.compute import base
-from tempest.common.utils import data_utils
+from tempest.common.utils.data_utils import rand_name
 from tempest import exceptions
 from tempest.test import attr
 
@@ -32,7 +30,7 @@
     def setUpClass(cls):
         super(FloatingIPsTestJSON, cls).setUpClass()
         cls.client = cls.floating_ips_client
-        cls.servers_client = cls.servers_client
+        #cls.servers_client = cls.servers_client
 
         # Server creation
         resp, server = cls.create_test_server(wait_until='ACTIVE')
@@ -41,17 +39,6 @@
         resp, body = cls.client.create_floating_ip()
         cls.floating_ip_id = body['id']
         cls.floating_ip = body['ip']
-        # Generating a nonexistent floatingIP id
-        cls.floating_ip_ids = []
-        resp, body = cls.client.list_floating_ips()
-        for i in range(len(body)):
-            cls.floating_ip_ids.append(body[i]['id'])
-        while True:
-            cls.non_exist_id = data_utils.rand_int_id(start=999)
-            if cls.config.service_available.neutron:
-                cls.non_exist_id = str(uuid.uuid4())
-            if cls.non_exist_id not in cls.floating_ip_ids:
-                break
 
     @classmethod
     def tearDownClass(cls):
@@ -76,14 +63,6 @@
             # Deleting the floating IP which is created in this method
             self.client.delete_floating_ip(floating_ip_id_allocated)
 
-    @attr(type=['negative', 'gate'])
-    def test_allocate_floating_ip_from_nonexistent_pool(self):
-        # Positive test:Allocation of a new floating IP from a nonexistent_pool
-        # to a project should fail
-        self.assertRaises(exceptions.NotFound,
-                          self.client.create_floating_ip,
-                          "non_exist_pool")
-
     @attr(type='gate')
     def test_delete_floating_ip(self):
         # Positive test:Deletion of valid floating IP from project
@@ -115,38 +94,13 @@
             self.server_id)
         self.assertEqual(202, resp.status)
 
-    @attr(type=['negative', 'gate'])
-    def test_delete_nonexistant_floating_ip(self):
-        # Negative test:Deletion of a nonexistent floating IP
-        # from project should fail
-
-        # Deleting the non existent floating IP
-        self.assertRaises(exceptions.NotFound, self.client.delete_floating_ip,
-                          self.non_exist_id)
-
-    @attr(type=['negative', 'gate'])
-    def test_associate_nonexistant_floating_ip(self):
-        # Negative test:Association of a non existent floating IP
-        # to specific server should fail
-        # Associating non existent floating IP
-        self.assertRaises(exceptions.NotFound,
-                          self.client.associate_floating_ip_to_server,
-                          "0.0.0.0", self.server_id)
-
-    @attr(type=['negative', 'gate'])
-    def test_dissociate_nonexistant_floating_ip(self):
-        # Negative test:Dissociation of a non existent floating IP should fail
-        # Dissociating non existent floating IP
-        self.assertRaises(exceptions.NotFound,
-                          self.client.disassociate_floating_ip_from_server,
-                          "0.0.0.0", self.server_id)
-
     @attr(type='gate')
     def test_associate_already_associated_floating_ip(self):
         # positive test:Association of an already associated floating IP
         # to specific server should change the association of the Floating IP
         # Create server so as to use for Multiple association
-        resp, body = self.servers_client.create_server('floating-server2',
+        new_name = rand_name('floating_server')
+        resp, body = self.servers_client.create_server(new_name,
                                                        self.image_ref,
                                                        self.flavor_ref)
         self.servers_client.wait_for_server_status(body['id'], 'ACTIVE')
@@ -173,14 +127,6 @@
                           self.client.disassociate_floating_ip_from_server,
                           self.floating_ip, self.server_id)
 
-    @attr(type=['negative', 'gate'])
-    def test_associate_ip_to_server_without_passing_floating_ip(self):
-        # Negative test:Association of empty floating IP to specific server
-        # should raise NotFound exception
-        self.assertRaises(exceptions.NotFound,
-                          self.client.associate_floating_ip_to_server,
-                          '', self.server_id)
-
 
 class FloatingIPsTestXML(FloatingIPsTestJSON):
     _interface = 'xml'
diff --git a/tempest/api/compute/floating_ips/test_floating_ips_actions_negative.py b/tempest/api/compute/floating_ips/test_floating_ips_actions_negative.py
new file mode 100644
index 0000000..89315bb
--- /dev/null
+++ b/tempest/api/compute/floating_ips/test_floating_ips_actions_negative.py
@@ -0,0 +1,94 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# 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.
+
+import uuid
+
+from tempest.api.compute import base
+from tempest.common.utils import data_utils
+from tempest import exceptions
+from tempest.test import attr
+
+
+class FloatingIPsNegativeTestJSON(base.BaseV2ComputeTest):
+    _interface = 'json'
+    server_id = None
+
+    @classmethod
+    def setUpClass(cls):
+        super(FloatingIPsNegativeTestJSON, cls).setUpClass()
+        cls.client = cls.floating_ips_client
+
+        # Server creation
+        resp, server = cls.create_test_server(wait_until='ACTIVE')
+        cls.server_id = server['id']
+        # Generating a nonexistent floatingIP id
+        cls.floating_ip_ids = []
+        resp, body = cls.client.list_floating_ips()
+        for i in range(len(body)):
+            cls.floating_ip_ids.append(body[i]['id'])
+        while True:
+            cls.non_exist_id = data_utils.rand_int_id(start=999)
+            if cls.config.service_available.neutron:
+                cls.non_exist_id = str(uuid.uuid4())
+            if cls.non_exist_id not in cls.floating_ip_ids:
+                break
+
+    @attr(type=['negative', 'gate'])
+    def test_allocate_floating_ip_from_nonexistent_pool(self):
+        # Negative test:Allocation of a new floating IP from a nonexistent_pool
+        # to a project should fail
+        self.assertRaises(exceptions.NotFound,
+                          self.client.create_floating_ip,
+                          "non_exist_pool")
+
+    @attr(type=['negative', 'gate'])
+    def test_delete_nonexistent_floating_ip(self):
+        # Negative test:Deletion of a nonexistent floating IP
+        # from project should fail
+
+        # Deleting the non existent floating IP
+        self.assertRaises(exceptions.NotFound, self.client.delete_floating_ip,
+                          self.non_exist_id)
+
+    @attr(type=['negative', 'gate'])
+    def test_associate_nonexistent_floating_ip(self):
+        # Negative test:Association of a non existent floating IP
+        # to specific server should fail
+        # Associating non existent floating IP
+        self.assertRaises(exceptions.NotFound,
+                          self.client.associate_floating_ip_to_server,
+                          "0.0.0.0", self.server_id)
+
+    @attr(type=['negative', 'gate'])
+    def test_dissociate_nonexistent_floating_ip(self):
+        # Negative test:Dissociation of a non existent floating IP should fail
+        # Dissociating non existent floating IP
+        self.assertRaises(exceptions.NotFound,
+                          self.client.disassociate_floating_ip_from_server,
+                          "0.0.0.0", self.server_id)
+
+    @attr(type=['negative', 'gate'])
+    def test_associate_ip_to_server_without_passing_floating_ip(self):
+        # Negative test:Association of empty floating IP to specific server
+        # should raise NotFound exception
+        self.assertRaises(exceptions.NotFound,
+                          self.client.associate_floating_ip_to_server,
+                          '', self.server_id)
+
+
+class FloatingIPsNegativeTestXML(FloatingIPsNegativeTestJSON):
+    _interface = 'xml'
diff --git a/tempest/api/compute/images/test_images.py b/tempest/api/compute/images/test_images.py
index 4539981..f7db89b 100644
--- a/tempest/api/compute/images/test_images.py
+++ b/tempest/api/compute/images/test_images.py
@@ -14,7 +14,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest.api import compute
 from tempest.api.compute import base
 from tempest import clients
 from tempest.common.utils import data_utils
@@ -36,7 +35,7 @@
 
         cls.image_ids = []
 
-        if compute.MULTI_USER:
+        if cls.multi_user:
             if cls.config.compute.allow_tenant_isolation:
                 creds = cls.isolated_creds.get_alt_creds()
                 username, tenant_name, password = creds
@@ -98,7 +97,8 @@
         snapshot_name = data_utils.rand_name('test-snap-')
         resp, image = self.create_image_from_server(server['id'],
                                                     name=snapshot_name,
-                                                    wait_until='ACTIVE')
+                                                    wait_until='ACTIVE',
+                                                    wait_for_server=False)
         self.addCleanup(self.client.delete_image, image['id'])
         self.assertEqual(snapshot_name, image['name'])
 
diff --git a/tempest/api/compute/images/test_images_oneserver.py b/tempest/api/compute/images/test_images_oneserver.py
index 612c110..6e4c8cb 100644
--- a/tempest/api/compute/images/test_images_oneserver.py
+++ b/tempest/api/compute/images/test_images_oneserver.py
@@ -49,7 +49,7 @@
             LOG.exception(exc)
             # Rebuild server if cannot reach the ACTIVE state
             # Usually it means the server had a serius accident
-            self.rebuild_server()
+            self.__class__.server_id = self.rebuild_server(self.server_id)
 
     @classmethod
     def setUpClass(cls):
@@ -68,7 +68,7 @@
 
         cls.image_ids = []
 
-        if compute.MULTI_USER:
+        if cls.multi_user:
             if cls.config.compute.allow_tenant_isolation:
                 creds = cls.isolated_creds.get_alt_creds()
                 username, tenant_name, password = creds
@@ -117,6 +117,20 @@
         self.assertEqual('204', resp['status'])
         self.client.wait_for_resource_deletion(image_id)
 
+    @attr(type=['gate'])
+    def test_create_image_specify_multibyte_character_image_name(self):
+        if self.__class__._interface == "xml":
+            # NOTE(sdague): not entirely accurage, but we'd need a ton of work
+            # in our XML client to make this good
+            raise self.skipException("Not testable in XML")
+        # prefix character is:
+        # http://www.fileformat.info/info/unicode/char/1F4A9/index.htm
+        utf8_name = data_utils.rand_name(u'\xF0\x9F\x92\xA9')
+        resp, body = self.client.create_image(self.server_id, utf8_name)
+        image_id = data_utils.parse_image_id(resp['location'])
+        self.addCleanup(self.client.delete_image, image_id)
+        self.assertEqual('202', resp['status'])
+
 
 class ImagesOneServerTestXML(ImagesOneServerTestJSON):
     _interface = 'xml'
diff --git a/tempest/api/compute/images/test_images_oneserver_negative.py b/tempest/api/compute/images/test_images_oneserver_negative.py
index b4e778c..b8a4304 100644
--- a/tempest/api/compute/images/test_images_oneserver_negative.py
+++ b/tempest/api/compute/images/test_images_oneserver_negative.py
@@ -16,7 +16,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest.api import compute
 from tempest.api.compute import base
 from tempest import clients
 from tempest.common.utils import data_utils
@@ -50,7 +49,10 @@
             LOG.exception(exc)
             # Rebuild server if cannot reach the ACTIVE state
             # Usually it means the server had a serius accident
-            self.rebuild_server()
+            self._reset_server()
+
+    def _reset_server(self):
+        self.__class__.server_id = self.rebuild_server(self.server_id)
 
     @classmethod
     def setUpClass(cls):
@@ -69,7 +71,7 @@
 
         cls.image_ids = []
 
-        if compute.MULTI_USER:
+        if cls.multi_user:
             if cls.config.compute.allow_tenant_isolation:
                 creds = cls.isolated_creds.get_alt_creds()
                 username, tenant_name, password = creds
@@ -84,11 +86,15 @@
     @skip_because(bug="1006725")
     @attr(type=['negative', 'gate'])
     def test_create_image_specify_multibyte_character_image_name(self):
-        # Return an error if the image name has multi-byte characters
-        snapshot_name = data_utils.rand_name('\xef\xbb\xbf')
+        if self.__class__._interface == "xml":
+            raise self.skipException("Not testable in XML")
+        # invalid multibyte sequence from:
+        # http://stackoverflow.com/questions/1301402/
+        #     example-invalid-utf8-string
+        invalid_name = data_utils.rand_name(u'\xc3\x28')
         self.assertRaises(exceptions.BadRequest,
                           self.client.create_image, self.server_id,
-                          snapshot_name)
+                          invalid_name)
 
     @attr(type=['negative', 'gate'])
     def test_create_image_specify_invalid_metadata(self):
@@ -117,12 +123,12 @@
         self.assertEqual(202, resp.status)
         image_id = data_utils.parse_image_id(resp['location'])
         self.image_ids.append(image_id)
+        self.addCleanup(self._reset_server)
 
         # Create second snapshot
         alt_snapshot_name = data_utils.rand_name('test-snap-')
         self.assertRaises(exceptions.Conflict, self.client.create_image,
                           self.server_id, alt_snapshot_name)
-        self.client.wait_for_image_status(image_id, 'ACTIVE')
 
     @attr(type=['negative', 'gate'])
     def test_create_image_specify_name_over_256_chars(self):
@@ -141,6 +147,7 @@
         self.assertEqual(202, resp.status)
         image_id = data_utils.parse_image_id(resp['location'])
         self.image_ids.append(image_id)
+        self.addCleanup(self._reset_server)
 
         # Do not wait, attempt to delete the image, ensure it's successful
         resp, body = self.client.delete_image(image_id)
diff --git a/tempest/api/compute/images/test_list_image_filters.py b/tempest/api/compute/images/test_list_image_filters.py
index 1401654..ac2ecba 100644
--- a/tempest/api/compute/images/test_list_image_filters.py
+++ b/tempest/api/compute/images/test_list_image_filters.py
@@ -16,7 +16,6 @@
 #    under the License.
 
 from tempest.api.compute import base
-from tempest.common.utils import data_utils
 from tempest import exceptions
 from tempest.openstack.common import log as logging
 from tempest.test import attr
@@ -45,24 +44,21 @@
                                                       'ACTIVE')
 
             # Create images to be used in the filter tests
-            resp, body = cls.create_image_from_server(cls.server1['id'])
-            cls.image1_id = data_utils.parse_image_id(resp['location'])
-            cls.client.wait_for_image_status(cls.image1_id, 'ACTIVE')
-            resp, cls.image1 = cls.client.get_image(cls.image1_id)
+            resp, cls.image1 = cls.create_image_from_server(
+                cls.server1['id'], wait_until='ACTIVE')
+            cls.image1_id = cls.image1['id']
 
             # Servers have a hidden property for when they are being imaged
             # Performing back-to-back create image calls on a single
             # server will sometimes cause failures
-            resp, body = cls.create_image_from_server(cls.server2['id'])
-            cls.image3_id = data_utils.parse_image_id(resp['location'])
-            cls.client.wait_for_image_status(cls.image3_id, 'ACTIVE')
-            resp, cls.image3 = cls.client.get_image(cls.image3_id)
+            resp, cls.image3 = cls.create_image_from_server(
+                cls.server2['id'], wait_until='ACTIVE')
+            cls.image3_id = cls.image3['id']
 
-            resp, body = cls.create_image_from_server(cls.server1['id'])
-            cls.image2_id = data_utils.parse_image_id(resp['location'])
-
-            cls.client.wait_for_image_status(cls.image2_id, 'ACTIVE')
-            resp, cls.image2 = cls.client.get_image(cls.image2_id)
+            # Wait for the server to be active after the image upload
+            resp, cls.image2 = cls.create_image_from_server(
+                cls.server1['id'], wait_until='ACTIVE')
+            cls.image2_id = cls.image2['id']
         except Exception as exc:
             LOG.exception(exc)
             cls.tearDownClass()
diff --git a/tempest/api/compute/keypairs/test_keypairs.py b/tempest/api/compute/keypairs/test_keypairs.py
index 50b6c77..b36595c 100644
--- a/tempest/api/compute/keypairs/test_keypairs.py
+++ b/tempest/api/compute/keypairs/test_keypairs.py
@@ -17,7 +17,7 @@
 
 from tempest.api.compute import base
 from tempest.common.utils import data_utils
-from tempest.test import attr
+from tempest import test
 
 
 class KeyPairsTestJSON(base.BaseV2ComputeTest):
@@ -28,14 +28,23 @@
         super(KeyPairsTestJSON, cls).setUpClass()
         cls.client = cls.keypairs_client
 
-    @attr(type='gate')
+    def _delete_keypair(self, keypair_name):
+        resp, _ = self.client.delete_keypair(keypair_name)
+        self.assertEqual(202, resp.status)
+
+    def _create_keypair(self, keypair_name, pub_key=None):
+        resp, body = self.client.create_keypair(keypair_name, pub_key)
+        self.addCleanup(self._delete_keypair, keypair_name)
+        return resp, body
+
+    @test.attr(type='gate')
     def test_keypairs_create_list_delete(self):
         # Keypairs created should be available in the response list
         # Create 3 keypairs
         key_list = list()
         for i in range(3):
             k_name = data_utils.rand_name('keypair-')
-            resp, keypair = self.client.create_keypair(k_name)
+            resp, keypair = self._create_keypair(k_name)
             # Need to pop these keys so that our compare doesn't fail later,
             # as the keypair dicts from list API doesn't have them.
             keypair.pop('private_key')
@@ -57,16 +66,12 @@
         self.assertFalse(missing_kps,
                          "Failed to find keypairs %s in fetched list"
                          % ', '.join(m_key['name'] for m_key in missing_kps))
-        # Delete all the keypairs created
-        for keypair in key_list:
-            resp, _ = self.client.delete_keypair(keypair['name'])
-            self.assertEqual(202, resp.status)
 
-    @attr(type='gate')
+    @test.attr(type='gate')
     def test_keypair_create_delete(self):
         # Keypair should be created, verified and deleted
         k_name = data_utils.rand_name('keypair-')
-        resp, keypair = self.client.create_keypair(k_name)
+        resp, keypair = self._create_keypair(k_name)
         self.assertEqual(200, resp.status)
         private_key = keypair['private_key']
         key_name = keypair['name']
@@ -75,15 +80,12 @@
                          "to the requested name")
         self.assertTrue(private_key is not None,
                         "Field private_key is empty or not found.")
-        resp, _ = self.client.delete_keypair(k_name)
-        self.assertEqual(202, resp.status)
 
-    @attr(type='gate')
+    @test.attr(type='gate')
     def test_get_keypair_detail(self):
         # Keypair should be created, Got details by name and deleted
         k_name = data_utils.rand_name('keypair-')
-        resp, keypair = self.client.create_keypair(k_name)
-        self.addCleanup(self.client.delete_keypair, k_name)
+        resp, keypair = self._create_keypair(k_name)
         resp, keypair_detail = self.client.get_keypair(k_name)
         self.assertEqual(200, resp.status)
         self.assertIn('name', keypair_detail)
@@ -95,7 +97,7 @@
         self.assertTrue(public_key is not None,
                         "Field public_key is empty or not found.")
 
-    @attr(type='gate')
+    @test.attr(type='gate')
     def test_keypair_create_with_pub_key(self):
         # Keypair should be created with a given public key
         k_name = data_utils.rand_name('keypair-')
@@ -108,7 +110,7 @@
                    "LOeB1kYMOBaiUPLQTWXR3JpckqFIQwhIH0zoHlJvZE8hh90"
                    "XcPojYN56tI0OlrGqojbediJYD0rUsJu4weZpbn8vilb3JuDY+jws"
                    "snSA8wzBx3A/8y9Pp1B nova@ubuntu")
-        resp, keypair = self.client.create_keypair(k_name, pub_key)
+        resp, keypair = self._create_keypair(k_name, pub_key)
         self.assertEqual(200, resp.status)
         self.assertFalse('private_key' in keypair,
                          "Field private_key is not empty!")
@@ -116,8 +118,6 @@
         self.assertEqual(key_name, k_name,
                          "The created keypair name is not equal "
                          "to the requested name!")
-        resp, _ = self.client.delete_keypair(k_name)
-        self.assertEqual(202, resp.status)
 
 
 class KeyPairsTestXML(KeyPairsTestJSON):
diff --git a/tempest/api/compute/keypairs/test_keypairs_negative.py b/tempest/api/compute/keypairs/test_keypairs_negative.py
index fad985e..621487c 100644
--- a/tempest/api/compute/keypairs/test_keypairs_negative.py
+++ b/tempest/api/compute/keypairs/test_keypairs_negative.py
@@ -19,7 +19,7 @@
 from tempest.api.compute import base
 from tempest.common.utils import data_utils
 from tempest import exceptions
-from tempest.test import attr
+from tempest import test
 
 
 class KeyPairsNegativeTestJSON(base.BaseV2ComputeTest):
@@ -30,67 +30,71 @@
         super(KeyPairsNegativeTestJSON, cls).setUpClass()
         cls.client = cls.keypairs_client
 
-    @attr(type=['negative', 'gate'])
+    def _create_keypair(self, keypair_name, pub_key=None):
+        self.client.create_keypair(keypair_name, pub_key)
+        self.addCleanup(self.client.delete_keypair, keypair_name)
+
+    @test.attr(type=['negative', 'gate'])
     def test_keypair_create_with_invalid_pub_key(self):
         # Keypair should not be created with a non RSA public key
         k_name = data_utils.rand_name('keypair-')
         pub_key = "ssh-rsa JUNK nova@ubuntu"
         self.assertRaises(exceptions.BadRequest,
-                          self.client.create_keypair, k_name, pub_key)
+                          self._create_keypair, k_name, pub_key)
 
-    @attr(type=['negative', 'gate'])
+    @test.attr(type=['negative', 'gate'])
     def test_keypair_delete_nonexistant_key(self):
         # Non-existant key deletion should throw a proper error
         k_name = data_utils.rand_name("keypair-non-existant-")
         self.assertRaises(exceptions.NotFound, self.client.delete_keypair,
                           k_name)
 
-    @attr(type=['negative', 'gate'])
+    @test.attr(type=['negative', 'gate'])
     def test_create_keypair_with_empty_public_key(self):
         # Keypair should not be created with an empty public key
         k_name = data_utils.rand_name("keypair-")
         pub_key = ' '
-        self.assertRaises(exceptions.BadRequest, self.client.create_keypair,
+        self.assertRaises(exceptions.BadRequest, self._create_keypair,
                           k_name, pub_key)
 
-    @attr(type=['negative', 'gate'])
+    @test.attr(type=['negative', 'gate'])
     def test_create_keypair_when_public_key_bits_exceeds_maximum(self):
         # Keypair should not be created when public key bits are too long
         k_name = data_utils.rand_name("keypair-")
         pub_key = 'ssh-rsa ' + 'A' * 2048 + ' openstack@ubuntu'
-        self.assertRaises(exceptions.BadRequest, self.client.create_keypair,
+        self.assertRaises(exceptions.BadRequest, self._create_keypair,
                           k_name, pub_key)
 
-    @attr(type=['negative', 'gate'])
+    @test.attr(type=['negative', 'gate'])
     def test_create_keypair_with_duplicate_name(self):
         # Keypairs with duplicate names should not be created
         k_name = data_utils.rand_name('keypair-')
         resp, _ = self.client.create_keypair(k_name)
         self.assertEqual(200, resp.status)
         # Now try the same keyname to create another key
-        self.assertRaises(exceptions.Conflict, self.client.create_keypair,
+        self.assertRaises(exceptions.Conflict, self._create_keypair,
                           k_name)
         resp, _ = self.client.delete_keypair(k_name)
         self.assertEqual(202, resp.status)
 
-    @attr(type=['negative', 'gate'])
+    @test.attr(type=['negative', 'gate'])
     def test_create_keypair_with_empty_name_string(self):
         # Keypairs with name being an empty string should not be created
-        self.assertRaises(exceptions.BadRequest, self.client.create_keypair,
+        self.assertRaises(exceptions.BadRequest, self._create_keypair,
                           '')
 
-    @attr(type=['negative', 'gate'])
+    @test.attr(type=['negative', 'gate'])
     def test_create_keypair_with_long_keynames(self):
         # Keypairs with name longer than 255 chars should not be created
         k_name = 'keypair-'.ljust(260, '0')
-        self.assertRaises(exceptions.BadRequest, self.client.create_keypair,
+        self.assertRaises(exceptions.BadRequest, self._create_keypair,
                           k_name)
 
-    @attr(type=['negative', 'gate'])
+    @test.attr(type=['negative', 'gate'])
     def test_create_keypair_invalid_name(self):
         # Keypairs with name being an invalid name should not be created
         k_name = 'key_/.\@:'
-        self.assertRaises(exceptions.BadRequest, self.client.create_keypair,
+        self.assertRaises(exceptions.BadRequest, self._create_keypair,
                           k_name)
 
 
diff --git a/tempest/api/compute/servers/test_create_server.py b/tempest/api/compute/servers/test_create_server.py
index 24ade96..cbd0eb1 100644
--- a/tempest/api/compute/servers/test_create_server.py
+++ b/tempest/api/compute/servers/test_create_server.py
@@ -93,13 +93,6 @@
 
     @testtools.skipIf(not run_ssh, 'Instance validation tests are disabled.')
     @attr(type='gate')
-    def test_can_log_into_created_server(self):
-        # Check that the user can authenticate with the generated password
-        linux_client = RemoteClient(self.server, self.ssh_user, self.password)
-        self.assertTrue(linux_client.can_authenticate())
-
-    @testtools.skipIf(not run_ssh, 'Instance validation tests are disabled.')
-    @attr(type='gate')
     def test_verify_created_server_vcpus(self):
         # Verify that the number of vcpus reported by the instance matches
         # the amount stated by the flavor
diff --git a/tempest/api/compute/servers/test_disk_config.py b/tempest/api/compute/servers/test_disk_config.py
index 5e9ee5c..0121c42 100644
--- a/tempest/api/compute/servers/test_disk_config.py
+++ b/tempest/api/compute/servers/test_disk_config.py
@@ -80,7 +80,7 @@
     def _get_alternative_flavor(self):
         resp, server = self.client.get_server(self.server_id)
 
-        if int(server['flavor']['id']) == self.flavor_ref:
+        if server['flavor']['id'] == self.flavor_ref:
             return self.flavor_ref_alt
         else:
             return self.flavor_ref
diff --git a/tempest/api/compute/servers/test_server_actions.py b/tempest/api/compute/servers/test_server_actions.py
index e3441bd..e009888 100644
--- a/tempest/api/compute/servers/test_server_actions.py
+++ b/tempest/api/compute/servers/test_server_actions.py
@@ -45,13 +45,13 @@
             self.client.wait_for_server_status(self.server_id, 'ACTIVE')
         except Exception:
             # Rebuild server if something happened to it during a test
-            self.rebuild_server()
+            self.__class__.server_id = self.rebuild_server(self.server_id)
 
     @classmethod
     def setUpClass(cls):
         super(ServerActionsTestJSON, cls).setUpClass()
         cls.client = cls.servers_client
-        cls.rebuild_server()
+        cls.server_id = cls.rebuild_server(None)
 
     @testtools.skipUnless(compute.CHANGE_PASSWORD_AVAILABLE,
                           'Change password not available.')
@@ -67,7 +67,7 @@
             # Verify that the user can authenticate with the new password
             resp, server = self.client.get_server(self.server_id)
             linux_client = RemoteClient(server, self.ssh_user, new_password)
-            self.assertTrue(linux_client.can_authenticate())
+            linux_client.validate_authentication()
 
     @attr(type='smoke')
     def test_reboot_server_hard(self):
@@ -123,6 +123,7 @@
                                                    metadata=meta,
                                                    personality=personality,
                                                    adminPass=password)
+        self.addCleanup(self.client.rebuild, self.server_id, self.image_ref)
 
         # Verify the properties in the initial response are correct
         self.assertEqual(self.server_id, rebuilt_server['id'])
@@ -133,14 +134,43 @@
         # Verify the server properties after the rebuild completes
         self.client.wait_for_server_status(rebuilt_server['id'], 'ACTIVE')
         resp, server = self.client.get_server(rebuilt_server['id'])
-        rebuilt_image_id = rebuilt_server['image']['id']
+        rebuilt_image_id = server['image']['id']
         self.assertTrue(self.image_ref_alt.endswith(rebuilt_image_id))
-        self.assertEqual(new_name, rebuilt_server['name'])
+        self.assertEqual(new_name, server['name'])
 
         if self.run_ssh:
             # Verify that the user can authenticate with the provided password
             linux_client = RemoteClient(server, self.ssh_user, password)
-            self.assertTrue(linux_client.can_authenticate())
+            linux_client.validate_authentication()
+
+    @attr(type='gate')
+    def test_rebuild_server_in_stop_state(self):
+        # The server in stop state  should be rebuilt using the provided
+        # image and remain in SHUTOFF state
+        resp, server = self.client.get_server(self.server_id)
+        old_image = server['image']['id']
+        new_image = self.image_ref_alt \
+            if old_image == self.image_ref else self.image_ref
+        resp, server = self.client.stop(self.server_id)
+        self.assertEqual(202, resp.status)
+        self.client.wait_for_server_status(self.server_id, 'SHUTOFF')
+        self.addCleanup(self.client.start, self.server_id)
+        resp, rebuilt_server = self.client.rebuild(self.server_id, new_image)
+        self.addCleanup(self.client.wait_for_server_status, self.server_id,
+                        'SHUTOFF')
+        self.addCleanup(self.client.rebuild, self.server_id, old_image)
+
+        # Verify the properties in the initial response are correct
+        self.assertEqual(self.server_id, rebuilt_server['id'])
+        rebuilt_image_id = rebuilt_server['image']['id']
+        self.assertEqual(new_image, rebuilt_image_id)
+        self.assertEqual(self.flavor_ref, rebuilt_server['flavor']['id'])
+
+        # Verify the server properties after the rebuild completes
+        self.client.wait_for_server_status(rebuilt_server['id'], 'SHUTOFF')
+        resp, server = self.client.get_server(rebuilt_server['id'])
+        rebuilt_image_id = server['image']['id']
+        self.assertEqual(new_image, rebuilt_image_id)
 
     def _detect_server_image_flavor(self, server_id):
         # Detects the current server image flavor ref.
@@ -217,6 +247,7 @@
         image1_id = data_utils.parse_image_id(resp['location'])
         self.addCleanup(_clean_oldest_backup, image1_id)
         self.assertEqual(202, resp.status)
+        self.os.image_client.wait_for_image_status(image1_id, 'active')
 
         backup2 = data_utils.rand_name('backup')
         self.servers_client.wait_for_server_status(self.server_id, 'ACTIVE')
@@ -227,6 +258,7 @@
         image2_id = data_utils.parse_image_id(resp['location'])
         self.addCleanup(self.os.image_client.delete_image, image2_id)
         self.assertEqual(202, resp.status)
+        self.os.image_client.wait_for_image_status(image2_id, 'active')
 
         # verify they have been created
         properties = {
@@ -266,6 +298,14 @@
         self.assertEqual((backup2, backup3),
                          (image_list[0]['name'], image_list[1]['name']))
 
+    def _get_output(self):
+        resp, output = self.servers_client.get_console_output(
+            self.server_id, 10)
+        self.assertEqual(200, resp.status)
+        self.assertTrue(output, "Console output was empty.")
+        lines = len(output.split('\n'))
+        self.assertEqual(lines, 10)
+
     @attr(type='gate')
     def test_get_console_output(self):
         # Positive test:Should be able to GET the console output
@@ -280,29 +320,24 @@
         self.assertEqual(202, resp.status)
         self.servers_client.wait_for_server_status(self.server_id, 'ACTIVE')
 
-        def get_output():
-            resp, output = self.servers_client.get_console_output(
-                self.server_id, 10)
-            self.assertEqual(200, resp.status)
-            self.assertTrue(output, "Console output was empty.")
-            lines = len(output.split('\n'))
-            self.assertEqual(lines, 10)
-        self.wait_for(get_output)
+        self.wait_for(self._get_output)
 
-    @skip_because(bug="1014683")
     @attr(type='gate')
-    def test_get_console_output_server_id_in_reboot_status(self):
+    def test_get_console_output_server_id_in_shutoff_status(self):
         # Positive test:Should be able to GET the console output
-        # for a given server_id in reboot status
-        resp, output = self.servers_client.reboot(self.server_id, 'SOFT')
-        self.servers_client.wait_for_server_status(self.server_id,
-                                                   'REBOOT')
-        resp, output = self.servers_client.get_console_output(self.server_id,
-                                                              10)
-        self.assertEqual(200, resp.status)
-        self.assertIsNotNone(output)
-        lines = len(output.split('\n'))
-        self.assertEqual(lines, 10)
+        # for a given server_id in SHUTOFF status
+
+        # NOTE: SHUTOFF is irregular status. To avoid test instability,
+        #       one server is created only for this test without using
+        #       the server that was created in setupClass.
+        resp, server = self.create_test_server(wait_until='ACTIVE')
+        temp_server_id = server['id']
+
+        resp, server = self.servers_client.stop(temp_server_id)
+        self.assertEqual(202, resp.status)
+        self.servers_client.wait_for_server_status(temp_server_id, 'SHUTOFF')
+
+        self.wait_for(self._get_output)
 
     @attr(type='gate')
     def test_pause_unpause_server(self):
diff --git a/tempest/api/compute/servers/test_servers_negative.py b/tempest/api/compute/servers/test_servers_negative.py
index 5ec0cbe..8142250 100644
--- a/tempest/api/compute/servers/test_servers_negative.py
+++ b/tempest/api/compute/servers/test_servers_negative.py
@@ -34,7 +34,7 @@
         try:
             self.client.wait_for_server_status(self.server_id, 'ACTIVE')
         except Exception:
-            self.rebuild_server()
+            self.__class__.server_id = self.rebuild_server(self.server_id)
 
     @classmethod
     def setUpClass(cls):
diff --git a/tempest/api/compute/test_authorization.py b/tempest/api/compute/test_authorization.py
index 49c4f32..327c7d1 100644
--- a/tempest/api/compute/test_authorization.py
+++ b/tempest/api/compute/test_authorization.py
@@ -15,7 +15,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest.api import compute
 from tempest.api.compute import base
 from tempest import clients
 from tempest.common.utils import data_utils
@@ -31,12 +30,10 @@
 
     @classmethod
     def setUpClass(cls):
-        if not compute.MULTI_USER:
+        super(AuthorizationTestJSON, cls).setUpClass()
+        if not cls.multi_user:
             msg = "Need >1 user"
             raise cls.skipException(msg)
-
-        super(AuthorizationTestJSON, cls).setUpClass()
-
         cls.client = cls.os.servers_client
         cls.images_client = cls.os.images_client
         cls.keypairs_client = cls.os.keypairs_client
@@ -85,7 +82,7 @@
 
     @classmethod
     def tearDownClass(cls):
-        if compute.MULTI_USER:
+        if cls.multi_user:
             cls.images_client.delete_image(cls.image['id'])
             cls.keypairs_client.delete_keypair(cls.keypairname)
             cls.security_client.delete_security_group(cls.security_group['id'])
diff --git a/tempest/api/compute/test_extensions.py b/tempest/api/compute/test_extensions.py
index 8f1e446..b0bffc4 100644
--- a/tempest/api/compute/test_extensions.py
+++ b/tempest/api/compute/test_extensions.py
@@ -17,18 +17,31 @@
 
 
 from tempest.api.compute import base
-from tempest.test import attr
+from tempest import test
+import testtools
 
 
 class ExtensionsTestJSON(base.BaseV2ComputeTest):
     _interface = 'json'
 
-    @attr(type='gate')
+    @testtools.skipIf(not test.is_extension_enabled('os-consoles', 'compute'),
+                      'os-consoles extension not enabled.')
+    @test.attr(type='gate')
     def test_list_extensions(self):
         # List of all extensions
         resp, extensions = self.extensions_client.list_extensions()
         self.assertIn("extensions", extensions)
         self.assertEqual(200, resp.status)
+        self.assertTrue(self.extensions_client.is_enabled("Consoles"))
+
+    @testtools.skipIf(not test.is_extension_enabled('os-consoles', 'compute'),
+                      'os-consoles extension not enabled.')
+    @test.attr(type='gate')
+    def test_get_extension(self):
+        # get the specified extensions
+        resp, extension = self.extensions_client.get_extension('os-consoles')
+        self.assertEqual(200, resp.status)
+        self.assertEqual('os-consoles', extension['alias'])
 
 
 class ExtensionsTestXML(ExtensionsTestJSON):
diff --git a/tempest/api/compute/v3/admin/test_availability_zone.py b/tempest/api/compute/v3/admin/test_availability_zone.py
index ff2765c..dca556f 100644
--- a/tempest/api/compute/v3/admin/test_availability_zone.py
+++ b/tempest/api/compute/v3/admin/test_availability_zone.py
@@ -16,21 +16,20 @@
 #    under the License.
 
 from tempest.api.compute import base
-from tempest import exceptions
 from tempest.test import attr
 
 
-class AvailabilityZoneAdminV3TestJSON(base.BaseV3ComputeAdminTest):
+class AZAdminV3TestJSON(base.BaseV3ComputeAdminTest):
 
     """
-    Tests Availability Zone API List that require admin privileges
+    Tests Availability Zone API List
     """
 
     _interface = 'json'
 
     @classmethod
     def setUpClass(cls):
-        super(AvailabilityZoneAdminV3TestJSON, cls).setUpClass()
+        super(AZAdminV3TestJSON, cls).setUpClass()
         cls.client = cls.availability_zone_admin_client
         cls.non_adm_client = cls.availability_zone_client
 
@@ -57,14 +56,6 @@
         self.assertEqual(200, resp.status)
         self.assertTrue(len(availability_zone) > 0)
 
-    @attr(type=['negative', 'gate'])
-    def test_get_availability_zone_list_detail_with_non_admin_user(self):
-        # List of availability zones and available services with
-        # non-administrator user
-        self.assertRaises(
-            exceptions.Unauthorized,
-            self.non_adm_client.get_availability_zone_list_detail)
 
-
-class AvailabilityZoneAdminV3TestXML(AvailabilityZoneAdminV3TestJSON):
+class AZAdminV3TestXML(AZAdminV3TestJSON):
     _interface = 'xml'
diff --git a/tempest/api/compute/v3/admin/test_availability_zone_negative.py b/tempest/api/compute/v3/admin/test_availability_zone_negative.py
new file mode 100644
index 0000000..93a57e3
--- /dev/null
+++ b/tempest/api/compute/v3/admin/test_availability_zone_negative.py
@@ -0,0 +1,47 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 NEC Corporation
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.api.compute import base
+from tempest import exceptions
+from tempest.test import attr
+
+
+class AZAdminNegativeV3TestJSON(base.BaseV3ComputeAdminTest):
+
+    """
+    Tests Availability Zone API List
+    """
+
+    _interface = 'json'
+
+    @classmethod
+    def setUpClass(cls):
+        super(AZAdminNegativeV3TestJSON, cls).setUpClass()
+        cls.client = cls.availability_zone_admin_client
+        cls.non_adm_client = cls.availability_zone_client
+
+    @attr(type=['negative', 'gate'])
+    def test_get_availability_zone_list_detail_with_non_admin_user(self):
+        # List of availability zones and available services with
+        # non-administrator user
+        self.assertRaises(
+            exceptions.Unauthorized,
+            self.non_adm_client.get_availability_zone_list_detail)
+
+
+class AZAdminNegativeV3TestXML(AZAdminNegativeV3TestJSON):
+    _interface = 'xml'
diff --git a/tempest/api/compute/v3/admin/test_flavors_access.py b/tempest/api/compute/v3/admin/test_flavors_access.py
new file mode 100644
index 0000000..048312b
--- /dev/null
+++ b/tempest/api/compute/v3/admin/test_flavors_access.py
@@ -0,0 +1,111 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 NEC Corporation.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.api.compute import base
+from tempest.common.utils import data_utils
+from tempest import test
+
+
+class FlavorsAccessTestJSON(base.BaseV2ComputeAdminTest):
+
+    """
+    Tests Flavor Access API extension.
+    Add and remove Flavor Access require admin privileges.
+    """
+
+    _interface = 'json'
+
+    @classmethod
+    def setUpClass(cls):
+        super(FlavorsAccessTestJSON, cls).setUpClass()
+        if not test.is_extension_enabled('FlavorExtraData', 'compute'):
+            msg = "FlavorExtraData extension not enabled."
+            raise cls.skipException(msg)
+
+        cls.client = cls.os_adm.flavors_client
+        admin_client = cls._get_identity_admin_client()
+        cls.tenant = admin_client.get_tenant_by_name(cls.flavors_client.
+                                                     tenant_name)
+        cls.tenant_id = cls.tenant['id']
+        cls.adm_tenant = admin_client.get_tenant_by_name(cls.os_adm.
+                                                         flavors_client.
+                                                         tenant_name)
+        cls.adm_tenant_id = cls.adm_tenant['id']
+        cls.flavor_name_prefix = 'test_flavor_access_'
+        cls.ram = 512
+        cls.vcpus = 1
+        cls.disk = 10
+
+    @test.attr(type='gate')
+    def test_flavor_access_list_with_private_flavor(self):
+        # Test to list flavor access successfully by querying private flavor
+        flavor_name = data_utils.rand_name(self.flavor_name_prefix)
+        new_flavor_id = data_utils.rand_int_id(start=1000)
+        resp, new_flavor = self.client.create_flavor(flavor_name,
+                                                     self.ram, self.vcpus,
+                                                     self.disk,
+                                                     new_flavor_id,
+                                                     is_public='False')
+        self.addCleanup(self.client.delete_flavor, new_flavor['id'])
+        self.assertEqual(resp.status, 200)
+        resp, flavor_access = self.client.list_flavor_access(new_flavor_id)
+        self.assertEqual(resp.status, 200)
+        self.assertEqual(len(flavor_access), 1, str(flavor_access))
+        first_flavor = flavor_access[0]
+        self.assertEqual(str(new_flavor_id), str(first_flavor['flavor_id']))
+        self.assertEqual(self.adm_tenant_id, first_flavor['tenant_id'])
+
+    @test.attr(type='gate')
+    def test_flavor_access_add_remove(self):
+        # Test to add and remove flavor access to a given tenant.
+        flavor_name = data_utils.rand_name(self.flavor_name_prefix)
+        new_flavor_id = data_utils.rand_int_id(start=1000)
+        resp, new_flavor = self.client.create_flavor(flavor_name,
+                                                     self.ram, self.vcpus,
+                                                     self.disk,
+                                                     new_flavor_id,
+                                                     is_public='False')
+        self.addCleanup(self.client.delete_flavor, new_flavor['id'])
+        # Add flavor access to a tenant.
+        resp_body = {
+            "tenant_id": str(self.tenant_id),
+            "flavor_id": str(new_flavor['id']),
+        }
+        add_resp, add_body = \
+            self.client.add_flavor_access(new_flavor['id'], self.tenant_id)
+        self.assertEqual(add_resp.status, 200)
+        self.assertIn(resp_body, add_body)
+
+        # The flavor is present in list.
+        resp, flavors = self.flavors_client.list_flavors_with_detail()
+        self.assertEqual(resp.status, 200)
+        self.assertIn(new_flavor['id'], map(lambda x: x['id'], flavors))
+
+        # Remove flavor access from a tenant.
+        remove_resp, remove_body = \
+            self.client.remove_flavor_access(new_flavor['id'], self.tenant_id)
+        self.assertEqual(remove_resp.status, 200)
+        self.assertNotIn(resp_body, remove_body)
+
+        # The flavor is not present in list.
+        resp, flavors = self.flavors_client.list_flavors_with_detail()
+        self.assertEqual(resp.status, 200)
+        self.assertNotIn(new_flavor['id'], map(lambda x: x['id'], flavors))
+
+
+class FlavorsAdminTestXML(FlavorsAccessTestJSON):
+    _interface = 'xml'
diff --git a/tempest/api/compute/v3/admin/test_flavors_access_negative.py b/tempest/api/compute/v3/admin/test_flavors_access_negative.py
new file mode 100644
index 0000000..976124e
--- /dev/null
+++ b/tempest/api/compute/v3/admin/test_flavors_access_negative.py
@@ -0,0 +1,152 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 IBM Corporation
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import uuid
+
+from tempest.api.compute import base
+from tempest.common.utils import data_utils
+from tempest import exceptions
+from tempest import test
+
+
+class FlavorsAccessNegativeTestJSON(base.BaseV2ComputeAdminTest):
+
+    """
+    Tests Flavor Access API extension.
+    Add and remove Flavor Access require admin privileges.
+    """
+
+    _interface = 'json'
+
+    @classmethod
+    def setUpClass(cls):
+        super(FlavorsAccessNegativeTestJSON, cls).setUpClass()
+        if not test.is_extension_enabled('FlavorExtraData', 'compute'):
+            msg = "FlavorExtraData extension not enabled."
+            raise cls.skipException(msg)
+
+        cls.client = cls.os_adm.flavors_client
+        admin_client = cls._get_identity_admin_client()
+        cls.tenant = admin_client.get_tenant_by_name(cls.flavors_client.
+                                                     tenant_name)
+        cls.tenant_id = cls.tenant['id']
+        cls.adm_tenant = admin_client.get_tenant_by_name(cls.os_adm.
+                                                         flavors_client.
+                                                         tenant_name)
+        cls.adm_tenant_id = cls.adm_tenant['id']
+        cls.flavor_name_prefix = 'test_flavor_access_'
+        cls.ram = 512
+        cls.vcpus = 1
+        cls.disk = 10
+
+    @test.attr(type=['negative', 'gate'])
+    def test_flavor_access_list_with_public_flavor(self):
+        # Test to list flavor access with exceptions by querying public flavor
+        flavor_name = data_utils.rand_name(self.flavor_name_prefix)
+        new_flavor_id = data_utils.rand_int_id(start=1000)
+        resp, new_flavor = self.client.create_flavor(flavor_name,
+                                                     self.ram, self.vcpus,
+                                                     self.disk,
+                                                     new_flavor_id,
+                                                     is_public='True')
+        self.addCleanup(self.client.delete_flavor, new_flavor['id'])
+        self.assertEqual(resp.status, 200)
+        self.assertRaises(exceptions.NotFound,
+                          self.client.list_flavor_access,
+                          new_flavor_id)
+
+    @test.attr(type=['negative', 'gate'])
+    def test_flavor_non_admin_add(self):
+        # Test to add flavor access as a user without admin privileges.
+        flavor_name = data_utils.rand_name(self.flavor_name_prefix)
+        new_flavor_id = data_utils.rand_int_id(start=1000)
+        resp, new_flavor = self.client.create_flavor(flavor_name,
+                                                     self.ram, self.vcpus,
+                                                     self.disk,
+                                                     new_flavor_id,
+                                                     is_public='False')
+        self.addCleanup(self.client.delete_flavor, new_flavor['id'])
+        self.assertRaises(exceptions.Unauthorized,
+                          self.flavors_client.add_flavor_access,
+                          new_flavor['id'],
+                          self.tenant_id)
+
+    @test.attr(type=['negative', 'gate'])
+    def test_flavor_non_admin_remove(self):
+        # Test to remove flavor access as a user without admin privileges.
+        flavor_name = data_utils.rand_name(self.flavor_name_prefix)
+        new_flavor_id = data_utils.rand_int_id(start=1000)
+        resp, new_flavor = self.client.create_flavor(flavor_name,
+                                                     self.ram, self.vcpus,
+                                                     self.disk,
+                                                     new_flavor_id,
+                                                     is_public='False')
+        self.addCleanup(self.client.delete_flavor, new_flavor['id'])
+        # Add flavor access to a tenant.
+        self.client.add_flavor_access(new_flavor['id'], self.tenant_id)
+        self.addCleanup(self.client.remove_flavor_access,
+                        new_flavor['id'], self.tenant_id)
+        self.assertRaises(exceptions.Unauthorized,
+                          self.flavors_client.remove_flavor_access,
+                          new_flavor['id'],
+                          self.tenant_id)
+
+    @test.attr(type=['negative', 'gate'])
+    def test_add_flavor_access_duplicate(self):
+        # Create a new flavor.
+        flavor_name = data_utils.rand_name(self.flavor_name_prefix)
+        new_flavor_id = data_utils.rand_int_id(start=1000)
+        resp, new_flavor = self.client.create_flavor(flavor_name,
+                                                     self.ram, self.vcpus,
+                                                     self.disk,
+                                                     new_flavor_id,
+                                                     is_public='False')
+        self.addCleanup(self.client.delete_flavor, new_flavor['id'])
+
+        # Add flavor access to a tenant.
+        self.client.add_flavor_access(new_flavor['id'], self.tenant_id)
+        self.addCleanup(self.client.remove_flavor_access,
+                        new_flavor['id'], self.tenant_id)
+
+        # An exception should be raised when adding flavor access to the same
+        # tenant
+        self.assertRaises(exceptions.Conflict,
+                          self.client.add_flavor_access,
+                          new_flavor['id'],
+                          self.tenant_id)
+
+    @test.attr(type=['negative', 'gate'])
+    def test_remove_flavor_access_not_found(self):
+        # Create a new flavor.
+        flavor_name = data_utils.rand_name(self.flavor_name_prefix)
+        new_flavor_id = data_utils.rand_int_id(start=1000)
+        resp, new_flavor = self.client.create_flavor(flavor_name,
+                                                     self.ram, self.vcpus,
+                                                     self.disk,
+                                                     new_flavor_id,
+                                                     is_public='False')
+        self.addCleanup(self.client.delete_flavor, new_flavor['id'])
+
+        # An exception should be raised when flavor access is not found
+        self.assertRaises(exceptions.NotFound,
+                          self.client.remove_flavor_access,
+                          new_flavor['id'],
+                          str(uuid.uuid4()))
+
+
+class FlavorsAdminNegativeTestXML(FlavorsAccessNegativeTestJSON):
+    _interface = 'xml'
diff --git a/tempest/api/compute/v3/admin/test_flavors_extra_specs.py b/tempest/api/compute/v3/admin/test_flavors_extra_specs.py
new file mode 100644
index 0000000..875f742
--- /dev/null
+++ b/tempest/api/compute/v3/admin/test_flavors_extra_specs.py
@@ -0,0 +1,131 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# 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 test
+
+
+class FlavorsExtraSpecsTestJSON(base.BaseV2ComputeAdminTest):
+
+    """
+    Tests Flavor Extra Spec API extension.
+    SET, UNSET, UPDATE Flavor Extra specs require admin privileges.
+    GET Flavor Extra specs can be performed even by without admin privileges.
+    """
+
+    _interface = 'json'
+
+    @classmethod
+    def setUpClass(cls):
+        super(FlavorsExtraSpecsTestJSON, cls).setUpClass()
+        if not test.is_extension_enabled('FlavorExtraData', 'compute'):
+            msg = "FlavorExtraData extension not enabled."
+            raise cls.skipException(msg)
+
+        cls.client = cls.os_adm.flavors_client
+        flavor_name = data_utils.rand_name('test_flavor')
+        ram = 512
+        vcpus = 1
+        disk = 10
+        ephemeral = 10
+        cls.new_flavor_id = data_utils.rand_int_id(start=1000)
+        swap = 1024
+        rxtx = 1
+        # Create a flavor so as to set/get/unset extra specs
+        resp, cls.flavor = cls.client.create_flavor(flavor_name,
+                                                    ram, vcpus,
+                                                    disk,
+                                                    cls.new_flavor_id,
+                                                    ephemeral=ephemeral,
+                                                    swap=swap, rxtx=rxtx)
+
+    @classmethod
+    def tearDownClass(cls):
+        resp, body = cls.client.delete_flavor(cls.flavor['id'])
+        cls.client.wait_for_resource_deletion(cls.flavor['id'])
+        super(FlavorsExtraSpecsTestJSON, cls).tearDownClass()
+
+    @test.attr(type='gate')
+    def test_flavor_set_get_update_show_unset_keys(self):
+        # Test to SET, GET, UPDATE, SHOW, UNSET flavor extra
+        # spec as a user with admin privileges.
+        # Assigning extra specs values that are to be set
+        specs = {"key1": "value1", "key2": "value2"}
+        # SET extra specs to the flavor created in setUp
+        set_resp, set_body = \
+            self.client.set_flavor_extra_spec(self.flavor['id'], specs)
+        self.assertEqual(set_resp.status, 200)
+        self.assertEqual(set_body, specs)
+        # GET extra specs and verify
+        get_resp, get_body = \
+            self.client.get_flavor_extra_spec(self.flavor['id'])
+        self.assertEqual(get_resp.status, 200)
+        self.assertEqual(get_body, specs)
+
+        # UPDATE the value of the extra specs key1
+        update_resp, update_body = \
+            self.client.update_flavor_extra_spec(self.flavor['id'],
+                                                 "key1",
+                                                 key1="value")
+        self.assertEqual(update_resp.status, 200)
+        self.assertEqual({"key1": "value"}, update_body)
+
+        # GET extra specs and verify the value of the key2
+        # is the same as before
+        get_resp, get_body = \
+            self.client.get_flavor_extra_spec(self.flavor['id'])
+        self.assertEqual(get_resp.status, 200)
+        self.assertEqual(get_body, {"key1": "value", "key2": "value2"})
+
+        # UNSET extra specs that were set in this test
+        unset_resp, _ = \
+            self.client.unset_flavor_extra_spec(self.flavor['id'], "key1")
+        self.assertEqual(unset_resp.status, 200)
+        unset_resp, _ = \
+            self.client.unset_flavor_extra_spec(self.flavor['id'], "key2")
+        self.assertEqual(unset_resp.status, 200)
+
+    @test.attr(type='gate')
+    def test_flavor_non_admin_get_all_keys(self):
+        specs = {"key1": "value1", "key2": "value2"}
+        set_resp, set_body = self.client.set_flavor_extra_spec(
+            self.flavor['id'], specs)
+        resp, body = self.flavors_client.get_flavor_extra_spec(
+            self.flavor['id'])
+        self.assertEqual(resp.status, 200)
+
+        for key in specs:
+            self.assertEqual(body[key], specs[key])
+
+    @test.attr(type='gate')
+    def test_flavor_non_admin_get_specific_key(self):
+        specs = {"key1": "value1", "key2": "value2"}
+        resp, body = self.client.set_flavor_extra_spec(
+            self.flavor['id'], specs)
+        self.assertEqual(resp.status, 200)
+        self.assertEqual(body['key1'], 'value1')
+        self.assertIn('key2', body)
+        resp, body = self.flavors_client.get_flavor_extra_spec_with_key(
+            self.flavor['id'], 'key1')
+        self.assertEqual(resp.status, 200)
+        self.assertEqual(body['key1'], 'value1')
+        self.assertNotIn('key2', body)
+
+
+class FlavorsExtraSpecsTestXML(FlavorsExtraSpecsTestJSON):
+    _interface = 'xml'
diff --git a/tempest/api/compute/v3/admin/test_flavors_extra_specs_negative.py b/tempest/api/compute/v3/admin/test_flavors_extra_specs_negative.py
new file mode 100644
index 0000000..fb09a63
--- /dev/null
+++ b/tempest/api/compute/v3/admin/test_flavors_extra_specs_negative.py
@@ -0,0 +1,135 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2012 OpenStack Foundation
+# All Rights Reserved.
+# Copyright 2013 IBM Corp.
+#
+#    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 FlavorsExtraSpecsNegativeTestJSON(base.BaseV2ComputeAdminTest):
+
+    """
+    Negative Tests Flavor Extra Spec API extension.
+    SET, UNSET, UPDATE Flavor Extra specs require admin privileges.
+    """
+
+    _interface = 'json'
+
+    @classmethod
+    def setUpClass(cls):
+        super(FlavorsExtraSpecsNegativeTestJSON, cls).setUpClass()
+        if not test.is_extension_enabled('FlavorExtraData', 'compute'):
+            msg = "FlavorExtraData extension not enabled."
+            raise cls.skipException(msg)
+
+        cls.client = cls.os_adm.flavors_client
+        flavor_name = data_utils.rand_name('test_flavor')
+        ram = 512
+        vcpus = 1
+        disk = 10
+        ephemeral = 10
+        cls.new_flavor_id = data_utils.rand_int_id(start=1000)
+        swap = 1024
+        rxtx = 1
+        # Create a flavor
+        resp, cls.flavor = cls.client.create_flavor(flavor_name,
+                                                    ram, vcpus,
+                                                    disk,
+                                                    cls.new_flavor_id,
+                                                    ephemeral=ephemeral,
+                                                    swap=swap, rxtx=rxtx)
+
+    @classmethod
+    def tearDownClass(cls):
+        resp, body = cls.client.delete_flavor(cls.flavor['id'])
+        cls.client.wait_for_resource_deletion(cls.flavor['id'])
+        super(FlavorsExtraSpecsNegativeTestJSON, cls).tearDownClass()
+
+    @test.attr(type=['negative', 'gate'])
+    def test_flavor_non_admin_set_keys(self):
+        # Test to SET flavor extra spec as a user without admin privileges.
+        specs = {"key1": "value1", "key2": "value2"}
+        self.assertRaises(exceptions.Unauthorized,
+                          self.flavors_client.set_flavor_extra_spec,
+                          self.flavor['id'],
+                          specs)
+
+    @test.attr(type=['negative', 'gate'])
+    def test_flavor_non_admin_update_specific_key(self):
+        # non admin user is not allowed to update flavor extra spec
+        specs = {"key1": "value1", "key2": "value2"}
+        resp, body = self.client.set_flavor_extra_spec(
+            self.flavor['id'], specs)
+        self.assertEqual(resp.status, 200)
+        self.assertEqual(body['key1'], 'value1')
+        self.assertRaises(exceptions.Unauthorized,
+                          self.flavors_client.
+                          update_flavor_extra_spec,
+                          self.flavor['id'],
+                          'key1',
+                          key1='value1_new')
+
+    @test.attr(type=['negative', 'gate'])
+    def test_flavor_non_admin_unset_keys(self):
+        specs = {"key1": "value1", "key2": "value2"}
+        set_resp, set_body = self.client.set_flavor_extra_spec(
+            self.flavor['id'], specs)
+
+        self.assertRaises(exceptions.Unauthorized,
+                          self.flavors_client.unset_flavor_extra_spec,
+                          self.flavor['id'],
+                          'key1')
+
+    @test.attr(type=['negative', 'gate'])
+    def test_flavor_unset_nonexistent_key(self):
+        nonexistent_key = data_utils.rand_name('flavor_key')
+        self.assertRaises(exceptions.NotFound,
+                          self.client.unset_flavor_extra_spec,
+                          self.flavor['id'],
+                          nonexistent_key)
+
+    @test.attr(type=['negative', 'gate'])
+    def test_flavor_get_nonexistent_key(self):
+        self.assertRaises(exceptions.NotFound,
+                          self.flavors_client.get_flavor_extra_spec_with_key,
+                          self.flavor['id'],
+                          "nonexistent_key")
+
+    @test.attr(type=['negative', 'gate'])
+    def test_flavor_update_mismatch_key(self):
+        # the key will be updated should be match the key in the body
+        self.assertRaises(exceptions.BadRequest,
+                          self.client.update_flavor_extra_spec,
+                          self.flavor['id'],
+                          "key2",
+                          key1="value")
+
+    @test.attr(type=['negative', 'gate'])
+    def test_flavor_update_more_key(self):
+        # there should be just one item in the request body
+        self.assertRaises(exceptions.BadRequest,
+                          self.client.update_flavor_extra_spec,
+                          self.flavor['id'],
+                          "key1",
+                          key1="value",
+                          key2="value")
+
+
+class FlavorsExtraSpecsNegativeTestXML(FlavorsExtraSpecsNegativeTestJSON):
+    _interface = 'xml'
diff --git a/tempest/api/compute/v3/admin/test_quotas.py b/tempest/api/compute/v3/admin/test_quotas.py
new file mode 100644
index 0000000..f49aae4
--- /dev/null
+++ b/tempest/api/compute/v3/admin/test_quotas.py
@@ -0,0 +1,220 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# 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 config
+from tempest import exceptions
+from tempest.test import attr
+from tempest.test import skip_because
+
+
+class QuotasAdminTestJSON(base.BaseV2ComputeAdminTest):
+    _interface = 'json'
+    force_tenant_isolation = True
+
+    @classmethod
+    def setUpClass(cls):
+        super(QuotasAdminTestJSON, cls).setUpClass()
+        cls.auth_url = cls.config.identity.uri
+        cls.client = cls.os.quotas_client
+        cls.adm_client = cls.os_adm.quotas_client
+        cls.identity_admin_client = cls._get_identity_admin_client()
+        cls.sg_client = cls.security_groups_client
+
+        # NOTE(afazekas): these test cases should always create and use a new
+        # tenant most of them should be skipped if we can't do that
+        cls.demo_tenant_id = cls.isolated_creds.get_primary_user().get(
+            'tenantId')
+
+        cls.default_quota_set = set(('injected_file_content_bytes',
+                                     'metadata_items', 'injected_files',
+                                     'ram', 'floating_ips',
+                                     'fixed_ips', 'key_pairs',
+                                     'injected_file_path_bytes',
+                                     'instances', 'security_group_rules',
+                                     'cores', 'security_groups'))
+
+    @attr(type='smoke')
+    def test_get_default_quotas(self):
+        # Admin can get the default resource quota set for a tenant
+        expected_quota_set = self.default_quota_set | set(['id'])
+        resp, quota_set = self.client.get_default_quota_set(
+            self.demo_tenant_id)
+        self.assertEqual(200, resp.status)
+        self.assertEqual(sorted(expected_quota_set),
+                         sorted(quota_set.keys()))
+        self.assertEqual(quota_set['id'], self.demo_tenant_id)
+
+    @attr(type='gate')
+    def test_update_all_quota_resources_for_tenant(self):
+        # Admin can update all the resource quota limits for a tenant
+        resp, default_quota_set = self.client.get_default_quota_set(
+            self.demo_tenant_id)
+        new_quota_set = {'injected_file_content_bytes': 20480,
+                         'metadata_items': 256, 'injected_files': 10,
+                         'ram': 10240, 'floating_ips': 20, 'fixed_ips': 10,
+                         'key_pairs': 200, 'injected_file_path_bytes': 512,
+                         'instances': 20, 'security_group_rules': 20,
+                         'cores': 2, 'security_groups': 20}
+        # Update limits for all quota resources
+        resp, quota_set = self.adm_client.update_quota_set(
+            self.demo_tenant_id,
+            force=True,
+            **new_quota_set)
+
+        default_quota_set.pop('id')
+        self.addCleanup(self.adm_client.update_quota_set,
+                        self.demo_tenant_id, **default_quota_set)
+        self.assertEqual(200, resp.status)
+        self.assertEqual(new_quota_set, quota_set)
+
+    # TODO(afazekas): merge these test cases
+    @attr(type='gate')
+    def test_get_updated_quotas(self):
+        # Verify that GET shows the updated quota set
+        tenant_name = data_utils.rand_name('cpu_quota_tenant_')
+        tenant_desc = tenant_name + '-desc'
+        identity_client = self.os_adm.identity_client
+        _, tenant = identity_client.create_tenant(name=tenant_name,
+                                                  description=tenant_desc)
+        tenant_id = tenant['id']
+        self.addCleanup(identity_client.delete_tenant,
+                        tenant_id)
+
+        self.adm_client.update_quota_set(tenant_id,
+                                         ram='5120')
+        resp, quota_set = self.adm_client.get_quota_set(tenant_id)
+        self.assertEqual(200, resp.status)
+        self.assertEqual(quota_set['ram'], 5120)
+
+    # TODO(afazekas): Add dedicated tenant to the skiped quota tests
+    # it can be moved into the setUpClass as well
+    @attr(type='gate')
+    def test_create_server_when_cpu_quota_is_full(self):
+        # Disallow server creation when tenant's vcpu quota is full
+        resp, quota_set = self.client.get_quota_set(self.demo_tenant_id)
+        default_vcpu_quota = quota_set['cores']
+        vcpu_quota = 0  # Set the quota to zero to conserve resources
+
+        resp, quota_set = self.adm_client.update_quota_set(self.demo_tenant_id,
+                                                           force=True,
+                                                           cores=vcpu_quota)
+
+        self.addCleanup(self.adm_client.update_quota_set, self.demo_tenant_id,
+                        cores=default_vcpu_quota)
+        self.assertRaises(exceptions.OverLimit, self.create_test_server)
+
+    @attr(type='gate')
+    def test_create_server_when_memory_quota_is_full(self):
+        # Disallow server creation when tenant's memory quota is full
+        resp, quota_set = self.client.get_quota_set(self.demo_tenant_id)
+        default_mem_quota = quota_set['ram']
+        mem_quota = 0  # Set the quota to zero to conserve resources
+
+        self.adm_client.update_quota_set(self.demo_tenant_id,
+                                         force=True,
+                                         ram=mem_quota)
+
+        self.addCleanup(self.adm_client.update_quota_set, self.demo_tenant_id,
+                        ram=default_mem_quota)
+        self.assertRaises(exceptions.OverLimit, self.create_test_server)
+
+    @attr(type='gate')
+    def test_update_quota_normal_user(self):
+        self.assertRaises(exceptions.Unauthorized,
+                          self.client.update_quota_set,
+                          self.demo_tenant_id,
+                          ram=0)
+
+    @attr(type=['negative', 'gate'])
+    def test_create_server_when_instances_quota_is_full(self):
+        # Once instances quota limit is reached, disallow server creation
+        resp, quota_set = self.client.get_quota_set(self.demo_tenant_id)
+        default_instances_quota = quota_set['instances']
+        instances_quota = 0  # Set quota to zero to disallow server creation
+
+        self.adm_client.update_quota_set(self.demo_tenant_id,
+                                         force=True,
+                                         instances=instances_quota)
+        self.addCleanup(self.adm_client.update_quota_set, self.demo_tenant_id,
+                        instances=default_instances_quota)
+        self.assertRaises(exceptions.OverLimit, self.create_test_server)
+
+    @skip_because(bug="1186354",
+                  condition=config.TempestConfig().service_available.neutron)
+    @attr(type=['negative', 'gate'])
+    def test_security_groups_exceed_limit(self):
+        # Negative test: Creation Security Groups over limit should FAIL
+
+        resp, quota_set = self.client.get_quota_set(self.demo_tenant_id)
+        default_sg_quota = quota_set['security_groups']
+        sg_quota = 0  # Set the quota to zero to conserve resources
+
+        resp, quota_set =\
+            self.adm_client.update_quota_set(self.demo_tenant_id,
+                                             force=True,
+                                             security_groups=sg_quota)
+
+        self.addCleanup(self.adm_client.update_quota_set,
+                        self.demo_tenant_id,
+                        security_groups=default_sg_quota)
+
+        # Check we cannot create anymore
+        self.assertRaises(exceptions.OverLimit,
+                          self.sg_client.create_security_group,
+                          "sg-overlimit", "sg-desc")
+
+    @skip_because(bug="1186354",
+                  condition=config.TempestConfig().service_available.neutron)
+    @attr(type=['negative', 'gate'])
+    def test_security_groups_rules_exceed_limit(self):
+        # Negative test: Creation of Security Group Rules should FAIL
+        # when we reach limit maxSecurityGroupRules
+
+        resp, quota_set = self.client.get_quota_set(self.demo_tenant_id)
+        default_sg_rules_quota = quota_set['security_group_rules']
+        sg_rules_quota = 0  # Set the quota to zero to conserve resources
+
+        resp, quota_set =\
+            self.adm_client.update_quota_set(
+                self.demo_tenant_id,
+                force=True,
+                security_group_rules=sg_rules_quota)
+
+        self.addCleanup(self.adm_client.update_quota_set,
+                        self.demo_tenant_id,
+                        security_group_rules=default_sg_rules_quota)
+
+        s_name = data_utils.rand_name('securitygroup-')
+        s_description = data_utils.rand_name('description-')
+        resp, securitygroup =\
+            self.sg_client.create_security_group(s_name, s_description)
+        self.addCleanup(self.sg_client.delete_security_group,
+                        securitygroup['id'])
+
+        secgroup_id = securitygroup['id']
+        ip_protocol = 'tcp'
+
+        # Check we cannot create SG rule anymore
+        self.assertRaises(exceptions.OverLimit,
+                          self.sg_client.create_security_group_rule,
+                          secgroup_id, ip_protocol, 1025, 1025)
+
+
+class QuotasAdminTestXML(QuotasAdminTestJSON):
+    _interface = 'xml'
diff --git a/tempest/api/compute/v3/admin/test_services.py b/tempest/api/compute/v3/admin/test_services.py
index 67f9947..64135ed 100644
--- a/tempest/api/compute/v3/admin/test_services.py
+++ b/tempest/api/compute/v3/admin/test_services.py
@@ -113,23 +113,6 @@
         self.assertEqual(200, resp.status)
         self.assertEqual(0, len(services))
 
-    @attr(type='gate')
-    def test_service_enable_disable(self):
-        resp, services = self.client.list_services()
-        host_name = services[0]['host']
-        binary_name = services[0]['binary']
-
-        resp, service = self.client.disable_service(host_name, binary_name)
-        self.assertEqual(200, resp.status)
-        params = {'host': host_name, 'binary': binary_name}
-        resp, services = self.client.list_services(params)
-        self.assertEqual('disabled', services[0]['status'])
-
-        resp, service = self.client.enable_service(host_name, binary_name)
-        self.assertEqual(200, resp.status)
-        resp, services = self.client.list_services(params)
-        self.assertEqual('enabled', services[0]['status'])
-
 
 class ServicesAdminV3TestXML(ServicesAdminV3TestJSON):
     _interface = 'xml'
diff --git a/tempest/api/compute/v3/admin/test_simple_tenant_usage.py b/tempest/api/compute/v3/admin/test_simple_tenant_usage.py
index a599f06..3fc58eb 100644
--- a/tempest/api/compute/v3/admin/test_simple_tenant_usage.py
+++ b/tempest/api/compute/v3/admin/test_simple_tenant_usage.py
@@ -23,15 +23,15 @@
 import time
 
 
-class TenantUsagesTestJSON(base.BaseV2ComputeAdminTest):
+class TenantUsagesV3TestJSON(base.BaseV3ComputeAdminTest):
 
     _interface = 'json'
 
     @classmethod
     def setUpClass(cls):
-        super(TenantUsagesTestJSON, cls).setUpClass()
-        cls.adm_client = cls.os_adm.tenant_usages_client
-        cls.client = cls.os.tenant_usages_client
+        super(TenantUsagesV3TestJSON, cls).setUpClass()
+        cls.adm_client = cls.tenant_usages_admin_client
+        cls.client = cls.tenant_usages_client
         cls.identity_client = cls._get_identity_admin_client()
 
         resp, tenants = cls.identity_client.list_tenants()
@@ -111,5 +111,5 @@
                           self.client.list_tenant_usages, params)
 
 
-class TenantUsagesTestXML(TenantUsagesTestJSON):
+class TenantUsagesV3TestXML(TenantUsagesV3TestJSON):
     _interface = 'xml'
diff --git a/tempest/api/compute/v3/images/test_images.py b/tempest/api/compute/v3/images/test_images.py
index 3aacafb..a179d65 100644
--- a/tempest/api/compute/v3/images/test_images.py
+++ b/tempest/api/compute/v3/images/test_images.py
@@ -14,7 +14,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest.api import compute
 from tempest.api.compute import base
 from tempest import clients
 from tempest.common.utils import data_utils
@@ -34,7 +33,7 @@
         cls.client = cls.images_client
         cls.servers_client = cls.servers_client
 
-        if compute.MULTI_USER:
+        if cls.multi_user:
             if cls.config.compute.allow_tenant_isolation:
                 creds = cls.isolated_creds.get_alt_creds()
                 username, tenant_name, password = creds
diff --git a/tempest/api/compute/v3/servers/test_create_server.py b/tempest/api/compute/v3/servers/test_create_server.py
new file mode 100644
index 0000000..24ade96
--- /dev/null
+++ b/tempest/api/compute/v3/servers/test_create_server.py
@@ -0,0 +1,130 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# 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.
+
+import base64
+
+import netaddr
+import testtools
+
+from tempest.api import compute
+from tempest.api.compute import base
+from tempest.common.utils import data_utils
+from tempest.common.utils.linux.remote_client import RemoteClient
+import tempest.config
+from tempest.test import attr
+
+
+class ServersTestJSON(base.BaseV2ComputeTest):
+    _interface = 'json'
+    run_ssh = tempest.config.TempestConfig().compute.run_ssh
+    disk_config = 'AUTO'
+
+    @classmethod
+    def setUpClass(cls):
+        super(ServersTestJSON, cls).setUpClass()
+        cls.meta = {'hello': 'world'}
+        cls.accessIPv4 = '1.1.1.1'
+        cls.accessIPv6 = '0000:0000:0000:0000:0000:babe:220.12.22.2'
+        cls.name = data_utils.rand_name('server')
+        file_contents = 'This is a test file.'
+        personality = [{'path': '/test.txt',
+                       'contents': base64.b64encode(file_contents)}]
+        cls.client = cls.servers_client
+        cli_resp = cls.create_test_server(name=cls.name,
+                                          meta=cls.meta,
+                                          accessIPv4=cls.accessIPv4,
+                                          accessIPv6=cls.accessIPv6,
+                                          personality=personality,
+                                          disk_config=cls.disk_config)
+        cls.resp, cls.server_initial = cli_resp
+        cls.password = cls.server_initial['adminPass']
+        cls.client.wait_for_server_status(cls.server_initial['id'], 'ACTIVE')
+        resp, cls.server = cls.client.get_server(cls.server_initial['id'])
+
+    @attr(type='smoke')
+    def test_create_server_response(self):
+        # Check that the required fields are returned with values
+        self.assertEqual(202, self.resp.status)
+        self.assertTrue(self.server_initial['id'] is not None)
+        self.assertTrue(self.server_initial['adminPass'] is not None)
+
+    @attr(type='smoke')
+    def test_verify_server_details(self):
+        # Verify the specified server attributes are set correctly
+        self.assertEqual(self.accessIPv4, self.server['accessIPv4'])
+        # NOTE(maurosr): See http://tools.ietf.org/html/rfc5952 (section 4)
+        # Here we compare directly with the canonicalized format.
+        self.assertEqual(self.server['accessIPv6'],
+                         str(netaddr.IPAddress(self.accessIPv6)))
+        self.assertEqual(self.name, self.server['name'])
+        self.assertEqual(self.image_ref, self.server['image']['id'])
+        self.assertEqual(self.flavor_ref, self.server['flavor']['id'])
+        self.assertEqual(self.meta, self.server['metadata'])
+
+    @attr(type='smoke')
+    def test_list_servers(self):
+        # The created server should be in the list of all servers
+        resp, body = self.client.list_servers()
+        servers = body['servers']
+        found = any([i for i in servers if i['id'] == self.server['id']])
+        self.assertTrue(found)
+
+    @attr(type='smoke')
+    def test_list_servers_with_detail(self):
+        # The created server should be in the detailed list of all servers
+        resp, body = self.client.list_servers_with_detail()
+        servers = body['servers']
+        found = any([i for i in servers if i['id'] == self.server['id']])
+        self.assertTrue(found)
+
+    @testtools.skipIf(not run_ssh, 'Instance validation tests are disabled.')
+    @attr(type='gate')
+    def test_can_log_into_created_server(self):
+        # Check that the user can authenticate with the generated password
+        linux_client = RemoteClient(self.server, self.ssh_user, self.password)
+        self.assertTrue(linux_client.can_authenticate())
+
+    @testtools.skipIf(not run_ssh, 'Instance validation tests are disabled.')
+    @attr(type='gate')
+    def test_verify_created_server_vcpus(self):
+        # Verify that the number of vcpus reported by the instance matches
+        # the amount stated by the flavor
+        resp, flavor = self.flavors_client.get_flavor_details(self.flavor_ref)
+        linux_client = RemoteClient(self.server, self.ssh_user, self.password)
+        self.assertEqual(flavor['vcpus'], linux_client.get_number_of_vcpus())
+
+    @testtools.skipIf(not run_ssh, 'Instance validation tests are disabled.')
+    @attr(type='gate')
+    def test_host_name_is_same_as_server_name(self):
+        # Verify the instance host name is the same as the server name
+        linux_client = RemoteClient(self.server, self.ssh_user, self.password)
+        self.assertTrue(linux_client.hostname_equals_servername(self.name))
+
+
+class ServersTestManualDisk(ServersTestJSON):
+    disk_config = 'MANUAL'
+
+    @classmethod
+    def setUpClass(cls):
+        if not compute.DISK_CONFIG_ENABLED:
+            msg = "DiskConfig extension not enabled."
+            raise cls.skipException(msg)
+        super(ServersTestManualDisk, cls).setUpClass()
+
+
+class ServersTestXML(ServersTestJSON):
+    _interface = 'xml'
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 6225345..3f7f885 100644
--- a/tempest/api/compute/v3/servers/test_list_servers_negative.py
+++ b/tempest/api/compute/v3/servers/test_list_servers_negative.py
@@ -17,7 +17,6 @@
 
 import datetime
 
-from tempest.api import compute
 from tempest.api.compute import base
 from tempest import clients
 from tempest import exceptions
@@ -53,7 +52,7 @@
         cls.client = cls.servers_client
         cls.servers = []
 
-        if compute.MULTI_USER:
+        if cls.multi_user:
             if cls.config.compute.allow_tenant_isolation:
                 creds = cls.isolated_creds.get_alt_creds()
                 username, tenant_name, password = creds
diff --git a/tempest/api/compute/v3/servers/test_multiple_create.py b/tempest/api/compute/v3/servers/test_multiple_create.py
new file mode 100644
index 0000000..080bd1a
--- /dev/null
+++ b/tempest/api/compute/v3/servers/test_multiple_create.py
@@ -0,0 +1,95 @@
+# 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.api.compute import base
+from tempest.common.utils import data_utils
+from tempest import exceptions
+from tempest.test import attr
+
+
+class MultipleCreateTestJSON(base.BaseV2ComputeTest):
+    _interface = 'json'
+    _name = 'multiple-create-test'
+
+    def _generate_name(self):
+        return data_utils.rand_name(self._name)
+
+    def _create_multiple_servers(self, name=None, wait_until=None, **kwargs):
+        """
+        This is the right way to create_multiple servers and manage to get the
+        created servers into the servers list to be cleaned up after all.
+        """
+        kwargs['name'] = kwargs.get('name', self._generate_name())
+        resp, body = self.create_test_server(**kwargs)
+
+        return resp, body
+
+    @attr(type='gate')
+    def test_multiple_create(self):
+        resp, body = self._create_multiple_servers(wait_until='ACTIVE',
+                                                   min_count=1,
+                                                   max_count=2)
+        # NOTE(maurosr): do status response check and also make sure that
+        # reservation_id is not in the response body when the request send
+        # contains return_reservation_id=False
+        self.assertEqual('202', resp['status'])
+        self.assertNotIn('reservation_id', body)
+
+    @attr(type=['negative', 'gate'])
+    def test_min_count_less_than_one(self):
+        invalid_min_count = 0
+        self.assertRaises(exceptions.BadRequest, self._create_multiple_servers,
+                          min_count=invalid_min_count)
+
+    @attr(type=['negative', 'gate'])
+    def test_min_count_non_integer(self):
+        invalid_min_count = 2.5
+        self.assertRaises(exceptions.BadRequest, self._create_multiple_servers,
+                          min_count=invalid_min_count)
+
+    @attr(type=['negative', 'gate'])
+    def test_max_count_less_than_one(self):
+        invalid_max_count = 0
+        self.assertRaises(exceptions.BadRequest, self._create_multiple_servers,
+                          max_count=invalid_max_count)
+
+    @attr(type=['negative', 'gate'])
+    def test_max_count_non_integer(self):
+        invalid_max_count = 2.5
+        self.assertRaises(exceptions.BadRequest, self._create_multiple_servers,
+                          max_count=invalid_max_count)
+
+    @attr(type=['negative', 'gate'])
+    def test_max_count_less_than_min_count(self):
+        min_count = 3
+        max_count = 2
+        self.assertRaises(exceptions.BadRequest, self._create_multiple_servers,
+                          min_count=min_count,
+                          max_count=max_count)
+
+    @attr(type='gate')
+    def test_multiple_create_with_reservation_return(self):
+        resp, body = self._create_multiple_servers(wait_until='ACTIVE',
+                                                   min_count=1,
+                                                   max_count=2,
+                                                   return_reservation_id=True)
+        self.assertEqual(resp['status'], '202')
+        self.assertIn('reservation_id', body)
+
+
+class MultipleCreateTestXML(MultipleCreateTestJSON):
+    _interface = 'xml'
diff --git a/tempest/api/compute/v3/servers/test_server_actions.py b/tempest/api/compute/v3/servers/test_server_actions.py
index 20cdf30..ee37502 100644
--- a/tempest/api/compute/v3/servers/test_server_actions.py
+++ b/tempest/api/compute/v3/servers/test_server_actions.py
@@ -45,13 +45,13 @@
             self.client.wait_for_server_status(self.server_id, 'ACTIVE')
         except Exception:
             # Rebuild server if something happened to it during a test
-            self.rebuild_server()
+            self.__class__.server_id = self.rebuild_server(self.server_id)
 
     @classmethod
     def setUpClass(cls):
         super(ServerActionsV3TestJSON, cls).setUpClass()
         cls.client = cls.servers_client
-        cls.rebuild_server()
+        cls.server_id = cls.rebuild_server(None)
 
     @testtools.skipUnless(compute.CHANGE_PASSWORD_AVAILABLE,
                           'Change password not available.')
@@ -67,7 +67,7 @@
             # Verify that the user can authenticate with the new password
             resp, server = self.client.get_server(self.server_id)
             linux_client = RemoteClient(server, self.ssh_user, new_password)
-            self.assertTrue(linux_client.can_authenticate())
+            linux_client.validate_authentication()
 
     @attr(type='smoke')
     def test_reboot_server_hard(self):
@@ -140,7 +140,7 @@
         if self.run_ssh:
             # Verify that the user can authenticate with the provided password
             linux_client = RemoteClient(server, self.ssh_user, password)
-            self.assertTrue(linux_client.can_authenticate())
+            linux_client.validate_authentication()
 
     def _detect_server_image_flavor(self, server_id):
         # Detects the current server image flavor ref.
diff --git a/tempest/api/compute/v3/servers/test_server_metadata.py b/tempest/api/compute/v3/servers/test_server_metadata.py
new file mode 100644
index 0000000..ee0f4a9
--- /dev/null
+++ b/tempest/api/compute/v3/servers/test_server_metadata.py
@@ -0,0 +1,217 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# 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 import exceptions
+from tempest.test import attr
+
+
+class ServerMetadataTestJSON(base.BaseV2ComputeTest):
+    _interface = 'json'
+
+    @classmethod
+    def setUpClass(cls):
+        super(ServerMetadataTestJSON, cls).setUpClass()
+        cls.client = cls.servers_client
+        cls.quotas = cls.quotas_client
+        cls.admin_client = cls._get_identity_admin_client()
+        resp, tenants = cls.admin_client.list_tenants()
+        cls.tenant_id = [tnt['id'] for tnt in tenants if tnt['name'] ==
+                         cls.client.tenant_name][0]
+        resp, server = cls.create_test_server(meta={}, wait_until='ACTIVE')
+
+        cls.server_id = server['id']
+
+    def setUp(self):
+        super(ServerMetadataTestJSON, self).setUp()
+        meta = {'key1': 'value1', 'key2': 'value2'}
+        resp, _ = self.client.set_server_metadata(self.server_id, meta)
+        self.assertEqual(resp.status, 200)
+
+    @attr(type='gate')
+    def test_list_server_metadata(self):
+        # All metadata key/value pairs for a server should be returned
+        resp, resp_metadata = self.client.list_server_metadata(self.server_id)
+
+        # Verify the expected metadata items are in the list
+        self.assertEqual(200, resp.status)
+        expected = {'key1': 'value1', 'key2': 'value2'}
+        self.assertEqual(expected, resp_metadata)
+
+    @attr(type='gate')
+    def test_set_server_metadata(self):
+        # The server's metadata should be replaced with the provided values
+        # Create a new set of metadata for the server
+        req_metadata = {'meta2': 'data2', 'meta3': 'data3'}
+        resp, metadata = self.client.set_server_metadata(self.server_id,
+                                                         req_metadata)
+        self.assertEqual(200, resp.status)
+
+        # Verify the expected values are correct, and that the
+        # previous values have been removed
+        resp, resp_metadata = self.client.list_server_metadata(self.server_id)
+        self.assertEqual(resp_metadata, req_metadata)
+
+    @attr(type='gate')
+    def test_server_create_metadata_key_too_long(self):
+        # Attempt to start a server with a meta-data key that is > 255
+        # characters
+
+        # Try a few values
+        for sz in [256, 257, 511, 1023]:
+            key = "k" * sz
+            meta = {key: 'data1'}
+            self.assertRaises(exceptions.OverLimit,
+                              self.create_test_server,
+                              meta=meta)
+
+        # no teardown - all creates should fail
+
+    @attr(type='gate')
+    def test_update_server_metadata(self):
+        # The server's metadata values should be updated to the
+        # provided values
+        meta = {'key1': 'alt1', 'key3': 'value3'}
+        resp, metadata = self.client.update_server_metadata(self.server_id,
+                                                            meta)
+        self.assertEqual(200, resp.status)
+
+        # Verify the values have been updated to the proper values
+        resp, resp_metadata = self.client.list_server_metadata(self.server_id)
+        expected = {'key1': 'alt1', 'key2': 'value2', 'key3': 'value3'}
+        self.assertEqual(expected, resp_metadata)
+
+    @attr(type='gate')
+    def test_update_metadata_empty_body(self):
+        # The original metadata should not be lost if empty metadata body is
+        # passed
+        meta = {}
+        _, metadata = self.client.update_server_metadata(self.server_id, meta)
+        resp, resp_metadata = self.client.list_server_metadata(self.server_id)
+        expected = {'key1': 'value1', 'key2': 'value2'}
+        self.assertEqual(expected, resp_metadata)
+
+    @attr(type='gate')
+    def test_get_server_metadata_item(self):
+        # The value for a specific metadata key should be returned
+        resp, meta = self.client.get_server_metadata_item(self.server_id,
+                                                          'key2')
+        self.assertEqual('value2', meta['key2'])
+
+    @attr(type='gate')
+    def test_set_server_metadata_item(self):
+        # The item's value should be updated to the provided value
+        # Update the metadata value
+        meta = {'nova': 'alt'}
+        resp, body = self.client.set_server_metadata_item(self.server_id,
+                                                          'nova', meta)
+        self.assertEqual(200, resp.status)
+
+        # Verify the meta item's value has been updated
+        resp, resp_metadata = self.client.list_server_metadata(self.server_id)
+        expected = {'key1': 'value1', 'key2': 'value2', 'nova': 'alt'}
+        self.assertEqual(expected, resp_metadata)
+
+    @attr(type='gate')
+    def test_delete_server_metadata_item(self):
+        # The metadata value/key pair should be deleted from the server
+        resp, meta = self.client.delete_server_metadata_item(self.server_id,
+                                                             'key1')
+        self.assertEqual(204, resp.status)
+
+        # Verify the metadata item has been removed
+        resp, resp_metadata = self.client.list_server_metadata(self.server_id)
+        expected = {'key2': 'value2'}
+        self.assertEqual(expected, resp_metadata)
+
+    @attr(type=['negative', 'gate'])
+    def test_server_metadata_negative(self):
+        # Blank key should trigger an error.
+        meta = {'': 'data1'}
+        self.assertRaises(exceptions.BadRequest,
+                          self.create_test_server,
+                          meta=meta)
+
+        # GET on a non-existent server should not succeed
+        self.assertRaises(exceptions.NotFound,
+                          self.client.get_server_metadata_item, 999, 'test2')
+
+        # List metadata on a non-existent server should not succeed
+        self.assertRaises(exceptions.NotFound,
+                          self.client.list_server_metadata, 999)
+
+        # Raise BadRequest if key in uri does not match
+        # the key passed in body.
+        meta = {'testkey': 'testvalue'}
+        self.assertRaises(exceptions.BadRequest,
+                          self.client.set_server_metadata_item,
+                          self.server_id, 'key', meta)
+
+        # Set metadata on a non-existent server should not succeed
+        meta = {'meta1': 'data1'}
+        self.assertRaises(exceptions.NotFound,
+                          self.client.set_server_metadata, 999, meta)
+
+        # An update should not happen for a non-existent image
+        meta = {'key1': 'value1', 'key2': 'value2'}
+        self.assertRaises(exceptions.NotFound,
+                          self.client.update_server_metadata, 999, meta)
+
+        # Blank key should trigger an error
+        meta = {'': 'data1'}
+        self.assertRaises(exceptions.BadRequest,
+                          self.client.update_server_metadata,
+                          self.server_id, meta=meta)
+
+        # Should not be able to delete metadata item from a non-existent server
+        self.assertRaises(exceptions.NotFound,
+                          self.client.delete_server_metadata_item, 999, 'd')
+
+        # Raise a 413 OverLimit exception while exceeding metadata items limit
+        # for tenant.
+        _, quota_set = self.quotas.get_quota_set(self.tenant_id)
+        quota_metadata = quota_set['metadata_items']
+        req_metadata = {}
+        for num in range(1, quota_metadata + 2):
+            req_metadata['key' + str(num)] = 'val' + str(num)
+        self.assertRaises(exceptions.OverLimit,
+                          self.client.set_server_metadata,
+                          self.server_id, req_metadata)
+
+        # Raise a 413 OverLimit exception while exceeding metadata items limit
+        # for tenant (update).
+        self.assertRaises(exceptions.OverLimit,
+                          self.client.update_server_metadata,
+                          self.server_id, req_metadata)
+
+        # Raise a bad request error for blank key.
+        # set_server_metadata will replace all metadata with new value
+        meta = {'': 'data1'}
+        self.assertRaises(exceptions.BadRequest,
+                          self.client.set_server_metadata,
+                          self.server_id, meta=meta)
+
+        # Raise a bad request error for a missing metadata field
+        # set_server_metadata will replace all metadata with new value
+        meta = {'meta1': 'data1'}
+        self.assertRaises(exceptions.BadRequest,
+                          self.client.set_server_metadata,
+                          self.server_id, meta=meta, no_metadata_field=True)
+
+
+class ServerMetadataTestXML(ServerMetadataTestJSON):
+    _interface = 'xml'
diff --git a/tempest/api/compute/v3/servers/test_server_personality.py b/tempest/api/compute/v3/servers/test_server_personality.py
new file mode 100644
index 0000000..c6d2e44
--- /dev/null
+++ b/tempest/api/compute/v3/servers/test_server_personality.py
@@ -0,0 +1,68 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# 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.
+
+import base64
+
+from tempest.api.compute import base
+from tempest import exceptions
+from tempest.test import attr
+
+
+class ServerPersonalityTestJSON(base.BaseV2ComputeTest):
+    _interface = 'json'
+
+    @classmethod
+    def setUpClass(cls):
+        super(ServerPersonalityTestJSON, cls).setUpClass()
+        cls.client = cls.servers_client
+        cls.user_client = cls.limits_client
+
+    @attr(type='gate')
+    def test_personality_files_exceed_limit(self):
+        # Server creation should fail if greater than the maximum allowed
+        # number of files are injected into the server.
+        file_contents = 'This is a test file.'
+        personality = []
+        max_file_limit = \
+            self.user_client.get_specific_absolute_limit("maxPersonality")
+        for i in range(0, int(max_file_limit) + 1):
+            path = 'etc/test' + str(i) + '.txt'
+            personality.append({'path': path,
+                                'contents': base64.b64encode(file_contents)})
+        self.assertRaises(exceptions.OverLimit, self.create_test_server,
+                          personality=personality)
+
+    @attr(type='gate')
+    def test_can_create_server_with_max_number_personality_files(self):
+        # Server should be created successfully if maximum allowed number of
+        # files is injected into the server during creation.
+        file_contents = 'This is a test file.'
+        max_file_limit = \
+            self.user_client.get_specific_absolute_limit("maxPersonality")
+        person = []
+        for i in range(0, int(max_file_limit)):
+            path = 'etc/test' + str(i) + '.txt'
+            person.append({
+                'path': path,
+                'contents': base64.b64encode(file_contents),
+            })
+        resp, server = self.create_test_server(personality=person)
+        self.assertEqual('202', resp['status'])
+
+
+class ServerPersonalityTestXML(ServerPersonalityTestJSON):
+    _interface = "xml"
diff --git a/tempest/api/compute/v3/servers/test_server_rescue.py b/tempest/api/compute/v3/servers/test_server_rescue.py
new file mode 100644
index 0000000..eebd4d8
--- /dev/null
+++ b/tempest/api/compute/v3/servers/test_server_rescue.py
@@ -0,0 +1,173 @@
+# 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 tempest.api.compute import base
+from tempest import exceptions
+from tempest.test import attr
+
+
+class ServerRescueV3TestJSON(base.BaseV3ComputeTest):
+    _interface = 'json'
+
+    @classmethod
+    def setUpClass(cls):
+        super(ServerRescueV3TestJSON, cls).setUpClass()
+        cls.device = 'vdf'
+
+        # Create a volume and wait for it to become ready for attach
+        resp, cls.volume_to_attach = \
+            cls.volumes_client.create_volume(1,
+                                             display_name=
+                                             'test_attach')
+        cls.volumes_client.wait_for_volume_status(
+            cls.volume_to_attach['id'], 'available')
+
+        # Create a volume and wait for it to become ready for attach
+        resp, cls.volume_to_detach = \
+            cls.volumes_client.create_volume(1,
+                                             display_name=
+                                             'test_detach')
+        cls.volumes_client.wait_for_volume_status(
+            cls.volume_to_detach['id'], 'available')
+
+        # Server for positive tests
+        resp, server = cls.create_test_server(wait_until='BUILD')
+        resp, resc_server = cls.create_test_server(wait_until='ACTIVE')
+        cls.server_id = server['id']
+        cls.password = server['admin_password']
+        cls.servers_client.wait_for_server_status(cls.server_id, 'ACTIVE')
+
+        # Server for negative tests
+        cls.rescue_id = resc_server['id']
+        cls.rescue_password = resc_server['admin_password']
+
+        cls.servers_client.rescue_server(
+            cls.rescue_id, cls.rescue_password)
+        cls.servers_client.wait_for_server_status(cls.rescue_id, 'RESCUE')
+
+    def setUp(self):
+        super(ServerRescueV3TestJSON, self).setUp()
+
+    @classmethod
+    def tearDownClass(cls):
+        client = cls.volumes_client
+        client.delete_volume(str(cls.volume_to_attach['id']).strip())
+        client.delete_volume(str(cls.volume_to_detach['id']).strip())
+        super(ServerRescueV3TestJSON, cls).tearDownClass()
+
+    def tearDown(self):
+        super(ServerRescueV3TestJSON, self).tearDown()
+
+    def _detach(self, server_id, volume_id):
+        self.servers_client.detach_volume(server_id, volume_id)
+        self.volumes_client.wait_for_volume_status(volume_id,
+                                                   'available')
+
+    def _delete(self, volume_id):
+        self.volumes_client.delete_volume(volume_id)
+
+    def _unrescue(self, server_id):
+        resp, body = self.servers_client.unrescue_server(server_id)
+        self.assertEqual(202, resp.status)
+        self.servers_client.wait_for_server_status(server_id, 'ACTIVE')
+
+    def _unpause(self, server_id):
+        resp, body = self.servers_client.unpause_server(server_id)
+        self.assertEqual(202, resp.status)
+        self.servers_client.wait_for_server_status(server_id, 'ACTIVE')
+
+    @attr(type='smoke')
+    def test_rescue_unrescue_instance(self):
+        resp, body = self.servers_client.rescue_server(
+            self.server_id, self.password)
+        self.assertEqual(202, resp.status)
+        self.servers_client.wait_for_server_status(self.server_id, 'RESCUE')
+        resp, body = self.servers_client.unrescue_server(self.server_id)
+        self.assertEqual(202, resp.status)
+        self.servers_client.wait_for_server_status(self.server_id, 'ACTIVE')
+
+    @attr(type=['negative', 'gate'])
+    def test_rescue_paused_instance(self):
+        # Rescue a paused server
+        resp, body = self.servers_client.pause_server(
+            self.server_id)
+        self.addCleanup(self._unpause, self.server_id)
+        self.assertEqual(202, resp.status)
+        self.servers_client.wait_for_server_status(self.server_id, 'PAUSED')
+        self.assertRaises(exceptions.Conflict,
+                          self.servers_client.rescue_server,
+                          self.server_id)
+
+    @attr(type=['negative', 'gate'])
+    def test_rescued_vm_reboot(self):
+        self.assertRaises(exceptions.Conflict, self.servers_client.reboot,
+                          self.rescue_id, 'HARD')
+
+    @attr(type=['negative', 'gate'])
+    def test_rescue_non_existent_server(self):
+        # Rescue a non-existing server
+        self.assertRaises(exceptions.NotFound,
+                          self.servers_client.rescue_server,
+                          '999erra43')
+
+    @attr(type=['negative', 'gate'])
+    def test_rescued_vm_rebuild(self):
+        self.assertRaises(exceptions.Conflict,
+                          self.servers_client.rebuild,
+                          self.rescue_id,
+                          self.image_ref_alt)
+
+    @attr(type=['negative', 'gate'])
+    def test_rescued_vm_attach_volume(self):
+        # Rescue the server
+        self.servers_client.rescue_server(self.server_id, self.password)
+        self.servers_client.wait_for_server_status(self.server_id, 'RESCUE')
+        self.addCleanup(self._unrescue, self.server_id)
+
+        # Attach the volume to the server
+        self.assertRaises(exceptions.Conflict,
+                          self.servers_client.attach_volume,
+                          self.server_id,
+                          self.volume_to_attach['id'],
+                          device='/dev/%s' % self.device)
+
+    @attr(type=['negative', 'gate'])
+    def test_rescued_vm_detach_volume(self):
+        # Attach the volume to the server
+        self.servers_client.attach_volume(self.server_id,
+                                          self.volume_to_detach['id'],
+                                          device='/dev/%s' % self.device)
+        self.volumes_client.wait_for_volume_status(
+            self.volume_to_detach['id'], 'in-use')
+
+        # Rescue the server
+        self.servers_client.rescue_server(self.server_id, self.password)
+        self.servers_client.wait_for_server_status(self.server_id, 'RESCUE')
+        # addCleanup is a LIFO queue
+        self.addCleanup(self._detach, self.server_id,
+                        self.volume_to_detach['id'])
+        self.addCleanup(self._unrescue, self.server_id)
+
+        # Detach the volume from the server expecting failure
+        self.assertRaises(exceptions.Conflict,
+                          self.servers_client.detach_volume,
+                          self.server_id,
+                          self.volume_to_detach['id'])
+
+
+class ServerRescueV3TestXML(ServerRescueV3TestJSON):
+    _interface = 'xml'
diff --git a/tempest/api/compute/v3/servers/test_servers.py b/tempest/api/compute/v3/servers/test_servers.py
new file mode 100644
index 0000000..d72476d
--- /dev/null
+++ b/tempest/api/compute/v3/servers/test_servers.py
@@ -0,0 +1,133 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# 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.test import attr
+
+
+class ServersTestJSON(base.BaseV2ComputeTest):
+    _interface = 'json'
+
+    @classmethod
+    def setUpClass(cls):
+        super(ServersTestJSON, cls).setUpClass()
+        cls.client = cls.servers_client
+
+    def tearDown(self):
+        self.clear_servers()
+        super(ServersTestJSON, self).tearDown()
+
+    @attr(type='gate')
+    def test_create_server_with_admin_password(self):
+        # If an admin password is provided on server creation, the server's
+        # root password should be set to that password.
+        resp, server = self.create_test_server(adminPass='testpassword')
+
+        # Verify the password is set correctly in the response
+        self.assertEqual('testpassword', server['adminPass'])
+
+    @attr(type='gate')
+    def test_create_with_existing_server_name(self):
+        # Creating a server with a name that already exists is allowed
+
+        # TODO(sdague): clear out try, we do cleanup one layer up
+        server_name = data_utils.rand_name('server')
+        resp, server = self.create_test_server(name=server_name,
+                                               wait_until='ACTIVE')
+        id1 = server['id']
+        resp, server = self.create_test_server(name=server_name,
+                                               wait_until='ACTIVE')
+        id2 = server['id']
+        self.assertNotEqual(id1, id2, "Did not create a new server")
+        resp, server = self.client.get_server(id1)
+        name1 = server['name']
+        resp, server = self.client.get_server(id2)
+        name2 = server['name']
+        self.assertEqual(name1, name2)
+
+    @attr(type='gate')
+    def test_create_specify_keypair(self):
+        # Specify a keypair while creating a server
+
+        key_name = data_utils.rand_name('key')
+        resp, keypair = self.keypairs_client.create_keypair(key_name)
+        resp, body = self.keypairs_client.list_keypairs()
+        resp, server = self.create_test_server(key_name=key_name)
+        self.assertEqual('202', resp['status'])
+        self.client.wait_for_server_status(server['id'], 'ACTIVE')
+        resp, server = self.client.get_server(server['id'])
+        self.assertEqual(key_name, server['key_name'])
+
+    @attr(type='gate')
+    def test_update_server_name(self):
+        # The server name should be changed to the the provided value
+        resp, server = self.create_test_server(wait_until='ACTIVE')
+
+        # Update the server with a new name
+        resp, server = self.client.update_server(server['id'],
+                                                 name='newname')
+        self.assertEqual(200, resp.status)
+        self.client.wait_for_server_status(server['id'], 'ACTIVE')
+
+        # Verify the name of the server has changed
+        resp, server = self.client.get_server(server['id'])
+        self.assertEqual('newname', server['name'])
+
+    @attr(type='gate')
+    def test_update_access_server_address(self):
+        # The server's access addresses should reflect the provided values
+        resp, server = self.create_test_server(wait_until='ACTIVE')
+
+        # Update the IPv4 and IPv6 access addresses
+        resp, body = self.client.update_server(server['id'],
+                                               accessIPv4='1.1.1.1',
+                                               accessIPv6='::babe:202:202')
+        self.assertEqual(200, resp.status)
+        self.client.wait_for_server_status(server['id'], 'ACTIVE')
+
+        # Verify the access addresses have been updated
+        resp, server = self.client.get_server(server['id'])
+        self.assertEqual('1.1.1.1', server['accessIPv4'])
+        self.assertEqual('::babe:202:202', server['accessIPv6'])
+
+    @attr(type='gate')
+    def test_delete_server_while_in_building_state(self):
+        # Delete a server while it's VM state is Building
+        resp, server = self.create_test_server(wait_until='BUILD')
+        resp, _ = self.client.delete_server(server['id'])
+        self.assertEqual('204', resp['status'])
+
+    @attr(type='gate')
+    def test_delete_active_server(self):
+        # Delete a server while it's VM state is Active
+        resp, server = self.create_test_server(wait_until='ACTIVE')
+        resp, _ = self.client.delete_server(server['id'])
+        self.assertEqual('204', resp['status'])
+
+    @attr(type='gate')
+    def test_create_server_with_ipv6_addr_only(self):
+        # Create a server without an IPv4 address(only IPv6 address).
+        resp, server = self.create_test_server(accessIPv6='2001:2001::3')
+        self.assertEqual('202', resp['status'])
+        self.client.wait_for_server_status(server['id'], 'ACTIVE')
+        resp, server = self.client.get_server(server['id'])
+        self.assertEqual('2001:2001::3', server['accessIPv6'])
+
+
+class ServersTestXML(ServersTestJSON):
+    _interface = 'xml'
diff --git a/tempest/api/compute/v3/servers/test_servers_negative.py b/tempest/api/compute/v3/servers/test_servers_negative.py
index 5ec0cbe..8142250 100644
--- a/tempest/api/compute/v3/servers/test_servers_negative.py
+++ b/tempest/api/compute/v3/servers/test_servers_negative.py
@@ -34,7 +34,7 @@
         try:
             self.client.wait_for_server_status(self.server_id, 'ACTIVE')
         except Exception:
-            self.rebuild_server()
+            self.__class__.server_id = self.rebuild_server(self.server_id)
 
     @classmethod
     def setUpClass(cls):
diff --git a/tempest/api/compute/v3/test_extensions.py b/tempest/api/compute/v3/test_extensions.py
index d7269d1..2affd86 100644
--- a/tempest/api/compute/v3/test_extensions.py
+++ b/tempest/api/compute/v3/test_extensions.py
@@ -17,18 +17,26 @@
 
 
 from tempest.api.compute import base
-from tempest.test import attr
+from tempest import test
 
 
 class ExtensionsV3TestJSON(base.BaseV3ComputeTest):
     _interface = 'json'
 
-    @attr(type='gate')
+    @test.attr(type='gate')
     def test_list_extensions(self):
         # List of all extensions
         resp, extensions = self.extensions_client.list_extensions()
         self.assertIn("extensions", extensions)
         self.assertEqual(200, resp.status)
+        self.assertTrue(self.extensions_client.is_enabled("Consoles"))
+
+    @test.attr(type='gate')
+    def test_get_extension(self):
+        # get the specified extensions
+        resp, extension = self.extensions_client.get_extension('servers')
+        self.assertEqual(200, resp.status)
+        self.assertEqual('servers', extension['alias'])
 
 
 class ExtensionsV3TestXML(ExtensionsV3TestJSON):
diff --git a/tempest/api/compute/v3/test_quotas.py b/tempest/api/compute/v3/test_quotas.py
new file mode 100644
index 0000000..475d055
--- /dev/null
+++ b/tempest/api/compute/v3/test_quotas.py
@@ -0,0 +1,73 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# 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.test import attr
+
+
+class QuotasTestJSON(base.BaseV2ComputeTest):
+    _interface = 'json'
+
+    @classmethod
+    def setUpClass(cls):
+        super(QuotasTestJSON, cls).setUpClass()
+        cls.client = cls.quotas_client
+        cls.admin_client = cls._get_identity_admin_client()
+        resp, tenants = cls.admin_client.list_tenants()
+        cls.tenant_id = [tnt['id'] for tnt in tenants if tnt['name'] ==
+                         cls.client.tenant_name][0]
+        cls.default_quota_set = set(('injected_file_content_bytes',
+                                     'metadata_items', 'injected_files',
+                                     'ram', 'floating_ips',
+                                     'fixed_ips', 'key_pairs',
+                                     'injected_file_path_bytes',
+                                     'instances', 'security_group_rules',
+                                     'cores', 'security_groups'))
+
+    @attr(type='smoke')
+    def test_get_quotas(self):
+        # User can get the quota set for it's tenant
+        expected_quota_set = self.default_quota_set | set(['id'])
+        resp, quota_set = self.client.get_quota_set(self.tenant_id)
+        self.assertEqual(200, resp.status)
+        self.assertEqual(sorted(expected_quota_set),
+                         sorted(quota_set.keys()))
+        self.assertEqual(quota_set['id'], self.tenant_id)
+
+    @attr(type='smoke')
+    def test_get_default_quotas(self):
+        # User can get the default quota set for it's tenant
+        expected_quota_set = self.default_quota_set | set(['id'])
+        resp, quota_set = self.client.get_default_quota_set(self.tenant_id)
+        self.assertEqual(200, resp.status)
+        self.assertEqual(sorted(expected_quota_set),
+                         sorted(quota_set.keys()))
+        self.assertEqual(quota_set['id'], self.tenant_id)
+
+    @attr(type='smoke')
+    def test_compare_tenant_quotas_with_default_quotas(self):
+        # Tenants are created with the default quota values
+        resp, defualt_quota_set = \
+            self.client.get_default_quota_set(self.tenant_id)
+        self.assertEqual(200, resp.status)
+        resp, tenant_quota_set = self.client.get_quota_set(self.tenant_id)
+        self.assertEqual(200, resp.status)
+        self.assertEqual(defualt_quota_set, tenant_quota_set)
+
+
+class QuotasTestXML(QuotasTestJSON):
+    _interface = 'xml'
diff --git a/tempest/api/compute/volumes/test_volumes_list.py b/tempest/api/compute/volumes/test_volumes_list.py
index f214641..b57dcfe 100644
--- a/tempest/api/compute/volumes/test_volumes_list.py
+++ b/tempest/api/compute/volumes/test_volumes_list.py
@@ -43,9 +43,8 @@
         cls.volume_list = []
         cls.volume_id_list = []
         for i in range(3):
-            v_name = data_utils.rand_name('volume-%s')
+            v_name = data_utils.rand_name('volume-%s' % cls._interface)
             metadata = {'Type': 'work'}
-            v_name += cls._interface
             try:
                 resp, volume = cls.client.create_volume(size=1,
                                                         display_name=v_name,
@@ -110,6 +109,65 @@
                          ', '.join(m_vol['displayName']
                                    for m_vol in missing_volumes))
 
+    @attr(type='gate')
+    def test_volume_list_param_limit(self):
+        # Return the list of volumes based on limit set
+        params = {'limit': 2}
+        resp, fetched_vol_list = self.client.list_volumes(params=params)
+        self.assertEqual(200, resp.status)
+
+        self.assertEqual(len(fetched_vol_list), params['limit'],
+                         "Failed to list volumes by limit set")
+
+    @attr(type='gate')
+    def test_volume_list_with_detail_param_limit(self):
+        # Return the list of volumes with details based on limit set.
+        params = {'limit': 2}
+        resp, fetched_vol_list = \
+            self.client.list_volumes_with_detail(params=params)
+        self.assertEqual(200, resp.status)
+
+        self.assertEqual(len(fetched_vol_list), params['limit'],
+                         "Failed to list volume details by limit set")
+
+    @attr(type='gate')
+    def test_volume_list_param_offset_and_limit(self):
+        # Return the list of volumes based on offset and limit set.
+        # get all volumes list
+        response, all_vol_list = self.client.list_volumes()
+        params = {'offset': 1, 'limit': 1}
+        resp, fetched_vol_list = self.client.list_volumes(params=params)
+        self.assertEqual(200, resp.status)
+
+        # Validating length of the fetched volumes
+        self.assertEqual(len(fetched_vol_list), params['limit'],
+                         "Failed to list volumes by offset and limit")
+        # Validating offset of fetched volume
+        for index, volume in enumerate(fetched_vol_list):
+            self.assertEqual(volume['id'],
+                             all_vol_list[index + params['offset']]['id'],
+                             "Failed to list volumes by offset and limit")
+
+    @attr(type='gate')
+    def test_volume_list_with_detail_param_offset_and_limit(self):
+        # Return the list of volumes details based on offset and limit set.
+        # get all volumes list
+        response, all_vol_list = self.client.list_volumes_with_detail()
+        params = {'offset': 1, 'limit': 1}
+        resp, fetched_vol_list = \
+            self.client.list_volumes_with_detail(params=params)
+        self.assertEqual(200, resp.status)
+
+        # Validating length of the fetched volumes
+        self.assertEqual(len(fetched_vol_list), params['limit'],
+                         "Failed to list volume details by offset and limit")
+        # Validating offset of fetched volume
+        for index, volume in enumerate(fetched_vol_list):
+            self.assertEqual(volume['id'],
+                             all_vol_list[index + params['offset']]['id'],
+                             "Failed to list volume details by "
+                             "offset and limit")
+
 
 class VolumesTestXML(VolumesTestJSON):
     _interface = 'xml'
diff --git a/tempest/api/identity/admin/v3/test_trusts.py b/tempest/api/identity/admin/v3/test_trusts.py
new file mode 100644
index 0000000..5e13a5a
--- /dev/null
+++ b/tempest/api/identity/admin/v3/test_trusts.py
@@ -0,0 +1,222 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+#    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.identity import base
+from tempest import clients
+from tempest.common.utils.data_utils import rand_name
+from tempest import exceptions
+from tempest.test import attr
+
+
+class BaseTrustsV3Test(base.BaseIdentityAdminTest):
+
+    def setUp(self):
+        super(BaseTrustsV3Test, self).setUp()
+        # Use alt_username as the trustee
+        self.trustee_username = self.config.identity.alt_username
+
+        self.trust_id = None
+        self.create_trustor_and_roles()
+        self.addCleanup(self.cleanup_trust_user_and_roles)
+
+    def create_trustor_and_roles(self):
+        # Get trustor project ID, use the admin project
+        self.trustor_project_name = self.v3_client.tenant_name
+        self.trustor_project_id = self.get_tenant_by_name(
+            self.trustor_project_name)['id']
+        self.assertIsNotNone(self.trustor_project_id)
+
+        # Create a trustor User
+        self.trustor_username = rand_name('user-')
+        u_desc = self.trustor_username + 'description'
+        u_email = self.trustor_username + '@testmail.tm'
+        self.trustor_password = rand_name('pass-')
+        resp, user = self.v3_client.create_user(
+            self.trustor_username,
+            description=u_desc,
+            password=self.trustor_password,
+            email=u_email,
+            project_id=self.trustor_project_id)
+        self.assertEqual(resp['status'], '201')
+        self.trustor_user_id = user['id']
+
+        # And two roles, one we'll delegate and one we won't
+        self.delegated_role = rand_name('DelegatedRole-')
+        self.not_delegated_role = rand_name('NotDelegatedRole-')
+
+        resp, role = self.v3_client.create_role(self.delegated_role)
+        self.assertEqual(resp['status'], '201')
+        self.delegated_role_id = role['id']
+
+        resp, role = self.v3_client.create_role(self.not_delegated_role)
+        self.assertEqual(resp['status'], '201')
+        self.not_delegated_role_id = role['id']
+
+        # Assign roles to trustor
+        self.v3_client.assign_user_role(self.trustor_project_id,
+                                        self.trustor_user_id,
+                                        self.delegated_role_id)
+        self.v3_client.assign_user_role(self.trustor_project_id,
+                                        self.trustor_user_id,
+                                        self.not_delegated_role_id)
+
+        # Get trustee user ID, use the demo user
+        trustee_username = self.v3_non_admin_client.user
+        self.trustee_user_id = self.get_user_by_name(trustee_username)['id']
+        self.assertIsNotNone(self.trustee_user_id)
+
+        # Initialize a new client with the trustor credentials
+        os = clients.Manager(username=self.trustor_username,
+                             password=self.trustor_password,
+                             tenant_name=self.trustor_project_name,
+                             interface=self._interface)
+        self.trustor_v3_client = os.identity_v3_client
+
+    def cleanup_trust_user_and_roles(self):
+        if self.trust_id:
+            try:
+                self.trustor_v3_client.delete_trust(self.trust_id)
+            except exceptions.NotFound:
+                pass
+            self.trust_id = None
+
+        if self.trustor_user_id:
+            self.v3_client.delete_user(self.trustor_user_id)
+        if self.delegated_role_id:
+            self.v3_client.delete_role(self.delegated_role_id)
+        if self.not_delegated_role_id:
+            self.v3_client.delete_role(self.not_delegated_role_id)
+
+    def create_trust(self, impersonate=True, expires=None):
+
+        resp, trust_create = self.trustor_v3_client.create_trust(
+            trustor_user_id=self.trustor_user_id,
+            trustee_user_id=self.trustee_user_id,
+            project_id=self.trustor_project_id,
+            role_names=[self.delegated_role],
+            impersonation=impersonate,
+            expires_at=expires)
+        self.assertEqual('201', resp['status'])
+        self.trust_id = trust_create['id']
+        return trust_create
+
+    def validate_trust(self, trust, impersonate=True, expires=None,
+                       summary=False):
+        self.assertIsNotNone(trust['id'])
+        self.assertEqual(impersonate, trust['impersonation'])
+        self.assertEqual(expires, trust['expires_at'])
+        self.assertEqual(self.trustor_user_id, trust['trustor_user_id'])
+        self.assertEqual(self.trustee_user_id, trust['trustee_user_id'])
+        self.assertIn('v3/OS-TRUST/trusts', trust['links']['self'])
+        self.assertEqual(self.trustor_project_id, trust['project_id'])
+        if not summary:
+            self.assertEqual(self.delegated_role, trust['roles'][0]['name'])
+            self.assertEqual(1, len(trust['roles']))
+
+    def get_trust(self):
+        resp, trust_get = self.trustor_v3_client.get_trust(self.trust_id)
+        self.assertEqual('200', resp['status'])
+        return trust_get
+
+    def validate_role(self, role):
+        self.assertEqual(self.delegated_role_id, role['id'])
+        self.assertEqual(self.delegated_role, role['name'])
+        self.assertIn('v3/roles/%s' % self.delegated_role_id,
+                      role['links']['self'])
+        self.assertNotEqual(self.not_delegated_role_id, role['id'])
+        self.assertNotEqual(self.not_delegated_role, role['name'])
+        self.assertNotIn('v3/roles/%s' % self.not_delegated_role_id,
+                         role['links']['self'])
+
+    def check_trust_roles(self):
+        # Check we find the delegated role
+        resp, roles_get = self.trustor_v3_client.get_trust_roles(
+            self.trust_id)
+        self.assertEqual('200', resp['status'])
+        self.assertEqual(1, len(roles_get))
+        self.validate_role(roles_get[0])
+
+        resp, role_get = self.trustor_v3_client.get_trust_role(
+            self.trust_id, self.delegated_role_id)
+        self.assertEqual('200', resp['status'])
+        self.validate_role(role_get)
+
+        resp, role_get = self.trustor_v3_client.check_trust_role(
+            self.trust_id, self.delegated_role_id)
+        self.assertEqual('204', resp['status'])
+
+        # And that we don't find not_delegated_role
+        self.assertRaises(exceptions.NotFound,
+                          self.trustor_v3_client.get_trust_role,
+                          self.trust_id,
+                          self.not_delegated_role_id)
+
+        self.assertRaises(exceptions.NotFound,
+                          self.trustor_v3_client.check_trust_role,
+                          self.trust_id,
+                          self.not_delegated_role_id)
+
+    def delete_trust(self):
+        resp, trust_delete = self.trustor_v3_client.delete_trust(self.trust_id)
+        self.assertEqual('204', resp['status'])
+        self.assertRaises(exceptions.NotFound,
+                          self.trustor_v3_client.get_trust,
+                          self.trust_id)
+        self.trust_id = None
+
+
+class TrustsV3TestJSON(BaseTrustsV3Test):
+    _interface = 'json'
+
+    def setUp(self):
+        super(TrustsV3TestJSON, self).setUp()
+        self.create_trustor_and_roles()
+
+    @attr(type='smoke')
+    def test_trust_impersonate(self):
+        # Test case to check we can create, get and delete a trust
+        # updates are not supported for trusts
+        trust = self.create_trust()
+        self.validate_trust(trust)
+
+        trust_get = self.get_trust()
+        self.validate_trust(trust_get)
+
+        self.check_trust_roles()
+
+        self.delete_trust()
+
+    @attr(type='smoke')
+    def test_trust_noimpersonate(self):
+        # Test case to check we can create, get and delete a trust
+        # with impersonation=False
+        trust = self.create_trust(impersonate=False)
+        self.validate_trust(trust, impersonate=False)
+
+        trust_get = self.get_trust()
+        self.validate_trust(trust_get, impersonate=False)
+
+        self.check_trust_roles()
+
+        self.delete_trust()
+
+    @attr(type='smoke')
+    def test_trust_expire_invalid(self):
+        # Test case to check we can check an invlaid expiry time
+        # is rejected with the correct error
+        # with an expiry specified
+        expires_str = 'bad.123Z'
+        self.assertRaises(exceptions.BadRequest,
+                          self.create_trust,
+                          expires=expires_str)
diff --git a/tempest/api/network/admin/test_agent_management.py b/tempest/api/network/admin/test_agent_management.py
new file mode 100644
index 0000000..94659b2
--- /dev/null
+++ b/tempest/api/network/admin/test_agent_management.py
@@ -0,0 +1,82 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 IBM Corp.
+#
+#    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.network import base
+from tempest.common import tempest_fixtures as fixtures
+from tempest.test import attr
+
+
+class AgentManagementTestJSON(base.BaseAdminNetworkTest):
+    _interface = 'json'
+
+    @classmethod
+    def setUpClass(cls):
+        super(AgentManagementTestJSON, cls).setUpClass()
+        resp, body = cls.admin_client.list_agents()
+        agents = body['agents']
+        cls.agent = agents[0]
+
+    @attr(type='smoke')
+    def test_list_agent(self):
+        resp, body = self.admin_client.list_agents()
+        self.assertEqual('200', resp['status'])
+        agents = body['agents']
+        self.assertIn(self.agent, agents)
+
+    @attr(type='smoke')
+    def test_show_agent(self):
+        resp, body = self.admin_client.show_agent(self.agent['id'])
+        agent = body['agent']
+        self.assertEqual('200', resp['status'])
+        self.assertEqual(agent['id'], self.agent['id'])
+
+    @attr(type='smoke')
+    def test_update_agent_status(self):
+        origin_status = self.agent['admin_state_up']
+        # Try to update the 'admin_state_up' to the original
+        # one to avoid the negative effect.
+        agent_status = {'admin_state_up': origin_status}
+        resp, body = self.admin_client.update_agent(agent_id=self.agent['id'],
+                                                    agent_info=agent_status)
+        updated_status = body['agent']['admin_state_up']
+        self.assertEqual('200', resp['status'])
+        self.assertEqual(origin_status, updated_status)
+
+    @attr(type='smoke')
+    def test_update_agent_description(self):
+        self.useFixture(fixtures.LockFixture('agent_description'))
+        description = 'description for update agent.'
+        agent_description = {'description': description}
+        resp, body = self.admin_client.update_agent(
+            agent_id=self.agent['id'],
+            agent_info=agent_description)
+        self.assertEqual('200', resp['status'])
+        self.addCleanup(self._restore_agent)
+        updated_description = body['agent']['description']
+        self.assertEqual(updated_description, description)
+
+    def _restore_agent(self):
+        """
+        Restore the agent description after update test.
+        """
+        description = self.agent['description'] or ''
+        origin_agent = {'description': description}
+        self.admin_client.update_agent(agent_id=self.agent['id'],
+                                       agent_info=origin_agent)
+
+
+class AgentManagementTestXML(AgentManagementTestJSON):
+    _interface = 'xml'
diff --git a/tempest/api/network/admin/test_dhcp_agent_scheduler.py b/tempest/api/network/admin/test_dhcp_agent_scheduler.py
new file mode 100644
index 0000000..ac10e68
--- /dev/null
+++ b/tempest/api/network/admin/test_dhcp_agent_scheduler.py
@@ -0,0 +1,78 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 IBM Corp.
+#
+#    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.network import base
+from tempest.test import attr
+
+
+class DHCPAgentSchedulersTestJSON(base.BaseAdminNetworkTest):
+    _interface = 'json'
+
+    @classmethod
+    def setUpClass(cls):
+        super(DHCPAgentSchedulersTestJSON, cls).setUpClass()
+        # Create a network and make sure it will be hosted by a
+        # dhcp agent.
+        cls.network = cls.create_network()
+        cls.subnet = cls.create_subnet(cls.network)
+        cls.cidr = cls.subnet['cidr']
+        cls.port = cls.create_port(cls.network)
+
+    @attr(type='smoke')
+    def test_list_dhcp_agent_hosting_network(self):
+        resp, body = self.admin_client.list_dhcp_agent_hosting_network(
+            self.network['id'])
+        self.assertEqual(resp['status'], '200')
+
+    @attr(type='smoke')
+    def test_list_networks_hosted_by_one_dhcp(self):
+        resp, body = self.admin_client.list_dhcp_agent_hosting_network(
+            self.network['id'])
+        agents = body['agents']
+        self.assertIsNotNone(agents)
+        agent = agents[0]
+        self.assertTrue(self._check_network_in_dhcp_agent(
+            self.network['id'], agent))
+
+    def _check_network_in_dhcp_agent(self, network_id, agent):
+        network_ids = []
+        resp, body = self.admin_client.list_networks_hosted_by_one_dhcp_agent(
+            agent['id'])
+        self.assertEqual(resp['status'], '200')
+        networks = body['networks']
+        for network in networks:
+            network_ids.append(network['id'])
+        return network_id in network_ids
+
+    @attr(type='smoke')
+    def test_remove_network_from_dhcp_agent(self):
+        resp, body = self.admin_client.list_dhcp_agent_hosting_network(
+            self.network['id'])
+        agents = body['agents']
+        self.assertIsNotNone(agents)
+        # Get an agent.
+        agent = agents[0]
+        network_id = self.network['id']
+        resp, body = self.admin_client.remove_network_from_dhcp_agent(
+            agent_id=agent['id'],
+            network_id=network_id)
+        self.assertEqual(resp['status'], '204')
+        self.assertFalse(self._check_network_in_dhcp_agent(
+            network_id, agent))
+
+
+class DHCPAgentSchedulersTestXML(DHCPAgentSchedulersTestJSON):
+    _interface = 'xml'
diff --git a/tempest/api/network/admin/test_l3_agent_scheduler.py b/tempest/api/network/admin/test_l3_agent_scheduler.py
index 9c187fd..64ab051 100644
--- a/tempest/api/network/admin/test_l3_agent_scheduler.py
+++ b/tempest/api/network/admin/test_l3_agent_scheduler.py
@@ -16,7 +16,7 @@
 
 from tempest.api.network import base
 from tempest.common.utils import data_utils
-from tempest.test import attr
+from tempest import test
 
 
 class L3AgentSchedulerJSON(base.BaseAdminNetworkTest):
@@ -36,8 +36,11 @@
     @classmethod
     def setUpClass(cls):
         super(L3AgentSchedulerJSON, cls).setUpClass()
+        if not test.is_extension_enabled('l3_agent_scheduler', 'network'):
+            msg = "L3 Agent Scheduler Extension not enabled."
+            raise cls.skipException(msg)
 
-    @attr(type='smoke')
+    @test.attr(type='smoke')
     def test_list_routers_on_l3_agent(self):
         resp, body = self.admin_client.list_agents()
         agents = body['agents']
@@ -48,7 +51,7 @@
             agent['id'])
         self.assertEqual('200', resp['status'])
 
-    @attr(type='smoke')
+    @test.attr(type='smoke')
     def test_list_l3_agents_hosting_router(self):
         name = data_utils.rand_name('router-')
         resp, router = self.client.create_router(name)
diff --git a/tempest/api/network/base.py b/tempest/api/network/base.py
index b222ae3..064eaff 100644
--- a/tempest/api/network/base.py
+++ b/tempest/api/network/base.py
@@ -65,12 +65,16 @@
         cls.members = []
         cls.health_monitors = []
         cls.vpnservices = []
+        cls.ikepolicies = []
 
     @classmethod
     def tearDownClass(cls):
+        # Clean up ike policies
+        for ikepolicy in cls.ikepolicies:
+            cls.client.delete_ikepolicy(ikepolicy['id'])
         # Clean up vpn services
         for vpnservice in cls.vpnservices:
-            cls.client.delete_vpn_service(vpnservice['id'])
+            cls.client.delete_vpnservice(vpnservice['id'])
         # Clean up routers
         for router in cls.routers:
             resp, body = cls.client.list_router_interfaces(router['id'])
@@ -209,13 +213,21 @@
     @classmethod
     def create_vpnservice(cls, subnet_id, router_id):
         """Wrapper utility that returns a test vpn service."""
-        resp, body = cls.client.create_vpn_service(
+        resp, body = cls.client.create_vpnservice(
             subnet_id, router_id, admin_state_up=True,
             name=data_utils.rand_name("vpnservice-"))
         vpnservice = body['vpnservice']
         cls.vpnservices.append(vpnservice)
         return vpnservice
 
+    @classmethod
+    def create_ikepolicy(cls, name):
+        """Wrapper utility that returns a test ike policy."""
+        resp, body = cls.client.create_ikepolicy(name)
+        ikepolicy = body['ikepolicy']
+        cls.ikepolicies.append(ikepolicy)
+        return ikepolicy
+
 
 class BaseAdminNetworkTest(BaseNetworkTest):
 
diff --git a/tempest/api/network/common.py b/tempest/api/network/common.py
index ab19fa8..528a204 100644
--- a/tempest/api/network/common.py
+++ b/tempest/api/network/common.py
@@ -47,6 +47,9 @@
     def delete(self):
         raise NotImplemented()
 
+    def __hash__(self):
+        return id(self)
+
 
 class DeletableNetwork(DeletableResource):
 
@@ -86,6 +89,23 @@
 
 class DeletableFloatingIp(DeletableResource):
 
+    def update(self, *args, **kwargs):
+        result = self.client.update_floatingip(floatingip=self.id,
+                                               body=dict(
+                                                   floatingip=dict(*args,
+                                                                   **kwargs)
+                                               ))
+        super(DeletableFloatingIp, self).update(**result['floatingip'])
+
+    def __repr__(self):
+        return '<%s addr="%s">' % (self.__class__.__name__,
+                                   self.floating_ip_address)
+
+    def __str__(self):
+        return '<"FloatingIP" addr="%s" id="%s">' % (self.__class__.__name__,
+                                                     self.floating_ip_address,
+                                                     self.id)
+
     def delete(self):
         self.client.delete_floatingip(self.id)
 
diff --git a/tempest/api/network/test_extensions.py b/tempest/api/network/test_extensions.py
index 1b27d1b..9d872f9 100644
--- a/tempest/api/network/test_extensions.py
+++ b/tempest/api/network/test_extensions.py
@@ -17,7 +17,7 @@
 
 
 from tempest.api.network import base
-from tempest.test import attr
+from tempest import test
 
 
 class ExtensionsTestJSON(base.BaseNetworkTest):
@@ -38,7 +38,7 @@
     def setUpClass(cls):
         super(ExtensionsTestJSON, cls).setUpClass()
 
-    @attr(type='smoke')
+    @test.attr(type='smoke')
     def test_list_show_extensions(self):
         # List available extensions for the tenant
         expected_alias = ['security-group', 'l3_agent_scheduler',
@@ -55,7 +55,7 @@
             ext_name = ext['name']
             ext_alias = ext['alias']
             actual_alias.append(ext['alias'])
-            resp, ext_details = self.client.show_extension_details(ext_alias)
+            resp, ext_details = self.client.show_extension(ext_alias)
             self.assertEqual('200', resp['status'])
             ext_details = ext_details['extension']
 
@@ -70,9 +70,11 @@
             self.assertEqual(ext_details['alias'], ext_alias)
             self.assertEqual(ext_details, ext)
         # Verify if expected extensions are present in the actual list
-        # of extensions returned
+        # of extensions returned, but only for those that have been
+        # enabled via configuration
         for e in expected_alias:
-            self.assertIn(e, actual_alias)
+            if test.is_extension_enabled(e, 'network'):
+                self.assertIn(e, actual_alias)
 
 
 class ExtensionsTestXML(ExtensionsTestJSON):
diff --git a/tempest/api/network/test_floating_ips.py b/tempest/api/network/test_floating_ips.py
index 35d4fa8..3a41f4f 100644
--- a/tempest/api/network/test_floating_ips.py
+++ b/tempest/api/network/test_floating_ips.py
@@ -68,10 +68,10 @@
 
     def _delete_floating_ip(self, floating_ip_id):
         # Deletes a floating IP and verifies if it is deleted or not
-        resp, _ = self.client.delete_floating_ip(floating_ip_id)
+        resp, _ = self.client.delete_floatingip(floating_ip_id)
         self.assertEqual(204, resp.status)
         # Asserting that the floating_ip is not found in list after deletion
-        resp, floating_ips = self.client.list_floating_ips()
+        resp, floating_ips = self.client.list_floatingips()
         floatingip_id_list = list()
         for f in floating_ips['floatingips']:
             floatingip_id_list.append(f['id'])
@@ -106,7 +106,7 @@
         self.assertEqual(show_floating_ip['port_id'], self.port[0]['id'])
 
         # Verify the floating ip exists in the list of all floating_ips
-        resp, floating_ips = self.client.list_floating_ips()
+        resp, floating_ips = self.client.list_floatingips()
         self.assertEqual('200', resp['status'])
         floatingip_id_list = list()
         for f in floating_ips['floatingips']:
diff --git a/tempest/api/network/test_quotas.py b/tempest/api/network/test_quotas.py
index f7ba3cb..8b77637 100644
--- a/tempest/api/network/test_quotas.py
+++ b/tempest/api/network/test_quotas.py
@@ -74,12 +74,13 @@
         resp, non_default_quotas = self.admin_client.list_quotas()
         self.assertEqual('200', resp['status'])
         found = False
-        for qs in non_default_quotas:
+        for qs in non_default_quotas['quotas']:
             if qs['tenant_id'] == tenant_id:
                 found = True
         self.assertTrue(found)
         # Confirm from APi quotas were changed as requested for tenant
         resp, quota_set = self.admin_client.show_quotas(tenant_id)
+        quota_set = quota_set['quota']
         self.assertEqual('200', resp['status'])
         self.assertEqual(0, quota_set['network'])
         self.assertEqual(0, quota_set['security_group'])
@@ -88,5 +89,5 @@
         self.assertEqual('204', resp['status'])
         resp, non_default_quotas = self.admin_client.list_quotas()
         self.assertEqual('200', resp['status'])
-        for q in non_default_quotas:
+        for q in non_default_quotas['quotas']:
             self.assertNotEqual(tenant_id, q['tenant_id'])
diff --git a/tempest/api/network/test_routers.py b/tempest/api/network/test_routers.py
index 3cbe23f..06e07bb 100644
--- a/tempest/api/network/test_routers.py
+++ b/tempest/api/network/test_routers.py
@@ -15,6 +15,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import netaddr
+
 from tempest.api.network import base
 from tempest.common.utils import data_utils
 from tempest.test import attr
@@ -229,3 +231,22 @@
             {'network_id': self.network_cfg.public_network_id,
              'enable_snat': False})
         self._verify_gateway_port(router['id'])
+
+    @attr(type='smoke')
+    def test_update_extra_route(self):
+        self.network = self.create_network()
+        self.name = self.network['name']
+        self.subnet = self.create_subnet(self.network)
+        # Add router interface with subnet id
+        self.router = self.create_router(data_utils.rand_name('router-'), True)
+        self.create_router_interface(self.router['id'], self.subnet['id'])
+        self.addCleanup(
+            self._delete_extra_routes,
+            self.router['id'])
+        # Update router extra route
+        cidr = netaddr.IPNetwork(self.subnet['cidr'])
+        resp, extra_route = self.client.update_extra_routes(
+            self.router['id'], str(cidr[0]), str(self.subnet['cidr']))
+
+    def _delete_extra_routes(self, router_id):
+        resp, _ = self.client.delete_extra_routes(router_id)
diff --git a/tempest/api/network/test_security_groups_negative.py b/tempest/api/network/test_security_groups_negative.py
index cb0c247..32f4c95 100644
--- a/tempest/api/network/test_security_groups_negative.py
+++ b/tempest/api/network/test_security_groups_negative.py
@@ -15,10 +15,11 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import uuid
+
 from tempest.api.network import base_security_groups as base
 from tempest import exceptions
 from tempest.test import attr
-import uuid
 
 
 class NegativeSecGroupTest(base.BaseSecGroupTest):
@@ -74,6 +75,22 @@
                                    port_range_max=pmax)
             self.assertIn(msg, str(ex))
 
+    @attr(type=['negative', 'smoke'])
+    def test_create_additional_default_security_group_fails(self):
+        # Create security group named 'default', it should be failed.
+        name = 'default'
+        self.assertRaises(exceptions.Conflict,
+                          self.client.create_security_group,
+                          name)
+
+    @attr(type=['negative', 'smoke'])
+    def test_create_security_group_rule_with_non_existent_security_group(self):
+        # Create security group rules with not existing security group.
+        non_existent_sg = str(uuid.uuid4())
+        self.assertRaises(exceptions.NotFound,
+                          self.client.create_security_group_rule,
+                          non_existent_sg)
+
 
 class NegativeSecGroupTestXML(NegativeSecGroupTest):
     _interface = 'xml'
diff --git a/tempest/api/network/test_vpnaas_extensions.py b/tempest/api/network/test_vpnaas_extensions.py
index 9cbc7ac..fc3b1d9 100644
--- a/tempest/api/network/test_vpnaas_extensions.py
+++ b/tempest/api/network/test_vpnaas_extensions.py
@@ -32,6 +32,7 @@
         Create VPN Services
         Update VPN Services
         Delete VPN Services
+        List, Show, Create, Delete, and Update IKE policy
     """
 
     @classmethod
@@ -39,15 +40,35 @@
         super(VPNaaSJSON, cls).setUpClass()
         cls.network = cls.create_network()
         cls.subnet = cls.create_subnet(cls.network)
-        cls.router = cls.create_router(data_utils.rand_name("router-"))
+        cls.router = cls.create_router(
+            data_utils.rand_name("router-"),
+            external_network_id=cls.network_cfg.public_network_id)
         cls.create_router_interface(cls.router['id'], cls.subnet['id'])
         cls.vpnservice = cls.create_vpnservice(cls.subnet['id'],
                                                cls.router['id'])
+        cls.ikepolicy = cls.create_ikepolicy(
+            data_utils.rand_name("ike-policy-"))
+
+    def _delete_ike_policy(self, ike_policy_id):
+        # Deletes a ike policy and verifies if it is deleted or not
+        ike_list = list()
+        resp, all_ike = self.client.list_ikepolicies()
+        for ike in all_ike['ikepolicies']:
+            ike_list.append(ike['id'])
+        if ike_policy_id in ike_list:
+            resp, _ = self.client.delete_ikepolicy(ike_policy_id)
+            self.assertEqual(204, resp.status)
+            # Asserting that the policy is not found in list after deletion
+            resp, ikepolicies = self.client.list_ikepolicies()
+            ike_id_list = list()
+            for i in ikepolicies['ikepolicies']:
+                ike_id_list.append(i['id'])
+            self.assertNotIn(ike_policy_id, ike_id_list)
 
     @attr(type='smoke')
     def test_list_vpn_services(self):
         # Verify the VPN service exists in the list of all VPN services
-        resp, body = self.client.list_vpn_services()
+        resp, body = self.client.list_vpnservices()
         self.assertEqual('200', resp['status'])
         vpnservices = body['vpnservices']
         self.assertIn(self.vpnservice['id'], [v['id'] for v in vpnservices])
@@ -56,14 +77,14 @@
     def test_create_update_delete_vpn_service(self):
         # Creates a VPN service
         name = data_utils.rand_name('vpn-service-')
-        resp, body = self.client.create_vpn_service(self.subnet['id'],
-                                                    self.router['id'],
-                                                    name=name,
-                                                    admin_state_up=True)
+        resp, body = self.client.create_vpnservice(self.subnet['id'],
+                                                   self.router['id'],
+                                                   name=name,
+                                                   admin_state_up=True)
         self.assertEqual('201', resp['status'])
         vpnservice = body['vpnservice']
         # Assert if created vpnservices are not found in vpnservices list
-        resp, body = self.client.list_vpn_services()
+        resp, body = self.client.list_vpnservices()
         vpn_services = [vs['id'] for vs in body['vpnservices']]
         self.assertIsNotNone(vpnservice['id'])
         self.assertIn(vpnservice['id'], vpn_services)
@@ -74,17 +95,17 @@
         # should be "ACTIVE" not "PENDING*"
 
         # Verification of vpn service delete
-        resp, body = self.client.delete_vpn_service(vpnservice['id'])
+        resp, body = self.client.delete_vpnservice(vpnservice['id'])
         self.assertEqual('204', resp['status'])
         # Asserting if vpn service is found in the list after deletion
-        resp, body = self.client.list_vpn_services()
+        resp, body = self.client.list_vpnservices()
         vpn_services = [vs['id'] for vs in body['vpnservices']]
         self.assertNotIn(vpnservice['id'], vpn_services)
 
     @attr(type='smoke')
     def test_show_vpn_service(self):
         # Verifies the details of a vpn service
-        resp, body = self.client.show_vpn_service(self.vpnservice['id'])
+        resp, body = self.client.show_vpnservice(self.vpnservice['id'])
         self.assertEqual('200', resp['status'])
         vpnservice = body['vpnservice']
         self.assertEqual(self.vpnservice['id'], vpnservice['id'])
@@ -94,3 +115,59 @@
         self.assertEqual(self.vpnservice['router_id'], vpnservice['router_id'])
         self.assertEqual(self.vpnservice['subnet_id'], vpnservice['subnet_id'])
         self.assertEqual(self.vpnservice['tenant_id'], vpnservice['tenant_id'])
+
+    @attr(type='smoke')
+    def test_list_ike_policies(self):
+        # Verify the ike policy exists in the list of all IKE policies
+        resp, body = self.client.list_ikepolicies()
+        self.assertEqual('200', resp['status'])
+        ikepolicies = body['ikepolicies']
+        self.assertIn(self.ikepolicy['id'], [i['id'] for i in ikepolicies])
+
+    @attr(type='smoke')
+    def test_create_update_delete_ike_policy(self):
+        # Creates a IKE policy
+        name = data_utils.rand_name('ike-policy-')
+        resp, body = (self.client.create_ikepolicy(
+                      name,
+                      ike_version="v1",
+                      encryption_algorithm="aes-128",
+                      auth_algorithm="sha1"))
+        self.assertEqual('201', resp['status'])
+        ikepolicy = body['ikepolicy']
+        self.addCleanup(self._delete_ike_policy, ikepolicy['id'])
+        # Verification of ike policy update
+        description = "Updated ike policy"
+        new_ike = {'description': description, 'pfs': 'group5',
+                   'name': data_utils.rand_name("New-IKE-")}
+        resp, body = self.client.update_ikepolicy(ikepolicy['id'],
+                                                  **new_ike)
+        self.assertEqual('200', resp['status'])
+        updated_ike_policy = body['ikepolicy']
+        self.assertEqual(updated_ike_policy['description'], description)
+        # Verification of ike policy delete
+        resp, body = self.client.delete_ikepolicy(ikepolicy['id'])
+        self.assertEqual('204', resp['status'])
+
+    @attr(type='smoke')
+    def test_show_ike_policy(self):
+        # Verifies the details of a ike policy
+        resp, body = self.client.show_ikepolicy(self.ikepolicy['id'])
+        self.assertEqual('200', resp['status'])
+        ikepolicy = body['ikepolicy']
+        self.assertEqual(self.ikepolicy['id'], ikepolicy['id'])
+        self.assertEqual(self.ikepolicy['name'], ikepolicy['name'])
+        self.assertEqual(self.ikepolicy['description'],
+                         ikepolicy['description'])
+        self.assertEqual(self.ikepolicy['encryption_algorithm'],
+                         ikepolicy['encryption_algorithm'])
+        self.assertEqual(self.ikepolicy['auth_algorithm'],
+                         ikepolicy['auth_algorithm'])
+        self.assertEqual(self.ikepolicy['tenant_id'],
+                         ikepolicy['tenant_id'])
+        self.assertEqual(self.ikepolicy['pfs'],
+                         ikepolicy['pfs'])
+        self.assertEqual(self.ikepolicy['phase1_negotiation_mode'],
+                         ikepolicy['phase1_negotiation_mode'])
+        self.assertEqual(self.ikepolicy['ike_version'],
+                         ikepolicy['ike_version'])
diff --git a/tempest/api/object_storage/test_account_quotas.py b/tempest/api/object_storage/test_account_quotas.py
index b4128e2..c1b3391 100644
--- a/tempest/api/object_storage/test_account_quotas.py
+++ b/tempest/api/object_storage/test_account_quotas.py
@@ -107,6 +107,7 @@
                                                    object_name, data)
 
         self.assertEqual(resp["status"], "201")
+        self.assertHeaders(resp, 'Object', 'PUT')
 
     @testtools.skipIf(not accounts_quotas_available,
                       "Account Quotas middleware not available")
@@ -141,6 +142,7 @@
                                                             headers, "")
 
             self.assertEqual(resp["status"], "204")
+            self.assertHeaders(resp, 'Account', 'POST')
 
     @testtools.skipIf(not accounts_quotas_available,
                       "Account Quotas middleware not available")
diff --git a/tempest/api/object_storage/test_container_acl.py b/tempest/api/object_storage/test_container_acl.py
index 18000b9..b2dc20f 100644
--- a/tempest/api/object_storage/test_container_acl.py
+++ b/tempest/api/object_storage/test_container_acl.py
@@ -86,6 +86,7 @@
         resp, _ = self.object_client.create_object(
             self.container_name, object_name, 'data')
         self.assertEqual(resp['status'], '201')
+        self.assertHeaders(resp, 'Object', 'PUT')
         # trying to get object with non authorized user token
         self.assertRaises(exceptions.Unauthorized,
                           self.custom_object_client.get_object,
@@ -100,6 +101,7 @@
         resp, _ = self.object_client.create_object(
             self.container_name, object_name, 'data')
         self.assertEqual(resp['status'], '201')
+        self.assertHeaders(resp, 'Object', 'PUT')
         # trying to delete object with non-authorized user token
         self.assertRaises(exceptions.Unauthorized,
                           self.custom_object_client.delete_object,
@@ -115,11 +117,13 @@
             self.container_name, metadata=cont_headers,
             metadata_prefix='')
         self.assertIn(int(resp_meta['status']), HTTP_SUCCESS)
+        self.assertHeaders(resp_meta, 'Container', 'POST')
         # create object
         object_name = data_utils.rand_name(name='Object')
         resp, _ = self.object_client.create_object(self.container_name,
                                                    object_name, 'data')
         self.assertEqual(resp['status'], '201')
+        self.assertHeaders(resp, 'Object', 'PUT')
         # Trying to read the object without rights
         self.assertRaises(exceptions.Unauthorized,
                           self.custom_object_client.get_object,
@@ -135,6 +139,7 @@
             self.container_name, metadata=cont_headers,
             metadata_prefix='')
         self.assertIn(int(resp_meta['status']), HTTP_SUCCESS)
+        self.assertHeaders(resp_meta, 'Container', 'POST')
         # Trying to write the object without rights
         object_name = data_utils.rand_name(name='Object')
         self.assertRaises(exceptions.Unauthorized,
@@ -153,16 +158,19 @@
             self.container_name, metadata=cont_headers,
             metadata_prefix='')
         self.assertIn(int(resp_meta['status']), HTTP_SUCCESS)
+        self.assertHeaders(resp_meta, 'Container', 'POST')
         # create object
         object_name = data_utils.rand_name(name='Object')
         resp, _ = self.object_client.create_object(self.container_name,
                                                    object_name, 'data')
         self.assertEqual(resp['status'], '201')
+        self.assertHeaders(resp, 'Object', 'PUT')
         # Trying to read the object with rights
         resp, _ = self.custom_object_client.get_object(
             self.container_name, object_name,
             metadata=self.custom_headers)
         self.assertIn(int(resp['status']), HTTP_SUCCESS)
+        self.assertHeaders(resp, 'Object', 'GET')
 
     @attr(type='smoke')
     def test_write_object_with_rights(self):
@@ -174,6 +182,7 @@
             self.container_name, metadata=cont_headers,
             metadata_prefix='')
         self.assertIn(int(resp_meta['status']), HTTP_SUCCESS)
+        self.assertHeaders(resp_meta, 'Container', 'POST')
         # Trying to write the object with rights
         object_name = data_utils.rand_name(name='Object')
         resp, _ = self.custom_object_client.create_object(
@@ -181,6 +190,7 @@
             object_name, 'data',
             metadata=self.custom_headers)
         self.assertIn(int(resp['status']), HTTP_SUCCESS)
+        self.assertHeaders(resp, 'Object', 'PUT')
 
     @attr(type=['negative', 'smoke'])
     def test_write_object_without_write_rights(self):
@@ -193,6 +203,7 @@
             self.container_name, metadata=cont_headers,
             metadata_prefix='')
         self.assertIn(int(resp_meta['status']), HTTP_SUCCESS)
+        self.assertHeaders(resp_meta, 'Container', 'POST')
         # Trying to write the object without write rights
         object_name = data_utils.rand_name(name='Object')
         self.assertRaises(exceptions.Unauthorized,
@@ -212,11 +223,13 @@
             self.container_name, metadata=cont_headers,
             metadata_prefix='')
         self.assertIn(int(resp_meta['status']), HTTP_SUCCESS)
+        self.assertHeaders(resp_meta, 'Container', 'POST')
         # create object
         object_name = data_utils.rand_name(name='Object')
         resp, _ = self.object_client.create_object(self.container_name,
                                                    object_name, 'data')
         self.assertEqual(resp['status'], '201')
+        self.assertHeaders(resp, 'Object', 'PUT')
         # Trying to delete the object without write rights
         self.assertRaises(exceptions.Unauthorized,
                           self.custom_object_client.delete_object,
diff --git a/tempest/api/object_storage/test_container_quotas.py b/tempest/api/object_storage/test_container_quotas.py
index 04536fe..c7b5e28 100644
--- a/tempest/api/object_storage/test_container_quotas.py
+++ b/tempest/api/object_storage/test_container_quotas.py
@@ -69,6 +69,7 @@
         resp, _ = self.object_client.create_object(
             self.container_name, object_name, data)
         self.assertIn(int(resp['status']), HTTP_SUCCESS)
+        self.assertHeaders(resp, 'Object', 'PUT')
 
         nafter = self._get_bytes_used()
         self.assertEqual(nbefore + len(data), nafter)
diff --git a/tempest/api/object_storage/test_container_staticweb.py b/tempest/api/object_storage/test_container_staticweb.py
index 94048f7..9f9abd8 100644
--- a/tempest/api/object_storage/test_container_staticweb.py
+++ b/tempest/api/object_storage/test_container_staticweb.py
@@ -15,8 +15,9 @@
 # under the License.
 
 from tempest.api.object_storage import base
+from tempest.common import custom_matchers
 from tempest.common.utils import data_utils
-from tempest.test import attr, HTTP_SUCCESS
+from tempest import test
 
 
 class StaticWebTest(base.BaseObjectTest):
@@ -48,7 +49,7 @@
         cls.data.teardown_all()
         super(StaticWebTest, cls).tearDownClass()
 
-    @attr('gate')
+    @test.attr('gate')
     def test_web_index(self):
         headers = {'web-index': self.object_name}
 
@@ -59,7 +60,9 @@
         # we should retrieve the self.object_name file
         resp, body = self.custom_account_client.request("GET",
                                                         self.container_name)
-        self.assertIn(int(resp['status']), HTTP_SUCCESS)
+        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
+        # This request is equivalent to GET object
+        self.assertHeaders(resp, 'Object', 'GET')
         self.assertEqual(body, self.object_data)
 
         # clean up before exiting
@@ -70,7 +73,7 @@
             self.container_name)
         self.assertNotIn('x-container-meta-web-index', body)
 
-    @attr('gate')
+    @test.attr('gate')
     def test_web_listing(self):
         headers = {'web-listings': 'true'}
 
@@ -81,7 +84,16 @@
         # we should retrieve a listing of objects
         resp, body = self.custom_account_client.request("GET",
                                                         self.container_name)
-        self.assertIn(int(resp['status']), HTTP_SUCCESS)
+        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
+        # The target of the request is not any Swift resource. Therefore, the
+        # existence of response header is checked without a custom matcher.
+        self.assertIn('content-length', resp)
+        self.assertIn('content-type', resp)
+        self.assertIn('x-trans-id', resp)
+        self.assertIn('date', resp)
+        # Check only the format of common headers with custom matcher
+        self.assertThat(resp, custom_matchers.AreAllWellFormatted())
+
         self.assertIn(self.object_name, body)
 
         # clean up before exiting
@@ -92,7 +104,7 @@
             self.container_name)
         self.assertNotIn('x-container-meta-web-listings', body)
 
-    @attr('gate')
+    @test.attr('gate')
     def test_web_listing_css(self):
         headers = {'web-listings': 'true',
                    'web-listings-css': 'listings.css'}
@@ -104,12 +116,12 @@
         # we should retrieve a listing of objects
         resp, body = self.custom_account_client.request("GET",
                                                         self.container_name)
-        self.assertIn(int(resp['status']), HTTP_SUCCESS)
+        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertIn(self.object_name, body)
         css = '<link rel="stylesheet" type="text/css" href="listings.css" />'
         self.assertIn(css, body)
 
-    @attr('gate')
+    @test.attr('gate')
     def test_web_error(self):
         headers = {'web-listings': 'true',
                    'web-error': self.object_name}
diff --git a/tempest/api/object_storage/test_crossdomain.py b/tempest/api/object_storage/test_crossdomain.py
index 0ae7e46..51ecd16 100644
--- a/tempest/api/object_storage/test_crossdomain.py
+++ b/tempest/api/object_storage/test_crossdomain.py
@@ -18,6 +18,7 @@
 
 from tempest.api.object_storage import base
 from tempest import clients
+from tempest.common import custom_matchers
 from tempest import config
 from tempest.test import attr
 from tempest.test import HTTP_SUCCESS
@@ -80,3 +81,12 @@
         self.assertIn(int(resp['status']), HTTP_SUCCESS)
         self.assertTrue(body.startswith(self.xml_start) and
                         body.endswith(self.xml_end))
+
+        # The target of the request is not any Swift resource. Therefore, the
+        # existence of response header is checked without a custom matcher.
+        self.assertIn('content-length', resp)
+        self.assertIn('content-type', resp)
+        self.assertIn('x-trans-id', resp)
+        self.assertIn('date', resp)
+        # Check only the format of common headers with custom matcher
+        self.assertThat(resp, custom_matchers.AreAllWellFormatted())
diff --git a/tempest/api/object_storage/test_healthcheck.py b/tempest/api/object_storage/test_healthcheck.py
index 798ea4f..7bbdd1e 100644
--- a/tempest/api/object_storage/test_healthcheck.py
+++ b/tempest/api/object_storage/test_healthcheck.py
@@ -19,6 +19,7 @@
 
 from tempest.api.object_storage import base
 from tempest import clients
+from tempest.common import custom_matchers
 from tempest.test import attr
 from tempest.test import HTTP_SUCCESS
 
@@ -63,3 +64,12 @@
 
         # The status is expected to be 200
         self.assertIn(int(resp['status']), HTTP_SUCCESS)
+
+        # The target of the request is not any Swift resource. Therefore, the
+        # existence of response header is checked without a custom matcher.
+        self.assertIn('content-length', resp)
+        self.assertIn('content-type', resp)
+        self.assertIn('x-trans-id', resp)
+        self.assertIn('date', resp)
+        # Check only the format of common headers with custom matcher
+        self.assertThat(resp, custom_matchers.AreAllWellFormatted())
diff --git a/tempest/api/object_storage/test_object_expiry.py b/tempest/api/object_storage/test_object_expiry.py
index 6fc3853..4958f70 100644
--- a/tempest/api/object_storage/test_object_expiry.py
+++ b/tempest/api/object_storage/test_object_expiry.py
@@ -62,10 +62,13 @@
             self.object_client.list_object_metadata(self.container_name,
                                                     object_name)
         self.assertEqual(resp['status'], '200')
+        self.assertHeaders(resp, 'Object', 'HEAD')
         self.assertIn('x-delete-at', resp)
         resp, body = self.object_client.get_object(self.container_name,
                                                    object_name)
         self.assertEqual(resp['status'], '200')
+        self.assertHeaders(resp, 'Object', 'GET')
+        self.assertIn('x-delete-at', resp)
         # check data
         self.assertEqual(body, data)
         # sleep for over 5 seconds, so that object expires
diff --git a/tempest/api/object_storage/test_object_formpost.py b/tempest/api/object_storage/test_object_formpost.py
index 63393e4..817c892 100644
--- a/tempest/api/object_storage/test_object_formpost.py
+++ b/tempest/api/object_storage/test_object_formpost.py
@@ -109,11 +109,13 @@
         resp, body = self.object_client.http_obj.request(url, "POST",
                                                          body, headers=headers)
         self.assertIn(int(resp['status']), HTTP_SUCCESS)
+        self.assertHeaders(resp, "Object", "POST")
 
         # Ensure object is available
         resp, body = self.object_client.get("%s/%s%s" % (
             self.container_name, self.object_name, "testfile"))
         self.assertIn(int(resp['status']), HTTP_SUCCESS)
+        self.assertHeaders(resp, "Object", "GET")
         self.assertEqual(body, "hello world")
 
     @attr(type=['gate', 'negative'])
diff --git a/tempest/api/object_storage/test_object_slo.py b/tempest/api/object_storage/test_object_slo.py
new file mode 100644
index 0000000..997120a
--- /dev/null
+++ b/tempest/api/object_storage/test_object_slo.py
@@ -0,0 +1,193 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 NTT Corporation
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import hashlib
+import json
+import re
+
+from tempest.api.object_storage import base
+from tempest.common import custom_matchers
+from tempest.common.utils import data_utils
+from tempest import exceptions
+from tempest import test
+
+# Each segment, except for the final one, must be at least 1 megabyte
+MIN_SEGMENT_SIZE = 1024 * 1024
+
+
+class ObjectSloTest(base.BaseObjectTest):
+
+    def setUp(self):
+        super(ObjectSloTest, self).setUp()
+        self.container_name = data_utils.rand_name(name='TestContainer')
+        self.container_client.create_container(self.container_name)
+        self.objects = []
+
+    def tearDown(self):
+        for obj in self.objects:
+            try:
+                self.object_client.delete_object(
+                    self.container_name,
+                    obj)
+            except exceptions.NotFound:
+                pass
+        self.container_client.delete_container(self.container_name)
+        super(ObjectSloTest, self).tearDown()
+
+    def _create_object(self, container_name, object_name, data, params=None):
+        resp, _ = self.object_client.create_object(container_name,
+                                                   object_name,
+                                                   data,
+                                                   params)
+        self.objects.append(object_name)
+
+        return resp
+
+    def _create_manifest(self):
+        # Create a manifest file for SLO uploading
+        object_name = data_utils.rand_name(name='TestObject')
+        object_name_base_1 = object_name + '_01'
+        object_name_base_2 = object_name + '_02'
+        data_size = MIN_SEGMENT_SIZE
+        self.data = data_utils.arbitrary_string(data_size)
+        self._create_object(self.container_name,
+                            object_name_base_1,
+                            self.data)
+        self._create_object(self.container_name,
+                            object_name_base_2,
+                            self.data)
+
+        path_object_1 = '/%s/%s' % (self.container_name,
+                                    object_name_base_1)
+        path_object_2 = '/%s/%s' % (self.container_name,
+                                    object_name_base_2)
+        data_manifest = [{'path': path_object_1,
+                          'etag': hashlib.md5(self.data).hexdigest(),
+                          'size_bytes': data_size},
+                         {'path': path_object_2,
+                          'etag': hashlib.md5(self.data).hexdigest(),
+                          'size_bytes': data_size}]
+
+        return json.dumps(data_manifest)
+
+    def _create_large_object(self):
+        # Create a large object for preparation of testing various SLO
+        # features
+        manifest = self._create_manifest()
+
+        params = {'multipart-manifest': 'put'}
+        object_name = data_utils.rand_name(name='TestObject')
+        self._create_object(self.container_name,
+                            object_name,
+                            manifest,
+                            params)
+        return object_name
+
+    def _assertHeadersSLO(self, resp, method):
+        # Check the existence of common headers with custom matcher
+        self.assertThat(resp, custom_matchers.ExistsAllResponseHeaders(
+                        'Object', method))
+        # When sending GET or HEAD requests to SLO the response contains
+        # 'X-Static-Large-Object' header
+        if method in ('GET', 'HEAD'):
+            self.assertIn('x-static-large-object', resp)
+
+        # Check common headers for all HTTP methods
+        self.assertTrue(re.match("^tx[0-9a-f]*-[0-9a-f]*$",
+                                 resp['x-trans-id']))
+        self.assertTrue(resp['content-length'].isdigit())
+        self.assertNotEqual(len(resp['date']), 0)
+        # Etag value of a large object is enclosed in double-quotations.
+        self.assertTrue(resp['etag'].startswith('\"'))
+        self.assertTrue(resp['etag'].endswith('\"'))
+        self.assertTrue(resp['etag'].strip('\"').isalnum())
+        # Check header formats for a specific method
+        if method in ('GET', 'HEAD'):
+            self.assertTrue(re.match("^\d+\.?\d*\Z", resp['x-timestamp']))
+            self.assertNotEqual(len(resp['content-type']), 0)
+            self.assertEqual(resp['accept-ranges'], 'bytes')
+            self.assertEqual(resp['x-static-large-object'], 'True')
+
+    @test.attr(type='gate')
+    def test_upload_manifest(self):
+        # create static large object from multipart manifest
+        manifest = self._create_manifest()
+
+        params = {'multipart-manifest': 'put'}
+        object_name = data_utils.rand_name(name='TestObject')
+        resp = self._create_object(self.container_name,
+                                   object_name,
+                                   manifest,
+                                   params)
+
+        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
+        self._assertHeadersSLO(resp, 'PUT')
+
+    @test.attr(type='gate')
+    def test_list_large_object_metadata(self):
+        # list static large object metadata using multipart manifest
+        object_name = self._create_large_object()
+
+        resp, body = self.object_client.list_object_metadata(
+            self.container_name,
+            object_name)
+
+        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
+        self._assertHeadersSLO(resp, 'HEAD')
+
+    @test.attr(type='gate')
+    def test_retrieve_large_object(self):
+        # list static large object using multipart manifest
+        object_name = self._create_large_object()
+
+        resp, body = self.object_client.get_object(
+            self.container_name,
+            object_name)
+
+        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
+        self._assertHeadersSLO(resp, 'GET')
+
+        sum_data = self.data + self.data
+        self.assertEqual(body, sum_data)
+
+    @test.attr(type='gate')
+    def test_delete_large_object(self):
+        # delete static large object using multipart manifest
+        object_name = self._create_large_object()
+
+        params_del = {'multipart-manifest': 'delete'}
+        resp, body = self.object_client.delete_object(
+            self.container_name,
+            object_name,
+            params=params_del)
+
+        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
+
+        # When deleting SLO using multipart manifest, the response contains
+        # not 'content-length' but 'transfer-encoding' header. This is the
+        # special case, therefore the existence of response headers is checked
+        # outside of custom matcher.
+        self.assertIn('transfer-encoding', resp)
+        self.assertIn('content-type', resp)
+        self.assertIn('x-trans-id', resp)
+        self.assertIn('date', resp)
+
+        # Check only the format of common headers with custom matcher
+        self.assertThat(resp, custom_matchers.AreAllWellFormatted())
+
+        resp, body = self.container_client.list_container_contents(
+            self.container_name)
+        self.assertEqual(int(resp['x-container-object-count']), 0)
diff --git a/tempest/api/object_storage/test_object_temp_url.py b/tempest/api/object_storage/test_object_temp_url.py
index c8ce57a..bb03932 100644
--- a/tempest/api/object_storage/test_object_temp_url.py
+++ b/tempest/api/object_storage/test_object_temp_url.py
@@ -113,13 +113,14 @@
 
         # trying to get object using temp url within expiry time
         resp, body = self.object_client.get_object_using_temp_url(url)
-
         self.assertIn(int(resp['status']), HTTP_SUCCESS)
+        self.assertHeaders(resp, 'Object', 'GET')
         self.assertEqual(body, self.data)
 
         # Testing a HEAD on this Temp URL
         resp, body = self.object_client.head(url)
         self.assertIn(int(resp['status']), HTTP_SUCCESS)
+        self.assertHeaders(resp, 'Object', 'HEAD')
 
     @attr(type='gate')
     def test_get_object_using_temp_url_key_2(self):
@@ -157,10 +158,12 @@
             url, new_data)
 
         self.assertIn(int(resp['status']), HTTP_SUCCESS)
+        self.assertHeaders(resp, 'Object', 'PUT')
 
         # Testing a HEAD on this Temp URL
         resp, body = self.object_client.head(url)
         self.assertIn(int(resp['status']), HTTP_SUCCESS)
+        self.assertHeaders(resp, 'Object', 'HEAD')
 
         # Validate that the content of the object has been modified
         url = self._get_temp_url(self.container_name,
diff --git a/tempest/api/object_storage/test_object_version.py b/tempest/api/object_storage/test_object_version.py
index c47e1b6..d706eef 100644
--- a/tempest/api/object_storage/test_object_version.py
+++ b/tempest/api/object_storage/test_object_version.py
@@ -34,6 +34,7 @@
     def assertContainer(self, container, count, byte, versioned):
         resp, _ = self.container_client.list_container_metadata(container)
         self.assertEqual(resp['status'], ('204'))
+        self.assertHeaders(resp, 'Container', 'HEAD')
         header_value = resp.get('x-container-object-count', 'Missing Header')
         self.assertEqual(header_value, count)
         header_value = resp.get('x-container-bytes-used', 'Missing Header')
@@ -49,6 +50,7 @@
             vers_container_name)
         self.containers.append(vers_container_name)
         self.assertIn(resp['status'], ('202', '201'))
+        self.assertHeaders(resp, 'Container', 'PUT')
         self.assertContainer(vers_container_name, '0', '0', 'Missing Header')
 
         base_container_name = data_utils.rand_name(name='TestBaseContainer')
@@ -59,6 +61,7 @@
             metadata_prefix='')
         self.containers.append(base_container_name)
         self.assertIn(resp['status'], ('202', '201'))
+        self.assertHeaders(resp, 'Container', 'PUT')
         self.assertContainer(base_container_name, '0', '0',
                              vers_container_name)
         object_name = data_utils.rand_name(name='TestObject')
diff --git a/tempest/api/orchestration/stacks/test_non_empty_stack.py b/tempest/api/orchestration/stacks/test_non_empty_stack.py
index 35a7326..b19344d 100644
--- a/tempest/api/orchestration/stacks/test_non_empty_stack.py
+++ b/tempest/api/orchestration/stacks/test_non_empty_stack.py
@@ -28,75 +28,57 @@
     template = """
 HeatTemplateFormatVersion: '2012-12-12'
 Description: |
-  Template which creates single EC2 instance
+  Template which creates some simple resources
 Parameters:
-  KeyName:
+  trigger:
     Type: String
-  InstanceType:
-    Type: String
-  ImageId:
-    Type: String
-  Subnet:
-    Type: String
+    Default: not_yet
 Resources:
-  SmokeServer:
-    Type: AWS::EC2::Instance
+  fluffy:
+    Type: AWS::AutoScaling::LaunchConfiguration
     Metadata:
-      Name: SmokeServer
+      kittens:
+      - Tom
+      - Stinky
     Properties:
-      ImageId: {Ref: ImageId}
-      InstanceType: {Ref: InstanceType}
-      KeyName: {Ref: KeyName}
-      SubnetId: {Ref: Subnet}
+      ImageId: not_used
+      InstanceType: not_used
       UserData:
-        Fn::Base64:
-          Fn::Join:
-          - ''
-          - - '#!/bin/bash -v
-
-              '
-            - /opt/aws/bin/cfn-signal -e 0 -r "SmokeServer created" '
-            - {Ref: WaitHandle}
-            - '''
-
-              '
-  WaitHandle:
-    Type: AWS::CloudFormation::WaitConditionHandle
-  WaitCondition:
-    Type: AWS::CloudFormation::WaitCondition
-    DependsOn: SmokeServer
-    Properties:
-      Handle: {Ref: WaitHandle}
-      Timeout: '600'
+        Fn::Replace:
+        - variable_a: {Ref: trigger}
+          variable_b: bee
+        - |
+          A == variable_a
+          B == variable_b
+Outputs:
+  fluffy:
+    Description: "fluffies irc nick"
+    Value:
+      Fn::Replace:
+      - nick: {Ref: fluffy}
+      - |
+        #nick
 """
 
     @classmethod
     def setUpClass(cls):
         super(StacksTestJSON, cls).setUpClass()
-        if not cls.orchestration_cfg.image_ref:
-            raise cls.skipException("No image available to test")
         cls.client = cls.orchestration_client
         cls.stack_name = data_utils.rand_name('heat')
-        keypair_name = (cls.orchestration_cfg.keypair_name or
-                        cls._create_keypair()['name'])
 
         # create the stack
-        subnet = cls._get_default_network()['subnets'][0]
         cls.stack_identifier = cls.create_stack(
             cls.stack_name,
             cls.template,
             parameters={
-                'KeyName': keypair_name,
-                'InstanceType': cls.orchestration_cfg.instance_type,
-                'ImageId': cls.orchestration_cfg.image_ref,
-                'Subnet': subnet
+                'trigger': 'start'
             })
         cls.stack_id = cls.stack_identifier.split('/')[1]
-        cls.resource_name = 'SmokeServer'
-        cls.resource_type = 'AWS::EC2::Instance'
+        cls.resource_name = 'fluffy'
+        cls.resource_type = 'AWS::AutoScaling::LaunchConfiguration'
         cls.client.wait_for_stack_status(cls.stack_id, 'CREATE_COMPLETE')
 
-    @attr(type='slow')
+    @attr(type='gate')
     def test_stack_list(self):
         """Created stack should be on the list of existing stacks."""
         resp, stacks = self.client.list_stacks()
@@ -105,7 +87,7 @@
         stacks_names = map(lambda stack: stack['stack_name'], stacks)
         self.assertIn(self.stack_name, stacks_names)
 
-    @attr(type='slow')
+    @attr(type='gate')
     def test_stack_show(self):
         """Getting details about created stack should be possible."""
         resp, stack = self.client.get_stack(self.stack_name)
@@ -114,7 +96,7 @@
         self.assertEqual(self.stack_name, stack['stack_name'])
         self.assertEqual(self.stack_id, stack['id'])
 
-    @attr(type='slow')
+    @attr(type='gate')
     def test_list_resources(self):
         """Getting list of created resources for the stack should be possible.
         """
@@ -128,7 +110,7 @@
                               resources)
         self.assertIn(self.resource_type, resources_types)
 
-    @attr(type='slow')
+    @attr(type='gate')
     def test_show_resource(self):
         """Getting details about created resource should be possible."""
         resp, resource = self.client.get_resource(self.stack_identifier,
@@ -137,7 +119,7 @@
         self.assertEqual(self.resource_name, resource['logical_resource_id'])
         self.assertEqual(self.resource_type, resource['resource_type'])
 
-    @attr(type='slow')
+    @attr(type='gate')
     def test_resource_metadata(self):
         """Getting metadata for created resource should be possible."""
         resp, metadata = self.client.show_resource_metadata(
@@ -145,9 +127,9 @@
             self.resource_name)
         self.assertEqual('200', resp['status'])
         self.assertIsInstance(metadata, dict)
-        self.assertEqual(self.resource_name, metadata.get('Name', None))
+        self.assertEqual(['Tom', 'Stinky'], metadata.get('kittens', None))
 
-    @attr(type='slow')
+    @attr(type='gate')
     def test_list_events(self):
         """Getting list of created events for the stack should be possible."""
         resp, events = self.client.list_events(self.stack_identifier)
@@ -157,7 +139,7 @@
         self.assertIn('CREATE_IN_PROGRESS', resource_statuses)
         self.assertIn('CREATE_COMPLETE', resource_statuses)
 
-    @attr(type='slow')
+    @attr(type='gate')
     def test_show_event(self):
         """Getting details about existing event should be possible."""
         resp, events = self.client.list_resource_events(self.stack_identifier,
@@ -168,7 +150,7 @@
         resp, event = self.client.show_event(self.stack_identifier,
                                              self.resource_name, event_id)
         self.assertEqual('200', resp['status'])
-        self.assertEqual('CREATE_IN_PROGRESS', event['resource_status'])
+        self.assertIsInstance(event, dict)
+        self.assertEqual(self.resource_name, event['resource_name'])
         self.assertEqual('state changed', event['resource_status_reason'])
         self.assertEqual(self.resource_name, event['logical_resource_id'])
-        self.assertIsInstance(event, dict)
diff --git a/tempest/api/orchestration/stacks/test_server_cfn_init.py b/tempest/api/orchestration/stacks/test_server_cfn_init.py
index 3c2a2d2..0480570 100644
--- a/tempest/api/orchestration/stacks/test_server_cfn_init.py
+++ b/tempest/api/orchestration/stacks/test_server_cfn_init.py
@@ -169,9 +169,9 @@
             body['physical_resource_id'])
 
         # Check that the user can authenticate with the generated password
-        linux_client = RemoteClient(
-            server, 'ec2-user', pkey=self.keypair['private_key'])
-        self.assertTrue(linux_client.can_authenticate())
+        linux_client = RemoteClient(server, 'ec2-user',
+                                    pkey=self.keypair['private_key'])
+        linux_client.validate_authentication()
 
     @attr(type='slow')
     def test_stack_wait_condition_data(self):
diff --git a/tempest/api/volume/admin/test_volume_hosts.py b/tempest/api/volume/admin/test_volume_hosts.py
new file mode 100644
index 0000000..e7d8c02
--- /dev/null
+++ b/tempest/api/volume/admin/test_volume_hosts.py
@@ -0,0 +1,34 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 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.volume import base
+from tempest.test import attr
+
+
+class VolumeHostsAdminTestsJSON(base.BaseVolumeAdminTest):
+    _interface = "json"
+
+    @attr(type='gate')
+    def test_list_hosts(self):
+        resp, hosts = self.hosts_client.list_hosts()
+        self.assertEqual(200, resp.status)
+        self.assertTrue(len(hosts) >= 2, "No. of hosts are < 2,"
+                        "response of list hosts is: % s" % hosts)
+
+
+class VolumeHostsAdminTestsXML(VolumeHostsAdminTestsJSON):
+    _interface = 'xml'
diff --git a/tempest/api/volume/admin/test_volumes_actions.py b/tempest/api/volume/admin/test_volumes_actions.py
index 4063eef..cb9ff11 100644
--- a/tempest/api/volume/admin/test_volumes_actions.py
+++ b/tempest/api/volume/admin/test_volumes_actions.py
@@ -47,7 +47,7 @@
         super(VolumesActionsTest, cls).tearDownClass()
 
     def _reset_volume_status(self, volume_id, status):
-        #Reset the volume status
+        # Reset the volume status
         resp, body = self.admin_volume_client.reset_volume_status(volume_id,
                                                                   status)
         return resp, body
@@ -57,6 +57,26 @@
         self._reset_volume_status(self.volume['id'], 'available')
         super(VolumesActionsTest, self).tearDown()
 
+    def _create_temp_volume(self):
+        # Create a temp volume for force delete tests
+        vol_name = utils.rand_name('Volume')
+        resp, temp_volume = self.client.create_volume(size=1,
+                                                      display_name=vol_name)
+        self.client.wait_for_volume_status(temp_volume['id'], 'available')
+
+        return temp_volume
+
+    def _create_reset_and_force_delete_temp_volume(self, status=None):
+        # Create volume, reset volume status, and force delete temp volume
+        temp_volume = self._create_temp_volume()
+        if status:
+            resp, body = self._reset_volume_status(temp_volume['id'], status)
+            self.assertEqual(202, resp.status)
+        resp_delete, volume_delete = self.admin_volume_client.\
+            force_delete_volume(temp_volume['id'])
+        self.assertEqual(202, resp_delete.status)
+        self.client.wait_for_resource_deletion(temp_volume['id'])
+
     @attr(type='gate')
     def test_volume_reset_status(self):
         # test volume reset status : available->error->available
@@ -84,6 +104,19 @@
         resp_get, volume_get = self.client.get_volume(self.volume['id'])
         self.assertEqual('in-use', volume_get['status'])
 
+    def test_volume_force_delete_when_volume_is_creating(self):
+        # test force delete when status of volume is creating
+        self._create_reset_and_force_delete_temp_volume('creating')
+
+    def test_volume_force_delete_when_volume_is_attaching(self):
+        # test force delete when status of volume is attaching
+        self._create_reset_and_force_delete_temp_volume('attaching')
+
+    @attr(type='gate')
+    def test_volume_force_delete_when_volume_is_error(self):
+        # test force delete when status of volume is error
+        self._create_reset_and_force_delete_temp_volume('error')
+
 
 class VolumesActionsTestXML(VolumesActionsTest):
     _interface = "xml"
diff --git a/tempest/api/volume/base.py b/tempest/api/volume/base.py
index cdf8638..465f570 100644
--- a/tempest/api/volume/base.py
+++ b/tempest/api/volume/base.py
@@ -151,3 +151,4 @@
         else:
             cls.os_adm = clients.AdminManager(interface=cls._interface)
         cls.client = cls.os_adm.volume_types_client
+        cls.hosts_client = cls.os_adm.volume_hosts_client
diff --git a/tempest/api/volume/test_volumes_list.py b/tempest/api/volume/test_volumes_list.py
index 4dbc88a..def330e 100644
--- a/tempest/api/volume/test_volumes_list.py
+++ b/tempest/api/volume/test_volumes_list.py
@@ -57,13 +57,13 @@
         # Create 3 test volumes
         cls.volume_list = []
         cls.volume_id_list = []
+        cls.metadata = {'Type': 'work'}
         for i in range(3):
             v_name = data_utils.rand_name('volume')
-            metadata = {'Type': 'work'}
             try:
                 resp, volume = cls.client.create_volume(size=1,
                                                         display_name=v_name,
-                                                        metadata=metadata)
+                                                        metadata=cls.metadata)
                 cls.client.wait_for_volume_status(volume['id'], 'available')
                 resp, volume = cls.client.get_volume(volume['id'])
                 cls.volume_list.append(volume)
@@ -88,6 +88,25 @@
             cls.client.wait_for_resource_deletion(volid)
         super(VolumesListTest, cls).tearDownClass()
 
+    def _list_by_param_value_and_assert(self, params, with_detail=False):
+        """
+        Perform list or list_details action with given params
+        and validates result.
+        """
+        if with_detail:
+            resp, fetched_vol_list = \
+                self.client.list_volumes_with_detail(params=params)
+        else:
+            resp, fetched_vol_list = self.client.list_volumes(params=params)
+
+        self.assertEqual(200, resp.status)
+        # Validating params of fetched volumes
+        for volume in fetched_vol_list:
+            for key in params:
+                msg = "Failed to list volumes %s by %s" % \
+                      ('details' if with_detail else '', key)
+                self.assertEqual(params[key], volume[key], msg)
+
     @attr(type='smoke')
     def test_volume_list(self):
         # Get a list of Volumes
@@ -164,6 +183,34 @@
             self.assertEqual(zone, volume['availability_zone'])
         self.assertVolumesIn(fetched_list, self.volume_list)
 
+    @attr(type='gate')
+    def test_volume_list_with_param_metadata(self):
+        # Test to list volumes when metadata param is given
+        params = {'metadata': self.metadata}
+        self._list_by_param_value_and_assert(params)
+
+    @attr(type='gate')
+    def test_volume_list_with_detail_param_metadata(self):
+        # Test to list volumes details when metadata param is given
+        params = {'metadata': self.metadata}
+        self._list_by_param_value_and_assert(params, with_detail=True)
+
+    @attr(type='gate')
+    def test_volume_list_param_display_name_and_status(self):
+        # Test to list volume when display name and status param is given
+        volume = self.volume_list[data_utils.rand_int_id(0, 2)]
+        params = {'display_name': volume['display_name'],
+                  'status': 'available'}
+        self._list_by_param_value_and_assert(params)
+
+    @attr(type='gate')
+    def test_volume_list_with_detail_param_display_name_and_status(self):
+        # Test to list volume when name and status param is given
+        volume = self.volume_list[data_utils.rand_int_id(0, 2)]
+        params = {'display_name': volume['display_name'],
+                  'status': 'available'}
+        self._list_by_param_value_and_assert(params, with_detail=True)
+
 
 class VolumeListTestXML(VolumesListTest):
     _interface = 'xml'
diff --git a/tempest/api/volume/test_volumes_snapshots.py b/tempest/api/volume/test_volumes_snapshots.py
index 99e8de7..6c45c3d 100644
--- a/tempest/api/volume/test_volumes_snapshots.py
+++ b/tempest/api/volume/test_volumes_snapshots.py
@@ -37,6 +37,27 @@
     def tearDownClass(cls):
         super(VolumesSnapshotTest, cls).tearDownClass()
 
+    def _list_by_param_values_and_assert(self, params, with_detail=False):
+        """
+        Perform list or list_details action with given params
+        and validates result.
+        """
+        if with_detail:
+            resp, fetched_snap_list = \
+                self.snapshots_client.\
+                list_snapshots_with_detail(params=params)
+        else:
+            resp, fetched_snap_list = \
+                self.snapshots_client.list_snapshots(params=params)
+
+        self.assertEqual(200, resp.status)
+        # Validating params of fetched snapshots
+        for snap in fetched_snap_list:
+            for key in params:
+                msg = "Failed to list snapshots %s by %s" % \
+                      ('details' if with_detail else '', key)
+                self.assertEqual(params[key], snap[key], msg)
+
     @attr(type='gate')
     def test_snapshot_create_get_list_update_delete(self):
         # Create a snapshot
@@ -83,6 +104,46 @@
         self.snapshots.remove(snapshot)
 
     @attr(type='gate')
+    def test_snapshots_list_with_params(self):
+        """list snapshots with params."""
+        # Create a snapshot
+        display_name = data_utils.rand_name('snap')
+        snapshot = self.create_snapshot(self.volume_origin['id'],
+                                        display_name=display_name)
+
+        # Verify list snapshots by display_name filter
+        params = {'display_name': snapshot['display_name']}
+        self._list_by_param_values_and_assert(params)
+
+        # Verify list snapshots by status filter
+        params = {'status': 'available'}
+        self._list_by_param_values_and_assert(params)
+
+        # Verify list snapshots by status and display name filter
+        params = {'status': 'available',
+                  'display_name': snapshot['display_name']}
+        self._list_by_param_values_and_assert(params)
+
+    @attr(type='gate')
+    def test_snapshots_list_details_with_params(self):
+        """list snapshot details with params."""
+        # Create a snapshot
+        display_name = data_utils.rand_name('snap')
+        snapshot = self.create_snapshot(self.volume_origin['id'],
+                                        display_name=display_name)
+
+        # Verify list snapshot details by display_name filter
+        params = {'display_name': snapshot['display_name']}
+        self._list_by_param_values_and_assert(params, with_detail=True)
+        # Verify list snapshot details by status filter
+        params = {'status': 'available'}
+        self._list_by_param_values_and_assert(params, with_detail=True)
+        # Verify list snapshot details by status and display name filter
+        params = {'status': 'available',
+                  'display_name': snapshot['display_name']}
+        self._list_by_param_values_and_assert(params, with_detail=True)
+
+    @attr(type='gate')
     def test_volume_from_snapshot(self):
         # Create a temporary snap using wrapper method from base, then
         # create a snap based volume, check resp code and deletes it
diff --git a/tempest/cli/simple_read_only/test_neutron.py b/tempest/cli/simple_read_only/test_neutron.py
index 047b17d..80376ab 100644
--- a/tempest/cli/simple_read_only/test_neutron.py
+++ b/tempest/cli/simple_read_only/test_neutron.py
@@ -44,35 +44,43 @@
             raise cls.skipException(msg)
         super(SimpleReadOnlyNeutronClientTest, cls).setUpClass()
 
+    @test.attr(type='smoke')
     def test_neutron_fake_action(self):
         self.assertRaises(subprocess.CalledProcessError,
                           self.neutron,
                           'this-does-not-exist')
 
+    @test.attr(type='smoke')
     def test_neutron_net_list(self):
         self.neutron('net-list')
 
+    @test.attr(type='smoke')
     def test_neutron_ext_list(self):
         ext = self.parser.listing(self.neutron('ext-list'))
         self.assertTableStruct(ext, ['alias', 'name'])
 
+    @test.attr(type='smoke')
     def test_neutron_dhcp_agent_list_hosting_net(self):
         self.neutron('dhcp-agent-list-hosting-net',
                      params=CONF.compute.fixed_network_name)
 
+    @test.attr(type='smoke')
     def test_neutron_agent_list(self):
         agents = self.parser.listing(self.neutron('agent-list'))
         field_names = ['id', 'agent_type', 'host', 'alive', 'admin_state_up']
         self.assertTableStruct(agents, field_names)
 
+    @test.attr(type='smoke')
     def test_neutron_floatingip_list(self):
         self.neutron('floatingip-list')
 
     @test.skip_because(bug="1240694")
+    @test.attr(type='smoke')
     def test_neutron_meter_label_list(self):
         self.neutron('meter-label-list')
 
     @test.skip_because(bug="1240694")
+    @test.attr(type='smoke')
     def test_neutron_meter_label_rule_list(self):
         self.neutron('meter-label-rule-list')
 
@@ -83,40 +91,52 @@
             if '404 Not Found' not in e.stderr:
                 self.fail('%s: Unexpected failure.' % command)
 
+    @test.attr(type='smoke')
     def test_neutron_lb_healthmonitor_list(self):
         self._test_neutron_lbaas_command('lb-healthmonitor-list')
 
+    @test.attr(type='smoke')
     def test_neutron_lb_member_list(self):
         self._test_neutron_lbaas_command('lb-member-list')
 
+    @test.attr(type='smoke')
     def test_neutron_lb_pool_list(self):
         self._test_neutron_lbaas_command('lb-pool-list')
 
+    @test.attr(type='smoke')
     def test_neutron_lb_vip_list(self):
         self._test_neutron_lbaas_command('lb-vip-list')
 
+    @test.attr(type='smoke')
     def test_neutron_net_external_list(self):
         self.neutron('net-external-list')
 
+    @test.attr(type='smoke')
     def test_neutron_port_list(self):
         self.neutron('port-list')
 
+    @test.attr(type='smoke')
     def test_neutron_quota_list(self):
         self.neutron('quota-list')
 
+    @test.attr(type='smoke')
     def test_neutron_router_list(self):
         self.neutron('router-list')
 
+    @test.attr(type='smoke')
     def test_neutron_security_group_list(self):
         security_grp = self.parser.listing(self.neutron('security-group-list'))
         self.assertTableStruct(security_grp, ['id', 'name', 'description'])
 
+    @test.attr(type='smoke')
     def test_neutron_security_group_rule_list(self):
         self.neutron('security-group-rule-list')
 
+    @test.attr(type='smoke')
     def test_neutron_subnet_list(self):
         self.neutron('subnet-list')
 
+    @test.attr(type='smoke')
     def test_neutron_help(self):
         help_text = self.neutron('help')
         lines = help_text.split('\n')
@@ -136,11 +156,14 @@
 
      # Optional arguments:
 
+    @test.attr(type='smoke')
     def test_neutron_version(self):
         self.neutron('', flags='--version')
 
+    @test.attr(type='smoke')
     def test_neutron_debug_net_list(self):
         self.neutron('net-list', flags='--debug')
 
+    @test.attr(type='smoke')
     def test_neutron_quiet_net_list(self):
         self.neutron('net-list', flags='--quiet')
diff --git a/tempest/clients.py b/tempest/clients.py
index 291b946..ac79ce0 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -62,6 +62,8 @@
     ServersV3ClientJSON
 from tempest.services.compute.v3.json.services_client import \
     ServicesV3ClientJSON
+from tempest.services.compute.v3.json.tenant_usages_client import \
+    TenantUsagesV3ClientJSON
 from tempest.services.compute.v3.xml.availability_zone_client import \
     AvailabilityZoneV3ClientXML
 from tempest.services.compute.v3.xml.extensions_client import \
@@ -73,6 +75,8 @@
 from tempest.services.compute.v3.xml.servers_client import ServersV3ClientXML
 from tempest.services.compute.v3.xml.services_client import \
     ServicesV3ClientXML
+from tempest.services.compute.v3.xml.tenant_usages_client import \
+    TenantUsagesV3ClientXML
 from tempest.services.compute.xml.aggregates_client import AggregatesClientXML
 from tempest.services.compute.xml.availability_zone_client import \
     AvailabilityZoneClientXML
@@ -136,10 +140,14 @@
     ObjectClientCustomizedHeader
 from tempest.services.orchestration.json.orchestration_client import \
     OrchestrationClient
+from tempest.services.volume.json.admin.volume_hosts_client import \
+    VolumeHostsClientJSON
 from tempest.services.volume.json.admin.volume_types_client import \
     VolumeTypesClientJSON
 from tempest.services.volume.json.snapshots_client import SnapshotsClientJSON
 from tempest.services.volume.json.volumes_client import VolumesClientJSON
+from tempest.services.volume.xml.admin.volume_hosts_client import \
+    VolumeHostsClientXML
 from tempest.services.volume.xml.admin.volume_types_client import \
     VolumeTypesClientXML
 from tempest.services.volume.xml.snapshots_client import SnapshotsClientXML
@@ -230,6 +238,8 @@
             self.service_client = ServiceClientXML(*client_args)
             self.aggregates_client = AggregatesClientXML(*client_args)
             self.services_client = ServicesClientXML(*client_args)
+            self.tenant_usages_v3_client = TenantUsagesV3ClientXML(
+                *client_args)
             self.tenant_usages_client = TenantUsagesClientXML(*client_args)
             self.policy_client = PolicyClientXML(*client_args)
             self.hypervisor_v3_client = HypervisorV3ClientXML(*client_args)
@@ -239,6 +249,7 @@
             self.credentials_client = CredentialsClientXML(*client_args)
             self.instance_usages_audit_log_client = \
                 InstanceUsagesAuditLogClientXML(*client_args)
+            self.volume_hosts_client = VolumeHostsClientXML(*client_args)
 
             if client_args_v3_auth:
                 self.servers_client_v3_auth = ServersClientXML(
@@ -278,6 +289,8 @@
             self.service_client = ServiceClientJSON(*client_args)
             self.aggregates_client = AggregatesClientJSON(*client_args)
             self.services_client = ServicesClientJSON(*client_args)
+            self.tenant_usages_v3_client = TenantUsagesV3ClientJSON(
+                *client_args)
             self.tenant_usages_client = TenantUsagesClientJSON(*client_args)
             self.policy_client = PolicyClientJSON(*client_args)
             self.hypervisor_v3_client = HypervisorV3ClientJSON(*client_args)
@@ -287,6 +300,7 @@
             self.credentials_client = CredentialsClientJSON(*client_args)
             self.instance_usages_audit_log_client = \
                 InstanceUsagesAuditLogClientJSON(*client_args)
+            self.volume_hosts_client = VolumeHostsClientJSON(*client_args)
 
             if client_args_v3_auth:
                 self.servers_client_v3_auth = ServersClientJSON(
diff --git a/tempest/common/rest_client.py b/tempest/common/rest_client.py
index 9322f1b..9aca2ff 100644
--- a/tempest/common/rest_client.py
+++ b/tempest/common/rest_client.py
@@ -506,18 +506,26 @@
         if resp.status in (500, 501):
             message = resp_body
             if parse_resp:
-                resp_body = self._parse_resp(resp_body)
-                # I'm seeing both computeFault and cloudServersFault come back.
-                # Will file a bug to fix, but leave as is for now.
-                if 'cloudServersFault' in resp_body:
-                    message = resp_body['cloudServersFault']['message']
-                elif 'computeFault' in resp_body:
-                    message = resp_body['computeFault']['message']
-                elif 'error' in resp_body:  # Keystone errors
-                    message = resp_body['error']['message']
-                    raise exceptions.IdentityError(message)
-                elif 'message' in resp_body:
-                    message = resp_body['message']
+                try:
+                    resp_body = self._parse_resp(resp_body)
+                except ValueError:
+                    # If response body is a non-json string message.
+                    # Use resp_body as is and raise InvalidResponseBody
+                    # exception.
+                    raise exceptions.InvalidHTTPResponseBody(message)
+                else:
+                    # I'm seeing both computeFault
+                    # and cloudServersFault come back.
+                    # Will file a bug to fix, but leave as is for now.
+                    if 'cloudServersFault' in resp_body:
+                        message = resp_body['cloudServersFault']['message']
+                    elif 'computeFault' in resp_body:
+                        message = resp_body['computeFault']['message']
+                    elif 'error' in resp_body:  # Keystone errors
+                        message = resp_body['error']['message']
+                        raise exceptions.IdentityError(message)
+                    elif 'message' in resp_body:
+                        message = resp_body['message']
 
             raise exceptions.ServerFault(message)
 
diff --git a/tempest/common/ssh.py b/tempest/common/ssh.py
index 742a354..bca2f9e 100644
--- a/tempest/common/ssh.py
+++ b/tempest/common/ssh.py
@@ -23,6 +23,7 @@
 import warnings
 
 from tempest import exceptions
+from tempest.openstack.common import log as logging
 
 
 with warnings.catch_warnings():
@@ -30,6 +31,9 @@
     import paramiko
 
 
+LOG = logging.getLogger(__name__)
+
+
 class Client(object):
 
     def __init__(self, host, username, password=None, timeout=300, pkey=None,
@@ -49,33 +53,44 @@
 
     def _get_ssh_connection(self, sleep=1.5, backoff=1.01):
         """Returns an ssh connection to the specified host."""
-        _timeout = True
         bsleep = sleep
         ssh = paramiko.SSHClient()
         ssh.set_missing_host_key_policy(
             paramiko.AutoAddPolicy())
         _start_time = time.time()
-
-        while not self._is_timed_out(_start_time):
+        if self.pkey is not None:
+            LOG.info("Creating ssh connection to '%s' as '%s'"
+                     " with public key authentication",
+                     self.host, self.username)
+        else:
+            LOG.info("Creating ssh connection to '%s' as '%s'"
+                     " with password %s",
+                     self.host, self.username, str(self.password))
+        attempts = 0
+        while True:
             try:
                 ssh.connect(self.host, username=self.username,
                             password=self.password,
                             look_for_keys=self.look_for_keys,
                             key_filename=self.key_filename,
-                            timeout=self.timeout, pkey=self.pkey)
-                _timeout = False
-                break
+                            timeout=self.channel_timeout, pkey=self.pkey)
+                LOG.info("ssh connection to %s@%s sucessfuly created",
+                         self.username, self.host)
+                return ssh
             except (socket.error,
-                    paramiko.AuthenticationException,
                     paramiko.SSHException):
+                attempts += 1
                 time.sleep(bsleep)
                 bsleep *= backoff
-                continue
-        if _timeout:
-            raise exceptions.SSHTimeout(host=self.host,
-                                        user=self.username,
-                                        password=self.password)
-        return ssh
+                if not self._is_timed_out(_start_time):
+                    continue
+                else:
+                    LOG.exception("Failed to establish authenticated ssh"
+                                  " connection to %s@%s after %d attempts",
+                                  self.username, self.host, attempts)
+                    raise exceptions.SSHTimeout(host=self.host,
+                                                user=self.username,
+                                                password=self.password)
 
     def _is_timed_out(self, start_time):
         return (time.time() - self.timeout) > start_time
@@ -144,11 +159,6 @@
         return ''.join(out_data)
 
     def test_connection_auth(self):
-        """Returns true if ssh can connect to server."""
-        try:
-            connection = self._get_ssh_connection()
-            connection.close()
-        except paramiko.AuthenticationException:
-            return False
-
-        return True
+        """Raises an exception when we can not connect to server via ssh."""
+        connection = self._get_ssh_connection()
+        connection.close()
diff --git a/tempest/common/utils/linux/remote_client.py b/tempest/common/utils/linux/remote_client.py
index 0d0e794..144536a 100644
--- a/tempest/common/utils/linux/remote_client.py
+++ b/tempest/common/utils/linux/remote_client.py
@@ -19,7 +19,6 @@
 from tempest.common import utils
 from tempest.config import TempestConfig
 from tempest.exceptions import ServerUnreachable
-from tempest.exceptions import SSHTimeout
 
 
 class RemoteClient():
@@ -40,16 +39,15 @@
                     break
             else:
                 raise ServerUnreachable()
-
         self.ssh_client = Client(ip_address, username, password, ssh_timeout,
                                  pkey=pkey,
                                  channel_timeout=ssh_channel_timeout)
-        if not self.ssh_client.test_connection_auth():
-            raise SSHTimeout()
 
-    def can_authenticate(self):
-        # Re-authenticate
-        return self.ssh_client.test_connection_auth()
+    def validate_authentication(self):
+        """Validate ssh connection and authentication
+           This method raises an Exception when the validation fails.
+        """
+        self.ssh_client.test_connection_auth()
 
     def hostname_equals_servername(self, expected_hostname):
         # Get host name using command "hostname"
@@ -89,3 +87,11 @@
         # usually to /dev/ttyS0
         cmd = 'sudo sh -c "echo \\"%s\\" >/dev/console"' % message
         return self.ssh_client.exec_command(cmd)
+
+    def ping_host(self, host):
+        cmd = 'ping -c1 -w1 %s' % host
+        return self.ssh_client.exec_command(cmd)
+
+    def get_mac_address(self):
+        cmd = "/sbin/ifconfig | awk '/HWaddr/ {print $5}'"
+        return self.ssh_client.exec_command(cmd)
diff --git a/tempest/common/waiters.py b/tempest/common/waiters.py
index bea2cdc..d2b40c9 100644
--- a/tempest/common/waiters.py
+++ b/tempest/common/waiters.py
@@ -25,7 +25,7 @@
 
 # NOTE(afazekas): This function needs to know a token and a subject.
 def wait_for_server_status(client, server_id, status, ready_wait=True,
-                           extra_timeout=0):
+                           extra_timeout=0, raise_on_error=True):
     """Waits for a server to reach a given status."""
 
     def _get_task_state(body):
@@ -69,16 +69,53 @@
                      '/'.join((old_status, str(old_task_state))),
                      '/'.join((server_status, str(task_state))),
                      time.time() - start_time)
-        if server_status == 'ERROR':
+        if (server_status == 'ERROR') and raise_on_error:
             raise exceptions.BuildErrorException(server_id=server_id)
 
         timed_out = int(time.time()) - start_time >= timeout
 
         if timed_out:
-            message = ('Server %s failed to reach %s status within the '
-                       'required time (%s s).' %
-                       (server_id, status, timeout))
+            expected_task_state = 'None' if ready_wait else 'n/a'
+            message = ('Server %(server_id)s failed to reach %(status)s '
+                       'status and task state "%(expected_task_state)s" '
+                       'within the required time (%(timeout)s s).' %
+                       {'server_id': server_id,
+                        'status': status,
+                        'expected_task_state': expected_task_state,
+                        'timeout': timeout})
             message += ' Current status: %s.' % server_status
+            message += ' Current task state: %s.' % task_state
             raise exceptions.TimeoutException(message)
         old_status = server_status
         old_task_state = task_state
+
+
+def wait_for_image_status(client, image_id, status):
+    """Waits for an image to reach a given status.
+
+    The client should have a get_image(image_id) method to get the image.
+    The client should also have build_interval and build_timeout attributes.
+    """
+    resp, image = client.get_image(image_id)
+    start = int(time.time())
+
+    while image['status'] != status:
+        time.sleep(client.build_interval)
+        resp, image = client.get_image(image_id)
+        if image['status'] == 'ERROR':
+            raise exceptions.AddImageException(image_id=image_id)
+
+        # check the status again to avoid a false negative where we hit
+        # the timeout at the same time that the image reached the expected
+        # status
+        if image['status'] == status:
+            return
+
+        if int(time.time()) - start >= client.build_timeout:
+            message = ('Image %(image_id)s failed to reach %(status)s '
+                       'status within the required time (%(timeout)s s).' %
+                       {'image_id': image_id,
+                        'status': status,
+                        'timeout': client.build_timeout})
+            message += ' Current status: %s.' % image['status']
+            raise exceptions.TimeoutException(message)
diff --git a/tempest/config.py b/tempest/config.py
index d97c7b2..3d9eba9 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -103,14 +103,6 @@
                      "users. This option enables isolated test cases and "
                      "better parallel execution, but also requires that "
                      "OpenStack Identity API admin credentials are known."),
-    cfg.BoolOpt('allow_tenant_reuse',
-                default=True,
-                help="If allow_tenant_isolation is True and a tenant that "
-                     "would be created for a given test already exists (such "
-                     "as from a previously-failed run), re-use that tenant "
-                     "instead of failing because of the conflict. Note that "
-                     "this would result in the tenant being deleted at the "
-                     "end of a subsequent successful run."),
     cfg.StrOpt('image_ref',
                default="{$IMAGE_ID}",
                help="Valid secondary image reference to be used in tests."),
@@ -216,9 +208,14 @@
     cfg.BoolOpt('disk_config',
                 default=True,
                 help="If false, skip disk config tests"),
-    cfg.BoolOpt('flavor_extra',
-                default=True,
-                help="If false, skip flavor extra data test"),
+    cfg.ListOpt('api_extensions',
+                default=['all'],
+                help='A list of enabled extensions with a special entry all '
+                     'which indicates every extension is enabled'),
+    cfg.ListOpt('api_v3_extensions',
+                default=['all'],
+                help='A list of enabled v3 extensions with a special entry all'
+                     ' which indicates every extension is enabled'),
     cfg.BoolOpt('change_password',
                 default=False,
                 help="Does the test environment support changing the admin "
@@ -325,6 +322,16 @@
                     "connectivity"),
 ]
 
+network_feature_group = cfg.OptGroup(name='network-feature-enabled',
+                                     title='Enabled network service features')
+
+NetworkFeaturesGroup = [
+    cfg.ListOpt('api_extensions',
+                default=['all'],
+                help='A list of enabled extensions with a special entry all '
+                     'which indicates every extension is enabled'),
+]
+
 volume_group = cfg.OptGroup(name='volume',
                             title='Block Storage Options')
 
@@ -368,7 +375,11 @@
 VolumeFeaturesGroup = [
     cfg.BoolOpt('multi_backend',
                 default=False,
-                help="Runs Cinder multi-backend test (requires 2 backends)")
+                help="Runs Cinder multi-backend test (requires 2 backends)"),
+    cfg.ListOpt('api_extensions',
+                default=['all'],
+                help='A list of enabled extensions with a special entry all '
+                     'which indicates every extension is enabled'),
 ]
 
 
@@ -667,6 +678,8 @@
         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)
@@ -688,6 +701,7 @@
         self.images = cfg.CONF.image
         self.image_feature_enabled = cfg.CONF['image-feature-enabled']
         self.network = cfg.CONF.network
+        self.network_feature_enabled = cfg.CONF['network-feature-enabled']
         self.volume = cfg.CONF.volume
         self.volume_feature_enabled = cfg.CONF['volume-feature-enabled']
         self.object_storage = cfg.CONF['object-storage']
diff --git a/tempest/exceptions.py b/tempest/exceptions.py
index 02fc231..0bab9c7 100644
--- a/tempest/exceptions.py
+++ b/tempest/exceptions.py
@@ -184,3 +184,7 @@
 class ResponseWithEntity(RFCViolation):
     message = ("RFC Violation! Response with 205 HTTP Status Code "
                "MUST NOT have an entity")
+
+
+class InvalidHTTPResponseBody(RestClientException):
+    message = "HTTP response body is invalid json or xml"
diff --git a/tempest/hacking/checks.py b/tempest/hacking/checks.py
index 4c1c107..2adc98e 100644
--- a/tempest/hacking/checks.py
+++ b/tempest/hacking/checks.py
@@ -21,6 +21,7 @@
 
 PYTHON_CLIENT_RE = re.compile('import (%s)client' % '|'.join(PYTHON_CLIENTS))
 TEST_DEFINITION = re.compile(r'^\s*def test.*')
+SETUPCLASS_DEFINITION = re.compile(r'^\s*def setUpClass')
 SCENARIO_DECORATOR = re.compile(r'\s*@.*services\(')
 
 
@@ -52,6 +53,14 @@
                         "T104: Scenario tests require a service decorator")
 
 
+def no_setupclass_for_unit_tests(physical_line, filename):
+    if 'tempest/tests' in filename:
+        if SETUPCLASS_DEFINITION.match(physical_line):
+            return (physical_line.find('def'),
+                    "T105: setUpClass can not be used with unit tests")
+
+
 def factory(register):
     register(import_no_clients_in_api)
     register(scenario_tests_need_service_tags)
+    register(no_setupclass_for_unit_tests)
diff --git a/tempest/openstack/common/log.py b/tempest/openstack/common/log.py
index 5cf8ed6..abb44ef 100644
--- a/tempest/openstack/common/log.py
+++ b/tempest/openstack/common/log.py
@@ -132,6 +132,7 @@
                     'boto=WARN',
                     'suds=INFO',
                     'keystone=INFO',
+                    'paramiko=INFO'
                 ],
                 help='list of logger=LEVEL pairs'),
     cfg.BoolOpt('publish_errors',
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 06841e1..9f97964 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -33,7 +33,6 @@
 
 from tempest.api.network import common as net_common
 from tempest.common import isolated_creds
-from tempest.common import ssh
 from tempest.common.utils import data_utils
 from tempest.common.utils.linux.remote_client import RemoteClient
 from tempest import exceptions
@@ -248,7 +247,8 @@
                 thing.delete()
             except Exception as e:
                 # If the resource is already missing, mission accomplished.
-                if e.__class__.__name__ == 'NotFound':
+                # add status code as workaround for bug 1247568
+                if e.__class__.__name__ == 'NotFound' or e.status_code == 404:
                     continue
                 raise
 
@@ -343,7 +343,11 @@
                     raise
 
             new_status = thing.status
-            if new_status == error_status:
+
+            # Some components are reporting error status in lower case
+            # so case sensitive comparisons can really mess things
+            # up.
+            if new_status.lower() == error_status.lower():
                 message = "%s failed to get to expected status. \
                           In %s state." % (thing, new_status)
                 raise exceptions.BuildErrorException(message)
@@ -537,6 +541,27 @@
         routers = self.network_client.list_routers()
         return routers['routers']
 
+    def _list_ports(self):
+        ports = self.network_client.list_ports()
+        return ports['ports']
+
+    def _get_tenant_own_network_num(self, tenant_id):
+        nets = self._list_networks()
+        ownnets = [value for value in nets if tenant_id == value['tenant_id']]
+        return len(ownnets)
+
+    def _get_tenant_own_subnet_num(self, tenant_id):
+        subnets = self._list_subnets()
+        ownsubnets = ([value for value in subnets
+                      if tenant_id == value['tenant_id']])
+        return len(ownsubnets)
+
+    def _get_tenant_own_port_num(self, tenant_id):
+        ports = self._list_ports()
+        ownports = ([value for value in ports
+                    if tenant_id == value['tenant_id']])
+        return len(ownports)
+
     def _create_subnet(self, network, namestart='subnet-smoke-'):
         """
         Create a subnet for the given network within the cidr block
@@ -603,7 +628,15 @@
         self.set_resource(data_utils.rand_name('floatingip-'), floating_ip)
         return floating_ip
 
-    def _ping_ip_address(self, ip_address):
+    def _disassociate_floating_ip(self, floating_ip):
+        """
+        :param floating_ip: type DeletableFloatingIp
+        """
+        floating_ip.update(port_id=None)
+        self.assertEqual(None, floating_ip.port_id)
+        return floating_ip
+
+    def _ping_ip_address(self, ip_address, should_succeed=True):
         cmd = ['ping', '-c1', '-w1', ip_address]
 
         def ping():
@@ -611,30 +644,38 @@
                                     stdout=subprocess.PIPE,
                                     stderr=subprocess.PIPE)
             proc.wait()
-            if proc.returncode == 0:
-                return True
+            return (proc.returncode == 0) == should_succeed
 
         return tempest.test.call_until_true(
             ping, self.config.compute.ping_timeout, 1)
 
-    def _is_reachable_via_ssh(self, ip_address, username, private_key,
-                              timeout):
-        ssh_client = ssh.Client(ip_address, username,
-                                pkey=private_key,
-                                timeout=timeout)
-        return ssh_client.test_connection_auth()
+    def _check_vm_connectivity(self, ip_address,
+                               username=None,
+                               private_key=None,
+                               should_connect=True):
+        """
+        :param ip_address: server to test against
+        :param username: server's ssh username
+        :param private_key: server's ssh private key to be used
+        :param should_connect: True/False indicates positive/negative test
+            positive - attempt ping and ssh
+            negative - attempt ping and fail if succeed
 
-    def _check_vm_connectivity(self, ip_address, username, private_key):
-        self.assertTrue(self._ping_ip_address(ip_address),
-                        "Timed out waiting for %s to become "
-                        "reachable" % ip_address)
-        self.assertTrue(self._is_reachable_via_ssh(
-            ip_address,
-            username,
-            private_key,
-            timeout=self.config.compute.ssh_timeout),
-            'Auth failure in connecting to %s@%s via ssh' %
-            (username, ip_address))
+        :raises: AssertError if the result of the connectivity check does
+            not match the value of the should_connect param
+        """
+        if should_connect:
+            msg = "Timed out waiting for %s to become reachable" % ip_address
+        else:
+            msg = "ip address %s is reachable" % ip_address
+        self.assertTrue(self._ping_ip_address(ip_address,
+                                              should_succeed=should_connect),
+                        msg=msg)
+        if should_connect:
+            # no need to check ssh for negative connectivity
+            linux_client = self.get_remote_client(ip_address, username,
+                                                  private_key)
+            linux_client.validate_authentication()
 
     def _create_security_group_nova(self, client=None,
                                     namestart='secgroup-smoke-',
@@ -801,6 +842,78 @@
 
         return rules
 
+    def _ssh_to_server(self, server, private_key):
+        ssh_login = self.config.compute.image_ssh_user
+        return self.get_remote_client(server,
+                                      username=ssh_login,
+                                      private_key=private_key)
+
+    def _show_quota_network(self, tenant_id):
+        quota = self.network_client.show_quota(tenant_id)
+        return quota['quota']['network']
+
+    def _show_quota_subnet(self, tenant_id):
+        quota = self.network_client.show_quota(tenant_id)
+        return quota['quota']['subnet']
+
+    def _show_quota_port(self, tenant_id):
+        quota = self.network_client.show_quota(tenant_id)
+        return quota['quota']['port']
+
+    def _get_router(self, tenant_id):
+        """Retrieve a router for the given tenant id.
+
+        If a public router has been configured, it will be returned.
+
+        If a public router has not been configured, but a public
+        network has, a tenant router will be created and returned that
+        routes traffic to the public network.
+        """
+        router_id = self.config.network.public_router_id
+        network_id = self.config.network.public_network_id
+        if router_id:
+            result = self.network_client.show_router(router_id)
+            return net_common.AttributeDict(**result['router'])
+        elif network_id:
+            router = self._create_router(tenant_id)
+            router.add_gateway(network_id)
+            return router
+        else:
+            raise Exception("Neither of 'public_router_id' or "
+                            "'public_network_id' has been defined.")
+
+    def _create_router(self, tenant_id, namestart='router-smoke-'):
+        name = data_utils.rand_name(namestart)
+        body = dict(
+            router=dict(
+                name=name,
+                admin_state_up=True,
+                tenant_id=tenant_id,
+            ),
+        )
+        result = self.network_client.create_router(body=body)
+        router = net_common.DeletableRouter(client=self.network_client,
+                                            **result['router'])
+        self.assertEqual(router.name, name)
+        self.set_resource(name, router)
+        return router
+
+    def _create_networks(self, tenant_id=None):
+        """Create a network with a subnet connected to a router.
+
+        :returns: network, subnet, router
+        """
+        if tenant_id is None:
+            tenant_id = self.tenant_id
+        network = self._create_network(tenant_id)
+        router = self._get_router(tenant_id)
+        subnet = self._create_subnet(network)
+        subnet.add_to_router(router.id)
+        self.networks.append(network)
+        self.subnets.append(subnet)
+        self.routers.append(router)
+        return network, subnet, router
+
 
 class OrchestrationScenarioTest(OfficialClientTest):
     """
diff --git a/tempest/scenario/orchestration/test_autoscaling.py b/tempest/scenario/orchestration/test_autoscaling.py
index e843793..90ef3a0 100644
--- a/tempest/scenario/orchestration/test_autoscaling.py
+++ b/tempest/scenario/orchestration/test_autoscaling.py
@@ -19,6 +19,7 @@
 from tempest.test import attr
 from tempest.test import call_until_true
 from tempest.test import services
+from tempest.test import skip_because
 
 
 class AutoScalingTest(manager.OrchestrationScenarioTest):
@@ -62,6 +63,7 @@
         if not self.config.orchestration.keypair_name:
             self.set_resource('stack', self.stack)
 
+    @skip_because(bug="1257575")
     @attr(type='slow')
     @services('orchestration', 'compute')
     def test_scale_up_then_down(self):
diff --git a/tempest/scenario/orchestration/test_autoscaling.yaml b/tempest/scenario/orchestration/test_autoscaling.yaml
index 745eb05..4651284 100644
--- a/tempest/scenario/orchestration/test_autoscaling.yaml
+++ b/tempest/scenario/orchestration/test_autoscaling.yaml
@@ -23,11 +23,11 @@
     Default: '420'
   ScaleUpThreshold:
     Description: Memory percentage threshold to scale up on
-    Type: Number
+    Type: String
     Default: '70'
   ScaleDownThreshold:
     Description: Memory percentage threshold to scale down on
-    Type: Number
+    Type: String
     Default: '60'
   ConsumeMemoryLimit:
     Description: Memory percentage threshold to consume
@@ -182,4 +182,4 @@
             # wait ConsumeStartSeconds then ramp up memory consumption
             # until it is over ConsumeMemoryLimit%
             # then exits ConsumeStopSeconds seconds after stack launch
-            /root/consume_memory > /root/consume_memory.log &
\ No newline at end of file
+            /root/consume_memory > /root/consume_memory.log &
diff --git a/tempest/scenario/test_cross_tenant_connectivity.py b/tempest/scenario/test_cross_tenant_connectivity.py
new file mode 100644
index 0000000..ad2c271
--- /dev/null
+++ b/tempest/scenario/test_cross_tenant_connectivity.py
@@ -0,0 +1,494 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 Red Hat, Inc.
+# 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 debug
+from tempest.common.utils import data_utils
+from tempest import exceptions
+from tempest.openstack.common import log as logging
+from tempest.scenario import manager
+from tempest.scenario.manager import OfficialClientManager
+from tempest.test import attr
+from tempest.test import call_until_true
+from tempest.test import services
+
+LOG = logging.getLogger(__name__)
+
+
+class TestNetworkCrossTenant(manager.NetworkScenarioTest):
+
+    """
+    This test suite assumes that Nova has been configured to
+    boot VM's with Neutron-managed networking, and attempts to
+    verify cross tenant connectivity as follows
+
+    ssh:
+        in order to overcome "ip namespace", each tenant has an "access point"
+        VM with floating-ip open to incoming ssh connection allowing network
+        commands (ping/ssh) to be executed from within the
+        tenant-network-namespace
+        Tempest host performs key-based authentication to the ssh server via
+        floating IP address
+
+    connectivity test is done by pinging destination server via source server
+    ssh connection.
+    success - ping returns
+    failure - ping_timeout reached
+
+    setup:
+        for each tenant (demo and alt):
+            1. create a network&subnet
+            2. create a router (if public router isn't configured)
+            3. connect tenant network to public network via router
+            4. create an access point:
+                a. a security group open to incoming ssh connection
+                b. a VM with a floating ip
+            5. create a general empty security group (same as "default", but
+            without rules allowing in-tenant traffic)
+            6. for demo tenant - create another server to test in-tenant
+            connections
+
+    tests:
+        1. _verify_network_details
+        2. _verify_mac_addr: for each access point verify that
+        (subnet, fix_ip, mac address) are as defined in the port list
+        3. _test_in_tenant_block: test that in-tenant traffic is disabled
+        without rules allowing it
+        4. _test_in_tenant_allow: test that in-tenant traffic is enabled
+        once an appropriate rule has been created
+        5. _test_cross_tenant_block: test that cross-tenant traffic is disabled
+        without a rule allowing it on destination tenant
+        6. _test_cross_tenant_allow:
+            * test that cross-tenant traffic is enabled once an appropriate
+            rule has been created on destination tenant.
+            * test that reverse traffic is still blocked
+            * test than revesre traffic is enabled once an appropriate rule has
+            been created on source tenant
+
+    assumptions:
+        1. alt_tenant/user existed and is different from demo_tenant/user
+        2. Public network is defined and reachable from the Tempest host
+        3. Public router can either be:
+            * defined, in which case all tenants networks can connect directly
+            to it, and cross tenant check will be done on the private IP of the
+            destination tenant
+            or
+            * not defined (empty string), in which case each tanant will have
+            its own router connected to the public network
+    """
+
+    class TenantProperties():
+        '''
+        helper class to save tenant details
+            id
+            credentials
+            network
+            subnet
+            security groups
+            servers
+            access point
+        '''
+
+        def __init__(self, tenant_id, tenant_user, tenant_pass, tenant_name):
+            self.manager = OfficialClientManager(
+                tenant_user,
+                tenant_pass,
+                tenant_name
+            )
+            self.tenant_id = tenant_id
+            self.tenant_name = tenant_name
+            self.tenant_user = tenant_user
+            self.tenant_pass = tenant_pass
+            self.network = None
+            self.subnet = None
+            self.router = None
+            self.security_groups = {}
+            self.servers = list()
+
+        def _set_network(self, network, subnet, router):
+            self.network = network
+            self.subnet = subnet
+            self.router = router
+
+        def _get_tenant_credentials(self):
+            return self.tenant_user, self.tenant_pass, self.tenant_name
+
+    @classmethod
+    def check_preconditions(cls):
+        super(TestNetworkCrossTenant, cls).check_preconditions()
+        if (cls.alt_tenant_id is None) or (cls.tenant_id is cls.alt_tenant_id):
+            msg = 'No alt_tenant defined'
+            cls.enabled = False
+            raise cls.skipException(msg)
+        cfg = cls.config.network
+        if not (cfg.tenant_networks_reachable or cfg.public_network_id):
+            msg = ('Either tenant_networks_reachable must be "true", or '
+                   'public_network_id must be defined.')
+            cls.enabled = False
+            raise cls.skipException(msg)
+
+    @classmethod
+    def setUpClass(cls):
+        super(TestNetworkCrossTenant, cls).setUpClass()
+        cls.alt_tenant_id = cls.manager._get_identity_client(
+            cls.config.identity.alt_username,
+            cls.config.identity.alt_password,
+            cls.config.identity.alt_tenant_name
+        ).tenant_id
+        cls.check_preconditions()
+        # TODO(mnewby) Consider looking up entities as needed instead
+        # of storing them as collections on the class.
+        cls.keypairs = {}
+        cls.security_groups = {}
+        cls.networks = []
+        cls.subnets = []
+        cls.routers = []
+        cls.servers = []
+        cls.floating_ips = {}
+        cls.tenants = {}
+        cls.demo_tenant = cls.TenantProperties(
+            cls.tenant_id,
+            cls.config.identity.username,
+            cls.config.identity.password,
+            cls.config.identity.tenant_name
+        )
+        cls.alt_tenant = cls.TenantProperties(
+            cls.alt_tenant_id,
+            cls.config.identity.alt_username,
+            cls.config.identity.alt_password,
+            cls.config.identity.alt_tenant_name
+        )
+        for tenant in [cls.demo_tenant, cls.alt_tenant]:
+            cls.tenants[tenant.tenant_id] = tenant
+        if not cls.config.network.public_router_id:
+            cls.floating_ip_access = True
+        else:
+            cls.floating_ip_access = False
+
+    @classmethod
+    def tearDownClass(cls):
+        super(TestNetworkCrossTenant, cls).tearDownClass()
+
+    def _create_tenant_keypairs(self, tenant_id):
+        self.keypairs[tenant_id] = self.create_keypair(
+            name=data_utils.rand_name('keypair-smoke-'))
+
+    def _create_tenant_security_groups(self, tenant):
+        self.security_groups.setdefault(self.tenant_id, [])
+        access_sg = self._create_empty_security_group(
+            namestart='secgroup_access-',
+            tenant_id=tenant.tenant_id
+        )
+        # don't use default secgroup since it allows in-tenant traffic
+        def_sg = self._create_empty_security_group(
+            namestart='secgroup_general-',
+            tenant_id=tenant.tenant_id
+        )
+        tenant.security_groups.update(access=access_sg, default=def_sg)
+        ssh_rule = dict(
+            protocol='tcp',
+            port_range_min=22,
+            port_range_max=22,
+            direction='ingress',
+        )
+        self._create_security_group_rule(secgroup=access_sg,
+                                         **ssh_rule
+                                         )
+
+    def _verify_network_details(self, tenant):
+        # Checks that we see the newly created network/subnet/router via
+        # checking the result of list_[networks,routers,subnets]
+        # Check that (router, subnet) couple exist in port_list
+        seen_nets = self._list_networks()
+        seen_names = [n['name'] for n in seen_nets]
+        seen_ids = [n['id'] for n in seen_nets]
+
+        self.assertIn(tenant.network.name, seen_names)
+        self.assertIn(tenant.network.id, seen_ids)
+
+        seen_subnets = [(n['id'], n['cidr'], n['network_id'])
+                        for n in self._list_subnets()]
+        mysubnet = (tenant.subnet.id, tenant.subnet.cidr, tenant.network.id)
+        self.assertIn(mysubnet, seen_subnets)
+
+        seen_routers = self._list_routers()
+        seen_router_ids = [n['id'] for n in seen_routers]
+        seen_router_names = [n['name'] for n in seen_routers]
+
+        self.assertIn(tenant.router.name, seen_router_names)
+        self.assertIn(tenant.router.id, seen_router_ids)
+
+        myport = (tenant.router.id, tenant.subnet.id)
+        router_ports = [(i['device_id'], i['fixed_ips'][0]['subnet_id']) for i
+                        in self.network_client.list_ports()['ports']
+                        if i['device_owner'] == 'network:router_interface']
+
+        self.assertIn(myport, router_ports)
+
+    def _create_server(self, name, tenant, security_groups=None):
+        """
+        creates a server and assigns to security group
+        """
+        self._set_compute_context(tenant)
+        if security_groups is None:
+            security_groups = [tenant.security_groups['default'].name]
+        create_kwargs = {
+            'nics': [
+                {'net-id': tenant.network.id},
+            ],
+            'key_name': self.keypairs[tenant.tenant_id].name,
+            'security_groups': security_groups,
+            'tenant_id': tenant.tenant_id
+        }
+        server = self.create_server(name=name, create_kwargs=create_kwargs)
+        return server
+
+    def _create_tenant_servers(self, tenant, num=1):
+        for i in range(num):
+            name = 'server-{tenant}-gen-{num}-'.format(
+                   tenant=tenant.tenant_name,
+                   num=i
+            )
+            name = data_utils.rand_name(name)
+            server = self._create_server(name, tenant)
+            self.servers.append(server)
+            tenant.servers.append(server)
+
+    def _set_access_point(self, tenant):
+        """
+        creates a server in a secgroup with rule allowing external ssh
+        in order to access tenant internal network
+        workaround ip namespace
+        """
+        secgroups = [sg.name for sg in tenant.security_groups.values()]
+        name = 'server-{tenant}-access_point-'.format(tenant=tenant.tenant_name
+                                                      )
+        name = data_utils.rand_name(name)
+        server = self._create_server(name, tenant,
+                                     security_groups=secgroups)
+        self.servers.append(server)
+        tenant.access_point = server
+        self._assign_floating_ips(server)
+
+    def _assign_floating_ips(self, server):
+        public_network_id = self.config.network.public_network_id
+        floating_ip = self._create_floating_ip(server, public_network_id)
+        self.floating_ips.setdefault(server, floating_ip)
+
+    def _create_tenant_network(self, tenant):
+        tenant._set_network(*self._create_networks(tenant.tenant_id))
+
+    def _set_compute_context(self, tenant):
+        self.compute_client = tenant.manager.compute_client
+        return self.compute_client
+
+    def _deploy_tenant(self, tenant_or_id):
+        """
+        creates:
+            network
+            subnet
+            router (if public not defined)
+            access security group
+            access-point server
+            for demo_tenant:
+                creates general server to test against
+        """
+        if not isinstance(tenant_or_id, self.TenantProperties):
+            tenant = self.tenants[tenant_or_id]
+            tenant_id = tenant_or_id
+        else:
+            tenant = tenant_or_id
+            tenant_id = tenant.tenant_id
+        self._set_compute_context(tenant)
+        self._create_tenant_keypairs(tenant_id)
+        self._create_tenant_network(tenant)
+        self._create_tenant_security_groups(tenant)
+        if tenant is self.demo_tenant:
+            self._create_tenant_servers(tenant, num=1)
+        self._set_access_point(tenant)
+
+    def _get_server_ip(self, server, floating=False):
+        '''
+        returns the ip (floating/internal) of a server
+        '''
+        if floating:
+            return self.floating_ips[server].floating_ip_address
+        else:
+            network_name = self.tenants[server.tenant_id].network.name
+            return server.networks[network_name][0]
+
+    def _connect_to_access_point(self, tenant):
+        """
+        create ssh connection to tenant access point
+        """
+        access_point_ssh = \
+            self.floating_ips[tenant.access_point].floating_ip_address
+        private_key = self.keypairs[tenant.tenant_id].private_key
+        access_point_ssh = self._ssh_to_server(access_point_ssh,
+                                               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 call_until_true(ping_remote,
+                               self.config.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
+        else:
+            # todo(yfried): remove this line when bug 1252620 is fixed
+            return True
+            msg = "%s is reachable" % ip
+        try:
+            self.assertTrue(self._test_remote_connectivity(access_point, ip,
+                                                           should_succeed),
+                            msg)
+        except Exception:
+            debug.log_ip_ns()
+            raise
+
+    def _test_in_tenant_block(self, tenant):
+        access_point_ssh = self._connect_to_access_point(tenant)
+        for server in tenant.servers:
+            self._check_connectivity(access_point=access_point_ssh,
+                                     ip=self._get_server_ip(server),
+                                     should_succeed=False)
+
+    def _test_in_tenant_allow(self, tenant):
+        ruleset = dict(
+            protocol='icmp',
+            remote_group_id=tenant.security_groups['default'].id,
+            direction='ingress'
+        )
+        rule = self._create_security_group_rule(
+            secgroup=tenant.security_groups['default'],
+            **ruleset
+        )
+        access_point_ssh = self._connect_to_access_point(tenant)
+        for server in tenant.servers:
+            self._check_connectivity(access_point=access_point_ssh,
+                                     ip=self._get_server_ip(server))
+        rule.delete()
+
+    def _test_cross_tenant_block(self, source_tenant, dest_tenant):
+        '''
+        if public router isn't defined, then dest_tenant access is via
+        floating-ip
+        '''
+        access_point_ssh = self._connect_to_access_point(source_tenant)
+        ip = self._get_server_ip(dest_tenant.access_point,
+                                 floating=self.floating_ip_access)
+        self._check_connectivity(access_point=access_point_ssh, ip=ip,
+                                 should_succeed=False)
+
+    def _test_cross_tenant_allow(self, source_tenant, dest_tenant):
+        '''
+        check for each direction:
+        creating rule for tenant incoming traffic enables only 1way traffic
+        '''
+        ruleset = dict(
+            protocol='icmp',
+            direction='ingress'
+        )
+        rule_s2d = self._create_security_group_rule(
+            secgroup=dest_tenant.security_groups['default'],
+            **ruleset
+        )
+        try:
+            access_point_ssh = self._connect_to_access_point(source_tenant)
+            ip = self._get_server_ip(dest_tenant.access_point,
+                                     floating=self.floating_ip_access)
+            self._check_connectivity(access_point_ssh, ip)
+
+            # test that reverse traffic is still blocked
+            self._test_cross_tenant_block(dest_tenant, source_tenant)
+
+            # allow reverse traffic and check
+            rule_d2s = self._create_security_group_rule(
+                secgroup=source_tenant.security_groups['default'],
+                **ruleset
+            )
+            try:
+                access_point_ssh_2 = self._connect_to_access_point(dest_tenant)
+                ip = self._get_server_ip(source_tenant.access_point,
+                                         floating=self.floating_ip_access)
+                self._check_connectivity(access_point_ssh_2, ip)
+
+                # clean_rules
+                rule_s2d.delete()
+                rule_d2s.delete()
+
+            except Exception as e:
+                rule_d2s.delete()
+                raise e
+
+        except Exception as e:
+            rule_s2d.delete()
+            raise e
+
+    def _verify_mac_addr(self, tenant):
+        """
+        verify that VM (tenant's access point) has the same ip,mac as listed in
+        port list
+        """
+        access_point_ssh = self._connect_to_access_point(tenant)
+        mac_addr = access_point_ssh.get_mac_address()
+        mac_addr = mac_addr.strip().lower()
+        port_list = self.network_client.list_ports()['ports']
+        port_detail_list = [
+            (port['fixed_ips'][0]['subnet_id'],
+             port['fixed_ips'][0]['ip_address'],
+             port['mac_address'].lower()) for port in port_list
+        ]
+        server_ip = self._get_server_ip(tenant.access_point)
+        subnet_id = tenant.subnet.id
+        self.assertIn((subnet_id, server_ip, mac_addr), port_detail_list)
+
+    @attr(type='smoke')
+    @services('compute', 'network')
+    def test_cross_tenant_traffic(self):
+        for tenant_id in self.tenants.keys():
+            self._deploy_tenant(tenant_id)
+            self._verify_network_details(self.tenants[tenant_id])
+            self._verify_mac_addr(self.tenants[tenant_id])
+
+        # in-tenant check
+        self._test_in_tenant_block(self.demo_tenant)
+        self._test_in_tenant_allow(self.demo_tenant)
+
+        # cross tenant check
+        source_tenant = self.demo_tenant
+        dest_tenant = self.alt_tenant
+        self._test_cross_tenant_block(source_tenant, dest_tenant)
+        self._test_cross_tenant_allow(source_tenant, dest_tenant)
diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
index bfded53..54517ab 100644
--- a/tempest/scenario/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -16,18 +16,59 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-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
+from tempest.openstack.common import jsonutils
 from tempest.openstack.common import log as logging
 from tempest.scenario import manager
+
+import tempest.test
 from tempest.test import attr
 from tempest.test import services
 
 LOG = logging.getLogger(__name__)
 
 
+class FloatingIPCheckTracker(object):
+    """
+    Checking VM connectivity through floating IP addresses is bound to fail
+    if the floating IP has not actually been associated with the VM yet.
+    This helper class facilitates checking for floating IP assignments on
+    VMs. It only checks for a given IP address once.
+    """
+
+    def __init__(self, compute_client, floating_ip_map):
+        self.compute_client = compute_client
+        self.unchecked = floating_ip_map.copy()
+
+    def run_checks(self):
+        """Check for any remaining unverified floating IPs
+
+        Gets VM details from nova and checks for floating IPs
+        within the returned information. Returns true when all
+        checks are complete and is suitable for use with
+        tempest.test.call_until_true()
+        """
+        to_delete = []
+        loggable_map = {}
+        for check_addr, server in self.unchecked.iteritems():
+            serverdata = self.compute_client.servers.get(server.id)
+            ip_addr = [addr for sublist in serverdata.networks.values() for
+                       addr in sublist]
+            if check_addr.floating_ip_address in ip_addr:
+                to_delete.append(check_addr)
+            else:
+                loggable_map[server.id] = check_addr
+
+        for to_del in to_delete:
+            del self.unchecked[to_del]
+
+        LOG.debug('Unchecked floating IPs: %s',
+                  jsonutils.dumps(loggable_map))
+        return len(self.unchecked) == 0
+
+
 class TestNetworkBasicOps(manager.NetworkScenarioTest):
 
     """
@@ -46,6 +87,9 @@
          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
+
        # TODO(mnewby) - Need to implement the following:
        - the Tempest host can ssh into the VM via the IP address and
          successfully execute the following:
@@ -120,45 +164,6 @@
         cls.servers = []
         cls.floating_ips = {}
 
-    def _get_router(self, tenant_id):
-        """Retrieve a router for the given tenant id.
-
-        If a public router has been configured, it will be returned.
-
-        If a public router has not been configured, but a public
-        network has, a tenant router will be created and returned that
-        routes traffic to the public network.
-
-        """
-        router_id = self.config.network.public_router_id
-        network_id = self.config.network.public_network_id
-        if router_id:
-            result = self.network_client.show_router(router_id)
-            return net_common.AttributeDict(**result['router'])
-        elif network_id:
-            router = self._create_router(tenant_id)
-            router.add_gateway(network_id)
-            return router
-        else:
-            raise Exception("Neither of 'public_router_id' or "
-                            "'public_network_id' has been defined.")
-
-    def _create_router(self, tenant_id, namestart='router-smoke-'):
-        name = data_utils.rand_name(namestart)
-        body = dict(
-            router=dict(
-                name=name,
-                admin_state_up=True,
-                tenant_id=tenant_id,
-            ),
-        )
-        result = self.network_client.create_router(body=body)
-        router = net_common.DeletableRouter(client=self.network_client,
-                                            **result['router'])
-        self.assertEqual(router.name, name)
-        self.set_resource(name, router)
-        return router
-
     def _create_keypairs(self):
         self.keypairs[self.tenant_id] = self.create_keypair(
             name=data_utils.rand_name('keypair-smoke-'))
@@ -167,15 +172,6 @@
         self.security_groups[self.tenant_id] =\
             self._create_security_group_neutron(tenant_id=self.tenant_id)
 
-    def _create_networks(self):
-        network = self._create_network(self.tenant_id)
-        router = self._get_router(self.tenant_id)
-        subnet = self._create_subnet(network)
-        subnet.add_to_router(router.id)
-        self.networks.append(network)
-        self.subnets.append(subnet)
-        self.routers.append(router)
-
     def _check_networks(self):
         # Checks that we see the newly created network/subnet/router via
         # checking the result of list_[networks,routers,subnets]
@@ -228,36 +224,56 @@
         # key-based authentication by cloud-init.
         ssh_login = self.config.compute.image_ssh_user
         private_key = self.keypairs[self.tenant_id].private_key
-        for server in self.servers:
-            for net_name, ip_addresses in server.networks.iteritems():
-                for ip_address in ip_addresses:
-                    self._check_vm_connectivity(ip_address, ssh_login,
-                                                private_key)
+        try:
+            for server in self.servers:
+                for net_name, ip_addresses in server.networks.iteritems():
+                    for ip_address in ip_addresses:
+                        self._check_vm_connectivity(ip_address, ssh_login,
+                                                    private_key)
+        except Exception as exc:
+            LOG.exception(exc)
+            debug.log_ip_ns()
+            raise exc
 
-    def _assign_floating_ips(self):
+    def _wait_for_floating_ip_association(self):
+        ip_tracker = FloatingIPCheckTracker(self.compute_client,
+                                            self.floating_ips)
+
+        self.assertTrue(
+            tempest.test.call_until_true(
+                ip_tracker.run_checks, self.config.compute.build_timeout,
+                self.config.compute.build_interval),
+            "Timed out while waiting for the floating IP assignments "
+            "to propagate")
+
+    def _create_and_associate_floating_ips(self):
         public_network_id = self.config.network.public_network_id
         for server in self.servers:
             floating_ip = self._create_floating_ip(server, public_network_id)
-            self.floating_ips.setdefault(server, [])
-            self.floating_ips[server].append(floating_ip)
+            self.floating_ips[floating_ip] = server
 
-    def _check_public_network_connectivity(self):
+    def _check_public_network_connectivity(self, should_connect=True):
         # The target login is assumed to have been configured for
         # key-based authentication by cloud-init.
         ssh_login = self.config.compute.image_ssh_user
         private_key = self.keypairs[self.tenant_id].private_key
         try:
-            for server, floating_ips in self.floating_ips.iteritems():
-                for floating_ip in floating_ips:
-                    ip_address = floating_ip.floating_ip_address
-                    self._check_vm_connectivity(ip_address,
-                                                ssh_login,
-                                                private_key)
+            for floating_ip, server in self.floating_ips.iteritems():
+                ip_address = floating_ip.floating_ip_address
+                self._check_vm_connectivity(ip_address,
+                                            ssh_login,
+                                            private_key,
+                                            should_connect=should_connect)
         except Exception as exc:
             LOG.exception(exc)
             debug.log_ip_ns()
             raise exc
 
+    def _disassociate_floating_ips(self):
+        for floating_ip, server in self.floating_ips.iteritems():
+            self._disassociate_floating_ip(floating_ip)
+            self.floating_ips[floating_ip] = None
+
     @attr(type='smoke')
     @services('compute', 'network')
     def test_network_basic_ops(self):
@@ -266,6 +282,9 @@
         self._create_networks()
         self._check_networks()
         self._create_servers()
-        self._assign_floating_ips()
-        self._check_public_network_connectivity()
+        self._create_and_associate_floating_ips()
+        self._wait_for_floating_ip_association()
         self._check_tenant_network_connectivity()
+        self._check_public_network_connectivity(should_connect=True)
+        self._disassociate_floating_ips()
+        self._check_public_network_connectivity(should_connect=False)
diff --git a/tempest/scenario/test_network_quotas.py b/tempest/scenario/test_network_quotas.py
index 3268066..cb7aa0b 100644
--- a/tempest/scenario/test_network_quotas.py
+++ b/tempest/scenario/test_network_quotas.py
@@ -20,8 +20,6 @@
 from tempest.scenario.manager import NetworkScenarioTest
 from tempest.test import services
 
-MAX_REASONABLE_ITERATIONS = 51  # more than enough. Default for port is 50.
-
 
 class TestNetworkQuotaBasic(NetworkScenarioTest):
     """
@@ -46,7 +44,9 @@
     @services('network')
     def test_create_network_until_quota_hit(self):
         hit_limit = False
-        for n in xrange(MAX_REASONABLE_ITERATIONS):
+        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,
@@ -56,6 +56,16 @@
                     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')
@@ -65,7 +75,9 @@
                 self._create_network(self.tenant_id,
                                      namestart='network-quotatest-'))
         hit_limit = False
-        for n in xrange(MAX_REASONABLE_ITERATIONS):
+        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],
@@ -75,6 +87,16 @@
                     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')
@@ -84,7 +106,9 @@
                 self._create_network(self.tenant_id,
                                      namestart='network-quotatest-'))
         hit_limit = False
-        for n in xrange(MAX_REASONABLE_ITERATIONS):
+        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],
@@ -94,4 +118,14 @@
                     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/services/compute/json/extensions_client.py b/tempest/services/compute/json/extensions_client.py
index ce46a9b..ad5354c 100644
--- a/tempest/services/compute/json/extensions_client.py
+++ b/tempest/services/compute/json/extensions_client.py
@@ -37,3 +37,8 @@
         _, extensions = self.list_extensions()
         exts = extensions['extensions']
         return any([e for e in exts if e['name'] == extension])
+
+    def get_extension(self, extension_alias):
+        resp, body = self.get('extensions/%s' % extension_alias)
+        body = json.loads(body)
+        return resp, body['extension']
diff --git a/tempest/services/compute/json/images_client.py b/tempest/services/compute/json/images_client.py
index 5f17894..c05571a 100644
--- a/tempest/services/compute/json/images_client.py
+++ b/tempest/services/compute/json/images_client.py
@@ -16,10 +16,10 @@
 #    under the License.
 
 import json
-import time
 import urllib
 
 from tempest.common.rest_client import RestClient
+from tempest.common import waiters
 from tempest import exceptions
 
 
@@ -82,18 +82,7 @@
 
     def wait_for_image_status(self, image_id, status):
         """Waits for an image to reach a given status."""
-        resp, image = self.get_image(image_id)
-        start = int(time.time())
-
-        while image['status'] != status:
-            time.sleep(self.build_interval)
-            resp, image = self.get_image(image_id)
-
-            if image['status'] == 'ERROR':
-                raise exceptions.AddImageException(image_id=image_id)
-
-            if int(time.time()) - start >= self.build_timeout:
-                raise exceptions.TimeoutException
+        waiters.wait_for_image_status(self, image_id, status)
 
     def list_image_metadata(self, image_id):
         """Lists all metadata items for an image."""
diff --git a/tempest/services/compute/json/servers_client.py b/tempest/services/compute/json/servers_client.py
index 3c6a40f..eb1a0c3 100644
--- a/tempest/services/compute/json/servers_client.py
+++ b/tempest/services/compute/json/servers_client.py
@@ -154,10 +154,12 @@
         body = json.loads(body)
         return resp, body
 
-    def wait_for_server_status(self, server_id, status, extra_timeout=0):
+    def wait_for_server_status(self, server_id, status, extra_timeout=0,
+                               raise_on_error=True):
         """Waits for a server to reach a given status."""
         return waiters.wait_for_server_status(self, server_id, status,
-                                              extra_timeout=extra_timeout)
+                                              extra_timeout=extra_timeout,
+                                              raise_on_error=raise_on_error)
 
     def wait_for_server_termination(self, server_id, ignore_error=False):
         """Waits for server to reach termination."""
diff --git a/tempest/services/compute/v3/json/extensions_client.py b/tempest/services/compute/v3/json/extensions_client.py
index 60c0217..6e0dc9d 100644
--- a/tempest/services/compute/v3/json/extensions_client.py
+++ b/tempest/services/compute/v3/json/extensions_client.py
@@ -38,3 +38,8 @@
         _, extensions = self.list_extensions()
         exts = extensions['extensions']
         return any([e for e in exts if e['name'] == extension])
+
+    def get_extension(self, extension_alias):
+        resp, body = self.get('extensions/%s' % extension_alias)
+        body = json.loads(body)
+        return resp, body['extension']
diff --git a/tempest/services/compute/v3/json/flavors_client.py b/tempest/services/compute/v3/json/flavors_client.py
new file mode 100644
index 0000000..00d6f8a
--- /dev/null
+++ b/tempest/services/compute/v3/json/flavors_client.py
@@ -0,0 +1,156 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# 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.
+
+import json
+import urllib
+
+from tempest.common.rest_client import RestClient
+
+
+class FlavorsClientJSON(RestClient):
+
+    def __init__(self, config, username, password, auth_url, tenant_name=None):
+        super(FlavorsClientJSON, self).__init__(config, username, password,
+                                                auth_url, tenant_name)
+        self.service = self.config.compute.catalog_type
+
+    def list_flavors(self, params=None):
+        url = 'flavors'
+        if params:
+            url += '?%s' % urllib.urlencode(params)
+
+        resp, body = self.get(url)
+        body = json.loads(body)
+        return resp, body['flavors']
+
+    def list_flavors_with_detail(self, params=None):
+        url = 'flavors/detail'
+        if params:
+            url += '?%s' % urllib.urlencode(params)
+
+        resp, body = self.get(url)
+        body = json.loads(body)
+        return resp, body['flavors']
+
+    def get_flavor_details(self, flavor_id):
+        resp, body = self.get("flavors/%s" % str(flavor_id))
+        body = json.loads(body)
+        return resp, body['flavor']
+
+    def create_flavor(self, name, ram, vcpus, disk, flavor_id, **kwargs):
+        """Creates a new flavor or instance type."""
+        post_body = {
+            'name': name,
+            'ram': ram,
+            'vcpus': vcpus,
+            'disk': disk,
+            'id': flavor_id,
+        }
+        if kwargs.get('ephemeral'):
+            post_body['OS-FLV-EXT-DATA:ephemeral'] = kwargs.get('ephemeral')
+        if kwargs.get('swap'):
+            post_body['swap'] = kwargs.get('swap')
+        if kwargs.get('rxtx'):
+            post_body['rxtx_factor'] = kwargs.get('rxtx')
+        if kwargs.get('is_public'):
+            post_body['os-flavor-access:is_public'] = kwargs.get('is_public')
+        post_body = json.dumps({'flavor': post_body})
+        resp, body = self.post('flavors', post_body, self.headers)
+
+        body = json.loads(body)
+        return resp, body['flavor']
+
+    def delete_flavor(self, flavor_id):
+        """Deletes the given flavor."""
+        return self.delete("flavors/%s" % str(flavor_id))
+
+    def is_resource_deleted(self, id):
+        # Did not use get_flavor_details(id) for verification as it gives
+        # 200 ok even for deleted id. LP #981263
+        # we can remove the loop here and use get by ID when bug gets sortedout
+        resp, flavors = self.list_flavors_with_detail()
+        for flavor in flavors:
+            if flavor['id'] == id:
+                return False
+        return True
+
+    def set_flavor_extra_spec(self, flavor_id, specs):
+        """Sets extra Specs to the mentioned flavor."""
+        post_body = json.dumps({'extra_specs': specs})
+        resp, body = self.post('flavors/%s/os-extra_specs' % flavor_id,
+                               post_body, self.headers)
+        body = json.loads(body)
+        return resp, body['extra_specs']
+
+    def get_flavor_extra_spec(self, flavor_id):
+        """Gets extra Specs details of the mentioned flavor."""
+        resp, body = self.get('flavors/%s/os-extra_specs' % flavor_id)
+        body = json.loads(body)
+        return resp, body['extra_specs']
+
+    def get_flavor_extra_spec_with_key(self, flavor_id, key):
+        """Gets extra Specs key-value of the mentioned flavor and key."""
+        resp, body = self.get('flavors/%s/os-extra_specs/%s' % (str(flavor_id),
+                              key))
+        body = json.loads(body)
+        return resp, body
+
+    def update_flavor_extra_spec(self, flavor_id, key, **kwargs):
+        """Update specified extra Specs of the mentioned flavor and key."""
+        resp, body = self.put('flavors/%s/os-extra_specs/%s' %
+                              (flavor_id, key),
+                              json.dumps(kwargs), self.headers)
+        body = json.loads(body)
+        return resp, body
+
+    def unset_flavor_extra_spec(self, flavor_id, key):
+        """Unsets extra Specs from the mentioned flavor."""
+        return self.delete('flavors/%s/os-extra_specs/%s' % (str(flavor_id),
+                           key))
+
+    def list_flavor_access(self, flavor_id):
+        """Gets flavor access information given the flavor id."""
+        resp, body = self.get('flavors/%s/os-flavor-access' % flavor_id,
+                              self.headers)
+        body = json.loads(body)
+        return resp, body['flavor_access']
+
+    def add_flavor_access(self, flavor_id, tenant_id):
+        """Add flavor access for the specified tenant."""
+        post_body = {
+            'addTenantAccess': {
+                'tenant': tenant_id
+            }
+        }
+        post_body = json.dumps(post_body)
+        resp, body = self.post('flavors/%s/action' % flavor_id,
+                               post_body, self.headers)
+        body = json.loads(body)
+        return resp, body['flavor_access']
+
+    def remove_flavor_access(self, flavor_id, tenant_id):
+        """Remove flavor access from the specified tenant."""
+        post_body = {
+            'removeTenantAccess': {
+                'tenant': tenant_id
+            }
+        }
+        post_body = json.dumps(post_body)
+        resp, body = self.post('flavors/%s/action' % flavor_id,
+                               post_body, self.headers)
+        body = json.loads(body)
+        return resp, body['flavor_access']
diff --git a/tempest/services/compute/v3/json/limits_client.py b/tempest/services/compute/v3/json/limits_client.py
new file mode 100644
index 0000000..3e53e3e
--- /dev/null
+++ b/tempest/services/compute/v3/json/limits_client.py
@@ -0,0 +1,40 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# 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.
+
+import json
+from tempest.common.rest_client import RestClient
+
+
+class LimitsClientJSON(RestClient):
+
+    def __init__(self, config, username, password, auth_url, tenant_name=None):
+        super(LimitsClientJSON, self).__init__(config, username, password,
+                                               auth_url, tenant_name)
+        self.service = self.config.compute.catalog_type
+
+    def get_absolute_limits(self):
+        resp, body = self.get("limits")
+        body = json.loads(body)
+        return resp, body['limits']['absolute']
+
+    def get_specific_absolute_limit(self, absolute_limit):
+        resp, body = self.get("limits")
+        body = json.loads(body)
+        if absolute_limit not in body['limits']['absolute']:
+            return None
+        else:
+            return body['limits']['absolute'][absolute_limit]
diff --git a/tempest/services/compute/v3/json/quotas_client.py b/tempest/services/compute/v3/json/quotas_client.py
new file mode 100644
index 0000000..a910dec
--- /dev/null
+++ b/tempest/services/compute/v3/json/quotas_client.py
@@ -0,0 +1,103 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+#
+# Copyright 2012 NTT Data
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import json
+
+from tempest.common.rest_client import RestClient
+
+
+class QuotasClientJSON(RestClient):
+
+    def __init__(self, config, username, password, auth_url, tenant_name=None):
+        super(QuotasClientJSON, self).__init__(config, username, password,
+                                               auth_url, tenant_name)
+        self.service = self.config.compute.catalog_type
+
+    def get_quota_set(self, tenant_id):
+        """List the quota set for a tenant."""
+
+        url = 'os-quota-sets/%s' % str(tenant_id)
+        resp, body = self.get(url)
+        body = json.loads(body)
+        return resp, body['quota_set']
+
+    def get_default_quota_set(self, tenant_id):
+        """List the default quota set for a tenant."""
+
+        url = 'os-quota-sets/%s/defaults' % str(tenant_id)
+        resp, body = self.get(url)
+        body = json.loads(body)
+        return resp, body['quota_set']
+
+    def update_quota_set(self, tenant_id, force=None,
+                         injected_file_content_bytes=None,
+                         metadata_items=None, ram=None, floating_ips=None,
+                         fixed_ips=None, key_pairs=None, instances=None,
+                         security_group_rules=None, injected_files=None,
+                         cores=None, injected_file_path_bytes=None,
+                         security_groups=None):
+        """
+        Updates the tenant's quota limits for one or more resources
+        """
+        post_body = {}
+
+        if force is not None:
+            post_body['force'] = force
+
+        if injected_file_content_bytes is not None:
+            post_body['injected_file_content_bytes'] = \
+                injected_file_content_bytes
+
+        if metadata_items is not None:
+            post_body['metadata_items'] = metadata_items
+
+        if ram is not None:
+            post_body['ram'] = ram
+
+        if floating_ips is not None:
+            post_body['floating_ips'] = floating_ips
+
+        if fixed_ips is not None:
+            post_body['fixed_ips'] = fixed_ips
+
+        if key_pairs is not None:
+            post_body['key_pairs'] = key_pairs
+
+        if instances is not None:
+            post_body['instances'] = instances
+
+        if security_group_rules is not None:
+            post_body['security_group_rules'] = security_group_rules
+
+        if injected_files is not None:
+            post_body['injected_files'] = injected_files
+
+        if cores is not None:
+            post_body['cores'] = cores
+
+        if injected_file_path_bytes is not None:
+            post_body['injected_file_path_bytes'] = injected_file_path_bytes
+
+        if security_groups is not None:
+            post_body['security_groups'] = security_groups
+
+        post_body = json.dumps({'quota_set': post_body})
+        resp, body = self.put('os-quota-sets/%s' % str(tenant_id), post_body,
+                              self.headers)
+
+        body = json.loads(body)
+        return resp, body['quota_set']
diff --git a/tempest/services/compute/v3/json/servers_client.py b/tempest/services/compute/v3/json/servers_client.py
index cddbb53..a7fcc6d 100644
--- a/tempest/services/compute/v3/json/servers_client.py
+++ b/tempest/services/compute/v3/json/servers_client.py
@@ -121,7 +121,7 @@
             post_body['access_ip_v6'] = access_ip_v6
 
         if disk_config is not None:
-            post_body['OS-DCF:diskConfig'] = disk_config
+            post_body['os-disk-config:disk_config'] = disk_config
 
         post_body = json.dumps({'server': post_body})
         resp, body = self.put("servers/%s" % str(server_id),
@@ -309,14 +309,6 @@
         """Detaches a volume from a server instance."""
         return self.action(server_id, 'detach', None, volume_id=volume_id)
 
-    def add_security_group(self, server_id, name):
-        """Adds a security group to the server."""
-        return self.action(server_id, 'add_security_group', None, name=name)
-
-    def remove_security_group(self, server_id, name):
-        """Removes a security group from the server."""
-        return self.action(server_id, 'remove_security_group', None, name=name)
-
     def live_migrate_server(self, server_id, dest_host, use_block_migration):
         """This should be called with administrator privileges ."""
 
diff --git a/tempest/services/compute/v3/json/tenant_usages_client.py b/tempest/services/compute/v3/json/tenant_usages_client.py
index 4dd6964..298f363 100644
--- a/tempest/services/compute/v3/json/tenant_usages_client.py
+++ b/tempest/services/compute/v3/json/tenant_usages_client.py
@@ -21,12 +21,12 @@
 from tempest.common.rest_client import RestClient
 
 
-class TenantUsagesClientJSON(RestClient):
+class TenantUsagesV3ClientJSON(RestClient):
 
     def __init__(self, config, username, password, auth_url, tenant_name=None):
-        super(TenantUsagesClientJSON, self).__init__(
+        super(TenantUsagesV3ClientJSON, self).__init__(
             config, username, password, auth_url, tenant_name)
-        self.service = self.config.compute.catalog_type
+        self.service = self.config.compute.catalog_v3_type
 
     def list_tenant_usages(self, params=None):
         url = 'os-simple-tenant-usage'
diff --git a/tempest/services/compute/v3/xml/extensions_client.py b/tempest/services/compute/v3/xml/extensions_client.py
index e03251c..8f97692 100644
--- a/tempest/services/compute/v3/xml/extensions_client.py
+++ b/tempest/services/compute/v3/xml/extensions_client.py
@@ -43,3 +43,8 @@
         _, extensions = self.list_extensions()
         exts = extensions['extensions']
         return any([e for e in exts if e['name'] == extension])
+
+    def get_extension(self, extension_alias):
+        resp, body = self.get('extensions/%s' % extension_alias, self.headers)
+        body = xml_to_json(etree.fromstring(body))
+        return resp, body
diff --git a/tempest/services/compute/v3/xml/flavors_client.py b/tempest/services/compute/v3/xml/flavors_client.py
new file mode 100644
index 0000000..a1c74d9
--- /dev/null
+++ b/tempest/services/compute/v3/xml/flavors_client.py
@@ -0,0 +1,220 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# 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.
+
+import urllib
+
+from lxml import etree
+
+from tempest.common.rest_client import RestClientXML
+from tempest.services.compute.xml.common import Document
+from tempest.services.compute.xml.common import Element
+from tempest.services.compute.xml.common import Text
+from tempest.services.compute.xml.common import xml_to_json
+from tempest.services.compute.xml.common import XMLNS_11
+
+
+XMLNS_OS_FLV_EXT_DATA = \
+    "http://docs.openstack.org/compute/ext/flavor_extra_data/api/v1.1"
+XMLNS_OS_FLV_ACCESS = \
+    "http://docs.openstack.org/compute/ext/flavor_access/api/v2"
+
+
+class FlavorsClientXML(RestClientXML):
+
+    def __init__(self, config, username, password, auth_url, tenant_name=None):
+        super(FlavorsClientXML, self).__init__(config, username, password,
+                                               auth_url, tenant_name)
+        self.service = self.config.compute.catalog_type
+
+    def _format_flavor(self, f):
+        flavor = {'links': []}
+        for k, v in f.items():
+            if k == 'id':
+                flavor['id'] = v
+                continue
+
+            if k == 'link':
+                flavor['links'].append(v)
+                continue
+
+            if k == '{%s}ephemeral' % XMLNS_OS_FLV_EXT_DATA:
+                k = 'OS-FLV-EXT-DATA:ephemeral'
+
+            if k == '{%s}is_public' % XMLNS_OS_FLV_ACCESS:
+                k = 'os-flavor-access:is_public'
+                v = True if v == 'True' else False
+
+            if k == 'extra_specs':
+                k = 'OS-FLV-WITH-EXT-SPECS:extra_specs'
+                flavor[k] = dict(v)
+                continue
+
+            try:
+                v = int(v)
+            except ValueError:
+                try:
+                    v = float(v)
+                except ValueError:
+                    pass
+
+            flavor[k] = v
+
+        return flavor
+
+    def _parse_array(self, node):
+        return [self._format_flavor(xml_to_json(x)) for x in node]
+
+    def _list_flavors(self, url, params):
+        if params:
+            url += "?%s" % urllib.urlencode(params)
+
+        resp, body = self.get(url, self.headers)
+        flavors = self._parse_array(etree.fromstring(body))
+        return resp, flavors
+
+    def list_flavors(self, params=None):
+        url = 'flavors'
+        return self._list_flavors(url, params)
+
+    def list_flavors_with_detail(self, params=None):
+        url = 'flavors/detail'
+        return self._list_flavors(url, params)
+
+    def get_flavor_details(self, flavor_id):
+        resp, body = self.get("flavors/%s" % str(flavor_id), self.headers)
+        body = xml_to_json(etree.fromstring(body))
+        flavor = self._format_flavor(body)
+        return resp, flavor
+
+    def create_flavor(self, name, ram, vcpus, disk, flavor_id, **kwargs):
+        """Creates a new flavor or instance type."""
+        flavor = Element("flavor",
+                         xmlns=XMLNS_11,
+                         ram=ram,
+                         vcpus=vcpus,
+                         disk=disk,
+                         id=flavor_id,
+                         name=name)
+        if kwargs.get('rxtx'):
+            flavor.add_attr('rxtx_factor', kwargs.get('rxtx'))
+        if kwargs.get('swap'):
+            flavor.add_attr('swap', kwargs.get('swap'))
+        if kwargs.get('ephemeral'):
+            flavor.add_attr('OS-FLV-EXT-DATA:ephemeral',
+                            kwargs.get('ephemeral'))
+        if kwargs.get('is_public'):
+            flavor.add_attr('os-flavor-access:is_public',
+                            kwargs.get('is_public'))
+        flavor.add_attr('xmlns:OS-FLV-EXT-DATA', XMLNS_OS_FLV_EXT_DATA)
+        flavor.add_attr('xmlns:os-flavor-access', XMLNS_OS_FLV_ACCESS)
+        resp, body = self.post('flavors', str(Document(flavor)), self.headers)
+        body = xml_to_json(etree.fromstring(body))
+        flavor = self._format_flavor(body)
+        return resp, flavor
+
+    def delete_flavor(self, flavor_id):
+        """Deletes the given flavor."""
+        return self.delete("flavors/%s" % str(flavor_id), self.headers)
+
+    def is_resource_deleted(self, id):
+        # Did not use get_flavor_details(id) for verification as it gives
+        # 200 ok even for deleted id. LP #981263
+        # we can remove the loop here and use get by ID when bug gets sortedout
+        resp, flavors = self.list_flavors_with_detail()
+        for flavor in flavors:
+            if flavor['id'] == id:
+                return False
+        return True
+
+    def set_flavor_extra_spec(self, flavor_id, specs):
+        """Sets extra Specs to the mentioned flavor."""
+        extra_specs = Element("extra_specs")
+        for key in specs.keys():
+            extra_specs.add_attr(key, specs[key])
+        resp, body = self.post('flavors/%s/os-extra_specs' % flavor_id,
+                               str(Document(extra_specs)), self.headers)
+        body = xml_to_json(etree.fromstring(body))
+        return resp, body
+
+    def get_flavor_extra_spec(self, flavor_id):
+        """Gets extra Specs of the mentioned flavor."""
+        resp, body = self.get('flavors/%s/os-extra_specs' % flavor_id,
+                              self.headers)
+        body = xml_to_json(etree.fromstring(body))
+        return resp, body
+
+    def get_flavor_extra_spec_with_key(self, flavor_id, key):
+        """Gets extra Specs key-value of the mentioned flavor and key."""
+        resp, xml_body = self.get('flavors/%s/os-extra_specs/%s' %
+                                  (str(flavor_id), key), self.headers)
+        body = {}
+        element = etree.fromstring(xml_body)
+        key = element.get('key')
+        body[key] = xml_to_json(element)
+        return resp, body
+
+    def update_flavor_extra_spec(self, flavor_id, key, **kwargs):
+        """Update extra Specs details of the mentioned flavor and key."""
+        doc = Document()
+        for (k, v) in kwargs.items():
+            element = Element(k)
+            doc.append(element)
+            value = Text(v)
+            element.append(value)
+
+        resp, body = self.put('flavors/%s/os-extra_specs/%s' %
+                              (flavor_id, key),
+                              str(doc), self.headers)
+        body = xml_to_json(etree.fromstring(body))
+        return resp, {key: body}
+
+    def unset_flavor_extra_spec(self, flavor_id, key):
+        """Unsets an extra spec based on the mentioned flavor and key."""
+        return self.delete('flavors/%s/os-extra_specs/%s' % (str(flavor_id),
+                           key))
+
+    def _parse_array_access(self, node):
+        return [xml_to_json(x) for x in node]
+
+    def list_flavor_access(self, flavor_id):
+        """Gets flavor access information given the flavor id."""
+        resp, body = self.get('flavors/%s/os-flavor-access' % str(flavor_id),
+                              self.headers)
+        body = self._parse_array(etree.fromstring(body))
+        return resp, body
+
+    def add_flavor_access(self, flavor_id, tenant_id):
+        """Add flavor access for the specified tenant."""
+        doc = Document()
+        server = Element("addTenantAccess")
+        doc.append(server)
+        server.add_attr("tenant", tenant_id)
+        resp, body = self.post('flavors/%s/action' % str(flavor_id),
+                               str(doc), self.headers)
+        body = self._parse_array_access(etree.fromstring(body))
+        return resp, body
+
+    def remove_flavor_access(self, flavor_id, tenant_id):
+        """Remove flavor access from the specified tenant."""
+        doc = Document()
+        server = Element("removeTenantAccess")
+        doc.append(server)
+        server.add_attr("tenant", tenant_id)
+        resp, body = self.post('flavors/%s/action' % str(flavor_id),
+                               str(doc), self.headers)
+        body = self._parse_array_access(etree.fromstring(body))
+        return resp, body
diff --git a/tempest/services/compute/v3/xml/limits_client.py b/tempest/services/compute/v3/xml/limits_client.py
new file mode 100644
index 0000000..704de52
--- /dev/null
+++ b/tempest/services/compute/v3/xml/limits_client.py
@@ -0,0 +1,55 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+#
+# Copyright 2012 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 lxml import objectify
+
+from tempest.common.rest_client import RestClientXML
+
+NS = "{http://docs.openstack.org/common/api/v1.0}"
+
+
+class LimitsClientXML(RestClientXML):
+
+    def __init__(self, config, username, password, auth_url, tenant_name=None):
+        super(LimitsClientXML, self).__init__(config, username, password,
+                                              auth_url, tenant_name)
+        self.service = self.config.compute.catalog_type
+
+    def get_absolute_limits(self):
+        resp, body = self.get("limits", self.headers)
+        body = objectify.fromstring(body)
+        lim = NS + 'absolute'
+        ret = {}
+
+        for el in body[lim].iterchildren():
+            attributes = el.attrib
+            ret[attributes['name']] = attributes['value']
+        return resp, ret
+
+    def get_specific_absolute_limit(self, absolute_limit):
+        resp, body = self.get("limits", self.headers)
+        body = objectify.fromstring(body)
+        lim = NS + 'absolute'
+        ret = {}
+
+        for el in body[lim].iterchildren():
+            attributes = el.attrib
+            ret[attributes['name']] = attributes['value']
+        if absolute_limit not in ret:
+            return None
+        else:
+            return ret[absolute_limit]
diff --git a/tempest/services/compute/v3/xml/quotas_client.py b/tempest/services/compute/v3/xml/quotas_client.py
new file mode 100644
index 0000000..ef5362c
--- /dev/null
+++ b/tempest/services/compute/v3/xml/quotas_client.py
@@ -0,0 +1,126 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+#
+# Copyright 2012 NTT Data
+# 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 lxml import etree
+
+from tempest.common.rest_client import RestClientXML
+from tempest.services.compute.xml.common import Document
+from tempest.services.compute.xml.common import Element
+from tempest.services.compute.xml.common import xml_to_json
+from tempest.services.compute.xml.common import XMLNS_11
+
+
+class QuotasClientXML(RestClientXML):
+
+    def __init__(self, config, username, password, auth_url, tenant_name=None):
+        super(QuotasClientXML, self).__init__(config, username, password,
+                                              auth_url, tenant_name)
+        self.service = self.config.compute.catalog_type
+
+    def _format_quota(self, q):
+        quota = {}
+        for k, v in q.items():
+            try:
+                v = int(v)
+            except ValueError:
+                pass
+
+            quota[k] = v
+
+        return quota
+
+    def _parse_array(self, node):
+        return [self._format_quota(xml_to_json(x)) for x in node]
+
+    def get_quota_set(self, tenant_id):
+        """List the quota set for a tenant."""
+
+        url = 'os-quota-sets/%s' % str(tenant_id)
+        resp, body = self.get(url, self.headers)
+        body = xml_to_json(etree.fromstring(body))
+        body = self._format_quota(body)
+        return resp, body
+
+    def get_default_quota_set(self, tenant_id):
+        """List the default quota set for a tenant."""
+
+        url = 'os-quota-sets/%s/defaults' % str(tenant_id)
+        resp, body = self.get(url, self.headers)
+        body = xml_to_json(etree.fromstring(body))
+        body = self._format_quota(body)
+        return resp, body
+
+    def update_quota_set(self, tenant_id, force=None,
+                         injected_file_content_bytes=None,
+                         metadata_items=None, ram=None, floating_ips=None,
+                         fixed_ips=None, key_pairs=None, instances=None,
+                         security_group_rules=None, injected_files=None,
+                         cores=None, injected_file_path_bytes=None,
+                         security_groups=None):
+        """
+        Updates the tenant's quota limits for one or more resources
+        """
+        post_body = Element("quota_set",
+                            xmlns=XMLNS_11)
+
+        if force is not None:
+            post_body.add_attr('force', force)
+
+        if injected_file_content_bytes is not None:
+            post_body.add_attr('injected_file_content_bytes',
+                               injected_file_content_bytes)
+
+        if metadata_items is not None:
+            post_body.add_attr('metadata_items', metadata_items)
+
+        if ram is not None:
+            post_body.add_attr('ram', ram)
+
+        if floating_ips is not None:
+            post_body.add_attr('floating_ips', floating_ips)
+
+        if fixed_ips is not None:
+            post_body.add_attr('fixed_ips', fixed_ips)
+
+        if key_pairs is not None:
+            post_body.add_attr('key_pairs', key_pairs)
+
+        if instances is not None:
+            post_body.add_attr('instances', instances)
+
+        if security_group_rules is not None:
+            post_body.add_attr('security_group_rules', security_group_rules)
+
+        if injected_files is not None:
+            post_body.add_attr('injected_files', injected_files)
+
+        if cores is not None:
+            post_body.add_attr('cores', cores)
+
+        if injected_file_path_bytes is not None:
+            post_body.add_attr('injected_file_path_bytes',
+                               injected_file_path_bytes)
+
+        if security_groups is not None:
+            post_body.add_attr('security_groups', security_groups)
+
+        resp, body = self.put('os-quota-sets/%s' % str(tenant_id),
+                              str(Document(post_body)),
+                              self.headers)
+        body = xml_to_json(etree.fromstring(body))
+        body = self._format_quota(body)
+        return resp, body
diff --git a/tempest/services/compute/v3/xml/servers_client.py b/tempest/services/compute/v3/xml/servers_client.py
index 2ad5849..7af4161 100644
--- a/tempest/services/compute/v3/xml/servers_client.py
+++ b/tempest/services/compute/v3/xml/servers_client.py
@@ -254,6 +254,10 @@
             server.add_attr("access_ip_v4", access_ip_v4)
         if access_ip_v6 is not None:
             server.add_attr("access_ip_v6", access_ip_v6)
+        if disk_config is not None:
+            server.add_attr('xmlns:os-disk-config', "http://docs.openstack.org"
+                            "/compute/ext/disk_config/api/v3")
+            server.add_attr("os-disk-config:disk_config", disk_config)
         if meta is not None:
             metadata = Element("metadata")
             server.append(metadata)
@@ -511,12 +515,6 @@
                                str(Document(post_body)), self.headers)
         return resp, body
 
-    def add_security_group(self, server_id, name):
-        return self.action(server_id, 'add_security_group', None, name=name)
-
-    def remove_security_group(self, server_id, name):
-        return self.action(server_id, 'remove_security_group', None, name=name)
-
     def live_migrate_server(self, server_id, dest_host, use_block_migration):
         """This should be called with administrator privileges ."""
 
diff --git a/tempest/services/compute/v3/xml/tenant_usages_client.py b/tempest/services/compute/v3/xml/tenant_usages_client.py
index cb92324..790bd5c 100644
--- a/tempest/services/compute/v3/xml/tenant_usages_client.py
+++ b/tempest/services/compute/v3/xml/tenant_usages_client.py
@@ -23,13 +23,13 @@
 from tempest.services.compute.xml.common import xml_to_json
 
 
-class TenantUsagesClientXML(RestClientXML):
+class TenantUsagesV3ClientXML(RestClientXML):
 
     def __init__(self, config, username, password, auth_url, tenant_name=None):
-        super(TenantUsagesClientXML, self).__init__(config, username,
-                                                    password, auth_url,
-                                                    tenant_name)
-        self.service = self.config.compute.catalog_type
+        super(TenantUsagesV3ClientXML, self).__init__(config, username,
+                                                      password, auth_url,
+                                                      tenant_name)
+        self.service = self.config.compute.catalog_v3_type
 
     def _parse_array(self, node):
         json = xml_to_json(node)
diff --git a/tempest/services/compute/xml/extensions_client.py b/tempest/services/compute/xml/extensions_client.py
index 1395b5a..b17fc4f 100644
--- a/tempest/services/compute/xml/extensions_client.py
+++ b/tempest/services/compute/xml/extensions_client.py
@@ -43,3 +43,8 @@
         _, extensions = self.list_extensions()
         exts = extensions['extensions']
         return any([e for e in exts if e['name'] == extension])
+
+    def get_extension(self, extension_alias):
+        resp, body = self.get('extensions/%s' % extension_alias, self.headers)
+        body = xml_to_json(etree.fromstring(body))
+        return resp, body
diff --git a/tempest/services/compute/xml/images_client.py b/tempest/services/compute/xml/images_client.py
index b17ae78..20fcc9b 100644
--- a/tempest/services/compute/xml/images_client.py
+++ b/tempest/services/compute/xml/images_client.py
@@ -15,12 +15,12 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import time
 import urllib
 
 from lxml import etree
 
 from tempest.common.rest_client import RestClientXML
+from tempest.common import waiters
 from tempest import exceptions
 from tempest.services.compute.xml.common import Document
 from tempest.services.compute.xml.common import Element
@@ -140,17 +140,7 @@
 
     def wait_for_image_status(self, image_id, status):
         """Waits for an image to reach a given status."""
-        resp, image = self.get_image(image_id)
-        start = int(time.time())
-
-        while image['status'] != status:
-            time.sleep(self.build_interval)
-            resp, image = self.get_image(image_id)
-            if image['status'] == 'ERROR':
-                raise exceptions.AddImageException(image_id=image_id)
-
-            if int(time.time()) - start >= self.build_timeout:
-                raise exceptions.TimeoutException
+        waiters.wait_for_image_status(self, image_id, status)
 
     def _metadata_body(self, meta):
         post_body = Element('metadata')
diff --git a/tempest/services/compute/xml/servers_client.py b/tempest/services/compute/xml/servers_client.py
index 7d40d0e..68f6cf0 100644
--- a/tempest/services/compute/xml/servers_client.py
+++ b/tempest/services/compute/xml/servers_client.py
@@ -363,10 +363,12 @@
         server = self._parse_server(etree.fromstring(body))
         return resp, server
 
-    def wait_for_server_status(self, server_id, status, extra_timeout=0):
+    def wait_for_server_status(self, server_id, status, extra_timeout=0,
+                               raise_on_error=True):
         """Waits for a server to reach a given status."""
         return waiters.wait_for_server_status(self, server_id, status,
-                                              extra_timeout=extra_timeout)
+                                              extra_timeout=extra_timeout,
+                                              raise_on_error=raise_on_error)
 
     def wait_for_server_termination(self, server_id, ignore_error=False):
         """Waits for server to reach termination."""
diff --git a/tempest/services/identity/v3/json/identity_client.py b/tempest/services/identity/v3/json/identity_client.py
index ec99d37..e457c1f 100644
--- a/tempest/services/identity/v3/json/identity_client.py
+++ b/tempest/services/identity/v3/json/identity_client.py
@@ -359,6 +359,66 @@
                                  (domain_id, group_id, role_id))
         return resp, body
 
+    def create_trust(self, trustor_user_id, trustee_user_id, project_id,
+                     role_names, impersonation, expires_at):
+        """Creates a trust."""
+        roles = [{'name': n} for n in role_names]
+        post_body = {
+            'trustor_user_id': trustor_user_id,
+            'trustee_user_id': trustee_user_id,
+            'project_id': project_id,
+            'impersonation': impersonation,
+            'roles': roles,
+            'expires_at': expires_at
+        }
+        post_body = json.dumps({'trust': post_body})
+        resp, body = self.post('OS-TRUST/trusts', post_body, self.headers)
+        body = json.loads(body)
+        return resp, body['trust']
+
+    def delete_trust(self, trust_id):
+        """Deletes a trust."""
+        resp, body = self.delete("OS-TRUST/trusts/%s" % trust_id)
+        return resp, body
+
+    def get_trusts(self, trustor_user_id=None, trustee_user_id=None):
+        """GET trusts."""
+        if trustor_user_id:
+            resp, body = self.get("OS-TRUST/trusts?trustor_user_id=%s"
+                                  % trustor_user_id)
+        elif trustee_user_id:
+            resp, body = self.get("OS-TRUST/trusts?trustee_user_id=%s"
+                                  % trustee_user_id)
+        else:
+            resp, body = self.get("OS-TRUST/trusts")
+        body = json.loads(body)
+        return resp, body['trusts']
+
+    def get_trust(self, trust_id):
+        """GET trust."""
+        resp, body = self.get("OS-TRUST/trusts/%s" % trust_id)
+        body = json.loads(body)
+        return resp, body['trust']
+
+    def get_trust_roles(self, trust_id):
+        """GET roles delegated by a trust."""
+        resp, body = self.get("OS-TRUST/trusts/%s/roles" % trust_id)
+        body = json.loads(body)
+        return resp, body['roles']
+
+    def get_trust_role(self, trust_id, role_id):
+        """GET role delegated by a trust."""
+        resp, body = self.get("OS-TRUST/trusts/%s/roles/%s"
+                              % (trust_id, role_id))
+        body = json.loads(body)
+        return resp, body['role']
+
+    def check_trust_role(self, trust_id, role_id):
+        """HEAD Check if role is delegated by a trust."""
+        resp, body = self.head("OS-TRUST/trusts/%s/roles/%s"
+                               % (trust_id, role_id))
+        return resp, body
+
 
 class V3TokenClientJSON(RestClient):
 
diff --git a/tempest/services/network/json/network_client.py b/tempest/services/network/json/network_client.py
index aa7f2f2..b323dc6 100644
--- a/tempest/services/network/json/network_client.py
+++ b/tempest/services/network/json/network_client.py
@@ -15,9 +15,10 @@
 import json
 
 from tempest.common.rest_client import RestClient
+from tempest.services.network import network_client_base
 
 
-class NetworkClientJSON(RestClient):
+class NetworkClientJSON(network_client_base.NetworkClientBase):
 
     """
     Tempest REST client for Neutron. Uses v2 of the Neutron API, since the
@@ -32,25 +33,25 @@
     quotas
     """
 
-    def __init__(self, config, username, password, auth_url, tenant_name=None):
-        super(NetworkClientJSON, self).__init__(config, username, password,
-                                                auth_url, tenant_name)
-        self.service = self.config.network.catalog_type
-        self.version = '2.0'
-        self.uri_prefix = "v%s" % (self.version)
+    def get_rest_client(self, config, username,
+                        password, auth_url, tenant_name=None):
+        return RestClient(config, username, password, auth_url, tenant_name)
 
-    def list_networks(self):
-        uri = '%s/networks' % (self.uri_prefix)
-        resp, body = self.get(uri, self.headers)
-        body = json.loads(body)
-        return resp, body
+    def deserialize_single(self, body):
+        return json.loads(body)
+
+    def deserialize_list(self, body):
+        res = json.loads(body)
+        # expecting response in form
+        # {'resources': [ res1, res2] }
+        return res[res.keys()[0]]
 
     def create_network(self, name, **kwargs):
         post_body = {'network': kwargs}
         post_body['network']['name'] = name
         body = json.dumps(post_body)
         uri = '%s/networks' % (self.uri_prefix)
-        resp, body = self.post(uri, headers=self.headers, body=body)
+        resp, body = self.post(uri, body)
         body = json.loads(body)
         return resp, body
 
@@ -61,21 +62,10 @@
         post_body = {'networks': network_list}
         body = json.dumps(post_body)
         uri = '%s/networks' % (self.uri_prefix)
-        resp, body = self.post(uri, headers=self.headers, body=body)
+        resp, body = self.post(uri, body)
         body = json.loads(body)
         return resp, body
 
-    def show_network(self, uuid):
-        uri = '%s/networks/%s' % (self.uri_prefix, uuid)
-        resp, body = self.get(uri, self.headers)
-        body = json.loads(body)
-        return resp, body
-
-    def delete_network(self, uuid):
-        uri = '%s/networks/%s' % (self.uri_prefix, uuid)
-        resp, body = self.delete(uri, self.headers)
-        return resp, body
-
     def create_subnet(self, net_uuid, cidr, ip_version=4, **kwargs):
         post_body = {'subnet': kwargs}
         post_body['subnet']['ip_version'] = ip_version
@@ -83,24 +73,7 @@
         post_body['subnet']['cidr'] = cidr
         body = json.dumps(post_body)
         uri = '%s/subnets' % (self.uri_prefix)
-        resp, body = self.post(uri, headers=self.headers, body=body)
-        body = json.loads(body)
-        return resp, body
-
-    def delete_subnet(self, uuid):
-        uri = '%s/subnets/%s' % (self.uri_prefix, uuid)
-        resp, body = self.delete(uri, self.headers)
-        return resp, body
-
-    def list_subnets(self):
-        uri = '%s/subnets' % (self.uri_prefix)
-        resp, body = self.get(uri, self.headers)
-        body = json.loads(body)
-        return resp, body
-
-    def show_subnet(self, uuid):
-        uri = '%s/subnets/%s' % (self.uri_prefix, uuid)
-        resp, body = self.get(uri, self.headers)
+        resp, body = self.post(uri, body)
         body = json.loads(body)
         return resp, body
 
@@ -114,28 +87,7 @@
             post_body['port'][key] = val
         body = json.dumps(post_body)
         uri = '%s/ports' % (self.uri_prefix)
-        resp, body = self.post(uri, headers=self.headers, body=body)
-        body = json.loads(body)
-        return resp, body
-
-    def delete_port(self, port_id):
-        uri = '%s/ports/%s' % (self.uri_prefix, port_id)
-        resp, body = self.delete(uri, self.headers)
-        return resp, body
-
-    def list_ports(self, **filters):
-        uri = '%s/ports' % (self.uri_prefix)
-        filter_items = ["%s=%s" % (k, v) for (k, v) in filters.iteritems()]
-        querystring = "&".join(filter_items)
-        if querystring:
-            uri = "%s?%s" % (uri, querystring)
-        resp, body = self.get(uri, self.headers)
-        body = json.loads(body)
-        return resp, body
-
-    def show_port(self, port_id):
-        uri = '%s/ports/%s' % (self.uri_prefix, port_id)
-        resp, body = self.get(uri, self.headers)
+        resp, body = self.post(uri, body)
         body = json.loads(body)
         return resp, body
 
@@ -143,27 +95,15 @@
         put_body = {'quota': kwargs}
         body = json.dumps(put_body)
         uri = '%s/quotas/%s' % (self.uri_prefix, tenant_id)
-        resp, body = self.put(uri, body, self.headers)
-        body = json.loads(body)
-        return resp, body['quota']
-
-    def show_quotas(self, tenant_id):
-        uri = '%s/quotas/%s' % (self.uri_prefix, tenant_id)
-        resp, body = self.get(uri, self.headers)
+        resp, body = self.put(uri, body)
         body = json.loads(body)
         return resp, body['quota']
 
     def reset_quotas(self, tenant_id):
         uri = '%s/quotas/%s' % (self.uri_prefix, tenant_id)
-        resp, body = self.delete(uri, self.headers)
+        resp, body = self.delete(uri)
         return resp, body
 
-    def list_quotas(self):
-        uri = '%s/quotas' % (self.uri_prefix)
-        resp, body = self.get(uri, self.headers)
-        body = json.loads(body)
-        return resp, body['quotas']
-
     def update_subnet(self, subnet_id, new_name):
         put_body = {
             'subnet': {
@@ -172,7 +112,7 @@
         }
         body = json.dumps(put_body)
         uri = '%s/subnets/%s' % (self.uri_prefix, subnet_id)
-        resp, body = self.put(uri, body=body, headers=self.headers)
+        resp, body = self.put(uri, body)
         body = json.loads(body)
         return resp, body
 
@@ -184,7 +124,7 @@
         }
         body = json.dumps(put_body)
         uri = '%s/ports/%s' % (self.uri_prefix, port_id)
-        resp, body = self.put(uri, body=body, headers=self.headers)
+        resp, body = self.put(uri, body)
         body = json.loads(body)
         return resp, body
 
@@ -196,13 +136,7 @@
         }
         body = json.dumps(put_body)
         uri = '%s/networks/%s' % (self.uri_prefix, network_id)
-        resp, body = self.put(uri, body=body, headers=self.headers)
-        body = json.loads(body)
-        return resp, body
-
-    def list_routers(self):
-        uri = '%s/routers' % (self.uri_prefix)
-        resp, body = self.get(uri, self.headers)
+        resp, body = self.put(uri, body)
         body = json.loads(body)
         return resp, body
 
@@ -212,24 +146,13 @@
         post_body['router']['admin_state_up'] = admin_state_up
         body = json.dumps(post_body)
         uri = '%s/routers' % (self.uri_prefix)
-        resp, body = self.post(uri, headers=self.headers, body=body)
-        body = json.loads(body)
-        return resp, body
-
-    def delete_router(self, router_id):
-        uri = '%s/routers/%s' % (self.uri_prefix, router_id)
-        resp, body = self.delete(uri, self.headers)
-        return resp, body
-
-    def show_router(self, router_id):
-        uri = '%s/routers/%s' % (self.uri_prefix, router_id)
-        resp, body = self.get(uri, self.headers)
+        resp, body = self.post(uri, body)
         body = json.loads(body)
         return resp, body
 
     def _update_router(self, router_id, set_enable_snat, **kwargs):
         uri = '%s/routers/%s' % (self.uri_prefix, router_id)
-        resp, body = self.get(uri, self.headers)
+        resp, body = self.get(uri)
         body = json.loads(body)
         update_body = {}
         update_body['name'] = kwargs.get('name', body['router']['name'])
@@ -242,7 +165,7 @@
             'external_gateway_info', body['router']['external_gateway_info'])
         update_body = dict(router=update_body)
         update_body = json.dumps(update_body)
-        resp, body = self.put(uri, update_body, self.headers)
+        resp, body = self.put(uri, update_body)
         body = json.loads(body)
         return resp, body
 
@@ -268,7 +191,7 @@
               router_id)
         update_body = {"subnet_id": subnet_id}
         update_body = json.dumps(update_body)
-        resp, body = self.put(uri, update_body, self.headers)
+        resp, body = self.put(uri, update_body)
         body = json.loads(body)
         return resp, body
 
@@ -277,7 +200,7 @@
               router_id)
         update_body = {"port_id": port_id}
         update_body = json.dumps(update_body)
-        resp, body = self.put(uri, update_body, self.headers)
+        resp, body = self.put(uri, update_body)
         body = json.loads(body)
         return resp, body
 
@@ -286,7 +209,7 @@
               router_id)
         update_body = {"subnet_id": subnet_id}
         update_body = json.dumps(update_body)
-        resp, body = self.put(uri, update_body, self.headers)
+        resp, body = self.put(uri, update_body)
         body = json.loads(body)
         return resp, body
 
@@ -295,7 +218,7 @@
               router_id)
         update_body = {"port_id": port_id}
         update_body = json.dumps(update_body)
-        resp, body = self.put(uri, update_body, self.headers)
+        resp, body = self.put(uri, update_body)
         body = json.loads(body)
         return resp, body
 
@@ -305,21 +228,10 @@
         post_body['floatingip']['floating_network_id'] = ext_network_id
         body = json.dumps(post_body)
         uri = '%s/floatingips' % (self.uri_prefix)
-        resp, body = self.post(uri, headers=self.headers, body=body)
+        resp, body = self.post(uri, body=body)
         body = json.loads(body)
         return resp, body
 
-    def list_security_groups(self):
-        uri = '%s/security-groups' % (self.uri_prefix)
-        resp, body = self.get(uri, self.headers)
-        body = json.loads(body)
-        return resp, body
-
-    def delete_security_group(self, secgroup_id):
-        uri = '%s/security-groups/%s' % (self.uri_prefix, secgroup_id)
-        resp, body = self.delete(uri, self.headers)
-        return resp, body
-
     def create_security_group(self, name, **kwargs):
         post_body = {
             'security_group': {
@@ -330,45 +242,16 @@
             post_body['security_group'][str(key)] = value
         body = json.dumps(post_body)
         uri = '%s/security-groups' % (self.uri_prefix)
-        resp, body = self.post(uri, headers=self.headers, body=body)
+        resp, body = self.post(uri, body)
         body = json.loads(body)
         return resp, body
 
-    def show_floating_ip(self, floating_ip_id):
-        uri = '%s/floatingips/%s' % (self.uri_prefix, floating_ip_id)
-        resp, body = self.get(uri, self.headers)
-        body = json.loads(body)
-        return resp, body
-
-    def show_security_group(self, secgroup_id):
-        uri = '%s/security-groups/%s' % (self.uri_prefix, secgroup_id)
-        resp, body = self.get(uri, self.headers)
-        body = json.loads(body)
-        return resp, body
-
-    def list_floating_ips(self):
-        uri = '%s/floatingips' % (self.uri_prefix)
-        resp, body = self.get(uri, self.headers)
-        body = json.loads(body)
-        return resp, body
-
-    def list_security_group_rules(self):
-        uri = '%s/security-group-rules' % (self.uri_prefix)
-        resp, body = self.get(uri, self.headers)
-        body = json.loads(body)
-        return resp, body
-
-    def delete_floating_ip(self, floating_ip_id):
-        uri = '%s/floatingips/%s' % (self.uri_prefix, floating_ip_id)
-        resp, body = self.delete(uri, self.headers)
-        return resp, body
-
     def update_floating_ip(self, floating_ip_id, **kwargs):
         post_body = {
             'floatingip': kwargs}
         body = json.dumps(post_body)
         uri = '%s/floatingips/%s' % (self.uri_prefix, floating_ip_id)
-        resp, body = self.put(uri, headers=self.headers, body=body)
+        resp, body = self.put(uri, body)
         body = json.loads(body)
         return resp, body
 
@@ -384,7 +267,7 @@
             post_body['security_group_rule'][str(key)] = value
         body = json.dumps(post_body)
         uri = '%s/security-group-rules' % (self.uri_prefix)
-        resp, body = self.post(uri, headers=self.headers, body=body)
+        resp, body = self.post(uri, body)
         body = json.loads(body)
         return resp, body
 
@@ -392,18 +275,7 @@
         post_body = {'subnets': subnet_list}
         body = json.dumps(post_body)
         uri = '%s/subnets' % (self.uri_prefix)
-        resp, body = self.post(uri, headers=self.headers, body=body)
-        body = json.loads(body)
-        return resp, body
-
-    def delete_security_group_rule(self, rule_id):
-        uri = '%s/security-group-rules/%s' % (self.uri_prefix, rule_id)
-        resp, body = self.delete(uri, self.headers)
-        return resp, body
-
-    def show_security_group_rule(self, rule_id):
-        uri = '%s/security-group-rules/%s' % (self.uri_prefix, rule_id)
-        resp, body = self.get(uri, self.headers)
+        resp, body = self.post(uri, body)
         body = json.loads(body)
         return resp, body
 
@@ -411,13 +283,7 @@
         post_body = {'ports': port_list}
         body = json.dumps(post_body)
         uri = '%s/ports' % (self.uri_prefix)
-        resp, body = self.post(uri, headers=self.headers, body=body)
-        body = json.loads(body)
-        return resp, body
-
-    def list_vips(self):
-        uri = '%s/lb/vips' % (self.uri_prefix)
-        resp, body = self.get(uri, self.headers)
+        resp, body = self.post(uri, body)
         body = json.loads(body)
         return resp, body
 
@@ -433,7 +299,7 @@
         }
         body = json.dumps(post_body)
         uri = '%s/lb/vips' % (self.uri_prefix)
-        resp, body = self.post(uri, headers=self.headers, body=body)
+        resp, body = self.post(uri, body)
         body = json.loads(body)
         return resp, body
 
@@ -448,26 +314,10 @@
         }
         body = json.dumps(post_body)
         uri = '%s/lb/pools' % (self.uri_prefix)
-        resp, body = self.post(uri, headers=self.headers, body=body)
+        resp, body = self.post(uri, body)
         body = json.loads(body)
         return resp, body
 
-    def show_vip(self, uuid):
-        uri = '%s/lb/vips/%s' % (self.uri_prefix, uuid)
-        resp, body = self.get(uri, self.headers)
-        body = json.loads(body)
-        return resp, body
-
-    def delete_vip(self, uuid):
-        uri = '%s/lb/vips/%s' % (self.uri_prefix, uuid)
-        resp, body = self.delete(uri, self.headers)
-        return resp, body
-
-    def delete_pool(self, uuid):
-        uri = '%s/lb/pools/%s' % (self.uri_prefix, uuid)
-        resp, body = self.delete(uri, self.headers)
-        return resp, body
-
     def update_vip(self, vip_id, new_name):
         put_body = {
             "vip": {
@@ -476,7 +326,7 @@
         }
         body = json.dumps(put_body)
         uri = '%s/lb/vips/%s' % (self.uri_prefix, vip_id)
-        resp, body = self.put(uri, body=body, headers=self.headers)
+        resp, body = self.put(uri, body)
         body = json.loads(body)
         return resp, body
 
@@ -488,25 +338,7 @@
         }
         body = json.dumps(put_body)
         uri = '%s/lb/pools/%s' % (self.uri_prefix, pool_id)
-        resp, body = self.put(uri, body=body, headers=self.headers)
-        body = json.loads(body)
-        return resp, body
-
-    def list_pools(self):
-        uri = '%s/lb/pools' % (self.uri_prefix)
-        resp, body = self.get(uri, self.headers)
-        body = json.loads(body)
-        return resp, body
-
-    def show_pool(self, uuid):
-        uri = '%s/lb/pools/%s' % (self.uri_prefix, uuid)
-        resp, body = self.get(uri, self.headers)
-        body = json.loads(body)
-        return resp, body
-
-    def list_members(self):
-        uri = '%s/lb/members' % (self.uri_prefix)
-        resp, body = self.get(uri, self.headers)
+        resp, body = self.put(uri, body)
         body = json.loads(body)
         return resp, body
 
@@ -520,21 +352,10 @@
         }
         body = json.dumps(post_body)
         uri = '%s/lb/members' % (self.uri_prefix)
-        resp, body = self.post(uri, headers=self.headers, body=body)
+        resp, body = self.post(uri, body)
         body = json.loads(body)
         return resp, body
 
-    def show_member(self, uuid):
-        uri = '%s/lb/members/%s' % (self.uri_prefix, uuid)
-        resp, body = self.get(uri, self.headers)
-        body = json.loads(body)
-        return resp, body
-
-    def delete_member(self, uuid):
-        uri = '%s/lb/members/%s' % (self.uri_prefix, uuid)
-        resp, body = self.delete(uri, self.headers)
-        return resp, body
-
     def update_member(self, admin_state_up, member_id):
         put_body = {
             "member": {
@@ -543,13 +364,7 @@
         }
         body = json.dumps(put_body)
         uri = '%s/lb/members/%s' % (self.uri_prefix, member_id)
-        resp, body = self.put(uri, body=body, headers=self.headers)
-        body = json.loads(body)
-        return resp, body
-
-    def list_health_monitors(self):
-        uri = '%s/lb/health_monitors' % (self.uri_prefix)
-        resp, body = self.get(uri, self.headers)
+        resp, body = self.put(uri, body)
         body = json.loads(body)
         return resp, body
 
@@ -564,21 +379,10 @@
         }
         body = json.dumps(post_body)
         uri = '%s/lb/health_monitors' % (self.uri_prefix)
-        resp, body = self.post(uri, headers=self.headers, body=body)
+        resp, body = self.post(uri, body)
         body = json.loads(body)
         return resp, body
 
-    def show_health_monitor(self, uuid):
-        uri = '%s/lb/health_monitors/%s' % (self.uri_prefix, uuid)
-        resp, body = self.get(uri, self.headers)
-        body = json.loads(body)
-        return resp, body
-
-    def delete_health_monitor(self, uuid):
-        uri = '%s/lb/health_monitors/%s' % (self.uri_prefix, uuid)
-        resp, body = self.delete(uri, self.headers)
-        return resp, body
-
     def update_health_monitor(self, admin_state_up, uuid):
         put_body = {
             "health_monitor": {
@@ -587,7 +391,7 @@
         }
         body = json.dumps(put_body)
         uri = '%s/lb/health_monitors/%s' % (self.uri_prefix, uuid)
-        resp, body = self.put(uri, body=body, headers=self.headers)
+        resp, body = self.put(uri, body)
         body = json.loads(body)
         return resp, body
 
@@ -601,7 +405,7 @@
         body = json.dumps(post_body)
         uri = '%s/lb/pools/%s/health_monitors' % (self.uri_prefix,
                                                   pool_id)
-        resp, body = self.post(uri, headers=self.headers, body=body)
+        resp, body = self.post(uri, body)
         body = json.loads(body)
         return resp, body
 
@@ -609,28 +413,10 @@
                                               pool_id):
         uri = '%s/lb/pools/%s/health_monitors/%s' % (self.uri_prefix, pool_id,
                                                      health_monitor_id)
-        resp, body = self.delete(uri, headers=self.headers)
+        resp, body = self.delete(uri)
         return resp, body
 
-    def list_extensions(self):
-        uri = '%s/extensions' % (self.uri_prefix)
-        resp, body = self.get(uri, self.headers)
-        body = json.loads(body)
-        return resp, body
-
-    def show_extension_details(self, ext_alias):
-        uri = '%s/extensions/%s' % (self.uri_prefix, ext_alias)
-        resp, body = self.get(uri, headers=self.headers)
-        body = json.loads(body)
-        return resp, body
-
-    def list_vpn_services(self):
-        uri = '%s/vpn/vpnservices' % (self.uri_prefix)
-        resp, body = self.get(uri, self.headers)
-        body = json.loads(body)
-        return resp, body
-
-    def create_vpn_service(self, subnet_id, router_id, **kwargs):
+    def create_vpnservice(self, subnet_id, router_id, **kwargs):
         post_body = {
             "vpnservice": {
                 "subnet_id": subnet_id,
@@ -641,22 +427,11 @@
             post_body['vpnservice'][key] = val
         body = json.dumps(post_body)
         uri = '%s/vpn/vpnservices' % (self.uri_prefix)
-        resp, body = self.post(uri, headers=self.headers, body=body)
+        resp, body = self.post(uri, body)
         body = json.loads(body)
         return resp, body
 
-    def show_vpn_service(self, uuid):
-        uri = '%s/vpn/vpnservices/%s' % (self.uri_prefix, uuid)
-        resp, body = self.get(uri, self.headers)
-        body = json.loads(body)
-        return resp, body
-
-    def delete_vpn_service(self, uuid):
-        uri = '%s/vpn/vpnservices/%s' % (self.uri_prefix, uuid)
-        resp, body = self.delete(uri, self.headers)
-        return resp, body
-
-    def update_vpn_service(self, uuid, description):
+    def update_vpnservice(self, uuid, description):
         put_body = {
             "vpnservice": {
                 "description": description
@@ -664,36 +439,102 @@
         }
         body = json.dumps(put_body)
         uri = '%s/vpn/vpnservices/%s' % (self.uri_prefix, uuid)
-        resp, body = self.put(uri, body=body, headers=self.headers)
+        resp, body = self.put(uri, body)
         body = json.loads(body)
         return resp, body
 
     def list_router_interfaces(self, uuid):
         uri = '%s/ports?device_id=%s' % (self.uri_prefix, uuid)
-        resp, body = self.get(uri, self.headers)
+        resp, body = self.get(uri)
         body = json.loads(body)
         return resp, body
 
-    def list_agents(self):
-        uri = '%s/agents' % self.uri_prefix
-        resp, body = self.get(uri, self.headers)
+    def update_agent(self, agent_id, agent_info):
+        """
+        :param agent_info: Agent update information.
+        E.g {"admin_state_up": True}
+        """
+        uri = '%s/agents/%s' % (self.uri_prefix, agent_id)
+        agent = {"agent": agent_info}
+        body = json.dumps(agent)
+        resp, body = self.put(uri, body)
         body = json.loads(body)
         return resp, body
 
     def list_routers_on_l3_agent(self, agent_id):
         uri = '%s/agents/%s/l3-routers' % (self.uri_prefix, agent_id)
-        resp, body = self.get(uri, self.headers)
+        resp, body = self.get(uri)
         body = json.loads(body)
         return resp, body
 
     def list_l3_agents_hosting_router(self, router_id):
         uri = '%s/routers/%s/l3-agents' % (self.uri_prefix, router_id)
-        resp, body = self.get(uri, self.headers)
+        resp, body = self.get(uri)
         body = json.loads(body)
         return resp, body
 
-    def list_service_providers(self):
-        uri = '%s/service-providers' % self.uri_prefix
-        resp, body = self.get(uri, self.headers)
+    def list_dhcp_agent_hosting_network(self, network_id):
+        uri = '%s/networks/%s/dhcp-agents' % (self.uri_prefix, network_id)
+        resp, body = self.get(uri)
+        body = json.loads(body)
+        return resp, body
+
+    def list_networks_hosted_by_one_dhcp_agent(self, agent_id):
+        uri = '%s/agents/%s/dhcp-networks' % (self.uri_prefix, agent_id)
+        resp, body = self.get(uri)
+        body = json.loads(body)
+        return resp, body
+
+    def remove_network_from_dhcp_agent(self, agent_id, network_id):
+        uri = '%s/agents/%s/dhcp-networks/%s' % (self.uri_prefix, agent_id,
+                                                 network_id)
+        resp, body = self.delete(uri)
+        return resp, body
+
+    def create_ikepolicy(self, name, **kwargs):
+        post_body = {
+            "ikepolicy": {
+                "name": name,
+            }
+        }
+        for key, val in kwargs.items():
+            post_body['ikepolicy'][key] = val
+        body = json.dumps(post_body)
+        uri = '%s/vpn/ikepolicies' % (self.uri_prefix)
+        resp, body = self.post(uri, body)
+        body = json.loads(body)
+        return resp, body
+
+    def update_ikepolicy(self, uuid, **kwargs):
+        put_body = {'ikepolicy': kwargs}
+        body = json.dumps(put_body)
+        uri = '%s/vpn/ikepolicies/%s' % (self.uri_prefix, uuid)
+        resp, body = self.put(uri, body)
+        body = json.loads(body)
+        return resp, body
+
+    def update_extra_routes(self, router_id, nexthop, destination):
+        uri = '%s/routers/%s' % (self.uri_prefix, router_id)
+        put_body = {
+            'router': {
+                'routes': [{'nexthop': nexthop,
+                            "destination": destination}]
+            }
+        }
+        body = json.dumps(put_body)
+        resp, body = self.put(uri, body)
+        body = json.loads(body)
+        return resp, body
+
+    def delete_extra_routes(self, router_id):
+        uri = '%s/routers/%s' % (self.uri_prefix, router_id)
+        null_routes = None
+        put_body = {
+            'router': {
+                'routes': null_routes
+            }
+        }
+        body = json.dumps(put_body)
+        resp, body = self.put(uri, body)
         body = json.loads(body)
         return resp, body
diff --git a/tempest/services/network/network_client_base.py b/tempest/services/network/network_client_base.py
new file mode 100644
index 0000000..b48dd34
--- /dev/null
+++ b/tempest/services/network/network_client_base.py
@@ -0,0 +1,136 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import urllib
+
+# the folliwing map is used to construct proper URI
+# for the given neutron resource
+service_resource_prefix_map = {
+    'networks': '',
+    'subnets': '',
+    'ports': '',
+    'pools': 'lb',
+    'vips': 'lb',
+    'health_monitors': 'lb',
+    'members': 'lb',
+    'vpnservices': 'vpn',
+    'ikepolicies': 'vpn'
+}
+
+# The following list represents resource names that do not require
+# changing underscore to a hyphen
+hyphen_exceptions = ["health_monitors"]
+
+# map from resource name to a plural name
+# needed only for those which can't be constructed as name + 's'
+resource_plural_map = {
+    'security_groups': 'security_groups',
+    'security_group_rules': 'security_group_rules',
+    'ikepolicy': 'ikepolicies',
+    'floating_ip': 'floatingips',
+    'quotas': 'quotas'
+}
+
+
+class NetworkClientBase(object):
+    def __init__(self, config, username, password,
+                 auth_url, tenant_name=None):
+        self.rest_client = self.get_rest_client(
+            config, username, password, auth_url, tenant_name)
+        self.rest_client.service = self.rest_client.config.network.catalog_type
+        self.version = '2.0'
+        self.uri_prefix = "v%s" % (self.version)
+
+    def get_rest_client(self, config, username, password,
+                        auth_url, tenant_name):
+        raise NotImplementedError
+
+    def post(self, uri, body, headers=None):
+        headers = headers or self.rest_client.headers
+        return self.rest_client.post(uri, body, headers)
+
+    def put(self, uri, body, headers=None):
+        headers = headers or self.rest_client.headers
+        return self.rest_client.put(uri, body, headers)
+
+    def get(self, uri, headers=None):
+        headers = headers or self.rest_client.headers
+        return self.rest_client.get(uri, headers)
+
+    def delete(self, uri, headers=None):
+        headers = headers or self.rest_client.headers
+        return self.rest_client.delete(uri, headers)
+
+    def deserialize_list(self, body):
+        raise NotImplementedError
+
+    def deserialize_single(self, body):
+        raise NotImplementedError
+
+    def get_uri(self, plural_name):
+        # get service prefix from resource name
+        service_prefix = service_resource_prefix_map.get(
+            plural_name)
+        if plural_name not in hyphen_exceptions:
+            plural_name = plural_name.replace("_", "-")
+        if service_prefix:
+            uri = '%s/%s/%s' % (self.uri_prefix, service_prefix,
+                                plural_name)
+        else:
+            uri = '%s/%s' % (self.uri_prefix, plural_name)
+        return uri
+
+    def pluralize(self, resource_name):
+        # get plural from map or just add 's'
+        return resource_plural_map.get(resource_name, resource_name + 's')
+
+    def _lister(self, plural_name):
+        def _list(**filters):
+            uri = self.get_uri(plural_name)
+            if filters:
+                uri += '?' + urllib.urlencode(filters)
+            resp, body = self.get(uri)
+            result = {plural_name: self.deserialize_list(body)}
+            return resp, result
+
+        return _list
+
+    def _deleter(self, resource_name):
+        def _delete(resource_id):
+            plural = self.pluralize(resource_name)
+            uri = '%s/%s' % (self.get_uri(plural), resource_id)
+            return self.delete(uri)
+
+        return _delete
+
+    def _shower(self, resource_name):
+        def _show(resource_id):
+            plural = self.pluralize(resource_name)
+            uri = '%s/%s' % (self.get_uri(plural), resource_id)
+            resp, body = self.get(uri)
+            body = self.deserialize_single(body)
+            return resp, body
+
+        return _show
+
+    def __getattr__(self, name):
+        method_prefixes = ["list_", "delete_", "show_"]
+        method_functors = [self._lister,
+                           self._deleter,
+                           self._shower]
+        for index, prefix in enumerate(method_prefixes):
+            prefix_len = len(prefix)
+            if name[:prefix_len] == prefix:
+                return method_functors[index](name[prefix_len:])
+        raise AttributeError(name)
diff --git a/tempest/services/network/xml/network_client.py b/tempest/services/network/xml/network_client.py
old mode 100755
new mode 100644
index 5af2dfb..a999e31
--- a/tempest/services/network/xml/network_client.py
+++ b/tempest/services/network/xml/network_client.py
@@ -20,30 +20,28 @@
 from tempest.services.compute.xml.common import Document
 from tempest.services.compute.xml.common import Element
 from tempest.services.compute.xml.common import xml_to_json
+from tempest.services.network import network_client_base as client_base
 
 
-class NetworkClientXML(RestClientXML):
+class NetworkClientXML(client_base.NetworkClientBase):
 
-    def __init__(self, config, username, password, auth_url, tenant_name=None):
-        super(NetworkClientXML, self).__init__(config, username, password,
-                                               auth_url, tenant_name)
-        self.service = self.config.network.catalog_type
-        self.version = '2.0'
-        self.uri_prefix = "v%s" % (self.version)
+    def get_rest_client(self, config, username, password,
+                        auth_url, tenant_name=None):
+        return RestClientXML(config, username, password,
+                             auth_url, tenant_name)
 
-    def list_networks(self):
-        uri = '%s/networks' % (self.uri_prefix)
-        resp, body = self.get(uri, self.headers)
-        networks = self._parse_array(etree.fromstring(body))
-        networks = {"networks": networks}
-        return resp, networks
+    def deserialize_list(self, body):
+        return self._parse_array(etree.fromstring(body))
+
+    def deserialize_single(self, body):
+        return _root_tag_fetcher_and_xml_to_json_parse(body)
 
     def create_network(self, name):
         uri = '%s/networks' % (self.uri_prefix)
         post_body = Element("network")
         p2 = Element("name", name)
         post_body.append(p2)
-        resp, body = self.post(uri, str(Document(post_body)), self.headers)
+        resp, body = self.post(uri, str(Document(post_body)))
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
@@ -55,21 +53,11 @@
                 p2 = Element("name", names[i])
                 p1.append(p2)
                 post_body.append(p1)
-        resp, body = self.post(uri, str(Document(post_body)), self.headers)
+        resp, body = self.post(uri, str(Document(post_body)))
         networks = self._parse_array(etree.fromstring(body))
         networks = {"networks": networks}
         return resp, networks
 
-    def delete_network(self, uuid):
-        uri = '%s/networks/%s' % (self.uri_prefix, str(uuid))
-        return self.delete(uri, self.headers)
-
-    def show_network(self, uuid):
-        uri = '%s/networks/%s' % (self.uri_prefix, str(uuid))
-        resp, body = self.get(uri, self.headers)
-        body = _root_tag_fetcher_and_xml_to_json_parse(body)
-        return resp, body
-
     def create_subnet(self, net_uuid, cidr):
         uri = '%s/subnets' % (self.uri_prefix)
         subnet = Element("subnet")
@@ -79,24 +67,7 @@
         subnet.append(p2)
         subnet.append(p3)
         subnet.append(p4)
-        resp, body = self.post(uri, str(Document(subnet)), self.headers)
-        body = _root_tag_fetcher_and_xml_to_json_parse(body)
-        return resp, body
-
-    def delete_subnet(self, subnet_id):
-        uri = '%s/subnets/%s' % (self.uri_prefix, str(subnet_id))
-        return self.delete(uri, self.headers)
-
-    def list_subnets(self):
-        uri = '%s/subnets' % (self.uri_prefix)
-        resp, body = self.get(uri, self.headers)
-        subnets = self._parse_array(etree.fromstring(body))
-        subnets = {"subnets": subnets}
-        return resp, subnets
-
-    def show_subnet(self, uuid):
-        uri = '%s/subnets/%s' % (self.uri_prefix, str(uuid))
-        resp, body = self.get(uri, self.headers)
+        resp, body = self.post(uri, str(Document(subnet)))
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
@@ -108,39 +79,22 @@
         for key, val in kwargs.items():
             key = Element(key, val)
             port.append(key)
-        resp, body = self.post(uri, str(Document(port)), self.headers)
+        resp, body = self.post(uri, str(Document(port)))
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
-    def delete_port(self, port_id):
-        uri = '%s/ports/%s' % (self.uri_prefix, str(port_id))
-        return self.delete(uri, self.headers)
-
     def _parse_array(self, node):
         array = []
         for child in node.getchildren():
             array.append(xml_to_json(child))
         return array
 
-    def list_ports(self):
-        url = '%s/ports' % (self.uri_prefix)
-        resp, body = self.get(url, self.headers)
-        ports = self._parse_array(etree.fromstring(body))
-        ports = {"ports": ports}
-        return resp, ports
-
-    def show_port(self, port_id):
-        uri = '%s/ports/%s' % (self.uri_prefix, str(port_id))
-        resp, body = self.get(uri, self.headers)
-        body = _root_tag_fetcher_and_xml_to_json_parse(body)
-        return resp, body
-
     def update_port(self, port_id, name):
         uri = '%s/ports/%s' % (self.uri_prefix, str(port_id))
         port = Element("port")
         p2 = Element("name", name)
         port.append(p2)
-        resp, body = self.put(uri, str(Document(port)), self.headers)
+        resp, body = self.put(uri, str(Document(port)))
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
@@ -149,7 +103,7 @@
         subnet = Element("subnet")
         p2 = Element("name", name)
         subnet.append(p2)
-        resp, body = self.put(uri, str(Document(subnet)), self.headers)
+        resp, body = self.put(uri, str(Document(subnet)))
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
@@ -158,7 +112,7 @@
         network = Element("network")
         p2 = Element("name", name)
         network.append(p2)
-        resp, body = self.put(uri, str(Document(network)), self.headers)
+        resp, body = self.put(uri, str(Document(network)))
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
@@ -167,34 +121,10 @@
         post_body = Element("security_group")
         p2 = Element("name", name)
         post_body.append(p2)
-        resp, body = self.post(uri, str(Document(post_body)), self.headers)
+        resp, body = self.post(uri, str(Document(post_body)))
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
-    def list_security_groups(self):
-        url = '%s/security-groups' % (self.uri_prefix)
-        resp, body = self.get(url, self.headers)
-        secgroups = self._parse_array(etree.fromstring(body))
-        secgroups = {"security_groups": secgroups}
-        return resp, secgroups
-
-    def delete_security_group(self, secgroup_id):
-        uri = '%s/security-groups/%s' % (self.uri_prefix, str(secgroup_id))
-        return self.delete(uri, self.headers)
-
-    def show_security_group(self, secgroup_id):
-        uri = '%s/security-groups/%s' % (self.uri_prefix, str(secgroup_id))
-        resp, body = self.get(uri, self.headers)
-        body = _root_tag_fetcher_and_xml_to_json_parse(body)
-        return resp, body
-
-    def list_security_group_rules(self):
-        url = '%s/security-group-rules' % (self.uri_prefix)
-        resp, body = self.get(url, self.headers)
-        rules = self._parse_array(etree.fromstring(body))
-        rules = {"security_group_rules": rules}
-        return resp, rules
-
     def create_security_group_rule(self, secgroup_id,
                                    direction='ingress', **kwargs):
         uri = '%s/security-group-rules' % (self.uri_prefix)
@@ -206,17 +136,7 @@
         for key, val in kwargs.items():
             key = Element(key, val)
             rule.append(key)
-        resp, body = self.post(uri, str(Document(rule)), self.headers)
-        body = _root_tag_fetcher_and_xml_to_json_parse(body)
-        return resp, body
-
-    def delete_security_group_rule(self, rule_id):
-        uri = '%s/security-group-rules/%s' % (self.uri_prefix, str(rule_id))
-        return self.delete(uri, self.headers)
-
-    def show_security_group_rule(self, rule_id):
-        uri = '%s/security-group-rules/%s' % (self.uri_prefix, str(rule_id))
-        resp, body = self.get(uri, self.headers)
+        resp, body = self.post(uri, str(Document(rule)))
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
@@ -230,7 +150,7 @@
                 p2 = Element(k, kv)
                 p1.append(p2)
             post_body.append(p1)
-        resp, body = self.post(uri, str(Document(post_body)), self.headers)
+        resp, body = self.post(uri, str(Document(post_body)))
         subnets = self._parse_array(etree.fromstring(body))
         subnets = {"subnets": subnets}
         return resp, subnets
@@ -245,18 +165,11 @@
                 p2 = Element(k, kv)
                 p1.append(p2)
             post_body.append(p1)
-        resp, body = self.post(uri, str(Document(post_body)), self.headers)
+        resp, body = self.post(uri, str(Document(post_body)))
         ports = self._parse_array(etree.fromstring(body))
         ports = {"ports": ports}
         return resp, ports
 
-    def list_vips(self):
-        url = '%s/lb/vips' % (self.uri_prefix)
-        resp, body = self.get(url, self.headers)
-        vips = self._parse_array(etree.fromstring(body))
-        vips = {"vips": vips}
-        return resp, vips
-
     def create_vip(self, name, protocol, protocol_port, subnet_id, pool_id):
         uri = '%s/lb/vips' % (self.uri_prefix)
         post_body = Element("vip")
@@ -270,17 +183,7 @@
         post_body.append(p3)
         post_body.append(p4)
         post_body.append(p5)
-        resp, body = self.post(uri, str(Document(post_body)), self.headers)
-        body = _root_tag_fetcher_and_xml_to_json_parse(body)
-        return resp, body
-
-    def delete_vip(self, vip_id):
-        uri = '%s/lb/vips/%s' % (self.uri_prefix, str(vip_id))
-        return self.delete(uri, self.headers)
-
-    def show_vip(self, vip_id):
-        uri = '%s/lb/vips/%s' % (self.uri_prefix, str(vip_id))
-        resp, body = self.get(uri, self.headers)
+        resp, body = self.post(uri, str(Document(post_body)))
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
@@ -289,17 +192,10 @@
         put_body = Element("vip")
         p2 = Element("name", new_name)
         put_body.append(p2)
-        resp, body = self.put(uri, str(Document(put_body)), self.headers)
+        resp, body = self.put(uri, str(Document(put_body)))
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
-    def list_pools(self):
-        url = '%s/lb/pools' % (self.uri_prefix)
-        resp, body = self.get(url, self.headers)
-        pools = self._parse_array(etree.fromstring(body))
-        pools = {"pools": pools}
-        return resp, pools
-
     def create_pool(self, name, lb_method, protocol, subnet_id):
         uri = '%s/lb/pools' % (self.uri_prefix)
         post_body = Element("pool")
@@ -309,17 +205,7 @@
         post_body.append(p1)
         post_body.append(p2)
         post_body.append(p3)
-        resp, body = self.post(uri, str(Document(post_body)), self.headers)
-        body = _root_tag_fetcher_and_xml_to_json_parse(body)
-        return resp, body
-
-    def delete_pool(self, pool_id):
-        uri = '%s/lb/pools/%s' % (self.uri_prefix, str(pool_id))
-        return self.delete(uri, self.headers)
-
-    def show_pool(self, pool_id):
-        uri = '%s/lb/pools/%s' % (self.uri_prefix, str(pool_id))
-        resp, body = self.get(uri, self.headers)
+        resp, body = self.post(uri, str(Document(post_body)))
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
@@ -328,17 +214,10 @@
         put_body = Element("pool")
         p2 = Element("name", new_name)
         put_body.append(p2)
-        resp, body = self.put(uri, str(Document(put_body)), self.headers)
+        resp, body = self.put(uri, str(Document(put_body)))
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
-    def list_members(self):
-        url = '%s/lb/members' % (self.uri_prefix)
-        resp, body = self.get(url, self.headers)
-        members = self._parse_array(etree.fromstring(body))
-        members = {"members": members}
-        return resp, members
-
     def create_member(self, address, protocol_port, pool_id):
         uri = '%s/lb/members' % (self.uri_prefix)
         post_body = Element("member")
@@ -348,17 +227,7 @@
         post_body.append(p1)
         post_body.append(p2)
         post_body.append(p3)
-        resp, body = self.post(uri, str(Document(post_body)), self.headers)
-        body = _root_tag_fetcher_and_xml_to_json_parse(body)
-        return resp, body
-
-    def delete_member(self, member_id):
-        uri = '%s/lb/members/%s' % (self.uri_prefix, str(member_id))
-        return self.delete(uri, self.headers)
-
-    def show_member(self, member_id):
-        uri = '%s/lb/members/%s' % (self.uri_prefix, str(member_id))
-        resp, body = self.get(uri, self.headers)
+        resp, body = self.post(uri, str(Document(post_body)))
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
@@ -367,17 +236,10 @@
         put_body = Element("member")
         p2 = Element("admin_state_up", admin_state_up)
         put_body.append(p2)
-        resp, body = self.put(uri, str(Document(put_body)), self.headers)
+        resp, body = self.put(uri, str(Document(put_body)))
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
-    def list_health_monitors(self):
-        uri = '%s/lb/health_monitors' % (self.uri_prefix)
-        resp, body = self.get(uri, self.headers)
-        body = self._parse_array(etree.fromstring(body))
-        body = {"health_monitors": body}
-        return resp, body
-
     def create_health_monitor(self, delay, max_retries, Type, timeout):
         uri = '%s/lb/health_monitors' % (self.uri_prefix)
         post_body = Element("health_monitor")
@@ -389,17 +251,7 @@
         post_body.append(p2)
         post_body.append(p3)
         post_body.append(p4)
-        resp, body = self.post(uri, str(Document(post_body)), self.headers)
-        body = _root_tag_fetcher_and_xml_to_json_parse(body)
-        return resp, body
-
-    def delete_health_monitor(self, uuid):
-        uri = '%s/lb/health_monitors/%s' % (self.uri_prefix, str(uuid))
-        return self.delete(uri, self.headers)
-
-    def show_health_monitor(self, uuid):
-        uri = '%s/lb/health_monitors/%s' % (self.uri_prefix, str(uuid))
-        resp, body = self.get(uri, self.headers)
+        resp, body = self.post(uri, str(Document(post_body)))
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
@@ -408,7 +260,7 @@
         put_body = Element("health_monitor")
         p2 = Element("admin_state_up", admin_state_up)
         put_body.append(p2)
-        resp, body = self.put(uri, str(Document(put_body)), self.headers)
+        resp, body = self.put(uri, str(Document(put_body)))
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
@@ -419,7 +271,7 @@
         post_body = Element("health_monitor")
         p1 = Element("id", health_monitor_id,)
         post_body.append(p1)
-        resp, body = self.post(uri, str(Document(post_body)), self.headers)
+        resp, body = self.post(uri, str(Document(post_body)))
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
@@ -427,18 +279,11 @@
                                               pool_id):
         uri = '%s/lb/pools/%s/health_monitors/%s' % (self.uri_prefix, pool_id,
                                                      health_monitor_id)
-        return self.delete(uri, self.headers)
-
-    def list_extensions(self):
-        url = '%s/extensions' % (self.uri_prefix)
-        resp, body = self.get(url, self.headers)
-        extensions = self._parse_array(etree.fromstring(body))
-        extensions = {"extensions": extensions}
-        return resp, extensions
+        return self.delete(uri)
 
     def show_extension_details(self, ext_alias):
         uri = '%s/extensions/%s' % (self.uri_prefix, str(ext_alias))
-        resp, body = self.get(uri, self.headers)
+        resp, body = self.get(uri)
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
@@ -447,18 +292,7 @@
         router = Element("router")
         router.append(Element("name", name))
         deep_dict_to_xml(router, kwargs)
-        resp, body = self.post(uri, str(Document(router)), self.headers)
-        body = _root_tag_fetcher_and_xml_to_json_parse(body)
-        return resp, body
-
-    def delete_router(self, router_id):
-        uri = '%s/routers/%s' % (self.uri_prefix, router_id)
-        resp, body = self.delete(uri, self.headers)
-        return resp, body
-
-    def show_router(self, router_id):
-        uri = '%s/routers/%s' % (self.uri_prefix, router_id)
-        resp, body = self.get(uri, self.headers)
+        resp, body = self.post(uri, str(Document(router)))
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
@@ -467,7 +301,7 @@
         router = Element("router")
         for element, content in kwargs.iteritems():
             router.append(Element(element, content))
-        resp, body = self.put(uri, str(Document(router)), self.headers)
+        resp, body = self.put(uri, str(Document(router)))
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
@@ -475,7 +309,7 @@
         uri = '%s/routers/%s/add_router_interface' % (self.uri_prefix,
               router_id)
         subnet = Element("subnet_id", subnet_id)
-        resp, body = self.put(uri, str(Document(subnet)), self.headers)
+        resp, body = self.put(uri, str(Document(subnet)))
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
@@ -483,7 +317,7 @@
         uri = '%s/routers/%s/add_router_interface' % (self.uri_prefix,
               router_id)
         port = Element("port_id", port_id)
-        resp, body = self.put(uri, str(Document(port)), self.headers)
+        resp, body = self.put(uri, str(Document(port)))
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
@@ -491,7 +325,7 @@
         uri = '%s/routers/%s/remove_router_interface' % (self.uri_prefix,
               router_id)
         subnet = Element("subnet_id", subnet_id)
-        resp, body = self.put(uri, str(Document(subnet)), self.headers)
+        resp, body = self.put(uri, str(Document(subnet)))
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
@@ -499,7 +333,7 @@
         uri = '%s/routers/%s/remove_router_interface' % (self.uri_prefix,
               router_id)
         port = Element("port_id", port_id)
-        resp, body = self.put(uri, str(Document(port)), self.headers)
+        resp, body = self.put(uri, str(Document(port)))
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
@@ -509,28 +343,10 @@
         floatingip.append(Element("floating_network_id", ext_network_id))
         for element, content in kwargs.iteritems():
             floatingip.append(Element(element, content))
-        resp, body = self.post(uri, str(Document(floatingip)), self.headers)
+        resp, body = self.post(uri, str(Document(floatingip)))
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
-    def show_floating_ip(self, floating_ip_id):
-        uri = '%s/floatingips/%s' % (self.uri_prefix, floating_ip_id)
-        resp, body = self.get(uri, self.headers)
-        body = _root_tag_fetcher_and_xml_to_json_parse(body)
-        return resp, body
-
-    def list_floating_ips(self):
-        uri = '%s/floatingips' % (self.uri_prefix)
-        resp, body = self.get(uri, self.headers)
-        floatingips = self._parse_array(etree.fromstring(body))
-        floatingips = {"floatingips": floatingips}
-        return resp, floatingips
-
-    def delete_floating_ip(self, floating_ip_id):
-        uri = '%s/floatingips/%s' % (self.uri_prefix, floating_ip_id)
-        resp, body = self.delete(uri, self.headers)
-        return resp, body
-
     def update_floating_ip(self, floating_ip_id, **kwargs):
         uri = '%s/floatingips/%s' % (self.uri_prefix, floating_ip_id)
         floatingip = Element('floatingip')
@@ -543,41 +359,57 @@
                 floatingip.append(xml_elem)
             else:
                 floatingip.append(Element(element, content))
-        resp, body = self.put(uri, str(Document(floatingip)), self.headers)
+        resp, body = self.put(uri, str(Document(floatingip)))
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
     def list_router_interfaces(self, uuid):
         uri = '%s/ports?device_id=%s' % (self.uri_prefix, uuid)
-        resp, body = self.get(uri, self.headers)
+        resp, body = self.get(uri)
         ports = self._parse_array(etree.fromstring(body))
         ports = {"ports": ports}
         return resp, ports
 
-    def list_agents(self):
-        uri = '%s/agents' % self.uri_prefix
-        resp, body = self.get(uri, self.headers)
-        agents = self._parse_array(etree.fromstring(body))
-        agents = {'agents': agents}
-        return resp, agents
+    def update_agent(self, agent_id, agent_info):
+        uri = '%s/agents/%s' % (self.uri_prefix, agent_id)
+        agent = Element('agent')
+        for (key, value) in agent_info.items():
+            p = Element(key, value)
+            agent.append(p)
+        resp, body = self.put(uri, str(Document(agent)))
+        body = _root_tag_fetcher_and_xml_to_json_parse(body)
+        return resp, body
 
     def list_routers_on_l3_agent(self, agent_id):
         uri = '%s/agents/%s/l3-routers' % (self.uri_prefix, agent_id)
-        resp, body = self.get(uri, self.headers)
+        resp, body = self.get(uri)
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
     def list_l3_agents_hosting_router(self, router_id):
         uri = '%s/routers/%s/l3-agents' % (self.uri_prefix, router_id)
-        resp, body = self.get(uri, self.headers)
+        resp, body = self.get(uri)
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
-    def list_service_providers(self):
-        uri = '%s/service-providers' % self.uri_prefix
-        resp, body = self.get(uri, self.headers)
-        providers = self._parse_array(etree.fromstring(body))
-        body = {'service_providers': providers}
+    def list_dhcp_agent_hosting_network(self, network_id):
+        uri = '%s/networks/%s/dhcp-agents' % (self.uri_prefix, network_id)
+        resp, body = self.get(uri)
+        agents = self._parse_array(etree.fromstring(body))
+        body = {'agents': agents}
+        return resp, body
+
+    def list_networks_hosted_by_one_dhcp_agent(self, agent_id):
+        uri = '%s/agents/%s/dhcp-networks' % (self.uri_prefix, agent_id)
+        resp, body = self.get(uri)
+        networks = self._parse_array(etree.fromstring(body))
+        body = {'networks': networks}
+        return resp, body
+
+    def remove_network_from_dhcp_agent(self, agent_id, network_id):
+        uri = '%s/agents/%s/dhcp-networks/%s' % (self.uri_prefix, agent_id,
+                                                 network_id)
+        resp, body = self.delete(uri)
         return resp, body
 
 
diff --git a/tempest/services/object_storage/object_client.py b/tempest/services/object_storage/object_client.py
index 2fee042..9e0adff 100644
--- a/tempest/services/object_storage/object_client.py
+++ b/tempest/services/object_storage/object_client.py
@@ -15,6 +15,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import urllib
+
 from tempest.common import http
 from tempest.common.rest_client import RestClient
 from tempest import exceptions
@@ -27,13 +29,16 @@
 
         self.service = self.config.object_storage.catalog_type
 
-    def create_object(self, container, object_name, data):
+    def create_object(self, container, object_name, data, params=None):
         """Create storage object."""
 
         headers = dict(self.headers)
         if not data:
             headers['content-length'] = '0'
         url = "%s/%s" % (str(container), str(object_name))
+        if params:
+            url += '?%s' % urllib.urlencode(params)
+
         resp, body = self.put(url, data, headers)
         return resp, body
 
@@ -41,9 +46,11 @@
         """Upload data to replace current storage object."""
         return self.create_object(container, object_name, data)
 
-    def delete_object(self, container, object_name):
+    def delete_object(self, container, object_name, params=None):
         """Delete storage object."""
         url = "%s/%s" % (str(container), str(object_name))
+        if params:
+            url += '?%s' % urllib.urlencode(params)
         resp, body = self.delete(url)
         return resp, body
 
diff --git a/tempest/services/volume/json/admin/volume_hosts_client.py b/tempest/services/volume/json/admin/volume_hosts_client.py
new file mode 100644
index 0000000..fc28ada
--- /dev/null
+++ b/tempest/services/volume/json/admin/volume_hosts_client.py
@@ -0,0 +1,46 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 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.
+
+import json
+import urllib
+
+from tempest.common.rest_client import RestClient
+
+
+class VolumeHostsClientJSON(RestClient):
+    """
+    Client class to send CRUD Volume Hosts API requests to a Cinder endpoint
+    """
+
+    def __init__(self, config, username, password, auth_url, tenant_name=None):
+        super(VolumeHostsClientJSON, self).__init__(config, username, password,
+                                                    auth_url, tenant_name)
+
+        self.service = self.config.volume.catalog_type
+        self.build_interval = self.config.volume.build_interval
+        self.build_timeout = self.config.volume.build_timeout
+
+    def list_hosts(self, params=None):
+        """Lists all hosts."""
+
+        url = 'os-hosts'
+        if params:
+            url += '?%s' % urllib.urlencode(params)
+
+        resp, body = self.get(url)
+        body = json.loads(body)
+        return resp, body['hosts']
diff --git a/tempest/services/volume/json/snapshots_client.py b/tempest/services/volume/json/snapshots_client.py
index 5d980eb..9435122 100644
--- a/tempest/services/volume/json/snapshots_client.py
+++ b/tempest/services/volume/json/snapshots_client.py
@@ -44,7 +44,7 @@
         body = json.loads(body)
         return resp, body['snapshots']
 
-    def list_snapshot_with_detail(self, params=None):
+    def list_snapshots_with_detail(self, params=None):
         """List the details of all snapshots."""
         url = 'snapshots/detail'
         if params:
diff --git a/tempest/services/volume/json/volumes_client.py b/tempest/services/volume/json/volumes_client.py
index b4a1a68..967dc09 100644
--- a/tempest/services/volume/json/volumes_client.py
+++ b/tempest/services/volume/json/volumes_client.py
@@ -256,3 +256,10 @@
         url = 'volumes/%s/action' % (volume_id)
         resp, body = self.post(url, post_body, self.headers)
         return resp, body
+
+    def force_delete_volume(self, volume_id):
+        """Force Delete Volume."""
+        post_body = json.dumps({'os-force_delete': {}})
+        resp, body = self.post('volumes/%s/action' % volume_id, post_body,
+                               self.headers)
+        return resp, body
diff --git a/tempest/services/volume/xml/admin/volume_hosts_client.py b/tempest/services/volume/xml/admin/volume_hosts_client.py
new file mode 100644
index 0000000..59ce933
--- /dev/null
+++ b/tempest/services/volume/xml/admin/volume_hosts_client.py
@@ -0,0 +1,72 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+#
+# Copyright 2013 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.
+
+import urllib
+
+from lxml import etree
+
+from tempest.common.rest_client import RestClientXML
+from tempest.services.compute.xml.common import xml_to_json
+
+
+class VolumeHostsClientXML(RestClientXML):
+    """
+    Client class to send CRUD Volume Hosts API requests to a Cinder endpoint
+    """
+
+    def __init__(self, config, username, password, auth_url, tenant_name=None):
+        super(VolumeHostsClientXML, self).__init__(config, username, password,
+                                                   auth_url, tenant_name)
+        self.service = self.config.volume.catalog_type
+        self.build_interval = self.config.compute.build_interval
+        self.build_timeout = self.config.compute.build_timeout
+
+    def _parse_array(self, node):
+        """
+        This method is to parse the "list" response body
+        Eg:
+
+        <?xml version='1.0' encoding='UTF-8'?>
+        <hosts>
+        <host service-status="available" service="cinder-scheduler"/>
+        <host service-status="available" service="cinder-volume"/>
+        </hosts>
+
+        This method will append the details of specified tag,
+        here it is "host"
+        Return value would be list of hosts as below
+
+        [{'service-status': 'available', 'service': 'cinder-scheduler'},
+         {'service-status': 'available', 'service': 'cinder-volume'}]
+        """
+        array = []
+        for child in node.getchildren():
+            tag_list = child.tag.split('}', 1)
+            if tag_list[0] == "host":
+                array.append(xml_to_json(child))
+        return array
+
+    def list_hosts(self, params=None):
+        """List all the hosts."""
+        url = 'os-hosts'
+
+        if params:
+            url += '?%s' % urllib.urlencode(params)
+
+        resp, body = self.get(url, self.headers)
+        body = self._parse_array(etree.fromstring(body))
+        return resp, body
diff --git a/tempest/services/volume/xml/volumes_client.py b/tempest/services/volume/xml/volumes_client.py
index 21254aa..1fc63e9 100644
--- a/tempest/services/volume/xml/volumes_client.py
+++ b/tempest/services/volume/xml/volumes_client.py
@@ -347,3 +347,12 @@
         if body:
             body = xml_to_json(etree.fromstring(body))
         return resp, body
+
+    def force_delete_volume(self, volume_id):
+        """Force Delete Volume."""
+        post_body = Element("os-force_delete")
+        url = 'volumes/%s/action' % str(volume_id)
+        resp, body = self.post(url, str(Document(post_body)), self.headers)
+        if body:
+            body = xml_to_json(etree.fromstring(body))
+        return resp, body
diff --git a/tempest/stress/run_stress.py b/tempest/stress/run_stress.py
index e5cc281..067b994 100755
--- a/tempest/stress/run_stress.py
+++ b/tempest/stress/run_stress.py
@@ -24,6 +24,7 @@
 from unittest import loader
 
 from tempest.openstack.common import log as logging
+from tempest.stress import driver
 
 LOG = logging.getLogger(__name__)
 
@@ -68,8 +69,6 @@
 
 
 def main(ns):
-    # NOTE(mkoderer): moved import to make "-h" possible without OpenStack
-    from tempest.stress import driver
     result = 0
     if not ns.all:
         tests = json.load(open(ns.tests, 'r'))
diff --git a/tempest/test.py b/tempest/test.py
index 6ae7925..ceb2c80 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -123,6 +123,42 @@
     return decorator
 
 
+def requires_ext(*args, **kwargs):
+    """A decorator to skip tests if an extension is not enabled
+
+    @param extension
+    @param service
+    """
+    def decorator(func):
+        @functools.wraps(func)
+        def wrapper(*func_args, **func_kwargs):
+            if not is_extension_enabled(kwargs['extension'],
+                                        kwargs['service']):
+                msg = "Skipped because %s extension: %s is not enabled" % (
+                    kwargs['service'], kwargs['extension'])
+                raise testtools.TestCase.skipException(msg)
+            return func(*func_args, **func_kwargs)
+        return wrapper
+    return decorator
+
+
+def is_extension_enabled(extension_name, service):
+    """A function that will check the list of enabled extensions from config
+
+    """
+    configs = config.TempestConfig()
+    config_dict = {
+        'compute': configs.compute_feature_enabled.api_extensions,
+        'compute_v3': configs.compute_feature_enabled.api_v3_extensions,
+        'volume': configs.volume_feature_enabled.api_extensions,
+        'network': configs.network_feature_enabled.api_extensions,
+    }
+    if config_dict[service][0] == 'all':
+        return True
+    if extension_name in config_dict[service]:
+        return True
+    return False
+
 # there is a mis-match between nose and testtools for older pythons.
 # testtools will set skipException to be either
 # unittest.case.SkipTest, unittest2.case.SkipTest or an internal skip
diff --git a/tempest/tests/stress/__init__.py b/tempest/tests/stress/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tempest/tests/stress/__init__.py
diff --git a/tempest/tests/stress/test_stress.py b/tempest/tests/stress/test_stress.py
new file mode 100644
index 0000000..4d7de9d
--- /dev/null
+++ b/tempest/tests/stress/test_stress.py
@@ -0,0 +1,57 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 Deutsche Telekom AG
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import shlex
+import subprocess
+
+import tempest.cli as cli
+from tempest.openstack.common import log as logging
+import tempest.test
+
+LOG = logging.getLogger(__name__)
+
+
+class StressFrameworkTest(tempest.test.BaseTestCase):
+    """Basic test for the stress test framework.
+    """
+
+    def _cmd(self, cmd, param):
+        """Executes specified command."""
+        cmd = ' '.join([cmd, param])
+        LOG.info("running: '%s'" % cmd)
+        cmd_str = cmd
+        cmd = shlex.split(cmd)
+        result = ''
+        result_err = ''
+        try:
+            stdout = subprocess.PIPE
+            stderr = subprocess.PIPE
+            proc = subprocess.Popen(
+                cmd, stdout=stdout, stderr=stderr)
+            result, result_err = proc.communicate()
+            if proc.returncode != 0:
+                LOG.debug('error of %s:\n%s' % (cmd_str, result_err))
+                raise cli.CommandFailed(proc.returncode,
+                                        cmd,
+                                        result)
+        finally:
+            LOG.debug('output of %s:\n%s' % (cmd_str, result))
+        return proc.returncode
+
+    def test_help_function(self):
+        result = self._cmd("python", "-m tempest.stress.run_stress -h")
+        self.assertEqual(0, result)
diff --git a/tempest/tests/stress/test_stressaction.py b/tempest/tests/stress/test_stressaction.py
new file mode 100644
index 0000000..3d2901e
--- /dev/null
+++ b/tempest/tests/stress/test_stressaction.py
@@ -0,0 +1,65 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 Deutsche Telekom AG
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import tempest.stress.stressaction as stressaction
+import tempest.test
+
+
+class FakeStressAction(stressaction.StressAction):
+    def __init__(self, manager, max_runs=None, stop_on_error=False):
+        super(self.__class__, self).__init__(manager, max_runs, stop_on_error)
+        self._run_called = False
+
+    def run(self):
+        self._run_called = True
+
+    @property
+    def run_called(self):
+        return self._run_called
+
+
+class FakeStressActionFailing(stressaction.StressAction):
+    def run(self):
+        raise Exception('FakeStressActionFailing raise exception')
+
+
+class TestStressAction(tempest.test.BaseTestCase):
+    def _bulid_stats_dict(self, runs=0, fails=0):
+        return {'runs': runs, 'fails': fails}
+
+    def testStressTestRun(self):
+        stressAction = FakeStressAction(manager=None, max_runs=1)
+        stats = self._bulid_stats_dict()
+        stressAction.execute(stats)
+        self.assertTrue(stressAction.run_called)
+        self.assertEqual(stats['runs'], 1)
+        self.assertEqual(stats['fails'], 0)
+
+    def testStressMaxTestRuns(self):
+        stressAction = FakeStressAction(manager=None, max_runs=500)
+        stats = self._bulid_stats_dict(runs=499)
+        stressAction.execute(stats)
+        self.assertTrue(stressAction.run_called)
+        self.assertEqual(stats['runs'], 500)
+        self.assertEqual(stats['fails'], 0)
+
+    def testStressTestRunWithException(self):
+        stressAction = FakeStressActionFailing(manager=None, max_runs=1)
+        stats = self._bulid_stats_dict()
+        stressAction.execute(stats)
+        self.assertEqual(stats['runs'], 1)
+        self.assertEqual(stats['fails'], 1)
diff --git a/tempest/tests/test_wrappers.py b/tempest/tests/test_wrappers.py
index dbf1809..88bef9b 100644
--- a/tempest/tests/test_wrappers.py
+++ b/tempest/tests/test_wrappers.py
@@ -56,7 +56,7 @@
         # version or an sdist to work. so make the test directory a git repo
         # too.
         subprocess.call(['git', 'init'])
-        exit_code = subprocess.call('sh pretty_tox.sh tests.passing',
+        exit_code = subprocess.call('bash pretty_tox.sh tests.passing',
                                     shell=True, stdout=DEVNULL, stderr=DEVNULL)
         self.assertEqual(exit_code, 0)
 
@@ -71,7 +71,7 @@
         # version or an sdist to work. so make the test directory a git repo
         # too.
         subprocess.call(['git', 'init'])
-        exit_code = subprocess.call('sh pretty_tox.sh', shell=True,
+        exit_code = subprocess.call('bash pretty_tox.sh', shell=True,
                                     stdout=DEVNULL, stderr=DEVNULL)
         self.assertEqual(exit_code, 1)
 
@@ -82,7 +82,7 @@
         # Change directory, run wrapper and check result
         self.addCleanup(os.chdir, os.path.abspath(os.curdir))
         os.chdir(self.directory)
-        exit_code = subprocess.call('sh pretty_tox_serial.sh tests.passing',
+        exit_code = subprocess.call('bash pretty_tox_serial.sh tests.passing',
                                     shell=True, stdout=DEVNULL, stderr=DEVNULL)
         self.assertEqual(exit_code, 0)
 
@@ -93,6 +93,6 @@
         # Change directory, run wrapper and check result
         self.addCleanup(os.chdir, os.path.abspath(os.curdir))
         os.chdir(self.directory)
-        exit_code = subprocess.call('sh pretty_tox_serial.sh', shell=True,
+        exit_code = subprocess.call('bash pretty_tox_serial.sh', shell=True,
                                     stdout=DEVNULL, stderr=DEVNULL)
         self.assertEqual(exit_code, 1)
diff --git a/test-requirements.txt b/test-requirements.txt
index fbe7e43..9486244 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -1,7 +1,8 @@
-hacking>=0.5.6,<0.8
+hacking>=0.8.0,<0.9
 # needed for doc build
 docutils==0.9.1
-sphinx>=1.1.2
+sphinx>=1.1.2,<1.2
 python-subunit
 oslo.sphinx
 mox>=0.5.3
+mock>=1.0
diff --git a/tools/check_logs.py b/tools/check_logs.py
index 6d4436e..963709b 100755
--- a/tools/check_logs.py
+++ b/tools/check_logs.py
@@ -27,11 +27,13 @@
 
 
 is_neutron = os.environ.get('DEVSTACK_GATE_NEUTRON', "0") == "1"
+is_grenade = (os.environ.get('DEVSTACK_GATE_GRENADE', "0") == "1" or
+              os.environ.get('DEVSTACK_GATE_GRENADE_FORWARD', "0") == "1")
 dump_all_errors = is_neutron
 
 
 def process_files(file_specs, url_specs, whitelists):
-    regexp = re.compile(r"^.*(ERROR|CRITICAL).*\[.*\-.*\]")
+    regexp = re.compile(r"^.* (ERROR|CRITICAL) .*\[.*\-.*\]")
     had_errors = False
     for (name, filename) in file_specs:
         whitelist = whitelists.get(name, [])
@@ -125,6 +127,9 @@
         if is_neutron:
             print("Currently not failing neutron builds with errors")
             return 0
+        if is_grenade:
+            print("Currently not failing grenade runs with errors")
+            return 0
         print("FAILED")
         return 1
     else:
diff --git a/tools/pretty_tox.sh b/tools/pretty_tox.sh
index a5a6076..07c35a0 100755
--- a/tools/pretty_tox.sh
+++ b/tools/pretty_tox.sh
@@ -1,4 +1,6 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
+set -o pipefail
 
 TESTRARGS=$1
 python setup.py testr --slowest --testr-args="--subunit $TESTRARGS" | subunit2pyunit
diff --git a/tools/pretty_tox_serial.sh b/tools/pretty_tox_serial.sh
index 45f05bd..42ce760 100755
--- a/tools/pretty_tox_serial.sh
+++ b/tools/pretty_tox_serial.sh
@@ -1,4 +1,6 @@
-#!/bin/sh
+#!/usr/bin/env bash
+
+set -o pipefail
 
 TESTRARGS=$@
 
diff --git a/tools/tempest_coverage.py b/tools/tempest_coverage.py
deleted file mode 100755
index ef2eacd..0000000
--- a/tools/tempest_coverage.py
+++ /dev/null
@@ -1,193 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2012 IBM Corp.
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-import json
-import os
-import shutil
-import sys
-
-from oslo.config import cfg
-
-from tempest.common.rest_client import RestClient
-from tempest import config
-
-CONF = config.TempestConfig()
-
-
-class CoverageClientJSON(RestClient):
-
-    def __init__(self, config, username, password, auth_url, tenant_name=None):
-        super(CoverageClientJSON, self).__init__(config, username, password,
-                                                 auth_url, tenant_name)
-        self.service = self.config.compute.catalog_type
-
-    def start_coverage(self):
-        post_body = {
-            'start': {},
-        }
-        post_body = json.dumps(post_body)
-        return self.post('os-coverage/action', post_body, self.headers)
-
-    def start_coverage_combine(self):
-        post_body = {
-            'start': {
-                'combine': True,
-            },
-        }
-        post_body = json.dumps(post_body)
-        return self.post('os-coverage/action', post_body, self.headers)
-
-    def stop_coverage(self):
-        post_body = {
-            'stop': {},
-        }
-        post_body = json.dumps(post_body)
-        resp, body = self.post('os-coverage/action', post_body, self.headers)
-        body = json.loads(body)
-        return resp, body
-
-    def report_coverage_xml(self, file=None):
-        post_body = {
-            'report': {
-                'file': 'coverage.report',
-                'xml': True,
-            },
-        }
-        if file:
-            post_body['report']['file'] = file
-        post_body = json.dumps(post_body)
-        resp, body = self.post('os-coverage/action', post_body, self.headers)
-        body = json.loads(body)
-        return resp, body
-
-    def report_coverage(self, file=None):
-        post_body = {
-            'report': {
-                'file': 'coverage.report',
-            },
-        }
-        if file:
-            post_body['report']['file'] = file
-        post_body = json.dumps(post_body)
-        resp, body = self.post('os-coverage/action', post_body, self.headers)
-        body = json.loads(body)
-        return resp, body
-
-    def report_coverage_html(self, file=None):
-        post_body = {
-            'report': {
-                'file': 'coverage.report',
-                'html': True,
-            },
-        }
-        if file:
-            post_body['report']['file'] = file
-        post_body = json.dumps(post_body)
-        resp, body = self.post('os-coverage/action', post_body, self.headers)
-        body = json.loads(body)
-        return resp, body
-
-
-def parse_opts(argv):
-    cli_opts = [
-        cfg.StrOpt('command',
-                   short='c',
-                   default='',
-                   help="This required argument is used to specify the "
-                        "coverage command to run. Only 'start', "
-                        "'stop', or 'report' are valid fields."),
-        cfg.StrOpt('filename',
-                   default='tempest-coverage',
-                   help="Specify a filename to be used for generated report "
-                        "files"),
-        cfg.BoolOpt('xml',
-                    default=False,
-                    help='Generate XML reports instead of text'),
-        cfg.BoolOpt('html',
-                    default=False,
-                    help='Generate HTML reports instead of text'),
-        cfg.BoolOpt('combine',
-                    default=False,
-                    help='Generate a single report for all services'),
-        cfg.StrOpt('output',
-                   short='o',
-                   default=None,
-                   help='Optional directory to copy generated coverage data or'
-                        ' reports into. This directory must not already exist '
-                        'it will be created')
-    ]
-    CLI = cfg.ConfigOpts()
-    CLI.register_cli_opts(cli_opts)
-    CLI(argv[1:])
-    return CLI
-
-
-def main(argv):
-    CLI = parse_opts(argv)
-    client_args = (CONF, CONF.identity.admin_username,
-                   CONF.identity.admin_password, CONF.identity.uri,
-                   CONF.identity.admin_tenant_name)
-    coverage_client = CoverageClientJSON(*client_args)
-
-    if CLI.command == 'start':
-        if CLI.combine:
-            coverage_client.start_coverage_combine()
-        else:
-            coverage_client.start_coverage()
-
-    elif CLI.command == 'stop':
-        resp, body = coverage_client.stop_coverage()
-        if not resp['status'] == '200':
-            print('coverage stop failed with: %s:' % (resp['status'] + ': '
-                                                      + body))
-            exit(int(resp['status']))
-        path = body['path']
-        if CLI.output:
-            shutil.copytree(path, CLI.output)
-        else:
-            print("Data files located at: %s" % path)
-
-    elif CLI.command == 'report':
-        if CLI.xml:
-            resp, body = coverage_client.report_coverage_xml(file=CLI.filename)
-        elif CLI.html:
-            resp, body = coverage_client.report_coverage_html(
-                file=CLI.filename)
-        else:
-            resp, body = coverage_client.report_coverage(file=CLI.filename)
-        if not resp['status'] == '200':
-            print('coverage report failed with: %s:' % (resp['status'] + ': '
-                                                        + body))
-            exit(int(resp['status']))
-        path = body['path']
-        if CLI.output:
-            if CLI.html:
-                shutil.copytree(path, CLI.output)
-            else:
-                path = os.path.dirname(path)
-                shutil.copytree(path, CLI.output)
-        else:
-            if not CLI.html:
-                path = os.path.dirname(path)
-            print('Report files located at: %s' % path)
-
-    else:
-        print('Invalid command')
-        exit(1)
-
-
-if __name__ == "__main__":
-    main(sys.argv)
diff --git a/tools/verify_tempest_config.py b/tools/verify_tempest_config.py
index 1b5fe68..347659d 100755
--- a/tools/verify_tempest_config.py
+++ b/tools/verify_tempest_config.py
@@ -36,11 +36,11 @@
     __, versions = os.image_client.get_versions()
     if CONF.image_feature_enabled.api_v1 != ('v1.1' in versions or 'v1.0' in
                                              versions):
-        print 'Config option image api_v1 should be change to: %s' % (
-            not CONF.image_feature_enabled.api_v1)
+        print('Config option image api_v1 should be change to: %s' % (
+            not CONF.image_feature_enabled.api_v1))
     if CONF.image_feature_enabled.api_v2 != ('v2.0' in versions):
-        print 'Config option image api_v2 should be change to: %s' % (
-            not CONF.image_feature_enabled.api_v2)
+        print('Config option image api_v2 should be change to: %s' % (
+            not CONF.image_feature_enabled.api_v2))
 
 
 def verify_extensions(os):
@@ -62,8 +62,8 @@
     for option in NOVA_EXTENSIONS.keys():
         config_value = getattr(CONF.compute_feature_enabled, option)
         if config_value != results['nova_features'][option]:
-            print "Config option: %s should be changed to: %s" % (
-                option, not config_value)
+            print("Config option: %s should be changed to: %s" % (
+                option, not config_value))
 
 
 def main(argv):
diff --git a/tox.ini b/tox.ini
index 6efac78..c7f92ae 100644
--- a/tox.ini
+++ b/tox.ini
@@ -9,14 +9,18 @@
          LANGUAGE=en_US:en
          LC_ALL=C
 usedevelop = True
+install_command = pip install -U {opts} {packages}
 
 [testenv:py26]
+setenv = OS_TEST_PATH=./tempest/tests
 commands = python setup.py test --slowest --testr-arg='tempest\.tests {posargs}'
 
 [testenv:py33]
+setenv = OS_TEST_PATH=./tempest/tests
 commands = python setup.py test --slowest --testr-arg='tempest\.tests {posargs}'
 
 [testenv:py27]
+setenv = OS_TEST_PATH=./tempest/tests
 commands = python setup.py test --slowest --testr-arg='tempest\.tests {posargs}'
 
 [testenv:all]
@@ -30,19 +34,19 @@
 # The regex below is used to select which tests to run and exclude the slow tag:
 # See the testrepostiory bug: https://bugs.launchpad.net/testrepository/+bug/1208610
 commands =
-  sh tools/pretty_tox.sh '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario|thirdparty|cli)) {posargs}'
+  bash tools/pretty_tox.sh '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario|thirdparty|cli)) {posargs}'
 
 [testenv:testr-full]
 sitepackages = True
 commands =
-  sh tools/pretty_tox.sh '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario|thirdparty|cli)) {posargs}'
+  bash tools/pretty_tox.sh '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario|thirdparty|cli)) {posargs}'
 
 [testenv:heat-slow]
 sitepackages = True
 setenv = OS_TEST_TIMEOUT=1200
 # The regex below is used to select heat api/scenario tests tagged as slow.
 commands =
-  sh tools/pretty_tox_serial.sh '(?=.*\[.*\bslow\b.*\])(^tempest\.(api|scenario)\.orchestration) {posargs}'
+  bash tools/pretty_tox_serial.sh '(?=.*\[.*\bslow\b.*\])(^tempest\.(api|scenario)\.orchestration) {posargs}'
 
 [testenv:large-ops]
 sitepackages = True
@@ -78,7 +82,7 @@
 [testenv:smoke]
 sitepackages = True
 commands =
-   sh tools/pretty_tox.sh '(?!.*\[.*\bslow\b.*\])((smoke)|(^tempest\.scenario)) {posargs}'
+   bash tools/pretty_tox.sh '(?!.*\[.*\bslow\b.*\])((smoke)|(^tempest\.scenario)) {posargs}'
 
 [testenv:smoke-serial]
 sitepackages = True
@@ -86,14 +90,7 @@
 # https://bugs.launchpad.net/tempest/+bug/1216076 so the neutron smoke
 # job would fail if we moved it to parallel.
 commands =
-   sh tools/pretty_tox_serial.sh '(?!.*\[.*\bslow\b.*\])((smoke)|(^tempest\.scenario)) {posargs}'
-
-[testenv:coverage]
-sitepackages = True
-commands =
-   python -m tools/tempest_coverage -c start --combine
-   sh tools/pretty_tox.sh '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario|thirdparty|cli))'
-   python -m tools/tempest_coverage -c report --html {posargs}
+   bash tools/pretty_tox_serial.sh '(?!.*\[.*\bslow\b.*\])((smoke)|(^tempest\.scenario)) {posargs}'
 
 [testenv:stress]
 sitepackages = True