Migración Blobstore GAE a una aplicación DRH
Si usted está planeando migrar la aplicación de Google App Engine para el "nuevo" esquema de base de datos de alta replicación, entonces usted probablemente sabe que el proceso de migración de Google no manejar archivos Blobstore.
Aquí encontrará algunos scripts de Python que le ayudarán a mover los archivos Blobstore de la aplicación antigua a la nueva, y corregir todas las referencias en la base de datos nueva. Como siempre, utilice a su propio riesgo, no trates de hacer nada sin la lectura y la comprensión de las secuencias de comandos, de lo contrario puede perder sus datos de forma permanente.
Algunas consideraciones:
- Hicimos utilizar estos scripts en nuestra aplicación propia, así que puedo decir que funciona. Sin embargo, tuve que editar los guiones originales para hacerlos más "genérico", retire mis referencias de bases de datos y los nombres, etc,
- Voy a tratar de describir las fases de la migración, pero por favor no trates de hacer nada antes de leer el artículo completo en primer lugar.
- Esto no es por cualquier otro medio destinado a ser una migración totalmente automático, de hecho, los pasos necesita ser ejecutado manualmente una por una.
- Los scripts no se migran los archivos grandes. Hemos migrado archivos de hasta 40Mb sin problemas, pero si usted tiene archivos más grandes que eso, probablemente, se producirá un error. Por ejemplo, hemos tratado de un archivo de 300Mb, sin éxito, la razón es que el archivo debe ser descargado desde la aplicación antigua a la nueva, y hay un tiempo de espera de 1 minuto para que las solicitudes de aplicaciones, así que si la descarga tarda más de que va a fallar .
¿Cómo funciona el script
Usted tendrá que poner el guión en sus aplicaciones, tanto el nuevo (HRD) y el viejo. Básicamente, expone cuatro direcciones URL y tendrá que acceder a dos de ellos de la aplicación de los recursos humanos.
De esta manera vas a descargar todos los archivos BLOB de la aplicación antigua a la nueva, el script creará un modelo que mantiene un mapa entre las referencias antiguas y nuevas.
El último paso es migrar las referencias antiguas a la nueva en las bases de datos de recursos humanos.
Requisitos previos
- Todas las referencias a archivos BLOB en sus modelos deben ser del tipo
blobstore.BlobReferenceProperty, si no que tendrá que ajustar en primer lugar. - Migración de las bases de datos desde la aplicación antigua a la nueva aplicación de los recursos humanos mediante el método estándar de Google la migración .
Pasos
- Agregar el URL para su aplicación
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()
- A continuación, agregue el código de la migración
####
# 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
####
- Modificar el
MODELSvariable de la adición de los modelos y campos blob información que usted necesita para actualizar - Vuelva a colocar
myoldappURL con la dirección URL real de su aplicación anterior - Sincronizar el código de ambas aplicaciones
- Abra el navegador y el punto a
http://mynewapp.appspot.com/mig/__migrateblobs. Por supuesto,mynewappdebe ser reemplazado con el nombre real de aplicación de los recursos humanos. Esto descargará las manchas de la aplicación antigua a la nueva. Debido a que existe una limitación de tiempo de espera que tendrá que llamar muchas veces. ADVERTENCIA: Usted debe hacer una sola solicitud en el momento, nunca se llame a partir de dos navegadores, separadores, al mismo tiempo o si se hace un lío la base de datos de migración!. Así que este paso debe ser cuidadosamente ejecutada, una solicitud en tiempo y esperar a que termine antes de llamar a la siguiente. Repita este procedimiento hasta que aparezca el mensajeNothing to migrate!. Este paso puede ser muy lento dependiendo de la cantidad de archivos que tiene en el blobstore y el tamaño de ellos, puede ser que tome mucho tiempo para obtener todos los archivos descargados. ¡Tenga paciencia! - Una vez que todos los archivos se copian en la nueva aplicación, apuntar el navegador para
http://mynewapp.appspot.com/mig/__migratereferences. En caso de ser rápido, y necesita que se ejecute sólo una vez. Sin embargo, no pasa nada si lo llamo más de una vez. - El último paso, eliminar el código de la migración y las direcciones URL y sincronizar el código de nuevo. También puede quitar el
mig_BlobMigbase de datos.
Migración Buena.
