diff --git a/caprover/gc-stack-deploy/src/gc_stack_deploy/apps_registry.py b/caprover/gc-stack-deploy/src/gc_stack_deploy/apps_registry.py index 636d62b..2ed4522 100644 --- a/caprover/gc-stack-deploy/src/gc_stack_deploy/apps_registry.py +++ b/caprover/gc-stack-deploy/src/gc_stack_deploy/apps_registry.py @@ -49,6 +49,21 @@ def set_yaml_value(yaml_str: str | None, key: str | list[str], value: object) -> return buf.getvalue() +def disable_healthcheck(suo: str | None) -> str: + """ + Return a serviceUpdateOverride YAML with the Docker healthcheck disabled. + + HealthCheck gets nested under TaskTemplate.ContainerSpec; I can't find + documentation for that, you will have to trust me (from trial-and-error). + + TaskTemplate: + ContainerSpec: + HealthCheck: + Test: ["NONE"] + """ + return set_yaml_value(suo, "TaskTemplate.ContainerSpec.HealthCheck.Test", ["NONE"]) + + def set_memory_limit(cap, appname, memory_bytes=1610612736): app = cap.get_app(appname) new_suo = set_yaml_value( @@ -311,11 +326,7 @@ def _install(self) -> None: f"{self.app_name}-worker", ): worker_app = cap.get_app(appname) - new_suo = set_yaml_value( - worker_app["serviceUpdateOverride"], - "TaskTemplate.HealthCheck.Test", - ["NONE"], - ) + new_suo = disable_healthcheck(worker_app["serviceUpdateOverride"]) # Also set memory limit to workers new_suo = set_yaml_value( new_suo, "TaskTemplate.Resources.Limits.MemoryBytes", 1610612736 diff --git a/caprover/gc-stack-deploy/tests/apps_registry_test.py b/caprover/gc-stack-deploy/tests/apps_registry_test.py new file mode 100644 index 0000000..45b6d72 --- /dev/null +++ b/caprover/gc-stack-deploy/tests/apps_registry_test.py @@ -0,0 +1,77 @@ +import pytest +from ruamel.yaml import YAML + +from gc_stack_deploy.apps_registry import disable_healthcheck, set_yaml_value + + +def load_yaml(s): + return YAML().load(s) + + +class TestSetYamlValue: + def test_creates_nested_keys_from_scratch(self): + result = set_yaml_value(None, "A.B.C", 42) + assert load_yaml(result) == {"A": {"B": {"C": 42}}} + + def test_sets_value_in_existing_document(self): + existing = ( + "A:\n" + " B:\n" + " C: 1\n" + ) + result = set_yaml_value(existing, "A.B.C", 99) + assert load_yaml(result)["A"]["B"]["C"] == 99 + + def test_preserves_sibling_keys(self): + existing = ( + "A:\n" + " X: kept\n" + " B:\n" + " C: 1\n" + ) + result = set_yaml_value(existing, "A.B.C", 2) + data = load_yaml(result) + assert data["A"]["X"] == "kept" + assert data["A"]["B"]["C"] == 2 + + def test_accepts_list_key(self): + result = set_yaml_value(None, ["A", "B"], "v") + assert load_yaml(result) == {"A": {"B": "v"}} + + def test_empty_string_treated_as_empty(self): + result = set_yaml_value("", "K", "v") + assert load_yaml(result) == {"K": "v"} + + def test_list_value(self): + result = set_yaml_value(None, "A.B", ["NONE"]) + assert load_yaml(result) == {"A": {"B": ["NONE"]}} + + +class TestDisableHealthcheck: + HEALTHCHECK_ONLY = ( + "TaskTemplate:\n" + " ContainerSpec:\n" + " HealthCheck:\n" + " Test:\n" + " - NONE\n" + ) + + def test_none_input(self): + assert disable_healthcheck(None) == self.HEALTHCHECK_ONLY + + def test_empty_string_input(self): + assert disable_healthcheck("") == self.HEALTHCHECK_ONLY + + def test_disables_on_existing_suo(self): + existing = "TaskTemplate:\n Resources:\n Limits:\n MemoryBytes: 1024\n" + expected = ( + "TaskTemplate:\n" + " Resources:\n" + " Limits:\n" + " MemoryBytes: 1024\n" + " ContainerSpec:\n" + " HealthCheck:\n" + " Test:\n" + " - NONE\n" + ) + assert disable_healthcheck(existing) == expected