예제 #1
0
    def SetCaps(cls, g_name_or_id, caps):
        """
      Set this gateway's capabilities.
      """
        def set_caps_txn(g_name_or_id):
            gateway = Gateway.Read(g_name_or_id)
            if gateway == None:
                raise Exception("No such Gateway '%s'" % caps)

            gateway.caps = Gateway.safe_caps(gateway.gateway_type, caps)
            gateway.cert_version += 1
            gateway.need_cert = Gateway.needs_cert(gateway.gateway_type, caps)
            gateway.put()
            return gateway

        try:
            gateway = storagetypes.transaction(
                lambda: set_caps_txn(g_name_or_id))
        except:
            log.error("Failed to set caps")
            return False

        if gateway is not None:
            Gateway.FlushCache(gateway.g_id)
            return True
        else:
            return False
예제 #2
0
    def create_or_ref(cls, _text):
        """
      Create a new driver, or re-ref the existing one.
      Do so atomically.
      """
        driver_hash = cls.hash_driver(_text)

        def txn():

            dk = storagetypes.make_key(
                GatewayDriver, GatewayDriver.make_key_name(driver_hash))
            d = dk.get()
            f = None

            if d is None:
                d = GatewayDriver(key=dk,
                                  driver_hash=driver_hash,
                                  driver_text=_text,
                                  refcount=1)
                d.put()

            else:
                d.refcount += 1
                d.put()

            return d

        return storagetypes.transaction(txn)
예제 #3
0
 def Reversion( cls, volume_name_or_id ):
    '''
    Increase the cert version by one.
    Call this when you add/remove a Gateway.
    '''
    
    def update_txn( volume_id ):
       '''
       Update the Volume transactionally.
       '''
       
       volume = Volume.Read( volume_id )
       if not volume or volume.deleted:
          raise Exception("No volume with the ID %d exists.", volume_id)
       
       
       # purge from cache
       Volume.FlushCache( volume_id )
       
       volume.cert_version += 1
       
       volume.put()
       
       return volume.cert_version
    
    volume = Volume.Read( volume_name_or_id )
    if volume is None or volume.deleted:
       raise Exception("No such Volume %s" % volume_name_or_id)
    
    try:
       new_version = storagetypes.transaction( lambda: update_txn(volume.volume_id), xg=True )
    except Exception, e:
       logging.exception( e )
       raise e
예제 #4
0
    def Reversion(cls, volume_name_or_id):
        '''
      Increase the cert version by one.
      Call this when you add/remove a Gateway.
      '''
        def update_txn(volume_id):
            '''
         Update the Volume transactionally.
         '''

            volume = Volume.Read(volume_id)
            if not volume or volume.deleted:
                raise Exception("No volume with the ID %d exists.", volume_id)

            # purge from cache
            Volume.FlushCache(volume_id)

            volume.cert_version += 1

            volume.put()

            return volume.cert_version

        volume = Volume.Read(volume_name_or_id)
        if volume is None or volume.deleted:
            raise Exception("No such Volume %s" % volume_name_or_id)

        try:
            new_version = storagetypes.transaction(
                lambda: update_txn(volume.volume_id), xg=True)
        except Exception, e:
            logging.exception(e)
            raise e
예제 #5
0
 def SetCaps( cls, g_name_or_id, caps ):
    """
    Set this gateway's capabilities.
    """
    def set_caps_txn( g_name_or_id ):
       gateway = Gateway.Read( g_name_or_id )
       if gateway == None:
          raise Exception("No such Gateway '%s'" % caps)
       
       gateway.caps = Gateway.safe_caps( gateway.gateway_type, caps )
       gateway.cert_version += 1
       gateway.need_cert = Gateway.needs_cert( gateway.gateway_type, caps )
       gateway.put()
       return gateway
    
    try:
       gateway = storagetypes.transaction( lambda: set_caps_txn( g_name_or_id ) )
    except:
       log.error("Failed to set caps")
       return False
    
    if gateway is not None:
       Gateway.FlushCache( gateway.g_id )
       return True
    else:
       return False
예제 #6
0
 def update_shard_count( cls, volume_id, num_shards, **txn_args ):
    """
    Update the shard count of the volume, but in a transaction.
    """
    volume_key = storagetypes.make_key( Volume, Volume.make_key_name( volume_id=volume_id ) )      
    num_shards = storagetypes.transaction( lambda: Volume.__update_shard_count( volume_key, num_shards ), **txn_args )
    
    return num_shards
예제 #7
0
    def Delete(cls, g_name_or_id):
        """
      Given a gateway ID, delete the corresponding gateway.
      That is, set it's "deleted" flag so it no longer gets read.
      Unref the driver as well.
      """

        gateway = Gateway.Read(g_name_or_id)
        if gateway:
            g_id = gateway.g_id
        else:
            return True

        key_name = Gateway.make_key_name(g_id=g_id)

        def set_deleted():
            # atomically set the gateway to deleted
            g_key = storagetypes.make_key(cls, key_name)
            gw = g_key.get()
            if gw is None:
                return None

            gw.deleted = True
            gw.put()
            return gw.key

        storagetypes.transaction(lambda: set_deleted())

        g_name_key = storagetypes.make_key(
            GatewayNameHolder, GatewayNameHolder.make_key_name(gateway.name))

        g_name_delete_fut = g_name_key.delete_async()
        driver_fut = GatewayDriver.unref_async(gateway.driver_hash)

        storagetypes.wait_futures([g_name_delete_fut, driver_fut])

        Gateway.FlushCache(g_id)
        Gateway.FlushCacheDriver(gateway.driver_hash)

        g_name_to_id_cache_key = Gateway.Read_ByName_name_cache_key(
            g_name_or_id)
        storagetypes.memcache.delete(g_name_to_id_cache_key)

        return True
예제 #8
0
   def Update( cls, cls_name_or_id, **fields ):
      """
      Update the closure--i.e. to refer to a new binary.
      NOTE: You should call Reversion() on all Gateways that use this closure after calling this method
      """
      
      # get closure ID
      try:
         cls_id = int(cls_name_or_id)
      except:
         closure = Closure.Read( cls_name_or_id )
         if closure:
            cls_id = closure.closure_id 
         else:
            raise Exception("No such Closure '%s'" % cls_name_or_id )
      
      if len(fields.keys()) == 0:
         return True
      
      # validate...
      invalid = cls.validate_fields( fields )
      if len(invalid) != 0:
         raise Exception( "Invalid values for fields: %s" % (", ".join( invalid )) )

      invalid = cls.validate_write( fields )
      if len(invalid) != 0:
         raise Exception( "Unwritable fields: %s" % (", ".join(invalid)) )
      
      
      def update_txn( fields ):
         '''
         Update the Closure transactionally.
         '''
         
         closure = cls.Read(cls_id)
         if closure is None:
            raise Exception("No Closure with the ID %d exists.", cls_id)
         
         
         # purge from cache
         Closure.FlushCache( cls_id )
         
         # apply update
         for (k,v) in fields.items():
            setattr( closure, k, v )
         
         return closure.put()
      
      
      closure_key = None
      try:
         closure_key = storagetypes.transaction( lambda: update_txn( fields ), xg=True )
         assert closure_key is not None, "Transaction failed"
      except Exception, e:
         logging.exception( e )
         raise e
예제 #9
0
    def Reset(cls, user_cert):
        """
      Reset a user's account credentials.
      
      NOTE: the caller will need to have validated the cert beforehand
      """

        user_attrs = cls.cert_to_dict(user_cert)
        for k in user_attrs.keys():
            if k not in cls.modifiable_cert_fields:
                del user_attrs[k]

        user_cert_protobuf = user_cert.SerializeToString()

        def update_txn(fields):
            '''
         Update the User transactionally.
         '''
            user = SyndicateUser.Read(user_cert.email)
            if user is None:
                raise Exception("No such user '%s'" % user_cert.email)

            # key can't repeat
            if user_attrs['public_key'] == user.public_key:
                raise Exception("Public key did not change")

            # verify update
            unwriteable = []
            for (k, v) in fields.items():
                if k not in cls.modifiable_cert_fields and getattr(user,
                                                                   k) != v:
                    unwriteable.append(k)

            if len(unwriteable) > 0:
                raise Exception("Tried to modify read-only fields: %s" %
                                ",".join(unwriteable))

            # apply update
            for (k, v) in fields.items():
                setattr(user, k, v)

            # store new cert
            user.user_cert_protobuf = user_cert_protobuf
            ret = user.put()

            user_key_name = SyndicateUser.make_key_name(email=user.email)
            storagetypes.memcache.delete(user_key_name)
            return ret

        try:
            user_key = storagetypes.transaction(lambda: update_txn(user_attrs),
                                                xg=True)
            return user_key
        except Exception, e:
            logging.exception(e)
            raise e
예제 #10
0
    def Update(cls, email, **fields):
        '''
      Atomically (transactionally) update a SyndicateUser with the new fields.
      
      Positionl arguments:
      email             -- Email address of the user to update (str)
      
      '''
        def verify_auth_change(user, attrs):
            if not user.active:
                raise Exception(
                    "Account for %s is not active.  Please activate it." %
                    user.email)

            if attrs.has_key('allow_password_auth'):
                # this can only be disabled
                if attrs['allow_password_auth']:
                    raise Exception(
                        "For security reasons, re-enabling password authentication is forbidden.  Reset the account for %s instead."
                        % user.email)

            if attrs.has_key('signing_public_key'):
                # can't unset this if password auth is disabled
                if not user.allow_password_auth and not SyndicateUser.is_signing_public_key_set(
                        attrs['signing_public_key']):
                    raise Exception(
                        "Cannot disable public-key authentication once password authentication is disabled."
                    )

            return True

        def update_txn(email, attrs):
            user = SyndicateUser.Read(email)
            if user is None:
                raise Exception("No such user %s" % email)

            verify_auth_change(user, attrs)

            user_key_name = SyndicateUser.make_key_name(email=email)
            storagetypes.memcache.delete(user_key_name)

            for (k, v) in attrs.items():
                setattr(user, k, v)
            return user.put()

        # sanity check
        invalid = SyndicateUser.validate_fields(fields)
        if len(invalid) > 0:
            raise Exception("Invalid fields: %s" % (', '.join(invalid)))

        invalid = SyndicateUser.validate_write(fields)
        if len(invalid) > 0:
            raise Exception("Unwritable fields: %s" % (', '.join(invalid)))

        return storagetypes.transaction(lambda: update_txn(email, fields))
예제 #11
0
    def Update(cls, cls_name_or_id, **fields):
        """
      Update the closure--i.e. to refer to a new binary.
      NOTE: You should call Reversion() on all Gateways that use this closure after calling this method
      """

        # get closure ID
        try:
            cls_id = int(cls_name_or_id)
        except:
            closure = Closure.Read(cls_name_or_id)
            if closure:
                cls_id = closure.closure_id
            else:
                raise Exception("No such Closure '%s'" % cls_name_or_id)

        if len(fields.keys()) == 0:
            return True

        # validate...
        invalid = cls.validate_fields(fields)
        if len(invalid) != 0:
            raise Exception("Invalid values for fields: %s" %
                            (", ".join(invalid)))

        invalid = cls.validate_write(fields)
        if len(invalid) != 0:
            raise Exception("Unwritable fields: %s" % (", ".join(invalid)))

        def update_txn(fields):
            '''
         Update the Closure transactionally.
         '''

            closure = cls.Read(cls_id)
            if closure is None:
                raise Exception("No Closure with the ID %d exists.", cls_id)

            # purge from cache
            Closure.FlushCache(cls_id)

            # apply update
            for (k, v) in fields.items():
                setattr(closure, k, v)

            return closure.put()

        closure_key = None
        try:
            closure_key = storagetypes.transaction(lambda: update_txn(fields),
                                                   xg=True)
            assert closure_key is not None, "Transaction failed"
        except Exception, e:
            logging.exception(e)
            raise e
예제 #12
0
   def Delete( cls, g_name_or_id ):
      """
      Given a gateway ID, delete the corresponding gateway.
      That is, set it's "deleted" flag so it no longer gets read.
      Unref the driver as well.
      """
      
      gateway = Gateway.Read( g_name_or_id )
      if gateway:
         g_id = gateway.g_id 
      else:
         raise Exception("No such Gateway '%s'" % g_name_or_id )
      
      key_name = Gateway.make_key_name( g_id=g_id )
      
      def set_deleted():
          # atomically set the gateway to deleted
          g_key = storagetypes.make_key( cls, key_name )
          gw = g_key.get()
          if gw is None:
              return None

          gw.deleted = True
          gw.put()
          return gw.key 

      storagetypes.transaction( lambda: set_deleted() )

      g_name_key = storagetypes.make_key( GatewayNameHolder, GatewayNameHolder.make_key_name( gateway.name ) )
      
      g_name_delete_fut = g_name_key.delete_async()
      driver_fut = GatewayDriver.unref_async( gateway.driver_hash )
      
      storagetypes.wait_futures( [g_name_delete_fut, driver_fut] )
      
      Gateway.FlushCache( g_id )
      Gateway.FlushCacheDriver( gateway.driver_hash )
      
      g_name_to_id_cache_key = Gateway.Read_ByName_name_cache_key( g_name_or_id )
      storagetypes.memcache.delete( g_name_to_id_cache_key )
      
      return True
예제 #13
0
    def update_shard_count(cls, volume_id, num_shards, **txn_args):
        """
      Update the shard count of the volume, but in a transaction.
      """
        volume_key = storagetypes.make_key(
            Volume, Volume.make_key_name(volume_id=volume_id))
        num_shards = storagetypes.transaction(
            lambda: Volume.__update_shard_count(volume_key, num_shards),
            **txn_args)

        return num_shards
예제 #14
0
파일: user.py 프로젝트: iychoi/syndicate
   def Reset( cls, user_cert ):
      """
      Reset a user's account credentials.
      
      NOTE: the caller will need to have validated the cert beforehand
      """
      
      user_attrs = cls.cert_to_dict( user_cert )
      for k in user_attrs.keys():
          if k not in cls.modifiable_cert_fields:
              del user_attrs[k]
      
      user_cert_protobuf = user_cert.SerializeToString()

      def update_txn( fields ):
         '''
         Update the User transactionally.
         '''
         user = SyndicateUser.Read( user_cert.email )
         if user is None:
             raise Exception("No such user '%s'" % user_cert.email )

         # key can't repeat 
         if user_attrs['public_key'] == user.public_key:
             raise Exception("Public key did not change")

         # verify update
         unwriteable = []
         for (k, v) in fields.items():
            if k not in cls.modifiable_cert_fields and getattr(user, k) != v:
               unwriteable.append(k)
               
         if len(unwriteable) > 0:
            raise Exception("Tried to modify read-only fields: %s" % ",".join(unwriteable))
         
         # apply update
         for (k,v) in fields.items():
            setattr( user, k, v )
         
         # store new cert 
         user.user_cert_protobuf = user_cert_protobuf
         ret = user.put()

         user_key_name = SyndicateUser.make_key_name( email=user.email ) 
         storagetypes.memcache.delete( user_key_name )
         return ret
 
      try:
         user_key = storagetypes.transaction( lambda: update_txn( user_attrs ), xg=True )
         return user_key 
      except Exception, e:
         logging.exception( e )
         raise e
예제 #15
0
   def Update( cls, email, **fields ):
      '''
      Atomically (transactionally) update a SyndicateUser with the new fields.
      
      Positionl arguments:
      email             -- Email address of the user to update (str)
      
      '''
      
      def verify_auth_change( user, attrs ):
         if not user.active:
            raise Exception("Account for %s is not active.  Please activate it." % user.email )
         
         if attrs.has_key('allow_password_auth'):
            # this can only be disabled
            if attrs['allow_password_auth']:
               raise Exception("For security reasons, re-enabling password authentication is forbidden.  Reset the account for %s instead." % user.email)
            
         if attrs.has_key('signing_public_key'):
            # can't unset this if password auth is disabled
            if not user.allow_password_auth and not SyndicateUser.is_signing_public_key_set( attrs['signing_public_key'] ):
               raise Exception("Cannot disable public-key authentication once password authentication is disabled.")
            
         return True
         
      def update_txn( email, attrs ):
         user = SyndicateUser.Read(email)
         if user is None:
            raise Exception("No such user %s" % email)
         
         verify_auth_change( user, attrs )
         
         user_key_name = SyndicateUser.make_key_name( email=email)
         storagetypes.memcache.delete( user_key_name )

         for (k,v) in attrs.items():
            setattr(user, k, v )
         return user.put()
      
      # sanity check
      invalid = SyndicateUser.validate_fields( fields )
      if len(invalid) > 0:
         raise Exception( "Invalid fields: %s" % (', '.join( invalid )) )
      
      invalid = SyndicateUser.validate_write( fields )
      if len(invalid) > 0:
         raise Exception( "Unwritable fields: %s" % (', '.join( invalid )) )
      
      return storagetypes.transaction( lambda: update_txn( email, fields ) )
예제 #16
0
   def Put( cls, volume_id, cert_protobuf ):
      """
      Put a new volume cert bundle (which is really an SG Manifest repurposed)
      Verify that the version number has incremented.

      """
      
      cert = sg_pb2.Manifest() 
      cert.ParseFromString( cert_protobuf )
      
      if cert.volume_id != volume_id:
         raise Exception("Invalid volume ID: %s != %s" % (cert.volume_id, volume_id))
      
      def put_txn():
         
         volume_cert_bundle = cls.Get( volume_id )
         if volume_cert_bundle is not None:
         
            existing_cert = cls.Load( volume_cert_bundle )
            
            if existing_cert.volume_id != volume_id:
               raise Exception("BUG: existing cert bundle is for %s, but expected %s" % (volume_id, existing_cert.volume_id))
            
            if existing_cert.file_version > cert.file_version:
               raise Exception("Stale volume cert version: expected >= %s, got %s" % (existing_cert.file_version, cert.file_version))
            
            if existing_cert.mtime_sec > cert.mtime_sec or (existing_cert.mtime_sec == cert.mtime_sec and existing_cert.mtime_nsec > cert.mtime_nsec):
               # stale 
               raise Exception("Stale cert bundle timestamp: expected > %s.%s, got %s.%s" % (volume_id, existing_cert.mtime_sec, existing_cert.mtime_nsec, cert.mtime_sec, cert.mtime_nsec))
            
            volume_cert_bundle.cert_protobuf = cert_protobuf
            volume_cert_bundle.put()
            
            storagetypes.memcache.delete( VolumeCertBundle.make_key_name( volume_id ) )
         
         else:
            volume_cert_bundle = VolumeCertBundle( key=storagetypes.make_key( VolumeCertBundle, VolumeCertBundle.make_key_name( volume_id ) ), volume_id=volume_id, cert_protobuf=cert_protobuf )
            volume_cert_bundle.put()
         
         return True 
      
      return storagetypes.transaction( put_txn )
예제 #17
0
 def create_or_ref( cls, _text ):
    """
    Create a new driver, or re-ref the existing one.
    Do so atomically.
    """
    driver_hash = cls.hash_driver( _text )
    
    def txn():
        
        dk = storagetypes.make_key( GatewayDriver, GatewayDriver.make_key_name( driver_hash ) )
        d = dk.get()
        f = None 
        
        if d is None:
            d = GatewayDriver( key=dk, driver_hash=driver_hash, driver_text=_text, refcount=1 )
            d.put()
        
        else:
            d.refcount += 1
            d.put()
            
        return d
    
    return storagetypes.transaction( txn )
예제 #18
0
 def Update( cls, gateway_cert, new_driver=None ):
    '''
    Update a gateway identified by ID with a new certificate.
    
    Return the gateway record's key on success
    Raise an exception on error.
    
    NOTE: the caller must verify the authenticity of the certificate.
    Only the volume owner should be able to update a gateway cert.
    '''
    
    fields = cls.cert_to_dict( gateway_cert )
    g_id = fields['g_id']
    
    # validate...
    invalid = cls.validate_fields( fields )
    if len(invalid) != 0:
       
       raise Exception( "Invalid values for fields: %s" % (", ".join( invalid )) )
    
    rename = False
    gateway_nameholder_new_key = None
    
    new_driver_hash = None 
    old_driver_hash = None
    
    # sanity check...
    if new_driver is not None:
       new_driver_hash = GatewayDriver.hash_driver( new_driver )
       if binascii.hexlify( gateway_cert.driver_hash ) != new_driver_hash:
          raise Exception("Certificate driver hash mismatch: expected %s, got %s" % (binascii.hexlify( gateway_cert.driver_hash ), new_driver_hash))
    
    # do we intend to rename?  If so, reserve the name
    if "name" in fields.keys() and fields['name'] != gateway_cert.name:
       gateway_nameholder_new_fut = GatewayNameHolder.create_async( fields.get("name"), g_id )
       
       gateway_nameholder_new = gateway_nameholder_new_fut.get_result()
       gateway_nameholder_new_key = gateway_nameholder_new.key
       
       if gateway_nameholder_new.g_id != g_id:
          # name collision
          raise Exception("Gateway '%s' already exists!" % (fields.get("name")) )
       
       else:
          # reserved!
          rename = True
    
    # drop cert; we'll store it separately 
    gateway_cert_bin = fields['gateway_cert']
    del fields['gateway_cert']
    
    def update_txn( fields ):
       '''
       Update the Gateway transactionally.
       '''
       
       g_id = fields['g_id']
       
       gateway = cls.Read(g_id)
       if gateway is None:
          # gateway does not exist...
          # if we were to rename it, then delete the new nameholder
          if rename:
             storagetypes.deferred.defer( Gateway.delete_all, [gateway_nameholder_new_key] )
             
          raise Exception("No Gateway with the ID %d exists.", g_id)
       
       old_driver_hash = gateway.driver_hash
       old_name = gateway.name 
       
       # verify update
       unwriteable = []
       for (k, v) in fields.items():
          if k not in cls.modifiable_cert_attrs and getattr(gateway, k) != v:
             unwriteable.append(k)
             
       if len(unwriteable) > 0:
          raise Exception("Tried to modify read-only fields: %s" % ",".join(unwriteable))
       
       # sanity check: valid version?
       if gateway.cert_version >= gateway_cert.version:
          raise Exception("Stale Gateway certificate: expected > %s; got %s" % (gateway.cert_version, gateway_cert.version))
       
       # apply update
       for (k,v) in fields.items():
          setattr( gateway, k, v )
       
       gateway.need_cert = cls.needs_cert( gateway.gateway_type, fields['caps'] )
       gateway.gateway_cert = gateway_cert_bin
       
       gw_key = gateway.put()
       
       if old_driver_hash is not None:
           # unref the old one 
           GatewayDriver.unref( old_driver_hash )
           cls.FlushCacheDriver( old_driver_hash )
       
       # purge from cache
       cls.FlushCache( g_id )
       
       return gw_key, old_name
    
    
    gateway_key = None
    old_name = None
    try:
       gateway_key, old_name = storagetypes.transaction( lambda: update_txn( fields ), xg=True )
       assert gateway_key is not None, "Transaction failed"
    except Exception, e:
       logging.exception( e )
       raise e
예제 #19
0
 def Update( cls, volume_name_or_id, volume_cert ):
    '''
    Atomically (transactionally) update a given Volume with the given fields.
    
    NOTE: volume_cert will need to have been validated by the caller.
    NOTE: this calls should be followed up with a VolumeCertBundle.Put() to put the caller's new volume cert bundle
    
    return the volume key on success 
    raise an Exception on error
    '''
    try:
       volume_id = int(volume_name_or_id)
    except:
       volume = Volume.Read_ByName( volume_name_or_id )
       if volume:
          volume_id = volume.volume_id
       else:
          raise Exception("No such Volume '%s'" % volume_name_or_id )
    
    fields = cls.cert_to_dict( volume_cert )
    
    invalid = Volume.validate_fields( fields )
    if len(invalid) != 0:
       raise Exception( "Invalid values for fields: %s" % (", ".join( invalid )) )
    
    # are we changing the name? acquire the new name if so
    rename = False
    volume_nameholder_new_key = None
    old_name = None
    
    if "name" in fields.keys():
       volume_nameholder_new_fut = VolumeNameHolder.create_async( fields.get("name"), volume_id )
       
       volume_nameholder_new = volume_nameholder_new_fut.get_result()
       volume_nameholder_new_key = volume_nameholder_new.key
       
       if volume_nameholder_new.volume_id != volume_id:
          # name collision
          raise Exception("Volume '%s' already exists!" % (fields.get("name")) )
       
       else:
          # reserved!
          rename = True
    
    volume_cert_bin = volume_cert.SerializeToString()
    
    def update_txn( fields ):
       '''
       Update the Volume transactionally.
       '''
       
       volume = Volume.Read(volume_id)
       if not volume or volume.deleted:
          # volume does not exist...
          # if we were to rename it, then delete the new nameholder
          if rename:
             storagetypes.deferred.defer( Volume.delete_all, [volume_nameholder_new_key] )
             
          raise Exception("No volume with the ID %d exists.", volume_id)
       
       old_name = volume.name 
       
       # verify update
       unwriteable = []
       for (k, v) in fields.items():
          if k not in cls.modifiable_cert_fields and getattr(volume, k) != v:
             unwriteable.append(k)
             
       if len(unwriteable) > 0:
          raise Exception("Tried to modify read-only fields: %s" % ",".join(unwriteable))
       
       # check version...
       if volume.version > fields['version']:
          raise Exception("Stale Volume version: expected > %s, got %s" % (volume.version, fields['version']))
       
       # apply update
       for (k,v) in fields.items():
          setattr( volume, k, v )
       
       # store new cert 
       volume.volume_cert_bin = volume_cert_bin
       
       ret = volume.put()
       
       Volume.FlushCache( volume_id )
       
       return ret
    
    
    volume_key = None
    try:
       volume_key = storagetypes.transaction( lambda: update_txn( fields ), xg=True )
    except Exception, e:
       logging.exception( e )
       raise e
예제 #20
0
   def Update( cls, g_name_or_id, **fields ):
      '''
      Update a gateway identified by ID with fields specified as keyword arguments.
      '''
      
      # get gateway ID
      try:
         g_id = int(g_name_or_id)
      except:
         gateway = Gateway.Read( g_name_or_id )
         if gateway is not None:
            g_id = gateway.g_id 
         else:
            raise Exception("No such Gateway '%s'" % g_name_or_id )
      
      if len(fields.keys()) == 0:
         return True
      
      # validate...
      invalid = cls.validate_fields( fields )
      if len(invalid) != 0:
         raise Exception( "Invalid values for fields: %s" % (", ".join( invalid )) )

      invalid = cls.validate_write( fields )
      if len(invalid) != 0:
         raise Exception( "Unwritable fields: %s" % (", ".join(invalid)) )
      
      rename = False
      gateway_nameholder_new_key = None
      old_name = None
      
      # do we intend to rename?  If so, reserve the name
      if "name" in fields.keys():
         gateway_nameholder_new_fut = GatewayNameHolder.create_async( fields.get("name"), g_id )
         
         gateway_nameholder_new = gateway_nameholder_new_fut.get_result()
         gateway_nameholder_new_key = gateway_nameholder_new.key
         
         if gateway_nameholder_new.g_id != g_id:
            # name collision
            raise Exception("Gateway '%s' already exists!" % (fields.get("name")) )
         
         else:
            # reserved!
            rename = True
      
      
      def update_txn( fields ):
         '''
         Update the Gateway transactionally.
         '''
         
         gateway = cls.Read(g_id)
         if not gateway:
            # gateway does not exist...
            # if we were to rename it, then delete the new nameholder
            if rename:
               storagetypes.deferred.defer( Gateway.delete_all, [gateway_nameholder_new_key] )
               
            raise Exception("No Gateway with the ID %d exists.", g_id)

         
         old_name = gateway.name 
         
         # purge from cache
         Gateway.FlushCache( g_id )
         
         old_version = gateway.cert_version
         
         # apply update
         for (k,v) in fields.items():
            setattr( gateway, k, v )
         
         gateway.cert_version = old_version + 1
         
         return gateway.put()
      
      
      gateway_key = None
      try:
         gateway_key = storagetypes.transaction( lambda: update_txn( fields ), xg=True )
         assert gateway_key is not None, "Transaction failed"
      except Exception, e:
         logging.exception( e )
         raise e
예제 #21
0
 def Update( cls, gateway_cert, new_driver=None ):
    '''
    Update a gateway identified by ID with a new certificate.
    Do not call this method directly.
    
    Return the gateway record's key on success
    Raise an exception on error.
    
    NOTE: the caller must verify the authenticity of the certificate.
    Only the volume owner should be able to update a gateway cert's capabilities.
    '''
    
    fields = cls.cert_to_dict( gateway_cert )
    g_id = fields['g_id']
    
    # validate...
    invalid = cls.validate_fields( fields )
    if len(invalid) != 0:
       raise Exception( "Invalid values for fields: %s" % (", ".join( invalid )) )
    
    new_driver_hash = None 
    old_driver_hash = None
    
    # sanity check...
    if new_driver is not None:
       new_driver_hash = GatewayDriver.hash_driver( new_driver )
       if binascii.hexlify( gateway_cert.driver_hash ) != new_driver_hash:
          raise Exception("Certificate driver hash mismatch: expected %s, got %s" % (binascii.hexlify( gateway_cert.driver_hash ), new_driver_hash))
    
    # drop cert; we'll store it separately 
    gateway_cert_bin = fields['gateway_cert']
    del fields['gateway_cert']
    
    def update_txn( fields ):
       '''
       Update the Gateway transactionally.
       '''
       
       g_id = fields['g_id']
       
       gateway = cls.Read(g_id)
       if gateway is None:
          # gateway does not exist...
          raise Exception("No Gateway with the ID %d exists.", g_id)
       
       old_driver_hash = gateway.driver_hash
       
       # verify update
       unwriteable = []
       for (k, v) in fields.items():
          if k not in cls.modifiable_cert_attrs and getattr(gateway, k) != v:
             unwriteable.append(k)
             
       if len(unwriteable) > 0:
          raise Exception("Tried to modify read-only fields: %s" % ",".join(unwriteable))
       
       # sanity check: valid version?
       if gateway.cert_version >= gateway_cert.version:
          raise Exception("Stale Gateway certificate: expected > %s; got %s" % (gateway.cert_version, gateway_cert.version))
       
       # apply update
       for (k,v) in fields.items():
          setattr( gateway, k, v )
       
       gateway.need_cert = cls.needs_cert( gateway.gateway_type, fields['caps'] )
       gateway.gateway_cert = gateway_cert_bin
       
       gw_key = gateway.put()
       
       if old_driver_hash is not None:
           # unref the old one 
           GatewayDriver.unref( old_driver_hash )
           cls.FlushCacheDriver( old_driver_hash )
       
       # purge from cache
       cls.FlushCache( g_id )
       
       return gw_key
    
    
    gateway_key = None
    try:
       gateway_key = storagetypes.transaction( lambda: update_txn( fields ), xg=True )
       assert gateway_key is not None, "Transaction failed"
    except Exception, e:
       logging.exception( e )
       raise e
예제 #22
0
    def Update(cls, volume_name_or_id, **fields):
        '''
      Atomically (transactionally) update a given Volume with the given fields.
      
      Arguments:
      volume_id         -- ID of the Volume to update.
      
      Keyword arguments: same as Create()
      '''
        try:
            volume_id = int(volume_name_or_id)
        except:
            volume = Volume.Read_ByName(volume_name_or_id)
            if volume:
                volume_id = volume.volume_id
            else:
                raise Exception("No such Volume '%s'" % volume_name_or_id)

        invalid = Volume.validate_fields(fields)
        if len(invalid) != 0:
            raise Exception("Invalid values for fields: %s" %
                            (", ".join(invalid)))

        # make sure we're only writing correct fields
        invalid = Volume.validate_write(fields)
        if len(invalid) != 0:
            raise Exception("Unwritable fields: %s" % (", ".join(invalid)))

        if fields.has_key("metadata_private_key"):
            # extract the public key
            try:
                metadata_private_key = CryptoKey.importKey(
                    kwargs['metadata_private_key'])
                kwargs['metadata_public_key'] = metadata_private_key.publickey(
                ).exportKey()
            except:
                raise Exception("Invalid metadata private key: could not load")

            if not Volume.is_valid_key(metadata_private_key):
                raise Exception(
                    "Invalid metadata private key: not sufficiently secure")

        # are we changing the name? acquire the new name if so
        rename = False
        volume_nameholder_new_key = None
        old_name = None

        if "name" in fields.keys():
            volume_nameholder_new_fut = VolumeNameHolder.create_async(
                fields.get("name"), volume_id)

            volume_nameholder_new = volume_nameholder_new_fut.get_result()
            volume_nameholder_new_key = volume_nameholder_new.key

            if volume_nameholder_new.volume_id != volume_id:
                # name collision
                raise Exception("Volume '%s' already exists!" %
                                (fields.get("name")))

            else:
                # reserved!
                rename = True

        def update_txn(fields):
            '''
         Update the Volume transactionally.
         '''

            volume = Volume.Read(volume_id)
            if not volume or volume.deleted:
                # volume does not exist...
                # if we were to rename it, then delete the new nameholder
                if rename:
                    storagetypes.deferred.defer(Volume.delete_all,
                                                [volume_nameholder_new_key])

                raise Exception("No volume with the ID %d exists.", volume_id)

            old_name = volume.name

            # purge from cache
            Volume.FlushCache(volume_id)

            old_version = volume.version
            old_cert_version = volume.cert_version

            # apply update
            for (k, v) in fields.items():
                setattr(volume, k, v)

            volume.version = old_version + 1
            volume.cert_version = old_cert_version + 1

            return volume.put()

        volume_key = None
        try:
            volume_key = storagetypes.transaction(lambda: update_txn(fields),
                                                  xg=True)
        except Exception, e:
            logging.exception(e)
            raise e
예제 #23
0
    def Update(cls, gateway_cert, new_driver=None):
        '''
      Update a gateway identified by ID with a new certificate.
      Do not call this method directly.
      
      Return the gateway record's key on success
      Raise an exception on error.
      
      NOTE: the caller must verify the authenticity of the certificate.
      Only the volume owner should be able to update a gateway cert's capabilities.
      '''

        fields = cls.cert_to_dict(gateway_cert)
        g_id = fields['g_id']

        # validate...
        invalid = cls.validate_fields(fields)
        if len(invalid) != 0:
            raise Exception("Invalid values for fields: %s" %
                            (", ".join(invalid)))

        new_driver_hash = None
        old_driver_hash = None

        # sanity check...
        if new_driver is not None and len(new_driver) > 0:
            new_driver_hash = GatewayDriver.hash_driver(new_driver)
            if binascii.hexlify(gateway_cert.driver_hash) != new_driver_hash:
                raise Exception(
                    "Certificate driver hash mismatch: expected %s, got %s" %
                    (binascii.hexlify(
                        gateway_cert.driver_hash), new_driver_hash))

        # drop cert; we'll store it separately
        gateway_cert_bin = fields['gateway_cert']
        del fields['gateway_cert']

        def update_txn(fields):
            '''
         Update the Gateway transactionally.
         '''

            g_id = fields['g_id']

            gateway = cls.Read(g_id)
            if gateway is None:
                # gateway does not exist...
                raise Exception("No Gateway with the ID %d exists.", g_id)

            old_driver_hash = gateway.driver_hash

            # verify update
            unwriteable = []
            for (k, v) in fields.items():
                if k not in cls.modifiable_cert_attrs and getattr(gateway,
                                                                  k) != v:
                    unwriteable.append(k)

            if len(unwriteable) > 0:
                raise Exception("Tried to modify read-only fields: %s" %
                                ",".join(unwriteable))

            # sanity check: valid version?
            if gateway.cert_version >= gateway_cert.version:
                raise Exception(
                    "Stale Gateway certificate: expected > %s; got %s" %
                    (gateway.cert_version, gateway_cert.version))

            # apply update
            for (k, v) in fields.items():
                setattr(gateway, k, v)

            gateway.need_cert = cls.needs_cert(gateway.gateway_type,
                                               fields['caps'])
            gateway.gateway_cert = gateway_cert_bin

            gw_key = gateway.put()

            if old_driver_hash is not None and new_driver_hash is not None and old_driver_hash != new_driver_hash:
                # unref the old one
                GatewayDriver.unref(old_driver_hash)
                cls.FlushCacheDriver(old_driver_hash)

            # purge from cache
            cls.FlushCache(g_id)

            return gw_key

        gateway_key = None
        try:
            gateway_key = storagetypes.transaction(lambda: update_txn(fields),
                                                   xg=True)
            assert gateway_key is not None, "Transaction failed"
        except Exception, e:
            logging.exception(e)
            raise e
예제 #24
0
def create(request):
    '''
    View for creating UG's
    '''
    session = request.session
    username = session['login_email']
    user = db.read_user(username)

    # Helper method that simplifies returning forms after user error.
    def give_create_form(username, session):
        message = session.pop('message', "")
        form = gatewayforms.CreateUG()
        t = loader.get_template('gateway_templates/create_user_gateway.html')
        c = RequestContext(request, {
            'username': username,
            'form': form,
            'message': message
        })
        return HttpResponse(t.render(c))

    if request.POST:
        # Validate input forms
        form = gatewayforms.CreateUG(request.POST)
        if form.is_valid():
            if not form.cleaned_data['volume_name']:
                logging.info("DLFKJSDF")
                vol = None
            else:
                attrs = {
                    "Volume.name ==":
                    form.cleaned_data['volume_name'].strip().replace(" ", "_")
                }
                vols = db.list_volumes(attrs, limit=1)
                if vols:
                    vol = vols[0]
                else:
                    session[
                        'message'] = "No volume %s exists." % form.cleaned_data[
                            'volume_name']
                    return give_create_form(username, session)
                if (vol.volume_id
                        not in user.volumes_r) and (vol.volume_id
                                                    not in user.volumes_rw):
                    session[
                        'message'] = "Must have read rights to volume %s to create UG for it." % form.cleaned_data[
                            'volume_name']
                    return give_create_form(username, session)
                # Force update of UG version
                attrs = {"UG_version": 1}

                try:
                    transaction(
                        lambda: db.update_volume(vol.volume_id, **attrs))
                except Exception as E:
                    session['message'] = "UG creation error: %s" % E
                    return give_create_form(username, session)

            try:
                # Prep kwargs
                kwargs = {}
                kwargs['read_write'] = form.cleaned_data['read_write']
                kwargs['ms_username'] = form.cleaned_data['g_name']
                kwargs['port'] = form.cleaned_data['port']
                kwargs['host'] = form.cleaned_data['host']
                kwargs['ms_password'] = form.cleaned_data['g_password']

                # Create
                new_ug = db.create_user_gateway(user, vol, **kwargs)
            except Exception as E:
                session['message'] = "UG creation error: %s" % E
                return give_create_form(username, session)

            session['new_change'] = "Your new gateway is ready."
            session['next_url'] = '/syn/UG/mygateways'
            session['next_message'] = "Click here to see your gateways."
            return HttpResponseRedirect('/syn/thanks/')
        else:
            # Prep returned form values (so they don't have to re-enter stuff)

            if 'g_name' in form.errors:
                oldname = ""
            else:
                oldname = request.POST['g_name']
            if 'volume_name' in form.errors:
                oldvolume_name = ""
            else:
                oldvolume_name = request.POST['volume_name']
            if 'host' in form.errors:
                oldhost = ""
            else:
                oldhost = request.POST['host']
            if 'port' in form.errors:
                oldport = ""
            else:
                oldport = request.POST['port']

            # Prep error message
            message = "Invalid form entry: "

            for k, v in form.errors.items():
                message = message + "\"" + k + "\"" + " -> "
                for m in v:
                    message = message + m + " "

            # Give then the form again
            form = gatewayforms.CreateUG(
                initial={
                    'g_name': oldname,
                    'volume_name': oldvolume_name,
                    'host': oldhost,
                    'port': oldport,
                })
            t = loader.get_template(
                'gateway_templates/create_user_gateway.html')
            c = RequestContext(request, {
                'username': username,
                'form': form,
                'message': message
            })
            return HttpResponse(t.render(c))

    else:
        # Not a POST, give them blank form
        return give_create_form(username, session)
예제 #25
0
    def Update(cls, g_name_or_id, **fields):
        '''
      Update a gateway identified by ID with fields specified as keyword arguments.
      '''

        # get gateway ID
        try:
            g_id = int(g_name_or_id)
        except:
            gateway = Gateway.Read(g_name_or_id)
            if gateway is not None:
                g_id = gateway.g_id
            else:
                raise Exception("No such Gateway '%s'" % g_name_or_id)

        if len(fields.keys()) == 0:
            return True

        # validate...
        invalid = cls.validate_fields(fields)
        if len(invalid) != 0:
            raise Exception("Invalid values for fields: %s" %
                            (", ".join(invalid)))

        invalid = cls.validate_write(fields)
        if len(invalid) != 0:
            raise Exception("Unwritable fields: %s" % (", ".join(invalid)))

        rename = False
        gateway_nameholder_new_key = None
        old_name = None

        # do we intend to rename?  If so, reserve the name
        if "name" in fields.keys():
            gateway_nameholder_new_fut = GatewayNameHolder.create_async(
                fields.get("name"), g_id)

            gateway_nameholder_new = gateway_nameholder_new_fut.get_result()
            gateway_nameholder_new_key = gateway_nameholder_new.key

            if gateway_nameholder_new.g_id != g_id:
                # name collision
                raise Exception("Gateway '%s' already exists!" %
                                (fields.get("name")))

            else:
                # reserved!
                rename = True

        def update_txn(fields):
            '''
         Update the Gateway transactionally.
         '''

            gateway = cls.Read(g_id)
            if not gateway:
                # gateway does not exist...
                # if we were to rename it, then delete the new nameholder
                if rename:
                    storagetypes.deferred.defer(Gateway.delete_all,
                                                [gateway_nameholder_new_key])

                raise Exception("No Gateway with the ID %d exists.", g_id)

            old_name = gateway.name

            # purge from cache
            Gateway.FlushCache(g_id)

            old_version = gateway.cert_version

            # apply update
            for (k, v) in fields.items():
                setattr(gateway, k, v)

            gateway.cert_version = old_version + 1

            return gateway.put()

        gateway_key = None
        try:
            gateway_key = storagetypes.transaction(lambda: update_txn(fields),
                                                   xg=True)
            assert gateway_key is not None, "Transaction failed"
        except Exception, e:
            logging.exception(e)
            raise e
예제 #26
0
 def Update( cls, volume_name_or_id, **fields ):
    '''
    Atomically (transactionally) update a given Volume with the given fields.
    
    Arguments:
    volume_id         -- ID of the Volume to update.
    
    Keyword arguments: same as Create()
    '''
    try:
       volume_id = int(volume_name_or_id)
    except:
       volume = Volume.Read_ByName( volume_name_or_id )
       if volume:
          volume_id = volume.volume_id
       else:
          raise Exception("No such Volume '%s'" % volume_name_or_id )
    
    invalid = Volume.validate_fields( fields )
    if len(invalid) != 0:
       raise Exception( "Invalid values for fields: %s" % (", ".join( invalid )) )
    
    # make sure we're only writing correct fields
    invalid = Volume.validate_write( fields )
    if len(invalid) != 0:
       raise Exception( "Unwritable fields: %s" % (", ".join( invalid )) )
    
    if fields.has_key("metadata_private_key"):
       # extract the public key
       try:
          metadata_private_key = CryptoKey.importKey( kwargs['metadata_private_key'] )
          kwargs['metadata_public_key'] = metadata_private_key.publickey().exportKey()
       except:
          raise Exception("Invalid metadata private key: could not load")
       
       if not Volume.is_valid_key( metadata_private_key ):
          raise Exception("Invalid metadata private key: not sufficiently secure")
    
    # are we changing the name? acquire the new name if so
    rename = False
    volume_nameholder_new_key = None
    old_name = None
    
    if "name" in fields.keys():
       volume_nameholder_new_fut = VolumeNameHolder.create_async( fields.get("name"), volume_id )
       
       volume_nameholder_new = volume_nameholder_new_fut.get_result()
       volume_nameholder_new_key = volume_nameholder_new.key
       
       if volume_nameholder_new.volume_id != volume_id:
          # name collision
          raise Exception("Volume '%s' already exists!" % (fields.get("name")) )
       
       else:
          # reserved!
          rename = True
    
    def update_txn( fields ):
       '''
       Update the Volume transactionally.
       '''
       
       volume = Volume.Read(volume_id)
       if not volume or volume.deleted:
          # volume does not exist...
          # if we were to rename it, then delete the new nameholder
          if rename:
             storagetypes.deferred.defer( Volume.delete_all, [volume_nameholder_new_key] )
             
          raise Exception("No volume with the ID %d exists.", volume_id)
       
       old_name = volume.name 
       
       # purge from cache
       Volume.FlushCache( volume_id )
       
       old_version = volume.version
       old_cert_version = volume.cert_version
       
       # apply update
       for (k,v) in fields.items():
          setattr( volume, k, v )
       
       volume.version = old_version + 1
       volume.cert_version = old_cert_version + 1
       
       return volume.put()
    
    
    volume_key = None
    try:
       volume_key = storagetypes.transaction( lambda: update_txn( fields ), xg=True )
    except Exception, e:
       logging.exception( e )
       raise e