def cmd_upgrade(upgrader=None): """Command for applying upgrades.""" from flask import current_app from invenio_utils.text import wrap_text_in_a_box, wait_for_user logfilename = os.path.join(current_app.config['CFG_LOGDIR'], 'invenio_upgrader.log') if not upgrader: upgrader = InvenioUpgrader() logger = upgrader.get_logger(logfilename=logfilename) try: upgrades = upgrader.get_upgrades() if not upgrades: logger.info("All upgrades have been applied.") return logger.info("Following upgrade(s) will be applied:") for u in upgrades: title = u['__doc__'] if title: logger.info(" * %s (%s)" % (u['id'], title)) else: logger.info(" * %s" % u['id']) logger.info("Running pre-upgrade checks...") upgrader.pre_upgrade_checks(upgrades) logger.info("Calculating estimated upgrade time...") estimate = upgrader.human_estimate(upgrades) wait_for_user(wrap_text_in_a_box( "WARNING: You are going to upgrade your installation " "(estimated time: %s)!" % estimate)) for u in upgrades: title = u['__doc__'] if title: logger.info("Applying %s (%s)" % (u['id'], title)) else: logger.info("Applying %s" % u['id']) upgrader.apply_upgrade(u) logger.info("Running post-upgrade checks...") upgrader.post_upgrade_checks(upgrades) if upgrader.has_warnings(): logger.warning("Upgrade completed with %s warnings - please check " "log-file for further information:\nless %s" % (upgrader.get_warnings_count(), logfilename)) else: logger.info("Upgrade completed successfully.") except RuntimeError as e: for msg in e.args: logger.error(unicode(msg)) logger.info("Please check log file for further information:\n" "less %s" % logfilename) sys.exit(1)
def drop(yes_i_know=False, quiet=False): """Drop database tables.""" print(">>> Going to drop tables and related data on filesystem ...") from invenio_utils.date import get_time_estimator from invenio_utils.text import wrap_text_in_a_box, wait_for_user from invenio_ext.sqlalchemy.utils import test_sqla_connection, \ test_sqla_utf8_chain from invenio_ext.sqlalchemy import db, models # Step 0: confirm deletion wait_for_user( wrap_text_in_a_box( "WARNING: You are going to destroy your database tables and related " "data on filesystem!")) # Step 1: test database connection test_sqla_connection() test_sqla_utf8_chain() list(models) # Step 2: destroy associated data tables = list(reversed(db.metadata.sorted_tables)) def _dropper(items, prefix, dropper): N = len(items) prefix = prefix.format(N) e = get_time_estimator(N) dropped = 0 if quiet: print(prefix) for i, table in enumerate(items): try: if not quiet: print_progress(1.0 * (i + 1) / N, prefix=prefix, suffix=str( datetime.timedelta(seconds=e()[0]))) dropper(table) dropped += 1 except Exception: print('\r>>> problem with dropping {0}'.format(table)) current_app.logger.exception(table) if dropped == N: print(">>> Everything has been dropped successfully.") else: print("ERROR: not all items were properly dropped.") print(">>> Dropped", dropped, 'out of', N) _dropper(tables, '>>> Dropping {0} tables ...', lambda table: table.drop(bind=db.engine, checkfirst=True))
def init(user='******', password='', yes_i_know=False): """Initialize database and user.""" from invenio_ext.sqlalchemy.utils import initialize_database_user from invenio_utils.text import wrap_text_in_a_box, wait_for_user from sqlalchemy_utils.functions import database_exists, create_database, \ drop_database from sqlalchemy.engine.url import URL from sqlalchemy import create_engine # Step 0: confirm deletion wait_for_user( wrap_text_in_a_box( "WARNING: You are going to destroy your database tables! Run first" " `inveniomanage database drop`.")) # Step 1: create URI to connect admin user cfg = current_app.config SQLALCHEMY_DATABASE_URI = URL( cfg.get('CFG_DATABASE_TYPE', 'mysql'), username=user, password=password, host=cfg.get('CFG_DATABASE_HOST'), database=cfg.get('CFG_DATABASE_NAME'), port=cfg.get('CFG_DATABASE_PORT'), ) # Step 2: drop the database if already exists if database_exists(SQLALCHEMY_DATABASE_URI): drop_database(SQLALCHEMY_DATABASE_URI) print('>>> Database has been dropped.') # Step 3: create the database create_database(SQLALCHEMY_DATABASE_URI, encoding='utf8') print('>>> Database has been created.') # Step 4: setup connection with special user engine = create_engine(SQLALCHEMY_DATABASE_URI) engine.connect() # Step 5: grant privileges for the user initialize_database_user( engine=engine, database_name=current_app.config['CFG_DATABASE_NAME'], database_user=current_app.config['CFG_DATABASE_USER'], database_pass=current_app.config['CFG_DATABASE_PASS'], ) print('>>> Database user has been initialized.')
def pre_upgrade(): """Check for potentially invalid revisions""" # Check for any inconsistent data missing_parents = list(db.engine.execute( """SELECT id, id_parent FROM bwlOBJECT WHERE id_parent NOT IN (SELECT id FROM bwlOBJECT)""" )) if missing_parents: warnings.warn("Inconsistent parent IDs in bwlOBJECT '{0}'".format( missing_parents )) try: wait_for_user("\nSetting all dangling parents to NULL? (Ctrl+C to stop)\n") except SystemExit: raise RuntimeError("Upgrade aborted by user.") for parent in missing_parents: db.engine.execute( """UPDATE bwlOBJECT SET id_parent=NULL WHERE id={0}""".format(parent[0]) ) dangling_logs = list(db.engine.execute( """SELECT id_object FROM bwlOBJECTLOGGING WHERE id_object NOT IN (SELECT id FROM bwlOBJECT)""" )) + list(db.engine.execute( """SELECT id_object FROM bwlWORKFLOWLOGGING WHERE id_object NOT IN (SELECT uuid FROM bwlWORKFLOW)""" )) if dangling_logs: warnings.warn("Inconsistent logs in bwlOBJECT/bwlWORKFLOW '{0}'".format( len(dangling_logs) )) try: wait_for_user("\nDelete all dangling logs? (Ctrl+C to stop)\n") except SystemExit: raise RuntimeError("Upgrade aborted by user.") db.engine.execute( """DELETE FROM bwlOBJECTLOGGING WHERE id_object NOT IN (SELECT id FROM bwlOBJECT)""" ) db.engine.execute( """DELETE FROM bwlWORKFLOWLOGGING WHERE id_object NOT IN (SELECT uuid FROM bwlWORKFLOW)""" )