Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Changelog

## v7.0.2 (2026-10-05)

### Fix
- `is_deployment_stopped` no longer counts a Pod in phase `Succeeded` (`Completed`) as a living
replica. A Deployment holding one was never seen as stopped, so the migration waited until an
operator deleted the Pod by hand. Terminal phases are now a real tuple, `("Failed", "Succeeded")`,
instead of the string `("Failed")`, which made `not in` a substring test.

## v7.0.1 (2026-07-09)

### Fix
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
7.0.1
7.0.2
4 changes: 3 additions & 1 deletion src/chartreuse/kubernetes_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
# (re_enable_hpa) remains, for HPAs left renamed by an older chartreuse.
# TODO: remove in 8.0 together with re_enable_hpa.
HPA_ID_PREFIX = "wm--disabled--kube"
# A Pod in a terminal phase holds no resource: it is not a living replica.
TERMINAL_POD_PHASES = ("Failed", "Succeeded")
# Set by stop_pods() on every Deployment it scales down, cleared by start_pods() and
# restore_stopped_pods(). Allows telling "stopped by us" apart from "deliberately scaled to 0".
STOPPED_ANNOTATION = "wiremind.io/stopped-by"
Expand Down Expand Up @@ -184,7 +186,7 @@ def is_deployment_stopped(self, deployment_name: str) -> bool:

current_scale = 0
for pod in pod_list:
if pod.status.phase not in ("Failed"):
if pod.status.phase not in TERMINAL_POD_PHASES:
current_scale += 1

if current_scale > 0:
Expand Down
24 changes: 24 additions & 0 deletions src/chartreuse/tests/unit_tests/test_kubernetes_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import unittest

import kubernetes
import pytest
from pytest_mock import MockerFixture

from chartreuse.kubernetes_helper import PAUSED_ANNOTATION, STOPPED_ANNOTATION, KubernetesDeploymentManager
Expand Down Expand Up @@ -275,3 +276,26 @@ def test_resume_hpa_restores_original_behavior(mocker: MockerFixture) -> None:
body={"metadata": {"annotations": {PAUSED_ANNOTATION: None}}, "spec": {"behavior": None}},
),
]


@pytest.mark.parametrize(
"phase, expected_stopped",
[
("Failed", True),
("Succeeded", True),
("Running", False),
("Pending", False),
],
)
def test_is_deployment_stopped(mocker: MockerFixture, phase: str, expected_stopped: bool) -> None:
"""
Test that we only consider Pods in a non-terminal phase as living Pods.

A Failed (like evicted) or Succeeded (Completed) Pod holds no resource.
"""
kdm = _make_kdm(mocker)
pod = mocker.MagicMock()
pod.status.phase = phase
mocker.patch.object(kdm, "_get_pods_from_deployment", return_value=[pod])

assert kdm.is_deployment_stopped("worker") is expected_stopped
Loading