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
5 changes: 5 additions & 0 deletions samcli/local/docker/container.py
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,11 @@ def create(self, context):
try:
real_container = self.docker_client.containers.create(self._image, **kwargs)
except DockerAPIError as ex:
if "port is already allocated" in str(ex):
raise ContainerCreationFailedException(
f"Container creation failed: {ex.explanation}. A host port that SAM CLI publishes for this "
"container is already in use, stop the process or container using it and try again"
) from ex
raise ContainerCreationFailedException(
f"Container creation failed: {ex.explanation}, check template for potential issue"
)
Expand Down
20 changes: 20 additions & 0 deletions tests/unit/local/docker/test_container.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
ContainerResponseException,
ContainerConnectionTimeoutException,
PortAlreadyInUse,
ContainerCreationFailedException,
)


Expand Down Expand Up @@ -374,6 +375,25 @@ def test_must_fail_if_already_created(self):
container.create(self.container_context)
self.assertIsNone(container._concurrency_semaphore)

def test_create_reports_port_in_use_when_port_allocated(self):
"""Test that create() keeps ContainerCreationFailedException but explains the port conflict"""
container = Container(
self.image, self.cmd, self.working_dir, self.host_dir, docker_client=self.mock_docker_client
)

# Mock APIError with "port is already allocated" message (as reported by Finch)
error_msg = 'failed to parse port mapping "0.0.0.0:7311:8080/tcp": bind for 0.0.0.0:7311 failed: port is already allocated'
mock_error = APIError(error_msg, explanation=error_msg)
self.mock_docker_client.containers.create.side_effect = mock_error

with self.assertRaises(ContainerCreationFailedException) as context:
container.create(self.container_context)

self.assertNotIsInstance(context.exception, PortAlreadyInUse)
self.assertIn("already in use", str(context.exception))
self.assertNotIn("check template", str(context.exception))
self.assertIs(context.exception.__cause__, mock_error)

@patch("samcli.local.docker.container.os.path.exists")
@patch("samcli.local.docker.container.os.makedirs")
def test_must_make_host_tmp_dir_if_mount_with_write_container_build(self, mock_makedirs, mock_exists):
Expand Down