Beispiel #1
0
    def test_sync_backup_no_tablespaces(self, rsync_mock, tmpdir):
        """
        Verify that sync_backup works if no tablespaces are present.
        """
        # GIVEN a backup for server 'main'
        backup_name = "1234567890"
        server_name = "main"

        # WITH a minimal set of files on disk
        backup_dir = tmpdir.mkdir(server_name)
        primary_info_content = self._create_primary_info_file(
            tmpdir, backup_dir, tablespaces=False
        )

        # AND a primary server
        server = build_real_server(
            global_conf={"barman_lock_directory": tmpdir.strpath},
            main_conf={
                "backup_directory": backup_dir.strpath,
                "primary_ssh_command": "ssh fakeuser@fakehost",
            },
        )

        # WHEN sync_backup is called for the backup
        server.sync_backup(backup_name)

        # THEN the data directory of that backup is added to the copy controller
        copy_controller = rsync_mock.return_value
        copy_controller.add_directory.assert_called_once()
        assert "basebackup" == copy_controller.add_directory.call_args_list[0][0][0]
        assert (
            ":%s/%s/"
            % (primary_info_content["config"]["basebackups_directory"], backup_name)
            == copy_controller.add_directory.call_args_list[0][0][1]
        )
Beispiel #2
0
    def test_sync_backup_tablespaces(self, rsync_mock, tmpdir):
        """
        Verify that the top level tablespaces are synced but symlinks in pg_tblspc are
        not.
        """
        # GIVEN a backup for server 'main'
        backup_name = "1234567890"
        server_name = "main"

        # WITH a minimal set of files on disk
        backup_dir = tmpdir.mkdir(server_name)
        primary_info_content = self._create_primary_info_file(tmpdir, backup_dir)

        # AND a primary server
        server = build_real_server(
            global_conf={"barman_lock_directory": tmpdir.strpath},
            main_conf={
                "backup_directory": backup_dir.strpath,
                "primary_ssh_command": "ssh fakeuser@fakehost",
            },
        )

        # WHEN sync_backup is called for the backup
        server.sync_backup(backup_name)

        # THEN the data directory of that backup is added to the copy controller
        copy_controller = rsync_mock.return_value
        copy_controller.add_directory.assert_called_once()
        assert "basebackup" == copy_controller.add_directory.call_args_list[0][0][0]
        assert (
            ":%s/%s/"
            % (primary_info_content["config"]["basebackups_directory"], backup_name)
            == copy_controller.add_directory.call_args_list[0][0][1]
        )

        # AND the tablespace symlinks in /data/pg_tblspc are excluded along with
        # the /backup.info and /.backup.lock files AND no other files or directories
        # are excluded
        expected_excludes = [
            "/data/pg_tblspc/16387",
            "/data/pg_tblspc/16405",
            "/backup.info",
            "/.backup.lock",
        ]
        assert set(expected_excludes) == set(
            copy_controller.add_directory.call_args_list[0][1]["exclude_and_protect"]
        )
Beispiel #3
0
    def test_sync_backup(self, logger_mock, rsync_mock, tmpdir, capsys):
        """
        Test the synchronisation method, testing all
        the possible error conditions.

        :param MagicMock logger_mock: MagicMock obj mimicking the logger
        :param MagicMock rsync_mock: MagicMock replacing Rsync class
        :param py.local.path tmpdir: py.test temporary directory
        :param capsys: fixture that allow to access stdout/stderr output
        """
        backup_name = '1234567890'
        server_name = 'main'

        # Prepare paths
        backup_dir = tmpdir.mkdir(server_name)
        basebackup_dir = backup_dir.mkdir("base")
        full_backup_path = basebackup_dir.mkdir(backup_name)
        primary_info_file = backup_dir.join(barman.server.PRIMARY_INFO_FILE)

        # prepare the primary_info file
        remote_basebackup_dir = tmpdir.mkdir("primary")
        primary_info_content = dict(EXPECTED_MINIMAL)
        primary_info_content['config'].update(
            basebackups_directory=str(remote_basebackup_dir))
        primary_info_file.write(json.dumps(primary_info_content))

        # Test 1: Not a passive node.
        # Expect SyncError
        server = build_real_server(
            global_conf={'barman_lock_directory': tmpdir.strpath},
            main_conf={'backup_directory': backup_dir.strpath})
        with pytest.raises(SyncError):
            server.sync_backup(backup_name)

        # Test 2: normal sync execution, no error expected.
        # test for all the step on the logger
        logger_mock.reset_mock()
        server = build_real_server(
            global_conf={'barman_lock_directory': tmpdir.strpath},
            main_conf={
                'backup_directory': backup_dir.strpath,
                'primary_ssh_command': 'ssh fakeuser@fakehost'
            })
        server.sync_backup(backup_name)
        logger_mock.info.assert_any_call(
            "Synchronising with server %s backup %s: step 1/3: "
            "parse server information", server_name, backup_name)
        logger_mock.info.assert_any_call(
            "Synchronising with server %s backup %s: step 2/3: "
            "file copy", server_name, backup_name)
        logger_mock.info.assert_any_call(
            "Synchronising with server %s backup %s: step 3/3: "
            "finalise sync", server_name, backup_name)

        # Test 3: test Rsync Failure
        # Expect a BackupInfo object with status "FAILED"
        # and a error message on the "error" field of the obj
        rsync_mock.reset_mock()
        server.backup_manager._backup_cache = {}
        rsync_mock.side_effect = CommandFailedException("TestFailure")
        full_backup_path.remove(rec=1)
        server.sync_backup(backup_name)
        backup_info = server.get_backup(backup_name)
        assert backup_info.status == BackupInfo.FAILED
        assert backup_info.error == 'failure syncing server main ' \
                                    'backup 1234567890: TestFailure'

        # Test 4: test KeyboardInterrupt management
        # Check the error message for the KeyboardInterrupt event
        rsync_mock.reset_mock()
        rsync_mock.side_effect = CommandFailedException("TestFailure")
        full_backup_path.remove(rec=1)
        rsync_mock.side_effect = KeyboardInterrupt()
        server.sync_backup(backup_name)
        backup_info = server.get_backup(backup_name)
        assert backup_info.status == BackupInfo.FAILED
        assert backup_info.error == 'failure syncing server main ' \
                                    'backup 1234567890: KeyboardInterrupt'

        # Test 5: test backup name not present on Master server
        # Expect a error message on stderr
        rsync_mock.reset_mock()
        rsync_mock.side_effect = CommandFailedException("TestFailure")
        full_backup_path.remove(rec=1)
        server.sync_backup('wrong_backup_name')

        (out, err) = capsys.readouterr()
        # Check the stderr using capsys. we need only the first line
        # from stderr
        e = err.split('\n')
        assert 'ERROR: failure syncing server main ' \
               'backup 1234567890: TestFailure' in e

        # Test 5: Backup already synced
        # Check for the warning message on the stout using capsys
        rsync_mock.reset_mock()
        rsync_mock.side_effect = None
        # do it the first time and check it succeeded
        server.sync_backup(backup_name)
        backup_info = server.get_backup(backup_name)
        assert backup_info.status == BackupInfo.DONE
        # do it again ant test it does not call rsync
        rsync_mock.reset_mock()
        server.sync_backup(backup_name)
        assert not rsync_mock.called
        (out, err) = capsys.readouterr()
        assert out.strip() == 'Backup 1234567890 is already' \
                              ' synced with main server'
Beispiel #4
0
    def test_sync_backup(self, logger_mock, rsync_mock, tmpdir, capsys):
        """
        Test the synchronisation method, testing all
        the possible error conditions.

        :param MagicMock logger_mock: MagicMock obj mimicking the logger
        :param MagicMock rsync_mock: MagicMock replacing Rsync class
        :param py.local.path tmpdir: py.test temporary directory
        :param capsys: fixture that allow to access stdout/stderr output
        """
        backup_name = "1234567890"
        server_name = "main"

        # Prepare paths
        backup_dir = tmpdir.mkdir(server_name)
        basebackup_dir = backup_dir.mkdir("base")
        full_backup_path = basebackup_dir.mkdir(backup_name)

        self._create_primary_info_file(tmpdir, backup_dir)

        # Test 1: Not a passive node.
        # Expect SyncError
        server = build_real_server(
            global_conf={"barman_lock_directory": tmpdir.strpath},
            main_conf={"backup_directory": backup_dir.strpath},
        )
        with pytest.raises(SyncError):
            server.sync_backup(backup_name)

        # Test 2: normal sync execution, no error expected.
        # test for all the step on the logger
        logger_mock.reset_mock()
        server = build_real_server(
            global_conf={"barman_lock_directory": tmpdir.strpath},
            main_conf={
                "backup_directory": backup_dir.strpath,
                "primary_ssh_command": "ssh fakeuser@fakehost",
            },
        )
        server.sync_backup(backup_name)
        logger_mock.info.assert_any_call(
            "Synchronising with server %s backup %s: step 1/3: "
            "parse server information",
            server_name,
            backup_name,
        )
        logger_mock.info.assert_any_call(
            "Synchronising with server %s backup %s: step 2/3: file copy",
            server_name,
            backup_name,
        )
        logger_mock.info.assert_any_call(
            "Synchronising with server %s backup %s: step 3/3: finalise sync",
            server_name,
            backup_name,
        )

        # Test 3: test Rsync Failure
        # Expect a BackupInfo object with status "FAILED"
        # and a error message on the "error" field of the obj
        rsync_mock.reset_mock()
        server.backup_manager._backup_cache = {}
        rsync_mock.side_effect = CommandFailedException("TestFailure")
        full_backup_path.remove(rec=1)
        server.sync_backup(backup_name)
        backup_info = server.get_backup(backup_name)
        assert backup_info.status == BackupInfo.FAILED
        assert (
            backup_info.error == "failure syncing server main "
            "backup 1234567890: TestFailure"
        )

        # Test 4: test KeyboardInterrupt management
        # Check the error message for the KeyboardInterrupt event
        rsync_mock.reset_mock()
        rsync_mock.side_effect = CommandFailedException("TestFailure")
        full_backup_path.remove(rec=1)
        rsync_mock.side_effect = KeyboardInterrupt()
        server.sync_backup(backup_name)
        backup_info = server.get_backup(backup_name)
        assert backup_info.status == BackupInfo.FAILED
        assert (
            backup_info.error == "failure syncing server main "
            "backup 1234567890: KeyboardInterrupt"
        )

        # Test 5: test backup name not present on Master server
        # Expect a error message on stderr
        rsync_mock.reset_mock()
        rsync_mock.side_effect = CommandFailedException("TestFailure")
        full_backup_path.remove(rec=1)
        server.sync_backup("wrong_backup_name")

        (out, err) = capsys.readouterr()
        # Check the stderr using capsys. we need only the first line
        # from stderr
        e = err.split("\n")
        assert "ERROR: failure syncing server main backup 1234567890: TestFailure" in e

        # Test 5: Backup already synced
        # Check for the warning message on the stout using capsys
        rsync_mock.reset_mock()
        rsync_mock.side_effect = None
        # do it the first time and check it succeeded
        server.sync_backup(backup_name)
        backup_info = server.get_backup(backup_name)
        assert backup_info.status == BackupInfo.DONE
        # do it again ant test it does not call rsync
        rsync_mock.reset_mock()
        server.sync_backup(backup_name)
        assert not rsync_mock.called
        (out, err) = capsys.readouterr()
        assert out.strip() == "Backup 1234567890 is already synced with main server"