972 Commits

Author SHA1 Message Date
Polina Bungina
c6943dc415 Implement --print option for --validate-config (#3296) 2025-02-28 14:49:11 +01:00
Alexander Kukushkin
a316105412 Fix bug with priority failover (#3297)
We should ignor the former leader with higher priority when it reports the same LSN as the current node.

This bug could be a contributing factor to issues described in #3295


In addition to that mock socket.getaddrinfo() call in test_api.py to avoid hitting DNS servers.
2025-02-28 09:48:16 +01:00
Garaz08
92c4f9fbb5 Solve a couple of Flaky unit tests (#3294) 2025-02-25 15:39:46 +01:00
Alexander Kukushkin
b573bd4c9d Compatibility with python 3.6 (#3287)
time.time_ns() is not available
2025-02-20 15:18:52 +01:00
Alexander Kukushkin
e9ba775959 Fix a couple of bugs in quorum state machine (#3278)
1. when evaluating whether there are healthy nodes for a leader race before demoting we need to take into account quorum requirements. Without it the former leader may end up in recovery surrounded by asynchronous nodes.
2. QuorumStateResolver wasn't correctly handling the case when the replica node quickly joined and disconnected, what was resulting in the following errors:
```
  File "/home/akukushkin/git/patroni/patroni/quorum.py", line 427, in _generate_transitions
    yield from self.__remove_gone_nodes()
  File "/home/akukushkin/git/patroni/patroni/quorum.py", line 327, in __remove_gone_nodes
    yield from self.sync_update(numsync, sync)
  File "/home/akukushkin/git/patroni/patroni/quorum.py", line 227, in sync_update
    raise QuorumError(f'Sync {numsync} > N of ({sync})')
patroni.quorum.QuorumError: Sync 2 > N of ({'postgresql2'})
2025-02-14 10:18:07,058 INFO: Unexpected exception raised, please report it as a BUG

  File "/home/akukushkin/git/patroni/patroni/quorum.py", line 246, in __iter__
    transitions = list(self._generate_transitions())
  File "/home/akukushkin/git/patroni/patroni/quorum.py", line 423, in _generate_transitions
    yield from self.__handle_non_steady_cases()
  File "/home/akukushkin/git/patroni/patroni/quorum.py", line 281, in __handle_non_steady_cases
    yield from self.quorum_update(len(voters) - self.numsync, voters)
  File "/home/akukushkin/git/patroni/patroni/quorum.py", line 184, in quorum_update
    raise QuorumError(f'Quorum {quorum} < 0 of ({voters})')
patroni.quorum.QuorumError: Quorum -1 < 0 of ({'postgresql1'})
2025-02-18 15:50:48,243 INFO: Unexpected exception raised, please report it as a BUG
```
2025-02-20 11:00:22 +01:00
Alexander Kukushkin
cf427e8b0b Bump pyright to 1.1.394 (#3283) 2025-02-19 17:04:19 +01:00
Polina Bungina
5dbfc9401b Implement kubernetes.bootstrap_labels (#3257)
Allow to define labels that will be assigned to a postgres instance pod when in 'initializing new cluster', 'running custom bootstrap script', 'starting after custom bootstrap', or 'creating replica' state
2025-02-18 09:37:22 +01:00
Alexander Kukushkin
ce79152088 Take advantage of written_lsn and latest_end_lsn from pg_stat_wal_receiver (#3268)
The first one if available starting from PostgreSQL v13 and contains the
real write LSN. We will prefer it over value returned by
pg_last_wal_receive_lsn(), which is in fact flush LSN.

The second one is available starting from PostgreSQL v9.6 and  points to
WAL flush on the source host. In case of primary it will allow to better
calculate the replay lag, because values stored in DCS are updated only
every loop_wait seconds.
2025-02-17 15:06:36 +01:00
Alexander Kukushkin
6920b3af0e Cleanup after unit tests (#3277)
Close https://github.com/patroni/patroni/issues/3276
2025-02-14 13:29:34 +01:00
Michael Morris
c97ad83396 Add configuration option to suppress duplicate heartbeat logs (#3252)
Close #3251
2025-02-04 16:25:08 +01:00
Alexander Kukushkin
38aef484e8 Fix a few little issues with 9.5 support (#3260)
1. pg_rewind error log format wasn't verbose
2. it doesn't support specifying num in synchronous_standby_names
2025-01-31 16:46:07 +01:00
Alexander Kukushkin
2bc25a32e4 Avoid dropping physical slots too early (#3244)
Consider a situation: there is a permanent logical slot and primary and replica are temporary down.
When Patroni is started on the former primary it starts Postgres in a standby mode, what leads to removal of physical replication slot for the replica because it has xmin.

We should postpone removal of such physical slots:
- on replica until there will be a leader in the cluster
- on primary until Postgres is promoted
2025-01-30 13:08:30 +01:00
Alexander Kukushkin
7db7dfd3c5 Compatibility with python 3.13 (#3246)
- fix unit tests (logging now uses time.time_ns() instead of time.time())
- update setup.py
- update tox.ini
- enable unix and behave tests with 3.13

Close https://github.com/patroni/patroni/issues/3243
2025-01-20 08:58:12 +01:00
Julian
26ae38960a Improve error on empty or non dict config file (#3238)
Test if config (file) parsed with yaml_load() contains a valid Mapping
object, otherwise Patroni throws an explicit exception. It also makes
the Patroni output more explicit when using that kind of "invalid"
configuration.

``` console
$ touch /tmp/patroni.yaml
$ patroni --validate-config /tmp/patroni.yaml
/tmp/patroni.yaml does not contain a dict
invalid config file /tmp/patroni.yaml
```
reportUnnecessaryIsInstance is explicitly ignored since we can't
determine what yaml_safeload can bring from a YAML config (list,
dict,...).
2025-01-17 14:44:47 +01:00
Alexander Kukushkin
836e527e6d Fix deps compatibility, increase tests coverage i(#3233)
* Compatibility with python-json-logger>=3.1

After refactoring the old API is still working, but producing warnings
and pyright also fails.

Besides that improve coverage of watchdog/base.py and ctl.py

* Stick to ubuntu 22.04

* Please pyright
2024-12-24 09:11:17 +01:00
Polina Bungina
39f5de2e77 Implement sync_priority tag (#3223) 2024-12-10 14:57:47 +01:00
Alexander Kukushkin
a903438a5a Compatibility with ydiff==1.4.2 (#3216)
1. Implemented compatibility.
2. Constrained the upper version in requirements.txt to avoid future failures.
3. Setup an additional pipeline to check with the latest ydiff.

Close #3209
Close #3212
Close #3218
2024-11-19 09:27:49 +01:00
Alexander Kukushkin
19f75b407e Compatibility with prettytable>=3.12.0 (#3217)
They started showing deprecation warning when importing ALL and FRAME constants.
2024-11-19 09:09:09 +01:00
Kian-Meng Ang
4ce0f99cfb Fix typos (#3204)
Found via `codespell -H` and `typos --hidden --format brief`
2024-11-12 10:06:53 +01:00
Alexander Kukushkin
efba02f52e Make sure only supported parameters are written to connection string (#3207)
Close #3206
2024-11-12 09:24:30 +01:00
Alexander Kukushkin
e1faa38e90 Cache DCS instances to avoid thread leak in patronictl list -W (#3205)
Close #3202
2024-11-11 13:59:27 +01:00
Polina Bungina
7dcb9b9840 Run on_role_change cb after a failed primary recovery (#3198)
Additionally run on_role_change callback in post_recover() for a primary
that failed to start after a crash to increase chances the callback is executed,
even if the further start as a replica fails

---------

Co-authored-by: Alexander Kukushkin <cyberdemn@gmail.com>
2024-10-31 09:22:51 +01:00
Alexander Kukushkin
e8a8bfe42f Switch to py-consul (#3191)
python-consul is unmaintained for a long time and py-consul is an official replacement.
However, we still keep backward compatibility with python-consul.

Close: #3189
2024-10-28 09:58:57 +01:00
Polina Bungina
ff278705d6 Partially revert patroni@8c5ab4c (#3180)
Still check against `postgres --describe-config` if a GUC does not have
a validator but is a valid postgres GUC
2024-10-16 11:13:25 +02:00
Alexander Kukushkin
8e46086335 Recheck annotations when reading leader object on 409 (#3174)
There are cases when we may send the same PATCH request more than one time to K8s API server and it could happen that the first request actually successfully updated the target and we cancelled while waiting for a response. The second PATCH request in this case will fail due to resource_version mismatch.

So far our strategy for update_leader() method was - re-read the object and repeat the request with the new resource_version. However, we can avoid the update by comparing annotations on the read object with annotations that we wanted to set.
2024-10-02 15:06:12 +02:00
Alexander Kukushkin
e91e6b5484 Add support of sslnegotiation client-side connection option (#3173)
It is available in PostgreSQL 17

Besides that, enable PG17 in behave tests and include PG17 to supported versions in docs.
2024-09-27 11:27:09 +02:00
Alexander Kukushkin
78a46b9ebc Follow up on #3148 (#3167)
the original fix didn't address same problem with with permanent slots,
but only the part with member slots being retained due to
`member_slots_ttl`.
2024-09-17 12:02:12 +02:00
Alexander Kukushkin
d7e172c20a Don't retains member slots on nodes with nofailover tag (#3169)
Followup on #3142
2024-09-17 11:21:54 +02:00
Alexander Kukushkin
bfa9b0ca4b Fix flake8 for tests directory (#3168)
Followup on #3123
2024-09-16 17:20:00 +02:00
hadizamani021
94a592d275 Fix keepalive connection out of the range issue (#3089) (#3158) 2024-09-13 17:48:59 +02:00
Alexander Kukushkin
74a72e4f78 Fix bug in quote_standby_name() function (#3161)
According to Postgres docs "ANY" and "FIRST" keywords are supposed to be double-quoted.

Ref: https://www.postgresql.org/docs/current/runtime-config-replication.html#GUC-SYNCHRONOUS-STANDBY-NAMES
2024-09-13 14:21:22 +02:00
Waynerv
57ed40f66c Fix unhandled DCSError during startup phase (#3149)
Ensure DCS connectivity before we check node uniqueness or load dynamic configuration.
2024-09-12 08:55:05 +02:00
Alexander Kukushkin
d5d6a51e2c Make sure inactive hot physical replication slots don't hold xmin (#3148)
Since `3.2.0` Patroni is able to create physical replication slots on replica nodes just for the case if this node at some moment will become the primary.
There are two potential problems of having such slots:
1. They prevent recycling of WAL files.
2. They may affect vacuum on the primary is hot_standby_feedback is enabled.

The first class of issues is already addressed by periodically calling pg_replication_slot_advance() function.
However the second class of issues doesn't happen instantly, but only when the old primary switched to a replica. In this case physical replication slots that were at some moment activate will hold NOT NULL value of `xmin`, which will be propagated to the primary via hot_standby_feedback mechanism.

To address the second problem we will detect that a physical replication slot is not supposed to be active, but having NOT NULL `xmin` and drop/crecreate it.

Close #3146
Close #3153

Co-authored-by: Polina Bungina <27892524+hughcapet@users.noreply.github.com>
2024-09-10 08:24:26 +02:00
Alexander Kukushkin
2f800173a5 Handle exception from iterdir while discovering static files (#3152)
Close https://github.com/patroni/patroni/issues/3151
2024-09-09 15:03:20 +02:00
Polina Bungina
3ecdf01b50 Release v4.0.0 (#3141)
- bump version
- update release notes
- adjust docs
- bump pyright version
- improve unit-test coverage
2024-08-29 14:37:13 +02:00
Sahil Naphade
c9322df095 Added a new flag to ignore unsuccessful bind (#3138) 2024-08-29 09:39:38 +02:00
Alexander Kukushkin
b470ade20e Change master->primary, take two (#3127)
This commit is a breaking change:
1. `role` in DCS is written as "primary" instead of "master".
2. `role` in REST API responses is also written as "primary".
3. REST API no longer accepts role=master in requests (for example switchover/failover/restart endpoints).
4. `/metrics` REST API endpoint will no longer report `patroni_master`.
5. `patronictl` no longer accepts `--master` argument.
6. `no_master` option in declarative configuration of custom replica creation methods is no longer treated as a special option, please use `no_leader` instead.
7. `patroni_wale_restore` doesn't accept `--no_master` anymore.
8. `patroni_barman` doesn't accept `--role=master` anymore.
9. callback scripts will be executed with role=primary instead of role=master
10. On Kubernetes Patroni by default will set role label to primary. In case if you want to keep old behavior and avoid downtime or lengthy complex migrations you can configure `kubernetes.leader_label_value` and `kubernetes.standby_leader_label_value` to `master`.

However, a few exceptions regarding master are still in place:
1. `GET /master` REST API endpoint will continue to work.
2. `master_start_timeout` and `master_stop_timeout` in global configuration are still accepted.
3. `master` tag is still preserved in Consul services in addition to `primary`.

Rationale for these exceptions: DBA doesn't always 100% control the infrastructure and can't adjust the configuration.
2024-08-28 17:19:00 +02:00
Alexander Kukushkin
835d93951d Add line with localhost to pgpass when unix sockets are detected (#3139)
There are two cases when libpq may search for "localhost":
1. When host in the connection string is not specified and it is using default socket directory path.
2. When specified host matches default socket directory path.

Since we don't know the value of default socket directory path and effectively can't detect the case 2, the best strategy to mitigate the problem would be to add "localhost" if we detected a "host" be a unix socket directory (it starts with '/' character).

Close #3134
2024-08-27 13:39:03 +02:00
Alexander Kukushkin
6d65aa311a Configurable retention of members replication slots (#3108)
Current problem of Patroni that strikes many people is that it removes replication slot for member which key is expired from DCS. As a result, when the replica comes back from a scheduled maintenance WAL segments could be already absent, and it can't continue streaming without pulling files from archive.
With PostgreSQL 16 and newer we get another problem: logical slot on a standby node could be invalidated if physical replication slot on the primary was removed (and `pg_catalog` vacuumed).
The most problematic environment is Kubernetes, where slot is removed nearly instantly when member Pod is deleted.

So far, one of the recommended solutions was to configure permanent physical slots with names that match member names to avoid removal of replication slots. It works, but depending on environment might be non-trivial to implement (when for example members may change their names).

This PR implements support of `member_slots_ttl` global configuration parameter, that controls for how long member replication slots should be kept when the member key is absent. Default value is set to `30min`.
The feature is supported only starting from PostgreSQL 11 and newer, because we want to retain slots not only on the leader node, but on all nodes that could potentially become the new leader, and they should be moved forward using `pg_replication_slot_advance()` function.

One could disable feature and get back to the old behavior by setting `member_slots_ttl` to `0`.
2024-08-23 14:50:36 +02:00
Polina Bungina
8c5ab4c07d Improve GUCs validation (#3130)
Due to postgres --describe-config not showing GUCs defined as GUC_NO_SHOW_ALL | GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE, Patroni was always ignoring some GUCs that a user might want to have configured with non-default values.

- remove postgres --describe-config validation.
- define minor versions for availability bounds of some back-patched GUCs
2024-08-23 14:20:16 +02:00
Polina Bungina
31cf951b69 Remove patronictl failover --leader option (#3129)
Option has been deprecated and should be removed in the new major release
2024-08-16 10:18:18 +02:00
Waynerv
7659ccd50b Fix request URL in failsafe handling logs (#3126) 2024-08-15 16:39:56 +02:00
Alexander Kukushkin
93eb4edbe6 Reformat imports with isort (#3123)
Besides that:
1. Introduce `setup.py isort` for quick check
2. Introduce GH actions to check imports
2024-08-13 17:53:59 +02:00
GuanqunYang193
c931da1eb3 Remove user creation (#2894)
It was announced as deprecated in v3.2.0
2024-08-13 15:55:58 +02:00
Alexander Kukushkin
0fa41502f1 Register Citus secondaries in pg_dist_node (#2755)
1. All nodes with role == 'replica' and state == 'running' are are registered. In case is state isn't running the node is removed.
2. In case of failover/switchover we always first update the primary
3. When switching to a registered secondary we call citus_update_node() three times: rename primary to primary-demoted, put the primary name to a promoted secondary row and put the promoted secondary name to the primary row

State transitions are produced by the transition() method. First of all the method makes sure that the actual primary is registered in the metadata. In case if for a given group the primary didn't change, the method registers new secondaries and removes secondaries that are gone. It prefers to use citus_update_node() UDF to replace gone secondaries with added.

Communication protocol between primary nodes remains the same and all old features work without any changes.
2024-08-13 09:12:03 +02:00
Alexander Kukushkin
384705ad97 Quorum based failover (#2668)
To enable quorum commit:
```diff
$ patronictl.py edit-config
--- 
+++ 
@@ -5,3 +5,4 @@
   use_pg_rewind: true
 retry_timeout: 10
 ttl: 30
+synchronous_mode: quorum

Apply these changes? [y/N]: y
Configuration changed
```

By default Patroni will use `ANY 1(list,of,stanbys)` in `synchronous_standby_names`. That is, only one node out of listed replicas will be used for quorum.
If you want to increase the number of quorum nodes it is possible to do it with:
```diff
$ patronictl edit-config
--- 
+++ 
@@ -6,3 +6,4 @@
 retry_timeout: 10
 synchronous_mode: quorum
 ttl: 30
+synchronous_node_count: 2

Apply these changes? [y/N]: y
Configuration changed
```

Good old `synchronous_mode: on` is still supported.

Close https://github.com/patroni/patroni/issues/664
Close https://github.com/zalando/patroni/pull/672
2024-08-13 08:51:01 +02:00
Alexander Kukushkin
56dba93c55 Implement support of log.mode. (#3122)
There was one oversight of #2781 - to influence external tools that Patroni could execute, we set global `umask` value based on permissions of the $PGDATA directory. As a result, it also influenced permissions of log files created by Patroni.

To address the problem we implement two measures:
1. Make `log.mode` configurable.
2. If the value is not set - calculate permissions from the original value of the umask setting.
2024-08-13 08:11:28 +02:00
Alexander Kukushkin
b458bd992a Use get_parameter_status() method instead of Connection.info.parameter_status() (#3119)
The last one is only available since psycopg 2.8, while the first one since 2.0.8.
For backward compatibility monkeypatch connection object returned by psycopg3.

Close https://github.com/patroni/patroni/issues/3116
2024-08-12 15:17:36 +02:00
Alexander Kukushkin
cd3f52b029 Don't let the current node be chosen as synchronous (#3112)
It could happen that there is "something" streaming from the current primary node with `application_name` that matches name of the current primary, for instance due to a faulty configuration. When processing `pg_stat_replication` we only checked that the `application_name` matches with the name one of the member nodes, but we forgot to exclude our own name.
As a result there were following side-effects:
1. The current primary could be declared as a synchronous node.
2. As a result of [1] it wasn't possible to do a switchover.
3. During shutdown the current primary was waiting for itself to release it from synchronous nodes.

Close #3111
2024-07-29 15:43:16 +02:00
Alexander Kukushkin
c6339234c6 Refactor update_leader() method (#3107)
Pass the `Cluster` object instead of `Leader`.
It will help to implement a new feature, "Configurable retention of replication slots for cluster members".

Besides that fix a couple of issues with docstrings.
2024-07-18 08:28:54 +02:00