def migrate(env, dry_run=False): """ User-friendly frontend to run database migrations. """ registry = env['registry'] settings = registry.settings readonly_backends = ('storage', 'permission') readonly_mode = asbool(settings.get('readonly', False)) for backend in ('cache', 'storage', 'permission'): if hasattr(registry, backend): if readonly_mode and backend in readonly_backends: message = ('Cannot migrate the %s backend while ' 'in readonly mode.' % backend) logger.error(message) else: getattr(registry, backend).initialize_schema(dry_run=dry_run)
def delete_collection(env, bucket_id, collection_id): registry = env['registry'] settings = registry.settings readonly_mode = asbool(settings.get('readonly', False)) if readonly_mode: message = ('Cannot delete the collection while in readonly mode.') logger.error(message) return 31 bucket = '/buckets/{}'.format(bucket_id) collection = '/buckets/{}/collections/{}'.format(bucket_id, collection_id) try: registry.storage.get(collection_id='bucket', parent_id='', object_id=bucket_id) except storage_exceptions.RecordNotFoundError: logger.error("Bucket '{}' does not exist.".format(bucket)) return 32 try: registry.storage.get(collection_id='collection', parent_id=bucket, object_id=collection_id) except storage_exceptions.RecordNotFoundError: logger.error("Collection '{}' does not exist.".format(collection)) return 33 deleted = registry.storage.delete_all(collection_id='record', parent_id=collection, with_deleted=False) if len(deleted) == 0: logger.info("No records found for '{}'.".format(collection)) else: logger.info('{} record(s) were deleted.'.format(len(deleted))) registry.storage.delete(collection_id='collection', parent_id=bucket, object_id=collection_id, with_deleted=False) logger.info("'{}' collection object was deleted.".format(collection)) record = ('/buckets/{bucket_id}' '/collections/{collection_id}' '/records/{record_id}') registry.permission.delete_object_permissions( collection, *[ record.format(bucket_id=bucket_id, collection_id=collection_id, record_id=r['id']) for r in deleted ]) logger.info('Related permissions were deleted.') current_transaction.commit() return 0
def delete_collection(env, bucket_id, collection_id): registry = env['registry'] settings = registry.settings readonly_mode = asbool(settings.get('readonly', False)) if readonly_mode: message = ('Cannot delete the collection while in readonly mode.') logger.error(message) return 31 bucket = '/buckets/%s' % bucket_id collection = '/buckets/%s/collections/%s' % (bucket_id, collection_id) try: registry.storage.get(collection_id='bucket', parent_id='', object_id=bucket_id) except storage_exceptions.RecordNotFoundError: logger.error("Bucket %r does not exist." % bucket) return 32 try: registry.storage.get(collection_id='collection', parent_id=bucket, object_id=collection_id) except storage_exceptions.RecordNotFoundError: logger.error("Collection %r does not exist." % collection) return 33 deleted = registry.storage.delete_all(collection_id='record', parent_id=collection, with_deleted=False) if len(deleted) == 0: logger.info('No records found for %r.' % collection) else: logger.info('%d record(s) were deleted.' % len(deleted)) registry.storage.delete(collection_id='collection', parent_id=bucket, object_id=collection_id, with_deleted=False) logger.info("%r collection object was deleted." % collection) record = ('/buckets/{bucket_id}' '/collections/{collection_id}' '/records/{record_id}') registry.permission.delete_object_permissions( collection, *[record.format(bucket_id=bucket_id, collection_id=collection_id, record_id=r['id']) for r in deleted]) logger.info('Related permissions were deleted.') current_transaction.commit() return 0
def get_heartbeat(request): """Return information about server health.""" status = {} def heartbeat_check(name, func): status[name] = False status[name] = func(request) # Since the heartbeat checks run concurrently, their transactions # overlap and might end in shared lock errors. By aborting here # we clean-up the state on each heartbeat call instead of once at the # end of the request. See bug Kinto/kinto#804 transaction.abort() # Start executing heartbeats concurrently. heartbeats = request.registry.heartbeats pool = ThreadPoolExecutor(max_workers=max(1, len(heartbeats.keys()))) futures = [] for name, func in heartbeats.items(): future = pool.submit(heartbeat_check, name, func) future.__heartbeat_name = name # For logging purposes. futures.append(future) # Wait for the results, with timeout. seconds = float(request.registry.settings['heartbeat_timeout_seconds']) done, not_done = wait(futures, timeout=seconds) # A heartbeat is supposed to return True or False, and never raise. # Just in case, go though results to spot any potential exception. for future in done: exc = future.exception() if exc is not None: logger.error("'{}' heartbeat failed.".format( future.__heartbeat_name)) logger.error(exc) # Log timed-out heartbeats. for future in not_done: name = future.__heartbeat_name error_msg = "'{}' heartbeat has exceeded timeout of {} seconds." logger.error(error_msg.format(name, seconds)) # If any has failed, return a 503 error response. has_error = not all([v or v is None for v in status.values()]) if has_error: request.response.status = 503 return status
def get_heartbeat(request): """Return information about server health.""" status = {} def heartbeat_check(name, func): status[name] = False status[name] = func(request) # Start executing heartbeats concurrently. heartbeats = request.registry.heartbeats pool = ThreadPoolExecutor(max_workers=max(1, len(heartbeats.keys()))) futures = [] for name, func in heartbeats.items(): future = pool.submit(heartbeat_check, name, func) future.__heartbeat_name = name # For logging purposes. futures.append(future) # Wait for the results, with timeout. seconds = float(request.registry.settings['heartbeat_timeout_seconds']) done, not_done = wait(futures, timeout=seconds) # A heartbeat is supposed to return True or False, and never raise. # Just in case, go though results to spot any potential exception. for future in done: exc = future.exception() if exc is not None: logger.error("%r heartbeat failed." % future.__heartbeat_name) logger.error(exc) # Log timed-out heartbeats. for future in not_done: name = future.__heartbeat_name error_msg = "%r heartbeat has exceeded timeout of %s seconds." logger.error(error_msg % (name, seconds)) # If any has failed, return a 503 error response. has_error = not all([v or v is None for v in status.values()]) if has_error: request.response.status = 503 return status