Source code for xmm.tasks.mongorestore

import glob
import os
import subprocess

import flask
from celery.task import Task as CeleryTask
from flask_babel import lazy_gettext as _

from xmm.core import mongo
from xmm.models import Notification
from xmm.util.text import get_host_from_url
from .base import runner


[docs]class MongoRestoreTask(CeleryTask): """Restore MongoDB collections from dumps created with the MongoDumpTask.""" SYSTEM_PREFIX = 'system_' DATA_PREFIX = 'data_' COLLECTION_PREFIX = 'collection_' MEDIA_PREFIX = 'media_' CMS_PREFIX = 'cms_' def _import_collection(self, path, db, collection, quiet): """`mongo_restore` requires the direct path to a *.bson file when trying to import a single collection.""" path = os.path.join(path, '{}.bson'.format(collection)) script = [ flask.current_app.config['BINARIES']['mongorestore'], '--host={}'.format(get_host_from_url(flask.current_app.config['MONGODB_URL'])), '--db={}'.format(db), '--collection={}'.format(collection), '--drop', path, ] if quiet: script.append('--quiet') return subprocess.call(script) def _import_one_collection(self, path, mongo_dbname, collection, quiet): returncode = self._import_collection(path, mongo_dbname, collection, quiet) if returncode == 0: message = _('Mongorestore: {} importiert.').format(collection) Notification.notify(message, 'success') else: message = _('Mongorestore fehlgeschlagen ({}).').format(returncode) Notification.notify(message, 'error') def _iter_collections(self, path, no_masterdata, no_collections, no_media, no_cms): files = glob.iglob(os.path.join(path, '*.bson')) for filename in files: collection = os.path.basename(filename).rsplit('.', 1)[0] if no_masterdata and collection.startswith(self.DATA_PREFIX): continue if no_collections and collection.startswith(self.COLLECTION_PREFIX): continue if no_media and collection.startswith(self.MEDIA_PREFIX): continue if no_cms and collection.startswith(self.CMS_PREFIX): continue yield collection def _import_many_collections(self, path, mongo_dbname, collections, quiet): succeeded = [] failed = [] returncode = -1 for collection in collections: returncode = self._import_collection(path, mongo_dbname, collection, quiet) if returncode == 0: succeeded.append(collection) else: failed.append(collection) if returncode == 0 and len(failed) == 0: message = _('Mongorestore: {} collections importiert.').format(len(succeeded)) Notification.notify(message, 'success') else: message = _('Mongorestore fehlgeschlagen ({}).').format(', '.join(failed)) Notification.notify(message, 'error') @runner def run(self, task, path=None, only=None, no_masterdata=False, no_collections=False, no_media=False, no_cms=False, quiet=False): """ Run the task. :param path: Path to dump location :param only: Import only one collection :param no_masterdata: Wether to include masterdata :param no_collections: Wether to include collections data :param no_media: Wether to include media data :param no_cms: Wether to include cms data :param quiet: No output on command line """ if path is None: path = os.path.join(flask.current_app.config['STATIC_ROOT'], 'mongodump') os.makedirs(path, 0o775, exist_ok=True) mongo_dbname = mongo.connection.get_default_database().name if not path.endswith(mongo_dbname): path = os.path.join(path, mongo_dbname) if only is not None: self._import_one_collection(path, mongo_dbname, only, quiet) else: self._import_many_collections( path, mongo_dbname, self._iter_collections( path, no_masterdata, no_collections, no_media, no_cms, ), quiet)