chartreuse 7.0.0.dev1__tar.gz → 7.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {chartreuse-7.0.0.dev1/src/chartreuse.egg-info → chartreuse-7.0.1}/PKG-INFO +1 -1
- chartreuse-7.0.1/VERSION +1 -0
- {chartreuse-7.0.0.dev1 → chartreuse-7.0.1}/src/chartreuse/chartreuse_restore.py +2 -0
- {chartreuse-7.0.0.dev1 → chartreuse-7.0.1}/src/chartreuse/kubernetes_helper.py +57 -8
- {chartreuse-7.0.0.dev1 → chartreuse-7.0.1/src/chartreuse.egg-info}/PKG-INFO +1 -1
- chartreuse-7.0.0.dev1/VERSION +0 -1
- {chartreuse-7.0.0.dev1 → chartreuse-7.0.1}/LICENCE.md +0 -0
- {chartreuse-7.0.0.dev1 → chartreuse-7.0.1}/MANIFEST.in +0 -0
- {chartreuse-7.0.0.dev1 → chartreuse-7.0.1}/README.md +0 -0
- {chartreuse-7.0.0.dev1 → chartreuse-7.0.1}/pyproject.toml +0 -0
- {chartreuse-7.0.0.dev1 → chartreuse-7.0.1}/setup.cfg +0 -0
- {chartreuse-7.0.0.dev1 → chartreuse-7.0.1}/src/chartreuse/__init__.py +0 -0
- {chartreuse-7.0.0.dev1 → chartreuse-7.0.1}/src/chartreuse/chartreuse.py +0 -0
- {chartreuse-7.0.0.dev1 → chartreuse-7.0.1}/src/chartreuse/chartreuse_upgrade.py +0 -0
- {chartreuse-7.0.0.dev1 → chartreuse-7.0.1}/src/chartreuse/config_loader.py +0 -0
- {chartreuse-7.0.0.dev1 → chartreuse-7.0.1}/src/chartreuse/utils/__init__.py +0 -0
- {chartreuse-7.0.0.dev1 → chartreuse-7.0.1}/src/chartreuse/utils/alembic_migration_helper.py +0 -0
- {chartreuse-7.0.0.dev1 → chartreuse-7.0.1}/src/chartreuse/utils/command.py +0 -0
- {chartreuse-7.0.0.dev1 → chartreuse-7.0.1}/src/chartreuse.egg-info/SOURCES.txt +0 -0
- {chartreuse-7.0.0.dev1 → chartreuse-7.0.1}/src/chartreuse.egg-info/dependency_links.txt +0 -0
- {chartreuse-7.0.0.dev1 → chartreuse-7.0.1}/src/chartreuse.egg-info/entry_points.txt +0 -0
- {chartreuse-7.0.0.dev1 → chartreuse-7.0.1}/src/chartreuse.egg-info/requires.txt +0 -0
- {chartreuse-7.0.0.dev1 → chartreuse-7.0.1}/src/chartreuse.egg-info/top_level.txt +0 -0
- {chartreuse-7.0.0.dev1 → chartreuse-7.0.1}/src/chartreuse.egg-info/zip-safe +0 -0
chartreuse-7.0.1/VERSION
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
7.0.1
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
import os
|
|
3
3
|
|
|
4
|
+
from .chartreuse import configure_logging
|
|
4
5
|
from .chartreuse_upgrade import ensure_safe_run
|
|
5
6
|
from .kubernetes_helper import KubernetesDeploymentManager
|
|
6
7
|
|
|
@@ -22,6 +23,7 @@ def main() -> None:
|
|
|
22
23
|
the annotation set by stop_pods() are touched. If this program fails, the deployment is
|
|
23
24
|
considered as failed: stranded workers must be visible, not a log line.
|
|
24
25
|
"""
|
|
26
|
+
configure_logging()
|
|
25
27
|
ensure_safe_run()
|
|
26
28
|
|
|
27
29
|
release_name: str = os.environ["CHARTREUSE_RELEASE_NAME"]
|
|
@@ -9,6 +9,7 @@ Depends only on the official kubernetes client.
|
|
|
9
9
|
"""
|
|
10
10
|
|
|
11
11
|
import functools
|
|
12
|
+
import json
|
|
12
13
|
import logging
|
|
13
14
|
import os
|
|
14
15
|
import pprint
|
|
@@ -20,10 +21,16 @@ import kubernetes
|
|
|
20
21
|
|
|
21
22
|
logger = logging.getLogger(__name__)
|
|
22
23
|
|
|
24
|
+
# Target-rename prefix used by the pre-7.0.1 HPA disable mechanism. Only the repair path
|
|
25
|
+
# (re_enable_hpa) remains, for HPAs left renamed by an older chartreuse.
|
|
26
|
+
# TODO: remove in 8.0 together with re_enable_hpa.
|
|
23
27
|
HPA_ID_PREFIX = "wm--disabled--kube"
|
|
24
28
|
# Set by stop_pods() on every Deployment it scales down, cleared by start_pods() and
|
|
25
29
|
# restore_stopped_pods(). Allows telling "stopped by us" apart from "deliberately scaled to 0".
|
|
26
30
|
STOPPED_ANNOTATION = "wiremind.io/stopped-by"
|
|
31
|
+
# Set by pause_hpa() on the HPA itself; stores the pre-pause spec.behavior as JSON ("" when
|
|
32
|
+
# absent) so resume_hpa() can restore it exactly. Presence of the annotation == "paused by us".
|
|
33
|
+
PAUSED_ANNOTATION = "wiremind.io/pre-pause-scale-behavior"
|
|
27
34
|
|
|
28
35
|
|
|
29
36
|
def load_kubernetes_config(use_kubeconfig: bool | None = None) -> None:
|
|
@@ -254,14 +261,51 @@ class KubernetesDeploymentManager:
|
|
|
254
261
|
return eds_dict
|
|
255
262
|
|
|
256
263
|
@retry_kubernetes_request
|
|
257
|
-
def
|
|
264
|
+
def pause_hpa(self, *, deployment_name: str) -> None:
|
|
265
|
+
"""
|
|
266
|
+
Forbid the Deployment's HPAs from scaling up (spec.behavior.scaleUp.selectPolicy:
|
|
267
|
+
Disabled) so they can't start pods mid-migration. Unlike breaking the scaleTargetRef,
|
|
268
|
+
the HPA stays Healthy: no FailedGetScale events, no Degraded ArgoCD application.
|
|
269
|
+
|
|
270
|
+
The pre-pause spec.behavior is saved in PAUSED_ANNOTATION so resume_hpa() can restore
|
|
271
|
+
it exactly. Idempotent: an already-paused HPA is left alone (never overwrite the
|
|
272
|
+
saved original with a paused state).
|
|
273
|
+
"""
|
|
258
274
|
for hpa in self.get_deployment_hpa(deployment_name=deployment_name):
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
self.
|
|
275
|
+
if PAUSED_ANNOTATION in (hpa.metadata.annotations or {}):
|
|
276
|
+
continue
|
|
277
|
+
original_behavior = self.client_autoscalingv2_api.api_client.sanitize_for_serialization(hpa.spec.behavior)
|
|
278
|
+
saved = json.dumps(original_behavior) if original_behavior else ""
|
|
279
|
+
body = {
|
|
280
|
+
"metadata": {"annotations": {PAUSED_ANNOTATION: saved}},
|
|
281
|
+
"spec": {"behavior": {"scaleUp": {"selectPolicy": "Disabled"}}},
|
|
282
|
+
}
|
|
283
|
+
self.patch_deployment_hpa(hpa_name=hpa.metadata.name, body=body)
|
|
284
|
+
|
|
285
|
+
@retry_kubernetes_request
|
|
286
|
+
def resume_hpa(self, *, deployment_name: str) -> None:
|
|
287
|
+
"""
|
|
288
|
+
Undo pause_hpa(): restore the exact pre-pause spec.behavior (or clear it when there
|
|
289
|
+
was none) and drop PAUSED_ANNOTATION. No-op on HPAs that don't carry the annotation,
|
|
290
|
+
so it is always safe to call.
|
|
291
|
+
"""
|
|
292
|
+
for hpa in self.get_deployment_hpa(deployment_name=deployment_name):
|
|
293
|
+
saved = (hpa.metadata.annotations or {}).get(PAUSED_ANNOTATION)
|
|
294
|
+
if saved is None:
|
|
295
|
+
continue
|
|
296
|
+
body = {
|
|
297
|
+
"metadata": {"annotations": {PAUSED_ANNOTATION: None}},
|
|
298
|
+
"spec": {"behavior": json.loads(saved) if saved else None},
|
|
299
|
+
}
|
|
300
|
+
self.patch_deployment_hpa(hpa_name=hpa.metadata.name, body=body)
|
|
262
301
|
|
|
263
302
|
@retry_kubernetes_request
|
|
264
303
|
def re_enable_hpa(self, *, deployment_name: str) -> None:
|
|
304
|
+
"""
|
|
305
|
+
Repair an HPA left pointing at a wm--disabled--kube- target by a pre-7.0.1 chartreuse
|
|
306
|
+
whose run crashed before re-enabling. 7.0.1+ never creates such renames.
|
|
307
|
+
TODO: remove in 8.0.
|
|
308
|
+
"""
|
|
265
309
|
for hpa in self.get_deployment_hpa(deployment_name=f"{HPA_ID_PREFIX}-{deployment_name}"):
|
|
266
310
|
hpa.spec.scale_target_ref.name = deployment_name
|
|
267
311
|
self.patch_deployment_hpa(hpa_name=hpa.metadata.name, body=hpa)
|
|
@@ -278,9 +322,9 @@ class KubernetesDeploymentManager:
|
|
|
278
322
|
"""
|
|
279
323
|
for deployment_name in deployment_dict:
|
|
280
324
|
self.annotate_deployment(deployment_name, {STOPPED_ANNOTATION: self.release_name})
|
|
325
|
+
self.pause_hpa(deployment_name=deployment_name)
|
|
281
326
|
for _ in range(self.SCALE_DOWN_MAX_WAIT_TIME):
|
|
282
327
|
for deployment_name in deployment_dict:
|
|
283
|
-
self.disable_hpa(deployment_name=deployment_name)
|
|
284
328
|
self.scale_down_deployment(deployment_name)
|
|
285
329
|
if self._are_deployments_stopped(deployment_dict):
|
|
286
330
|
break
|
|
@@ -324,6 +368,7 @@ class KubernetesDeploymentManager:
|
|
|
324
368
|
if len(priority_dict):
|
|
325
369
|
scaled = True
|
|
326
370
|
for name, expected_scale in priority_dict.items():
|
|
371
|
+
self.resume_hpa(deployment_name=name)
|
|
327
372
|
self.re_enable_hpa(deployment_name=name)
|
|
328
373
|
self.scale_up_deployment(name, expected_scale)
|
|
329
374
|
self.annotate_deployment(name, {STOPPED_ANNOTATION: None})
|
|
@@ -336,8 +381,11 @@ class KubernetesDeploymentManager:
|
|
|
336
381
|
"""
|
|
337
382
|
Restore Deployments that stop_pods() scaled down and that nothing scaled back up since.
|
|
338
383
|
|
|
339
|
-
Only
|
|
340
|
-
|
|
384
|
+
Only the replica restore is gated on STOPPED_ANNOTATION, so a Deployment deliberately
|
|
385
|
+
scaled to zero outside of stop_pods() is left alone. HPA resume/repair on the other
|
|
386
|
+
hand runs for EVERY tracked Deployment: a pause left behind by a crashed run is not
|
|
387
|
+
self-healing (ArgoCD ignores the live-only spec.behavior field), and resuming an
|
|
388
|
+
unpaused HPA is a no-op.
|
|
341
389
|
|
|
342
390
|
Meant to run after the deployment that follows a stop_pods() without start_pods()
|
|
343
391
|
(CHARTREUSE_UPGRADE_BEFORE_DEPLOYMENT): that deployment restores spec.replicas of
|
|
@@ -351,6 +399,8 @@ class KubernetesDeploymentManager:
|
|
|
351
399
|
restored: list[str] = []
|
|
352
400
|
for priority in sorted(expected_deployment_scale_dict):
|
|
353
401
|
for name, expected_scale in expected_deployment_scale_dict[priority].items():
|
|
402
|
+
self.resume_hpa(deployment_name=name)
|
|
403
|
+
self.re_enable_hpa(deployment_name=name)
|
|
354
404
|
try:
|
|
355
405
|
deployment = self.client_appsv1_api.read_namespaced_deployment(name, self.namespace)
|
|
356
406
|
except kubernetes.client.rest.ApiException as e:
|
|
@@ -359,7 +409,6 @@ class KubernetesDeploymentManager:
|
|
|
359
409
|
raise
|
|
360
410
|
if STOPPED_ANNOTATION not in (deployment.metadata.annotations or {}):
|
|
361
411
|
continue
|
|
362
|
-
self.re_enable_hpa(deployment_name=name)
|
|
363
412
|
if not deployment.spec.replicas:
|
|
364
413
|
target_scale = expected_scale
|
|
365
414
|
if target_scale < 1 and any(self.get_deployment_hpa(deployment_name=name)):
|
chartreuse-7.0.0.dev1/VERSION
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
7.0.0.dev1
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|