def test_get_latest_backup(raw_binlog_status): instance = BinlogStatus(raw_binlog_status) assert instance.get_latest_backup() == BinlogCopy( host='master1', name='mysqlbin005.bin', created_at=100504 )
def test_serialize_doesnt_change_orignal(raw_binlog_status): status_original = BinlogStatus(content=raw_binlog_status) status_original_before = deepcopy(status_original) assert status_original == status_original_before status_original.serialize() assert status_original == status_original_before
def test_remove_existing_copy(raw_binlog_status): instance = BinlogStatus(raw_binlog_status) copy = BinlogCopy(host='master1', name='mysqlbin001.bin', created_at=100500) assert copy in instance instance.remove("master1/binlog/mysqlbin001.bin") assert copy not in instance
def test_remove_existing_copy(raw_binlog_status): instance = BinlogStatus(raw_binlog_status) copy = BinlogCopy( host='master1', name='mysqlbin001.bin', created_at=100500 ) assert copy in instance instance.remove("master1/binlog/mysqlbin001.bin") assert copy not in instance
def backup_binlogs(run_type, config): # pylint: disable=too-many-locals """Copy MySQL binlog files to the backup destination. :param run_type: Run type :type run_type: str :param config: Tool configuration :type config: TwinDBBackupConfig """ if config.mysql is None: LOG.debug("No MySQL config, not copying binlogs") return dst = config.destination() status = BinlogStatus(dst=dst) mysql_client = MySQLClient(defaults_file=config.mysql.defaults_file) # last_copy = status.latest_backup LOG.debug("Latest copied binlog %s", status.latest_backup) with mysql_client.cursor() as cur: cur.execute("FLUSH BINARY LOGS") backup_set = binlogs_to_backup( cur, last_binlog=status.latest_backup.name if status.latest_backup else None, ) cur.execute("SELECT @@log_bin_basename") row = cur.fetchone() if row["@@log_bin_basename"]: binlog_dir = osp.dirname(row["@@log_bin_basename"]) else: return for binlog_name in backup_set: src = BinlogSource(run_type, mysql_client, binlog_name) binlog_copy = BinlogCopy( src.host, binlog_name, BinlogParser(osp.join(binlog_dir, binlog_name)).created_at, ) _backup_stream(config, src, dst) status.add(binlog_copy) try: expire_log_days = config.mysql.expire_log_days except (configparser.NoSectionError, configparser.NoOptionError): expire_log_days = 7 for copy in status: now = int(time.time()) LOG.debug("Reviewing copy %s. Now: %d", copy, now) if copy.created_at < now - expire_log_days * 24 * 3600: LOG.debug( "Deleting copy that was taken %d seconds ago", now - copy.created_at, ) dst.delete(copy.key + ".gz") status.remove(copy.key) status.save(dst)
def test_add_to_empty_status(): instance = BinlogStatus() instance.add(BinlogCopy("host", "foo/bar", 100500)) assert BinlogCopy("host", "foo/bar", 100500) in instance instance.add(BinlogCopy("host", "foo/bar-2", 100501)) assert BinlogCopy("host", "foo/bar", 100500) in instance assert BinlogCopy("host", "foo/bar-2", 100501) in instance
def test_load(status_json, copies): status = BinlogStatus() assert status._load(status_json) == copies
def test_remove_non_existing_copy(raw_binlog_status): instance = BinlogStatus(raw_binlog_status) with pytest.raises(StatusKeyNotFound): instance.remove("foo")
def test_ne(raw_binlog_status): status_1 = BinlogStatus(raw_binlog_status) status_2 = BinlogStatus() assert status_1 != status_2
def test_get_item_not_existing_copy(raw_binlog_status): instance = BinlogStatus(raw_binlog_status) with pytest.raises(StatusKeyNotFound): # noinspection PyStatementEffect instance["foo/bar"]
def test_eq(raw_binlog_status): status_1 = BinlogStatus(raw_binlog_status) status_2 = BinlogStatus(raw_binlog_status) assert status_1 == status_2
def test_init_not_empty(raw_binlog_status): instance = BinlogStatus(raw_binlog_status) assert instance.version == 1 assert len(instance) == 5
def test_init_empty(): instance = BinlogStatus() assert len(instance) == 0
def test_get_item_existing_copy(raw_binlog_status): instance = BinlogStatus(raw_binlog_status) copy = instance["master1/binlog/mysqlbin001.bin"] assert copy is not None
def test_serialize(raw_binlog_status): status_original = BinlogStatus(raw_binlog_status) status_converted = status_original.serialize() assert BinlogStatus(content=status_converted) == status_original
def backup_binlogs(run_type, config): # pylint: disable=too-many-locals """Copy MySQL binlog files to the backup destination. :param run_type: Run type :type run_type: str :param config: Tool configuration :type config: TwinDBBackupConfig """ if config.mysql is None: LOG.debug('No MySQL config, not copying binlogs') return dst = config.destination() status = BinlogStatus(dst=dst) mysql_client = MySQLClient( defaults_file=config.mysql.defaults_file ) # last_copy = status.latest_backup LOG.debug('Latest copied binlog %s', status.latest_backup) with mysql_client.cursor() as cur: cur.execute("FLUSH BINARY LOGS") backup_set = binlogs_to_backup( cur, last_binlog=status.latest_backup.name if status.latest_backup else None ) cur.execute("SELECT @@log_bin_basename") row = cur.fetchone() binlog_dir = osp.dirname(row['@@log_bin_basename']) for binlog_name in backup_set: src = BinlogSource(run_type, mysql_client, binlog_name) binlog_copy = BinlogCopy( src.host, binlog_name, BinlogParser( osp.join( binlog_dir, binlog_name ) ).created_at ) _backup_stream(config, src, dst) status.add(binlog_copy) try: expire_log_days = config.mysql.expire_log_days except (ConfigParser.NoSectionError, ConfigParser.NoOptionError): expire_log_days = 7 for copy in status: now = int(time.time()) LOG.debug('Reviewing copy %s. Now: %d', copy, now) if copy.created_at < now - expire_log_days * 24 * 3600: LOG.debug( 'Deleting copy that was taken %d seconds ago', now - copy.created_at ) dst.delete(copy.key + ".gz") status.remove(copy.key) status.save(dst)
def test_init_restores_name(raw_binlog_status): status = BinlogStatus(raw_binlog_status) copy = status['master1/binlog/mysqlbin001.bin'] assert copy.name == 'mysqlbin001.bin'
def test_basename(): assert BinlogStatus().basename == 'binlog-status'