예제 #1
0
    def _fetch_sub_slo_segments(self, req, version, acc, con, obj):
        """
        Fetch the submanifest, parse it, and return it.
        Raise exception on failures.
        """
        sub_req = make_subrequest(
            req.environ,
            path='/'.join(['', version, acc, con, obj]),
            method='GET',
            headers={'x-auth-token': req.headers.get('x-auth-token')},
            agent=('%(orig)s ' + 'SLO MultipartGET'),
            swift_source='SLO')
        sub_resp = sub_req.get_response(self.slo.app)

        if not is_success(sub_resp.status_int):
            raise ListingIterError(
                'ERROR: while fetching %s, GET of submanifest %s '
                'failed with status %d' %
                (req.path, sub_req.path, sub_resp.status_int))

        try:
            with closing_if_possible(sub_resp.app_iter):
                return json.loads(''.join(sub_resp.app_iter))
        except ValueError as err:
            raise ListingIterError(
                'ERROR: while fetching %s, JSON-decoding of submanifest %s '
                'failed with %s' % (req.path, sub_req.path, err))
예제 #2
0
def direct_delete_container(node,
                            part,
                            account,
                            container,
                            conn_timeout=5,
                            response_timeout=15,
                            headers=None):
    if headers is None:
        headers = {}

    path = '/%s/%s' % (account, container)
    with Timeout(conn_timeout):
        conn = http_connect(node['ip'],
                            node['port'],
                            node['device'],
                            part,
                            'DELETE',
                            path,
                            headers=gen_headers(headers, True))
    with Timeout(response_timeout):
        resp = conn.getresponse()
        resp.read()

    if not is_success(resp.status):
        raise ClientException(
            'Container server %s:%s direct DELETE %s gave status %s' %
            (node['ip'], node['port'],
             repr('/%s/%s%s' % (node['device'], part, path)), resp.status),
            http_host=node['ip'],
            http_port=node['port'],
            http_device=node['device'],
            http_status=resp.status,
            http_reason=resp.reason)
    return resp.status
예제 #3
0
 def release_lock(self, host, file_system, directory, data):
     """ 
     Release lock from container
     param host: Host information of container
     param file_system: File system name in which object resides
     param directory: Directory name in which object resides
     param data: Request header dictionary
     return response: HTTP response
     """
     method_type = 'FREE_LOCK'
     try:
         response = http_connection(host, file_system, directory, data, \
             method_type)
         response.read()
         if not is_success(response.status):
             self._logger.error(('ERROR method %(method)s failed '
                                 'response status: %(status)d '), {
                                     'method': method_type,
                                     'status': response.status
                                 })
         return response
     except Exception as err:
         self._logger.error(('ERROR release_lock failed '
                             '%(host)s/%(fs)s/%(dir)s '), {
                                 'host': host,
                                 'fs': file_system,
                                 'dir': directory
                             })
         self._logger.exception(err)
         raise err
예제 #4
0
    def release_lock(self, obj_hash, metadata=None, host=''):
        '''
        Send request to container service for releasing transaction lock.

        :param obj_hash: object hash
        :returns: True, if lock is released
                  False, otherwise.
        '''
        # TODO: In case of recovery of incomplete files, we do not have
        #       account, container, obj name. So evaluating container service
        #       ip, port to which request will be submitted to release lock is
        #       not possible at this time. So this is a just a work around to
        #       get container service details.
        #       In future, some other solution can be implemented to better cope
        #       with such situation.
        directory, filesystem = '', ''
        if not metadata:
            try:
                try:
                    self._logger.info("obj hash : %s " % obj_hash)
                    #hash(/acc/cont)
                    cont_hash = obj_hash.split('/')[1]
                    #hash(/acc)
                    acc_hash = obj_hash.split('/')[0]
                except Exception as err:
                    self._logger.error("Exception raised")

                service_details, filesystem, directory = \
                    self.__container_ring.get_service_list(acc_hash, cont_hash)
                self._logger.info("ip : port in release lock : %s" % service_details)
                #service_list = ([{'ip': u'169.254.1.52', 'port': 61007}], filesystem, directory)
                if not host:
                    host = '%s:%s' % (service_details[0]['ip'], service_details[0]['port'])
                self._logger.debug(" Details -> filesystem: %s directory: %s" % \
                                   (filesystem, directory))
            except Exception as err:
                self._logger.error(__("Error raised in release lock %s" \
                    % err))

        else:
            host, filesystem, directory = self.__get_service_details(metadata, host=host)
        try:
            header = HeaderKeyDict({'x-object-path': obj_hash, 'x-global-map-version': '-1'})
            resp = http_connection(host, filesystem, directory, \
                                   header, 'FREE_LOCKS')
        except (Exception, Timeout):
            self._logger.exception(__(
                'ERROR Release lock failed '
                '%(ip)s for %(obj_name)s'),
                {'ip': host,
                 'obj_name': obj_hash})
            return False
        resp.read()
        if not is_success(resp.status):
            return False
        return True
예제 #5
0
def _get_direct_account_container(path,
                                  stype,
                                  node,
                                  part,
                                  account,
                                  marker=None,
                                  limit=None,
                                  prefix=None,
                                  delimiter=None,
                                  conn_timeout=5,
                                  response_timeout=15):
    """Base class for get direct account and container.

    Do not use directly use the get_direct_account or
    get_direct_container instead.
    """
    qs = 'format=json'
    if marker:
        qs += '&marker=%s' % quote(marker)
    if limit:
        qs += '&limit=%d' % limit
    if prefix:
        qs += '&prefix=%s' % quote(prefix)
    if delimiter:
        qs += '&delimiter=%s' % quote(delimiter)
    with Timeout(conn_timeout):
        conn = http_connect(node['ip'],
                            node['port'],
                            node['device'],
                            part,
                            'GET',
                            path,
                            query_string=qs,
                            headers=gen_headers())
    with Timeout(response_timeout):
        resp = conn.getresponse()
    if not is_success(resp.status):
        resp.read()
        raise ClientException(
            '%s server %s:%s direct GET %s gave stats %s' %
            (stype, node['ip'], node['port'],
             repr('/%s/%s%s' % (node['device'], part, path)), resp.status),
            http_host=node['ip'],
            http_port=node['port'],
            http_device=node['device'],
            http_status=resp.status,
            http_reason=resp.reason)
    resp_headers = {}
    for header, value in resp.getheaders():
        resp_headers[header.lower()] = value
    if resp.status == HTTP_NO_CONTENT:
        resp.read()
        return resp_headers, []
    return resp_headers, json.loads(resp.read()), resp.status
예제 #6
0
def direct_put_container(node,
                         part,
                         account,
                         container,
                         conn_timeout=5,
                         response_timeout=15,
                         headers=None):
    """
    Request container put directly from the container server.

    :param node: node dictionary from the ring
    :param part: partition the container is on
    :param account: account name
    :param container: container name
    :param conn_timeout: timeout in seconds for establishing the connection
    :param response_timeout: timeout in seconds for getting the response
    :param headers: additional headers to include in the request
    :returns: a dict containing the response's headers (all header names will
    be lowercase)
    """
    path = '/%s/%s' % (account, container)
    if headers is None:
        headers = {}
    with Timeout(conn_timeout):
        conn = http_connect(node['ip'],
                            node['port'],
                            node['device'],
                            part,
                            'PUT',
                            path,
                            headers=gen_headers(headers, True))
    with Timeout(response_timeout):
        resp = conn.getresponse()
        resp.read()
    if not is_success(resp.status):
        raise ClientException(
            'Container server %s:%s direct PUT %s gave status %s' %
            (node['ip'], node['port'],
             repr('/%s/%s%s' % (node['device'], part, path)), resp.status),
            http_host=node['ip'],
            http_port=node['port'],
            http_device=node['device'],
            http_status=resp.status,
            http_reason=resp.reason)
    resp_headers = {}
    for header, value in resp.getheaders():
        resp_headers[header.lower()] = value
    return resp_headers
예제 #7
0
    def container_update(self, metadata, duplicate=False,
                         method='PUT', host=None, unknown=False):
        '''
        Send request to container service for info file update

        :param metadata: object metadata
        :param duplicate: If set to true, then container update request
                          will contain 'x-duplicate-update: True' header
                          else it not contain any additional header.
        :param method: method name
        :param host: host IP and port
        :returns: True, If update successful
                  False, otherwise.
        '''
        if not metadata:
            header = HeaderKeyDict({'x-timestamp': \
                normalize_timestamp(time.time())})
            file_system, directory = '', ''
        else:
            host, directory, file_system = self.__get_service_details(metadata, host=host)
            try:
                header = HeaderKeyDict({
                    'x-global-map-version': '-1',
                    'x-size': metadata['Content-Length'],
                    'x-content-type': metadata['Content-Type'],
                    'x-timestamp': metadata['X-Timestamp'],
                    'x-etag': metadata['ETag']})
            except KeyError:
                return False
            header.update({'x-object-path': metadata['name']})
        if duplicate:
            header.update({'x-duplicate-update': True})
        if unknown:
            header.update({'x-duplicate-unknown': True})
        try:
            resp = http_connection(host, file_system, directory, \
                                   header, method)
        except (Exception, Timeout):
            self._logger.exception(__(
                'ERROR container update failed '
                '%(host)s/%(fs)s '),
                {'host': host,
                'fs': file_system})
            return False
        resp.read()
        if not is_success(resp.status):
            return False
        return True
예제 #8
0
def direct_head_object(node,
                       part,
                       account,
                       container,
                       obj,
                       conn_timeout=5,
                       response_timeout=15):
    """
    Request object information directly from the object server.

    :param node: node dictionary from the ring
    :param part: partition the container is on
    :param account: account name
    :param container: container name
    :param obj: object name
    :param conn_timeout: timeout in seconds for establishing the connection
    :param response_timeout: timeout in seconds for getting the response
    :returns: a dict containing the response's headers (all header names will
              be lowercase)
    """
    path = '/%s/%s/%s' % (account, container, obj)
    with Timeout(conn_timeout):
        conn = http_connect(node['ip'],
                            node['port'],
                            node['device'],
                            part,
                            'HEAD',
                            path,
                            headers=gen_headers())
    with Timeout(response_timeout):
        resp = conn.getresponse()
        resp.read()
    if not is_success(resp.status):
        raise ClientException(
            'Object server %s:%s direct HEAD %s gave status %s' %
            (node['ip'], node['port'],
             repr('/%s/%s%s' % (node['device'], part, path)), resp.status),
            http_host=node['ip'],
            http_port=node['port'],
            http_device=node['device'],
            http_status=resp.status,
            http_reason=resp.reason)
    resp_headers = {}
    for header, value in resp.getheaders():
        resp_headers[header.lower()] = value
    return resp_headers, resp.status
예제 #9
0
def direct_delete_object(node,
                         part,
                         account,
                         container,
                         obj,
                         conn_timeout=5,
                         response_timeout=15,
                         headers=None):
    """
    Delete object directly from the object server.

    :param node: node dictionary from the ring
    :param part: partition the container is on
    :param account: account name
    :param container: container name
    :param obj: object name
    :param conn_timeout: timeout in seconds for establishing the connection
    :param response_timeout: timeout in seconds for getting the response
    :returns: response from server
    """
    if headers is None:
        headers = {}

    path = '/%s/%s/%s' % (account, container, obj)
    with Timeout(conn_timeout):
        conn = http_connect(node['ip'],
                            node['port'],
                            node['device'],
                            part,
                            'DELETE',
                            path,
                            headers=gen_headers(headers, True))
    with Timeout(response_timeout):
        resp = conn.getresponse()
        resp.read()
    if not is_success(resp.status):
        raise ClientException(
            'Object server %s:%s direct DELETE %s gave status %s' %
            (node['ip'], node['port'],
             repr('/%s/%s%s' % (node['device'], part, path)), resp.status),
            http_host=node['ip'],
            http_port=node['port'],
            http_device=node['device'],
            http_status=resp.status,
            http_reason=resp.reason)
    return resp.status
예제 #10
0
def direct_delete_account_metadata(node,
                                   part,
                                   account,
                                   headers,
                                   conn_timeout=5,
                                   response_timeout=15):
    """
    Request account metadata delete directly from the account server.

    :param node: node dictionary from the ring
    :param part: partition the account is on
    :param account: account name
    :param headers: headers to delete metadata
    :param conn_timeout: timeout in seconds for establishing the connection
    :param response_timeout: timeout in seconds for getting the response
    :returns: a dict containing the response's headers (all header names will
              be lowercase)
    """
    path = '/%s' % (account)
    with Timeout(conn_timeout):
        conn = http_connect(node['ip'],
                            node['port'],
                            node['device'],
                            part,
                            'POST',
                            path,
                            headers=gen_headers(headers, True))
    with Timeout(response_timeout):
        resp = conn.getresponse()
        resp.read()
    if not is_success(resp.status):
        raise ClientException(
            'Account server %s:%s direct DELETE METADATA %s gave status %s' %
            (node['ip'], node['port'],
             repr('/%s/%s%s' % (node['device'], part, path)), resp.status),
            http_host=node['ip'],
            http_port=node['port'],
            http_device=node['device'],
            http_status=resp.status,
            http_reason=resp.reason)
    resp_headers = {}
    for header, value in resp.getheaders():
        resp_headers[header.lower()] = value
    return resp_headers, resp.status
예제 #11
0
def direct_post_object(node,
                       part,
                       account,
                       container,
                       name,
                       headers,
                       conn_timeout=5,
                       response_timeout=15):
    """
    Direct update to object metadata on object server.

    :param node: node dictionary from the ring
    :param part: partition the container is on
    :param account: account name
    :param container: container name
    :param name: object name
    :param headers: headers to store as metadata
    :param conn_timeout: timeout in seconds for establishing the connection
    :param response_timeout: timeout in seconds for getting the response
    :raises ClientException: HTTP POST request failed
    """
    path = '/%s/%s/%s' % (account, container, name)
    with Timeout(conn_timeout):
        conn = http_connect(node['ip'],
                            node['port'],
                            node['device'],
                            part,
                            'POST',
                            path,
                            headers=gen_headers(headers, True))
    with Timeout(response_timeout):
        resp = conn.getresponse()
        resp.read()
    if not is_success(resp.status):
        raise ClientException(
            'Object server %s:%s direct POST %s gave status %s' %
            (node['ip'], node['port'],
             repr('/%s/%s%s' % (node['device'], part, path)), resp.status),
            http_host=node['ip'],
            http_port=node['port'],
            http_device=node['device'],
            http_status=resp.status,
            http_reason=resp.reason)
    return resp.status
예제 #12
0
    def _need_to_refetch_manifest(self, req):
        """
        Just because a response shows that an object is a SLO manifest does not
        mean that response's body contains the entire SLO manifest. If it
        doesn't, we need to make a second request to actually get the whole
        thing.

        Note: this assumes that X-Static-Large-Object has already been found.
        """
        if req.method == 'HEAD':
            return True

        response_status = int(self._response_status[:3])

        # These are based on etag, and the SLO's etag is almost certainly not
        # the manifest object's etag. Still, it's highly likely that the
        # submitted If-None-Match won't match the manifest object's etag, so
        # we can avoid re-fetching the manifest if we got a successful
        # response.
        if ((req.if_match or req.if_none_match)
                and not is_success(response_status)):
            return True

        if req.range and response_status in (206, 416):
            content_range = ''
            for header, value in self._response_headers:
                if header.lower() == 'content-range':
                    content_range = value
                    break
            # e.g. Content-Range: bytes 0-14289/14290
            match = re.match('bytes (\d+)-(\d+)/(\d+)$', content_range)
            if not match:
                # Malformed or missing, so we don't know what we got.
                return True
            first_byte, last_byte, length = [int(x) for x in match.groups()]
            # If and only if we actually got back the full manifest body, then
            # we can avoid re-fetching the object.
            got_everything = (first_byte == 0 and last_byte == length - 1)
            return not got_everything

        return False
예제 #13
0
def conn_for_obj(inner_dict, conn_time, node_timeout, logger, object_map):
    """
    Make connection to object service for expired IDs
    Returns: None
    """
    try:
        service_id = inner_dict['x-server-id']
        full_path = inner_dict['x-object-path']
        # get ip, port of object service
        logger.debug("object_map: %s" % object_map)
        data = {}
        data['ip'] = object_map[service_id][0]
        data['port'] = object_map[service_id][1]
        # update dict for container service id
        #TODO:(jaivish):just look whether this needs to passed as default parameter, 
        #else no need to  change
        cont_service_id = get_container_id()
        inner_dict['x-server-id'] = cont_service_id
        #TODO
        # make connection
        with ConnectionTimeout(conn_time):
            logger.debug('Connection to object service started')
            conn = http_connect(data['ip'], data['port'], '/', '/', \
                'RECOVER', full_path, inner_dict)
            logger.debug('Connection to object service completed: path:%s , dict: %s' % \
                         (full_path, inner_dict))
        with Timeout(node_timeout):
            response = conn.getresponse()
            response.read()
            if not is_success(response.status):
                logger.error((
                'ERROR connection to object service failed for '
                'service-id: %(service_id)s'
                'HTTP response status: %(status)d '),
                {'service_id': service_id,
                'status': response.status})
    except (Exception, Timeout) as err:
        logger.error('Exception occurred in sending'
            'request to object service')
        logger.exception(err)
예제 #14
0
def process_bulk_delete_transctions(obj_list, conn_time, node_timeout, obj_version, ll_port, logger):
    """
    Method to call BULK_DELETE interface of object service
    """
    try:
        service_id = socket.gethostname() + '_' + str(ll_port) +'_object-server'
        #obj_ring = ObjectRing(RING_DIR, logger)
        #data = obj_ring.get_service_details(service_id)[0]
        service_obj = get_service_obj('object', logger)
        cont_service_id = get_container_id()
        headers = {'x-server-id':cont_service_id, \
        'X-GLOBAL-MAP-VERSION': obj_version}
        with ConnectionTimeout(conn_time):
            logger.debug('Connection to object service started')
            # add the obj_list in the baody of request
            conn = httplib.HTTPConnection(service_obj.get_ip(), \
            service_obj.get_port())
            if conn:
                conn.request("BULK_DELETE", '', str(obj_list),headers)
            else:
                logger.debug("Can not create connection to object server ")
        logger.debug('Connection to object service completed')
        with Timeout(node_timeout):
            response = conn.getresponse()
            response.read()
            if not is_success(response.status):
                logger.error((
                'ERROR connection to object service failed for '
                'service-id: %(service_id)s'
                'HTTP response status: %(status)d '),
                {'service_id': service_id,
                'status': response.status})
    except (Exception, Timeout) as err:
        logger.error('Exception occurred in sending'
            'request to object service')
        logger.exception(err)
예제 #15
0
    def __iter__(self):
        start_time = time.time()
        have_yielded_data = False

        if self.response and self.response.content_length:
            bytes_left = int(self.response.content_length)
        else:
            bytes_left = None

        try:
            for seg_path, seg_etag, seg_size, first_byte, last_byte \
                    in self.listing_iter:
                if time.time() - start_time > self.max_get_time:
                    raise SegmentError('ERROR: While processing manifest %s, '
                                       'max LO GET time of %ds exceeded' %
                                       (self.name, self.max_get_time))
                # Make sure that the segment is a plain old object, not some
                # flavor of large object, so that we can check its MD5.
                path = seg_path + '?multipart-manifest=get'
                seg_req = make_subrequest(
                    self.req.environ,
                    path=path,
                    method='GET',
                    headers={
                        'x-auth-token': self.req.headers.get('x-auth-token')
                    },
                    agent=('%(orig)s ' + self.ua_suffix),
                    swift_source=self.swift_source)
                if first_byte is not None or last_byte is not None:
                    seg_req.headers['Range'] = "bytes=%s-%s" % (
                        # The 0 is to avoid having a range like "bytes=-10",
                        # which actually means the *last* 10 bytes.
                        '0' if first_byte is None else first_byte,
                        '' if last_byte is None else last_byte)

                seg_resp = seg_req.get_response(self.app)
                if not is_success(seg_resp.status_int):
                    close_if_possible(seg_resp.app_iter)
                    raise SegmentError(
                        'ERROR: While processing manifest %s, '
                        'got %d while retrieving %s' %
                        (self.name, seg_resp.status_int, seg_path))

                elif ((seg_etag and (seg_resp.etag != seg_etag))
                      or (seg_size and (seg_resp.content_length != seg_size)
                          and not seg_req.range)):
                    # The content-length check is for security reasons. Seems
                    # possible that an attacker could upload a >1mb object and
                    # then replace it with a much smaller object with same
                    # etag. Then create a big nested SLO that calls that
                    # object many times which would hammer our obj servers. If
                    # this is a range request, don't check content-length
                    # because it won't match.
                    close_if_possible(seg_resp.app_iter)
                    raise SegmentError(
                        'Object segment no longer valid: '
                        '%(path)s etag: %(r_etag)s != %(s_etag)s or '
                        '%(r_size)s != %(s_size)s.' % {
                            'path': seg_req.path,
                            'r_etag': seg_resp.etag,
                            'r_size': seg_resp.content_length,
                            's_etag': seg_etag,
                            's_size': seg_size
                        })

                seg_hash = hashlib.md5()
                for chunk in seg_resp.app_iter:
                    seg_hash.update(chunk)
                    have_yielded_data = True
                    if bytes_left is None:
                        yield chunk
                    elif bytes_left >= len(chunk):
                        yield chunk
                        bytes_left -= len(chunk)
                    else:
                        yield chunk[:bytes_left]
                        bytes_left -= len(chunk)
                        close_if_possible(seg_resp.app_iter)
                        raise SegmentError(
                            'Too many bytes for %(name)s; truncating in '
                            '%(seg)s with %(left)d bytes left' % {
                                'name': self.name,
                                'seg': seg_req.path,
                                'left': bytes_left
                            })
                close_if_possible(seg_resp.app_iter)

                if seg_resp.etag and seg_hash.hexdigest() != seg_resp.etag \
                   and first_byte is None and last_byte is None:
                    raise SegmentError(
                        "Bad MD5 checksum in %(name)s for %(seg)s: headers had"
                        " %(etag)s, but object MD5 was actually %(actual)s" % {
                            'seg': seg_req.path,
                            'etag': seg_resp.etag,
                            'name': self.name,
                            'actual': seg_hash.hexdigest()
                        })

            if bytes_left:
                raise SegmentError(
                    'Not enough bytes for %s; closing connection' % self.name)

        except ListingIterError as err:
            # I have to save this error because yielding the ' ' below clears
            # the exception from the current stack frame.
            excinfo = sys.exc_info()
            self.logger.exception('ERROR: While processing manifest %s, %s',
                                  self.name, err)
            # Normally, exceptions before any data has been yielded will
            # cause Eventlet to send a 5xx response. In this particular
            # case of ListingIterError we don't want that and we'd rather
            # just send the normal 2xx response and then hang up early
            # since 5xx codes are often used to judge Service Level
            # Agreements and this ListingIterError indicates the user has
            # created an invalid condition.
            if not have_yielded_data:
                yield ' '
            raise excinfo
        except SegmentError as err:
            self.logger.exception(err)
            # This doesn't actually change the response status (we're too
            # late for that), but this does make it to the logs.
            if self.response:
                self.response.status = HTTP_SERVICE_UNAVAILABLE
            raise
예제 #16
0
    def send_accept_component_request(self, method, target_service_obj, \
                                                            comp_list):
        """
        Creating http connection, sending ACCEPT_COMPONENT_TRANSFER
        http request with component transfer list to target node
        and sending intermediate response to GL.

        :param method: ACCEPT_COMPONENT_TRANSFER 
        :param target_service_obj: target node object containing (ip, port, id)
        :param comp_list: transfer component list, need to send to target node 
    
        """
        headers = {}
        create_connection = False
        conn_timeout = float(self.conf.get('conn_timeout', 10))
        node_timeout = int(self.conf.get('node_timeout', 10))
        self.logger.debug("Entering connect_target_node method")
        filesystem = 'export'
        directory = 'OSP_01'
        path = '/recovery_process/'
        #Parameters are fixed, could be changes according to requirement.
        headers['Expect'] = '100-continue'
        headers['X-Timestamp'] = time.time()
        headers['Content-Type'] = 'text/plain'
        try:
            #header_content_key = (self.node['ip'], self.node['port'])
            Content_length = len(str(comp_list))
            headers['Content-Length'] = Content_length
            self.logger.info("Header Sent:%s, ip:%s, port:%s, filesystem:%s,"
                " directory:%s, path:%s method:%s" %(headers, \
                target_service_obj.get_ip(), target_service_obj.get_port(), \
                filesystem, directory, path, method))

            #Creating http connection to target node
            with ConnectionTimeout(conn_timeout):
                conn = http_connect(
                    target_service_obj.get_ip(), target_service_obj.get_port(),\
                    filesystem, directory, method, path, headers)
            with Timeout(node_timeout):
                resp = conn.getexpect()

            if resp.status == HTTP_CONTINUE:
                conn.resp = None
                self.logger.info("HTTP continue %s" % resp.status)
                create_connection = True
            elif is_success(resp.status):
                conn.resp = resp
                self.logger.info("Successfull status:%s" % resp.status)
                create_connection = True
            elif resp.status == HTTP_INSUFFICIENT_STORAGE:
                self.logger.error('ERROR Insufficient Storage' \
                      'ip:%s, port:%s' %(target_service_obj.get_ip(), \
                      target_service_obj.get_port()))
                create_connection = False
                self.check_transfer_component_map[
                    target_service_obj] = "Failed"
        except (Exception, Timeout) as err:
            self.logger.exception(
                "Exception occured: %s during http connect id :%s, \
                Expected: 100-continue" % (err, target_service_obj.get_id()))
            create_connection = False
            self.check_transfer_component_map[target_service_obj] = "Failed"

        # sending component list to target node over http connection
        if create_connection:
            conn.reader = str(comp_list)
            self.logger.info("Sending component List: %s" % \
                conn.reader)
            try:
                with ChunkWriteTimeout(node_timeout):
                    conn.send(conn.reader)
                    conn.send_data = True
            except (Exception, ChunkWriteTimeout) as err:
                self.logger.error('Exception occured : %s at id : %s \
                    info: send file failed' %
                                  (target_service_obj.get_id(), err))
                conn.send_data = False
                self.check_transfer_component_map[target_service_obj] = \
                    "Failed"

            self.logger.info("Sending component list:%s completed ip:%s port:%s"
                %(comp_list, target_service_obj.get_ip(), \
                target_service_obj.get_port()))

            def get_conn_response(conn, comp_list, node_timeout):
                """
                Getting connection response
                """
                try:
                    with Timeout(node_timeout):
                        if conn.resp:
                            self.logger.debug("conn.resp returned")
                            return conn.resp
                        else:
                            self.logger.debug("conn.getexpect()")
                            return conn.getexpect()
                except (Exception, Timeout):
                    self.check_transfer_component_map[target_service_obj] = \
                        "Failed"
                    self.logger.exception('get_conn_response: Trying to get \
                        final status for id:%s' %
                                          (target_service_obj.get_id()))

            retry_count = 3
            counter = 0
            if conn.send_data:
                response = get_conn_response(conn, comp_list, node_timeout)
                if response and is_success(response.status):
                    # send intermediate status to GL
                    self.logger.info("Sending intermediate state to GL for \
                        target service : %s" % target_service_obj.get_id())
                    transferred_comp_list = []
                    for comp in comp_list:
                        transferred_comp_list.append(
                            (comp, target_service_obj))
                    while counter < retry_count:
                        counter += 1
                        gl_info_obj = self._request_handler.get_gl_info()
                        conn_obj = self._request_handler.connector(\
                            IoType.EVENTIO, gl_info_obj)
                        if conn_obj != None:
                            ret = self._request_handler.comp_transfer_info(\
                                self.service_id, transferred_comp_list, \
                                conn_obj)
                            if ret.status.get_status_code() == Resp.SUCCESS:
                                self.logger.info("Sent intermediate response " \
                                    ":%s to GL" %transferred_comp_list)
                                self.update_final_transfer_status(comp_list)
                                self.check_transfer_component_map[\
                                    target_service_obj] = True
                                break
                            else:
                                self.logger.warning("Sending intermediate" \
                                    "response to GL failed, Retrying")
                        conn_obj.close()
                    if ret.status.get_status_code() != Resp.SUCCESS:
                        self.check_transfer_component_map[target_service_obj] =\
                            "Failed"
                else:
                    self.logger.error('get_response failed id:%s' \
                        %(target_service_obj.get_id()))
                    self.check_transfer_component_map[target_service_obj] = \
                        "Failed"
    def _get_put_responses(self, conns, nodes, send_intermediate_resp):
        post_quorum_timeout = float(self.conf.get('POST_QUORUM_TIMEOUT', 0.5))
        global final_recovery_status_list
        global final_status

        statuses = []
        reasons = []
        bodies = []
        self.logger.info("running get_put_response ..")

        def get_conn_response(conn):
            node_timeout = int(self.conf.get('NODE_TIMEOUT', 600))
            try:
                with Timeout(node_timeout):
                    if conn.resp:
                        self.logger.info("conn.resp returned")
                        return (conn.resp, conn)
                    else:
                        self.logger.info("conn.getresponse()")
                        return (conn.getresponse(), conn)
            except (Exception, Timeout):
                self.logger.exception(_("connection: %(conn)s \
                    get_put_response: %(status)s"                                                  ), \
                    {'conn': conn.node, \
                    'status': _('Trying to get final status ')})

        #Get response on Async.
        pile = GreenAsyncPile(len(conns))
        #pile = GreenPile(len(conns))
        for conn in conns:
            self.logger.info("Spawning get_conn_response for:%s" % conn.node)
            pile.spawn(get_conn_response, conn)

        component_list_sent = []
        for (response, conn) in pile:
            #Return responses from here to Gl.
            global list_to_gl
            if response:
                self.logger.info("response.status:%s" % type(response.status))
                #Send Intermediate response to Global Leader
                #for service_id, components in self.Map_from_gl.iteritems():

                for components in \
                    self.service_component_map['%s:%s' % (conn.node['ip'], \
                        conn.node['port'])]:
                    #Need to change 200 in int or str depends.
                    if response.status == 200:
                        self.logger.debug("Component no: %s" % components)
                        obj_id = ''
                        for key in self.Map_from_gl.keys():
                            if (key.get_ip() == str(conn.node['ip'])) and (str(
                                    key.get_port()) == str(conn.node['port'])):
                                obj_id = key
                        list_to_gl.append((components, obj_id))
                        #self.logger.info("Blocked before list to gl appended: %s" % obj_id)

                        eventlet.sleep()
                        #context-switch

                    else:
                        if (components, obj_id) in list_to_gl:
                            list_to_gl.remove((components, obj_id))

                component_list_sent.append('%s:%s'%(conn.node['ip'], \
                        conn.node['port']))

                eventlet.sleep(3)
                #context-switch

                self.logger.info("Component List: %s, list_to_gl: %s"% \
                    (list(set(component_list_sent)), list_to_gl))


                statuses.append((response.status, \
                    "%s:%s"%(conn.node['ip'], conn.node['port'])))
                reasons.append(response.reason)
                bodies.append(response.read())
                if response.status >= HTTP_INTERNAL_SERVER_ERROR:
                    self.logger.error("Error:%s returned from ip:%s port:%s" %\
                        (response.status, conn.node['ip'], \
                        conn.node['port']))
                elif is_success(response.status):
                    self.logger.info("success status returned")

        #pile.waitall(post_quorum_timeout)

        if send_intermediate_resp:
            self.logger.info("Filling Data in Queue")
            try:
                #list_of_tuple.put(list_to_gl, block=False)
                list_of_tuple.put_nowait(list(set(list_to_gl)))
            except Exception as err:
                self.logger.info("Queue Full exception: %s" % err)
            #list_of_tuple.put(list_to_gl)

            self.logger.info("Queue Put successfull")

        while len(statuses) < self.pile_size:
            statuses.append(HTTP_SERVICE_UNAVAILABLE)
            reasons.append('')
            bodies.append('')

        #send Final Response to GL.
        global clean_journal_flag
        for i in self.service_component_map:
            for j in self.service_component_map[i]:
                if i in component_list_sent:
                    final_recovery_status_list.append((j, True))
                else:
                    final_recovery_status_list.append((j, False))
                    final_status = False
                    clean_journal_flag = False  # Do not clean journal if anything failed

        self.logger.info("final recovery status: %s" %
                         final_recovery_status_list)
        self.logger.info("Returned status:%s, reason:%s, bodies:%s" % \
            (statuses, reasons, bodies))
        return statuses, reasons, bodies, component_list_sent
    def _connect_put_node(self,
                          node,
                          headers,
                          logger_thread_locals,
                          method="ACCEPT_COMPONENT_CONT_DATA"):
        """Method for a connect"""
        self.logger.thread_locals = logger_thread_locals
        try:
            client_timeout = int(self.conf.get('CLIENT_TIMEOUT', 500))
            conn_timeout = float(self.conf.get('CONNECTION_TIMEOUT', 30))
            node_timeout = int(self.conf.get('NODE_TIMEOUT', 600))
        except Exception as err:
            self.logger.info("error :%s" % err)

        self.logger.info("Entering connect_put method")

        #Some values are needed for connections.
        filesystem = 'export'
        directory = 'OSP'
        path = '/recovery_process/'
        #Parameters are fixed, could be changes according to requirement.

        #Making headers
        headers['Expect'] = '100-continue'
        headers['X-Timestamp'] = time.time()
        headers['Content-Type'] = 'text/plain'
        headers['X-Object-Gl-Version-Id'] = self.__object_gl_version
        try:
            header_content_key = "%s:%s" % (node['ip'], node['port'])

            #Content-length is assumed to be in integer.
            Content_length = \
                len(pickle.dumps(self.dictionary_new.get(header_content_key)))
            headers['Node-ip'] = header_content_key
            headers['Content-Length'] = Content_length
            #headers['X-GLOBAL-MAP-VERSION'] = -1 (for now send actual map version)
            #Receive map version from GL.(service_id,logger)
            try:
                global_map_version = get_global_map_version(
                    service_id_, logger_obj)
                if global_map_version:
                    logger_obj.info("Map version received: %s" %
                                    global_map_version)
                else:
                    logger_obj.debug("Map version not received so exit")
                    sys.exit(130)
            except Exception as err:
                logger_obj.debug("Map version exception raised, Exit :%s" %
                                 err)
                sys.exit(130)

            headers['X-GLOBAL-MAP-VERSION'] = global_map_version
            headers['X-Recovery-Request'] = True
            if self.service_component_map.has_key(header_content_key):
                headers[
                    'X-COMPONENT-NUMBER-LIST'] = self.service_component_map[
                        header_content_key]
            else:
                headers['X-COMPONENT-NUMBER-LIST'] = []

            self.logger.info("Header Sent: %s" % headers)
            start_time = time.time()
            with ConnectionTimeout(conn_timeout):
                conn = http_connect(node['ip'], node['port'], filesystem,
                                    directory, method, path, headers)
            with Timeout(node_timeout):
                resp = conn.getexpect()
            if resp.status == HTTP_CONTINUE:
                conn.resp = None
                conn.node = node
                self.logger.info("HTTP continue %s" % resp.status)
                return conn
            elif is_success(resp.status):
                conn.resp = resp
                conn.node = node
                self.logger.info("Successfull status:%s" % resp.status)
                return conn
            elif resp.status == HTTP_INSUFFICIENT_STORAGE:
                self.logger.error(
                    _('%(msg)s %(ip)s:%(port)s'), {
                        'msg': _('ERROR Insufficient Storage'),
                        'ip': node['ip'],
                        'port': node['port']
                    })
        except (Exception, Timeout) as err:
            self.logger.exception(
                _('ERROR with %(type)s server %(ip)s:%(port)s/ re: '
                  '%(info)s'), {
                      'type': "Container",
                      'ip': node['ip'],
                      'port': node['port'],
                      'info': "Expect: 100-continue on "
                  })
예제 #19
0
def direct_get_object(node,
                      part,
                      account,
                      container,
                      obj,
                      conn_timeout=5,
                      response_timeout=15,
                      resp_chunk_size=None,
                      headers=None):
    """
    Get object directly from the object server.

    :param node: node dictionary from the ring
    :param part: partition the container is on
    :param account: account name
    :param container: container name
    :param obj: object name
    :param conn_timeout: timeout in seconds for establishing the connection
    :param response_timeout: timeout in seconds for getting the response
    :param resp_chunk_size: if defined, chunk size of data to read.
    :param headers: dict to be passed into HTTPConnection headers
    :returns: a tuple of (response headers, the object's contents) The response
              headers will be a dict and all header names will be lowercase.
    """
    if headers is None:
        headers = {}

    path = '/%s/%s/%s' % (account, container, obj)
    with Timeout(conn_timeout):
        conn = http_connect(node['ip'],
                            node['port'],
                            node['device'],
                            part,
                            'GET',
                            path,
                            headers=gen_headers(headers))
    with Timeout(response_timeout):
        resp = conn.getresponse()
    if not is_success(resp.status):
        resp.read()
        raise ClientException(
            'Object server %s:%s direct GET %s gave status %s' %
            (node['ip'], node['port'],
             repr('/%s/%s%s' % (node['device'], part, path)), resp.status),
            http_host=node['ip'],
            http_port=node['port'],
            http_device=node['device'],
            http_status=resp.status,
            http_reason=resp.reason)
    if resp_chunk_size:

        def _object_body():
            buf = resp.read(resp_chunk_size)
            while buf:
                yield buf
                buf = resp.read(resp_chunk_size)

        object_body = _object_body()
    else:
        object_body = resp.read()
    resp_headers = {}
    for header, value in resp.getheaders():
        resp_headers[header.lower()] = value
    return resp_headers, object_body, resp.status
예제 #20
0
def direct_put_object(node,
                      part,
                      account,
                      container,
                      name,
                      contents,
                      content_length=None,
                      etag=None,
                      content_type=None,
                      headers=None,
                      conn_timeout=5,
                      response_timeout=15,
                      chunk_size=65535):
    """
    Put object directly from the object server.

    :param node: node dictionary from the ring
    :param part: partition the container is on
    :param account: account name
    :param container: container name
    :param name: object name
    :param contents: an iterable or string to read object data from
    :param content_length: value to send as content-length header
    :param etag: etag of contents
    :param content_type: value to send as content-type header
    :param headers: additional headers to include in the request
    :param conn_timeout: timeout in seconds for establishing the connection
    :param response_timeout: timeout in seconds for getting the response
    :param chunk_size: if defined, chunk size of data to send.
    :returns: etag from the server response
    """

    path = '/%s/%s/%s' % (account, container, name)
    if headers is None:
        headers = {}
    if etag:
        headers['ETag'] = etag.strip('"')
    if content_length is not None:
        headers['Content-Length'] = str(content_length)
    else:
        for n, v in headers.iteritems():
            if n.lower() == 'content-length':
                content_length = int(v)
    if content_type is not None:
        headers['Content-Type'] = content_type
    else:
        headers['Content-Type'] = 'application/octet-stream'
    if not contents:
        headers['Content-Length'] = '0'
    if isinstance(contents, basestring):
        contents = [contents]
    #Incase the caller want to insert an object with specific age
    add_ts = 'X-Timestamp' not in headers

    if content_length is None:
        headers['Transfer-Encoding'] = 'chunked'

    with Timeout(conn_timeout):
        conn = http_connect(node['ip'],
                            node['port'],
                            node['device'],
                            part,
                            'PUT',
                            path,
                            headers=gen_headers(headers, add_ts))

    contents_f = FileLikeIter(contents)

    if content_length is None:
        chunk = contents_f.read(chunk_size)
        while chunk:
            conn.send('%x\r\n%s\r\n' % (len(chunk), chunk))
            chunk = contents_f.read(chunk_size)
        conn.send('0\r\n\r\n')
    else:
        left = content_length
        while left > 0:
            size = chunk_size
            if size > left:
                size = left
            chunk = contents_f.read(size)
            if not chunk:
                break
            conn.send(chunk)
            left -= len(chunk)

    with Timeout(response_timeout):
        resp = conn.getresponse()
        resp.read()
    if not is_success(resp.status):
        raise ClientException(
            'Object server %s:%s direct PUT %s gave status %s' %
            (node['ip'], node['port'],
             repr('/%s/%s%s' % (node['device'], part, path)), resp.status),
            http_host=node['ip'],
            http_port=node['port'],
            http_device=node['device'],
            http_status=resp.status,
            http_reason=resp.reason)
    return resp.getheader('etag').strip('"'), resp.status