in samcli/local/docker/lambda_image.py [0:0]
def build(self, runtime, packagetype, image, layers, architecture, stream=None, function_name=None):
"""
Build the image if one is not already on the system that matches the runtime and layers
Parameters
----------
runtime : str
Name of the Lambda runtime
packagetype : str
Packagetype for the Lambda
image : str
Pre-defined invocation image.
layers : list(samcli.commands.local.lib.provider.Layer)
List of layers
architecture : str
Architecture type either x86_64 or arm64 on AWS lambda
stream : io.RawIOBase
stream to write
function_name : str
The name of the function that the image is building for
Returns
-------
str
The image to be used (REPOSITORY:TAG)
"""
base_image = None
tag_prefix = ""
if packagetype == IMAGE:
base_image = image
elif packagetype == ZIP:
is_preview = runtime in TEST_RUNTIMES
runtime_image_tag = Runtime.get_image_name_tag(runtime, architecture, is_preview=is_preview)
if self.invoke_images:
base_image = self.invoke_images.get(function_name, self.invoke_images.get(None))
if not base_image:
# Gets the ECR image format like `python:3.12` or `nodejs:16-x86_64`
runtime_only_number = re.split("[:-]", runtime_image_tag)[1]
tag_prefix = f"{runtime_only_number}-"
base_image = f"{self._INVOKE_REPO_PREFIX}/{runtime_image_tag}"
# Temporarily add a version tag to the emulation image so that we don't pull a broken image
if platform.system().lower() == "windows" and runtime in [Runtime.go1x.value]:
LOG.info("Falling back to a previous version of the emulation image")
base_image = f"{base_image}.2023.08.02.10"
if not base_image:
raise InvalidIntermediateImageError(f"Invalid PackageType, PackageType needs to be one of [{ZIP}, {IMAGE}]")
if image:
self.skip_pull_image = True
# If the image name had a digest, removing the @ so that a valid image name can be constructed
# to use for the local invoke image name.
image_repo = base_image.split(":")[0].replace("@", "")
rapid_image = f"{image_repo}:{tag_prefix}{RAPID_IMAGE_TAG_PREFIX}-{architecture}"
downloaded_layers = []
if layers and packagetype == ZIP:
downloaded_layers = self.layer_downloader.download_all(layers, self.force_image_build)
docker_image_version = self._generate_docker_image_version(downloaded_layers, runtime_image_tag)
rapid_image = f"{self._SAM_CLI_REPO_NAME}-{docker_image_version}"
image_not_found = False
# If we are not using layers, build anyways to ensure any updates to rapid get added
try:
self.docker_client.images.get(rapid_image)
# Check if the base image is up-to-date locally and modify build/pull parameters accordingly
self._check_base_image_is_current(base_image)
except docker.errors.ImageNotFound:
LOG.info("Local image was not found.")
image_not_found = True
except docker.errors.APIError as e:
if e.__class__ is docker.errors.NotFound:
# A generic "NotFound" is raised when we aren't able to check the image version
# for example when the docker daemon's api doesn't support this action.
#
# See Also: https://github.com/containers/podman/issues/17726
LOG.warning(
"Unknown 404 - Unable to check if base image is current.\n\nPossible incompatible "
"Docker engine clone employed. Consider `--skip-pull-image` for improved speed, the "
"tradeoff being not running the latest image."
)
image_not_found = True
else:
raise DockerDistributionAPIError(str(e)) from e
# If building a new rapid image, delete older rapid images
if image_not_found and rapid_image == f"{image_repo}:{tag_prefix}{RAPID_IMAGE_TAG_PREFIX}-{architecture}":
if tag_prefix:
# ZIP functions with new RAPID format. Delete images from the old ecr/sam repository
self._remove_rapid_images(f"{self._SAM_INVOKE_REPO_PREFIX}-{runtime}")
else:
self._remove_rapid_images(image_repo)
if (
self.force_image_build
or image_not_found
or any(layer.is_defined_within_template for layer in downloaded_layers)
or not runtime
):
stream_writer = stream or StreamWriter(sys.stderr)
stream_writer.write_str("Building image...")
stream_writer.flush()
self._build_image(
image if image else base_image, rapid_image, downloaded_layers, architecture, stream=stream_writer
)
return rapid_image