示例#1
0
文件: kdyno.py 项目: bittorrent/kdyno
    def get_session_token(self, duration_seconds=None, callback=None):
        #logging.info('retreiving session token')
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
        stream = tornado.iostream.SSLIOStream(s)
        stream._always_callback = True # get callbacks on stream.connect
        addr = (self.DefaultRegionEndpoint,443)
        yield gen.Task( stream.connect, addr )
        if stream.error:
            callback(ErrorResponse('error connecting to %s to get token' % str(addr) ) )
            raise StopIteration

        data = {'Action':'GetSessionToken'}
        if duration_seconds:
            data['DurationSeconds'] = duration_seconds
        request = AWSRequest('POST', self.DefaultRegionEndpoint, data)
        request.set_parameter('Version', self.APIVersion)
        request.sign_request(self.aws_key, self.aws_secret)
        body = request.to_postdata()
        request.headers['Content-Length'] = str(len(body))
        towrite = request.make_request_headers() + body
        #logging.info('writing %s' % towrite)
        yield gen.Task( stream.write, towrite )
        rawheaders = yield gen.Task( stream.read_until, '\r\n\r\n' )
        if not rawheaders:
            logging.error('read until headers returned null, likely socket closed...')
            callback( ErrorResponse('socket closed') )
            raise StopIteration

        code, headers = parse_headers(rawheaders)
        if code != 200:
            logging.error('get token: got error response %s, %s' % (code, headers))
            callback( ErrorResponse('non 200 response %s' % code ) )
            stream.close()
            raise StopIteration
        if 'Content-Length' in headers:
            body = yield gen.Task( stream.read_bytes, int(headers['Content-Length']) )
            if not body:
                logging.error('conn closed reading for body?')
                callback( ErrorResponse('socket closed') )
                raise StopIteration
            #logging.info('got body %s' % body)
            response = Response( code, headers, body )
            callback( response )
        else:
            logging.error('chunked encoding response?')
            callback( ErrorResponse('unable to parse chunked encoding') )
        if not stream.closed(): stream.close()
示例#2
0
文件: kdyno.py 项目: bittorrent/kdyno
    def do_request(self, target, params, retry_if_invalid_stream=True, retry_on_expired_token=True, callback=None):
        
        if 'verbose' in options:
            if options.verbose > 0:
                logging.info('request %s %s' % (target, params))
            elif options.verbose > 0:
                logging.info('request %s' % (target))
        if not self.session_token:
            response = yield gen.Task( self.get_session_token, duration_seconds=3600 )
            if response.error:
                callback(response)
                raise StopIteration
            self.session_token = response.meta
            self.update_secret( str(response.meta['SecretAccessKey']) )
            #logging.info('got session token')

        stream_tries = 0
        while stream_tries <= 2:
            stream_tries += 1
            stream = yield gen.Task( self.get_stream )
            if stream.error:
                logging.error('error getting stream %s' % stream)
                callback( ErrorResponse('unable to get stream') )
                raise StopIteration
            request = AWSRequest('POST', self.DefaultHost, params)
            body = request.to_json_postdata()
            request.body = body
            request.headers['X-Amz-Target'] = 'DynamoDB_20111205.%s' % target

            if not self.session_token:
                err = 'session token was invalidated while getting a db connection'
                logging.error(err)
                callback( ErrorResponse(err) )
                raise StopIteration

            self.add_auth(request, security_token = self.session_token['SessionToken'], access_key = self.session_token['AccessKeyId'])
            request.headers['Content-Length'] = str(len(body))
            towrite = request.make_request_headers() + body
            stream._current_request = request
            #request.callback = callback # we're handling error states ourselves

            #logging.info('writing to stream..')

            yield gen.Task( stream.write, towrite )

            if stream.error:
                logging.error('connection died while writing to it')
                callback( ErrorResponse('connection died while writing') )
                raise StopIteration
            #yield gen.Task( asyncsleep, 10 )# for testing
            #logging.info('reading from stream')
            rawheaders = yield gen.Task( stream.read_until, '\r\n\r\n' )
            if not rawheaders or stream.error:
                logging.error('connection seems to have closed..')
                # if error is read error connection reset by peer, the request probably never made it in... (dead stream)...
                # if so, perhaps re-try.
                #callback( ErrorResponse('connection closed on reading for headers') )
                #raise StopIteration
            else:
                break

        code, headers = parse_headers(rawheaders)
        if 'Content-Length' in headers:
            body = yield gen.Task( stream.read_bytes, int(headers['Content-Length']) )
            if code != 200:
                logging.error('got error response %s, %s, %s' % (code, headers, body))
            #logging.info('GOT BODY %s' % body)
            if not body:
                callback( ErrorResponse('connection closed on reading for body') )
                raise StopIteration
            request.callback = None
            stream._current_request = None
            response = JSONResponse( code, headers, body )
            if 'ConsumedCapacityUnits' in response.attributes:
                self.register_usage( target, params, response.attributes['ConsumedCapacityUnits'] )
            if 'verbose' in options and options.verbose > 1 and code == 200:
                logging.info('got response :%s, %s' % (response, response.attributes))


            if code == 400 and response.attributes and '__type' in response.attributes and response.attributes['__type'].endswith('ProvisionedThroughputExceededException'):
                logging.error( 'throughput exceeded' )
                if 'TableName' in params:
                    if self.Statsd:
                        self.Statsd.increment('dynamo.throughput_exceeded.%s' % params['TableName'])

            elif code == 400 and response.attributes and '__type' in response.attributes and response.attributes['__type'].endswith('ExpiredTokenException'):
                self.session_token = None
                # re-do this request...
                if retry_on_expired_token:
                    result = yield gen.Task( self.do_request, target, params, retry_if_invalid_stream=True, retry_on_expired_token=False )
                    callback(result)
                    raise StopIteration

                

            callback( response )
        else:
            logging.error('chunked encoding response?')
            callback( ErrorResponse('no content length header') )

        if len(self.streams) > 25:
            logging.warn('too many db connections %s -- closing one' % len(self.streams))
            self.remove_connection(stream)