Skip to content

Commit c4e88ef

Browse files
authored
Docker Utils: Expose the build logs (#12376)
1 parent d1678b1 commit c4e88ef

File tree

4 files changed

+23
-4
lines changed

4 files changed

+23
-4
lines changed

localstack-core/localstack/utils/container_utils/container_client.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -701,13 +701,14 @@ def build_image(
701701
image_name: str,
702702
context_path: str = None,
703703
platform: Optional[DockerPlatform] = None,
704-
) -> None:
704+
) -> str:
705705
"""Builds an image from the given Dockerfile
706706
707707
:param dockerfile_path: Path to Dockerfile, or a directory that contains a Dockerfile
708708
:param image_name: Name of the image to be built
709709
:param context_path: Path for build context (defaults to dirname of Dockerfile)
710710
:param platform: Target platform for build (defaults to platform of Docker host)
711+
:return: Build logs as a string.
711712
"""
712713

713714
@abstractmethod

localstack-core/localstack/utils/container_utils/docker_cmd_client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,7 @@ def build_image(
412412
cmd += [context_path]
413413
LOG.debug("Building Docker image: %s", cmd)
414414
try:
415-
run(cmd)
415+
return run(cmd)
416416
except subprocess.CalledProcessError as e:
417417
raise ContainerException(
418418
f"Docker build process returned with error code {e.returncode}", e.stdout, e.stderr

localstack-core/localstack/utils/container_utils/docker_sdk_client.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -380,13 +380,23 @@ def build_image(
380380
dockerfile_path = Util.resolve_dockerfile_path(dockerfile_path)
381381
context_path = context_path or os.path.dirname(dockerfile_path)
382382
LOG.debug("Building Docker image %s from %s", image_name, dockerfile_path)
383-
self.client().images.build(
383+
_, logs_iterator = self.client().images.build(
384384
path=context_path,
385385
dockerfile=dockerfile_path,
386386
tag=image_name,
387387
rm=True,
388388
platform=platform,
389389
)
390+
# logs_iterator is a stream of dicts. Example content:
391+
# {'stream': 'Step 1/4 : FROM alpine'}
392+
# ... other build steps
393+
# {'aux': {'ID': 'sha256:4dcf90e87fb963e898f9c7a0451a40e36f8e7137454c65ae4561277081747825'}}
394+
# {'stream': 'Successfully tagged img-5201f3e1:latest\n'}
395+
output = ""
396+
for log in logs_iterator:
397+
if isinstance(log, dict) and ("stream" in log or "error" in log):
398+
output += log.get("stream") or log["error"]
399+
return output
390400
except APIError as e:
391401
raise ContainerException("Unable to build Docker image") from e
392402

tests/integration/docker_utils/test_docker.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1240,7 +1240,15 @@ def test_build_image(
12401240
dockerfile_ref = str(dockerfile_dir) if dockerfile_as_dir else dockerfile_path
12411241

12421242
image_name = f"img-{short_uid()}"
1243-
docker_client.build_image(dockerfile_path=dockerfile_ref, image_name=image_name, **kwargs)
1243+
build_logs = docker_client.build_image(
1244+
dockerfile_path=dockerfile_ref, image_name=image_name, **kwargs
1245+
)
1246+
# The exact log files are very different between the CMD and SDK
1247+
# We just run some smoke tests
1248+
assert build_logs
1249+
assert isinstance(build_logs, str)
1250+
assert "ADD" in build_logs
1251+
12441252
cleanups.append(lambda: docker_client.remove_image(image_name, force=True))
12451253

12461254
assert image_name in docker_client.get_docker_image_names()

0 commit comments

Comments
 (0)