diff --git a/nixos/modules/services/cluster/patroni/default.nix b/nixos/modules/services/cluster/patroni/default.nix index aa44adb9b02c..3b3e5d03a35b 100644 --- a/nixos/modules/services/cluster/patroni/default.nix +++ b/nixos/modules/services/cluster/patroni/default.nix @@ -254,7 +254,7 @@ in lib.mapAttrs (name: path: ''export ${name}="$(< ${lib.escapeShellArg path})"'') cfg.environmentFiles ) )} - exec ${pkgs.patroni}/bin/patroni ${configFile} + exec ${lib.getExe pkgs.patroni} ${configFile} ''; serviceConfig = lib.mkMerge [ diff --git a/pkgs/by-name/pa/patroni/package.nix b/pkgs/by-name/pa/patroni/package.nix index 530fa9e3212c..23911d710b74 100644 --- a/pkgs/by-name/pa/patroni/package.nix +++ b/pkgs/by-name/pa/patroni/package.nix @@ -1,55 +1,84 @@ { - lib, - python3Packages, fetchFromGitHub, - versionCheckHook, - nixosTests, + lib, nix-update-script, - writableTmpDirAsHomeHook, + nixosTests, + python3Packages, + versionCheckHook, + + extras ? [ + # upstream requires one of: psycopg, psycopg2 + "psycopg2" + + # distributed configuration stores + "consul" + "etcd" + "etcd3" + "exhibitor" + "kubernetes" + "raft" + "zookeeper" + ], }: python3Packages.buildPythonApplication (finalAttrs: { pname = "patroni"; version = "4.1.0"; - format = "setuptools"; + pyproject = true; src = fetchFromGitHub { owner = "zalando"; repo = "patroni"; tag = "v${finalAttrs.version}"; - sha256 = "sha256-iY5QLbJXfQtfkzpQxvqSOzYQwgfFsBh8HPYujqxU44k="; + hash = "sha256-iY5QLbJXfQtfkzpQxvqSOzYQwgfFsBh8HPYujqxU44k="; }; - dependencies = with python3Packages; [ - boto3 - click - consul - dnspython - kazoo - kubernetes - prettytable - psutil - psycopg2 - pysyncobj - python-dateutil - python-etcd - pyyaml - tzlocal - urllib3 - ydiff + build-system = with python3Packages; [ setuptools ]; + + pythonRelaxDeps = [ + "ydiff" # requires <1.5 ]; + dependencies = + (with python3Packages; [ + click + consul + prettytable + psutil + python-dateutil + pyyaml + urllib3 + ydiff + ]) + ++ lib.attrVals extras finalAttrs.passthru.optional-dependencies; + + optional-dependencies = with python3Packages; { + aws = [ boto3 ]; + consul = [ consul ]; + etcd = [ python-etcd ]; + etcd3 = [ python-etcd ]; + exhibitor = [ kazoo ]; + jsonlogger = [ python-json-logger ]; + kubernetes = [ ]; + psycopg2 = [ psycopg2 ]; + psycopg2-binary = [ psycopg2-binary ]; + psycopg3 = [ psycopg ]; + raft = [ + cryptography + pysyncobj + ]; + systemd = [ systemd-python ]; + zookeeper = [ kazoo ]; + }; + pythonImportsCheck = [ "patroni" ]; - nativeCheckInputs = with python3Packages; [ - flake8 - mock - pytestCheckHook - pytest-cov-stub - requests - versionCheckHook - writableTmpDirAsHomeHook - ]; + nativeCheckInputs = + (with python3Packages; [ + pytestCheckHook + versionCheckHook + ]) + ++ lib.concatAttrValues finalAttrs.passthru.optional-dependencies; __darwinAllowLocalNetworking = true; @@ -60,14 +89,15 @@ python3Packages.buildPythonApplication (finalAttrs: { }; meta = { - homepage = "https://patroni.readthedocs.io/en/latest/"; + changelog = "https://github.com/patroni/patroni/blob/${finalAttrs.src.tag}/docs/releases.rst"; description = "Template for PostgreSQL HA with ZooKeeper, etcd or Consul"; - changelog = "https://github.com/patroni/patroni/blob/v${finalAttrs.version}/docs/releases.rst"; + homepage = "https://patroni.readthedocs.io/en/latest/"; license = lib.licenses.mit; - platforms = lib.platforms.unix; + mainProgram = "patroni"; maintainers = with lib.maintainers; [ de11n despsyched ]; + platforms = lib.platforms.unix; }; }) diff --git a/pkgs/development/python-modules/python-etcd/default.nix b/pkgs/development/python-modules/python-etcd/default.nix index def0b49aecaa..c1b3fdcba3b3 100644 --- a/pkgs/development/python-modules/python-etcd/default.nix +++ b/pkgs/development/python-modules/python-etcd/default.nix @@ -2,6 +2,7 @@ lib, stdenv, buildPythonPackage, + nix-update-script, fetchFromGitHub, setuptools, urllib3, @@ -14,16 +15,18 @@ buildPythonPackage { pname = "python-etcd"; - version = "0.5.0-unstable-2023-10-31"; + version = "0.4.5-unstable-2024-08-09"; pyproject = true; src = fetchFromGitHub { owner = "jplana"; repo = "python-etcd"; - rev = "5aea0fd4461bd05dd96e4ad637f6be7bceb1cee5"; - hash = "sha256-eVirStLOPTbf860jfkNMWtGf+r0VygLZRjRDjBMCVKg="; + rev = "d2889f7b23feee8797657b19c404f0d4034dd03c"; + hash = "sha256-osiSeBdZBT3w9pJUBxD7cI9/2T7eiyj6M6+87T8bTj0="; }; + patches = [ ./remove-getheader-usage.patch ]; + build-system = [ setuptools ]; dependencies = [ @@ -59,6 +62,10 @@ buildPythonPackage { __darwinAllowLocalNetworking = true; + passthru.updateScript = nix-update-script { + extraArgs = [ "--version=branch" ]; + }; + meta = { description = "Python client for Etcd"; homepage = "https://github.com/jplana/python-etcd"; diff --git a/pkgs/development/python-modules/python-etcd/remove-getheader-usage.patch b/pkgs/development/python-modules/python-etcd/remove-getheader-usage.patch new file mode 100644 index 000000000000..348aecf7b0ba --- /dev/null +++ b/pkgs/development/python-modules/python-etcd/remove-getheader-usage.patch @@ -0,0 +1,131 @@ +From 38ba4e559a38279417719440174df6ca2bc203c5 Mon Sep 17 00:00:00 2001 +From: Priyanshu Tripathi +Date: Fri, 16 Jan 2026 06:50:43 -0500 +Subject: [PATCH] fix: migrate away from deprecated `HTTPResponse.getheader()` + method + +With urllib3 v2.6.0, `HTTPResponse.getheader()` was removed with the alternative +being `HTTPResponse.headers`, a dictionary that can be queried with `headers.get()` + +See: https://github.com/urllib3/urllib3/pull/3622 +--- + src/etcd/__init__.py | 2 +- + src/etcd/client.py | 2 +- + src/etcd/tests/unit/__init__.py | 2 +- + src/etcd/tests/unit/test_client.py | 6 +++--- + src/etcd/tests/unit/test_old_request.py | 6 ------ + src/etcd/tests/unit/test_request.py | 4 ++-- + 6 files changed, 8 insertions(+), 14 deletions(-) + +diff --git a/src/etcd/__init__.py b/src/etcd/__init__.py +index d716e9b..e85918e 100644 +--- a/src/etcd/__init__.py ++++ b/src/etcd/__init__.py +@@ -61,7 +61,7 @@ class EtcdResult(object): + self.dir = True + + def parse_headers(self, response): +- headers = response.getheaders() ++ headers = response.headers + self.etcd_index = int(headers.get("x-etcd-index", 1)) + self.raft_index = int(headers.get("x-raft-index", 1)) + +diff --git a/src/etcd/client.py b/src/etcd/client.py +index a011757..5acea07 100644 +--- a/src/etcd/client.py ++++ b/src/etcd/client.py +@@ -975,7 +975,7 @@ class Client(object): + ) + + def _check_cluster_id(self, response, path): +- cluster_id = response.getheader("x-etcd-cluster-id") ++ cluster_id = response.headers.get("x-etcd-cluster-id") + if not cluster_id: + if self.version_prefix in path: + _log.warning("etcd response did not contain a cluster ID") +diff --git a/src/etcd/tests/unit/__init__.py b/src/etcd/tests/unit/__init__.py +index a1b95c4..43bc9b5 100644 +--- a/src/etcd/tests/unit/__init__.py ++++ b/src/etcd/tests/unit/__init__.py +@@ -22,7 +22,7 @@ class TestClientApiBase(unittest.TestCase): + r = mock.create_autospec(urllib3.response.HTTPResponse)() + r.status = s + r.data = data +- r.getheader.return_value = cluster_id or "abcd1234" ++ r.headers = {"x-etcd-cluster-id": cluster_id or "abcd1234"} + return r + + def _mock_api(self, status, d, cluster_id=None): +diff --git a/src/etcd/tests/unit/test_client.py b/src/etcd/tests/unit/test_client.py +index 37cdee1..64b2650 100644 +--- a/src/etcd/tests/unit/test_client.py ++++ b/src/etcd/tests/unit/test_client.py +@@ -121,7 +121,7 @@ class TestClient(TestClientApiBase): + """Verify _set_version_info makes the proper call to the server""" + data = {"etcdserver": "2.2.3", "etcdcluster": "2.3.0"} + self._mock_api(200, data) +- self.client.api_execute.return_value.getheader.return_value = None ++ self.client.api_execute.return_value.headers = {} + # Create the client and make the call. + self.client._set_version_info() + +@@ -135,7 +135,7 @@ class TestClient(TestClientApiBase): + """Ensure the version property is set on first access.""" + data = {"etcdserver": "2.2.3", "etcdcluster": "2.3.0"} + self._mock_api(200, data) +- self.client.api_execute.return_value.getheader.return_value = None ++ self.client.api_execute.return_value.headers = {} + + # Verify the version property is set + self.assertEqual("2.2.3", self.client.version) +@@ -144,7 +144,7 @@ class TestClient(TestClientApiBase): + """Ensure the cluster version property is set on first access.""" + data = {"etcdserver": "2.2.3", "etcdcluster": "2.3.0"} + self._mock_api(200, data) +- self.client.api_execute.return_value.getheader.return_value = None ++ self.client.api_execute.return_value.headers = {} + # Verify the cluster_version property is set + self.assertEqual("2.3.0", self.client.cluster_version) + +diff --git a/src/etcd/tests/unit/test_old_request.py b/src/etcd/tests/unit/test_old_request.py +index b660c24..f2a0410 100644 +--- a/src/etcd/tests/unit/test_old_request.py ++++ b/src/etcd/tests/unit/test_old_request.py +@@ -17,12 +17,6 @@ class FakeHTTPResponse(object): + "x-etcd-cluster-id": "abdef12345", + } + +- def getheaders(self): +- return self.headers +- +- def getheader(self, header): +- return self.headers[header] +- + + class TestClientRequest(unittest.TestCase): + def test_set(self): +diff --git a/src/etcd/tests/unit/test_request.py b/src/etcd/tests/unit/test_request.py +index 7685dca..1cb7fd1 100644 +--- a/src/etcd/tests/unit/test_request.py ++++ b/src/etcd/tests/unit/test_request.py +@@ -381,7 +381,7 @@ class TestClientRequest(TestClientApiInterface): + + def _mock_api(self, status, d, cluster_id=None): + resp = self._prepare_response(status, d) +- resp.getheader.return_value = cluster_id or "abcdef1234" ++ resp.headers = {"x-etcd-cluster-id": cluster_id or "abcdef1234"} + self.client.http.request_encode_body = mock.MagicMock(return_value=resp) + self.client.http.request = mock.MagicMock(return_value=resp) + +@@ -389,7 +389,7 @@ class TestClientRequest(TestClientApiInterface): + resp = self._prepare_response( + 500, {"errorCode": error_code, "message": msg, "cause": cause} + ) +- resp.getheader.return_value = cluster_id or "abcdef1234" ++ resp.headers = {"x-etcd-cluster-id": cluster_id or "abcdef1234"} + self.client.http.request_encode_body = mock.create_autospec( + self.client.http.request_encode_body, return_value=resp + ) +-- +2.51.0 +