Skip to content
Open
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
69 changes: 22 additions & 47 deletions chi/container.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -28,7 +29,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"
Expand Down Expand Up @@ -80,12 +81,17 @@ def __init__(
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
self.reservation_id = reservation_id
self.start = start
self.start_timeout = start_timeout
self.runtime = runtime
self.id = None
self.created_at = None
Expand All @@ -101,7 +107,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
Expand Down Expand Up @@ -150,28 +155,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
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":
if wait_for_active and self._status != "Running":
self.wait(status="Running", timeout=wait_timeout)

if show:
Expand Down Expand Up @@ -371,9 +368,6 @@ def create_container(
image: "str" = None,
exposed_ports: "list[str]" = None,
reservation_id: "str" = None,
start: "bool" = True,
start_timeout: "int" = None,
platform_version: "int" = 2,
**kwargs,
):
"""
Expand Down Expand Up @@ -409,8 +403,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):
Expand All @@ -431,23 +423,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:
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


Expand Down
15 changes: 0 additions & 15 deletions chi/exception.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
26 changes: 0 additions & 26 deletions tests/test_container.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
from zunclient.exceptions import Conflict

from chi.container import Container, download, upload
from chi.exception import ContainerCreateWaitError, ResourceError


@pytest.fixture()
Expand Down Expand Up @@ -154,31 +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.

Expand Down