def restore_mysql(cfg, dst, backup_copy, cache): """Restore from mysql backup""" LOG.debug('mysql: %r', cfg) if not backup_copy: LOG.info('No backup copy specified. Choose one from below:') list_available_backups(cfg) exit(1) try: ensure_empty(dst) dst_storage = get_destination( cfg, get_hostname_from_backup_copy(backup_copy) ) key = dst_storage.basename(backup_copy) copy = dst_storage.status()[key] if cache: restore_from_mysql(cfg, copy, dst, cache=Cache(cache)) else: restore_from_mysql(cfg, copy, dst) except (TwinDBBackupError, CacheException) as err: LOG.error(err) exit(1) except (OSError, IOError) as err: LOG.error(err) exit(1)
def restore_file(cfg, dst, backup_copy): """Restore from file backup""" LOG.debug('file: %r', cfg) if not backup_copy: LOG.info('No backup copy specified. Choose one from below:') list_available_backups(cfg) exit(1) try: ensure_empty(dst) copy = FileCopy( get_hostname_from_backup_copy(backup_copy), basename(backup_copy), get_run_type_from_backup_copy(backup_copy) ) restore_from_file(cfg, copy, dst) except TwinDBBackupError as err: LOG.error(err) exit(1) except KeyboardInterrupt: LOG.info('Exiting...') kill_children() exit(1)
def test_get_hostname_from_backup_copy(name, host): assert get_hostname_from_backup_copy(name) == host
def restore_from_mysql(config, backup_copy, dst_dir, cache=None): """ Restore MySQL datadir in a given directory :param config: Tool configuration. :type config: ConfigParser.ConfigParser :param backup_copy: Backup copy name. :type backup_copy: str :param dst_dir: Destination directory. Must exist and be empty. :type dst_dir: str :param cache: Local cache object. :type cache: Cache """ LOG.info('Restoring %s in %s', backup_copy, dst_dir) mkdir_p(dst_dir) dst = None try: keep_local_path = config.get('destination', 'keep_local_path') if os.path.exists(backup_copy) \ and backup_copy.startswith(keep_local_path): dst = Local(keep_local_path) except ConfigParser.NoOptionError: pass if not dst: hostname = get_hostname_from_backup_copy(backup_copy) if not hostname: raise DestinationError('Failed to get hostname from %s' % backup_copy) dst = get_destination(config, hostname=hostname) key = dst.basename(backup_copy) status = dst.status() stream = dst.get_stream(backup_copy) if get_backup_type(status, key) == "full": cache_key = os.path.basename(key) if cache: if cache_key in cache: # restore from cache cache.restore_in(cache_key, dst_dir) else: restore_from_mysql_full(stream, dst_dir, config) cache.add(dst_dir, cache_key) else: restore_from_mysql_full(stream, dst_dir, config) else: full_copy = dst.get_full_copy_name(backup_copy) full_stream = dst.get_stream(full_copy) cache_key = os.path.basename(full_copy) if cache: if cache_key in cache: # restore from cache cache.restore_in(cache_key, dst_dir) else: restore_from_mysql_full(full_stream, dst_dir, config, redo_only=True) cache.add(dst_dir, cache_key) else: restore_from_mysql_full(full_stream, dst_dir, config, redo_only=True) restore_from_mysql_incremental(stream, dst_dir, config) config_dir = os.path.join(dst_dir, "_config") for path, content in get_my_cnf(status, key): config_sub_dir = os.path.join(config_dir, os.path.dirname(path).lstrip('/')) os.makedirs(config_sub_dir) with open(os.path.join(config_sub_dir, os.path.basename(path)), 'w') as mysql_config: mysql_config.write(content) update_grastate(dst_dir, status, key) LOG.info('Successfully restored %s in %s.', backup_copy, dst_dir) LOG.info('Now copy content of %s to MySQL datadir: ' 'cp -R %s/* /var/lib/mysql/', dst_dir, dst_dir) LOG.info('Fix permissions: chown -R mysql:mysql /var/lib/mysql/') LOG.info('Make sure innodb_log_file_size and innodb_log_files_in_group ' 'in %s/backup-my.cnf and in /etc/my.cnf are same.', dst_dir) if os.path.exists(config_dir): LOG.info('Original my.cnf is restored in %s.', config_dir) LOG.info('Then you can start MySQL normally.')
def restore_from_mysql(config, backup_copy, dst_dir, tmp_dir=None, cache=None): """ Restore MySQL datadir in a given directory :param config: Tool configuration. :type config: ConfigParser.ConfigParser :param backup_copy: Backup copy name. :type backup_copy: str :param dst_dir: Destination directory. Must exist and be empty. :type dst_dir: str :param tmp_dir: Path to temp directory :type tmp_dir: str :param cache: Local cache object. :type cache: Cache """ LOG.info('Restoring %s in %s', backup_copy, dst_dir) mkdir_p(dst_dir) dst = None restore_start = time.time() try: xtrabackup_binary = config.get('mysql', 'xtrabackup_binary') except ConfigParser.NoOptionError: xtrabackup_binary = XTRABACKUP_BINARY try: xbstream_binary = config.get('mysql', 'xbstream_binary') except ConfigParser.NoOptionError: xbstream_binary = XBSTREAM_BINARY try: keep_local_path = config.get('destination', 'keep_local_path') if os.path.exists(backup_copy) and \ backup_copy.startswith(keep_local_path): dst = Local(keep_local_path) except ConfigParser.NoOptionError: pass if not dst: hostname = get_hostname_from_backup_copy(backup_copy) if not hostname: raise DestinationError('Failed to get hostname from %s' % backup_copy) dst = get_destination(config, hostname=hostname) key = dst.basename(backup_copy) status = dst.status() stream = dst.get_stream(backup_copy) if status[key].type == "full": cache_key = os.path.basename(key) if cache: if cache_key in cache: # restore from cache cache.restore_in(cache_key, dst_dir) else: restore_from_mysql_full(stream, dst_dir, config, redo_only=False, xtrabackup_binary=xtrabackup_binary, xbstream_binary=xbstream_binary) cache.add(dst_dir, cache_key) else: restore_from_mysql_full(stream, dst_dir, config, redo_only=False, xtrabackup_binary=xtrabackup_binary, xbstream_binary=xbstream_binary) else: full_copy = status.eligble_parent( dst.get_run_type_from_full_path(backup_copy)) full_stream = dst.get_stream(full_copy.key) LOG.debug("Full parent copy is %s", full_copy.key) cache_key = os.path.basename(full_copy.key) if cache: if cache_key in cache: # restore from cache cache.restore_in(cache_key, dst_dir) else: restore_from_mysql_full(full_stream, dst_dir, config, redo_only=True, xtrabackup_binary=xtrabackup_binary, xbstream_binary=xbstream_binary) cache.add(dst_dir, cache_key) else: restore_from_mysql_full(full_stream, dst_dir, config, redo_only=True, xtrabackup_binary=xtrabackup_binary, xbstream_binary=xbstream_binary) restore_from_mysql_incremental(stream, dst_dir, config, tmp_dir, xtrabackup_binary=xtrabackup_binary, xbstream_binary=xbstream_binary) config_dir = os.path.join(dst_dir, "_config") for path, content in get_my_cnf(status, key): config_sub_dir = os.path.join(config_dir, os.path.dirname(path).lstrip('/')) os.makedirs(config_sub_dir) with open(os.path.join(config_sub_dir, os.path.basename(path)), 'w') as mysql_config: mysql_config.write(content) update_grastate(dst_dir, status, key) export_info(config, data=time.time() - restore_start, category=ExportCategory.mysql, measure_type=ExportMeasureType.restore) LOG.info('Successfully restored %s in %s.', backup_copy, dst_dir) LOG.info( 'Now copy content of %s to MySQL datadir: ' 'cp -R %s/* /var/lib/mysql/', dst_dir, dst_dir) LOG.info('Fix permissions: chown -R mysql:mysql /var/lib/mysql/') LOG.info( 'Make sure innodb_log_file_size and innodb_log_files_in_group ' 'in %s/backup-my.cnf and in /etc/my.cnf are same.', dst_dir) if os.path.exists(config_dir): LOG.info('Original my.cnf is restored in %s.', config_dir) LOG.info('Then you can start MySQL normally.')