Beispiel #1
0
    def receive_wal(self, reset=False):
        """
        Creates a PgReceiveXlog object and issues the pg_receivexlog command
        for a specific server

        :param bool reset: When set reset the status of receive-wal
        :raise ArchiverFailure: when something goes wrong
        """
        # Ensure the presence of the destination directory
        mkpath(self.config.streaming_wals_directory)

        # Execute basic sanity checks on PostgreSQL connection
        streaming_status = self.server.streaming.get_remote_status()
        if streaming_status["streaming_supported"] is None:
            raise ArchiverFailure(
                "failed opening the PostgreSQL streaming connection "
                "for server %s" % (self.config.name))
        elif not streaming_status["streaming_supported"]:
            raise ArchiverFailure("PostgreSQL version too old (%s < 9.2)" %
                                  self.server.streaming.server_txt_version)
        # Execute basic sanity checks on pg_receivexlog
        command = "pg_receivewal"
        if self.server.streaming.server_version < 100000:
            command = "pg_receivexlog"
        remote_status = self.get_remote_status()
        if not remote_status["pg_receivexlog_installed"]:
            raise ArchiverFailure("%s not present in $PATH" % command)
        if not remote_status["pg_receivexlog_compatible"]:
            raise ArchiverFailure(
                "%s version not compatible with PostgreSQL server version" %
                command)

        # Execute sanity check on replication slot usage
        postgres_status = self.server.postgres.get_remote_status()
        if self.config.slot_name:
            # Check if slots are supported
            if not remote_status["pg_receivexlog_supports_slots"]:
                raise ArchiverFailure(
                    "Physical replication slot not supported by %s "
                    "(9.4 or higher is required)" %
                    self.server.streaming.server_txt_version)
            # Check if the required slot exists
            if postgres_status["replication_slot"] is None:
                if self.config.create_slot == "auto":
                    if not reset:
                        output.info("Creating replication slot '%s'",
                                    self.config.slot_name)
                        self.server.create_physical_repslot()
                else:
                    raise ArchiverFailure(
                        "replication slot '%s' doesn't exist. "
                        "Please execute "
                        "'barman receive-wal --create-slot %s'" %
                        (self.config.slot_name, self.config.name))
            # Check if the required slot is available
            elif postgres_status["replication_slot"].active:
                raise ArchiverFailure(
                    "replication slot '%s' is already in use" %
                    (self.config.slot_name, ))

        # Check if is a reset request
        if reset:
            self._reset_streaming_status(postgres_status, streaming_status)
            return

        # Check the size of the .partial WAL file and truncate it if needed
        self._truncate_partial_file_if_needed(
            postgres_status["xlog_segment_size"])

        # Make sure we are not wasting precious PostgreSQL resources
        self.server.close()

        _logger.info("Activating WAL archiving through streaming protocol")
        try:
            output_handler = PgReceiveXlog.make_output_handler(
                self.config.name + ": ")
            receive = PgReceiveXlog(
                connection=self.server.streaming,
                destination=self.config.streaming_wals_directory,
                command=remote_status["pg_receivexlog_path"],
                version=remote_status["pg_receivexlog_version"],
                app_name=self.config.streaming_archiver_name,
                path=self.server.path,
                slot_name=self.config.slot_name,
                synchronous=remote_status["pg_receivexlog_synchronous"],
                out_handler=output_handler,
                err_handler=output_handler,
            )
            # Finally execute the pg_receivexlog process
            receive.execute()
        except CommandFailedException as e:
            # Retrieve the return code from the exception
            ret_code = e.args[0]["ret"]
            if ret_code < 0:
                # If the return code is negative, then pg_receivexlog
                # was terminated by a signal
                msg = "%s terminated by signal: %s" % (command, abs(ret_code))
            else:
                # Otherwise terminated with an error
                msg = "%s terminated with error code: %s" % (command, ret_code)

            raise ArchiverFailure(msg)
        except KeyboardInterrupt:
            # This is a normal termination, so there is nothing to do beside
            # informing the user.
            output.info("SIGINT received. Terminate gracefully.")
Beispiel #2
0
    def receive_wal(self, reset=False):
        """
        Creates a PgReceiveXlog object and issues the pg_receivexlog command
        for a specific server

        :param bool reset: When set reset the status of receive-wal
        :raise ArchiverFailure: when something goes wrong
        """
        # Ensure the presence of the destination directory
        mkpath(self.config.streaming_wals_directory)

        # Check if is a reset request
        if reset:
            self._reset_streaming_status()
            return

        # Execute basic sanity checks on PostgreSQL connection
        streaming_status = self.server.streaming.get_remote_status()
        if streaming_status["streaming_supported"] is None:
            raise ArchiverFailure(
                'failed opening the PostgreSQL streaming connection '
                'for server %s' % (self.config.name))
        elif not streaming_status["streaming_supported"]:
            raise ArchiverFailure('PostgreSQL version too old (%s < 9.2)' %
                                  self.server.streaming.server_txt_version)
        # Execute basic sanity checks on pg_receivexlog
        remote_status = self.get_remote_status()
        if not remote_status["pg_receivexlog_installed"]:
            raise ArchiverFailure('pg_receivexlog not present in $PATH')
        if not remote_status['pg_receivexlog_compatible']:
            raise ArchiverFailure('pg_receivexlog version not compatible with '
                                  'PostgreSQL server version')

        # Execute sanity check on replication slot usage
        if self.config.slot_name:
            # Check if slots are supported
            if not remote_status['pg_receivexlog_supports_slots']:
                raise ArchiverFailure(
                    'Physical replication slot not supported by %s '
                    '(9.4 or higher is required)' %
                    self.server.streaming.server_txt_version)
            # Check if the required slot exists
            postgres_status = self.server.postgres.get_remote_status()
            if postgres_status['replication_slot'] is None:
                raise ArchiverFailure(
                    "replication slot '%s' doesn't exist. "
                    "Please execute "
                    "'barman receive-wal --create-slot %s'" %
                    (self.config.slot_name, self.config.name))
            # Check if the required slot is available
            if postgres_status['replication_slot'].active:
                raise ArchiverFailure(
                    "replication slot '%s' is already in use" %
                    (self.config.slot_name, ))

        # Make sure we are not wasting precious PostgreSQL resources
        self.server.close()

        _logger.info('Activating WAL archiving through streaming protocol')
        try:
            output_handler = PgReceiveXlog.make_output_handler(
                self.config.name + ': ')
            receive = PgReceiveXlog(
                connection=self.server.streaming,
                destination=self.config.streaming_wals_directory,
                command=remote_status['pg_receivexlog_path'],
                version=remote_status['pg_receivexlog_version'],
                app_name=self.config.streaming_archiver_name,
                path=self.server.path,
                slot_name=self.config.slot_name,
                synchronous=remote_status['pg_receivexlog_synchronous'],
                out_handler=output_handler,
                err_handler=output_handler)
            # Finally execute the pg_receivexlog process
            receive.execute()
        except CommandFailedException as e:
            # Retrieve the return code from the exception
            ret_code = e.args[0]['ret']
            if ret_code < 0:
                # If the return code is negative, then pg_receivexlog
                # was terminated by a signal
                msg = "pg_receivexlog terminated by signal: %s" \
                      % abs(ret_code)
            else:
                # Otherwise terminated with an error
                msg = "pg_receivexlog terminated with error code: %s"\
                      % ret_code

            raise ArchiverFailure(msg)
        except KeyboardInterrupt:
            # This is a normal termination, so there is nothing to do beside
            # informing the user.
            output.info('SIGINT received. Terminate gracefully.')
Beispiel #3
0
    def receive_wal(self, reset=False):
        """
        Creates a PgReceiveXlog object and issues the pg_receivexlog command
        for a specific server

        :param bool reset: When set reset the status of receive-wal
        :raise ArchiverFailure: when something goes wrong
        """
        # Ensure the presence of the destination directory
        mkpath(self.config.streaming_wals_directory)

        # Check if is a reset request
        if reset:
            self._reset_streaming_status()
            return

        # Execute basic sanity checks on PostgreSQL connection
        postgres_status = self.server.streaming.get_remote_status()
        if postgres_status["streaming_supported"] is None:
            raise ArchiverFailure(
                'failed opening the PostgreSQL streaming connection')
        elif not postgres_status["streaming_supported"]:
            raise ArchiverFailure('PostgreSQL version too old (%s < 9.2)' %
                                  self.server.streaming.server_txt_version)
        # Execute basic sanity checks on pg_receivexlog
        remote_status = self.get_remote_status()
        if not remote_status["pg_receivexlog_installed"]:
            raise ArchiverFailure('pg_receivexlog not present in $PATH')
        if not remote_status['pg_receivexlog_compatible']:
            raise ArchiverFailure('pg_receivexlog version not compatible with '
                                  'PostgreSQL server version')

        # Make sure we are not wasting precious PostgreSQL resources
        self.server.close()

        _logger.info('Activating WAL archiving through streaming protocol')
        try:
            output_handler = PgReceiveXlog.make_output_handler(
                self.config.name + ': ')
            if remote_status['pg_receivexlog_version'] >= "9.3":
                conn_string = self.config.streaming_conninfo
                # Set a default application_name unless defined by user
                if ('application_name'
                        not in self.server.streaming.conn_parameters):
                    conn_string += ' application_name=%s' % (
                        self.config.streaming_archiver_name)
                # If pg_receivexlog version is >= 9.3 we use the connection
                # string because allows the user to use all the parameters
                # supported by the libpq library to create a connection
                receive = PgReceiveXlog(
                    remote_status['pg_receivexlog_path'],
                    conn_string=conn_string,
                    dest=self.config.streaming_wals_directory,
                    out_handler=output_handler,
                    err_handler=output_handler)
            else:
                # 9.2 version of pg_receivexlog doesn't support
                # connection strings so the 'split' version of the conninfo
                # option is used instead.
                conn_params = self.server.streaming.conn_parameters
                receive = PgReceiveXlog(
                    remote_status['pg_receivexlog_path'],
                    host=conn_params.get('host', None),
                    port=conn_params.get('port', None),
                    user=conn_params.get('user', None),
                    dest=self.config.streaming_wals_directory,
                    out_handler=output_handler,
                    err_handler=output_handler)
            # Finally execute the pg_receivexlog process
            receive.execute()
        except CommandFailedException as e:
            _logger.error(e)
            raise ArchiverFailure("pg_receivexlog exited with an error. "
                                  "Check the logs for more information.")
        except KeyboardInterrupt:
            # This is a normal termination, so there is nothing to do beside
            # informing the user.
            output.info('SIGINT received. Terminate gracefully.')