Example #1
0
def response_load_gateway_by_type_and_id( gateway_type, gateway_id ):
   """
   Given a gateway's numeric type and ID, load it from the datastore.
   """
   
   if gateway_id == None:
      # invalid header
      return (None, 403, None)

   gateway_read_start = storagetypes.get_time()
   gateway = storage.read_gateway( gateway_id )
   
   if gateway is None:
      # not present
      return (None, 404, None)
   
   if GATEWAY_TYPE_TO_STR.get( gateway.gateway_type ) == None:
      # bad type (shouldn't happen)
      return (None, 400, None)
   
   if GATEWAY_TYPE_TO_STR[ gateway.gateway_type ] != gateway_type:
      # caller has the wrong type
      return (None, 401, None)
      
   gateway_read_time = storagetypes.get_time() - gateway_read_start
   return (gateway, 200, gateway_read_time)
Example #2
0
def response_load_gateway_by_type_and_id(gateway_type, gateway_id):
    """
   Given a gateway's numeric type and ID, load it from the datastore.
   """

    if gateway_id == None:
        # invalid header
        return (None, 403, None)

    gateway_read_start = storagetypes.get_time()
    gateway = storage.read_gateway(gateway_id)

    if gateway is None:
        # not present
        return (None, 404, None)

    if GATEWAY_TYPE_TO_STR.get(gateway.gateway_type) == None:
        # bad type (shouldn't happen)
        return (None, 400, None)

    if GATEWAY_TYPE_TO_STR[gateway.gateway_type] != gateway_type:
        # caller has the wrong type
        return (None, 401, None)

    gateway_read_time = storagetypes.get_time() - gateway_read_start
    return (gateway, 200, gateway_read_time)
Example #3
0
def benchmark(category, benchmark_data, func):
    """
   Call function func, and time how long it takes to run.
   Store it in the given benchmark_data (dict) under the key 'category'.
   Return the result of func.
   """
    start = storagetypes.get_time()
    rc = func()
    t = storagetypes.get_time() - start

    if not benchmark_data.has_key(category):
        benchmark_data[category] = []

    benchmark_data[category].append(t)

    return rc
Example #4
0
def benchmark( category, benchmark_data, func ):
   """
   Call function func, and time how long it takes to run.
   Store it in the given benchmark_data (dict) under the key 'category'.
   Return the result of func.
   """
   start = storagetypes.get_time()
   rc = func()
   t = storagetypes.get_time() - start
   
   if not benchmark_data.has_key(category):
      benchmark_data[category] = []
      
   benchmark_data[category].append( t )
   
   return rc
Example #5
0
def response_begin(request_handler, volume_id):
    """
   Begin a response to a calling gateway, given the request handler and either the volume name or ID.
   Load up the calling gateway and the volume it's trying to access, and return both along with 
   some benchmark information.
   
   Return (volume, gateway, status, benchmark dict) on success
   Return Nones on failure.
   """

    timing = {}

    now = storagetypes.get_time()
    volume, gateway, volume_cert_bundle, status, read_time = response_load_volume_and_gateway(
        request_handler, volume_id)

    # transfer over cert bundle to volume
    if volume is not None and volume_cert_bundle is not None:
        cert_bundle = VolumeCertBundle.Load(volume_cert_bundle)
        volume.cert_bundle = cert_bundle

    timing['request_start'] = now
    timing['response_preprocess_time'] = read_time

    return (volume, gateway, status, timing)
Example #6
0
def response_end( request_handler, status, data, content_type=None, timing=None ):
   """
   Finish a response to a calling gateway, optionally including some benchmarking
   information in the HTTP headers.  Reply with the given status and the raw data string 
   (response MIME type is application/octet-stream unless otherwise specified).
   """
   
   if content_type == None:
      content_type = "application/octet-stream"

   if timing != None:
      request_total = storagetypes.get_time() - timing['request_start']
      timing['X-Total-Time'] = str(request_total)
      timing['X-Response-Preprocess-Time'] = str(timing['response_preprocess_time'])
      
      del timing['request_start']
      del timing['response_preprocess_time']
      
      for (time_header, time) in timing.items():
         request_handler.response.headers[time_header] = time

   request_handler.response.headers['Content-Type'] = content_type
   request_handler.response.status = status
   request_handler.response.write( data )
   return
Example #7
0
def response_end(request_handler,
                 status,
                 data,
                 content_type=None,
                 timing=None):
    """
   Finish a response to a calling gateway, optionally including some benchmarking
   information in the HTTP headers.  Reply with the given status and the raw data string 
   (response MIME type is application/octet-stream unless otherwise specified).
   """

    if content_type == None:
        content_type = "application/octet-stream"

    if timing != None:
        request_total = storagetypes.get_time() - timing['request_start']
        timing['X-Total-Time'] = str(request_total)
        timing['X-Response-Preprocess-Time'] = str(
            timing['response_preprocess_time'])

        del timing['request_start']
        del timing['response_preprocess_time']

        for (time_header, time) in timing.items():
            request_handler.response.headers[time_header] = time

    request_handler.response.headers['Content-Type'] = content_type
    request_handler.response.status = status
    request_handler.response.write(data)
    return
Example #8
0
   def post(self, volume_id_str, volume_version_str, cert_version_str ):

      file_post_start = storagetypes.get_time()
      
      volume_id = None
      try:
         volume_id = int(volume_id_str)
      except Exception, e:
         response_user_error( self, 400 )
         return
Example #9
0
 def create_async( cls, _requester_owner_id, _volume_id, _volume_name, _nonce, _status, **attrs ):
    ts = int(storagetypes.get_time())
    return VolumeAccessRequest.get_or_insert_async( VolumeAccessRequest.make_key_name( _requester_owner_id, _volume_id ),
                                                    requester_owner_id = _requester_owner_id,
                                                    volume_id = _volume_id,
                                                    nonce=_nonce,
                                                    request_timestamp=ts,
                                                    status=_status,
                                                    volume_name=_volume_name,
                                                    **attrs )
Example #10
0
    def post(self, volume_id_str, volume_version_str, cert_version_str):

        file_post_start = storagetypes.get_time()
        file_post_pre = file_post_start

        volume_id = None
        try:
            volume_id = int(volume_id_str)
        except Exception, e:
            response_user_error(self, 400)
            return
Example #11
0
def response_begin(request_handler,
                   volume_name_or_id,
                   fail_if_no_auth_header=True):
    """
   Begin a response to a calling gateway, given the request handler and either the volume name or ID.
   Load up the calling gateway and the volume it's trying to access, and return both along with 
   some benchmark information.  Return Nones on failure.
   
   TODO: load volume and gateway in parallel
   """

    timing = {}

    timing['request_start'] = storagetypes.get_time()

    # get the Volume
    volume, status, volume_read_time = response_load_volume(
        request_handler, volume_name_or_id)

    if status != 200:
        return (None, None, None)

    gateway_read_time = 0
    gateway = None

    # try to authenticate the gateway
    gateway, status, gateway_read_time = response_load_gateway(
        request_handler, volume)

    if fail_if_no_auth_header and (status != 200 or gateway == None):
        return (None, None, None)

    # make sure this gateway is allowed to access this Volume
    if volume.need_gateway_auth():
        if gateway is not None:
            valid_gateway = volume.is_gateway_in_volume(gateway)
            if not valid_gateway:
                # gateway does not belong to this Volume
                logging.error("Not in this Volume")
                response_user_error(request_handler, 403)
                return (None, None, None)

        else:
            logging.error("No gateway, but we required authentication")
            response_user_error(request_handler, 403)
            return (None, None, None)

    # if we're still here, we're good to go

    timing['X-Volume-Time'] = str(volume_read_time)
    timing['X-Gateway-Time'] = str(gateway_read_time)

    return (gateway, volume, timing)
Example #12
0
 def create_async(cls, _requester_owner_id, _volume_id, _volume_name,
                  _nonce, _status, **attrs):
     ts = int(storagetypes.get_time())
     return VolumeAccessRequest.get_or_insert_async(
         VolumeAccessRequest.make_key_name(_requester_owner_id, _volume_id),
         requester_owner_id=_requester_owner_id,
         volume_id=_volume_id,
         nonce=_nonce,
         request_timestamp=ts,
         status=_status,
         volume_name=_volume_name,
         **attrs)
Example #13
0
def response_begin( request_handler, volume_name_or_id, fail_if_no_auth_header=True ):
   """
   Begin a response to a calling gateway, given the request handler and either the volume name or ID.
   Load up the calling gateway and the volume it's trying to access, and return both along with 
   some benchmark information.  Return Nones on failure.
   
   TODO: load volume and gateway in parallel
   """
   
   timing = {}
   
   timing['request_start'] = storagetypes.get_time()

   # get the Volume
   volume, status, volume_read_time = response_load_volume( request_handler, volume_name_or_id )

   if status != 200:
      return (None, None, None)

   gateway_read_time = 0
   gateway = None

   # try to authenticate the gateway
   gateway, status, gateway_read_time = response_load_gateway( request_handler, volume )

   if fail_if_no_auth_header and (status != 200 or gateway == None):
      return (None, None, None)

   # make sure this gateway is allowed to access this Volume
   if volume.need_gateway_auth():
      if gateway is not None:
         valid_gateway = volume.is_gateway_in_volume( gateway )
         if not valid_gateway:
            # gateway does not belong to this Volume
            logging.error("Not in this Volume")
            response_user_error( request_handler, 403 )
            return (None, None, None)
      
      else:
         logging.error("No gateway, but we required authentication")
         response_user_error( request_handler, 403 )
         return (None, None, None)

   # if we're still here, we're good to go

   timing['X-Volume-Time'] = str(volume_read_time)
   timing['X-Gateway-Time'] = str(gateway_read_time)
   
   return (gateway, volume, timing)
Example #14
0
def response_load_volume(request_handler, volume_name_or_id):
    """
   Load a volume from the data store, given either its name or ID.
   Automatically reply with an error message via the given 
   request handler.
   """

    volume_read_start = storagetypes.get_time()

    volume = storage.read_volume(volume_name_or_id)

    volume_read_time = storagetypes.get_time() - volume_read_start

    if volume == None:
        # no volume
        response_volume_error(request_handler, 404)
        return (None, 404, None)

    if not volume.active:
        # inactive volume
        response_volume_error(request_handler, 503)
        return (None, 503, None)

    return (volume, 200, volume_read_time)
Example #15
0
def response_load_volume( request_handler, volume_name_or_id ):
   """
   Load a volume from the data store, given either its name or ID.
   Automatically reply with an error message via the given 
   request handler.
   """
   
   volume_read_start = storagetypes.get_time()

   volume = storage.read_volume( volume_name_or_id )

   volume_read_time = storagetypes.get_time() - volume_read_start

   if volume == None:
      # no volume
      response_volume_error( request_handler, 404 )
      return (None, 404, None)

   if not volume.active:
      # inactive volume
      response_volume_error( request_handler, 503 )
      return (None, 503, None)

   return (volume, 200, volume_read_time)
Example #16
0
def response_begin( request_handler, volume_id ):
   """
   Begin a response to a calling gateway, given the request handler and either the volume name or ID.
   Load up the calling gateway and the volume it's trying to access, and return both along with 
   some benchmark information.
   
   Return (volume, gateway, status, benchmark dict) on success
   Return Nones on failure.
   """
   
   timing = {}
  
   now = storagetypes.get_time()
   volume, gateway, volume_cert_bundle, status, read_time = response_load_volume_and_gateway( request_handler, volume_id )
   
   # transfer over cert bundle to volume
   if volume is not None and volume_cert_bundle is not None:
      cert_bundle = VolumeCertBundle.Load( volume_cert_bundle )
      volume.cert_bundle = cert_bundle
   
   timing['request_start'] = now
   timing['response_preprocess_time'] = read_time
   
   return (volume, gateway, status, timing)
Example #17
0
def response_load_volume_and_gateway(request_handler,
                                     volume_id,
                                     gateway_id=None):
    """
   Load a volume and the gateway from the request handler.
   
   Return (volume, gateway, volume_cert_bundle, status, time)
   """

    read_start = storagetypes.get_time()

    # get the gateway's ID and credentials
    g_id = None

    if gateway_id is None:
        gateway_type, g_id, signature_b64 = response_read_gateway_basic_auth(
            request_handler.request.headers)
    else:
        g_id = gateway_id

    volume = None
    gateway = None
    cert_bundle = None

    volume_fut = Volume.Read(volume_id, async=True)
    cert_bundle_fut = VolumeCertBundle.Get(volume_id, async=True)
    gateway_fut = None

    if g_id is not None:
        gateway_fut = Gateway.Read(g_id, async=True)

    storagetypes.wait_futures([volume_fut, gateway_fut, cert_bundle_fut])

    volume = volume_fut.get_result()
    cert_bundle = cert_bundle_fut.get_result()
    if gateway_fut is not None:
        gateway = gateway_fut.get_result()

    if volume is None or cert_bundle is None:
        logging.error("No volume, gateway, or cert bundle")
        response_user_error(request_handler, 404)
        return (None, None, None, 404, None)
    '''
   Volume.SetCache( volume.volume_id, volume )
   VolumeCertBundle.SetCache( volume.volume_id, cert_bundle )
   
   if gateway is not None:
      Gateway.SetCache( gateway.g_id, gateway )
   '''

    # sanity checks
    if (volume.need_gateway_auth()) and (gateway is None
                                         or gateway_type is None
                                         or signature_b64 is None):
        # required authentication, but we don't have an Authentication header
        logging.error("Unable to authenticate gateway")
        return (None, None, None, 403, None)

    # need auth?
    if volume.need_gateway_auth() and gateway is None:
        logging.error("Unable to authenticate gateway")
        return (None, None, None, 403, None)

    # gateway validity
    if gateway is not None:

        # type match?
        if gateway_type is not None and gateway.gateway_type != gateway_type:
            logging.error("Type mismatch on %s:%s" % (gateway_type, g_id))
            response_user_error(request_handler, 403)
            return (None, None, None, 403, None)

        # is the gateway in this volume?
        if not volume.is_gateway_in_volume(gateway):
            logging.error("Gateway '%s' is not in volume '%s'" %
                          (gateway.name, volume.name))
            response_user_error(request_handler, 403)
            return (None, None, None, 403, None)

        # make sure this gateway's cert is registered
        valid_gateway = gateway.authenticate_session(
            gateway_type, g_id, request_handler.request.url, signature_b64)

        if not valid_gateway and volume.need_gateway_auth():
            # invalid credentials
            logging.error("Invalid authentication credentials")
            response_user_error(request_handler, 403)
            return (None, None, None, 403, None)

    read_time = storagetypes.get_time() - read_start

    return (volume, gateway, cert_bundle, 200, read_time)
Example #18
0
            if request.type not in MSFileHandler.post_validators.keys():
                logging.error("Unrecognized request %s" % request.type)
                response_user_error(self, 501)
                return

            valid, failure_status = MSFileHandler.post_validators[
                request.type](gateway, request)
            if not valid:
                logging.error("Failed to validate request")
                response_user_error(self, failure_status,
                                    "Argument validation failed")
                return

        timing = {}

        file_post_begin = storagetypes.get_time() - file_post_pre

        file_post_operations_pre = storagetypes.get_time()

        # carry out the operation(s), and count them
        num_processed = 0
        types = {}
        for request in update_set.requests:

            if not types.has_key(request.type):
                types[request.type] = 0

            types[request.type] += 1

            # these are guaranteed to be non-None...
            api_call = MSFileHandler.post_api_calls.get(request.type, None)
Example #19
0
      for request in update_set.requests:
         
         if request.type not in MSFileHandler.post_validators.keys():
            logging.error("Unrecognized request %s" % request.type)
            response_user_error( self, 501 )
            return 
         
         valid, failure_status = MSFileHandler.post_validators[request.type]( gateway, request )
         if not valid:
            logging.error("Failed to validate request")
            response_user_error( self, failure_status, "Argument validation failed" )
            return 
      
      timing = {}
      
      file_post_begin = storagetypes.get_time() - file_post_pre

      file_post_operations_pre = storagetypes.get_time()

      # carry out the operation(s), and count them
      num_processed = 0
      types = {}
      for request in update_set.requests:

         if not types.has_key(request.type):
            types[request.type] = 0
            
         types[request.type] += 1
         
         # these are guaranteed to be non-None...
         api_call = MSFileHandler.post_api_calls.get( request.type, None )
def response_load_volume_and_gateway( request_handler, volume_id, gateway_id=None ):
   """
   Load a volume and the gateway from the request handler.
   
   Return (volume, gateway, volume_cert_bundle, status, time)
   """
   
   read_start = storagetypes.get_time()
   
   # get the gateway's ID and credentials
   g_id = None 
   
   if gateway_id is None:
      gateway_type, g_id, signature_b64 = response_read_gateway_basic_auth( request_handler.request.headers )
   else:
      g_id = gateway_id
   
   volume = None 
   gateway = None
   cert_bundle = None 
   
   volume_fut = Volume.Read( volume_id, async=True )
   cert_bundle_fut = VolumeCertBundle.Get( volume_id, async=True )
   gateway_fut = None 
   
   if g_id is not None:
      gateway_fut = Gateway.Read( g_id, async=True )
      
   storagetypes.wait_futures( [volume_fut, gateway_fut, cert_bundle_fut] )
   
   volume = volume_fut.get_result()
   cert_bundle = cert_bundle_fut.get_result()
   if gateway_fut is not None:
       gateway = gateway_fut.get_result()
   
   if volume is None or cert_bundle is None:
      logging.error("No volume, gateway, or cert bundle")
      response_user_error( request_handler, 404 )
      return (None, None, None, 404, None)
   
   Volume.SetCache( volume.volume_id, volume )
   VolumeCertBundle.SetCache( volume.volume_id, cert_bundle )
   
   if gateway is not None:
      Gateway.SetCache( gateway.g_id, gateway )
      
   # sanity checks
   if (volume.need_gateway_auth()) and (gateway is None or gateway_type is None or signature_b64 is None):
      # required authentication, but we don't have an Authentication header
      logging.error("Unable to authenticate gateway")
      return (None, None, None, 403, None)

   # need auth?
   if volume.need_gateway_auth() and gateway is None:
      logging.error("Unable to authenticate gateway")
      return (None, None, None, 403, None)
   
   # gateway validity
   if gateway is not None:
      
      # type match?
      if gateway_type is not None and gateway.gateway_type != gateway_type:
         logging.error("Type mismatch on %s:%s" % (gateway_type, g_id))
         response_user_error( request_handler, 403 )
         return (None, None, None, 403, None )
      
      # is the gateway in this volume?
      if not volume.is_gateway_in_volume( gateway ):
         logging.error("Gateway '%s' is not in volume '%s'" % (gateway.name, volume.name))
         response_user_error( request_handler, 403 )
         return (None, None, None, 403, None)
      
      # make sure this gateway's cert is registered
      valid_gateway = gateway.authenticate_session( gateway_type, g_id, request_handler.request.url, signature_b64 )

      if not valid_gateway and volume.need_gateway_auth():
         # invalid credentials
         logging.error("Invalid authentication credentials")
         response_user_error( request_handler, 403 )
         return (None, None, None, 403, None)
   
   read_time = storagetypes.get_time() - read_start
   
   return (volume, gateway, cert_bundle, 200, read_time)
Example #21
0
   def post(self, volume_id_str ):

      file_post_start = storagetypes.get_time()
      
      update_set = file_update_parse( self )
      if update_set == None:
         # malformed data
         response_user_error( self, 202, "%s\n" % (-errno.EINVAL) )
         return
      
      # begin the response
      gateway, volume, response_timing = response_begin( self, volume_id_str )
      if volume == None:
         return

      allowed = file_update_auth( gateway, volume )
      if not allowed:
         log.error("Failed to authenticate")
         response_user_error( self, 403 )
         return

      # verify the message integrity and authenticity
      if not gateway.verify_message( update_set ):
         # authentication failure
         response_user_error( self, 401, "Signature verification failed")
         return
      
      # TODO: rate-limit
      
      # populate the reply
      reply = file_update_init_response( volume )
      status = 200
      
      # validate requests before processing them 
      for update in update_set.updates:
         
         if update.type not in MSFileHandler.post_validators.keys():
            logging.error("Unrecognized update %s" % update.type)
            response_user_error( self, 501 )
            return 
         
         
         valid, failure_status = MSFileHandler.post_validators[update.type]( gateway, update )
         if not valid:
            log.error("Failed to validate update")
            response_user_error( self, failure_status, "Argument validation failed" )
            return 
      
      timing = {}
      
      # carry out the operation(s), and count them
      num_processed = 0
      types = {}
      for update in update_set.updates:

         if not types.has_key(update.type):
            types[update.type] = 0
            
         types[update.type] += 1
         
         # these are guaranteed to be non-None...
         api_call = MSFileHandler.post_api_calls.get( update.type, None )
         benchmark_header = MSFileHandler.post_benchmark_headers.get( update.type, None )
         
         # run the API call, but benchmark it too
         try:
            rc = benchmark( benchmark_header, timing, lambda: api_call( reply, gateway, volume, update ) )
            reply.errors.append( rc )
            
            num_processed += 1
            
         except storagetypes.RequestDeadlineExceededError, de:
            # quickly now...
            response_user_error( self, 503 )
            return
            
         except Exception, e:
            logging.exception(e)
            reply.error = -errno.EREMOTEIO
            break
Example #22
0
    def post(self, volume_id_str):

        file_post_start = storagetypes.get_time()

        update_set = file_update_parse(self)
        if update_set == None:
            # malformed data
            response_user_error(self, 202, "%s\n" % (-errno.EINVAL))
            return

        # begin the response
        gateway, volume, response_timing = response_begin(self, volume_id_str)
        if volume == None:
            return

        allowed = file_update_auth(gateway, volume)
        if not allowed:
            log.error("Failed to authenticate")
            response_user_error(self, 403)
            return

        # verify the message integrity and authenticity
        if not gateway.verify_message(update_set):
            # authentication failure
            response_user_error(self, 401, "Signature verification failed")
            return

        # TODO: rate-limit

        # populate the reply
        reply = file_update_init_response(volume)
        status = 200

        # validate requests before processing them
        for update in update_set.updates:

            if update.type not in MSFileHandler.post_validators.keys():
                logging.error("Unrecognized update %s" % update.type)
                response_user_error(self, 501)
                return

            valid, failure_status = MSFileHandler.post_validators[update.type](
                gateway, update)
            if not valid:
                log.error("Failed to validate update")
                response_user_error(self, failure_status,
                                    "Argument validation failed")
                return

        timing = {}

        # carry out the operation(s), and count them
        num_processed = 0
        types = {}
        for update in update_set.updates:

            if not types.has_key(update.type):
                types[update.type] = 0

            types[update.type] += 1

            # these are guaranteed to be non-None...
            api_call = MSFileHandler.post_api_calls.get(update.type, None)
            benchmark_header = MSFileHandler.post_benchmark_headers.get(
                update.type, None)

            # run the API call, but benchmark it too
            try:
                rc = benchmark(
                    benchmark_header, timing,
                    lambda: api_call(reply, gateway, volume, update))
                reply.errors.append(rc)

                num_processed += 1

            except storagetypes.RequestDeadlineExceededError, de:
                # quickly now...
                response_user_error(self, 503)
                return

            except Exception, e:
                logging.exception(e)
                reply.error = -errno.EREMOTEIO
                break