def test_recover_waiting_for_wals(self, backup_info_mock,
                                      rsync_copy_controller_mock,
                                      output_mock,
                                      rsync_pgdata_mock,
                                      unix_remote_command_mock, tmpdir):

        # This backup is waiting for WALs and it remains in that status
        # even after having copied the data files
        backup_info_mock.WAITING_FOR_WALS = "WAITING_FOR_WALS"
        backup_info_mock.return_value.status = BackupInfo.WAITING_FOR_WALS
        backup_info = testing_helpers.build_test_backup_info()
        backup_manager = testing_helpers.build_backup_manager()
        executor = RecoveryExecutor(backup_manager)
        backup_info.status = BackupInfo.WAITING_FOR_WALS
        destination = tmpdir.mkdir('destination').strpath
        with closing(executor):
            executor.recover(backup_info, destination, standby_mode=None)

        # The backup info has been read again
        backup_info_mock.assert_called()

        # The following two warning messages have been emitted
        output_mock.warning.assert_has_calls([
            mock.call(
                "IMPORTANT: You have requested a recovery operation for "
                "a backup that does not have yet all the WAL files that "
                "are required for consistency."),
            mock.call(
                "IMPORTANT: The backup we have recovered IS NOT "
                "VALID. Required WAL files for consistency are "
                "missing. Please verify that WAL archiving is "
                "working correctly or evaluate using the 'get-wal' "
                "option for recovery")])

        # In the following test case, the backup will be validated during
        # the copy of the data files, so there is no need for the warning
        # message at the end of the recovery process to be emitted again
        output_mock.warning.reset_mock()
        backup_info_mock.return_value.status = BackupInfo.DONE
        with closing(executor):
            executor.recover(backup_info, destination, standby_mode=None)

        # The backup info has been read again
        backup_info_mock.assert_called()

        # The following two warning messages have been emitted
        output_mock.warning.assert_has_calls([
            mock.call(
                "IMPORTANT: You have requested a recovery operation for "
                "a backup that does not have yet all the WAL files that "
                "are required for consistency.")])
Beispiel #2
0
    def recover(self, backup_info, dest, tablespaces=None, target_tli=None,
                target_time=None, target_xid=None, target_name=None,
                exclusive=False, remote_command=None):
        """
        Performs a recovery of a backup

        :param barman.infofile.BackupInfo backup_info: the backup to recover
        :param str dest: the destination directory
        :param dict[str,str]|None tablespaces: a tablespace name -> location map
            (for relocation)
        :param str|None target_tli: the target timeline
        :param str|None target_time: the target time
        :param str|None target_xid: the target xid
        :param str|None target_name: the target name created previously with
                            pg_create_restore_point() function call
        :param bool exclusive: whether the recovery is exclusive or not
        :param str|None remote_command: default None. The remote command to recover
                               the base backup, in case of remote backup.
        """

        # Archive every WAL files in the incoming directory of the server
        self.server.archive_wal(verbose=False)
        # Delegate the recovery operation to a RecoveryExecutor object
        executor = RecoveryExecutor(self)
        recovery_info = executor.recover(backup_info,
                                         dest, tablespaces,
                                         target_tli, target_time,
                                         target_xid, target_name,
                                         exclusive, remote_command)

        # Output recovery results
        output.result('recovery', recovery_info['results'])
Beispiel #3
0
    def recover(self, backup_info, dest, tablespaces=None, target_tli=None,
                target_time=None, target_xid=None, target_name=None,
                exclusive=False, remote_command=None):
        """
        Performs a recovery of a backup

        :param barman.infofile.BackupInfo backup_info: the backup to recover
        :param str dest: the destination directory
        :param dict[str,str]|None tablespaces: a tablespace name -> location
            map (for relocation)
        :param str|None target_tli: the target timeline
        :param str|None target_time: the target time
        :param str|None target_xid: the target xid
        :param str|None target_name: the target name created previously with
            pg_create_restore_point() function call
        :param bool exclusive: whether the recovery is exclusive or not
        :param str|None remote_command: default None. The remote command
            to recover the base backup, in case of remote backup.
        """

        # Archive every WAL files in the incoming directory of the server
        self.server.archive_wal(verbose=False)
        # Delegate the recovery operation to a RecoveryExecutor object
        executor = RecoveryExecutor(self)
        recovery_info = executor.recover(backup_info,
                                         dest, tablespaces,
                                         target_tli, target_time,
                                         target_xid, target_name,
                                         exclusive, remote_command)

        # Output recovery results
        output.result('recovery', recovery_info['results'])
    def test_recover_standby_mode(self, tmpdir):
        backup_info = testing_helpers.build_test_backup_info()
        backup_manager = testing_helpers.build_backup_manager()
        executor = RecoveryExecutor(backup_manager)
        backup_info.version = 90300
        destination = tmpdir.mkdir('destination').strpath

        # If standby mode is not enabled, recovery.conf is not generated
        executor._prepare_tablespaces = MagicMock()
        executor._backup_copy = MagicMock()
        executor._xlog_copy = MagicMock()
        executor._generate_recovery_conf = MagicMock()
        with closing(executor):
            executor.recover(backup_info, destination, standby_mode=None)
        executor._generate_recovery_conf.assert_not_called()

        # If standby mode is enabled, recovery.conf is generated
        executor._prepare_tablespaces.reset_mock()
        executor._backup_copy.reset_mock()
        executor._xlog_copy.reset_mock()
        executor._generate_recovery_conf.reset_mock()
        with closing(executor):
            executor.recover(backup_info, destination, standby_mode=True)
        executor._generate_recovery_conf.assert_called()

        # If standby mode is passed but PostgreSQL is older than 9.0,
        # we must raise an exception
        backup_info.version = 80000
        with pytest.raises(RecoveryStandbyModeException):
            with closing(executor):
                executor.recover(backup_info, destination, standby_mode=True)
 def test_recovery(self, remote_cmd_mock, rsync_pg_mock, tmpdir):
     """
     Test the execution of a recovery
     """
     # Prepare basic directory/files structure
     dest = tmpdir.mkdir('destination')
     base = tmpdir.mkdir('base')
     wals = tmpdir.mkdir('wals')
     backup_info = testing_helpers.build_test_backup_info(tablespaces=[])
     backup_info.config.basebackups_directory = base.strpath
     backup_info.config.wals_directory = wals.strpath
     backup_info.version = 90400
     datadir = base.mkdir(backup_info.backup_id).mkdir('data')
     backup_info.pgdata = datadir.strpath
     postgresql_conf_local = datadir.join('postgresql.conf')
     postgresql_auto_local = datadir.join('postgresql.auto.conf')
     postgresql_conf_local.write('archive_command = something\n'
                                 'data_directory = something')
     postgresql_auto_local.write('archive_command = something\n'
                                 'data_directory = something')
     shutil.copy2(postgresql_conf_local.strpath, dest.strpath)
     shutil.copy2(postgresql_auto_local.strpath, dest.strpath)
     # Build an executor
     server = testing_helpers.build_real_server(
         global_conf={
             "barman_lock_directory": tmpdir.mkdir('lock').strpath
         },
         main_conf={
             "wals_directory": wals.strpath
         })
     executor = RecoveryExecutor(server.backup_manager)
     # test local recovery
     rec_info = executor.recover(backup_info, dest.strpath, None, None,
                                 None, None, None, True, None)
     # remove not usefull keys from the result
     del rec_info['cmd']
     sys_tempdir = rec_info['tempdir']
     assert rec_info == {
         'rsync': None,
         'tempdir': sys_tempdir,
         'wal_dest': dest.join('pg_xlog').strpath,
         'recovery_dest': 'local',
         'destination_path': dest.strpath,
         'temporary_configuration_files': [
             dest.join('postgresql.conf').strpath,
             dest.join('postgresql.auto.conf').strpath],
         'results': {
             'delete_barman_xlog': False,
             'get_wal': False,
             'changes': [
                 Assertion._make([
                     'postgresql.conf',
                     0,
                     'archive_command',
                     'false']),
                 Assertion._make([
                     'postgresql.auto.conf',
                     0,
                     'archive_command',
                     'false'])],
             'warnings': [
                 Assertion._make([
                     'postgresql.conf',
                     2,
                     'data_directory',
                     'something']),
                 Assertion._make([
                     'postgresql.auto.conf',
                     2,
                     'data_directory',
                     'something'])]},
         'target_epoch': None,
         'configuration_files': [
             'postgresql.conf',
             'postgresql.auto.conf'],
         'target_datetime': None,
         'safe_horizon': None,
         'is_pitr': False,
         'get_wal': False,
     }
     # test remote recovery
     rec_info = executor.recover(backup_info, dest.strpath, {}, None, None,
                                 None, None, True, "remote@command")
     # remove not usefull keys from the result
     del rec_info['cmd']
     del rec_info['rsync']
     sys_tempdir = rec_info['tempdir']
     assert rec_info == {
         'tempdir': sys_tempdir,
         'wal_dest': dest.join('pg_xlog').strpath,
         'recovery_dest': 'remote',
         'destination_path': dest.strpath,
         'temporary_configuration_files': [
             os.path.join(sys_tempdir, 'postgresql.conf'),
             os.path.join(sys_tempdir, 'postgresql.auto.conf')],
         'results': {
             'delete_barman_xlog': False,
             'get_wal': False,
             'changes': [
                 Assertion._make([
                     'postgresql.conf',
                     0,
                     'archive_command',
                     'false']),
                 Assertion._make([
                     'postgresql.auto.conf',
                     0,
                     'archive_command',
                     'false'])],
             'warnings': [
                 Assertion._make([
                     'postgresql.conf',
                     2,
                     'data_directory',
                     'something']),
                 Assertion._make([
                     'postgresql.auto.conf',
                     2,
                     'data_directory',
                     'something'])]},
         'target_epoch': None,
         'configuration_files': [
             'postgresql.conf',
             'postgresql.auto.conf'],
         'target_datetime': None,
         'safe_horizon': None,
         'is_pitr': False,
         'get_wal': False,
     }
     # test failed rsync
     rsync_pg_mock.side_effect = CommandFailedException()
     with pytest.raises(CommandFailedException):
         executor.recover(backup_info, dest.strpath, {}, None, None, None,
                          None, True, "remote@command")
Beispiel #6
0
 def test_recovery(self, remote_cmd_mock, rsync_pg_mock,
                   copy_controller_mock, tmpdir):
     """
     Test the execution of a recovery
     """
     # Prepare basic directory/files structure
     dest = tmpdir.mkdir('destination')
     base = tmpdir.mkdir('base')
     wals = tmpdir.mkdir('wals')
     backup_info = testing_helpers.build_test_backup_info(tablespaces=[])
     backup_info.config.basebackups_directory = base.strpath
     backup_info.config.wals_directory = wals.strpath
     backup_info.version = 90400
     datadir = base.mkdir(backup_info.backup_id).mkdir('data')
     backup_info.pgdata = datadir.strpath
     postgresql_conf_local = datadir.join('postgresql.conf')
     postgresql_auto_local = datadir.join('postgresql.auto.conf')
     postgresql_conf_local.write('archive_command = something\n'
                                 'data_directory = something')
     postgresql_auto_local.write('archive_command = something\n'
                                 'data_directory = something')
     shutil.copy2(postgresql_conf_local.strpath, dest.strpath)
     shutil.copy2(postgresql_auto_local.strpath, dest.strpath)
     # Avoid triggering warning for missing config files
     datadir.ensure('pg_hba.conf')
     datadir.ensure('pg_ident.conf')
     # Build an executor
     server = testing_helpers.build_real_server(
         global_conf={
             "barman_lock_directory": tmpdir.mkdir('lock').strpath
         },
         main_conf={"wals_directory": wals.strpath})
     executor = RecoveryExecutor(server.backup_manager)
     # test local recovery
     rec_info = executor.recover(backup_info, dest.strpath, None, None,
                                 None, None, None, True, None)
     # remove not usefull keys from the result
     del rec_info['cmd']
     sys_tempdir = rec_info['tempdir']
     assert rec_info == {
         'rsync':
         None,
         'tempdir':
         sys_tempdir,
         'wal_dest':
         dest.join('pg_xlog').strpath,
         'recovery_dest':
         'local',
         'destination_path':
         dest.strpath,
         'temporary_configuration_files': [
             dest.join('postgresql.conf').strpath,
             dest.join('postgresql.auto.conf').strpath
         ],
         'results': {
             'delete_barman_xlog':
             False,
             'get_wal':
             False,
             'changes': [
                 Assertion._make(
                     ['postgresql.conf', 0, 'archive_command', 'false']),
                 Assertion._make([
                     'postgresql.auto.conf', 0, 'archive_command', 'false'
                 ])
             ],
             'missing_files': [],
             'warnings': [
                 Assertion._make(
                     ['postgresql.conf', 2, 'data_directory', 'something']),
                 Assertion._make([
                     'postgresql.auto.conf', 2, 'data_directory',
                     'something'
                 ])
             ]
         },
         'target_epoch':
         None,
         'configuration_files': ['postgresql.conf', 'postgresql.auto.conf'],
         'target_datetime':
         None,
         'safe_horizon':
         None,
         'is_pitr':
         False,
         'get_wal':
         False,
     }
     # test remote recovery
     rec_info = executor.recover(backup_info, dest.strpath, {}, None, None,
                                 None, None, True, "remote@command")
     # remove not useful keys from the result
     del rec_info['cmd']
     del rec_info['rsync']
     sys_tempdir = rec_info['tempdir']
     assert rec_info == {
         'tempdir':
         sys_tempdir,
         'wal_dest':
         dest.join('pg_xlog').strpath,
         'recovery_dest':
         'remote',
         'destination_path':
         dest.strpath,
         'temporary_configuration_files': [
             os.path.join(sys_tempdir, 'postgresql.conf'),
             os.path.join(sys_tempdir, 'postgresql.auto.conf')
         ],
         'results': {
             'delete_barman_xlog':
             False,
             'get_wal':
             False,
             'changes': [
                 Assertion._make(
                     ['postgresql.conf', 0, 'archive_command', 'false']),
                 Assertion._make([
                     'postgresql.auto.conf', 0, 'archive_command', 'false'
                 ])
             ],
             'missing_files': [],
             'warnings': [
                 Assertion._make(
                     ['postgresql.conf', 2, 'data_directory', 'something']),
                 Assertion._make([
                     'postgresql.auto.conf', 2, 'data_directory',
                     'something'
                 ])
             ]
         },
         'target_epoch':
         None,
         'configuration_files': ['postgresql.conf', 'postgresql.auto.conf'],
         'target_datetime':
         None,
         'safe_horizon':
         None,
         'is_pitr':
         False,
         'get_wal':
         False,
     }
     # test failed rsync
     rsync_pg_mock.side_effect = CommandFailedException()
     with pytest.raises(CommandFailedException):
         executor.recover(backup_info, dest.strpath, {}, None, None, None,
                          None, True, "remote@command")
Beispiel #7
0
    def recover(self,
                backup_info,
                dest,
                tablespaces=None,
                remote_command=None,
                **kwargs):
        """
        Performs a recovery of a backup

        :param barman.infofile.LocalBackupInfo backup_info: the backup
            to recover
        :param str dest: the destination directory
        :param dict[str,str]|None tablespaces: a tablespace name -> location
            map (for relocation)
        :param str|None remote_command: default None. The remote command
            to recover the base backup, in case of remote backup.
        :kwparam str|None target_tli: the target timeline
        :kwparam str|None target_time: the target time
        :kwparam str|None target_xid: the target xid
        :kwparam str|None target_lsn: the target LSN
        :kwparam str|None target_name: the target name created previously with
            pg_create_restore_point() function call
        :kwparam bool|None target_immediate: end recovery as soon as
            consistency is reached
        :kwparam bool exclusive: whether the recovery is exclusive or not
        :kwparam str|None target_action: default None. The recovery target
            action
        :kwparam bool|None standby_mode: the standby mode if needed
        """

        # Archive every WAL files in the incoming directory of the server
        self.server.archive_wal(verbose=False)
        # Delegate the recovery operation to a RecoveryExecutor object
        executor = RecoveryExecutor(self)

        # Run the pre_recovery_script if present.
        script = HookScriptRunner(self, 'recovery_script', 'pre')
        script.env_from_recover(backup_info, dest, tablespaces, remote_command,
                                **kwargs)
        script.run()

        # Run the pre_recovery_retry_script if present.
        retry_script = RetryHookScriptRunner(self, 'recovery_retry_script',
                                             'pre')
        retry_script.env_from_recover(backup_info, dest, tablespaces,
                                      remote_command, **kwargs)
        retry_script.run()

        # Execute the recovery.
        # We use a closing context to automatically remove
        # any resource eventually allocated during recovery.
        with closing(executor):
            recovery_info = executor.recover(backup_info,
                                             dest,
                                             tablespaces=tablespaces,
                                             remote_command=remote_command,
                                             **kwargs)

        # Run the post_recovery_retry_script if present.
        try:
            retry_script = RetryHookScriptRunner(self, 'recovery_retry_script',
                                                 'post')
            retry_script.env_from_recover(backup_info, dest, tablespaces,
                                          remote_command, **kwargs)
            retry_script.run()
        except AbortedRetryHookScript as e:
            # Ignore the ABORT_STOP as it is a post-hook operation
            _logger.warning(
                "Ignoring stop request after receiving "
                "abort (exit code %d) from post-recovery "
                "retry hook script: %s", e.hook.exit_status, e.hook.script)

        # Run the post-recovery-script if present.
        script = HookScriptRunner(self, 'recovery_script', 'post')
        script.env_from_recover(backup_info, dest, tablespaces, remote_command,
                                **kwargs)
        script.run()

        # Output recovery results
        output.result('recovery', recovery_info['results'])
 def test_recovery(self, remote_cmd_mock, rsync_pg_mock, copy_controller_mock, tmpdir):
     """
     Test the execution of a recovery
     """
     # Prepare basic directory/files structure
     dest = tmpdir.mkdir("destination")
     base = tmpdir.mkdir("base")
     wals = tmpdir.mkdir("wals")
     backup_info = testing_helpers.build_test_backup_info(tablespaces=[])
     backup_info.config.basebackups_directory = base.strpath
     backup_info.config.wals_directory = wals.strpath
     backup_info.version = 90400
     datadir = base.mkdir(backup_info.backup_id).mkdir("data")
     backup_info.pgdata = datadir.strpath
     postgresql_conf_local = datadir.join("postgresql.conf")
     postgresql_auto_local = datadir.join("postgresql.auto.conf")
     postgresql_conf_local.write("archive_command = something\n" "data_directory = something")
     postgresql_auto_local.write("archive_command = something\n" "data_directory = something")
     shutil.copy2(postgresql_conf_local.strpath, dest.strpath)
     shutil.copy2(postgresql_auto_local.strpath, dest.strpath)
     # Avoid triggering warning for missing config files
     datadir.ensure("pg_hba.conf")
     datadir.ensure("pg_ident.conf")
     # Build an executor
     server = testing_helpers.build_real_server(
         global_conf={"barman_lock_directory": tmpdir.mkdir("lock").strpath},
         main_conf={"wals_directory": wals.strpath},
     )
     executor = RecoveryExecutor(server.backup_manager)
     # test local recovery
     rec_info = executor.recover(backup_info, dest.strpath, None, None, None, None, None, True, None)
     # remove not usefull keys from the result
     del rec_info["cmd"]
     sys_tempdir = rec_info["tempdir"]
     assert rec_info == {
         "rsync": None,
         "tempdir": sys_tempdir,
         "wal_dest": dest.join("pg_xlog").strpath,
         "recovery_dest": "local",
         "destination_path": dest.strpath,
         "temporary_configuration_files": [
             dest.join("postgresql.conf").strpath,
             dest.join("postgresql.auto.conf").strpath,
         ],
         "results": {
             "delete_barman_xlog": False,
             "get_wal": False,
             "changes": [
                 Assertion._make(["postgresql.conf", 0, "archive_command", "false"]),
                 Assertion._make(["postgresql.auto.conf", 0, "archive_command", "false"]),
             ],
             "missing_files": [],
             "warnings": [
                 Assertion._make(["postgresql.conf", 2, "data_directory", "something"]),
                 Assertion._make(["postgresql.auto.conf", 2, "data_directory", "something"]),
             ],
         },
         "target_epoch": None,
         "configuration_files": ["postgresql.conf", "postgresql.auto.conf"],
         "target_datetime": None,
         "safe_horizon": None,
         "is_pitr": False,
         "get_wal": False,
     }
     # test remote recovery
     rec_info = executor.recover(backup_info, dest.strpath, {}, None, None, None, None, True, "remote@command")
     # remove not useful keys from the result
     del rec_info["cmd"]
     del rec_info["rsync"]
     sys_tempdir = rec_info["tempdir"]
     assert rec_info == {
         "tempdir": sys_tempdir,
         "wal_dest": dest.join("pg_xlog").strpath,
         "recovery_dest": "remote",
         "destination_path": dest.strpath,
         "temporary_configuration_files": [
             os.path.join(sys_tempdir, "postgresql.conf"),
             os.path.join(sys_tempdir, "postgresql.auto.conf"),
         ],
         "results": {
             "delete_barman_xlog": False,
             "get_wal": False,
             "changes": [
                 Assertion._make(["postgresql.conf", 0, "archive_command", "false"]),
                 Assertion._make(["postgresql.auto.conf", 0, "archive_command", "false"]),
             ],
             "missing_files": [],
             "warnings": [
                 Assertion._make(["postgresql.conf", 2, "data_directory", "something"]),
                 Assertion._make(["postgresql.auto.conf", 2, "data_directory", "something"]),
             ],
         },
         "target_epoch": None,
         "configuration_files": ["postgresql.conf", "postgresql.auto.conf"],
         "target_datetime": None,
         "safe_horizon": None,
         "is_pitr": False,
         "get_wal": False,
     }
     # test failed rsync
     rsync_pg_mock.side_effect = CommandFailedException()
     with pytest.raises(CommandFailedException):
         executor.recover(backup_info, dest.strpath, {}, None, None, None, None, True, "remote@command")
 def test_recovery(
     self, remote_cmd_mock, rsync_pg_mock, copy_controller_mock, tmpdir
 ):
     """
     Test the execution of a recovery
     """
     # Prepare basic directory/files structure
     dest = tmpdir.mkdir("destination")
     base = tmpdir.mkdir("base")
     wals = tmpdir.mkdir("wals")
     backup_info = testing_helpers.build_test_backup_info(tablespaces=[])
     backup_info.config.basebackups_directory = base.strpath
     backup_info.config.wals_directory = wals.strpath
     backup_info.version = 90400
     datadir = base.mkdir(backup_info.backup_id).mkdir("data")
     backup_info.pgdata = datadir.strpath
     postgresql_conf_local = datadir.join("postgresql.conf")
     postgresql_auto_local = datadir.join("postgresql.auto.conf")
     postgresql_conf_local.write(
         "archive_command = something\n" "data_directory = something"
     )
     postgresql_auto_local.write(
         "archive_command = something\n" "data_directory = something"
     )
     shutil.copy2(postgresql_conf_local.strpath, dest.strpath)
     shutil.copy2(postgresql_auto_local.strpath, dest.strpath)
     # Avoid triggering warning for missing config files
     datadir.ensure("pg_hba.conf")
     datadir.ensure("pg_ident.conf")
     # Build an executor
     server = testing_helpers.build_real_server(
         global_conf={"barman_lock_directory": tmpdir.mkdir("lock").strpath},
         main_conf={"wals_directory": wals.strpath},
     )
     executor = RecoveryExecutor(server.backup_manager)
     # test local recovery
     with closing(executor):
         rec_info = executor.recover(backup_info, dest.strpath, exclusive=True)
     # remove not useful keys from the result
     del rec_info["cmd"]
     sys_tempdir = rec_info["tempdir"]
     assert rec_info == {
         "rsync": None,
         "tempdir": sys_tempdir,
         "wal_dest": dest.join("pg_xlog").strpath,
         "recovery_dest": "local",
         "destination_path": dest.strpath,
         "temporary_configuration_files": [
             dest.join("postgresql.conf").strpath,
             dest.join("postgresql.auto.conf").strpath,
         ],
         "results": {
             "delete_barman_wal": False,
             "recovery_start_time": rec_info["results"]["recovery_start_time"],
             "get_wal": False,
             "changes": [
                 Assertion._make(["postgresql.conf", 0, "archive_command", "false"]),
                 Assertion._make(
                     ["postgresql.auto.conf", 0, "archive_command", "false"]
                 ),
             ],
             "missing_files": [],
             "recovery_configuration_file": "recovery.conf",
             "warnings": [
                 Assertion._make(
                     ["postgresql.conf", 2, "data_directory", "something"]
                 ),
                 Assertion._make(
                     ["postgresql.auto.conf", 2, "data_directory", "something"]
                 ),
             ],
         },
         "target_epoch": None,
         "configuration_files": ["postgresql.conf", "postgresql.auto.conf"],
         "target_datetime": None,
         "safe_horizon": None,
         "is_pitr": False,
         "get_wal": False,
     }
     # test remote recovery
     with closing(executor):
         rec_info = executor.recover(
             backup_info,
             dest.strpath,
             remote_command="remote@command",
             exclusive=True,
         )
     # remove not useful keys from the result
     del rec_info["cmd"]
     del rec_info["rsync"]
     sys_tempdir = rec_info["tempdir"]
     assert rec_info == {
         "tempdir": sys_tempdir,
         "wal_dest": dest.join("pg_xlog").strpath,
         "recovery_dest": "remote",
         "destination_path": dest.strpath,
         "temporary_configuration_files": [
             os.path.join(sys_tempdir, "postgresql.conf"),
             os.path.join(sys_tempdir, "postgresql.auto.conf"),
         ],
         "results": {
             "delete_barman_wal": False,
             "get_wal": False,
             "recovery_start_time": rec_info["results"]["recovery_start_time"],
             "changes": [
                 Assertion._make(["postgresql.conf", 0, "archive_command", "false"]),
                 Assertion._make(
                     ["postgresql.auto.conf", 0, "archive_command", "false"]
                 ),
             ],
             "missing_files": [],
             "recovery_configuration_file": "recovery.conf",
             "warnings": [
                 Assertion._make(
                     ["postgresql.conf", 2, "data_directory", "something"]
                 ),
                 Assertion._make(
                     ["postgresql.auto.conf", 2, "data_directory", "something"]
                 ),
             ],
         },
         "target_epoch": None,
         "configuration_files": ["postgresql.conf", "postgresql.auto.conf"],
         "target_datetime": None,
         "safe_horizon": None,
         "is_pitr": False,
         "get_wal": False,
     }
     # test failed rsync
     rsync_pg_mock.side_effect = CommandFailedException()
     with pytest.raises(CommandFailedException):
         with closing(executor):
             executor.recover(
                 backup_info,
                 dest.strpath,
                 exclusive=True,
                 remote_command="remote@command",
             )