Skip to content

Commit

Permalink
Update cluster_node_count to account for the quorum_standby state
Browse files Browse the repository at this point in the history
  • Loading branch information
blogh committed Dec 23, 2024
1 parent 104fceb commit 3b9fcc9
Show file tree
Hide file tree
Showing 6 changed files with 140 additions and 3 deletions.
2 changes: 1 addition & 1 deletion check_patroni/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ def cluster_node_count(
The "healthy" checks only ensures that:
* a leader has the running state
* a standby_leader has the running or streaming (V3.0.4) state
* a replica or sync-standby has the running or streaming (V3.0.4) state
* a replica, quorum standby or sync-standby has the running or streaming (V3.0.4) state
Since we dont check the lag or timeline, "in archive recovery" is not considered a valid state
for this service. See cluster_has_leader and cluster_has_replica for specialized checks.
Expand Down
7 changes: 6 additions & 1 deletion check_patroni/cluster.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,12 @@ def debug_member(member: Any, health: str) -> None:
debug_member(member, "healthy")
continue

if role in ["standby_leader", "replica", "sync_standby"] and (
if role in [
"standby_leader",
"replica",
"sync_standby",
"quorum_standby",
] and (
(self.has_detailed_states() and state == "streaming")
or (not self.has_detailed_states() and state == "running")
):
Expand Down
7 changes: 6 additions & 1 deletion tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,12 @@ def cluster_api_set_replica_running(in_json: Path, target_dir: Path) -> Path:
with in_json.open() as f:
js = json.load(f)
for node in js["members"]:
if node["role"] in ["replica", "sync_standby", "standby_leader"]:
if node["role"] in [
"replica",
"sync_standby",
"standby_leader",
"quorum_standby",
]:
if node["state"] in ["streaming", "in archive recovery"]:
node["state"] = "running"
assert target_dir.is_dir()
Expand Down
33 changes: 33 additions & 0 deletions tests/json/cluster_node_count_ok_quorum.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"members": [
{
"name": "srv1",
"role": "leader",
"state": "running",
"api_url": "https://10.20.199.3:8008/patroni",
"host": "10.20.199.3",
"port": 5432,
"timeline": 51
},
{
"name": "srv2",
"role": "quorum_standby",
"state": "streaming",
"api_url": "https://10.20.199.4:8008/patroni",
"host": "10.20.199.4",
"port": 5432,
"timeline": 51,
"lag": 0
},
{
"name": "srv3",
"role": "quorum_standby",
"state": "streaming",
"api_url": "https://10.20.199.5:8008/patroni",
"host": "10.20.199.5",
"port": 5432,
"timeline": 51,
"lag": 0
}
]
}
33 changes: 33 additions & 0 deletions tests/json/cluster_node_count_ok_sync.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"members": [
{
"name": "srv1",
"role": "leader",
"state": "running",
"api_url": "https://10.20.199.3:8008/patroni",
"host": "10.20.199.3",
"port": 5432,
"timeline": 51
},
{
"name": "srv2",
"role": "sync_standby",
"state": "streaming",
"api_url": "https://10.20.199.4:8008/patroni",
"host": "10.20.199.4",
"port": 5432,
"timeline": 51,
"lag": 0
},
{
"name": "srv3",
"role": "replica",
"state": "streaming",
"api_url": "https://10.20.199.5:8008/patroni",
"host": "10.20.199.5",
"port": 5432,
"timeline": 51,
"lag": 0
}
]
}
61 changes: 61 additions & 0 deletions tests/test_cluster_node_count.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,67 @@ def test_cluster_node_count_ok(
assert result.exit_code == 0


@pytest.fixture
def cluster_node_count_ok_sync(
patroni_api: PatroniAPI, old_replica_state: bool, datadir: Path, tmp_path: Path
) -> Iterator[None]:
cluster_path: Union[str, Path] = "cluster_node_count_ok_sync.json"
patroni_path = "cluster_has_replica_patroni_verion_3.1.0.json"
if old_replica_state:
cluster_path = cluster_api_set_replica_running(datadir / cluster_path, tmp_path)
patroni_path = "cluster_has_replica_patroni_verion_3.0.0.json"
with patroni_api.routes({"cluster": cluster_path, "patroni": patroni_path}):
yield None


@pytest.mark.usefixtures("cluster_node_count_ok_sync")
def test_cluster_node_count_ok_sync(
runner: CliRunner, patroni_api: PatroniAPI, old_replica_state: bool
) -> None:
result = runner.invoke(main, ["-e", patroni_api.endpoint, "cluster_node_count"])
if old_replica_state:
assert (
result.output
== "CLUSTERNODECOUNT OK - members is 3 | healthy_members=3 members=3 role_leader=1 role_replica=1 role_sync_standby=1 state_running=3\n"
)
else:
assert (
result.output
== "CLUSTERNODECOUNT OK - members is 3 | healthy_members=3 members=3 role_leader=1 role_replica=1 role_sync_standby=1 state_running=1 state_streaming=2\n"
)
assert result.exit_code == 0


@pytest.fixture
def cluster_node_count_ok_quorum(
patroni_api: PatroniAPI, old_replica_state: bool, datadir: Path, tmp_path: Path
) -> Iterator[None]:
cluster_path: Union[str, Path] = "cluster_node_count_ok_quorum.json"
patroni_path = "cluster_has_replica_patroni_verion_3.1.0.json"
if old_replica_state:
cluster_path = cluster_api_set_replica_running(datadir / cluster_path, tmp_path)
patroni_path = "cluster_has_replica_patroni_verion_3.0.0.json"
with patroni_api.routes({"cluster": cluster_path, "patroni": patroni_path}):
yield None


@pytest.mark.usefixtures("cluster_node_count_ok_quorum")
def test_cluster_node_count_ok_quorum(
runner: CliRunner, patroni_api: PatroniAPI, old_replica_state: bool
) -> None:
result = runner.invoke(main, ["-e", patroni_api.endpoint, "cluster_node_count"])
if old_replica_state:
assert (
result.output
== "CLUSTERNODECOUNT OK - members is 3 | healthy_members=3 members=3 role_leader=1 role_quorum_standby=2 state_running=3\n"
)
else:
assert (
result.output
== "CLUSTERNODECOUNT OK - members is 3 | healthy_members=3 members=3 role_leader=1 role_quorum_standby=2 state_running=1 state_streaming=2\n"
)


@pytest.mark.usefixtures("cluster_node_count_ok")
def test_cluster_node_count_ok_with_thresholds(
runner: CliRunner, patroni_api: PatroniAPI, old_replica_state: bool
Expand Down

0 comments on commit 3b9fcc9

Please sign in to comment.