Merge "enable test_servers_negative"
diff --git a/cli/__init__.py b/cli/__init__.py
index cea0b62..e97fe3e 100644
--- a/cli/__init__.py
+++ b/cli/__init__.py
@@ -16,8 +16,11 @@
 #    under the License.
 
 import logging
+import shlex
+import subprocess
 
 from tempest.openstack.common import cfg
+import tempest.test
 
 LOG = logging.getLogger(__name__)
 
@@ -34,3 +37,45 @@
 cli_group = cfg.OptGroup(name='cli', title="cli Configuration Options")
 CONF.register_group(cli_group)
 CONF.register_opts(cli_opts, group=cli_group)
+
+
+class ClientTestBase(tempest.test.BaseTestCase):
+    @classmethod
+    def setUpClass(cls):
+        if not CONF.cli.enabled:
+            msg = "cli testing disabled"
+            raise cls.skipException(msg)
+        cls.identity = cls.config.identity
+        super(ClientTestBase, cls).setUpClass()
+
+    def __init__(self, *args, **kwargs):
+        super(ClientTestBase, self).__init__(*args, **kwargs)
+
+    def nova(self, action, flags='', params='', admin=True, fail_ok=False):
+        """Executes nova command for the given action."""
+        return self.cmd_with_auth(
+            'nova', action, flags, params, admin, fail_ok)
+
+    def cmd_with_auth(self, cmd, action, flags='', params='',
+                      admin=True, fail_ok=False):
+        """Executes given command with auth attributes appended."""
+        #TODO(jogo) make admin=False work
+        creds = ('--os-username %s --os-tenant-name %s --os-password %s '
+                 '--os-auth-url %s ' % (self.identity.admin_username,
+                 self.identity.admin_tenant_name, self.identity.admin_password,
+                 self.identity.uri))
+        flags = creds + ' ' + flags
+        return self.cmd(cmd, action, flags, params, fail_ok)
+
+    def cmd(self, cmd, action, flags='', params='', fail_ok=False):
+        """Executes specified command for the given action."""
+        cmd = ' '.join([CONF.cli.cli_dir + cmd,
+                        flags, action, params])
+        LOG.info("running: '%s'" % cmd)
+        cmd = shlex.split(cmd)
+        try:
+            result = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
+        except subprocess.CalledProcessError, e:
+            LOG.error("command output:\n%s" % e.output)
+            raise
+        return result
diff --git a/cli/simple_read_only/test_compute.py b/cli/simple_read_only/test_compute.py
index 073fde1..849ed6f 100644
--- a/cli/simple_read_only/test_compute.py
+++ b/cli/simple_read_only/test_compute.py
@@ -16,14 +16,12 @@
 #    under the License.
 
 import logging
-import shlex
 import subprocess
 
 import testtools
 
 import cli
 
-from tempest import config
 from tempest.openstack.common import cfg
 
 
@@ -33,7 +31,7 @@
 LOG = logging.getLogger(__name__)
 
 
-class SimpleReadOnlyNovaCLientTest(testtools.TestCase):
+class SimpleReadOnlyNovaClientTest(cli.ClientTestBase):
 
     """
     This is a first pass at a simple read only python-novaclient test. This
@@ -47,33 +45,6 @@
 
     """
 
-    @classmethod
-    def setUpClass(cls):
-        if not CONF.cli.enabled:
-            msg = "cli testing disabled"
-            raise cls.skipException(msg)
-        cls.identity = config.TempestConfig().identity
-        super(SimpleReadOnlyNovaCLientTest, cls).setUpClass()
-
-    #NOTE(jogo): This should eventually be moved into a base class
-    def nova(self, action, flags='', params='', admin=True, fail_ok=False):
-        """Executes nova command for the given action."""
-        #TODO(jogo) make admin=False work
-        creds = ('--os-username %s --os-tenant-name %s --os-password %s '
-                 '--os-auth-url %s ' % (self.identity.admin_username,
-                 self.identity.admin_tenant_name, self.identity.admin_password,
-                 self.identity.uri))
-        flags = creds + ' ' + flags
-        cmd = ' '.join([CONF.cli.cli_dir + 'nova', flags, action, params])
-        LOG.info("running: '%s'" % cmd)
-        cmd = shlex.split(cmd)
-        try:
-            result = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
-        except subprocess.CalledProcessError, e:
-            LOG.error("command output:\n%s" % e.output)
-            raise
-        return result
-
     def test_admin_fake_action(self):
         self.assertRaises(subprocess.CalledProcessError,
                           self.nova,
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index 9dca609..a70a7ab 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -88,6 +88,9 @@
 # Number of seconds to wait to authenticate to an instance
 ssh_timeout = 300
 
+# Number of seconds to wait for output from ssh channel
+ssh_channel_timeout = 60
+
 # The type of endpoint for a Compute API service. Unless you have a
 # custom Keystone service catalog implementation, you probably want to leave
 # this value as "compute"
@@ -238,20 +241,20 @@
 
 #Image materials for S3 upload
 # ALL content of the specified directory will be uploaded to S3
-s3_materials_path = /opt/stack/devstack/files/images/s3-materials/cirros-0.3.0
+s3_materials_path = /opt/stack/devstack/files/images/s3-materials/cirros-0.3.1
 
 # The manifest.xml files, must be in the s3_materials_path directory
 # Subdirectories not allowed!
 # The filenames will be used as a Keys in the S3 Buckets
 
 #ARI Ramdisk manifest. Must be in the above s3_materials_path
-ari_manifest = cirros-0.3.0-x86_64-initrd.manifest.xml
+ari_manifest = cirros-0.3.1-x86_64-initrd.manifest.xml
 
 #AMI Machine Image manifest. Must be in the above s3_materials_path
-ami_manifest = cirros-0.3.0-x86_64-blank.img.manifest.xml
+ami_manifest = cirros-0.3.1-x86_64-blank.img.manifest.xml
 
 #AKI Kernel Image manifest, Must be in the above s3_materials_path
-aki_manifest = cirros-0.3.0-x86_64-vmlinuz.manifest.xml
+aki_manifest = cirros-0.3.1-x86_64-vmlinuz.manifest.xml
 
 #Instance type
 instance_type = m1.tiny
diff --git a/tempest/clients.py b/tempest/clients.py
index ef07d9c..f2e89a7 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -52,7 +52,7 @@
 from tempest.services.identity.json.identity_client import TokenClientJSON
 from tempest.services.identity.xml.identity_client import IdentityClientXML
 from tempest.services.identity.xml.identity_client import TokenClientXML
-from tempest.services.image.json.image_client import ImageClientJSON
+from tempest.services.image.v1.json.image_client import ImageClientJSON
 from tempest.services.network.json.network_client import NetworkClient
 from tempest.services.object_storage.account_client import AccountClient
 from tempest.services.object_storage.account_client import \
diff --git a/tempest/common/rest_client.py b/tempest/common/rest_client.py
index 170a137..c582826 100644
--- a/tempest/common/rest_client.py
+++ b/tempest/common/rest_client.py
@@ -338,6 +338,11 @@
             return self.check_over_limit(resp_body, method, url, headers, body,
                                          depth, wait)
 
+        if resp.status == 422:
+            if parse_resp:
+                resp_body = self._parse_resp(resp_body)
+            raise exceptions.UnprocessableEntity(resp_body)
+
         if resp.status in (500, 501):
             message = resp_body
             if parse_resp:
diff --git a/tempest/common/utils/linux/remote_client.py b/tempest/common/utils/linux/remote_client.py
index b501df4..fd5d3d0 100644
--- a/tempest/common/utils/linux/remote_client.py
+++ b/tempest/common/utils/linux/remote_client.py
@@ -15,6 +15,7 @@
         ssh_timeout = TempestConfig().compute.ssh_timeout
         network = TempestConfig().compute.network_for_ssh
         ip_version = TempestConfig().compute.ip_version_for_ssh
+        ssh_channel_timeout = TempestConfig().compute.ssh_channel_timeout
         if isinstance(server, basestring):
             ip_address = server
         else:
@@ -27,7 +28,8 @@
                 raise ServerUnreachable()
 
         self.ssh_client = Client(ip_address, username, password, ssh_timeout,
-                                 pkey=pkey)
+                                 pkey=pkey,
+                                 channel_timeout=ssh_channel_timeout)
         if not self.ssh_client.test_connection_auth():
             raise SSHTimeout()
 
diff --git a/tempest/config.py b/tempest/config.py
index c0e25c7..856be16 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -149,8 +149,12 @@
                help="User name used to authenticate to an instance."),
     cfg.IntOpt('ssh_timeout',
                default=300,
-               help="Timeout in seconds to wait for authentcation to "
+               help="Timeout in seconds to wait for authentication to "
                     "succeed."),
+    cfg.IntOpt('ssh_channel_timeout',
+               default=60,
+               help="Timeout in seconds to wait for output from ssh "
+                    "channel."),
     cfg.StrOpt('network_for_ssh',
                default='public',
                help="Network used for SSH connections."),
diff --git a/tempest/exceptions.py b/tempest/exceptions.py
index 577aa13..235a2e7 100644
--- a/tempest/exceptions.py
+++ b/tempest/exceptions.py
@@ -94,6 +94,10 @@
     message = "Bad request"
 
 
+class UnprocessableEntity(RestClientException):
+    message = "Unprocessable entity"
+
+
 class AuthenticationFailure(RestClientException):
     message = ("Authentication with user %(user)s and password "
                "%(password)s failed")
diff --git a/tempest/openstack/common/setup.py b/tempest/openstack/common/setup.py
index 2fb9cf2..80a0ece 100644
--- a/tempest/openstack/common/setup.py
+++ b/tempest/openstack/common/setup.py
@@ -43,6 +43,11 @@
     return mapping
 
 
+def _parse_git_mailmap(git_dir, mailmap='.mailmap'):
+    mailmap = os.path.join(os.path.dirname(git_dir), mailmap)
+    return parse_mailmap(mailmap)
+
+
 def canonicalize_emails(changelog, mapping):
     """Takes in a string and an email alias mapping and replaces all
        instances of the aliases in the string with their real email.
@@ -117,9 +122,9 @@
         output = subprocess.Popen(["/bin/sh", "-c", cmd],
                                   stdout=subprocess.PIPE,
                                   stderr=subprocess.PIPE)
+    out = output.communicate()
     if output.returncode and throw_on_error:
         raise Exception("%s returned %d" % cmd, output.returncode)
-    out = output.communicate()
     if len(out) == 0:
         return None
     if len(out[0].strip()) == 0:
@@ -127,14 +132,26 @@
     return out[0].strip()
 
 
+def _get_git_directory():
+    parent_dir = os.path.dirname(__file__)
+    while True:
+        git_dir = os.path.join(parent_dir, '.git')
+        if os.path.exists(git_dir):
+            return git_dir
+        parent_dir, child = os.path.split(parent_dir)
+        if not child:   # reached to root dir
+            return None
+
+
 def write_git_changelog():
     """Write a changelog based on the git changelog."""
     new_changelog = 'ChangeLog'
+    git_dir = _get_git_directory()
     if not os.getenv('SKIP_WRITE_GIT_CHANGELOG'):
-        if os.path.isdir('.git'):
-            git_log_cmd = 'git log --stat'
+        if git_dir:
+            git_log_cmd = 'git --git-dir=%s log --stat' % git_dir
             changelog = _run_shell_command(git_log_cmd)
-            mailmap = parse_mailmap()
+            mailmap = _parse_git_mailmap(git_dir)
             with open(new_changelog, "w") as changelog_file:
                 changelog_file.write(canonicalize_emails(changelog, mailmap))
     else:
@@ -146,13 +163,15 @@
     jenkins_email = 'jenkins@review.(openstack|stackforge).org'
     old_authors = 'AUTHORS.in'
     new_authors = 'AUTHORS'
+    git_dir = _get_git_directory()
     if not os.getenv('SKIP_GENERATE_AUTHORS'):
-        if os.path.isdir('.git'):
+        if git_dir:
             # don't include jenkins email address in AUTHORS file
-            git_log_cmd = ("git log --format='%aN <%aE>' | sort -u | "
+            git_log_cmd = ("git --git-dir=" + git_dir +
+                           " log --format='%aN <%aE>' | sort -u | "
                            "egrep -v '" + jenkins_email + "'")
             changelog = _run_shell_command(git_log_cmd)
-            mailmap = parse_mailmap()
+            mailmap = _parse_git_mailmap(git_dir)
             with open(new_authors, 'w') as new_authors_fh:
                 new_authors_fh.write(canonicalize_emails(changelog, mailmap))
                 if os.path.exists(old_authors):
@@ -258,40 +277,44 @@
     return cmdclass
 
 
-def _get_revno():
+def _get_revno(git_dir):
     """Return the number of commits since the most recent tag.
 
     We use git-describe to find this out, but if there are no
     tags then we fall back to counting commits since the beginning
     of time.
     """
-    describe = _run_shell_command("git describe --always")
+    describe = _run_shell_command(
+        "git --git-dir=%s describe --always" % git_dir)
     if "-" in describe:
         return describe.rsplit("-", 2)[-2]
 
     # no tags found
-    revlist = _run_shell_command("git rev-list --abbrev-commit HEAD")
+    revlist = _run_shell_command(
+        "git --git-dir=%s rev-list --abbrev-commit HEAD" % git_dir)
     return len(revlist.splitlines())
 
 
 def _get_version_from_git(pre_version):
     """Return a version which is equal to the tag that's on the current
     revision if there is one, or tag plus number of additional revisions
-    if the current revision has no tag.
-    """
+    if the current revision has no tag."""
 
-    if os.path.isdir('.git'):
+    git_dir = _get_git_directory()
+    if git_dir:
         if pre_version:
             try:
                 return _run_shell_command(
-                    "git describe --exact-match",
+                    "git --git-dir=" + git_dir + " describe --exact-match",
                     throw_on_error=True).replace('-', '.')
             except Exception:
-                sha = _run_shell_command("git log -n1 --pretty=format:%h")
-                return "%s.a%s.g%s" % (pre_version, _get_revno(), sha)
+                sha = _run_shell_command(
+                    "git --git-dir=" + git_dir + " log -n1 --pretty=format:%h")
+                return "%s.a%s.g%s" % (pre_version, _get_revno(git_dir), sha)
         else:
             return _run_shell_command(
-                "git describe --always").replace('-', '.')
+                "git --git-dir=" + git_dir + " describe --always").replace(
+                    '-', '.')
     return None
 
 
diff --git a/tempest/services/botoclients.py b/tempest/services/botoclients.py
index 143257a..0870c96 100644
--- a/tempest/services/botoclients.py
+++ b/tempest/services/botoclients.py
@@ -17,7 +17,6 @@
 
 import ConfigParser
 import contextlib
-import re
 import types
 import urlparse
 
diff --git a/tempest/services/compute/xml/servers_client.py b/tempest/services/compute/xml/servers_client.py
index 903e10c..bd393e8 100644
--- a/tempest/services/compute/xml/servers_client.py
+++ b/tempest/services/compute/xml/servers_client.py
@@ -399,6 +399,58 @@
     def remove_security_group(self, server_id, name):
         return self.action(server_id, 'removeSecurityGroup', None, name=name)
 
+    def list_server_metadata(self, server_id):
+        resp, body = self.get("servers/%s/metadata" % str(server_id),
+                              self.headers)
+        body = self._parse_key_value(etree.fromstring(body))
+        return resp, body
+
+    def set_server_metadata(self, server_id, meta):
+        doc = Document()
+        metadata = Element("metadata")
+        doc.append(metadata)
+        for k, v in meta.items():
+            meta_element = Element("meta", key=k)
+            meta_element.append(Text(v))
+            metadata.append(meta_element)
+        resp, body = self.put('servers/%s/metadata' % str(server_id),
+                              str(doc), self.headers)
+        return resp, xml_to_json(etree.fromstring(body))
+
+    def update_server_metadata(self, server_id, meta):
+        doc = Document()
+        metadata = Element("metadata")
+        doc.append(metadata)
+        for k, v in meta.items():
+            meta_element = Element("meta", key=k)
+            meta_element.append(Text(v))
+            metadata.append(meta_element)
+        resp, body = self.post("/servers/%s/metadata" % str(server_id),
+                               str(doc), headers=self.headers)
+        body = xml_to_json(etree.fromstring(body))
+        return resp, body
+
+    def get_server_metadata_item(self, server_id, key):
+        resp, body = self.get("servers/%s/metadata/%s" % (str(server_id), key),
+                              headers=self.headers)
+        return resp, dict([(etree.fromstring(body).attrib['key'],
+                            xml_to_json(etree.fromstring(body)))])
+
+    def set_server_metadata_item(self, server_id, key, meta):
+        doc = Document()
+        for k, v in meta.items():
+            meta_element = Element("meta", key=k)
+            meta_element.append(Text(v))
+            doc.append(meta_element)
+        resp, body = self.put('servers/%s/metadata/%s' % (str(server_id), key),
+                              str(doc), self.headers)
+        return resp, xml_to_json(etree.fromstring(body))
+
+    def delete_server_metadata_item(self, server_id, key):
+        resp, body = self.delete("servers/%s/metadata/%s" %
+                                 (str(server_id), key))
+        return resp, body
+
     def get_console_output(self, server_id, length):
         return self.action(server_id, 'os-getConsoleOutput', 'output',
                            length=length)
diff --git a/tempest/services/image/json/__init__.py b/tempest/services/image/v1/__init__.py
similarity index 100%
copy from tempest/services/image/json/__init__.py
copy to tempest/services/image/v1/__init__.py
diff --git a/tempest/services/image/json/__init__.py b/tempest/services/image/v1/json/__init__.py
similarity index 100%
rename from tempest/services/image/json/__init__.py
rename to tempest/services/image/v1/json/__init__.py
diff --git a/tempest/services/image/json/image_client.py b/tempest/services/image/v1/json/image_client.py
similarity index 93%
rename from tempest/services/image/json/image_client.py
rename to tempest/services/image/v1/json/image_client.py
index f119664..277075e 100644
--- a/tempest/services/image/json/image_client.py
+++ b/tempest/services/image/v1/json/image_client.py
@@ -25,7 +25,6 @@
 from tempest.common import glance_http
 from tempest.common.rest_client import RestClient
 from tempest import exceptions
-from tempest import manager
 
 
 class ImageClientJSON(RestClient):
@@ -97,11 +96,11 @@
             return None
 
     def _get_http(self):
-        temp_manager = manager.DefaultClientManager()
-        keystone = temp_manager._get_identity_client()
-        token = keystone.auth_token
-        endpoint = keystone.service_catalog.url_for(service_type='image',
-                                                    endpoint_type='publicURL')
+        token, endpoint = self.keystone_auth(self.user,
+                                             self.password,
+                                             self.auth_url,
+                                             self.service,
+                                             self.tenant_name)
         dscv = self.config.identity.disable_ssl_certificate_validation
         return glance_http.HTTPClient(endpoint=endpoint, token=token,
                                       insecure=dscv)
@@ -170,11 +169,7 @@
 
     def delete_image(self, image_id):
         url = 'v1/images/%s' % image_id
-        try:
-            self.delete(url)
-        except exceptions.Unauthorized:
-            url = '/' + url
-            self.http.raw_request('DELETE', url)
+        self.delete(url)
 
     def image_list(self, **kwargs):
         url = 'v1/images'
diff --git a/tempest/test.py b/tempest/test.py
index 90793ac..e0639b6 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -58,12 +58,11 @@
 
 
 class TestCase(BaseTestCase):
-
-    """
-    Base test case class for all Tempest tests
+    """Base test case class for all Tempest tests
 
     Contains basic setup and convenience methods
     """
+
     manager_class = None
 
     @classmethod
diff --git a/tempest/testboto.py b/tempest/testboto.py
index 5625841..cee8843 100644
--- a/tempest/testboto.py
+++ b/tempest/testboto.py
@@ -17,16 +17,21 @@
 
 from contextlib import closing
 import logging
+import os
 import re
+import urlparse
 
 import boto
 from boto import ec2
 from boto import exception
 from boto import s3
+import keystoneclient.exceptions
 
+import tempest.clients
+from tempest.common.utils.file_utils import have_effective_read_access
+import tempest.config
 from tempest import exceptions
 import tempest.test
-import tempest.tests.boto
 from tempest.tests.boto.utils.wait import re_search_wait
 from tempest.tests.boto.utils.wait import state_wait
 from tempest.tests.boto.utils.wait import wait_exception
@@ -34,6 +39,71 @@
 LOG = logging.getLogger(__name__)
 
 
+def decision_maker():
+    A_I_IMAGES_READY = True  # ari,ami,aki
+    S3_CAN_CONNECT_ERROR = None
+    EC2_CAN_CONNECT_ERROR = None
+    secret_matcher = re.compile("[A-Za-z0-9+/]{32,}")  # 40 in other system
+    id_matcher = re.compile("[A-Za-z0-9]{20,}")
+
+    def all_read(*args):
+        return all(map(have_effective_read_access, args))
+
+    config = tempest.config.TempestConfig()
+    materials_path = config.boto.s3_materials_path
+    ami_path = materials_path + os.sep + config.boto.ami_manifest
+    aki_path = materials_path + os.sep + config.boto.aki_manifest
+    ari_path = materials_path + os.sep + config.boto.ari_manifest
+
+    A_I_IMAGES_READY = all_read(ami_path, aki_path, ari_path)
+    boto_logger = logging.getLogger('boto')
+    level = boto_logger.level
+    boto_logger.setLevel(logging.CRITICAL)  # suppress logging for these
+
+    def _cred_sub_check(connection_data):
+        if not id_matcher.match(connection_data["aws_access_key_id"]):
+            raise Exception("Invalid AWS access Key")
+        if not secret_matcher.match(connection_data["aws_secret_access_key"]):
+            raise Exception("Invalid AWS secret Key")
+        raise Exception("Unknown (Authentication?) Error")
+    openstack = tempest.clients.Manager()
+    try:
+        if urlparse.urlparse(config.boto.ec2_url).hostname is None:
+            raise Exception("Failed to get hostname from the ec2_url")
+        ec2client = openstack.ec2api_client
+        try:
+            ec2client.get_all_regions()
+        except exception.BotoServerError as exc:
+                if exc.error_code is None:
+                    raise Exception("EC2 target does not looks EC2 service")
+                _cred_sub_check(ec2client.connection_data)
+
+    except keystoneclient.exceptions.Unauthorized:
+        EC2_CAN_CONNECT_ERROR = "AWS credentials not set," +\
+                                " faild to get them even by keystoneclient"
+    except Exception as exc:
+        EC2_CAN_CONNECT_ERROR = str(exc)
+
+    try:
+        if urlparse.urlparse(config.boto.s3_url).hostname is None:
+            raise Exception("Failed to get hostname from the s3_url")
+        s3client = openstack.s3_client
+        try:
+            s3client.get_bucket("^INVALID*#()@INVALID.")
+        except exception.BotoServerError as exc:
+            if exc.status == 403:
+                _cred_sub_check(s3client.connection_data)
+    except Exception as exc:
+        S3_CAN_CONNECT_ERROR = str(exc)
+    except keystoneclient.exceptions.Unauthorized:
+        S3_CAN_CONNECT_ERROR = "AWS credentials not set," +\
+                               " faild to get them even by keystoneclient"
+    boto_logger.setLevel(level)
+    return {'A_I_IMAGES_READY': A_I_IMAGES_READY,
+            'S3_CAN_CONNECT_ERROR': S3_CAN_CONNECT_ERROR,
+            'EC2_CAN_CONNECT_ERROR': EC2_CAN_CONNECT_ERROR}
+
+
 class BotoExceptionMatcher(object):
     STATUS_RE = r'[45]\d\d'
     CODE_RE = '.*'  # regexp makes sense in group match
@@ -121,7 +191,7 @@
 class BotoTestCase(tempest.test.BaseTestCase):
     """Recommended to use as base class for boto related test."""
 
-    conclusion = tempest.tests.boto.generic_setup_package()
+    conclusion = decision_maker()
 
     @classmethod
     def setUpClass(cls):
@@ -130,13 +200,13 @@
         cls._resource_trash_bin = {}
         cls._sequence = -1
         if (hasattr(cls, "EC2") and
-            tempest.tests.boto.EC2_CAN_CONNECT_ERROR is not None):
+            cls.conclusion['EC2_CAN_CONNECT_ERROR'] is not None):
             raise cls.skipException("EC2 " + cls.__name__ + ": " +
-                                    tempest.tests.boto.EC2_CAN_CONNECT_ERROR)
+                                    cls.conclusion['EC2_CAN_CONNECT_ERROR'])
         if (hasattr(cls, "S3") and
-            tempest.tests.boto.S3_CAN_CONNECT_ERROR is not None):
+            cls.conclusion['S3_CAN_CONNECT_ERROR'] is not None):
             raise cls.skipException("S3 " + cls.__name__ + ": " +
-                                    tempest.tests.boto.S3_CAN_CONNECT_ERROR)
+                                    cls.conclusion['S3_CAN_CONNECT_ERROR'])
 
     @classmethod
     def addResourceCleanUp(cls, function, *args, **kwargs):
diff --git a/tempest/tests/boto/__init__.py b/tempest/tests/boto/__init__.py
index dd224d6..e69de29 100644
--- a/tempest/tests/boto/__init__.py
+++ b/tempest/tests/boto/__init__.py
@@ -1,94 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2012 OpenStack, LLC
-# 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 logging
-import os
-import re
-import urlparse
-
-import boto.exception
-import keystoneclient.exceptions
-
-import tempest.clients
-from tempest.common.utils.file_utils import have_effective_read_access
-import tempest.config
-
-A_I_IMAGES_READY = True  # ari,ami,aki
-S3_CAN_CONNECT_ERROR = None
-EC2_CAN_CONNECT_ERROR = None
-
-
-def generic_setup_package():
-    global A_I_IMAGES_READY
-    global S3_CAN_CONNECT_ERROR
-    global EC2_CAN_CONNECT_ERROR
-    secret_matcher = re.compile("[A-Za-z0-9+/]{32,}")  # 40 in other system
-    id_matcher = re.compile("[A-Za-z0-9]{20,}")
-
-    def all_read(*args):
-        return all(map(have_effective_read_access, args))
-
-    config = tempest.config.TempestConfig()
-    materials_path = config.boto.s3_materials_path
-    ami_path = materials_path + os.sep + config.boto.ami_manifest
-    aki_path = materials_path + os.sep + config.boto.aki_manifest
-    ari_path = materials_path + os.sep + config.boto.ari_manifest
-
-    A_I_IMAGES_READY = all_read(ami_path, aki_path, ari_path)
-    boto_logger = logging.getLogger('boto')
-    level = boto_logger.level
-    boto_logger.setLevel(logging.CRITICAL)  # suppress logging for these
-
-    def _cred_sub_check(connection_data):
-        if not id_matcher.match(connection_data["aws_access_key_id"]):
-            raise Exception("Invalid AWS access Key")
-        if not secret_matcher.match(connection_data["aws_secret_access_key"]):
-            raise Exception("Invalid AWS secret Key")
-        raise Exception("Unknown (Authentication?) Error")
-    openstack = tempest.clients.Manager()
-    try:
-        if urlparse.urlparse(config.boto.ec2_url).hostname is None:
-            raise Exception("Failed to get hostname from the ec2_url")
-        ec2client = openstack.ec2api_client
-        try:
-            ec2client.get_all_regions()
-        except boto.exception.BotoServerError as exc:
-                if exc.error_code is None:
-                    raise Exception("EC2 target does not looks EC2 service")
-                _cred_sub_check(ec2client.connection_data)
-
-    except keystoneclient.exceptions.Unauthorized:
-        EC2_CAN_CONNECT_ERROR = "AWS credentials not set," +\
-                                " faild to get them even by keystoneclient"
-    except Exception as exc:
-        EC2_CAN_CONNECT_ERROR = str(exc)
-
-    try:
-        if urlparse.urlparse(config.boto.s3_url).hostname is None:
-            raise Exception("Failed to get hostname from the s3_url")
-        s3client = openstack.s3_client
-        try:
-            s3client.get_bucket("^INVALID*#()@INVALID.")
-        except boto.exception.BotoServerError as exc:
-            if exc.status == 403:
-                _cred_sub_check(s3client.connection_data)
-    except Exception as exc:
-        S3_CAN_CONNECT_ERROR = str(exc)
-    except keystoneclient.exceptions.Unauthorized:
-        S3_CAN_CONNECT_ERROR = "AWS credentials not set," +\
-                               " faild to get them even by keystoneclient"
-    boto_logger.setLevel(level)
diff --git a/tempest/tests/boto/test_ec2_instance_run.py b/tempest/tests/boto/test_ec2_instance_run.py
index 6b61c11..4ad37b6 100644
--- a/tempest/tests/boto/test_ec2_instance_run.py
+++ b/tempest/tests/boto/test_ec2_instance_run.py
@@ -17,15 +17,15 @@
 
 import logging
 
-from boto.exception import EC2ResponseError
+from boto import exception
 import testtools
 
 from tempest import clients
 from tempest.common.utils.data_utils import rand_name
 from tempest.common.utils.linux.remote_client import RemoteClient
+from tempest import exceptions
 from tempest.test import attr
 from tempest.testboto import BotoTestCase
-import tempest.tests.boto
 from tempest.tests.boto.utils.s3 import s3_upload_dir
 from tempest.tests.boto.utils.wait import re_search_wait
 from tempest.tests.boto.utils.wait import state_wait
@@ -39,7 +39,7 @@
     @classmethod
     def setUpClass(cls):
         super(InstanceRunTest, cls).setUpClass()
-        if not tempest.tests.boto.A_I_IMAGES_READY:
+        if not cls.conclusion['A_I_IMAGES_READY']:
             raise cls.skipException("".join(("EC2 ", cls.__name__,
                                     ": requires ami/aki/ari manifest")))
         cls.os = clients.Manager()
@@ -86,7 +86,8 @@
             if state != "available":
                 for _image in cls.images.itervalues():
                     cls.ec2_client.deregister_image(_image["image_id"])
-                raise EC2RegisterImageException(image_id=image["image_id"])
+                raise exceptions.EC2RegisterImageException(image_id=
+                                                           image["image_id"])
 
     @attr(type='smoke')
     def test_run_stop_terminate_instance(self):
@@ -129,7 +130,7 @@
             instance.update(validate=True)
         except ValueError:
             pass
-        except EC2ResponseError as exc:
+        except exception.EC2ResponseError as exc:
             if self.ec2_error_code.\
                 client.InvalidInstanceID.NotFound.match(exc):
                 pass
@@ -141,6 +142,7 @@
     #NOTE(afazekas): doctored test case,
     # with normal validation it would fail
     @attr("slow", type='smoke')
+    @testtools.skip("Skipped until the Bug #1117555 is resolved")
     def test_integration_1(self):
         # EC2 1. integration test (not strict)
         image_ami = self.ec2_client.get_image(self.images["ami"]["image_id"])
@@ -150,16 +152,18 @@
                                                                group_desc)
         self.addResourceCleanUp(self.destroy_security_group_wait,
                                 security_group)
-        self.ec2_client.authorize_security_group(sec_group_name,
-                                                 ip_protocol="icmp",
-                                                 cidr_ip="0.0.0.0/0",
-                                                 from_port=-1,
-                                                 to_port=-1)
-        self.ec2_client.authorize_security_group(sec_group_name,
-                                                 ip_protocol="tcp",
-                                                 cidr_ip="0.0.0.0/0",
-                                                 from_port=22,
-                                                 to_port=22)
+        self.assertTrue(self.ec2_client.authorize_security_group(
+                sec_group_name,
+                ip_protocol="icmp",
+                cidr_ip="0.0.0.0/0",
+                from_port=-1,
+                to_port=-1))
+        self.assertTrue(self.ec2_client.authorize_security_group(
+                sec_group_name,
+                ip_protocol="tcp",
+                cidr_ip="0.0.0.0/0",
+                from_port=22,
+                to_port=22))
         reservation = image_ami.run(kernel_id=self.images["aki"]["image_id"],
                                     ramdisk_id=self.images["ari"]["image_id"],
                                     instance_type=self.instance_type,
@@ -176,7 +180,7 @@
 
         address = self.ec2_client.allocate_address()
         rcuk_a = self.addResourceCleanUp(address.delete)
-        address.associate(instance.id)
+        self.assertTrue(address.associate(instance.id))
 
         rcuk_da = self.addResourceCleanUp(address.disassociate)
         #TODO(afazekas): ping test. dependecy/permission ?
diff --git a/tempest/tests/boto/test_s3_ec2_images.py b/tempest/tests/boto/test_s3_ec2_images.py
index 1088b00..4068aba 100644
--- a/tempest/tests/boto/test_s3_ec2_images.py
+++ b/tempest/tests/boto/test_s3_ec2_images.py
@@ -23,7 +23,6 @@
 from tempest.common.utils.data_utils import rand_name
 from tempest.test import attr
 from tempest.testboto import BotoTestCase
-import tempest.tests.boto
 from tempest.tests.boto.utils.s3 import s3_upload_dir
 from tempest.tests.boto.utils.wait import state_wait
 
@@ -34,7 +33,7 @@
     @classmethod
     def setUpClass(cls):
         super(S3ImagesTest, cls).setUpClass()
-        if not tempest.tests.boto.A_I_IMAGES_READY:
+        if not cls.conclusion['A_I_IMAGES_READY']:
             raise cls.skipException("".join(("EC2 ", cls.__name__,
                                     ": requires ami/aki/ari manifest")))
         cls.os = clients.Manager()
diff --git a/tempest/tests/compute/admin/test_quotas.py b/tempest/tests/compute/admin/test_quotas.py
index d63f72f..7430a7c 100644
--- a/tempest/tests/compute/admin/test_quotas.py
+++ b/tempest/tests/compute/admin/test_quotas.py
@@ -152,6 +152,19 @@
 
 #TODO(afazekas): Add test that tried to update the quota_set as a regular user
 
+    @attr(type='negative')
+    def test_create_server_when_instances_quota_is_full(self):
+        #Once instances quota limit is reached, disallow server creation
+        resp, quota_set = self.client.get_quota_set(self.demo_tenant_id)
+        default_instances_quota = quota_set['instances']
+        instances_quota = 0  # Set quota to zero to disallow server creation
+
+        self.adm_client.update_quota_set(self.demo_tenant_id,
+                                         instances=instances_quota)
+        self.addCleanup(self.adm_client.update_quota_set, self.demo_tenant_id,
+                        instances=default_instances_quota)
+        self.assertRaises(exceptions.OverLimit, self.create_server)
+
 
 class QuotasAdminTestXML(QuotasAdminTestJSON):
     _interface = 'xml'
diff --git a/tempest/tests/compute/floating_ips/test_floating_ips_actions.py b/tempest/tests/compute/floating_ips/test_floating_ips_actions.py
index d9f9613..0ff81e1 100644
--- a/tempest/tests/compute/floating_ips/test_floating_ips_actions.py
+++ b/tempest/tests/compute/floating_ips/test_floating_ips_actions.py
@@ -162,7 +162,8 @@
                             self.new_server_id)
 
         # Make sure no longer associated with old server
-        self.assertRaises((exceptions.NotFound, exceptions.BadRequest),
+        self.assertRaises((exceptions.NotFound,
+                           exceptions.UnprocessableEntity),
                           self.client.disassociate_floating_ip_from_server,
                           self.floating_ip, self.server_id)
 
diff --git a/tempest/tests/compute/servers/test_server_metadata.py b/tempest/tests/compute/servers/test_server_metadata.py
index 4b17fa2..bc523de 100644
--- a/tempest/tests/compute/servers/test_server_metadata.py
+++ b/tempest/tests/compute/servers/test_server_metadata.py
@@ -15,28 +15,25 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest.common.utils.data_utils import rand_name
 from tempest import exceptions
 from tempest.test import attr
 from tempest.tests.compute import base
 
 
-class ServerMetadataTest(base.BaseComputeTest):
+class ServerMetadataTestJSON(base.BaseComputeTest):
     _interface = 'json'
 
     @classmethod
     def setUpClass(cls):
-        super(ServerMetadataTest, cls).setUpClass()
+        super(ServerMetadataTestJSON, cls).setUpClass()
         cls.client = cls.servers_client
         cls.quotas = cls.quotas_client
         cls.admin_client = cls._get_identity_admin_client()
         resp, tenants = cls.admin_client.list_tenants()
         cls.tenant_id = [tnt['id'] for tnt in tenants if tnt['name'] ==
                          cls.client.tenant_name][0]
-        #Create a server to be used for all read only tests
-        name = rand_name('server')
-        resp, server = cls.client.create_server(name, cls.image_ref,
-                                                cls.flavor_ref, meta={})
+        resp, server = cls.create_server(meta={})
+
         cls.server_id = server['id']
 
         #Wait for the server to become active
@@ -45,10 +42,10 @@
     @classmethod
     def tearDownClass(cls):
         cls.client.delete_server(cls.server_id)
-        super(ServerMetadataTest, cls).tearDownClass()
+        super(ServerMetadataTestJSON, cls).tearDownClass()
 
     def setUp(self):
-        super(ServerMetadataTest, self).setUp()
+        super(ServerMetadataTestJSON, self).setUp()
         meta = {'key1': 'value1', 'key2': 'value2'}
         resp, _ = self.client.set_server_metadata(self.server_id, meta)
         self.assertEqual(resp.status, 200)
@@ -238,3 +235,7 @@
         self.assertRaises(exceptions.BadRequest,
                           self.client.set_server_metadata,
                           self.server_id, meta=meta)
+
+
+class ServerMetadataTestXML(ServerMetadataTestJSON):
+    _interface = 'xml'
diff --git a/tempest/tests/compute/test_live_block_migration.py b/tempest/tests/compute/test_live_block_migration.py
index dcd6a78..f2ec753 100644
--- a/tempest/tests/compute/test_live_block_migration.py
+++ b/tempest/tests/compute/test_live_block_migration.py
@@ -86,7 +86,7 @@
             if 'ACTIVE' == self._get_server_status(server_id):
                 return server_id
         else:
-            server = self.create_server()
+            _, server = self.create_server(wait_until="ACTIVE")
             server_id = server['id']
             self.password = server['adminPass']
             self.password = 'password'
diff --git a/tempest/services/image/json/__init__.py b/tempest/tests/image/v1/__init__.py
similarity index 100%
copy from tempest/services/image/json/__init__.py
copy to tempest/tests/image/v1/__init__.py
diff --git a/tempest/tests/image/test_images.py b/tempest/tests/image/v1/test_images.py
similarity index 100%
rename from tempest/tests/image/test_images.py
rename to tempest/tests/image/v1/test_images.py
diff --git a/tools/install_venv_common.py b/tools/install_venv_common.py
index 8f91251..fd9076f 100644
--- a/tools/install_venv_common.py
+++ b/tools/install_venv_common.py
@@ -21,20 +21,12 @@
 Synced in from openstack-common
 """
 
+import argparse
 import os
 import subprocess
 import sys
 
 
-possible_topdir = os.getcwd()
-if os.path.exists(os.path.join(possible_topdir, "tempest",
-                               "__init__.py")):
-    sys.path.insert(0, possible_topdir)
-
-
-from tempest.openstack.common import cfg
-
-
 class InstallVenv(object):
 
     def __init__(self, root, venv, pip_requires, test_requires, py_version,
@@ -139,17 +131,12 @@
 
     def parse_args(self, argv):
         """Parses command-line arguments."""
-        cli_opts = [
-            cfg.BoolOpt('no-site-packages',
-                        default=False,
-                        short='n',
-                        help="Do not inherit packages from global Python"
-                             "install"),
-        ]
-        CLI = cfg.ConfigOpts()
-        CLI.register_cli_opts(cli_opts)
-        CLI(argv[1:])
-        return CLI
+        parser = argparse.ArgumentParser()
+        parser.add_argument('-n', '--no-site-packages',
+                            action='store_true',
+                            help="Do not inherit packages from global Python "
+                                 "install")
+        return parser.parse_args(argv[1:])
 
 
 class Distro(InstallVenv):