From 61bc254346f31828d0c77d5e2a648a8805e04bd1 Mon Sep 17 00:00:00 2001 From: Michael Sherman Date: Wed, 18 Feb 2026 10:34:31 -0600 Subject: [PATCH 1/6] deprecate platform_version arg all hosts are now on "version 2", and we can remove this logic. --- chi/container.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/chi/container.py b/chi/container.py index b3cadb5..c5601dd 100644 --- a/chi/container.py +++ b/chi/container.py @@ -373,7 +373,6 @@ def create_container( reservation_id: "str" = None, start: "bool" = True, start_timeout: "int" = None, - platform_version: "int" = 2, **kwargs, ): """ @@ -438,16 +437,9 @@ def create_container( LOG.info(f"Waiting up to {timeout}s for container creation ...") try: - if platform_version == 2: container = _wait_for_status(container.uuid, "Running", timeout=timeout) - else: - container = _wait_for_status(container.uuid, "Created", timeout=timeout) - if start: - LOG.info("Starting container ...") - zun().containers.start(container.uuid) except (RuntimeError, TimeoutError) as exc: raise ContainerCreateWaitError(zun_container=container, cause=exc) from exc - return container From 65bdc69221f82794ef3223f8f31302aff88c903d Mon Sep 17 00:00:00 2001 From: Michael Sherman Date: Wed, 18 Feb 2026 10:36:42 -0600 Subject: [PATCH 2/6] remove "wait_for_status" from create_container with this change, create_container becomes a very simple wrapper to translate parameters into what zun expects. This removes the need for complex logic to pass the zun container to callers via error handling. --- chi/container.py | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/chi/container.py b/chi/container.py index c5601dd..95f3f75 100644 --- a/chi/container.py +++ b/chi/container.py @@ -371,8 +371,6 @@ def create_container( image: "str" = None, exposed_ports: "list[str]" = None, reservation_id: "str" = None, - start: "bool" = True, - start_timeout: "int" = None, **kwargs, ): """ @@ -408,8 +406,6 @@ def create_container( hints = kwargs.setdefault("hints", {}) if reservation_id: hints["reservation"] = reservation_id - if platform_version: - hints["platform_version"] = platform_version # Support simpler syntax for exposed_ports if exposed_ports and isinstance(exposed_ports, list): @@ -430,16 +426,6 @@ def create_container( **kwargs, ) - # Wait for a while, the image may need to download. 30 minutes is - # _quite_ a long time, but the user can interrupt or choose a smaller - # timeout. - timeout = start_timeout or (60 * 30) - LOG.info(f"Waiting up to {timeout}s for container creation ...") - - try: - container = _wait_for_status(container.uuid, "Running", timeout=timeout) - except (RuntimeError, TimeoutError) as exc: - raise ContainerCreateWaitError(zun_container=container, cause=exc) from exc return container From dde54c7853c7757f43adf84cf443898e687ac650 Mon Sep 17 00:00:00 2001 From: Michael Sherman Date: Wed, 18 Feb 2026 10:47:32 -0600 Subject: [PATCH 3/6] remove references to start, start_timeout --- chi/container.py | 43 +++++++++++++++---------------------------- 1 file changed, 15 insertions(+), 28 deletions(-) diff --git a/chi/container.py b/chi/container.py index 95f3f75..036a2dc 100644 --- a/chi/container.py +++ b/chi/container.py @@ -28,7 +28,7 @@ from .clients import connection, zun from .context import session -from .exception import ContainerCreateWaitError, ResourceError, ServiceError +from .exception import ServiceError from .network import bind_floating_ip, get_free_floating_ip DEFAULT_IMAGE_DRIVER = "docker" @@ -72,8 +72,6 @@ def __init__( image_ref: str, exposed_ports: List[str] = None, reservation_id: str = None, - start: bool = True, - start_timeout: int = 0, runtime: str = None, command: List[str] = None, workdir: str = None, @@ -84,8 +82,6 @@ def __init__( self.image_ref = image_ref self.exposed_ports = exposed_ports self.reservation_id = reservation_id - self.start = start - self.start_timeout = start_timeout self.runtime = runtime self.id = None self.created_at = None @@ -101,7 +97,6 @@ def from_zun_container(cls, zun_container): name=zun_container.name, image_ref=zun_container.image, exposed_ports=zun_container.ports if zun_container.ports else [], - start=True, # Assuming the container is already created ) container.id = zun_container.uuid container._status = zun_container.status @@ -150,28 +145,20 @@ def submit( if self.workdir: kwargs["workdir"] = self.workdir - try: - container = create_container( - name=self.name, - image=self.image_ref, - exposed_ports=self.exposed_ports, - reservation_id=self.reservation_id, - start=self.start, - start_timeout=self.start_timeout, - runtime=self.runtime, - environment=self.environment, - device_profiles=self.device_profiles, - **kwargs, - ) - self.id = container.uuid - self._status = container.status - except ContainerCreateWaitError as exc: - # ensure container object gets params even on error - self.id = exc.zun_container.uuid - self._status = exc.zun_container.status - raise ResourceError(message=exc.zun_container.status_reason) from exc - - if wait_for_active and self.status != "Running": + container = create_container( + name=self.name, + image=self.image_ref, + exposed_ports=self.exposed_ports, + reservation_id=self.reservation_id, + runtime=self.runtime, + environment=self.environment, + device_profiles=self.device_profiles, + **kwargs, + ) + self.id = container.uuid + self._status = container.status + + if wait_for_active and self._status != "Running": self.wait(status="Running", timeout=wait_timeout) if show: From 0266d0acb5ec211dde066d0b733a0042cf73acdc Mon Sep 17 00:00:00 2001 From: Michael Sherman Date: Wed, 18 Feb 2026 10:47:45 -0600 Subject: [PATCH 4/6] remove unused exceptions --- chi/exception.py | 15 --------------- tests/test_container.py | 25 ------------------------- 2 files changed, 40 deletions(-) diff --git a/chi/exception.py b/chi/exception.py index 4ad4b45..5ef0a15 100644 --- a/chi/exception.py +++ b/chi/exception.py @@ -28,18 +28,3 @@ class ServiceError(Exception): def __init__(self, message): super().__init__(message) - - -class ContainerCreateWaitError(ResourceError): - """Raised when Zun creates a container but waiting for target status fails.""" - - def __init__(self, zun_container, cause): - self.zun_container = zun_container - self.cause = cause - message = ( - "Container {} was created, but waiting for target status failed: {}".format( - self.zun_container.uuid, - cause, - ) - ) - super().__init__(message) diff --git a/tests/test_container.py b/tests/test_container.py index e04e168..0ac1751 100644 --- a/tests/test_container.py +++ b/tests/test_container.py @@ -21,7 +21,6 @@ from zunclient.exceptions import Conflict from chi.container import Container, download, upload -from chi.exception import ContainerCreateWaitError, ResourceError @pytest.fixture() @@ -154,30 +153,6 @@ def test_submit_idempotent_returns_existing_without_create_no_wait(mocker): assert submit_result is existing_zun_container -def test_submit_preserves_reference_on_create_wait_failure(mocker): - """Ensure that we keep the zun container id, even if create fails. - - This case can arise because the container moves to an error state, or if - the wait times out for another reason. - """ - chi_container = Container(name="test", image_ref="img") - leaked_zun_container = mocker.Mock(uuid="leaked-uuid", status="Error") - - mocker.patch( - "chi.container.create_container", - side_effect=ContainerCreateWaitError( - zun_container=leaked_zun_container, cause=RuntimeError - ), - ) - zun_mock = mocker.patch("chi.container.zun")() - zun_mock.containers.get.return_value = leaked_zun_container - - with pytest.raises(ResourceError): - chi_container.submit(wait_for_active=False, show=None) - - assert chi_container.id == "leaked-uuid" - assert chi_container._status == "Error" - def test_submit_duplicate_name_tracks_created_uuid(mocker): """Test the case where we re-run submit after a failure. From 103c0713e59a2f9dfc504286192bbdeb0b208619 Mon Sep 17 00:00:00 2001 From: Michael Sherman Date: Wed, 18 Feb 2026 12:36:46 -0600 Subject: [PATCH 5/6] apply linter fixes --- chi/container.py | 2 +- tests/test_container.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/chi/container.py b/chi/container.py index 036a2dc..ff0a0cb 100644 --- a/chi/container.py +++ b/chi/container.py @@ -157,7 +157,7 @@ def submit( ) self.id = container.uuid self._status = container.status - + if wait_for_active and self._status != "Running": self.wait(status="Running", timeout=wait_timeout) diff --git a/tests/test_container.py b/tests/test_container.py index 0ac1751..cfd1cb8 100644 --- a/tests/test_container.py +++ b/tests/test_container.py @@ -153,7 +153,6 @@ def test_submit_idempotent_returns_existing_without_create_no_wait(mocker): assert submit_result is existing_zun_container - def test_submit_duplicate_name_tracks_created_uuid(mocker): """Test the case where we re-run submit after a failure. From 77a67adee3f58646d166246f34164f11510b16b7 Mon Sep 17 00:00:00 2001 From: Michael Sherman Date: Wed, 18 Feb 2026 14:26:28 -0600 Subject: [PATCH 6/6] keep backwards compatible args, but warn --- chi/container.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/chi/container.py b/chi/container.py index ff0a0cb..084aa05 100644 --- a/chi/container.py +++ b/chi/container.py @@ -18,6 +18,7 @@ import tarfile import time from typing import Dict, List, Optional, Tuple +from warnings import warn from IPython.display import HTML, display from packaging.version import Version @@ -72,12 +73,21 @@ def __init__( image_ref: str, exposed_ports: List[str] = None, reservation_id: str = None, + start: bool = True, + start_timeout: int = 0, runtime: str = None, command: List[str] = None, workdir: str = None, environment: Dict[str, str] = {}, device_profiles: List[str] = [], ): + + # check if values are not the defaults. + if not start or start_timeout != 0: + warn( + "start and start_timeout are deprecated. Containers always start immmediately." + ) + self.name = name self.image_ref = image_ref self.exposed_ports = exposed_ports