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 test_must_return_sys_stderr(self): expected_stderr = sys.stderr if sys.version_info.major > 2: expected_stderr = sys.stderr.buffer self.assertEqual(expected_stderr, osutils.stderr())
def test_must_return_sys_stderr(self): expected_stderr = sys.stderr if sys.version_info.major > 2: expected_stderr = sys.stderr.buffer self.assertEquals(expected_stderr, osutils.stderr())
def stderr(self): """ Returns stderr stream to output Lambda function errors to :return File like object: Stream where the stderr of the function is sent to """ if self._log_file_handle: return self._log_file_handle return osutils.stderr()
def stderr(self) -> StreamWriter: """ Returns stream writer for stderr to output Lambda function errors to Returns ------- samcli.lib.utils.stream_writer.StreamWriter Stream writer for stderr """ stream = self._log_file_handle if self._log_file_handle else osutils.stderr() return StreamWriter(stream, self._is_debugging)
def stderr(self): """ Returns stream writer for stderr to output Lambda function errors to Returns ------- samcli.lib.utils.stream_writer.StreamWriter Stream writer for stderr """ stream = self._log_file_handle if self._log_file_handle else osutils.stderr() return StreamWriter(stream, self._is_debugging)
def __init__(self, docker_client, ecr_client, ecr_repo, tag="latest", stream=stderr()): self.docker_client = docker_client if docker_client else docker.from_env( ) self.ecr_client = ecr_client self.ecr_repo = ecr_repo self.tag = tag self.auth_config = {} self.stream = StreamWriter(stream=stream, auto_flush=True)
def __init__(self, resources_to_build, build_dir, base_dir, cache_dir, cached=False, is_building_specific_resource=False, manifest_path_override=None, container_manager=None, parallel=False, mode=None, stream_writer=None, docker_client=None): """ Initialize the class Parameters ---------- resources_to_build: Iterator Iterator that can vend out resources available in the SAM template build_dir : str Path to the directory where we will be storing built artifacts base_dir : str Path to a folder. Use this folder as the root to resolve relative source code paths against cache_dir : str Path to a the directory where we will be caching built artifacts cached: Optional. Set to True to build each function with cache to improve performance is_building_specific_resource : boolean Whether customer requested to build a specific resource alone in isolation, by specifying function_identifier to the build command. Ex: sam build MyServerlessFunction container_manager : samcli.local.docker.manager.ContainerManager Optional. If provided, we will attempt to build inside a Docker Container parallel : bool Optional. Set to True to build each function in parallel to improve performance mode : str Optional, name of the build mode to use ex: 'debug' """ self._resources_to_build = resources_to_build self._build_dir = build_dir self._base_dir = base_dir self._cache_dir = cache_dir self._cached = cached self._manifest_path_override = manifest_path_override self._is_building_specific_resource = is_building_specific_resource self._container_manager = container_manager self._parallel = parallel self._mode = mode self._stream_writer = stream_writer if stream_writer else StreamWriter( osutils.stderr()) self._docker_client = docker_client if docker_client else docker.from_env( ) self._deprecated_runtimes = { "nodejs4.3", "nodejs6.10", "nodejs8.10", "dotnetcore2.0" } self._colored = Colored()
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