From 4cbcaea9412216b124615801a32e4f8f39cec231 Mon Sep 17 00:00:00 2001 From: Francky Date: Fri, 13 Jun 2025 13:57:30 +0200 Subject: [PATCH 1/4] feat: look for deployments with maintenance.wiremind.io albels instead of ExpectedDeploymentScale --- requirements.txt | 50 ++++++++-------- src/wiremind_kubernetes/kubernetes_helper.py | 61 ++++++++------------ 2 files changed, 48 insertions(+), 63 deletions(-) diff --git a/requirements.txt b/requirements.txt index 9c264d0..4fac037 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,54 +1,50 @@ -# -# This file is autogenerated by pip-compile with Python 3.9 -# by the following command: -# -# pip-compile --no-emit-index-url setup.py -# -cachetools==5.2.0 +# This file was autogenerated by uv via the following command: +# uv pip compile --no-emit-index-url --python-platform=linux setup.py +cachetools==5.5.2 # via google-auth -certifi==2024.7.4 +certifi==2025.4.26 # via # kubernetes # requests -charset-normalizer==2.1.1 +charset-normalizer==3.4.2 # via requests -google-auth==2.11.1 +durationpy==0.10 # via kubernetes -idna==3.7 +google-auth==2.40.3 + # via kubernetes +idna==3.10 # via requests -kubernetes==24.2.0 +kubernetes==33.1.0 # via wiremind-kubernetes (setup.py) oauthlib==3.2.2 - # via requests-oauthlib -pyasn1==0.4.8 + # via + # kubernetes + # requests-oauthlib +pyasn1==0.6.1 # via # pyasn1-modules # rsa -pyasn1-modules==0.2.8 +pyasn1-modules==0.4.2 # via google-auth -python-dateutil==2.8.2 +python-dateutil==2.9.0.post0 # via kubernetes -pyyaml==6.0 +pyyaml==6.0.2 # via kubernetes -requests==2.32.3 +requests==2.32.4 # via # kubernetes # requests-oauthlib -requests-oauthlib==1.3.1 +requests-oauthlib==2.0.0 # via kubernetes -rsa==4.9 +rsa==4.9.1 # via google-auth -six==1.16.0 +six==1.17.0 # via - # google-auth # kubernetes # python-dateutil -urllib3==1.26.19 +urllib3==2.4.0 # via # kubernetes # requests -websocket-client==1.4.1 +websocket-client==1.8.0 # via kubernetes - -# The following packages are considered to be unsafe in a requirements file: -# setuptools diff --git a/src/wiremind_kubernetes/kubernetes_helper.py b/src/wiremind_kubernetes/kubernetes_helper.py index 710dd8b..7406453 100644 --- a/src/wiremind_kubernetes/kubernetes_helper.py +++ b/src/wiremind_kubernetes/kubernetes_helper.py @@ -2,6 +2,7 @@ import pprint import time from typing import Any, Dict, Generator, List, Optional, Union +from collections import defaultdict import kubernetes @@ -279,14 +280,14 @@ def __init__(self, release_name: str, **kwargs: Any): self.release_name = release_name super().__init__(**kwargs) + @retry_kubernetes_request_no_ignore def _get_expected_deployment_scale_dict(self) -> Dict[int, Dict[str, int]]: """ - Return a dict of expected deployment scale: - { - 0: { # priority - # key: Deployment name, only if it has an associated eds - # value: expected Deployment Scale (replicas) + Return a dict of priority as keys and deployments name and their expected count as values + + example: { + 0: { "my-deployment": 3, "my-other-deployment": 42 }, @@ -295,40 +296,28 @@ def _get_expected_deployment_scale_dict(self) -> Dict[int, Dict[str, int]]: }, } """ - logger.debug("Getting Expected Deployment Scale list") - eds_list: List[Dict[str, Any]] = [] + logger.debug("Getting list of deployments to scale down") + deploys: List[Dict[str, Any]] = [] release_label_keys = ["app.kubernetes.io/instance", "release"] for release_label_key in release_label_keys: - logger.debug(f"Getting Expected Deployment Scale list with the" f" release label key {release_label_key}") - try: - eds_list.extend( - self.client_custom_objects_api.list_namespaced_custom_object( - namespace=self.namespace, - group="wiremind.io", - version="v1", - plural="expecteddeploymentscales", - label_selector=f"{release_label_key}={self.release_name}", - )["items"] - ) - except kubernetes.client.rest.ApiException as e: - if e.status != 404: - raise - - eds_dict: Dict[int, Dict[str, int]] = {} - for eds in eds_list: - deployment_name: str = eds["spec"]["deploymentName"] - expected_scale: int = eds["spec"]["expectedScale"] - # Note: default should be removed once we use CRD v1 with default within the CRD itself - priority: int = eds["spec"].get("priority", 0) - - if priority not in eds_dict: - eds_dict[priority] = {} - - eds_dict[priority][deployment_name] = expected_scale - - logger.debug("Deployments are %s", pprint.pformat(eds_dict)) - return eds_dict + logger.debug("Getting list of deployments to scale down with the release label key %s", release_label_key) + deploys.extend( + self.client_appsv1_api.list_namespaced_deployment( + namespace=self.namespace, + label_selector=f"{release_label_key}={self.release_name},maintenance.wiremind.io/scale-down-required=true", + ).items + ) + + deploys_dict: Dict[int, Dict[str, int]] = defaultdict(dict) + for d in deploys: + name = d.metadata.name + priority = int(d.metadata.labels["maintenance.wiremind.io/scale-down-priority"]) + count = int(d.metadata.labels["maintenance.wiremind.io/replica-count"]) + deploys_dict[priority][name] = count + + logger.debug("Deployments are %s", pprint.pformat(deploys_dict)) + return deploys_dict def start_pods(self) -> None: """ From d537e8e95b2f9f4d07359a7177fa5fee6948f188 Mon Sep 17 00:00:00 2001 From: Francky Date: Fri, 13 Jun 2025 14:15:58 +0200 Subject: [PATCH 2/4] fix: lint --- src/wiremind_kubernetes/kubernetes_helper.py | 3 +-- .../tests/unit_tests/utils_test/run_command_test.py | 2 -- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/wiremind_kubernetes/kubernetes_helper.py b/src/wiremind_kubernetes/kubernetes_helper.py index 7406453..fb9f79a 100644 --- a/src/wiremind_kubernetes/kubernetes_helper.py +++ b/src/wiremind_kubernetes/kubernetes_helper.py @@ -280,12 +280,11 @@ def __init__(self, release_name: str, **kwargs: Any): self.release_name = release_name super().__init__(**kwargs) - @retry_kubernetes_request_no_ignore def _get_expected_deployment_scale_dict(self) -> Dict[int, Dict[str, int]]: """ Return a dict of priority as keys and deployments name and their expected count as values - + example: { 0: { "my-deployment": 3, diff --git a/src/wiremind_kubernetes/tests/unit_tests/utils_test/run_command_test.py b/src/wiremind_kubernetes/tests/unit_tests/utils_test/run_command_test.py index 00ada0b..ff15443 100644 --- a/src/wiremind_kubernetes/tests/unit_tests/utils_test/run_command_test.py +++ b/src/wiremind_kubernetes/tests/unit_tests/utils_test/run_command_test.py @@ -69,7 +69,6 @@ def test_run_command_succeeded_line_callback(mocker: MockerFixture) -> None: result = [] def line_callback(line: str) -> None: - nonlocal result result.append(line) popen_spy = mocker.spy(subprocess, "Popen") @@ -131,7 +130,6 @@ def test_run_command_failed_line_callback(mocker: MockerFixture) -> None: result = [] def line_callback(line: str) -> None: - nonlocal result result.append(line) with pytest.raises(subprocess.CalledProcessError): From bdae3635678a54f73cf75ceaae4875657d3b17a9 Mon Sep 17 00:00:00 2001 From: Francky Date: Fri, 13 Jun 2025 14:21:40 +0200 Subject: [PATCH 3/4] fix: typing --- src/wiremind_kubernetes/kubernetes_helper.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wiremind_kubernetes/kubernetes_helper.py b/src/wiremind_kubernetes/kubernetes_helper.py index fb9f79a..d76f976 100644 --- a/src/wiremind_kubernetes/kubernetes_helper.py +++ b/src/wiremind_kubernetes/kubernetes_helper.py @@ -296,7 +296,7 @@ def _get_expected_deployment_scale_dict(self) -> Dict[int, Dict[str, int]]: } """ logger.debug("Getting list of deployments to scale down") - deploys: List[Dict[str, Any]] = [] + deploys: List[kubernetes.client.V1Deployment] = [] release_label_keys = ["app.kubernetes.io/instance", "release"] for release_label_key in release_label_keys: From dcdae2efa9fc3d21a1dfbbd8c4c6f4b77e92eb1a Mon Sep 17 00:00:00 2001 From: Francky Date: Fri, 13 Jun 2025 14:57:22 +0200 Subject: [PATCH 4/4] fix: test (wip) does not work because labels cannot start with a minus sign, used for negative priority --- .../tests/e2e_tests/conftest.py | 4 - .../e2e_tests/manifests/1_deployments.yml | 30 +++++++ .../tests/e2e_tests/manifests/2_edss.yml | 85 ------------------- 3 files changed, 30 insertions(+), 89 deletions(-) delete mode 100644 src/wiremind_kubernetes/tests/e2e_tests/manifests/2_edss.yml diff --git a/src/wiremind_kubernetes/tests/e2e_tests/conftest.py b/src/wiremind_kubernetes/tests/e2e_tests/conftest.py index 0e0e8f0..b5d5994 100644 --- a/src/wiremind_kubernetes/tests/e2e_tests/conftest.py +++ b/src/wiremind_kubernetes/tests/e2e_tests/conftest.py @@ -38,10 +38,6 @@ def delete_namespace() -> None: @pytest.fixture def populate_cluster() -> Generator[None, None, None]: - run_command("helm repo add wiremind https://wiremind.github.io/wiremind-helm-charts") - run_command( - "helm install wiremind-crds wiremind/wiremind-crds --version 0.1.0", - ) try: run_command( diff --git a/src/wiremind_kubernetes/tests/e2e_tests/manifests/1_deployments.yml b/src/wiremind_kubernetes/tests/e2e_tests/manifests/1_deployments.yml index 171cf6b..c56aae2 100644 --- a/src/wiremind_kubernetes/tests/e2e_tests/manifests/1_deployments.yml +++ b/src/wiremind_kubernetes/tests/e2e_tests/manifests/1_deployments.yml @@ -2,6 +2,11 @@ apiVersion: apps/v1 kind: Deployment metadata: name: concerned + labels: + app.kubernetes.io/instance: concerned + maintenance.wiremind.io/scale-down-required: "true" + maintenance.wiremind.io/scale-down-priority: "0" + maintenance.wiremind.io/replica-count: "1" spec: replicas: 1 selector: @@ -25,6 +30,11 @@ apiVersion: apps/v1 kind: Deployment metadata: name: concerned-2 + labels: + app.kubernetes.io/instance: concerned + maintenance.wiremind.io/scale-down-required: "true" + maintenance.wiremind.io/scale-down-priority: "0" + maintenance.wiremind.io/replica-count: "2" spec: replicas: 2 selector: @@ -48,6 +58,11 @@ apiVersion: apps/v1 kind: Deployment metadata: name: concerned-high-priority + labels: + app.kubernetes.io/instance: concerned + maintenance.wiremind.io/scale-down-required: "true" + maintenance.wiremind.io/scale-down-priority: "10" + maintenance.wiremind.io/replica-count: "1" spec: replicas: 1 selector: @@ -70,6 +85,11 @@ apiVersion: apps/v1 kind: Deployment metadata: name: concerned-very-high-priority + labels: + app.kubernetes.io/instance: concerned + maintenance.wiremind.io/scale-down-required: "true" + maintenance.wiremind.io/scale-down-priority: "100" + maintenance.wiremind.io/replica-count: "1" spec: replicas: 1 selector: @@ -94,6 +114,11 @@ apiVersion: apps/v1 kind: Deployment metadata: name: concerned-low-priority + labels: + app.kubernetes.io/instance: concerned + maintenance.wiremind.io/scale-down-required: "true" + maintenance.wiremind.io/scale-down-priority: "-10" + maintenance.wiremind.io/replica-count: "1" spec: replicas: 1 selector: @@ -117,6 +142,11 @@ apiVersion: apps/v1 kind: Deployment metadata: name: unconcerned + labels: + app.kubernetes.io/instance: unconcerned + maintenance.wiremind.io/scale-down-required: "true" + maintenance.wiremind.io/scale-down-priority: "0" + maintenance.wiremind.io/replica-count: "1" spec: replicas: 1 selector: diff --git a/src/wiremind_kubernetes/tests/e2e_tests/manifests/2_edss.yml b/src/wiremind_kubernetes/tests/e2e_tests/manifests/2_edss.yml deleted file mode 100644 index 37eabf2..0000000 --- a/src/wiremind_kubernetes/tests/e2e_tests/manifests/2_edss.yml +++ /dev/null @@ -1,85 +0,0 @@ -apiVersion: "wiremind.io/v1" -kind: ExpectedDeploymentScale -metadata: - name: concerned - labels: - app.kubernetes.io/instance: concerned -spec: - deploymentName: concerned - expectedScale: 1 - ---- - -apiVersion: "wiremind.io/v1" -kind: ExpectedDeploymentScale -metadata: - name: concerned-2 - labels: - app.kubernetes.io/instance: concerned -spec: - deploymentName: concerned-2 - expectedScale: 2 - ---- - -apiVersion: "wiremind.io/v1" -kind: ExpectedDeploymentScale -metadata: - name: concerned-very-high-priority - labels: - app.kubernetes.io/instance: concerned -spec: - deploymentName: concerned-very-high-priority - expectedScale: 1 - priority: 100 - ---- - -apiVersion: "wiremind.io/v1" -kind: ExpectedDeploymentScale -metadata: - name: concerned-low-priority - labels: - app.kubernetes.io/instance: concerned -spec: - deploymentName: concerned-low-priority - expectedScale: 1 - priority: -10 - ---- - -apiVersion: "wiremind.io/v1" -kind: ExpectedDeploymentScale -metadata: - name: concerned-high-priority - labels: - app.kubernetes.io/instance: concerned -spec: - deploymentName: concerned-high-priority - expectedScale: 1 - priority: 10 - ---- - -apiVersion: "wiremind.io/v1" -kind: ExpectedDeploymentScale -metadata: - name: concerned-but-without-related-deployment - labels: - app.kubernetes.io/instance: concerned -spec: - deploymentName: concerned-but-without-related-deployment - expectedScale: 1 - priority: 10 - ---- - -apiVersion: "wiremind.io/v1" -kind: ExpectedDeploymentScale -metadata: - name: unconcerned - labels: - app.kubernetes.io/instance: unconcerned -spec: - deploymentName: unconcerned - expectedScale: 1