Beispiel #1
0
    def _build_lambda_image(self, function_name: str, metadata: Dict) -> str:
        """
        Build an Lambda image

        Parameters
        ----------
        function_name str
            Name of the function (logical id or function name)
        metadata dict
            Dictionary representing the Metadata attached to the Resource in the template

        Returns
        -------
        str
            The full tag (org/repo:tag) of the image that was built
        """

        LOG.info("Building image for %s function", function_name)

        dockerfile = cast(str, metadata.get("Dockerfile"))
        docker_context = cast(str, metadata.get("DockerContext"))
        # Have a default tag if not present.
        tag = metadata.get("DockerTag", "latest")
        docker_tag = f"{function_name.lower()}:{tag}"
        docker_build_args = metadata.get("DockerBuildArgs", {})
        if not isinstance(docker_build_args, dict):
            raise DockerBuildFailed("DockerBuildArgs needs to be a dictionary!")

        docker_context_dir = pathlib.Path(self._base_dir, docker_context).resolve()
        if not is_docker_reachable(self._docker_client):
            raise DockerConnectionError(msg=f"Building image for {function_name} requires Docker. is Docker running?")

        if os.environ.get("SAM_BUILD_MODE") and isinstance(docker_build_args, dict):
            docker_build_args["SAM_BUILD_MODE"] = os.environ.get("SAM_BUILD_MODE")
            docker_tag = "-".join([docker_tag, docker_build_args["SAM_BUILD_MODE"]])

        if isinstance(docker_build_args, dict):
            LOG.info("Setting DockerBuildArgs: %s for %s function", docker_build_args, function_name)

        build_logs = self._docker_client.api.build(
            path=str(docker_context_dir),
            dockerfile=dockerfile,
            tag=docker_tag,
            buildargs=docker_build_args,
            decode=True,
        )

        # The Docker-py low level api will stream logs back but if an exception is raised by the api
        # this is raised when accessing the generator. So we need to wrap accessing build_logs in a try: except.
        try:
            self._stream_lambda_image_build_logs(build_logs, function_name)
        except docker.errors.APIError as e:
            if e.is_server_error and "Cannot locate specified Dockerfile" in e.explanation:
                raise DockerfileOutSideOfContext(e.explanation) from e

            # Not sure what else can be raise that we should be catching but re-raising for now
            raise

        return docker_tag
Beispiel #2
0
    def is_docker_reachable(self):
        """
        Checks if Docker daemon is running. This is required for us to invoke the function locally

        Returns
        -------
        bool
            True, if Docker is available, False otherwise
        """
        return utils.is_docker_reachable(self.docker_client)