def rename_db_to_drop(instance, dbs, verbose=False, dry_run=False):
    """ Create a new empty db and move the contents of the original db there

    Args:
    instance - a hostaddr object
    dbs -  a set of database names
    verbose - bool, will direct sql to stdout
    dry_run - bool, will make no changes to
    """
    # confirm db is not in zk and not in use
    orphaned, _, _ = find_shard_mismatches.find_shard_mismatches(instance)
    if not orphaned:
        print "Detected no orphans"
        sys.exit(1)

    instance_orphans = orphaned[instance.__str__()]
    unexpected = dbs.difference(instance_orphans)
    if unexpected:
        print ''.join(("Cowardly refusing to act on the following dbs: ",
                       ','.join(unexpected)))
        sys.exit(1)

    # confirm that renames would not be blocked by an existing table
    conn = mysql_lib.connect_mysql(instance)

    cursor = conn.cursor()
    for db in dbs:
        renamed_db = ''.join((DB_PREPEND, db))

        sql = ''.join(("SELECT CONCAT(t2.TABLE_SCHEMA, \n",
                       "              '.', t2.TABLE_NAME) as tbl \n",
                       "FROM information_schema.tables t1 \n",
                       "INNER JOIN information_schema.tables t2 \n",
                       "    USING(TABLE_NAME) \n",
                       "WHERE t1.TABLE_SCHEMA = %(old_db)s AND \n"
                       "      t2.TABLE_SCHEMA = %(new_db)s;"))

        params = {'old_db': db,
                  'new_db': renamed_db}
        cursor = conn.cursor()
        cursor.execute(sql, params)
        dups = cursor.fetchall()

        if dups:
            for dup in dups:
                print "Table rename blocked by {tbl}".format(tbl=dup['tbl'])
            sys.exit(1)

        # We should be safe to create the new db and rename
        if not dry_run:
            mysql_lib.create_db(instance, renamed_db)
        mysql_lib.move_db_contents(instance,
                                   old_db=db,
                                   new_db=renamed_db,
                                   verbose=verbose,
                                   dry_run=dry_run)
def rename_db_to_drop(instance, dbs, verbose=False, dry_run=False):
    """ Create a new empty db and move the contents of the original db there

    Args:
    instance - a hostaddr object
    dbs -  a set of database names
    verbose - bool, will direct sql to stdout
    dry_run - bool, will make no changes to
    """
    # confirm db is not in zk and not in use
    orphaned, _, _ = find_shard_mismatches.find_shard_mismatches(instance)
    if not orphaned:
        print "Detected no orphans"
        sys.exit(1)

    instance_orphans = orphaned[instance.__str__()]
    unexpected = dbs.difference(instance_orphans)
    if unexpected:
        print ''.join(("Cowardly refusing to act on the following dbs: ",
                       ','.join(unexpected)))
        sys.exit(1)

    # confirm that renames would not be blocked by an existing table
    conn = mysql_lib.connect_mysql(instance)

    cursor = conn.cursor()
    for db in dbs:
        renamed_db = ''.join((DB_PREPEND, db))

        sql = ''.join(("SELECT CONCAT(t2.TABLE_SCHEMA, \n",
                       "              '.', t2.TABLE_NAME) as tbl \n",
                       "FROM information_schema.tables t1 \n",
                       "INNER JOIN information_schema.tables t2 \n",
                       "    USING(TABLE_NAME) \n",
                       "WHERE t1.TABLE_SCHEMA = %(old_db)s AND \n"
                       "      t2.TABLE_SCHEMA = %(new_db)s;"))

        params = {'old_db': db,
                  'new_db': renamed_db}
        cursor = conn.cursor()
        cursor.execute(sql, params)
        dups = cursor.fetchall()

        if dups:
            for dup in dups:
                print "Table rename blocked by {tbl}".format(tbl=dup['tbl'])
            sys.exit(1)

        # We should be safe to create the new db and rename
        if not dry_run:
            mysql_lib.create_db(conn, renamed_db)
        mysql_lib.move_db_contents(conn=conn,
                                   old_db=db,
                                   new_db=renamed_db,
                                   verbose=verbose,
                                   dry_run=dry_run)
def mysql_init_server(instance,
                      skip_production_check=False,
                      skip_backup=True,
                      lock_handle=None):
    """ Remove any data and initialize a MySQL instance

    Args:
    instance - A hostaddr object pointing towards localhost to act upon
    skip_production_check - Dangerous! will not run safety checks to protect
                            production data
    skip_backup - Don't run a backup after the instance is setup
    lock_handle - If the caller already locked the system, pass in the
                  lock handle, as we may need to release and reacquire
                  to prevent mysqld from keeping it.
    """
    if lock_handle is None:
        # Take a lock to prevent multiple restores from running concurrently
        log.info('Taking a lock to block race conditions')
        lock_handle = host_utils.bind_lock_socket(
            backup.STD_BACKUP_LOCK_SOCKET)
    else:
        log.info('Lock already exists from caller.')

    try:
        # sanity check
        zk = host_utils.MysqlZookeeper()
        if (not skip_production_check
                and instance in zk.get_all_mysql_instances()):
            raise Exception("It appears {instance} is in use. This is"
                            " very dangerous!".format(instance=instance))

        log.info('Checking host for mounts, etc...')
        basic_host_sanity()

        log.info('(re)Generating MySQL cnf files')
        mysql_cnf_builder.build_cnf()

        log.info('Creating any missing directories')
        create_and_chown_dirs(instance.port)

        log.info('Shutting down MySQL (if applicable)')
        host_utils.stop_mysql(instance.port)

        log.info('Deleting existing MySQL data')
        delete_mysql_data(instance.port)

        log.info('Creating MySQL privileges tables')
        init_privileges_tables(instance.port)

        log.info('Clearing innodb log files')
        delete_innodb_log_files(instance.port)

        log.info('Starting up instance')
        host_utils.start_mysql(instance.port)

        log.info('Importing MySQL users')
        mysql_grants.manage_mysql_grants(instance, 'nuke_then_import')

        log.info('Creating test database')
        mysql_lib.create_db(instance, 'test')

        log.info('Setting up query response time plugins')
        mysql_lib.setup_response_time_metrics(instance)

        log.info('Setting up semi-sync replication plugins')
        mysql_lib.setup_semisync_plugins(instance)

        log.info('Setting up audit log plugin')
        mysql_lib.setup_audit_plugin(instance)

        log.info('Restarting pt daemons')
        host_utils.manage_pt_daemons(instance.port)

        log.info('MySQL initalization complete')

    finally:
        # We have to do this, ugly though it may be, to ensure that
        # the running MySQL process doesn't maintain a hold on the lock
        # socket after the script exits.  We reacquire the lock after
        # the restart and pass it back to the caller.
        #
        if lock_handle:
            log.info('Restarting MySQL, releasing lock.')
            host_utils.stop_mysql(instance.port)
            log.info('Sleeping 5 seconds.')
            time.sleep(5)
            host_utils.release_lock_socket(lock_handle)
            host_utils.start_mysql(instance.port)
            log.info('Reacquiring lock.')
            lock_handle = host_utils.bind_lock_socket(
                backup.STD_BACKUP_LOCK_SOCKET)

    if not skip_backup:
        log.info('Taking a backup')
        mysql_backup.mysql_backup(instance,
                                  initial_build=True,
                                  lock_handle=lock_handle)

    return lock_handle
Example #4
0
def mysql_init_server(instance,
                      skip_production_check=False,
                      skip_locking=False,
                      skip_backup=True):
    """ Remove any data and initialize a MySQL instance

    Args:
    instance - A hostaddr object pointing towards localhost to act upon
    skip_production_check - Dangerous! will not run safety checks to protect
                            production data
    skip_locking - Do not take a lock on localhost. Useful when the caller has
                   already has taken the lock (ie mysql_restore_xtrabackup)
    skip_backup - Don't run a backup after the instance is setup
    """
    lock_handle = None
    if not skip_locking:
        # Take a lock to prevent multiple restores from running concurrently
        log.info('Taking a flock to block race conditions')
        lock_handle = host_utils.take_flock_lock(backup.BACKUP_LOCK_FILE)

    try:
        # sanity check
        zk = host_utils.MysqlZookeeper()
        if (not skip_production_check
                and instance in zk.get_all_mysql_instances()):
            raise Exception("It appears {instance} is in use. This is"
                            " very dangerous!".format(instance=instance))

        log.info('Checking host for mounts, etc...')
        basic_host_sanity()

        log.info('(re)Generating MySQL cnf files')
        mysql_cnf_builder.build_cnf()

        log.info('Creating any missing directories')
        create_and_chown_dirs(instance.port)

        log.info('Shutting down MySQL (if applicable)')
        host_utils.stop_mysql(instance.port)

        log.info('Deleting existing MySQL data')
        delete_mysql_data(instance.port)

        log.info('Creating MySQL privileges tables')
        init_privileges_tables(instance.port)

        log.info('Clearing innodb log files')
        delete_innodb_log_files(instance.port)

        log.info('Starting up instance')
        host_utils.start_mysql(instance.port)

        log.info('Importing MySQL users')
        mysql_grants.manage_mysql_grants(instance, 'nuke_then_import')

        log.info('Creating test database')
        mysql_lib.create_db(instance, 'test')

        log.info('Setting up query response time plugins')
        mysql_lib.setup_response_time_metrics(instance)

        log.info('Setting up semi-sync replication plugins')
        mysql_lib.setup_semisync_plugins(instance)

        log.info('Restarting pt daemons')
        host_utils.restart_pt_daemons(instance.port)

        log.info('MySQL initalization complete')

    finally:
        if not skip_locking and lock_handle:
            log.info('Releasing lock')
            host_utils.release_flock_lock(lock_handle)

    if not skip_backup:
        log.info('Taking a backup')
        mysql_backup.mysql_backup(instance)
def mysql_init_server(instance,
                      skip_production_check=False, skip_locking=False,
                      skip_backup=True):
    """ Remove any data and initialize a MySQL instance

    Args:
    instance - A hostaddr object pointing towards localhost to act upon
    skip_production_check - Dangerous! will not run safety checks to protect
                            production data
    skip_locking - Do not take a lock on localhost. Useful when the caller has
                   already has taken the lock (ie mysql_restore_xtrabackup)
    skip_backup - Don't run a backup after the instance is setup
    """
    lock_handle = None
    if not skip_locking:
        # Take a lock to prevent multiple restores from running concurrently
        log.info('Taking a flock to block race conditions')
        lock_handle = host_utils.take_flock_lock(backup.BACKUP_LOCK_FILE)

    try:
        # sanity check
        zk = host_utils.MysqlZookeeper()
        if (not skip_production_check and
                instance in zk.get_all_mysql_instances()):
            raise Exception("It appears {instance} is in use. This is"
                            " very dangerous!".format(instance=instance))

        log.info('Checking host for mounts, etc...')
        basic_host_sanity()

        log.info('(re)Generating MySQL cnf files')
        mysql_cnf_builder.build_cnf()

        log.info('Creating any missing directories')
        create_and_chown_dirs(instance.port)

        log.info('Shutting down MySQL (if applicable)')
        host_utils.stop_mysql(instance.port)

        log.info('Deleting existing MySQL data')
        delete_mysql_data(instance.port)

        log.info('Creating MySQL privileges tables')
        init_privileges_tables(instance.port)

        log.info('Clearing innodb log files')
        delete_innodb_log_files(instance.port)

        log.info('Starting up instance')
        host_utils.start_mysql(instance.port)

        log.info('Importing MySQL users')
        mysql_grants.manage_mysql_grants(instance, 'nuke_then_import')

        log.info('Creating test database')
        conn = mysql_lib.connect_mysql(instance)
        mysql_lib.create_db(conn, 'test')

        log.info('Setting up query response time plugins')
        mysql_lib.setup_response_time_metrics(instance)

        log.info('Setting up semi-sync replication plugins')
        mysql_lib.setup_semisync_plugins(instance)

        log.info('Restarting pt daemons')
        host_utils.restart_pt_daemons(instance.port)

        log.info('MySQL initalization complete')

    finally:
        if not skip_locking and lock_handle:
            log.info('Releasing lock')
            host_utils.release_flock_lock(lock_handle)

    if not skip_backup:
        log.info('Taking a backup')
        mysql_backup.mysql_backup(instance)
Example #6
0
def rename_db_to_drop(instance, dbs=None, dry_run=False, skip_check=False):
    """ Create a new empty db and move the contents of the original db
        into it

    Args:
        instance - a hostaddr object
        dbs -  a set of database names
        dry_run - bool, will make no changes to anything
        skip_check - Do not verify that db is not in production
    """

    orphaned, _, _ = find_shard_mismatches.find_shard_mismatches(instance)
    if not dbs:
        if instance not in orphaned:
            log.info("No orphaned shards, returning now.")
            return

        dbs = orphaned[instance]
        log.info('Detected orphaned shareds: {}'.format(dbs))

    if not skip_check:
        # confirm db is not in ZK and not in use.
        if not orphaned:
            log.info("No orphans detected, returning now.")
            return

        instance_orphans = orphaned[instance]
        unexpected = dbs.difference(instance_orphans)
        if unexpected:
            raise Exception('Cowardly refusing to act on the following'
                            'dbs: {}'.format(unexpected))

    # confirm that renames would not be blocked by an existing table
    conn = mysql_lib.connect_mysql(instance)

    cursor = conn.cursor()
    for db in dbs:
        # already dealt with
        if db.startswith(DB_PREPEND):
            continue

        renamed_db = ''.join((DB_PREPEND, db))
        sql = ''.join(("SELECT CONCAT(t2.TABLE_SCHEMA, \n",
                       "              '.', t2.TABLE_NAME) as tbl \n",
                       "FROM information_schema.tables t1 \n",
                       "INNER JOIN information_schema.tables t2 \n",
                       "    USING(TABLE_NAME) \n",
                       "WHERE t1.TABLE_SCHEMA = %(old_db)s AND \n"
                       "      t2.TABLE_SCHEMA = %(new_db)s;"))

        params = {'old_db': db, 'new_db': renamed_db}
        cursor = conn.cursor()
        cursor.execute(sql, params)
        dups = cursor.fetchall()

        if dups:
            for dup in dups:
                log.error('Table rename blocked by {}'.format(dup['tbl']))
            sys.exit(1)

        # We should be safe to create the new db and rename
        if not dry_run:
            mysql_lib.create_db(instance, renamed_db)
        mysql_lib.move_db_contents(instance,
                                   old_db=db,
                                   new_db=renamed_db,
                                   dry_run=dry_run)

        if dbs and not dry_run:
            log.info('To finish cleanup, wait a bit and then run:')
            log.info('/usr/local/bin/mysql_utils/fix_orphaned_shards.py -a'
                     'drop -i {}'.format(instance))