Merge "Adds "list hosts" test case - Cinder"
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index 251336e..937bbd3 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -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}
@@ -236,10 +228,10 @@
 # value)
 #image_ref_alt={$IMAGE_ID_ALT}
 
-# Valid primary flavor to use in tests. (integer value)
+# Valid primary flavor to use in tests. (string value)
 #flavor_ref=1
 
-# Valid secondary flavor to be used in tests. (integer value)
+# Valid secondary flavor to be used in tests. (string value)
 #flavor_ref_alt=2
 
 # User name used to authenticate to an instance. (string
@@ -711,7 +703,7 @@
 # Options defined in tempest.config
 #
 
-# Set to True if the container quota middleware is enabled
+# Set to True if the Container Quota middleware is enabled
 # (boolean value)
 #container_quotas=true
 
@@ -723,6 +715,10 @@
 # (boolean value)
 #crossdomain=true
 
+# Set to True if the TempURL middleware is enabled (boolean
+# value)
+#tempurl=true
+
 
 [volume-feature-enabled]
 
diff --git a/tempest/api/compute/admin/test_flavors.py b/tempest/api/compute/admin/test_flavors.py
index 8d2fcac..c5a8772 100644
--- a/tempest/api/compute/admin/test_flavors.py
+++ b/tempest/api/compute/admin/test_flavors.py
@@ -15,6 +15,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import uuid
+
 from tempest.api import compute
 from tempest.api.compute import base
 from tempest.common.utils import data_utils
@@ -53,18 +55,16 @@
         self.assertEqual(resp.status, 202)
         self.client.wait_for_resource_deletion(flavor_id)
 
-    @attr(type='gate')
-    def test_create_flavor(self):
+    def _create_flavor(self, flavor_id):
         # Create a flavor and ensure it is listed
         # This operation requires the user to have 'admin' role
         flavor_name = data_utils.rand_name(self.flavor_name_prefix)
-        new_flavor_id = data_utils.rand_int_id(start=1000)
 
         # Create the flavor
         resp, flavor = self.client.create_flavor(flavor_name,
                                                  self.ram, self.vcpus,
                                                  self.disk,
-                                                 new_flavor_id,
+                                                 flavor_id,
                                                  ephemeral=self.ephemeral,
                                                  swap=self.swap,
                                                  rxtx=self.rxtx)
@@ -74,7 +74,6 @@
         self.assertEqual(flavor['vcpus'], self.vcpus)
         self.assertEqual(flavor['disk'], self.disk)
         self.assertEqual(flavor['ram'], self.ram)
-        self.assertEqual(int(flavor['id']), new_flavor_id)
         self.assertEqual(flavor['swap'], self.swap)
         self.assertEqual(flavor['rxtx_factor'], self.rxtx)
         self.assertEqual(flavor['OS-FLV-EXT-DATA:ephemeral'],
@@ -82,10 +81,32 @@
         self.assertEqual(flavor['os-flavor-access:is_public'], True)
 
         # Verify flavor is retrieved
-        resp, flavor = self.client.get_flavor_details(new_flavor_id)
+        resp, flavor = self.client.get_flavor_details(flavor['id'])
         self.assertEqual(resp.status, 200)
         self.assertEqual(flavor['name'], flavor_name)
 
+        return flavor['id']
+
+    @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')
+    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')
+    def test_create_flavor_with_none_id(self):
+        # If nova receives a request with None as flavor_id,
+        # nova generates flavor_id of uuid.
+        flavor_id = None
+        new_flavor_id = self._create_flavor(flavor_id)
+        self.assertEqual(new_flavor_id, str(uuid.UUID(new_flavor_id)))
+
     @attr(type='gate')
     def test_create_flavor_verify_entry_in_list_details(self):
         # Create a flavor and ensure it's details are listed
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index 7ef5466..e3edd7c 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -181,17 +181,18 @@
         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):
@@ -258,17 +259,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):
diff --git a/tempest/api/compute/flavors/test_flavors.py b/tempest/api/compute/flavors/test_flavors.py
index eac98ea..fa99422 100644
--- a/tempest/api/compute/flavors/test_flavors.py
+++ b/tempest/api/compute/flavors/test_flavors.py
@@ -48,7 +48,7 @@
     def test_get_flavor(self):
         # The expected flavor details should be returned
         resp, flavor = self.client.get_flavor_details(self.flavor_ref)
-        self.assertEqual(self.flavor_ref, int(flavor['id']))
+        self.assertEqual(self.flavor_ref, flavor['id'])
 
     @attr(type=['negative', 'gate'])
     def test_get_non_existant_flavor(self):
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_oneserver.py b/tempest/api/compute/images/test_images_oneserver.py
index 612c110..18e32d8 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.server_id = self.rebuild_server(self.server_id)
 
     @classmethod
     def setUpClass(cls):
diff --git a/tempest/api/compute/images/test_images_oneserver_negative.py b/tempest/api/compute/images/test_images_oneserver_negative.py
index b4e778c..4cd41ee 100644
--- a/tempest/api/compute/images/test_images_oneserver_negative.py
+++ b/tempest/api/compute/images/test_images_oneserver_negative.py
@@ -50,7 +50,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.server_id = self.rebuild_server(self.server_id)
 
     @classmethod
     def setUpClass(cls):
diff --git a/tempest/api/compute/servers/test_create_server.py b/tempest/api/compute/servers/test_create_server.py
index 44ce405..24ade96 100644
--- a/tempest/api/compute/servers/test_create_server.py
+++ b/tempest/api/compute/servers/test_create_server.py
@@ -72,7 +72,7 @@
                          str(netaddr.IPAddress(self.accessIPv6)))
         self.assertEqual(self.name, self.server['name'])
         self.assertEqual(self.image_ref, self.server['image']['id'])
-        self.assertEqual(str(self.flavor_ref), self.server['flavor']['id'])
+        self.assertEqual(self.flavor_ref, self.server['flavor']['id'])
         self.assertEqual(self.meta, self.server['metadata'])
 
     @attr(type='smoke')
diff --git a/tempest/api/compute/servers/test_server_actions.py b/tempest/api/compute/servers/test_server_actions.py
index 5abde56..5fa4c35 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.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.')
@@ -128,7 +128,7 @@
         self.assertEqual(self.server_id, rebuilt_server['id'])
         rebuilt_image_id = rebuilt_server['image']['id']
         self.assertTrue(self.image_ref_alt.endswith(rebuilt_image_id))
-        self.assertEqual(self.flavor_ref, int(rebuilt_server['flavor']['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'], 'ACTIVE')
@@ -147,8 +147,8 @@
         resp, server = self.client.get_server(self.server_id)
         current_flavor = server['flavor']['id']
         new_flavor_ref = self.flavor_ref_alt \
-            if int(current_flavor) == self.flavor_ref else self.flavor_ref
-        return int(current_flavor), int(new_flavor_ref)
+            if current_flavor == self.flavor_ref else self.flavor_ref
+        return current_flavor, new_flavor_ref
 
     @testtools.skipIf(not resize_available, 'Resize not available.')
     @attr(type='smoke')
@@ -167,7 +167,7 @@
         self.client.wait_for_server_status(self.server_id, 'ACTIVE')
 
         resp, server = self.client.get_server(self.server_id)
-        self.assertEqual(new_flavor_ref, int(server['flavor']['id']))
+        self.assertEqual(new_flavor_ref, server['flavor']['id'])
 
     @testtools.skipIf(not resize_available, 'Resize not available.')
     @attr(type='gate')
@@ -189,7 +189,7 @@
         resp, server = self.client.get_server(self.server_id)
         start = int(time.time())
 
-        while int(server['flavor']['id']) != previous_flavor_ref:
+        while server['flavor']['id'] != previous_flavor_ref:
             time.sleep(self.build_interval)
             resp, server = self.client.get_server(self.server_id)
 
diff --git a/tempest/api/compute/servers/test_servers_negative.py b/tempest/api/compute/servers/test_servers_negative.py
index 5ec0cbe..7b86d2d 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.server_id = self.rebuild_server(self.server_id)
 
     @classmethod
     def setUpClass(cls):
diff --git a/tempest/api/compute/v3/servers/test_server_actions.py b/tempest/api/compute/v3/servers/test_server_actions.py
index 92b9e30..dc78a47 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.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.')
@@ -128,7 +128,7 @@
         self.assertEqual(self.server_id, rebuilt_server['id'])
         rebuilt_image_id = rebuilt_server['image']['id']
         self.assertTrue(self.image_ref_alt.endswith(rebuilt_image_id))
-        self.assertEqual(self.flavor_ref, int(rebuilt_server['flavor']['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'], 'ACTIVE')
@@ -147,8 +147,8 @@
         resp, server = self.client.get_server(self.server_id)
         current_flavor = server['flavor']['id']
         new_flavor_ref = self.flavor_ref_alt \
-            if int(current_flavor) == self.flavor_ref else self.flavor_ref
-        return int(current_flavor), int(new_flavor_ref)
+            if current_flavor == self.flavor_ref else self.flavor_ref
+        return current_flavor, new_flavor_ref
 
     @testtools.skipIf(not resize_available, 'Resize not available.')
     @attr(type='smoke')
@@ -167,7 +167,7 @@
         self.client.wait_for_server_status(self.server_id, 'ACTIVE')
 
         resp, server = self.client.get_server(self.server_id)
-        self.assertEqual(new_flavor_ref, int(server['flavor']['id']))
+        self.assertEqual(new_flavor_ref, server['flavor']['id'])
 
     @testtools.skipIf(not resize_available, 'Resize not available.')
     @attr(type='gate')
@@ -189,7 +189,7 @@
         resp, server = self.client.get_server(self.server_id)
         start = int(time.time())
 
-        while int(server['flavor']['id']) != previous_flavor_ref:
+        while server['flavor']['id'] != previous_flavor_ref:
             time.sleep(self.build_interval)
             resp, server = self.client.get_server(self.server_id)
 
diff --git a/tempest/api/compute/v3/servers/test_servers_negative.py b/tempest/api/compute/v3/servers/test_servers_negative.py
index 5ec0cbe..7b86d2d 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.server_id = self.rebuild_server(self.server_id)
 
     @classmethod
     def setUpClass(cls):
diff --git a/tempest/api/network/common.py b/tempest/api/network/common.py
index 43e7f68..ab19fa8 100644
--- a/tempest/api/network/common.py
+++ b/tempest/api/network/common.py
@@ -94,3 +94,18 @@
 
     def delete(self):
         self.client.delete_port(self.id)
+
+
+class DeletableSecurityGroup(DeletableResource):
+
+    def delete(self):
+        self.client.delete_security_group(self.id)
+
+
+class DeletableSecurityGroupRule(DeletableResource):
+
+    def __repr__(self):
+        return '<%s id="%s">' % (self.__class__.__name__, self.id)
+
+    def delete(self):
+        self.client.delete_security_group_rule(self.id)
diff --git a/tempest/api/object_storage/test_container_staticweb.py b/tempest/api/object_storage/test_container_staticweb.py
index 9e405d6..1eea30a 100644
--- a/tempest/api/object_storage/test_container_staticweb.py
+++ b/tempest/api/object_storage/test_container_staticweb.py
@@ -16,7 +16,7 @@
 
 from tempest.api.object_storage import base
 from tempest.common.utils import data_utils
-from tempest.test import attr
+from tempest import test
 
 
 class StaticWebTest(base.BaseObjectTest):
@@ -48,7 +48,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 +59,7 @@
         # we should retrieve the self.object_name file
         resp, body = self.custom_account_client.request("GET",
                                                         self.container_name)
-        self.assertEqual(resp['status'], '200')
+        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertEqual(body, self.object_data)
 
         # clean up before exiting
@@ -70,7 +70,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 +81,7 @@
         # we should retrieve a listing of objects
         resp, body = self.custom_account_client.request("GET",
                                                         self.container_name)
-        self.assertEqual(resp['status'], '200')
+        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertIn(self.object_name, body)
 
         # clean up before exiting
@@ -91,3 +91,41 @@
         _, body = self.container_client.list_container_metadata(
             self.container_name)
         self.assertNotIn('x-container-meta-web-listings', body)
+
+    @test.attr('gate')
+    def test_web_listing_css(self):
+        headers = {'web-listings': 'true',
+                   'web-listings-css': 'listings.css'}
+
+        self.container_client.update_container_metadata(
+            self.container_name, metadata=headers)
+
+        # test GET on http://account_url/container_name
+        # we should retrieve a listing of objects
+        resp, body = self.custom_account_client.request("GET",
+                                                        self.container_name)
+        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)
+
+    @test.attr('gate')
+    def test_web_error(self):
+        headers = {'web-listings': 'true',
+                   'web-error': self.object_name}
+
+        self.container_client.update_container_metadata(
+            self.container_name, metadata=headers)
+
+        # Create object to return when requested object not found
+        object_name_404 = "404" + self.object_name
+        object_data_404 = data_utils.arbitrary_string()
+        self.object_client.create_object(self.container_name,
+                                         object_name_404,
+                                         object_data_404)
+
+        # Request non-existing object
+        resp, body = self.custom_object_client.get_object(self.container_name,
+                                                          "notexisting")
+        self.assertEqual(resp['status'], '404')
+        self.assertEqual(body, object_data_404)
diff --git a/tempest/api/object_storage/test_object_formpost.py b/tempest/api/object_storage/test_object_formpost.py
new file mode 100644
index 0000000..63393e4
--- /dev/null
+++ b/tempest/api/object_storage/test_object_formpost.py
@@ -0,0 +1,135 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+# Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
+#
+# Author: Christian Schwede <christian.schwede@enovance.com>
+#
+# 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 hmac
+import time
+import urlparse
+
+from tempest.api.object_storage import base
+from tempest.common.utils import data_utils
+from tempest.test import attr
+from tempest.test import HTTP_SUCCESS
+
+
+class ObjectFormPostTest(base.BaseObjectTest):
+
+    @classmethod
+    def setUpClass(cls):
+        super(ObjectFormPostTest, cls).setUpClass()
+        cls.container_name = data_utils.rand_name(name='TestContainer')
+        cls.object_name = data_utils.rand_name(name='ObjectTemp')
+
+        cls.container_client.create_container(cls.container_name)
+        cls.containers = [cls.container_name]
+
+        cls.key = 'Meta'
+        cls.metadata = {'Temp-URL-Key': cls.key}
+        cls.account_client.create_account_metadata(metadata=cls.metadata)
+
+    @classmethod
+    def tearDownClass(cls):
+        cls.account_client.delete_account_metadata(metadata=cls.metadata)
+        cls.delete_containers(cls.containers)
+        cls.data.teardown_all()
+        super(ObjectFormPostTest, cls).tearDownClass()
+
+    def get_multipart_form(self, expires=600):
+        path = "%s/%s/%s" % (
+            urlparse.urlparse(self.container_client.base_url).path,
+            self.container_name,
+            self.object_name)
+
+        redirect = ''
+        max_file_size = 104857600
+        max_file_count = 10
+        expires += int(time.time())
+        hmac_body = '%s\n%s\n%s\n%s\n%s' % (path,
+                                            redirect,
+                                            max_file_size,
+                                            max_file_count,
+                                            expires)
+
+        signature = hmac.new(self.key, hmac_body, hashlib.sha1).hexdigest()
+
+        fields = {'redirect': redirect,
+                  'max_file_size': str(max_file_size),
+                  'max_file_count': str(max_file_count),
+                  'expires': str(expires),
+                  'signature': signature}
+
+        boundary = '--boundary--'
+        data = []
+        for (key, value) in fields.items():
+            data.append('--' + boundary)
+            data.append('Content-Disposition: form-data; name="%s"' % key)
+            data.append('')
+            data.append(value)
+
+        data.append('--' + boundary)
+        data.append('Content-Disposition: form-data; '
+                    'name="file1"; filename="testfile"')
+        data.append('Content-Type: application/octet-stream')
+        data.append('')
+        data.append('hello world')
+
+        data.append('--' + boundary + '--')
+        data.append('')
+
+        body = '\r\n'.join(data)
+        content_type = 'multipart/form-data; boundary=%s' % boundary
+        return body, content_type
+
+    @attr(type='gate')
+    def test_post_object_using_form(self):
+        body, content_type = self.get_multipart_form()
+
+        headers = {'Content-Type': content_type,
+                   'Content-Length': str(len(body))}
+
+        url = "%s/%s/%s" % (self.container_client.base_url,
+                            self.container_name,
+                            self.object_name)
+
+        # Use a raw request, otherwise authentication headers are used
+        resp, body = self.object_client.http_obj.request(url, "POST",
+                                                         body, headers=headers)
+        self.assertIn(int(resp['status']), HTTP_SUCCESS)
+
+        # 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.assertEqual(body, "hello world")
+
+    @attr(type=['gate', 'negative'])
+    def test_post_object_using_form_expired(self):
+        body, content_type = self.get_multipart_form(expires=1)
+        time.sleep(2)
+
+        headers = {'Content-Type': content_type,
+                   'Content-Length': str(len(body))}
+
+        url = "%s/%s/%s" % (self.container_client.base_url,
+                            self.container_name,
+                            self.object_name)
+
+        # Use a raw request, otherwise authentication headers are used
+        resp, body = self.object_client.http_obj.request(url, "POST",
+                                                         body, headers=headers)
+        self.assertEqual(int(resp['status']), 401)
+        self.assertIn('FormPost: Form Expired', body)
diff --git a/tempest/api/object_storage/test_object_temp_url.py b/tempest/api/object_storage/test_object_temp_url.py
index 77f3a53..c8ce57a 100644
--- a/tempest/api/object_storage/test_object_temp_url.py
+++ b/tempest/api/object_storage/test_object_temp_url.py
@@ -22,6 +22,7 @@
 
 from tempest.api.object_storage 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 HTTP_SUCCESS
@@ -29,9 +30,19 @@
 
 class ObjectTempUrlTest(base.BaseObjectTest):
 
+    tempurl_available = \
+        config.TempestConfig().object_storage_feature_enabled.tempurl
+
     @classmethod
     def setUpClass(cls):
         super(ObjectTempUrlTest, cls).setUpClass()
+
+        # skip this test if CORS isn't enabled in the conf file.
+        if not cls.tempurl_available:
+            skip_msg = ("%s skipped as TempUrl middleware not available"
+                        % cls.__name__)
+            raise cls.skipException(skip_msg)
+
         cls.container_name = data_utils.rand_name(name='TestContainer')
         cls.container_client.create_container(cls.container_name)
         cls.containers = [cls.container_name]
@@ -47,9 +58,9 @@
     def tearDownClass(cls):
         resp, _ = cls.account_client.delete_account_metadata(
             metadata=cls.metadata)
-        resp, _ = cls.account_client.list_account_metadata()
 
         cls.delete_containers(cls.containers)
+
         # delete the user setup created
         cls.data.teardown_all()
         super(ObjectTempUrlTest, cls).tearDownClass()
@@ -71,8 +82,11 @@
         self.object_client.create_object(self.container_name,
                                          self.object_name, self.data)
 
-    def get_temp_url(self, container, object_name, method, expires,
-                     key):
+    def _get_expiry_date(self, expiration_time=1000):
+        return int(time.time() + expiration_time)
+
+    def _get_temp_url(self, container, object_name, method, expires,
+                      key):
         """Create the temporary URL."""
 
         path = "%s/%s/%s" % (
@@ -90,17 +104,17 @@
 
     @attr(type='gate')
     def test_get_object_using_temp_url(self):
-        EXPIRATION_TIME = 10000  # high to ensure the test finishes.
-        expires = int(time.time() + EXPIRATION_TIME)
+        expires = self._get_expiry_date()
 
         # get a temp URL for the created object
-        url = self.get_temp_url(self.container_name,
-                                self.object_name, "GET",
-                                expires, self.key)
+        url = self._get_temp_url(self.container_name,
+                                 self.object_name, "GET",
+                                 expires, self.key)
 
         # trying to get object using temp url within expiry time
-        _, body = self.object_client.get_object_using_temp_url(url)
+        resp, body = self.object_client.get_object_using_temp_url(url)
 
+        self.assertIn(int(resp['status']), HTTP_SUCCESS)
         self.assertEqual(body, self.data)
 
         # Testing a HEAD on this Temp URL
@@ -108,18 +122,35 @@
         self.assertIn(int(resp['status']), HTTP_SUCCESS)
 
     @attr(type='gate')
+    def test_get_object_using_temp_url_key_2(self):
+        key2 = 'Meta2-'
+        metadata = {'Temp-URL-Key-2': key2}
+        self.account_client.create_account_metadata(metadata=metadata)
+
+        self.account_client_metadata, _ = \
+            self.account_client.list_account_metadata()
+        self.assertIn('x-account-meta-temp-url-key-2',
+                      self.account_client_metadata)
+
+        expires = self._get_expiry_date()
+        url = self._get_temp_url(self.container_name,
+                                 self.object_name, "GET",
+                                 expires, key2)
+        resp, body = self.object_client.get_object_using_temp_url(url)
+        self.assertIn(int(resp['status']), HTTP_SUCCESS)
+        self.assertEqual(body, self.data)
+
+    @attr(type='gate')
     def test_put_object_using_temp_url(self):
         # make sure the metadata has been set
         new_data = data_utils.arbitrary_string(
             size=len(self.object_name),
             base_text=data_utils.rand_name(name="random"))
 
-        EXPIRATION_TIME = 10000  # high to ensure the test finishes.
-        expires = int(time.time() + EXPIRATION_TIME)
-
-        url = self.get_temp_url(self.container_name,
-                                self.object_name, "PUT",
-                                expires, self.key)
+        expires = self._get_expiry_date()
+        url = self._get_temp_url(self.container_name,
+                                 self.object_name, "PUT",
+                                 expires, self.key)
 
         # trying to put random data in the object using temp url
         resp, body = self.object_client.put_object_using_temp_url(
@@ -132,25 +163,24 @@
         self.assertIn(int(resp['status']), HTTP_SUCCESS)
 
         # Validate that the content of the object has been modified
-        url = self.get_temp_url(self.container_name,
-                                self.object_name, "GET",
-                                expires, self.key)
+        url = self._get_temp_url(self.container_name,
+                                 self.object_name, "GET",
+                                 expires, self.key)
 
         _, body = self.object_client.get_object_using_temp_url(url)
         self.assertEqual(body, new_data)
 
     @attr(type=['gate', 'negative'])
     def test_get_object_after_expiration_time(self):
-        EXPIRATION_TIME = 1
-        expires = int(time.time() + EXPIRATION_TIME)
 
+        expires = self._get_expiry_date(1)
         # get a temp URL for the created object
-        url = self.get_temp_url(self.container_name,
-                                self.object_name, "GET",
-                                expires, self.key)
+        url = self._get_temp_url(self.container_name,
+                                 self.object_name, "GET",
+                                 expires, self.key)
 
-        # temp URL is valid for 1 seconds, let's wait 3
-        time.sleep(EXPIRATION_TIME + 2)
+        # temp URL is valid for 1 seconds, let's wait 2
+        time.sleep(2)
 
         self.assertRaises(exceptions.Unauthorized,
                           self.object_client.get_object_using_temp_url,
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/common/ssh.py b/tempest/common/ssh.py
index 742a354..c397b7c 100644
--- a/tempest/common/ssh.py
+++ b/tempest/common/ssh.py
@@ -62,7 +62,7 @@
                             password=self.password,
                             look_for_keys=self.look_for_keys,
                             key_filename=self.key_filename,
-                            timeout=self.timeout, pkey=self.pkey)
+                            timeout=self.channel_timeout, pkey=self.pkey)
                 _timeout = False
                 break
             except (socket.error,
diff --git a/tempest/config.py b/tempest/config.py
index 6af7d51..220fd04 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -103,25 +103,17 @@
                      "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."),
     cfg.StrOpt('image_ref_alt',
                default="{$IMAGE_ID_ALT}",
                help="Valid secondary image reference to be used in tests."),
-    cfg.IntOpt('flavor_ref',
-               default=1,
+    cfg.StrOpt('flavor_ref',
+               default="1",
                help="Valid primary flavor to use in tests."),
-    cfg.IntOpt('flavor_ref_alt',
-               default=2,
+    cfg.StrOpt('flavor_ref_alt',
+               default="2",
                help='Valid secondary flavor to be used in tests.'),
     cfg.StrOpt('image_ssh_user',
                default="root",
@@ -406,7 +398,7 @@
 ObjectStoreFeaturesGroup = [
     cfg.BoolOpt('container_quotas',
                 default=True,
-                help="Set to True if the container quota middleware "
+                help="Set to True if the Container Quota middleware "
                      "is enabled"),
     cfg.BoolOpt('accounts_quotas',
                 default=True,
@@ -414,6 +406,9 @@
     cfg.BoolOpt('crossdomain',
                 default=True,
                 help="Set to True if the Crossdomain middleware is enabled"),
+    cfg.BoolOpt('tempurl',
+                default=True,
+                help="Set to True if the TempURL middleware is enabled"),
 ]
 
 
diff --git a/tempest/openstack/common/lockutils.py b/tempest/openstack/common/lockutils.py
index 8ea8766..65f3548 100644
--- a/tempest/openstack/common/lockutils.py
+++ b/tempest/openstack/common/lockutils.py
@@ -20,6 +20,10 @@
 import errno
 import functools
 import os
+import shutil
+import subprocess
+import sys
+import tempfile
 import threading
 import time
 import weakref
@@ -39,6 +43,7 @@
     cfg.BoolOpt('disable_process_locking', default=False,
                 help='Whether to disable inter-process locks'),
     cfg.StrOpt('lock_path',
+               default=os.environ.get("TEMPEST_LOCK_PATH"),
                help=('Directory to use for lock files.'))
 ]
 
@@ -131,6 +136,7 @@
     InterProcessLock = _PosixLock
 
 _semaphores = weakref.WeakValueDictionary()
+_semaphores_lock = threading.Lock()
 
 
 @contextlib.contextmanager
@@ -153,15 +159,12 @@
     special location for external lock files to live. If nothing is set, then
     CONF.lock_path is used as a default.
     """
-    # NOTE(soren): If we ever go natively threaded, this will be racy.
-    #              See http://stackoverflow.com/questions/5390569/dyn
-    #              amically-allocating-and-destroying-mutexes
-    sem = _semaphores.get(name, threading.Semaphore())
-    if name not in _semaphores:
-        # this check is not racy - we're already holding ref locally
-        # so GC won't remove the item and there was no IO switch
-        # (only valid in greenthreads)
-        _semaphores[name] = sem
+    with _semaphores_lock:
+        try:
+            sem = _semaphores[name]
+        except KeyError:
+            sem = threading.Semaphore()
+            _semaphores[name] = sem
 
     with sem:
         LOG.debug(_('Got semaphore "%(lock)s"'), {'lock': name})
@@ -276,3 +279,27 @@
     """
 
     return functools.partial(synchronized, lock_file_prefix=lock_file_prefix)
+
+
+def main(argv):
+    """Create a dir for locks and pass it to command from arguments
+
+    If you run this:
+    python -m openstack.common.lockutils python setup.py testr <etc>
+
+    a temporary directory will be created for all your locks and passed to all
+    your tests in an environment variable. The temporary dir will be deleted
+    afterwards and the return value will be preserved.
+    """
+
+    lock_dir = tempfile.mkdtemp()
+    os.environ["TEMPEST_LOCK_PATH"] = lock_dir
+    try:
+        ret_val = subprocess.call(argv[1:])
+    finally:
+        shutil.rmtree(lock_dir, ignore_errors=True)
+    return ret_val
+
+
+if __name__ == '__main__':
+    sys.exit(main(sys.argv))
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 7848afc..06841e1 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -360,7 +360,8 @@
                       to become %s" % (thing_id, log_status)
             raise exceptions.TimeoutException(message)
 
-    def create_loginable_secgroup_rule(self, client=None, secgroup_id=None):
+    def _create_loginable_secgroup_rule_nova(self, client=None,
+                                             secgroup_id=None):
         if client is None:
             client = self.compute_client
         if secgroup_id is None:
@@ -389,10 +390,13 @@
                 'cidr': '0.0.0.0/0',
             }
         ]
+        rules = list()
         for ruleset in rulesets:
             sg_rule = client.security_group_rules.create(secgroup_id,
                                                          **ruleset)
             self.set_resource(sg_rule.id, sg_rule)
+            rules.append(sg_rule)
+        return rules
 
     def create_server(self, client=None, name=None, image=None, flavor=None,
                       create_kwargs={}):
@@ -506,22 +510,6 @@
                 cls.config.identity.password,
                 cls.config.identity.tenant_name).tenant_id
 
-    def _create_security_group(self, client=None, namestart='secgroup-smoke-'):
-        if client is None:
-            client = self.compute_client
-        # Create security group
-        sg_name = data_utils.rand_name(namestart)
-        sg_desc = sg_name + " description"
-        secgroup = client.security_groups.create(sg_name, sg_desc)
-        self.assertEqual(secgroup.name, sg_name)
-        self.assertEqual(secgroup.description, sg_desc)
-        self.set_resource(sg_name, secgroup)
-
-        # Add rules to the security group
-        self.create_loginable_secgroup_rule(client, secgroup.id)
-
-        return secgroup
-
     def _create_network(self, tenant_id, namestart='network-smoke-'):
         name = data_utils.rand_name(namestart)
         body = dict(
@@ -648,6 +636,171 @@
             'Auth failure in connecting to %s@%s via ssh' %
             (username, ip_address))
 
+    def _create_security_group_nova(self, client=None,
+                                    namestart='secgroup-smoke-',
+                                    tenant_id=None):
+        if client is None:
+            client = self.compute_client
+        # Create security group
+        sg_name = data_utils.rand_name(namestart)
+        sg_desc = sg_name + " description"
+        secgroup = client.security_groups.create(sg_name, sg_desc)
+        self.assertEqual(secgroup.name, sg_name)
+        self.assertEqual(secgroup.description, sg_desc)
+        self.set_resource(sg_name, secgroup)
+
+        # Add rules to the security group
+        self._create_loginable_secgroup_rule_nova(client, secgroup.id)
+
+        return secgroup
+
+    def _create_security_group_neutron(self, tenant_id, client=None,
+                                       namestart='secgroup-smoke-'):
+        if client is None:
+            client = self.network_client
+        secgroup = self._create_empty_security_group(namestart=namestart,
+                                                     client=client,
+                                                     tenant_id=tenant_id)
+
+        # Add rules to the security group
+        rules = self._create_loginable_secgroup_rule_neutron(secgroup=secgroup)
+        for rule in rules:
+            self.assertEqual(tenant_id, rule.tenant_id)
+            self.assertEqual(secgroup.id, rule.security_group_id)
+        return secgroup
+
+    def _create_empty_security_group(self, tenant_id, client=None,
+                                     namestart='secgroup-smoke-'):
+        """Create a security group without rules.
+
+        Default rules will be created:
+         - IPv4 egress to any
+         - IPv6 egress to any
+
+        :param tenant_id: secgroup will be created in this tenant
+        :returns: DeletableSecurityGroup -- containing the secgroup created
+        """
+        if client is None:
+            client = self.network_client
+        sg_name = data_utils.rand_name(namestart)
+        sg_desc = sg_name + " description"
+        sg_dict = dict(name=sg_name,
+                       description=sg_desc)
+        sg_dict['tenant_id'] = tenant_id
+        body = dict(security_group=sg_dict)
+        result = client.create_security_group(body=body)
+        secgroup = net_common.DeletableSecurityGroup(
+            client=client,
+            **result['security_group']
+        )
+        self.assertEqual(secgroup.name, sg_name)
+        self.assertEqual(tenant_id, secgroup.tenant_id)
+        self.assertEqual(secgroup.description, sg_desc)
+        self.set_resource(sg_name, secgroup)
+        return secgroup
+
+    def _default_security_group(self, tenant_id, client=None):
+        """Get default secgroup for given tenant_id.
+
+        :returns: DeletableSecurityGroup -- default secgroup for given tenant
+        """
+        if client is None:
+            client = self.network_client
+        sgs = [
+            sg for sg in client.list_security_groups().values()[0]
+            if sg['tenant_id'] == tenant_id and sg['name'] == 'default'
+        ]
+        msg = "No default security group for tenant %s." % (tenant_id)
+        self.assertTrue(len(sgs) > 0, msg)
+        if len(sgs) > 1:
+            msg = "Found %d default security groups" % len(sgs)
+            raise exc.NeutronClientNoUniqueMatch(msg=msg)
+        return net_common.DeletableSecurityGroup(client=client,
+                                                 **sgs[0])
+
+    def _create_security_group_rule(self, client=None, secgroup=None,
+                                    tenant_id=None, **kwargs):
+        """Create a rule from a dictionary of rule parameters.
+
+        Create a rule in a secgroup. if secgroup not defined will search for
+        default secgroup in tenant_id.
+
+        :param secgroup: type DeletableSecurityGroup.
+        :param secgroup_id: search for secgroup by id
+            default -- choose default secgroup for given tenant_id
+        :param tenant_id: if secgroup not passed -- the tenant in which to
+            search for default secgroup
+        :param kwargs: a dictionary containing rule parameters:
+            for example, to allow incoming ssh:
+            rule = {
+                    direction: 'ingress'
+                    protocol:'tcp',
+                    port_range_min: 22,
+                    port_range_max: 22
+                    }
+        """
+        if client is None:
+            client = self.network_client
+        if secgroup is None:
+            secgroup = self._default_security_group(tenant_id)
+
+        ruleset = dict(security_group_id=secgroup.id,
+                       tenant_id=secgroup.tenant_id,
+                       )
+        ruleset.update(kwargs)
+
+        body = dict(security_group_rule=dict(ruleset))
+        sg_rule = client.create_security_group_rule(body=body)
+        sg_rule = net_common.DeletableSecurityGroupRule(
+            client=client,
+            **sg_rule['security_group_rule']
+        )
+        self.set_resource(sg_rule.id, sg_rule)
+        self.assertEqual(secgroup.tenant_id, sg_rule.tenant_id)
+        self.assertEqual(secgroup.id, sg_rule.security_group_id)
+
+        return sg_rule
+
+    def _create_loginable_secgroup_rule_neutron(self, client=None,
+                                                secgroup=None):
+        """These rules are intended to permit inbound ssh and icmp
+        traffic from all sources, so no group_id is provided.
+        Setting a group_id would only permit traffic from ports
+        belonging to the same security group.
+        """
+
+        if client is None:
+            client = self.network_client
+        rules = []
+        rulesets = [
+            dict(
+                # ssh
+                protocol='tcp',
+                port_range_min=22,
+                port_range_max=22,
+            ),
+            dict(
+                # ping
+                protocol='icmp',
+            )
+        ]
+        for ruleset in rulesets:
+            for r_direction in ['ingress', 'egress']:
+                ruleset['direction'] = r_direction
+                try:
+                    sg_rule = self._create_security_group_rule(
+                        client=client, secgroup=secgroup, **ruleset)
+                except exc.NeutronClientException as ex:
+                    # if rule already exist - skip rule and continue
+                    if not (ex.status_code is 409 and 'Security group rule'
+                            ' already exists' in ex.message):
+                        raise ex
+                else:
+                    self.assertEqual(r_direction, sg_rule.direction)
+                    rules.append(sg_rule)
+
+        return rules
+
 
 class OrchestrationScenarioTest(OfficialClientTest):
     """
diff --git a/tempest/scenario/test_large_ops.py b/tempest/scenario/test_large_ops.py
index 30c223f..7f8d3e4 100644
--- a/tempest/scenario/test_large_ops.py
+++ b/tempest/scenario/test_large_ops.py
@@ -85,7 +85,7 @@
         name = data_utils.rand_name('scenario-server-')
         client = self.compute_client
         flavor_id = self.config.compute.flavor_ref
-        secgroup = self._create_security_group()
+        secgroup = self._create_security_group_nova()
         self.servers = client.servers.create(
             name=name, image=self.image,
             flavor=flavor_id,
diff --git a/tempest/scenario/test_minimum_basic.py b/tempest/scenario/test_minimum_basic.py
index 9cc8541..8a51cd1 100644
--- a/tempest/scenario/test_minimum_basic.py
+++ b/tempest/scenario/test_minimum_basic.py
@@ -161,7 +161,7 @@
 
         self.nova_floating_ip_create()
         self.nova_floating_ip_add()
-        self.create_loginable_secgroup_rule()
+        self._create_loginable_secgroup_rule_nova()
         self.ssh_to_server()
         self.check_partitions()
 
diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
index a7618b1..bfded53 100644
--- a/tempest/scenario/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -164,7 +164,8 @@
             name=data_utils.rand_name('keypair-smoke-'))
 
     def _create_security_groups(self):
-        self.security_groups[self.tenant_id] = self._create_security_group()
+        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)
diff --git a/tempest/scenario/test_server_basic_ops.py b/tempest/scenario/test_server_basic_ops.py
index 0b08f9c..1e1a310 100644
--- a/tempest/scenario/test_server_basic_ops.py
+++ b/tempest/scenario/test_server_basic_ops.py
@@ -50,7 +50,7 @@
         self.set_resource('secgroup', self.secgroup)
 
         # Add rules to the security group
-        self.create_loginable_secgroup_rule(secgroup_id=self.secgroup.id)
+        self._create_loginable_secgroup_rule_nova(secgroup_id=self.secgroup.id)
 
     def boot_instance(self):
         create_kwargs = {
diff --git a/tempest/scenario/test_snapshot_pattern.py b/tempest/scenario/test_snapshot_pattern.py
index ba347e0..00139f0 100644
--- a/tempest/scenario/test_snapshot_pattern.py
+++ b/tempest/scenario/test_snapshot_pattern.py
@@ -65,7 +65,7 @@
     def test_snapshot_pattern(self):
         # prepare for booting a instance
         self._add_keypair()
-        self.create_loginable_secgroup_rule()
+        self._create_loginable_secgroup_rule_nova()
 
         # boot a instance and create a timestamp file in it
         server = self._boot_image(self.config.compute.image_ref)
diff --git a/tempest/scenario/test_stamp_pattern.py b/tempest/scenario/test_stamp_pattern.py
index a8cedc7..5eac55c 100644
--- a/tempest/scenario/test_stamp_pattern.py
+++ b/tempest/scenario/test_stamp_pattern.py
@@ -146,7 +146,7 @@
     def test_stamp_pattern(self):
         # prepare for booting a instance
         self._add_keypair()
-        self.create_loginable_secgroup_rule()
+        self._create_loginable_secgroup_rule_nova()
 
         # boot an instance and create a timestamp file in it
         volume = self._create_volume()
diff --git a/tempest/scenario/test_volume_boot_pattern.py b/tempest/scenario/test_volume_boot_pattern.py
index 84846c1..fa9a228 100644
--- a/tempest/scenario/test_volume_boot_pattern.py
+++ b/tempest/scenario/test_volume_boot_pattern.py
@@ -120,7 +120,7 @@
     @services('compute', 'volume', 'image')
     def test_volume_boot_pattern(self):
         keypair = self.create_keypair()
-        self.create_loginable_secgroup_rule()
+        self._create_loginable_secgroup_rule_nova()
 
         # create an instance from volume
         volume_origin = self._create_volume_from_image()
diff --git a/tempest/services/compute/xml/flavors_client.py b/tempest/services/compute/xml/flavors_client.py
index 363c1a8..a1c74d9 100644
--- a/tempest/services/compute/xml/flavors_client.py
+++ b/tempest/services/compute/xml/flavors_client.py
@@ -43,6 +43,10 @@
     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
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/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/test-requirements.txt b/test-requirements.txt
index fbe7e43..41a784e 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -1,4 +1,4 @@
-hacking>=0.5.6,<0.8
+hacking>=0.8.0,<0.9
 # needed for doc build
 docutils==0.9.1
 sphinx>=1.1.2
diff --git a/tools/check_logs.py b/tools/check_logs.py
index ded51b4..6d4436e 100755
--- a/tools/check_logs.py
+++ b/tools/check_logs.py
@@ -125,8 +125,8 @@
         if is_neutron:
             print("Currently not failing neutron builds with errors")
             return 0
-        # Return non-zero to start failing builds
-        return 0
+        print("FAILED")
+        return 1
     else:
         print("ok")
         return 0
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):