示例#1
0
 def set_attr(self, value):
     if not isinstance(value, (list, StoreLocations)):
         reason = _('Invalid locations')
         raise exception.BadStoreUri(message=reason)
     ori_value = getattr(getattr(self, target), attr)
     if ori_value != value:
         # NOTE(flwang): If all the URL of passed-in locations are same as
         # current image locations, that means user would like to only
         # update the metadata, not the URL.
         ordered_value = sorted([loc['url'] for loc in value])
         ordered_ori = sorted([loc['url'] for loc in ori_value])
         if len(ori_value) > 0 and ordered_value != ordered_ori:
             raise exception.Invalid(
                 _('Original locations is not empty: '
                   '%s') % ori_value)
         # NOTE(zhiyan): Check locations are all valid
         # NOTE(flwang): If all the URL of passed-in locations are same as
         # current image locations, then it's not necessary to verify those
         # locations again. Otherwise, if there is any restricted scheme in
         # existing locations. _check_image_location will fail.
         if ordered_value != ordered_ori:
             for loc in value:
                 _check_image_location(self.context, self.store_api,
                                       self.store_utils, loc)
                 loc['status'] = 'active'
                 if _count_duplicated_locations(value, loc) > 1:
                     raise exception.DuplicateLocation(location=loc['url'])
             _set_image_size(self.context, getattr(self, target), value)
         else:
             for loc in value:
                 loc['status'] = 'active'
         return setattr(getattr(self, target), attr, list(value))
示例#2
0
    def wrapper(*args, **kwargs):
        def _is_match(some_str):
            return (isinstance(some_str, six.text_type)
                    and REGEX_4BYTE_UNICODE.findall(some_str) != [])

        def _check_dict(data_dict):
            # a dict of dicts has to be checked recursively
            for key, value in six.iteritems(data_dict):
                if isinstance(value, dict):
                    _check_dict(value)
                else:
                    if _is_match(key):
                        msg = _("Property names can't contain 4 byte unicode.")
                        raise exception.Invalid(msg)
                    if _is_match(value):
                        msg = (
                            _("%s can't contain 4 byte unicode characters.") %
                            key.title())
                        raise exception.Invalid(msg)

        for data_dict in [arg for arg in args if isinstance(arg, dict)]:
            _check_dict(data_dict)
        # now check args for str values
        for arg in args:
            if _is_match(arg):
                msg = _("Param values can't contain 4 byte unicode.")
                raise exception.Invalid(msg)
        # check kwargs as well, as params are passed as kwargs via
        # registry calls
        _check_dict(kwargs)
        return f(*args, **kwargs)
示例#3
0
文件: __init__.py 项目: afliu/glance
 def locations(self, value):
     if not isinstance(value, (list, QuotaImageLocationsProxy)):
         raise exception.Invalid(_('Invalid locations: %s') % value)
     glance.api.common.check_quota(self.context,
                                   self.image.size * len(value),
                                   self.db_api,
                                   image_id=self.image.image_id)
     self.image.locations = value
示例#4
0
 def locations(self, value):
     if not isinstance(value, (list, ImageLocationsProxy)):
         raise exception.Invalid(_('Invalid locations: %s') % value)
     self.policy.enforce(self.context, 'set_image_location', {})
     new_locations = list(value)
     if (set([loc['url'] for loc in self.image.locations]) -
             set([loc['url'] for loc in new_locations])):
         self.policy.enforce(self.context, 'delete_image_location', {})
     self.image.locations = new_locations
示例#5
0
def _validate_image(values):
    """
    Validates the incoming data and raises a Invalid exception
    if anything is out of order.

    :param values: Mapping of image metadata to check
    """

    status = values.get('status', None)
    if not status:
        msg = "Image status is required."
        raise exception.Invalid(msg)

    if status not in STATUSES:
        msg = "Invalid image status '%s' for image." % status
        raise exception.Invalid(msg)

    return values
 def remove(self, artifact):
     """
     Checks that artifact has no dependencies and removes it.
     Otherwise an exception is raised
     """
     for param in artifact.metadata.attributes.dependencies:
         if getattr(artifact, param):
             raise exc.Invalid(_(
                 "Dependency property '%s' has to be deleted first") %
                 param)
     return self.base.remove(self.helper.unproxy(artifact))
示例#7
0
def image_member_count(context, image_id):
    """Return the number of image members for this image

    :param image_id: identifier of image entity
    """
    if not image_id:
        msg = _("Image id is required.")
        raise exception.Invalid(msg)

    members = DATA['members']
    return len(filter(lambda x: x['image_id'] == image_id, members))
示例#8
0
def unpack_task_input(task):
    """Verifies and returns valid task input dictionary.

    :param task: Task domain object
    """
    task_type = task.type
    task_input = task.task_input

    if task_type == 'api_image_import':
        if 'import_method' not in task_input:
            msg = _("Input does not contain 'import_method'")
            raise exception.Invalid(msg)
    else:
        for key in ["import_from", "import_from_format", "image_properties"]:
            if key not in task_input:
                msg = (_("Input does not contain '%(key)s' field") % {
                    "key": key
                })
                raise exception.Invalid(msg)

    return task_input
示例#9
0
    def get_images_detailed(self, filters=None, marker=None, limit=3):
        if marker is None:
            index = 0
        else:
            for index, image in enumerate(self.images):
                if image['id'] == str(marker):
                    index += 1
                    break
            else:
                raise glance_exception.Invalid()

        return self.images[index:index + limit]
示例#10
0
    def locations(self, value):
        _enforce_image_location_quota(self.image, value, is_setter=True)

        if not isinstance(value, (list, QuotaImageLocationsProxy)):
            raise exception.Invalid(_('Invalid locations: %s') % value)

        required_size = _calc_required_size(self.context, self.image, value)

        glance.api.common.check_quota(self.context,
                                      required_size,
                                      self.db_api,
                                      image_id=self.image.image_id)
        self.image.locations = value
示例#11
0
def ensure_image_dict_v2_compliant(image):
    """
    Accepts an image dictionary that contains a v1-style 'is_public' member
    and returns the equivalent v2-style image dictionary.
    """
    if ('is_public' in image):
        if ('visibility' in image):
            msg = _("Specifying both 'visibility' and 'is_public' is not "
                    "permiitted.")
            raise exception.Invalid(msg)
        else:
            image['visibility'] = ('public' if image.pop('is_public') else
                                   'shared')
    return image
示例#12
0
def image_create(context, image_values):
    global DATA
    image_id = image_values.get('id', uuidutils.generate_uuid())

    if image_id in DATA['images']:
        raise exception.Duplicate()

    if 'status' not in image_values:
        raise exception.Invalid('status is a required attribute')

    allowed_keys = set(['id', 'name', 'status', 'min_ram', 'min_disk', 'size',
                        'checksum', 'locations', 'owner', 'protected',
                        'is_public', 'container_format', 'disk_format',
                        'created_at', 'updated_at', 'deleted_at', 'deleted',
                        'properties', 'tags'])

    if set(image_values.keys()) - allowed_keys:
        raise exception.Invalid()

    image = _image_format(image_id, **image_values)
    DATA['images'][image_id] = image
    DATA['tags'][image_id] = image.pop('tags', [])
    return image
示例#13
0
def validate_mysql_int(*args, **kwargs):
    """
    Make sure that all arguments are less than 2 ** 31 - 1.

    This limitation is introduced because mysql stores INT in 4 bytes.
    If the validation fails for some argument, exception.Invalid is raised with
    appropriate information.
    """
    max_int = (2 ** 31) - 1
    for param in args:
        if param > max_int:
            msg = _("Value %(value)d out of range, "
                    "must not exceed %(max)d") % {"value": param,
                                                  "max": max_int}
            raise exception.Invalid(msg)

    for param_str in kwargs:
        param = kwargs.get(param_str)
        if param and param > max_int:
            msg = _("'%(param)s' value out of range, "
                    "must not exceed %(max)d") % {"param": param_str,
                                                  "max": max_int}
            raise exception.Invalid(msg)
示例#14
0
 def set_attr(self, value):
     if not isinstance(value, (list, StoreLocations)):
         raise exception.BadStoreUri(_('Invalid locations: %s') % value)
     ori_value = getattr(getattr(self, target), attr)
     if ori_value != value:
         # NOTE(zhiyan): Enforced locations list was previously empty list.
         if len(ori_value) > 0:
             raise exception.Invalid(
                 _('Original locations is not empty: '
                   '%s') % ori_value)
         # NOTE(zhiyan): Check locations are all valid.
         for location in value:
             _check_image_location(self.context, self.store_api, location)
         return setattr(getattr(self, target), attr, list(value))
示例#15
0
def unpack_task_input(task):
    """Verifies and returns valid task input dictionary.

    :param task: Task domain object
    """
    task_input = task.task_input

    # NOTE: until we support multiple task types, we just check for
    # input fields related to 'import task'.
    for key in ["import_from", "import_from_format", "image_properties"]:
        if key not in task_input:
            msg = _("Input does not contain '%(key)s' field") % {"key": key}
            raise exception.Invalid(msg)

    return task_input
示例#16
0
文件: api.py 项目: russellb/glance
def validate_image(values):
    """
    Validates the incoming data and raises a Invalid exception
    if anything is out of order.

    :param values: Mapping of image metadata to check
    """
    status = values.get('status')
    disk_format = values.get('disk_format')
    container_format = values.get('container_format')

    status = values.get('status', None)
    if not status:
        msg = "Image status is required."
        raise exception.Invalid(msg)

    if status not in STATUSES:
        msg = "Invalid image status '%s' for image." % status
        raise exception.Invalid(msg)

    if disk_format and disk_format not in DISK_FORMATS:
        msg = "Invalid disk format '%s' for image." % disk_format
        raise exception.Invalid(msg)

    if container_format and container_format not in CONTAINER_FORMATS:
        msg = "Invalid container format '%s' for image." % container_format
        raise exception.Invalid(msg)

    if disk_format in ('aki', 'ari', 'ami') or\
            container_format in ('aki', 'ari', 'ami'):
        if container_format != disk_format:
            msg = ("Invalid mix of disk and container formats. "
                   "When setting a disk or container format to "
                   "one of 'ami', 'ari', or 'ami', the container "
                   "and disk formats must match.")
            raise exception.Invalid(msg)
示例#17
0
def image_member_count(context, image_id):
    """Return the number of image members for this image

    :param image_id: identifier of image entity
    """
    session = _get_session()

    if not image_id:
        msg = _("Image id is required.")
        raise exception.Invalid(msg)

    query = session.query(models.ImageMember)
    query = query.filter_by(deleted=False)
    query = query.filter(models.ImageMember.image_id == str(image_id))

    return query.count()
def validate_image(values):
    """
    Validates the incoming data and raises a Invalid exception
    if anything is out of order.

    :param values: Mapping of image metadata to check
    """
    status = values.get('status')
    disk_format = values.get('disk_format')
    container_format = values.get('container_format')

    status = values.get('status', None)
    if not status:
        msg = "Image status is required."
        raise exception.Invalid(msg)

    if status not in STATUSES:
        msg = "Invalid image status '%s' for image." % status
        raise exception.Invalid(msg)

    def _required_format_absent(format, formats):
        activating = status == 'active'
        unrecognized = format not in formats
        # We don't mind having format = None when we're just registering
        # an image, but if the image is being activated, make sure that the
        # format is valid. Conversely if the format happens to be set on
        # registration, it must be one of the recognized formats.
        return ((activating and (not format or unrecognized))
                or (not activating and format and unrecognized))

    if _required_format_absent(disk_format, DISK_FORMATS):
        msg = "Invalid disk format '%s' for image." % disk_format
        raise exception.Invalid(msg)

    if _required_format_absent(container_format, CONTAINER_FORMATS):
        msg = "Invalid container format '%s' for image." % container_format
        raise exception.Invalid(msg)

    if disk_format in ('aki', 'ari', 'ami') or\
            container_format in ('aki', 'ari', 'ami'):
        if container_format != disk_format:
            msg = ("Invalid mix of disk and container formats. "
                   "When setting a disk or container format to "
                   "one of 'ami', 'ari', or 'ami', the container "
                   "and disk formats must match.")
            raise exception.Invalid(msg)

    name = values.get('name')
    if name and len(name) > 255:
        msg = _('Image name too long: %d') % len(name)
        raise exception.Invalid(msg)
示例#19
0
 def set_attr(self, value):
     if not isinstance(value, (list, StoreLocations)):
         reason = _('Invalid locations')
         raise exception.BadStoreUri(message=reason)
     ori_value = getattr(getattr(self, target), attr)
     if ori_value != value:
         # NOTE(zhiyan): Enforced locations list was previously empty list.
         if len(ori_value) > 0:
             raise exception.Invalid(
                 _('Original locations is not empty: '
                   '%s') % ori_value)
         # NOTE(zhiyan): Check locations are all valid.
         for location in value:
             _check_image_location(self.context, self.store_api, location)
             location['status'] = 'active'
             if _count_duplicated_locations(value, location) > 1:
                 raise exception.DuplicateLocation(location=location['url'])
         _set_image_size(self.context, getattr(self, target), value)
         return setattr(getattr(self, target), attr, list(value))
示例#20
0
def fix_uri_credentials(uri, to_quoted):
    """
    Fix the given uri's embedded credentials by round-tripping with
    StoreLocation.

    If to_quoted is True, the uri is assumed to have credentials that
    have not been quoted, and the resulting uri will contain quoted
    credentials.

    If to_quoted is False, the uri is assumed to have credentials that
    have been quoted, and the resulting uri will contain credentials
    that have not been quoted.
    """
    if not uri:
        return
    try:
        decrypted_uri = decrypt_location(uri)
    # NOTE (ameade): If a uri is not encrypted or incorrectly encoded then we
    # we raise an exception.
    except (TypeError, ValueError) as e:
        raise exception.Invalid(str(e))

    return legacy_parse_uri(decrypted_uri, to_quoted)
示例#21
0
    def _do_request(self,
                    method,
                    action,
                    body=None,
                    headers=None,
                    params=None):
        """
        Connects to the server and issues a request.  Handles converting
        any returned HTTP error status codes to OpenStack/Glance exceptions
        and closing the server connection. Returns the result data, or
        raises an appropriate exception.

        :param method: HTTP method ("GET", "POST", "PUT", etc...)
        :param action: part of URL after root netloc
        :param body: string of data to send, or None (default)
        :param headers: mapping of key/value pairs to add as headers
        :param params: dictionary of key/value pairs to add to append
                             to action

        :note

        If the body param has a read attribute, and method is either
        POST or PUT, this method will automatically conduct a chunked-transfer
        encoding and use the body as a file object, transferring chunks
        of data using the connection's send() method. This allows large
        objects to be transferred efficiently without buffering the entire
        body in memory.
        """
        if type(params) is dict:

            # remove any params that are None
            for (key, value) in params.items():
                if value is None:
                    del params[key]

            action += '?' + urllib.urlencode(params)

        try:
            connection_type = self.get_connection_type()
            headers = headers or {}

            if 'x-auth-token' not in headers and self.auth_tok:
                headers['x-auth-token'] = self.auth_tok

            c = connection_type(self.host, self.port)

            if self.doc_root:
                action = '/'.join([self.doc_root, action.lstrip('/')])

            # Do a simple request or a chunked request, depending
            # on whether the body param is a file-like object and
            # the method is PUT or POST
            if hasattr(body, 'read') and method.lower() in ('post', 'put'):
                # Chunk it, baby...
                c.putrequest(method, action)

                for header, value in headers.items():
                    c.putheader(header, value)
                c.putheader('Transfer-Encoding', 'chunked')
                c.endheaders()

                chunk = body.read(self.CHUNKSIZE)
                while chunk:
                    c.send('%x\r\n%s\r\n' % (len(chunk), chunk))
                    chunk = body.read(self.CHUNKSIZE)
                c.send('0\r\n\r\n')
            else:
                # Simple request...
                c.request(method, action, body, headers)
            res = c.getresponse()
            status_code = self.get_status_code(res)
            if status_code in (httplib.OK, httplib.CREATED, httplib.ACCEPTED,
                               httplib.NO_CONTENT):
                return res
            elif status_code == httplib.UNAUTHORIZED:
                raise exception.NotAuthorized(res.read())
            elif status_code == httplib.FORBIDDEN:
                raise exception.NotAuthorized(res.read())
            elif status_code == httplib.NOT_FOUND:
                raise exception.NotFound(res.read())
            elif status_code == httplib.CONFLICT:
                raise exception.Duplicate(res.read())
            elif status_code == httplib.BAD_REQUEST:
                raise exception.Invalid(res.read())
            elif status_code == httplib.MULTIPLE_CHOICES:
                raise exception.MultipleChoices(body=res.read())
            elif status_code == httplib.INTERNAL_SERVER_ERROR:
                raise Exception("Internal Server error: %s" % res.read())
            else:
                raise Exception("Unknown error occurred! %s" % res.read())

        except (socket.error, IOError), e:
            raise exception.ClientConnectionError("Unable to connect to "
                                                  "server. Got error: %s" % e)
示例#22
0
def get_terminal_size():
    def _get_terminal_size_posix():
        import fcntl
        import struct
        import termios

        height_width = None

        try:
            height_width = struct.unpack(
                'hh',
                fcntl.ioctl(sys.stderr.fileno(), termios.TIOCGWINSZ,
                            struct.pack('HH', 0, 0)))
        except Exception:
            pass

        if not height_width:
            try:
                p = subprocess.Popen(['stty', 'size'],
                                     shell=False,
                                     stdout=subprocess.PIPE,
                                     stderr=open(os.devnull, 'w'))
                result = p.communicate()
                if p.returncode == 0:
                    return tuple(int(x) for x in result[0].split())
            except Exception:
                pass

        return height_width

    def _get_terminal_size_win32():
        try:
            from ctypes import create_string_buffer
            from ctypes import windll
            handle = windll.kernel32.GetStdHandle(-12)
            csbi = create_string_buffer(22)
            res = windll.kernel32.GetConsoleScreenBufferInfo(handle, csbi)
        except Exception:
            return None
        if res:
            import struct
            unpack_tmp = struct.unpack("hhhhHhhhhhh", csbi.raw)
            (bufx, bufy, curx, cury, wattr, left, top, right, bottom, maxx,
             maxy) = unpack_tmp
            height = bottom - top + 1
            width = right - left + 1
            return (height, width)
        else:
            return None

    def _get_terminal_size_unknownOS():
        raise NotImplementedError

    func = {
        'posix': _get_terminal_size_posix,
        'win32': _get_terminal_size_win32
    }

    height_width = func.get(platform.os.name, _get_terminal_size_unknownOS)()

    if height_width is None:
        raise exception.Invalid()

    for i in height_width:
        if not isinstance(i, int) or i <= 0:
            raise exception.Invalid()

    return height_width[0], height_width[1]
示例#23
0
    def _do_request(self, method, url, body, headers):
        """
        Connects to the server and issues a request.  Handles converting
        any returned HTTP error status codes to OpenStack/Glance exceptions
        and closing the server connection. Returns the result data, or
        raises an appropriate exception.

        :param method: HTTP method ("GET", "POST", "PUT", etc...)
        :param url: urlparse.ParsedResult object with URL information
        :param body: string of data to send, or None (default)
        :param headers: mapping of key/value pairs to add as headers

        :note

        If the body param has a read attribute, and method is either
        POST or PUT, this method will automatically conduct a chunked-transfer
        encoding and use the body as a file object, transferring chunks
        of data using the connection's send() method. This allows large
        objects to be transferred efficiently without buffering the entire
        body in memory.
        """
        if url.query:
            path = url.path + "?" + url.query
        else:
            path = url.path

        try:
            connection_type = self.get_connection_type()
            headers = headers or {}

            if 'x-auth-token' not in headers and self.auth_tok:
                headers['x-auth-token'] = self.auth_tok

            c = connection_type(url.hostname, url.port, **self.connect_kwargs)

            # Do a simple request or a chunked request, depending
            # on whether the body param is a file-like object and
            # the method is PUT or POST
            if hasattr(body, 'read') and method.lower() in ('post', 'put'):
                # Chunk it, baby...
                c.putrequest(method, path)

                for header, value in headers.items():
                    c.putheader(header, value)
                c.putheader('Transfer-Encoding', 'chunked')
                c.endheaders()

                chunk = body.read(self.CHUNKSIZE)
                while chunk:
                    c.send('%x\r\n%s\r\n' % (len(chunk), chunk))
                    chunk = body.read(self.CHUNKSIZE)
                c.send('0\r\n\r\n')
            else:
                # Simple request...
                c.request(method, path, body, headers)
            res = c.getresponse()
            status_code = self.get_status_code(res)
            if status_code in self.OK_RESPONSE_CODES:
                return res
            elif status_code in self.REDIRECT_RESPONSE_CODES:
                raise exception.RedirectException(res.getheader('Location'))
            elif status_code == httplib.UNAUTHORIZED:
                raise exception.NotAuthorized(res.read())
            elif status_code == httplib.FORBIDDEN:
                raise exception.NotAuthorized(res.read())
            elif status_code == httplib.NOT_FOUND:
                raise exception.NotFound(res.read())
            elif status_code == httplib.CONFLICT:
                raise exception.Duplicate(res.read())
            elif status_code == httplib.BAD_REQUEST:
                raise exception.Invalid(res.read())
            elif status_code == httplib.MULTIPLE_CHOICES:
                raise exception.MultipleChoices(body=res.read())
            elif status_code == httplib.INTERNAL_SERVER_ERROR:
                raise Exception("Internal Server error: %s" % res.read())
            else:
                raise Exception("Unknown error occurred! %s" % res.read())

        except (socket.error, IOError), e:
            raise exception.ClientConnectionError(e)
 def _check_dep_state(self, dep, state):
     """Raises an exception if dependency 'dep' is not in state 'state'"""
     if dep.state != state:
         raise exc.Invalid(_(
             "Not all dependencies are in '%s' state") % state)
示例#25
0
    def _do_request(self, method, url, body, headers):
        """
        Connects to the server and issues a request.  Handles converting
        any returned HTTP error status codes to OpenStack/Glance exceptions
        and closing the server connection. Returns the result data, or
        raises an appropriate exception.

        :param method: HTTP method ("GET", "POST", "PUT", etc...)
        :param url: urlparse.ParsedResult object with URL information
        :param body: data to send (as string, filelike or iterable),
                     or None (default)
        :param headers: mapping of key/value pairs to add as headers

        :note

        If the body param has a read attribute, and method is either
        POST or PUT, this method will automatically conduct a chunked-transfer
        encoding and use the body as a file object or iterable, transferring
        chunks of data using the connection's send() method. This allows large
        objects to be transferred efficiently without buffering the entire
        body in memory.
        """
        if url.query:
            path = url.path + "?" + url.query
        else:
            path = url.path

        try:
            connection_type = self.get_connection_type()
            headers = self._encode_headers(headers or {})

            if 'x-auth-token' not in headers and self.auth_tok:
                headers['x-auth-token'] = self.auth_tok

            c = connection_type(url.hostname, url.port, **self.connect_kwargs)

            def _pushing(method):
                return method.lower() in ('post', 'put')

            def _simple(body):
                return body is None or isinstance(body, six.string_types)

            def _filelike(body):
                return hasattr(body, 'read')

            def _sendbody(connection, iter):
                connection.endheaders()
                for sent in iter:
                    # iterator has done the heavy lifting
                    pass

            def _chunkbody(connection, iter):
                connection.putheader('Transfer-Encoding', 'chunked')
                connection.endheaders()
                for chunk in iter:
                    connection.send('%x\r\n%s\r\n' % (len(chunk), chunk))
                connection.send('0\r\n\r\n')

            # Do a simple request or a chunked request, depending
            # on whether the body param is file-like or iterable and
            # the method is PUT or POST
            #
            if not _pushing(method) or _simple(body):
                # Simple request...
                c.request(method, path, body, headers)
            elif _filelike(body) or self._iterable(body):
                c.putrequest(method, path)

                use_sendfile = self._sendable(body)

                # According to HTTP/1.1, Content-Length and Transfer-Encoding
                # conflict.
                for header, value in headers.items():
                    if use_sendfile or header.lower() != 'content-length':
                        c.putheader(header, str(value))

                iter = self.image_iterator(c, headers, body)

                if use_sendfile:
                    # send actual file without copying into userspace
                    _sendbody(c, iter)
                else:
                    # otherwise iterate and chunk
                    _chunkbody(c, iter)
            else:
                raise TypeError('Unsupported image type: %s' % body.__class__)

            res = c.getresponse()

            def _retry(res):
                return res.getheader('Retry-After')

            status_code = self.get_status_code(res)
            if status_code in self.OK_RESPONSE_CODES:
                return res
            elif status_code in self.REDIRECT_RESPONSE_CODES:
                raise exception.RedirectException(res.getheader('Location'))
            elif status_code == httplib.UNAUTHORIZED:
                raise exception.NotAuthenticated(res.read())
            elif status_code == httplib.FORBIDDEN:
                raise exception.Forbidden(res.read())
            elif status_code == httplib.NOT_FOUND:
                raise exception.NotFound(res.read())
            elif status_code == httplib.CONFLICT:
                raise exception.Duplicate(res.read())
            elif status_code == httplib.BAD_REQUEST:
                raise exception.Invalid(res.read())
            elif status_code == httplib.MULTIPLE_CHOICES:
                raise exception.MultipleChoices(body=res.read())
            elif status_code == httplib.REQUEST_ENTITY_TOO_LARGE:
                raise exception.LimitExceeded(retry=_retry(res),
                                              body=res.read())
            elif status_code == httplib.INTERNAL_SERVER_ERROR:
                raise exception.ServerError()
            elif status_code == httplib.SERVICE_UNAVAILABLE:
                raise exception.ServiceUnavailable(retry=_retry(res))
            else:
                raise exception.UnexpectedStatus(status=status_code,
                                                 body=res.read())

        except (socket.error, IOError) as e:
            raise exception.ClientConnectionError(e)