def _build_function_on_container( self, # pylint: disable=too-many-locals config, source_dir, artifacts_dir, scratch_dir, manifest_path, runtime): # If we are printing debug logs in SAM CLI, the builder library should also print debug logs log_level = LOG.getEffectiveLevel() container = LambdaBuildContainer(lambda_builders_protocol_version, config.language, config.dependency_manager, config.application_framework, source_dir, manifest_path, runtime, log_level=log_level, optimizations=None, options=None) try: try: self._container_manager.run(container) except docker.errors.APIError as ex: if "executable file not found in $PATH" in str(ex): raise UnsupportedBuilderLibraryVersionError( container.image, "{} executable not found in container".format( container.executable_name)) # Container's output provides status of whether the build succeeded or failed # stdout contains the result of JSON-RPC call stdout_stream = io.BytesIO() # stderr contains logs printed by the builder. Stream it directly to terminal stderr_stream = osutils.stderr() container.wait_for_logs(stdout=stdout_stream, stderr=stderr_stream) stdout_data = stdout_stream.getvalue().decode('utf-8') LOG.debug("Build inside container returned response %s", stdout_data) response = self._parse_builder_response(stdout_data, container.image) # Request is successful. Now copy the artifacts back to the host LOG.debug( "Build inside container was successful. Copying artifacts from container to host" ) # "/." is a Docker thing that instructions the copy command to download contents of the folder only result_dir_in_container = response["result"]["artifacts_dir"] + "/." container.copy(result_dir_in_container, artifacts_dir) finally: self._container_manager.stop(container) LOG.debug("Build inside container succeeded") return artifacts_dir
def _build_function_on_container( self, # pylint: disable=too-many-locals config: CONFIG, source_dir: str, artifacts_dir: str, scratch_dir: str, manifest_path: str, runtime: str, options: Optional[Dict], container_env_vars: Optional[Dict] = None, ) -> str: # _build_function_on_container() is only called when self._container_manager if not None if not self._container_manager: raise RuntimeError( "_build_function_on_container() is called when self._container_manager is None." ) if not self._container_manager.is_docker_reachable: raise BuildInsideContainerError( "Docker is unreachable. Docker needs to be running to build inside a container." ) container_build_supported, reason = supports_build_in_container(config) if not container_build_supported: raise ContainerBuildNotSupported(reason) # If we are printing debug logs in SAM CLI, the builder library should also print debug logs log_level = LOG.getEffectiveLevel() container_env_vars = container_env_vars or {} container = LambdaBuildContainer( lambda_builders_protocol_version, config.language, config.dependency_manager, config.application_framework, source_dir, manifest_path, runtime, log_level=log_level, optimizations=None, options=options, executable_search_paths=config.executable_search_paths, mode=self._mode, env_vars=container_env_vars, ) try: try: self._container_manager.run(container) except docker.errors.APIError as ex: if "executable file not found in $PATH" in str(ex): raise UnsupportedBuilderLibraryVersionError( container.image, "{} executable not found in container".format( container.executable_name)) from ex # Container's output provides status of whether the build succeeded or failed # stdout contains the result of JSON-RPC call stdout_stream = io.BytesIO() # stderr contains logs printed by the builder. Stream it directly to terminal stderr_stream = osutils.stderr() container.wait_for_logs(stdout=stdout_stream, stderr=stderr_stream) stdout_data = stdout_stream.getvalue().decode("utf-8") LOG.debug("Build inside container returned response %s", stdout_data) response = self._parse_builder_response(stdout_data, container.image) # Request is successful. Now copy the artifacts back to the host LOG.debug( "Build inside container was successful. Copying artifacts from container to host" ) # "/." is a Docker thing that instructions the copy command to download contents of the folder only result_dir_in_container = response["result"]["artifacts_dir"] + "/." container.copy(result_dir_in_container, artifacts_dir) finally: self._container_manager.stop(container) LOG.debug("Build inside container succeeded") return artifacts_dir