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.")
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.')
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.')