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
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)
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
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
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
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
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
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
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
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))
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
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
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
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
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 ) )
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 )
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 )
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
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
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
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
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
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
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)
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
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