def _get_import_backup(self, context, backup_url): """Prepare database backup record for import. This method decodes provided backup_url and expects to find the id of the backup in there. Then checks the DB for the presence of this backup record and if it finds it and is not deleted it will raise an exception because the record cannot be created or used. If the record is in deleted status then we must be trying to recover this record, so we'll reuse it. If the record doesn't already exist we create it with provided id. :param context: running context :param backup_url: backup description to be used by the backup driver :return: BackupImport object :raises InvalidBackup: :raises InvalidInput: """ reservations = None backup = None # Deserialize string backup record into a dictionary backup_record = objects.Backup.decode_record(backup_url) # ID is a required field since it's what links incremental backups if 'id' not in backup_record: msg = _('Provided backup record is missing an id') raise exception.InvalidInput(reason=msg) # Since we use size to reserve&commit quota, size is another required # field. if 'size' not in backup_record: msg = _('Provided backup record is missing size attribute') raise exception.InvalidInput(reason=msg) try: reserve_opts = { 'backups': 1, 'backup_gigabytes': backup_record['size'] } reservations = QUOTAS.reserve(context, **reserve_opts) except exception.OverQuota as e: quota_utils.process_reserve_over_quota(context, e, resource='backups', size=backup_record['size']) kwargs = { 'user_id': context.user_id, 'project_id': context.project_id, 'volume_id': IMPORT_VOLUME_ID, 'status': fields.BackupStatus.CREATING, 'deleted_at': None, 'deleted': False, 'metadata': {} } try: try: # Try to get the backup with that ID in all projects even among # deleted entries. backup = objects.BackupImport.get_by_id( context.elevated(read_deleted='yes'), backup_record['id'], project_only=False) # If record exists and it's not deleted we cannot proceed # with the import if backup.status != fields.BackupStatus.DELETED: msg = _('Backup already exists in database.') raise exception.InvalidBackup(reason=msg) # Otherwise we'll "revive" delete backup record backup.update(kwargs) backup.save() QUOTAS.commit(context, reservations) except exception.BackupNotFound: # If record doesn't exist create it with the specific ID backup = objects.BackupImport(context=context, id=backup_record['id'], **kwargs) backup.create() QUOTAS.commit(context, reservations) except Exception: with excutils.save_and_reraise_exception(): try: if backup and 'id' in backup: backup.destroy() finally: QUOTAS.rollback(context, reservations) return backup
def _get_import_backup(self, context, backup_url): """Prepare database backup record for import. This method decodes provided backup_url and expects to find the id of the backup in there. Then checks the DB for the presence of this backup record and if it finds it and is not deleted it will raise an exception because the record cannot be created or used. If the record is in deleted status then we must be trying to recover this record, so we'll reuse it. If the record doesn't already exist we create it with provided id. :param context: running context :param backup_url: backup description to be used by the backup driver :return: BackupImport object :raises InvalidBackup: :raises InvalidInput: """ # Deserialize string backup record into a dictionary backup_record = objects.Backup.decode_record(backup_url) # ID is a required field since it's what links incremental backups if 'id' not in backup_record: msg = _('Provided backup record is missing an id') raise exception.InvalidInput(reason=msg) kwargs = { 'user_id': context.user_id, 'project_id': context.project_id, 'volume_id': IMPORT_VOLUME_ID, 'status': fields.BackupStatus.CREATING, 'deleted_at': None, 'deleted': False, 'metadata': {} } try: # Try to get the backup with that ID in all projects even among # deleted entries. backup = objects.BackupImport.get_by_id( context.elevated(read_deleted='yes'), backup_record['id'], project_only=False) # If record exists and it's not deleted we cannot proceed with the # import if backup.status != fields.BackupStatus.DELETED: msg = _('Backup already exists in database.') raise exception.InvalidBackup(reason=msg) # Otherwise we'll "revive" delete backup record backup.update(kwargs) backup.save() except exception.BackupNotFound: # If record doesn't exist create it with the specific ID backup = objects.BackupImport(context=context, id=backup_record['id'], **kwargs) backup.create() return backup