Merge "Append some operations to boot from volume pattern"
diff --git a/HACKING.rst b/HACKING.rst
index 1eb2d4f..03e7dc3 100644
--- a/HACKING.rst
+++ b/HACKING.rst
@@ -68,16 +68,34 @@
  the ``self.fail`` line as the origin of the error.
 
 Avoid constructing complex boolean expressions for assertion.
-The ``self.assertTrue`` or ``self.assertFalse`` will just tell you the
-single boolean, and you will not know anything about the values used in
-the formula. Most other assert method can include more information.
+The ``self.assertTrue`` or ``self.assertFalse`` without a ``msg`` argument,
+will just tell you the single boolean value, and you will not know anything
+about the values used in the formula, the ``msg`` argument might be good enough
+for providing more information.
+
+Most other assert method can include more information by default.
 For example ``self.assertIn`` can include the whole set.
 
+Recommended to use testtools matcher for more tricky assertion.
+`[doc] <http://testtools.readthedocs.org/en/latest/for-test-authors.html#matchers>`_
+
+You can implement your own specific matcher as well.
+`[doc] <http://testtools.readthedocs.org/en/latest/for-test-authors.html#writing-your-own-matchers>`_
+
 If the test case fails you can see the related logs and the information
 carried by the exception (exception class, backtrack and exception info).
 This and the service logs are your only guide to find the root cause of flaky
 issue.
 
+Test cases are independent
+--------------------------
+Every ``test_method`` must be callable individually and MUST NOT depends on,
+any other ``test_method`` or ``test_method`` ordering.
+
+Test cases MAY depend on commonly initialized resources/facilities, like
+credentials management, testresources and so on. These facilities, MUST be able
+to work even if just one ``test_method`` selected for execution.
+
 Guidelines
 ----------
 - Do not submit changesets with only testcases which are skipped as
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index d39ef70..8d96858 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -76,10 +76,18 @@
 flavor_ref = 1
 flavor_ref_alt = 2
 
-# User names used to authenticate to an instance for a given image.
+# User name used to authenticate to an instance
 image_ssh_user = root
+
+# Password used to authenticate to an instance
+image_ssh_password = password
+
+# User name used to authenticate to an instance using the alternate image
 image_alt_ssh_user = root
 
+# Password used to authenticate to an instance using the alternate image
+image_alt_ssh_password = password
+
 # Number of seconds to wait while looping to check the status of an
 # instance that is building.
 build_interval = 10
@@ -93,7 +101,7 @@
 #  executing the tests
 run_ssh = false
 
-# Name of a user used to authenticated to an instance
+# Name of a user used to authenticate to an instance.
 ssh_user = cirros
 
 # Visible fixed network name
@@ -150,6 +158,9 @@
 # When set to false, flavor extra data tests are forced to skip
 flavor_extra_enabled = true
 
+# Expected first device name when a volume is attached to an instance
+volume_device_name = vdb
+
 [whitebox]
 # Whitebox options for compute. Whitebox options enable the
 # whitebox test cases, which look at internal Nova database state,
diff --git a/run_tests.sh b/run_tests.sh
index 856ce54..d672b62 100755
--- a/run_tests.sh
+++ b/run_tests.sh
@@ -124,7 +124,11 @@
 }
 
 function run_pep8 {
-  echo "Running pep8 ..."
+  echo "Running flake8 ..."
+  if [ $never_venv -eq 1 ]; then
+      echo "**WARNING**:" >&2
+      echo "Running flake8 without virtual env may miss OpenStack HACKING detection" >&2
+  fi
   ${wrapper} flake8
 }
 
diff --git a/tempest/api/compute/admin/test_aggregates.py b/tempest/api/compute/admin/test_aggregates.py
index 303bc0c..0bb0460 100644
--- a/tempest/api/compute/admin/test_aggregates.py
+++ b/tempest/api/compute/admin/test_aggregates.py
@@ -15,6 +15,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import fixtures
+
 from tempest.api.compute import base
 from tempest.common.utils.data_utils import rand_name
 from tempest import exceptions
@@ -22,6 +24,16 @@
 from tempest.test import attr
 
 
+class LockFixture(fixtures.Fixture):
+    def __init__(self, name):
+        self.mgr = lockutils.lock(name, 'tempest-', True)
+
+    def setUp(self):
+        super(LockFixture, self).setUp()
+        self.addCleanup(self.mgr.__exit__, None, None, None)
+        self.mgr.__enter__()
+
+
 class AggregatesAdminTestJSON(base.BaseComputeAdminTest):
 
     """
@@ -146,9 +158,9 @@
                           self.client.get_aggregate, -1)
 
     @attr(type='gate')
-    @lockutils.synchronized('availability_zone', 'tempest-', True)
     def test_aggregate_add_remove_host(self):
         # Add an host to the given aggregate and remove.
+        self.useFixture(LockFixture('availability_zone'))
         aggregate_name = rand_name(self.aggregate_name_prefix)
         resp, aggregate = self.client.create_aggregate(aggregate_name)
         self.addCleanup(self.client.delete_aggregate, aggregate['id'])
@@ -168,9 +180,9 @@
         self.assertNotIn(self.host, body['hosts'])
 
     @attr(type='gate')
-    @lockutils.synchronized('availability_zone', 'tempest-', True)
     def test_aggregate_add_host_list(self):
         # Add an host to the given aggregate and list.
+        self.useFixture(LockFixture('availability_zone'))
         aggregate_name = rand_name(self.aggregate_name_prefix)
         resp, aggregate = self.client.create_aggregate(aggregate_name)
         self.addCleanup(self.client.delete_aggregate, aggregate['id'])
@@ -186,9 +198,9 @@
         self.assertIn(self.host, agg['hosts'])
 
     @attr(type='gate')
-    @lockutils.synchronized('availability_zone', 'tempest-', True)
     def test_aggregate_add_host_get_details(self):
         # Add an host to the given aggregate and get details.
+        self.useFixture(LockFixture('availability_zone'))
         aggregate_name = rand_name(self.aggregate_name_prefix)
         resp, aggregate = self.client.create_aggregate(aggregate_name)
         self.addCleanup(self.client.delete_aggregate, aggregate['id'])
@@ -201,9 +213,9 @@
         self.assertIn(self.host, body['hosts'])
 
     @attr(type='gate')
-    @lockutils.synchronized('availability_zone', 'tempest-', True)
     def test_aggregate_add_host_create_server_with_az(self):
         # Add an host to the given aggregate and create a server.
+        self.useFixture(LockFixture('availability_zone'))
         aggregate_name = rand_name(self.aggregate_name_prefix)
         az_name = rand_name(self.az_name_prefix)
         resp, aggregate = self.client.create_aggregate(aggregate_name, az_name)
@@ -248,9 +260,9 @@
                           aggregate['id'], self.host)
 
     @attr(type=['negative', 'gate'])
-    @lockutils.synchronized('availability_zone', 'tempest-', True)
     def test_aggregate_remove_host_as_user(self):
         # Regular user is not allowed to remove a host from an aggregate.
+        self.useFixture(LockFixture('availability_zone'))
         aggregate_name = rand_name(self.aggregate_name_prefix)
         resp, aggregate = self.client.create_aggregate(aggregate_name)
         self.addCleanup(self.client.delete_aggregate, aggregate['id'])
diff --git a/tempest/api/compute/admin/test_flavors.py b/tempest/api/compute/admin/test_flavors.py
index 5f31084..7efd3c1 100644
--- a/tempest/api/compute/admin/test_flavors.py
+++ b/tempest/api/compute/admin/test_flavors.py
@@ -296,6 +296,24 @@
         _test_string_variations(['t', 'true', 'yes', '1'],
                                 flavor_name_public)
 
+    @attr(type='gate')
+    def test_create_flavor_using_string_ram(self):
+        flavor_name = rand_name(self.flavor_name_prefix)
+        new_flavor_id = rand_int_id(start=1000)
+
+        ram = " 1024 "
+        resp, flavor = self.client.create_flavor(flavor_name,
+                                                 ram, self.vcpus,
+                                                 self.disk,
+                                                 new_flavor_id)
+        self.addCleanup(self.flavor_clean_up, flavor['id'])
+        self.assertEqual(200, resp.status)
+        self.assertEqual(flavor['name'], flavor_name)
+        self.assertEqual(flavor['vcpus'], self.vcpus)
+        self.assertEqual(flavor['disk'], self.disk)
+        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,
@@ -319,6 +337,26 @@
                           self.user_client.delete_flavor,
                           self.flavor_ref_alt)
 
+    @attr(type=['negative', 'gate'])
+    def test_create_flavor_using_invalid_ram(self):
+        flavor_name = rand_name(self.flavor_name_prefix)
+        new_flavor_id = 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 = rand_name(self.flavor_name_prefix)
+        new_flavor_id = 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_extra_specs.py b/tempest/api/compute/admin/test_flavors_extra_specs.py
index 7b79a12..f2f82b5 100644
--- a/tempest/api/compute/admin/test_flavors_extra_specs.py
+++ b/tempest/api/compute/admin/test_flavors_extra_specs.py
@@ -58,6 +58,7 @@
     @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()
 
     @attr(type='gate')
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index acf0275..09d9bc0 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -73,6 +73,8 @@
         cls.build_interval = cls.config.compute.build_interval
         cls.build_timeout = cls.config.compute.build_timeout
         cls.ssh_user = cls.config.compute.ssh_user
+        cls.image_ssh_user = cls.config.compute.image_ssh_user
+        cls.image_ssh_password = cls.config.compute.image_ssh_password
         cls.image_ref = cls.config.compute.image_ref
         cls.image_ref_alt = cls.config.compute.image_ref_alt
         cls.flavor_ref = cls.config.compute.flavor_ref
diff --git a/tempest/api/compute/images/test_images_oneserver.py b/tempest/api/compute/images/test_images_oneserver.py
index 0052a30..06e9ab2 100644
--- a/tempest/api/compute/images/test_images_oneserver.py
+++ b/tempest/api/compute/images/test_images_oneserver.py
@@ -64,7 +64,7 @@
                 cls.alt_manager = clients.AltManager()
             cls.alt_client = cls.alt_manager.images_client
 
-    @testtools.skip("Until Bug #1006725 is fixed")
+    @testtools.skip("Skipped until the Bug #1006725 is resolved.")
     @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
diff --git a/tempest/api/compute/servers/test_list_server_filters.py b/tempest/api/compute/servers/test_list_server_filters.py
index ade7604..8d31598 100644
--- a/tempest/api/compute/servers/test_list_server_filters.py
+++ b/tempest/api/compute/servers/test_list_server_filters.py
@@ -205,7 +205,7 @@
         self.assertNotIn(self.s2_name, map(lambda x: x['name'], servers))
         self.assertNotIn(self.s3_name, map(lambda x: x['name'], servers))
 
-    @testtools.skip('Until Bug #1170718 is resolved.')
+    @testtools.skip('Skipped until the Bug #1170718 is resolved.')
     @attr(type='gate')
     def test_list_servers_filtered_by_ip(self):
         # Filter servers by ip
diff --git a/tempest/api/compute/servers/test_server_actions.py b/tempest/api/compute/servers/test_server_actions.py
index 25df6e6..5ea771b 100644
--- a/tempest/api/compute/servers/test_server_actions.py
+++ b/tempest/api/compute/servers/test_server_actions.py
@@ -86,7 +86,7 @@
             new_boot_time = linux_client.get_boot_time()
             self.assertGreater(new_boot_time, boot_time)
 
-    @testtools.skip('Until Bug #1014647 is dealt with.')
+    @testtools.skip('Skipped until the Bug #1014647 is resolved.')
     @attr(type='smoke')
     def test_reboot_server_soft(self):
         # The server should be signaled to reboot gracefully
@@ -225,7 +225,7 @@
             resp, output = self.servers_client.get_console_output(
                 self.server_id, 10)
             self.assertEqual(200, resp.status)
-            self.assertIsNotNone(output)
+            self.assertTrue(output, "Console output was empty.")
             lines = len(output.split('\n'))
             self.assertEqual(lines, 10)
         self.wait_for(get_output)
@@ -238,7 +238,7 @@
                           self.servers_client.get_console_output,
                           '!@#$%^&*()', 10)
 
-    @testtools.skip('Until tempest Bug #1014683 is fixed.')
+    @testtools.skip('Skipped until the Bug #1014683 is resolved.')
     @attr(type='gate')
     def test_get_console_output_server_id_in_reboot_status(self):
         # Positive test:Should be able to GET the console output
diff --git a/tempest/api/compute/servers/test_virtual_interfaces.py b/tempest/api/compute/servers/test_virtual_interfaces.py
index e5ea30e..b743a85 100644
--- a/tempest/api/compute/servers/test_virtual_interfaces.py
+++ b/tempest/api/compute/servers/test_virtual_interfaces.py
@@ -37,8 +37,8 @@
         resp, server = cls.create_server(wait_until='ACTIVE')
         cls.server_id = server['id']
 
-    @testtools.skipIf(CONF.service_available.neutron, "This feature is not " +
-                      "implemented by Neutron. See bug: #1183436")
+    @testtools.skipIf(CONF.service_available.neutron, "Not implemented by " +
+                      "Neutron. Skipped until the Bug #1183436 is resolved.")
     @attr(type='gate')
     def test_list_virtual_interfaces(self):
         # Positive test:Should be able to GET the virtual interfaces list
diff --git a/tempest/api/compute/volumes/test_attach_volume.py b/tempest/api/compute/volumes/test_attach_volume.py
index b67a5e0..ee1ad9e 100644
--- a/tempest/api/compute/volumes/test_attach_volume.py
+++ b/tempest/api/compute/volumes/test_attach_volume.py
@@ -36,7 +36,7 @@
     @classmethod
     def setUpClass(cls):
         super(AttachVolumeTestJSON, cls).setUpClass()
-        cls.device = 'vdb'
+        cls.device = cls.config.compute.volume_device_name
         if not cls.config.service_available.cinder:
             skip_msg = ("%s skipped as Cinder is not available" % cls.__name__)
             raise cls.skipException(skip_msg)
@@ -54,7 +54,7 @@
     def _create_and_attach(self):
         # Start a server and wait for it to become ready
         resp, server = self.create_server(wait_until='ACTIVE',
-                                          adminPass='password')
+                                          adminPass=self.image_ssh_password)
         self.server = server
 
         # Record addresses so that we can ssh later
@@ -92,7 +92,7 @@
         self.servers_client.wait_for_server_status(server['id'], 'ACTIVE')
 
         linux_client = RemoteClient(server,
-                                    self.ssh_user, server['adminPass'])
+                                    self.image_ssh_user, server['adminPass'])
         partitions = linux_client.get_partitions()
         self.assertIn(self.device, partitions)
 
@@ -106,7 +106,7 @@
         self.servers_client.wait_for_server_status(server['id'], 'ACTIVE')
 
         linux_client = RemoteClient(server,
-                                    self.ssh_user, server['adminPass'])
+                                    self.image_ssh_user, server['adminPass'])
         partitions = linux_client.get_partitions()
         self.assertNotIn(self.device, partitions)
 
diff --git a/tempest/api/network/test_floating_ips.py b/tempest/api/network/test_floating_ips.py
new file mode 100644
index 0000000..017864f
--- /dev/null
+++ b/tempest/api/network/test_floating_ips.py
@@ -0,0 +1,135 @@
+# 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.network import base
+from tempest.common.utils.data_utils import rand_name
+from tempest.test import attr
+
+
+class FloatingIPTest(base.BaseNetworkTest):
+    _interface = 'json'
+
+    """
+    Tests the following operations in the Quantum API using the REST client for
+    Quantum:
+
+        Create a Floating IP
+        Update a Floating IP
+        Delete a Floating IP
+        List all Floating IPs
+        Show Floating IP details
+
+    v2.0 of the Quantum API is assumed. It is also assumed that the following
+    options are defined in the [network] section of etc/tempest.conf:
+
+        public_network_id which is the id for the external network present
+    """
+
+    @classmethod
+    def setUpClass(cls):
+        super(FloatingIPTest, cls).setUpClass()
+        cls.ext_net_id = cls.config.network.public_network_id
+
+        # Create network, subnet, router and add interface
+        cls.network = cls.create_network()
+        cls.subnet = cls.create_subnet(cls.network)
+        resp, router = cls.client.create_router(
+            rand_name('router-'),
+            external_gateway_info={"network_id":
+                                   cls.network_cfg.public_network_id})
+        cls.router = router['router']
+        resp, _ = cls.client.add_router_interface_with_subnet_id(
+            cls.router['id'], cls.subnet['id'])
+        cls.port = list()
+        # Create two ports one each for Creation and Updating of floatingIP
+        for i in range(2):
+            resp, port = cls.client.create_port(cls.network['id'])
+            cls.port.append(port['port'])
+
+    @classmethod
+    def tearDownClass(cls):
+        cls.client.remove_router_interface_with_subnet_id(cls.router['id'],
+                                                          cls.subnet['id'])
+        for i in range(2):
+            cls.client.delete_port(cls.port[i]['id'])
+        cls.client.delete_router(cls.router['id'])
+        super(FloatingIPTest, cls).tearDownClass()
+
+    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)
+        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()
+        floatingip_id_list = list()
+        for f in floating_ips['floatingips']:
+            floatingip_id_list.append(f['id'])
+        self.assertNotIn(floating_ip_id, floatingip_id_list)
+
+    @attr(type='smoke')
+    def test_create_list_show_update_delete_floating_ip(self):
+        # Creates a floating IP
+        resp, floating_ip = self.client.create_floating_ip(
+            self.ext_net_id, port_id=self.port[0]['id'])
+        self.assertEqual('201', resp['status'])
+        create_floating_ip = floating_ip['floatingip']
+        self.assertIsNotNone(create_floating_ip['id'])
+        self.assertIsNotNone(create_floating_ip['tenant_id'])
+        self.assertIsNotNone(create_floating_ip['floating_ip_address'])
+        self.assertEqual(create_floating_ip['port_id'], self.port[0]['id'])
+        self.assertEqual(create_floating_ip['floating_network_id'],
+                         self.ext_net_id)
+        self.addCleanup(self._delete_floating_ip, create_floating_ip['id'])
+        # Verifies the details of a floating_ip
+        resp, floating_ip = self.client.show_floating_ip(
+            create_floating_ip['id'])
+        self.assertEqual('200', resp['status'])
+        show_floating_ip = floating_ip['floatingip']
+        self.assertEqual(show_floating_ip['id'], create_floating_ip['id'])
+        self.assertEqual(show_floating_ip['floating_network_id'],
+                         self.ext_net_id)
+        self.assertEqual(show_floating_ip['tenant_id'],
+                         create_floating_ip['tenant_id'])
+        self.assertEqual(show_floating_ip['floating_ip_address'],
+                         create_floating_ip['floating_ip_address'])
+        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()
+        self.assertEqual('200', resp['status'])
+        floatingip_id_list = list()
+        for f in floating_ips['floatingips']:
+            floatingip_id_list.append(f['id'])
+        self.assertIn(create_floating_ip['id'], floatingip_id_list)
+
+        # Associate floating IP to the other port
+        resp, floating_ip = self.client.update_floating_ip(
+            create_floating_ip['id'], port_id=self.port[1]['id'])
+        self.assertEqual('200', resp['status'])
+        update_floating_ip = floating_ip['floatingip']
+        self.assertEqual(update_floating_ip['port_id'], self.port[1]['id'])
+        self.assertIsNotNone(update_floating_ip['fixed_ip_address'])
+        self.assertEqual(update_floating_ip['router_id'], self.router['id'])
+
+        # Disassociate floating IP from the port
+        resp, floating_ip = self.client.update_floating_ip(
+            create_floating_ip['id'], port_id=None)
+        self.assertEqual('200', resp['status'])
+        update_floating_ip = floating_ip['floatingip']
+        self.assertIsNone(update_floating_ip['port_id'])
+        self.assertIsNone(update_floating_ip['fixed_ip_address'])
+        self.assertIsNone(update_floating_ip['router_id'])
diff --git a/tempest/api/network/test_networks.py b/tempest/api/network/test_networks.py
index 7f49452..f3d1485 100644
--- a/tempest/api/network/test_networks.py
+++ b/tempest/api/network/test_networks.py
@@ -75,7 +75,7 @@
         for n in created_networks:
             self.assertNotIn(n['id'], networks_list)
 
-    @attr(type='gate')
+    @attr(type='smoke')
     def test_create_update_delete_network_subnet(self):
         # Creates a network
         name = rand_name('network-')
@@ -116,7 +116,7 @@
         resp, body = self.client.delete_network(net_id)
         self.assertEqual('204', resp['status'])
 
-    @attr(type='gate')
+    @attr(type='smoke')
     def test_show_network(self):
         # Verifies the details of a network
         resp, body = self.client.show_network(self.network['id'])
@@ -125,7 +125,7 @@
         self.assertEqual(self.network['id'], network['id'])
         self.assertEqual(self.name, network['name'])
 
-    @attr(type='gate')
+    @attr(type='smoke')
     def test_list_networks(self):
         # Verify the network exists in the list of all networks
         resp, body = self.client.list_networks()
@@ -138,7 +138,7 @@
         msg = "Network list doesn't contain created network"
         self.assertIsNotNone(found, msg)
 
-    @attr(type='gate')
+    @attr(type='smoke')
     def test_show_subnet(self):
         # Verifies the details of a subnet
         resp, body = self.client.show_subnet(self.subnet['id'])
@@ -147,7 +147,7 @@
         self.assertEqual(self.subnet['id'], subnet['id'])
         self.assertEqual(self.cidr, subnet['cidr'])
 
-    @attr(type='gate')
+    @attr(type='smoke')
     def test_list_subnets(self):
         # Verify the subnet exists in the list of all subnets
         resp, body = self.client.list_subnets()
@@ -160,7 +160,7 @@
         msg = "Subnet list doesn't contain created subnet"
         self.assertIsNotNone(found, msg)
 
-    @attr(type='gate')
+    @attr(type='smoke')
     def test_create_update_delete_port(self):
         # Verify that successful port creation, update & deletion
         resp, body = self.client.create_port(self.network['id'])
@@ -176,7 +176,7 @@
         resp, body = self.client.delete_port(port['id'])
         self.assertEqual('204', resp['status'])
 
-    @attr(type='gate')
+    @attr(type='smoke')
     def test_show_port(self):
         # Verify the details of port
         resp, body = self.client.show_port(self.port['id'])
@@ -184,7 +184,7 @@
         port = body['port']
         self.assertEqual(self.port['id'], port['id'])
 
-    @attr(type='gate')
+    @attr(type='smoke')
     def test_list_ports(self):
         # Verify the port exists in the list of all ports
         resp, body = self.client.list_ports()
@@ -196,19 +196,19 @@
                 found = n['id']
         self.assertIsNotNone(found, "Port list doesn't contain created port")
 
-    @attr(type=['negative', 'gate'])
+    @attr(type=['negative', 'smoke'])
     def test_show_non_existent_network(self):
         non_exist_id = rand_name('network')
         self.assertRaises(exceptions.NotFound, self.client.show_network,
                           non_exist_id)
 
-    @attr(type=['negative', 'gate'])
+    @attr(type=['negative', 'smoke'])
     def test_show_non_existent_subnet(self):
         non_exist_id = rand_name('subnet')
         self.assertRaises(exceptions.NotFound, self.client.show_subnet,
                           non_exist_id)
 
-    @attr(type='gate')
+    @attr(type='smoke')
     def test_bulk_create_delete_network(self):
         # Creates 2 networks in one request
         network_names = [rand_name('network-'), rand_name('network-')]
diff --git a/tempest/api/network/test_routers.py b/tempest/api/network/test_routers.py
index 4f687b0..9f8c742 100644
--- a/tempest/api/network/test_routers.py
+++ b/tempest/api/network/test_routers.py
@@ -49,7 +49,7 @@
             router_id, port_id)
         self.assertEqual('200', resp['status'])
 
-    @attr(type='gate')
+    @attr(type='smoke')
     def test_create_show_list_update_delete_router(self):
         # Create a router
         name = rand_name('router-')
@@ -90,7 +90,7 @@
             create_body['router']['id'])
         self.assertEqual(show_body['router']['name'], updated_name)
 
-    @attr(type='gate')
+    @attr(type='smoke')
     def test_add_remove_router_interface_with_subnet_id(self):
         network = self.create_network()
         subnet = self.create_subnet(network)
@@ -111,7 +111,7 @@
         self.assertEqual(show_port_body['port']['device_id'],
                          create_body['router']['id'])
 
-    @attr(type='gate')
+    @attr(type='smoke')
     def test_add_remove_router_interface_with_port_id(self):
         network = self.create_network()
         self.create_subnet(network)
diff --git a/tempest/api/object_storage/test_container_staticweb.py b/tempest/api/object_storage/test_container_staticweb.py
new file mode 100644
index 0000000..d07697a
--- /dev/null
+++ b/tempest/api/object_storage/test_container_staticweb.py
@@ -0,0 +1,94 @@
+# Copyright (C) 2013 eNovance SAS <licensing@enovance.com>
+#
+# Author: Joe H. Rahme <joe.hakim.rahme@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.
+
+from tempest.api.object_storage import base
+from tempest.common.utils.data_utils import arbitrary_string
+from tempest.common.utils.data_utils import rand_name
+from tempest.test import attr
+
+
+class StaticWebTest(base.BaseObjectTest):
+
+    @classmethod
+    def setUpClass(cls):
+        super(StaticWebTest, cls).setUpClass()
+        cls.container_name = rand_name(name="TestContainer")
+
+        # This header should be posted on the container before every test
+        cls.headers_public_read_acl = {'Read': '.r:*'}
+
+        # Create test container and create one object in it
+        cls.container_client.create_container(cls.container_name)
+        cls.object_name = rand_name(name="TestObject")
+        cls.object_data = arbitrary_string()
+        cls.object_client.create_object(cls.container_name,
+                                        cls.object_name,
+                                        cls.object_data)
+
+        cls.container_client.update_container_metadata(
+            cls.container_name,
+            metadata=cls.headers_public_read_acl,
+            metadata_prefix="X-Container-")
+
+    @classmethod
+    def tearDownClass(cls):
+        cls.delete_containers([cls.container_name])
+        cls.data.teardown_all()
+        super(StaticWebTest, cls).tearDownClass()
+
+    @attr('gate')
+    def test_web_index(self):
+        headers = {'web-index': self.object_name}
+
+        self.container_client.update_container_metadata(
+            self.container_name, metadata=headers)
+
+        # test GET on http://account_url/container_name
+        # 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.assertEqual(body, self.object_data)
+
+        # clean up before exiting
+        self.container_client.update_container_metadata(self.container_name,
+                                                        {'web-index': ""})
+
+        _, body = self.container_client.list_container_metadata(
+            self.container_name)
+        self.assertNotIn('x-container-meta-web-index', body)
+
+    @attr('gate')
+    def test_web_listing(self):
+        headers = {'web-listings': 'true'}
+
+        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.assertEqual(resp['status'], '200')
+        self.assertIn(self.object_name, body)
+
+        # clean up before exiting
+        self.container_client.update_container_metadata(self.container_name,
+                                                        {'web-listings': ""})
+
+        _, body = self.container_client.list_container_metadata(
+            self.container_name)
+        self.assertNotIn('x-container-meta-web-listings', body)
diff --git a/tempest/api/object_storage/test_container_sync.py b/tempest/api/object_storage/test_container_sync.py
index d18c2ad..66a74e4 100644
--- a/tempest/api/object_storage/test_container_sync.py
+++ b/tempest/api/object_storage/test_container_sync.py
@@ -52,7 +52,7 @@
             cls.delete_containers(cls.containers, client[0], client[1])
         super(ContainerSyncTest, cls).tearDownClass()
 
-    @testtools.skip('Until Bug #1093743 is resolved.')
+    @testtools.skip('Skipped until the Bug #1093743 is resolved.')
     @attr(type='gate')
     def test_container_synchronization(self):
         # container to container synchronization
diff --git a/tempest/api/object_storage/test_object_expiry.py b/tempest/api/object_storage/test_object_expiry.py
index 8703480..889436d 100644
--- a/tempest/api/object_storage/test_object_expiry.py
+++ b/tempest/api/object_storage/test_object_expiry.py
@@ -43,7 +43,7 @@
         cls.delete_containers([cls.container_name])
         super(ObjectExpiryTest, cls).tearDownClass()
 
-    @testtools.skip('Until Bug #1069849 is resolved.')
+    @testtools.skip('Skipped until the Bug #1069849 is resolved.')
     @attr(type='gate')
     def test_get_object_after_expiry_time(self):
         # TODO(harika-vakadi): similar test case has to be created for
diff --git a/tempest/api/orchestration/stacks/test_instance_cfn_init.py b/tempest/api/orchestration/stacks/test_server_cfn_init.py
similarity index 90%
rename from tempest/api/orchestration/stacks/test_instance_cfn_init.py
rename to tempest/api/orchestration/stacks/test_server_cfn_init.py
index fe55ecf..ffe8def 100644
--- a/tempest/api/orchestration/stacks/test_instance_cfn_init.py
+++ b/tempest/api/orchestration/stacks/test_server_cfn_init.py
@@ -26,7 +26,7 @@
 LOG = logging.getLogger(__name__)
 
 
-class InstanceCfnInitTestJSON(base.BaseOrchestrationTest):
+class ServerCfnInitTestJSON(base.BaseOrchestrationTest):
     _interface = 'json'
     existing_keypair = (tempest.config.TempestConfig().
                         orchestration.keypair_name is not None)
@@ -37,11 +37,11 @@
   Template which uses a wait condition to confirm that a minimal
   cfn-init and cfn-signal has worked
 Parameters:
-  KeyName:
+  key_name:
     Type: String
-  InstanceType:
+  flavor:
     Type: String
-  ImageId:
+  image:
     Type: String
 Resources:
   CfnUser:
@@ -58,7 +58,7 @@
     Properties:
       UserName: {Ref: CfnUser}
   SmokeServer:
-    Type: AWS::EC2::Instance
+    Type: OS::Nova::Server
     Metadata:
       AWS::CloudFormation::Init:
         config:
@@ -83,12 +83,12 @@
               owner: root
               group: root
     Properties:
-      ImageId: {Ref: ImageId}
-      InstanceType: {Ref: InstanceType}
-      KeyName: {Ref: KeyName}
-      SecurityGroups:
+      image: {Ref: image}
+      flavor: {Ref: flavor}
+      key_name: {Ref: key_name}
+      security_groups:
       - {Ref: SmokeSecurityGroup}
-      UserData:
+      user_data:
         Fn::Base64:
           Fn::Join:
           - ''
@@ -118,12 +118,12 @@
   SmokeServerIp:
     Description: IP address of server
     Value:
-      Fn::GetAtt: [SmokeServer, PublicIp]
+      Fn::GetAtt: [SmokeServer, first_private_address]
 """
 
     @classmethod
     def setUpClass(cls):
-        super(InstanceCfnInitTestJSON, cls).setUpClass()
+        super(ServerCfnInitTestJSON, cls).setUpClass()
         if not cls.orchestration_cfg.image_ref:
             raise cls.skipException("No image available to test")
         cls.client = cls.orchestration_client
@@ -140,9 +140,9 @@
             stack_name,
             cls.template,
             parameters={
-                'KeyName': keypair_name,
-                'InstanceType': cls.orchestration_cfg.instance_type,
-                'ImageId': cls.orchestration_cfg.image_ref
+                'key_name': keypair_name,
+                'flavor': cls.orchestration_cfg.instance_type,
+                'image': cls.orchestration_cfg.image_ref
             })
 
     @attr(type='slow')
@@ -187,7 +187,7 @@
         # This is an assert of great significance, as it means the following
         # has happened:
         # - cfn-init read the provided metadata and wrote out a file
-        # - a user was created and credentials written to the instance
+        # - a user was created and credentials written to the server
         # - a cfn-signal was built which was signed with provided credentials
         # - the wait condition was fulfilled and the stack has changed state
         wait_status = json.loads(
diff --git a/tempest/api/volume/admin/test_volume_types.py b/tempest/api/volume/admin/test_volume_types.py
index 822f691..b15f8dd 100644
--- a/tempest/api/volume/admin/test_volume_types.py
+++ b/tempest/api/volume/admin/test_volume_types.py
@@ -41,6 +41,7 @@
     def _delete_volume(self, volume_id):
         resp, _ = self.volumes_client.delete_volume(volume_id)
         self.assertEqual(202, resp.status)
+        self.volumes_client.wait_for_resource_deletion(volume_id)
 
     def _delete_volume_type(self, volume_type_id):
         resp, _ = self.client.delete_volume_type(volume_type_id)
diff --git a/tempest/api/volume/test_volumes_actions.py b/tempest/api/volume/test_volumes_actions.py
index 9fa86b6..960785d 100644
--- a/tempest/api/volume/test_volumes_actions.py
+++ b/tempest/api/volume/test_volumes_actions.py
@@ -86,7 +86,7 @@
         resp, volume = self.client.get_volume(self.volume['id'])
         self.assertEqual(200, resp.status)
         self.assertIn('attachments', volume)
-        attachment = volume['attachments'][0]
+        attachment = self.client.get_attachment_from_volume(volume)
         self.assertEqual(mountpoint, attachment['device'])
         self.assertEqual(self.server['id'], attachment['server_id'])
         self.assertEqual(self.volume['id'], attachment['id'])
@@ -105,3 +105,7 @@
         self.assertEqual(202, resp.status)
         self.image_client.wait_for_image_status(image_id, 'active')
         self.client.wait_for_volume_status(self.volume['id'], 'available')
+
+
+class VolumesActionsTestXML(VolumesActionsTest):
+    _interface = "xml"
diff --git a/tempest/api/volume/test_volumes_list.py b/tempest/api/volume/test_volumes_list.py
index 5d5fd7e..8c39e08 100644
--- a/tempest/api/volume/test_volumes_list.py
+++ b/tempest/api/volume/test_volumes_list.py
@@ -32,6 +32,19 @@
 
     _interface = 'json'
 
+    def assertVolumesIn(self, fetched_list, expected_list):
+        missing_vols = [v for v in expected_list if v not in fetched_list]
+        if len(missing_vols) == 0:
+            return
+
+        def str_vol(vol):
+            return "%s:%s" % (vol['id'], vol['display_name'])
+
+        raw_msg = "Could not find volumes %s in expected list %s; fetched %s"
+        self.fail(raw_msg % ([str_vol(v) for v in missing_vols],
+                             [str_vol(v) for v in expected_list],
+                             [str_vol(v) for v in fetched_list]))
+
     @classmethod
     def setUpClass(cls):
         super(VolumesListTest, cls).setUpClass()
@@ -82,12 +95,7 @@
         # Fetch all volumes
         resp, fetched_list = self.client.list_volumes()
         self.assertEqual(200, resp.status)
-        # Now check if all the volumes created in setup are in fetched list
-        missing_vols = [v for v in self.volume_list if v not in fetched_list]
-        self.assertFalse(missing_vols,
-                         "Failed to find volume %s in fetched list" %
-                         ', '.join(m_vol['display_name']
-                                   for m_vol in missing_vols))
+        self.assertVolumesIn(fetched_list, self.volume_list)
 
     @attr(type='gate')
     def test_volume_list_with_details(self):
@@ -95,12 +103,7 @@
         # Fetch all Volumes
         resp, fetched_list = self.client.list_volumes_with_detail()
         self.assertEqual(200, resp.status)
-        # Verify that all the volumes are returned
-        missing_vols = [v for v in self.volume_list if v not in fetched_list]
-        self.assertFalse(missing_vols,
-                         "Failed to find volume %s in fetched list" %
-                         ', '.join(m_vol['display_name']
-                                   for m_vol in missing_vols))
+        self.assertVolumesIn(fetched_list, self.volume_list)
 
 
 class VolumeListTestXML(VolumesListTest):
diff --git a/tempest/common/ssh.py b/tempest/common/ssh.py
index 2ed1057..2052705 100644
--- a/tempest/common/ssh.py
+++ b/tempest/common/ssh.py
@@ -56,7 +56,7 @@
             paramiko.AutoAddPolicy())
         _start_time = time.time()
 
-        while not self._is_timed_out(self.timeout, _start_time):
+        while not self._is_timed_out(_start_time):
             try:
                 ssh.connect(self.host, username=self.username,
                             password=self.password,
@@ -76,8 +76,8 @@
                                         password=self.password)
         return ssh
 
-    def _is_timed_out(self, timeout, start_time):
-        return (time.time() - timeout) > start_time
+    def _is_timed_out(self, start_time):
+        return (time.time() - self.timeout) > start_time
 
     def connect_until_closed(self):
         """Connect to the server and wait until connection is lost."""
@@ -85,10 +85,10 @@
             ssh = self._get_ssh_connection()
             _transport = ssh.get_transport()
             _start_time = time.time()
-            _timed_out = self._is_timed_out(self.timeout, _start_time)
+            _timed_out = self._is_timed_out(_start_time)
             while _transport.is_active() and not _timed_out:
                 time.sleep(5)
-                _timed_out = self._is_timed_out(self.timeout, _start_time)
+                _timed_out = self._is_timed_out(_start_time)
             ssh.close()
         except (EOFError, paramiko.AuthenticationException, socket.error):
             return
@@ -119,7 +119,7 @@
         while True:
             ready = poll.poll(self.channel_timeout)
             if not any(ready):
-                if not self._is_timed_out(self.timeout, start_time):
+                if not self._is_timed_out(start_time):
                     continue
                 raise exceptions.TimeoutException(
                     "Command: '{0}' executed on host '{1}'.".format(
diff --git a/tempest/config.py b/tempest/config.py
index 3b09b5e..7245b10 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -121,10 +121,17 @@
     cfg.StrOpt('image_ssh_user',
                default="root",
                help="User name used to authenticate to an instance."),
+    cfg.StrOpt('image_ssh_password',
+               default="password",
+               help="Password used to authenticate to an instance."),
     cfg.StrOpt('image_alt_ssh_user',
                default="root",
                help="User name used to authenticate to an instance using "
                     "the alternate image."),
+    cfg.StrOpt('image_alt_ssh_password',
+               default="password",
+               help="Password used to authenticate to an instance using "
+                    "the alternate image."),
     cfg.BoolOpt('resize_available',
                 default=False,
                 help="Does the test environment support resizing?"),
@@ -196,6 +203,10 @@
     cfg.BoolOpt('flavor_extra_enabled',
                 default=True,
                 help="If false, skip flavor extra data test"),
+    cfg.StrOpt('volume_device_name',
+               default='vdb',
+               help="Expected device name when a volume is attached to "
+                    "an instance")
 ]
 
 
diff --git a/tempest/exceptions.py b/tempest/exceptions.py
index 62bd8cf..924ebc9 100644
--- a/tempest/exceptions.py
+++ b/tempest/exceptions.py
@@ -65,6 +65,10 @@
     message = 'Unauthorized'
 
 
+class InvalidServiceTag(RestClientException):
+    message = "Invalid service tag"
+
+
 class TimeoutException(TempestException):
     message = "Request timed out"
 
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 83db76a..d3c2a18 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -392,7 +392,7 @@
             client = self.volume_client
         if name is None:
             name = rand_name('scenario-volume-')
-        LOG.debug("Creating a volume (size :%s, name: %s)", size, name)
+        LOG.debug("Creating a volume (size: %s, name: %s)", size, name)
         volume = client.volumes.create(size=size, display_name=name,
                                        snapshot_id=snapshot_id,
                                        imageRef=imageRef)
diff --git a/tempest/scenario/orchestration/test_autoscaling.py b/tempest/scenario/orchestration/test_autoscaling.py
index 78025ee..b31a0a7 100644
--- a/tempest/scenario/orchestration/test_autoscaling.py
+++ b/tempest/scenario/orchestration/test_autoscaling.py
@@ -12,10 +12,11 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import time
+
 from tempest.scenario import manager
 from tempest.test import attr
 from tempest.test import call_until_true
-import time
 
 
 class AutoScalingTest(manager.OrchestrationScenarioTest):
diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
index 70939f6..930ffae 100644
--- a/tempest/scenario/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -19,9 +19,12 @@
 from tempest.api.network import common as net_common
 from tempest.common.utils.data_utils import rand_name
 from tempest import config
+from tempest.openstack.common import log as logging
 from tempest.scenario import manager
 from tempest.test import attr
 
+LOG = logging.getLogger(__name__)
+
 
 class TestNetworkBasicOps(manager.NetworkScenarioTest):
 
@@ -158,18 +161,15 @@
         self.set_resource(name, router)
         return router
 
-    @attr(type='smoke')
-    def test_001_create_keypairs(self):
+    def _create_keypairs(self):
         self.keypairs[self.tenant_id] = self.create_keypair(
             name=rand_name('keypair-smoke-'))
 
-    @attr(type='smoke')
-    def test_002_create_security_groups(self):
+    def _create_security_groups(self):
         self.security_groups[self.tenant_id] = self._create_security_group(
             self.compute_client)
 
-    @attr(type='smoke')
-    def test_003_create_networks(self):
+    def _create_networks(self):
         network = self._create_network(self.tenant_id)
         router = self._get_router(self.tenant_id)
         subnet = self._create_subnet(network)
@@ -178,8 +178,7 @@
         self.subnets.append(subnet)
         self.routers.append(router)
 
-    @attr(type='smoke')
-    def test_004_check_networks(self):
+    def _check_networks(self):
         # Checks that we see the newly created network/subnet/router via
         # checking the result of list_[networks,routers,subnets]
         seen_nets = self._list_networks()
@@ -202,10 +201,7 @@
             self.assertIn(myrouter.name, seen_router_names)
             self.assertIn(myrouter.id, seen_router_ids)
 
-    @attr(type='smoke')
-    def test_005_create_servers(self):
-        if not (self.keypairs or self.security_groups or self.networks):
-            raise self.skipTest('Necessary resources have not been defined')
+    def _create_servers(self):
         for i, network in enumerate(self.networks):
             tenant_id = network.tenant_id
             name = rand_name('server-smoke-%d-' % i)
@@ -222,13 +218,11 @@
                                         create_kwargs=create_kwargs)
             self.servers.append(server)
 
-    @attr(type='smoke')
-    def test_006_check_tenant_network_connectivity(self):
+    def _check_tenant_network_connectivity(self):
         if not self.config.network.tenant_networks_reachable:
             msg = 'Tenant networks not configured to be reachable.'
-            raise self.skipTest(msg)
-        if not self.servers:
-            raise self.skipTest("No VM's have been created")
+            LOG.info(msg)
+            return
         # The target login is assumed to have been configured for
         # key-based authentication by cloud-init.
         ssh_login = self.config.compute.image_ssh_user
@@ -239,22 +233,14 @@
                     self._check_vm_connectivity(ip_address, ssh_login,
                                                 private_key)
 
-    @attr(type='smoke')
-    def test_007_assign_floating_ips(self):
+    def _assign_floating_ips(self):
         public_network_id = self.config.network.public_network_id
-        if not public_network_id:
-            raise self.skipTest('Public network not configured')
-        if not self.servers:
-            raise self.skipTest("No VM's have been created")
         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)
 
-    @attr(type='smoke')
-    def test_008_check_public_network_connectivity(self):
-        if not self.floating_ips:
-            raise self.skipTest('No floating ips have been allocated.')
+    def _check_public_network_connectivity(self):
         # The target login is assumed to have been configured for
         # key-based authentication by cloud-init.
         ssh_login = self.config.compute.image_ssh_user
@@ -263,3 +249,14 @@
             for floating_ip in floating_ips:
                 ip_address = floating_ip.floating_ip_address
                 self._check_vm_connectivity(ip_address, ssh_login, private_key)
+
+    @attr(type='smoke')
+    def test_network_basic_ops(self):
+        self._create_keypairs()
+        self._create_security_groups()
+        self._create_networks()
+        self._check_networks()
+        self._create_servers()
+        self._check_tenant_network_connectivity()
+        self._assign_floating_ips()
+        self._check_public_network_connectivity()
diff --git a/tempest/scenario/test_network_quotas.py b/tempest/scenario/test_network_quotas.py
index 267aff6..8259feb 100644
--- a/tempest/scenario/test_network_quotas.py
+++ b/tempest/scenario/test_network_quotas.py
@@ -16,6 +16,7 @@
 #    under the License.
 
 from neutronclient.common import exceptions as exc
+
 from tempest.scenario.manager import NetworkScenarioTest
 
 MAX_REASONABLE_ITERATIONS = 51  # more than enough. Default for port is 50.
diff --git a/tempest/scenario/test_stamp_pattern.py b/tempest/scenario/test_stamp_pattern.py
index 3cbd1fa..5af4bb2 100644
--- a/tempest/scenario/test_stamp_pattern.py
+++ b/tempest/scenario/test_stamp_pattern.py
@@ -143,7 +143,7 @@
         got_timestamp = ssh_client.exec_command('sudo cat /mnt/timestamp')
         self.assertEqual(self.timestamp, got_timestamp)
 
-    @testtools.skip("Until Bug #1205344 is fixed")
+    @testtools.skip("Skipped until the Bug #1205344 is resolved.")
     def test_stamp_pattern(self):
         # prepare for booting a instance
         self._add_keypair()
diff --git a/tempest/services/compute/json/servers_client.py b/tempest/services/compute/json/servers_client.py
index 6906610..c5827f6 100644
--- a/tempest/services/compute/json/servers_client.py
+++ b/tempest/services/compute/json/servers_client.py
@@ -157,6 +157,8 @@
         start = int(time.time())
 
         while(server_status != status):
+            if status == 'BUILD' and server_status != 'UNKNOWN':
+                return
             time.sleep(self.build_interval)
             resp, body = self.get_server(server_id)
             server_status = body['status']
diff --git a/tempest/services/compute/xml/servers_client.py b/tempest/services/compute/xml/servers_client.py
index 5c7a629..6f17611 100644
--- a/tempest/services/compute/xml/servers_client.py
+++ b/tempest/services/compute/xml/servers_client.py
@@ -46,9 +46,14 @@
     # expanded xml namespace.
     type_ns_prefix = ('{http://docs.openstack.org/compute/ext/extended_ips/'
                       'api/v1.1}type')
+    mac_ns_prefix = ('{http://docs.openstack.org/compute/ext/extended_ips_mac'
+                     '/api/v1.1}mac_addr')
+
     if type_ns_prefix in ip:
-        ip['OS-EXT-IPS:type'] = ip[type_ns_prefix]
-        ip.pop(type_ns_prefix)
+        ip['OS-EXT-IPS:type'] = ip.pop(type_ns_prefix)
+
+    if mac_ns_prefix in ip:
+        ip['OS-EXT-IPS-MAC:mac_addr'] = ip.pop(mac_ns_prefix)
     return ip
 
 
@@ -101,11 +106,35 @@
         json['addresses'] = json_addresses
     else:
         json = xml_to_json(xml_dom)
-    diskConfig = '{http://docs.openstack.org/compute/ext/disk_config/api/v1.1'\
-                 '}diskConfig'
+    diskConfig = ('{http://docs.openstack.org'
+                  '/compute/ext/disk_config/api/v1.1}diskConfig')
+    terminated_at = ('{http://docs.openstack.org/'
+                     'compute/ext/server_usage/api/v1.1}terminated_at')
+    launched_at = ('{http://docs.openstack.org'
+                   '/compute/ext/server_usage/api/v1.1}launched_at')
+    power_state = ('{http://docs.openstack.org'
+                   '/compute/ext/extended_status/api/v1.1}power_state')
+    availability_zone = ('{http://docs.openstack.org'
+                         '/compute/ext/extended_availability_zone/api/v2}'
+                         'availability_zone')
+    vm_state = ('{http://docs.openstack.org'
+                '/compute/ext/extended_status/api/v1.1}vm_state')
+    task_state = ('{http://docs.openstack.org'
+                  '/compute/ext/extended_status/api/v1.1}task_state')
     if diskConfig in json:
-        json['OS-DCF:diskConfig'] = json[diskConfig]
-        del json[diskConfig]
+        json['OS-DCF:diskConfig'] = json.pop(diskConfig)
+    if terminated_at in json:
+        json['OS-SRV-USG:terminated_at'] = json.pop(terminated_at)
+    if launched_at in json:
+        json['OS-SRV-USG:launched_at'] = json.pop(launched_at)
+    if power_state in json:
+        json['OS-EXT-STS:power_state'] = json.pop(power_state)
+    if availability_zone in json:
+        json['OS-EXT-AZ:availability_zone'] = json.pop(availability_zone)
+    if vm_state in json:
+        json['OS-EXT-STS:vm_state'] = json.pop(vm_state)
+    if task_state in json:
+        json['OS-EXT-STS:task_state'] = json.pop(task_state)
     return json
 
 
@@ -312,6 +341,8 @@
         start = int(time.time())
 
         while(server_status != status):
+            if status == 'BUILD' and server_status != 'UNKNOWN':
+                return
             time.sleep(self.build_interval)
             resp, body = self.get_server(server_id)
             server_status = body['status']
diff --git a/tempest/services/network/json/network_client.py b/tempest/services/network/json/network_client.py
index 588dc8f..ef12a00 100644
--- a/tempest/services/network/json/network_client.py
+++ b/tempest/services/network/json/network_client.py
@@ -24,7 +24,7 @@
     V1 API has been removed from the code base.
 
     Implements create, delete, update, list and show for the basic Neutron
-    abstractions (networks, sub-networks, routers and ports):
+    abstractions (networks, sub-networks, routers, ports and floating IP):
 
     Implements add/remove interface to router using subnet ID / port ID
 
@@ -285,3 +285,39 @@
         resp, body = self.put(uri, update_body, self.headers)
         body = json.loads(body)
         return resp, body
+
+    def create_floating_ip(self, ext_network_id, **kwargs):
+        post_body = {
+            'floatingip': kwargs}
+        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)
+        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 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 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)
+        body = json.loads(body)
+        return resp, body
diff --git a/tempest/services/volume/json/volumes_client.py b/tempest/services/volume/json/volumes_client.py
index c22b398..2ae73b1 100644
--- a/tempest/services/volume/json/volumes_client.py
+++ b/tempest/services/volume/json/volumes_client.py
@@ -36,6 +36,10 @@
         self.build_interval = self.config.volume.build_interval
         self.build_timeout = self.config.volume.build_timeout
 
+    def get_attachment_from_volume(self, volume):
+        """Return the element 'attachment' from input volumes."""
+        return volume['attachments'][0]
+
     def list_volumes(self, params=None):
         """List all the volumes created."""
         url = 'volumes'
diff --git a/tempest/services/volume/xml/volumes_client.py b/tempest/services/volume/xml/volumes_client.py
index eaa3ae0..936e036 100644
--- a/tempest/services/volume/xml/volumes_client.py
+++ b/tempest/services/volume/xml/volumes_client.py
@@ -56,6 +56,10 @@
                 vol[tag] = xml_to_json(child)
         return vol
 
+    def get_attachment_from_volume(self, volume):
+        """Return the element 'attachment' from input volumes."""
+        return volume['attachments']['attachment']
+
     def list_volumes(self, params=None):
         """List all the volumes created."""
         url = 'volumes'
@@ -157,3 +161,33 @@
         except exceptions.NotFound:
             return True
         return False
+
+    def attach_volume(self, volume_id, instance_uuid, mountpoint):
+        """Attaches a volume to a given instance on a given mountpoint."""
+        post_body = Element("os-attach",
+                            instance_uuid=instance_uuid,
+                            mountpoint=mountpoint
+                            )
+        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
+
+    def detach_volume(self, volume_id):
+        """Detaches a volume from an instance."""
+        post_body = Element("os-detach")
+        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
+
+    def upload_volume(self, volume_id, image_name):
+        """Uploads a volume in Glance."""
+        post_body = Element("os-volume_upload_image",
+                            image_name=image_name)
+        url = 'volumes/%s/action' % str(volume_id)
+        resp, body = self.post(url, str(Document(post_body)), self.headers)
+        volume = xml_to_json(etree.fromstring(body))
+        return resp, volume
diff --git a/tempest/stress/actions/ssh_floating.py b/tempest/stress/actions/ssh_floating.py
new file mode 100644
index 0000000..36ef023
--- /dev/null
+++ b/tempest/stress/actions/ssh_floating.py
@@ -0,0 +1,189 @@
+# 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 socket
+import subprocess
+
+from tempest.common.utils.data_utils import rand_name
+import tempest.stress.stressaction as stressaction
+import tempest.test
+
+
+class FloatingStress(stressaction.StressAction):
+
+    # from the scenario manager
+    def ping_ip_address(self, ip_address):
+        cmd = ['ping', '-c1', '-w1', ip_address]
+
+        proc = subprocess.Popen(cmd,
+                                stdout=subprocess.PIPE,
+                                stderr=subprocess.PIPE)
+        proc.wait()
+        success = proc.returncode == 0
+        self.logger.info("%s(%s): %s", self.server_id, self.floating['ip'],
+                         "pong!" if success else "no pong :(")
+        return success
+
+    def tcp_connect_scan(self, addr, port):
+        # like tcp
+        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+        try:
+            s.connect((addr, port))
+        except socket.error as exc:
+            self.logger.info("%s(%s): %s", self.server_id, self.floating['ip'],
+                             str(exc))
+            return False
+        self.logger.info("%s(%s): Connected :)", self.server_id,
+                         self.floating['ip'])
+        s.close()
+        return True
+
+    def check_port_ssh(self):
+        def func():
+            return self.tcp_connect_scan(self.floating['ip'], 22)
+        if not tempest.test.call_until_true(func, self.check_timeout,
+                                            self.check_interval):
+            raise RuntimeError("Cannot connect to the ssh port.")
+
+    def check_icmp_echo(self):
+        def func():
+            return self.ping_ip_address(self.floating['ip'])
+        if not tempest.test.call_until_true(func, self.check_timeout,
+                                            self.check_interval):
+            raise RuntimeError("Cannot ping the machine.")
+
+    def _create_vm(self):
+        self.name = name = rand_name("instance")
+        servers_client = self.manager.servers_client
+        self.logger.info("creating %s" % name)
+        vm_args = self.vm_extra_args.copy()
+        vm_args['security_groups'] = [{'name': self.sec_grp}]
+        resp, server = servers_client.create_server(name, self.image,
+                                                    self.flavor,
+                                                    **vm_args)
+        self.server_id = server['id']
+        assert(resp.status == 202)
+        if self.wait_after_vm_create:
+            self.manager.servers_client.wait_for_server_status(self.server_id,
+                                                               'ACTIVE')
+
+    def _destroy_vm(self):
+        self.logger.info("deleting %s" % self.server_id)
+        resp, _ = self.manager.servers_client.delete_server(self.server_id)
+        assert(resp.status == 204)  # It cannot be 204 if I had to wait..
+        self.manager.servers_client.wait_for_server_termination(self.server_id)
+        self.logger.info("deleted %s" % self.server_id)
+
+    def _create_sec_group(self):
+        sec_grp_cli = self.manager.security_groups_client
+        s_name = rand_name('sec_grp-')
+        s_description = rand_name('desc-')
+        _, _sec_grp = sec_grp_cli.create_security_group(s_name,
+                                                        s_description)
+        self.sec_grp = _sec_grp['id']
+        create_rule = sec_grp_cli.create_security_group_rule
+        create_rule(self.sec_grp, 'tcp', 22, 22)
+        create_rule(self.sec_grp, 'icmp', -1, -1)
+
+    def _destroy_sec_grp(self):
+        sec_grp_cli = self.manager.security_groups_client
+        sec_grp_cli.delete_security_group(self.sec_grp)
+
+    def _create_floating_ip(self):
+        floating_cli = self.manager.floating_ips_client
+        _, self.floating = floating_cli.create_floating_ip(self.floating_pool)
+
+    def _destroy_floating_ip(self):
+        cli = self.manager.floating_ips_client
+        cli.delete_floating_ip(self.floating['id'])
+        cli.wait_for_resource_deletion(self.floating['id'])
+        self.logger.info("Deleted Floating IP %s", str(self.floating['ip']))
+
+    def setUp(self, **kwargs):
+        self.image = self.manager.config.compute.image_ref
+        self.flavor = self.manager.config.compute.flavor_ref
+        self.vm_extra_args = kwargs.get('vm_extra_args', {})
+        self.wait_after_vm_create = kwargs.get('wait_after_vm_create',
+                                               True)
+        self.new_vm = kwargs.get('new_vm', False)
+        self.new_sec_grp = kwargs.get('new_sec_group', False)
+        self.new_floating = kwargs.get('new_floating', False)
+        self.reboot = kwargs.get('reboot', False)
+        self.floating_pool = kwargs.get('floating_pool', None)
+        self.verify = kwargs.get('verify', ('check_port_ssh',
+                                            'check_icmp_echo'))
+        self.check_timeout = kwargs.get('check_timeout', 120)
+        self.check_interval = kwargs.get('check_interval', 1)
+        self.wait_for_disassociate = kwargs.get('wait_for_disassociate',
+                                                True)
+
+        # allocate floating
+        if not self.new_floating:
+            self._create_floating_ip()
+        # add security group
+        if not self.new_sec_grp:
+            self._create_sec_group()
+        # create vm
+        if not self.new_vm:
+            self._create_vm()
+
+    def wait_disassociate(self):
+        cli = self.manager.floating_ips_client
+
+        def func():
+            _, floating = cli.get_floating_ip_details(self.floating['id'])
+            return floating['instance_id'] is None
+
+        if not tempest.test.call_until_true(func, self.check_timeout,
+                                            self.check_interval):
+            raise RuntimeError("IP disassociate timeout!")
+
+    def run_core(self):
+        cli = self.manager.floating_ips_client
+        cli.associate_floating_ip_to_server(self.floating['ip'],
+                                            self.server_id)
+        for method in self.verify:
+            m = getattr(self, method)
+            m()
+        cli.disassociate_floating_ip_from_server(self.floating['ip'],
+                                                 self.server_id)
+        if self.wait_for_disassociate:
+            self.wait_disassociate()
+
+    def run(self):
+        if self.new_sec_grp:
+            self._create_sec_group()
+        if self.new_floating:
+            self._create_floating_ip()
+        if self.new_vm:
+            self._create_vm()
+        if self.reboot:
+            self.manager.servers_client.reboot(self.server_id, 'HARD')
+
+        self.run_core()
+
+        if self.new_vm:
+            self._destroy_vm()
+        if self.new_floating:
+            self._destroy_floating_ip()
+        if self.new_sec_grp:
+            self._destroy_sec_grp()
+
+    def tearDown(self):
+        if not self.new_vm:
+            self._destroy_vm()
+        if not self.new_floating:
+            self._destroy_floating_ip()
+        if not self.new_sec_grp:
+            self._destroy_sec_grp()
diff --git a/tempest/stress/etc/ssh_floating.json b/tempest/stress/etc/ssh_floating.json
new file mode 100644
index 0000000..0cb6776
--- /dev/null
+++ b/tempest/stress/etc/ssh_floating.json
@@ -0,0 +1,16 @@
+[{"action": "tempest.stress.actions.ssh_floating.FloatingStress",
+  "threads": 8,
+  "use_admin": false,
+  "use_isolated_tenants": false,
+  "kwargs": {"vm_extra_args": {},
+             "new_vm": true,
+             "new_sec_group": true,
+             "new_floating": true,
+             "verify": ["check_icmp_echo", "check_port_ssh"],
+             "check_timeout": 120,
+             "check_inerval": 1,
+             "wait_after_vm_create": true,
+             "wait_for_disassociate": true,
+             "reboot": false}
+}
+]
diff --git a/tempest/stress/run_stress.py b/tempest/stress/run_stress.py
index aab2afd..886d94b 100755
--- a/tempest/stress/run_stress.py
+++ b/tempest/stress/run_stress.py
@@ -17,16 +17,16 @@
 #    limitations under the License.
 
 import argparse
+import inspect
 import json
 import sys
 from testtools.testsuite import iterate_tests
 from unittest import loader
 
 
-def discover_stress_tests(path="./", filter_attr=None):
+def discover_stress_tests(path="./", filter_attr=None, call_inherited=False):
     """Discovers all tempest tests and create action out of them
     """
-
     tests = []
     testloader = loader.TestLoader()
     list = testloader.discover(path)
@@ -52,6 +52,11 @@
                                  "class_setup_per": class_setup_per
                                  }
                       }
+            if (not call_inherited and
+                getattr(test_func, "st_allow_inheritance") is not True):
+                class_structure = inspect.getmro(test_func.im_class)
+                if test_func.__name__ not in class_structure[0].__dict__:
+                    continue
             tests.append(action)
     return tests
 
@@ -63,7 +68,8 @@
     if not ns.all:
         tests = json.load(open(ns.tests, 'r'))
     else:
-        tests = discover_stress_tests(filter_attr=ns.type)
+        tests = discover_stress_tests(filter_attr=ns.type,
+                                      call_inherited=ns.call_inherited)
 
     if ns.serial:
         for test in tests:
@@ -79,22 +85,25 @@
     return result
 
 
-parser = argparse.ArgumentParser(description='Run stress tests. ')
+parser = argparse.ArgumentParser(description='Run stress tests')
 parser.add_argument('-d', '--duration', default=300, type=int,
-                    help="Duration of test in secs.")
+                    help="Duration of test in secs")
 parser.add_argument('-s', '--serial', action='store_true',
-                    help="Trigger running tests serially.")
+                    help="Trigger running tests serially")
 parser.add_argument('-S', '--stop', action='store_true',
-                    default=False, help="Stop on first error.")
+                    default=False, help="Stop on first error")
 parser.add_argument('-n', '--number', type=int,
-                    help="How often an action is executed for each process.")
+                    help="How often an action is executed for each process")
 group = parser.add_mutually_exclusive_group(required=True)
 group.add_argument('-a', '--all', action='store_true',
                    help="Execute all stress tests")
 parser.add_argument('-T', '--type',
                     help="Filters tests of a certain type (e.g. gate)")
+parser.add_argument('-i', '--call-inherited', action='store_true',
+                    default=False,
+                    help="Call also inherited function with stress attribute")
 group.add_argument('-t', "--tests", nargs='?',
-                   help="Name of the file with test description.")
+                   help="Name of the file with test description")
 
 if __name__ == "__main__":
     sys.exit(main(parser.parse_args()))
diff --git a/tempest/test.py b/tempest/test.py
index ca626da..24c4489 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -26,6 +26,7 @@
 
 from tempest import clients
 from tempest import config
+from tempest import exceptions
 from tempest.openstack.common import log as logging
 
 LOG = logging.getLogger(__name__)
@@ -57,6 +58,25 @@
     return decorator
 
 
+def services(*args, **kwargs):
+    """A decorator used to set an attr for each service used in a test case
+
+    This decorator applies a testtools attr for each service that gets
+    exercised by a test case.
+    """
+    valid_service_list = ['compute', 'image', 'volume', 'orchestration',
+                          'network', 'identity', 'object', 'dashboard']
+
+    def decorator(f):
+        for service in args:
+            if service not in valid_service_list:
+                raise exceptions.InvalidServiceTag('%s is not a valid service'
+                                                   % service)
+        attr(type=list(args))(f)
+        return f
+    return decorator
+
+
 def stresstest(*args, **kwargs):
     """Add stress test decorator
 
@@ -67,12 +87,17 @@
            ``application``: once in the stress job lifetime
            ``process``: once in the worker process lifetime
            ``action``: on each action
+    @param allow_inheritance: allows inheritance of this attribute
     """
     def decorator(f):
         if 'class_setup_per' in kwargs:
             setattr(f, "st_class_setup_per", kwargs['class_setup_per'])
         else:
             setattr(f, "st_class_setup_per", 'process')
+        if 'allow_inheritance' in kwargs:
+            setattr(f, "st_allow_inheritance", kwargs['allow_inheritance'])
+        else:
+            setattr(f, "st_allow_inheritance", False)
         attr(type='stress')(f)
         return f
     return decorator
diff --git a/tempest/thirdparty/boto/test_ec2_instance_run.py b/tempest/thirdparty/boto/test_ec2_instance_run.py
index 5007503..a848fc9 100644
--- a/tempest/thirdparty/boto/test_ec2_instance_run.py
+++ b/tempest/thirdparty/boto/test_ec2_instance_run.py
@@ -233,7 +233,7 @@
 
     # NOTE(afazekas): doctored test case,
     # with normal validation it would fail
-    @testtools.skip("Until Bug #1182679 is fixed")
+    @testtools.skip("Skipped until the Bug #1182679 is resolved.")
     @attr(type='smoke')
     def test_integration_1(self):
         # EC2 1. integration test (not strict)