Миграция GAE Blobstore к HRD применение

Google App Engine Если вы планируете перенести Google App Engine приложения к "новому" Высокое схему репликации баз данных, то вы наверняка знаете, что процесс миграции Google не будет обрабатывать Blobstore файлов.

Здесь вы найдете некоторые Python скриптов, которые помогут вам двигаться Blobstore файлы из старых приложений с новой, и исправить все ссылки в новой базе данных. Как всегда, используйте на свой страх и риск, не пытайтесь ничего делать без чтения и понимания сценариев, иначе вы можете потерять свои данные навсегда.

Некоторые соображения:

  • Мы же использовали эти сценарии в наших собственных приложений, так что я могу сказать, что это работает. Тем не менее, мне пришлось редактировать оригинальные сценарии, чтобы сделать их более "общий", отказаться от ссылок базы данных и имена и т.д.
  • Я постараюсь описать этапы миграции, но, пожалуйста, не пытайтесь ничего делать, прежде чем читать всю статью в первую очередь.
  • Это отнюдь не предназначены для полностью автоматической миграции, по сути, шаги должны быть выполнены вручную по одному.
  • Сценарии не будут мигрировать большие файлы. Мы мигрировали файлы размером до 40 Мб без проблем, но если у вас есть файлы более, что он, вероятно, удастся. Например, мы пытались безуспешно 300Mb файл, причина в том, что файл должен быть загружен из старых приложений с новой, и есть 1 минута ожидания для приложения запросов, так что, если загрузка занимает больше, чем она не будет выполнена .
Как скрипт работает

Вам нужно будет поставить скрипт в своих приложениях, как новые (HRD) и старый. Это в основном предоставляет четыре адреса и вам необходимо получить доступ к двум из них из HRD приложения.
Делая это, вы будете скачивать все файлы, капля из старых приложений на новый, то сценарий будет создать модель, которая поддерживает отображение между старой и новой литературы.
Последним шагом является перенос старых ссылок на новые в HRD баз данных.

Предпосылки
  • Все ссылки на файлы капля в модели должны быть типа blobstore.BlobReferenceProperty , если не необходимо скорректировать их в первую очередь.
  • Перенос базы данных из старых приложений на новые приложения HRD использованием стандартных методов миграции Google .
Шаги
  • Добавьте адреса для вашего приложения
def main():
    application = webapp.WSGIApplication(
          [
           # ... Your app URLs here ...
           # TODO - REMOVE THIS AFTER MIGRATION
           ('/mig/__getblob/(.+)', GetBlob),
           ('/mig/__getblobkeys/?', GetBlobKeys),
           ('/mig/__migrateblobs/?', MigrateBlobs),
           ('/mig/__migratereferences/?', MigrateBlobReferences),
          ], debug=True)
    run_wsgi_app(application)

if __name__ == '__main__':
  main()
  • Затем добавить миграции кода
####
# TEMPORARY BLOBSTORE MIGRATION CODE
####

MODELS = (
    # add your (model, blobinfo_field_name) tuples here
    ("myModel1", "blobinfofield"),
    ("myModel2", "BlobInfo"),
)

class mig_BlobMig(db.Model):
    fname = db.StringProperty()
    blobinfo = blobstore.BlobReferenceProperty()
    origkey = db.StringProperty()

class MigrateBlobReferences(blobstore_handlers.BlobstoreDownloadHandler):
    '''Migrate blob info references'''
    def get(self):
        import models
        tb = dict([(str(blob.origkey), blob.blobinfo) for blob in mig_BlobMig.all()])
        for modelname, field in MODELS:
            to_put = []
            skipped = 0
            for obj in db.GqlQuery('SELECT * FROM %s'%modelname):
                oldkey = getattr(obj, field)
                if oldkey:
                    oldkey = str(oldkey.key())
                if oldkey in tb:
                    setattr(obj, field, tb[oldkey])
                    to_put.append(obj)
                else:
                    skipped += 1
            db.put(to_put)
            self.response.out.write("[%s] - Migrated %d references!<br/>Skipped: %d<br/>\n"%(modelname, len(to_put), skipped))

class MigrateBlobs(blobstore_handlers.BlobstoreDownloadHandler):
    '''Migrate blobs from myoldapp to mynewapp'''
    def get(self):
        import time
        from google.appengine.api import files, urlfetch
        start_time = time.time()
        timed_out = False
        migrated_keys = set([str(blob.origkey) for blob in mig_BlobMig.all()])
        all_blobs = eval(urlfetch.fetch("https://myoldapp.appspot.com/mig/__getblobkeys", deadline=15.0).content)
        all_keys = set(all_blobs.keys())
        missing_keys = list(all_keys-migrated_keys)
        if not missing_keys:
            self.response.out.write("Nothing to migrate!")
            return
        # Download 20 blobs per round
        download_keys = missing_keys[:20]
        MAXSIZE = (10*1024*1024) # 10MB
        for origkey in download_keys:
            blob = all_blobs[origkey]
            url = "https://myoldapp.appspot.com/mig/__getblob/%s"%urllib.quote_plus(origkey)
            blob_path = files.blobstore.create(mime_type=blob["content_type"], _blobinfo_uploaded_filename=blob["filename"])
            fsize = int(blob["size"])
            with files.open(blob_path, 'a') as f:
                for first_byte in range(0, fsize, MAXSIZE):
                    last_byte = (first_byte+MAXSIZE-1)
                    if last_byte>=fsize: last_byte=(fsize-1)
                    bytes_range = "bytes=%d-%d"%(first_byte,last_byte)
                    logging.info("Downloading [%s] range [%s] key=[%s]"%(blob["filename"], bytes_range, origkey))
                    res = urlfetch.fetch(url, deadline=35.0, headers={"Range": bytes_range})
                    f.write(res.content)
                    del res.content
                    del res
                    if (time.time()-start_time > 40.0):
                        timed_out = True
                        break
            if timed_out:
                self.response.out.write("Stopped due to time limit!<br/>")
                break
            files.finalize(blob_path)
            blob_key = files.blobstore.get_blob_key(blob_path)
            blob_info = blobstore.BlobInfo.get(blob_key)
            mig_BlobMig(fname=blob["filename"], blobinfo=blob_info, origkey=origkey).put()
            logging.info("Successfully downloaded [%s]!!!"%(blob["filename"]))
            self.response.out.write("Migrated %s<br/>"%blob["filename"])
        self.response.out.write("<br/>SUCCESS!")

class GetBlobKeys(blobstore_handlers.BlobstoreDownloadHandler):
    '''Retrieve all Blob Keys, as a JSON string'''
    def get(self):
        from simplejson.encoder import JSONEncoder
        blobs = {}
        for blob_info in blobstore.BlobInfo.all():
            blobs[str(blob_info.key())] = {
             "filename":str(blob_info.filename),
             "content_type":str(blob_info.content_type),
             "size":int(blob_info.size),
             "key":str(blob_info.key()),
            }
        self.response.headers["Content-type"] = "application/json"
        self.response.out.write(JSONEncoder().encode(blobs))

class GetBlob(blobstore_handlers.BlobstoreDownloadHandler):
    '''Download a blob given its key'''
    def get(self, blobkey):
        blobkey = str(urllib.unquote(blobkey))
        blob_info = blobstore.BlobInfo.get(blobkey)
        if not blob_info:
            self.error(404)
            return
        self.response.headers["Content-type"] = str(blob_info.content_type)
        self.send_blob(blob_info, save_as=True)

####
# END OF TEMPORARY BLOBSTORE MIGRATION CODE
####
  • Изменение MODELS переменная добавления модели и поля капля информации, которую необходимо обновить
  • Замените myoldapp адреса с фактическим URL старых приложений
  • Синхронизация кода и приложений
  • Откройте браузер и укажите в нем http://mynewapp.appspot.com/mig/__migrateblobs . Конечно, mynewapp должны быть заменены на ваши фактические HRD имя приложения. Это позволит загрузить капли от старых приложений с новой. Потому что есть ожидания ограничение необходимо называть его много раз. ВНИМАНИЕ: Вы должны сделать только один запрос на время, не вызывать его из двух браузеров / вкладок в то же время, или вы запутались миграции баз данных!. Таким образом, этот шаг должен быть тщательно выполнен, одна просьба во время и дождаться ее завершения до вызова следующей. Повторите это, пока не появится сообщение Nothing to migrate! . Этот шаг может быть очень медленным в зависимости от того, сколько файлов находится в blobstore и их размер, это может занять много времени, чтобы все файлы загружены. Будьте терпеливы!
  • После того как все файлы копируются в новое приложение, указать браузеру http://mynewapp.appspot.com/mig/__migratereferences . Должно быть быстрым, и она должна быть выполнена только один раз. Однако не вредит называют его более одного раза.
  • Последний шаг, удалите код миграции и адреса и синхронизировать код снова. Вы также можете удалить mig_BlobMig базе данных.

Хорошо миграции.

  1. Пока нет комментариев.

Защита от спама на WP Captcha-Free