patroni.postgresql.config module

class patroni.postgresql.config.ConfigHandler(postgresql: Postgresql, config: Dict[str, Any])

Bases: object

CMDLINE_OPTIONS = <CaseInsensitiveDict{'listen_addresses': (None, <function _false_validator>, 90100), 'port': (None, <function _false_validator>, 90100), 'cluster_name': (None, <function _false_validator>, 90500), 'wal_level': ('hot_standby', <patroni.validator.EnumValidator object>, 90100), 'hot_standby': ('on', <function _bool_is_true_validator>, 90100), 'max_connections': (100, <patroni.validator.IntValidator object>, 90100), 'max_wal_senders': (10, <patroni.validator.IntValidator object>, 90100), 'wal_keep_segments': (8, <patroni.validator.IntValidator object>, 90100), 'wal_keep_size': ('128MB', <patroni.validator.IntValidator object>, 130000), 'max_prepared_transactions': (0, <patroni.validator.IntValidator object>, 90100), 'max_locks_per_transaction': (64, <patroni.validator.IntValidator object>, 90100), 'track_commit_timestamp': ('off', <function _bool_validator>, 90500), 'max_replication_slots': (10, <patroni.validator.IntValidator object>, 90400), 'max_worker_processes': (8, <patroni.validator.IntValidator object>, 90400), 'wal_log_hints': ('on', <function _bool_validator>, 90400)} at 7fdac7d602d0>
_RECOVERY_PARAMETERS = <CaseInsensitiveSet('archive_cleanup_command', 'pause_at_recovery_target', 'primary_conninfo', 'primary_slot_name', 'promote_trigger_file', 'recovery_end_command', 'recovery_min_apply_delay', 'recovery_target', 'recovery_target_action', 'recovery_target_inclusive', 'recovery_target_lsn', 'recovery_target_name', 'recovery_target_time', 'recovery_target_timeline', 'recovery_target_xid', 'restore_command', 'standby_mode', 'trigger_file') at 7fdac7d60410>
__init__(postgresql: Postgresql, config: Dict[str, Any]) None
_adjust_recovery_parameters() None
_check_passfile(passfile: str, wanted_primary_conninfo: Dict[str, Any]) bool
_check_primary_conninfo(primary_conninfo: Dict[str, Any], wanted_primary_conninfo: Dict[str, Any]) bool
property _configuration_to_save: List[str]
_get_pg_settings(names: Collection[str]) Dict[Any, Tuple[Any, ...]]
_get_tcp_local_address() str
static _get_unix_local_address(unix_socket_directories: str) str
static _handle_wal_buffers(old_values: Dict[Any, Tuple[Any, ...]], changes: CaseInsensitiveDict) None
static _pgpass_content(record: Dict[str, Any]) str | None

Generate content of pgpassfile based on connection parameters.

Note

In case if host is a comma separated string we generate one line per host.

Parameters:

recorddict object with connection parameters.

Returns:

a string with generated content of pgpassfile or None if there is no password.

_read_recovery_params() Tuple[CaseInsensitiveDict | None, bool]

Read current recovery parameters values.

Note

We query Postgres only if we detected that Postgresql was restarted or when at least one of the following files was updated:

  • postgresql.conf;

  • postgresql.auto.conf;

  • passfile that is used in the primary_conninfo.

Returns:

a tuple with two elements:

  • CaseInsensitiveDict object with current values of recovery parameters, or None if no configuration files were updated;

  • True if new values of recovery parameters were queried, False otherwise.

_read_recovery_params_pre_v12() Tuple[CaseInsensitiveDict | None, bool]
property _recovery_parameters_to_compare: CaseInsensitiveSet
static _remove_file_if_exists(name: str) None
_sanitize_auto_conf() None
property _triggerfile_wrong_name: str
_write_recovery_params(fd: ConfigWriter, recovery_params: CaseInsensitiveDict) None
append_pg_hba(config: List[str]) bool
build_recovery_params(member: Leader | Member | None) CaseInsensitiveDict
check_directories() None
check_recovery_conf(member: Leader | Member | None) Tuple[bool, bool]

Returns a tuple. The first boolean element indicates that recovery params don’t match and the second is set to True if the restart is required in order to apply new values

property config_dir: str
config_writer(filename: str) Iterator[ConfigWriter]

Create ConfigWriter object and set permissions on a filename.

Parameters:

filename – path to a config file.

Yields:

ConfigWriter object.

property effective_configuration: CaseInsensitiveDict

It might happen that the current value of one (or more) below parameters stored in the controldata is higher than the value stored in the global cluster configuration.

Example: max_connections in global configuration is 100, but in controldata Current max_connections setting: 200. If we try to start postgres with max_connections=100, it will immediately exit. As a workaround we will start it with the values from controldata and set pending_restart to true as an indicator that current values of parameters are not matching expectations.

format_dsn(params: Dict[str, Any]) str

Format connection string from connection parameters.

Note

only parameters from the below list are considered and values are escaped.

Parameters:

paramsdict object with connection parameters.

Returns:

a connection string in a format “key1=value2 key2=value2”

get(key: str, default: Any | None = None) Any | None
get_server_parameters(config: Dict[str, Any]) CaseInsensitiveDict
property hba_file: str | None
property ident_file: str | None
load_current_server_parameters() None

Read GUC’s values from pg_settings when Patroni is joining the the postgres that is already running.

property pg_hba_conf: str
property pg_version: int

Current full postgres version if instance is running, major version otherwise.

We can only use postgres --version output if major version there equals to the one in data directory. If it is not the case, we should use major version from the PG_VERSION file.

property postgresql_conf: str
primary_conninfo_params(member: Leader | Member | None) Dict[str, Any] | None
recovery_conf_exists() bool
reload_config(config: Dict[str, Any], sighup: bool = False) None
remove_recovery_conf() None
replace_pg_hba() bool | None

Replace pg_hba.conf content in the PGDATA if hba_file is not defined in the postgresql.parameters and pg_hba is defined in postgresql configuration section.

Returns:

True if pg_hba.conf was rewritten.

replace_pg_ident() bool | None

Replace pg_ident.conf content in the PGDATA if ident_file is not defined in the postgresql.parameters and pg_ident is defined in the postgresql section.

Returns:

True if pg_ident.conf was rewritten.

property replication: Dict[str, Any]
resolve_connection_addresses() None

Calculates and sets local and remote connection urls and options.

This method sets:
  • Postgresql.connection_string attribute, which is later written to the member key in DCS as conn_url.

  • ConfigHandler.local_replication_address attribute, which is used for replication connections to local postgres.

  • ConnectionPool.conn_kwargs attribute, which is used for superuser connections to local postgres.

Note

If there is a valid directory in postgresql.parameters.unix_socket_directories in the Patroni configuration and postgresql.use_unix_socket and/or postgresql.use_unix_socket_repl are set to True, we respectively use unix sockets for superuser and replication connections to local postgres.

If there is a requirement to use unix sockets, but nothing is set in the postgresql.parameters.unix_socket_directories, we omit a host in connection parameters relying on the ability of libpq to connect via some default unix socket directory.

If unix sockets are not requested we “switch” to TCP, preferring to use localhost if it is possible to deduce that Postgres is listening on a local interface address.

Otherwise we just used the first address specified in the listen_addresses GUC.

restore_command() str | None
restore_configuration_files() None

restore a previously saved postgresql.conf

property rewind_credentials: Dict[str, Any]
save_configuration_files(check_custom_bootstrap: bool = False) bool

copy postgresql.conf to postgresql.conf.backup to be able to retrieve configuration files - originally stored as symlinks, those are normally skipped by pg_basebackup - in case of WAL-E basebackup (see http://comments.gmane.org/gmane.comp.db.postgresql.wal-e/239)

set_file_permissions(filename: str) None

Set permissions of file filename according to the expected permissions.

Note

Use original umask if the file is not under PGDATA, use PGDATA permissions otherwise.

Parameters:

filename – path to a file which permissions might need to be adjusted.

set_synchronous_standby_names(value: str | None) bool | None

Updates synchronous_standby_names and reloads if necessary. :returns: True if value was updated.

setup_server_parameters() None
property superuser: Dict[str, Any]
property synchronous_standby_names: str | None

Get synchronous_standby_names value configured by the user.

Returns:

value of synchronous_standby_names in the Patroni configuration, if any, otherwise None.

property triggerfile_good_name: str
try_to_create_dir(d: str, msg: str) None
write_pgpass(record: Dict[str, Any]) Dict[str, str]

Maybe creates _passfile based on connection parameters.

Parameters:

recorddict object with connection parameters.

Returns:

a copy of environment variables, that will include PGPASSFILE in case if the file was written.

write_postgresql_conf(configuration: CaseInsensitiveDict | None = None) None
write_recovery_conf(recovery_params: CaseInsensitiveDict) None
class patroni.postgresql.config.ConfigWriter(filename: str)

Bases: object

__init__(filename: str) None
static escape(value: Any) str
write_param(param: str, value: Any) None
writeline(line: str) None
writelines(lines: List[str | None]) None
patroni.postgresql.config._bool_is_true_validator(value: Any) bool
patroni.postgresql.config._bool_validator(value: Any) bool
patroni.postgresql.config._conninfo_dsn_parse(dsn: str) Dict[str, str] | None
>>> r = _conninfo_dsn_parse(" host = 'host' dbname = db\\ name requiressl=1 ")
>>> r == {'dbname': 'db name', 'host': 'host', 'requiressl': '1'}
True
>>> _conninfo_dsn_parse('requiressl = 0\\') == {'requiressl': '0'}
True
>>> _conninfo_dsn_parse("host=a foo = '") is None
True
>>> _conninfo_dsn_parse("host=a foo = ") is None
True
>>> _conninfo_dsn_parse("1") is None
True
patroni.postgresql.config._conninfo_parse(value: str) Dict[str, str] | None

Very simple equivalent of psycopg2.extensions.parse_dsn introduced in 2.7.0. Exists just for compatibility with 2.5.4+.

>>> r = _conninfo_parse('postgresql://foo/postgres')
>>> r == {'dbname': 'postgres', 'host': 'foo'}
True
>>> r = _conninfo_parse(" host = 'host' dbname = db\\ name requiressl=1 ")
>>> r == {'dbname': 'db name', 'host': 'host', 'sslmode': 'require'}
True
>>> _conninfo_parse('requiressl = 0\\') == {'sslmode': 'prefer'}
True
patroni.postgresql.config._conninfo_uri_parse(dsn: str) Dict[str, str]
>>> r = _conninfo_uri_parse('postgresql://u%2Fse:pass@:%2f123/db%2Fsdf?application_name=mya%2Fpp&ssl=true')
>>> r == {'application_name': 'mya/pp', 'dbname': 'db/sdf', 'sslmode': 'require',              'password': 'pass', 'port': '/123', 'user': 'u/se'}
True
>>> r = _conninfo_uri_parse('postgresql://u%2Fse:pass@[::1]/db%2Fsdf?application_name=mya%2Fpp&ssl=true')
>>> r == {'application_name': 'mya/pp', 'dbname': 'db/sdf', 'host': '::1', 'sslmode': 'require',              'password': 'pass', 'user': 'u/se'}
True
patroni.postgresql.config._false_validator(value: Any) bool
patroni.postgresql.config.get_param_diff(old_value: Any, new_value: Any, vartype: str | None = None, unit: str | None = None) Dict[str, str]

Get a dictionary representing a single PG parameter’s value diff.

Parameters:
Returns:

a dict object that contains two keys: old_value and new_value with their values casted to str and converted from base units (if possible).

patroni.postgresql.config.mtime(filename: str) float | None
patroni.postgresql.config.parse_dsn(value: str) Dict[str, str] | None

Compatibility layer on top of function from psycopg2/psycopg3, which parses connection strings. In this function sets the sslmode, ‘gssencmode’, and channel_binding to prefer and sslnegotiation to postgres if they are not present in the connection string. This is necessary to simplify comparison of the old and the new values.

>>> r = parse_dsn('postgresql://foo/postgres')
>>> r == {'dbname': 'postgres', 'host': 'foo', 'sslmode': 'prefer', 'gssencmode': 'prefer',              'channel_binding': 'prefer', 'sslnegotiation': 'postgres'}
True
>>> r = parse_dsn(" host = 'host' dbname = db\\ name requiressl=1 ")
>>> r == {'dbname': 'db name', 'host': 'host', 'sslmode': 'require',              'gssencmode': 'prefer', 'channel_binding': 'prefer', 'sslnegotiation': 'postgres'}
True
>>> parse_dsn('requiressl = 0\\') == {'sslmode': 'prefer', 'gssencmode': 'prefer',                                            'channel_binding': 'prefer', 'sslnegotiation': 'postgres'}
True
>>> parse_dsn('foo=bar') == {'foo': 'bar', 'sslmode': 'prefer', 'gssencmode': 'prefer',                                 'channel_binding': 'prefer', 'sslnegotiation': 'postgres'}
True
patroni.postgresql.config.read_param_value(value: str) Tuple[None, None] | Tuple[str, int]
patroni.postgresql.config.read_recovery_param_value(value: str) str | None
>>> read_recovery_param_value('') is None
True
>>> read_recovery_param_value("'") is None
True
>>> read_recovery_param_value("''a") is None
True
>>> read_recovery_param_value('a b') is None
True
>>> read_recovery_param_value("'''") is None
True
>>> read_recovery_param_value("'\\") is None
True
>>> read_recovery_param_value("'a' s#") is None
True
>>> read_recovery_param_value("'\\'''' #a")
"''"
>>> read_recovery_param_value('asd')
'asd'
patroni.postgresql.config.strip_comment(value: str) str