diff --git a/samcli/local/docker/lambda_container.py b/samcli/local/docker/lambda_container.py index d9e7eb77ee..c9a3dfd2b3 100644 --- a/samcli/local/docker/lambda_container.py +++ b/samcli/local/docker/lambda_container.py @@ -2,6 +2,7 @@ Represents Lambda runtime containers. """ import logging +import os from typing import List from samcli.lib.utils.packagetype import IMAGE @@ -12,6 +13,8 @@ LOG = logging.getLogger(__name__) +RIE_LOG_LEVEL_ENV_VAR = "SAM_CLI_RIE_DEV" + class LambdaContainer(Container): """ @@ -21,7 +24,6 @@ class LambdaContainer(Container): """ _WORKING_DIR = "/var/task" - _DEFAULT_ENTRYPOINT = ["/var/rapid/aws-lambda-rie", "--log-level", "error"] # The Volume Mount path for debug files in docker _DEBUGGER_VOLUME_MOUNT_PATH = "/tmp/lambci_debug_files" @@ -115,10 +117,10 @@ def __init__( _additional_entrypoint_args = (image_config.get("EntryPoint") if image_config else None) or config.get( "Entrypoint" ) - _entrypoint = entry or self._DEFAULT_ENTRYPOINT + _entrypoint = entry or self._get_default_entry_point() # NOTE(sriram-mv): Only add entrypoint specified in the image configuration if the entrypoint # has not changed for debugging. - if isinstance(_additional_entrypoint_args, list) and entry == self._DEFAULT_ENTRYPOINT: + if isinstance(_additional_entrypoint_args, list) and entry == self._get_default_entry_point(): _entrypoint = _entrypoint + _additional_entrypoint_args _work_dir = (image_config.get("WorkingDirectory") if image_config else None) or config.get("WorkingDir") @@ -138,6 +140,16 @@ def __init__( container_host_interface=container_host_interface, ) + @staticmethod + def _get_default_entry_point() -> List[str]: + """ + Returns default entry point for lambda container, which is the path of the RIE executable with its debugging + configuration. If SAM_CLI_RIE_DEV is set to 1, RIE log level is set to 'debug', otherwise it is kept as 'error'. + """ + # + rie_log_level = "debug" if os.environ.get(RIE_LOG_LEVEL_ENV_VAR, "0") == "1" else "error" + return ["/var/rapid/aws-lambda-rie", "--log-level", rie_log_level] + @staticmethod def _get_exposed_ports(debug_options): """ @@ -253,7 +265,7 @@ def _get_debug_settings(runtime, debug_options=None): # pylint: disable=too-man ie. if command is ``node index.js arg1 arg2``, then this list will be ["node", "index.js", "arg1", "arg2"] """ - entry = LambdaContainer._DEFAULT_ENTRYPOINT + entry = LambdaContainer._get_default_entry_point() if not debug_options: return entry, {} diff --git a/tests/unit/local/docker/test_lambda_container.py b/tests/unit/local/docker/test_lambda_container.py index cf589ee65f..d36aeff841 100644 --- a/tests/unit/local/docker/test_lambda_container.py +++ b/tests/unit/local/docker/test_lambda_container.py @@ -1,14 +1,14 @@ """ Unit test for Lambda container management """ - from unittest import TestCase from unittest.mock import patch, Mock + from parameterized import parameterized, param from samcli.commands.local.lib.debug_context import DebugContext from samcli.lib.utils.packagetype import IMAGE, ZIP -from samcli.local.docker.lambda_container import LambdaContainer, Runtime +from samcli.local.docker.lambda_container import LambdaContainer, Runtime, RIE_LOG_LEVEL_ENV_VAR from samcli.local.docker.lambda_debug_settings import DebuggingNotSupported from samcli.local.docker.lambda_image import RAPID_IMAGE_TAG_PREFIX @@ -147,7 +147,7 @@ def test_must_configure_container_properly_image_no_debug( expected_cmd = ["mycommand"] get_image_mock.return_value = image - get_debug_settings_mock.return_value = (LambdaContainer._DEFAULT_ENTRYPOINT, {}) + get_debug_settings_mock.return_value = (LambdaContainer._get_default_entry_point(), {}) get_config_mock.return_value = { "Cmd": ["mycommand"], "Entrypoint": ["my-additional-entrypoint"], @@ -181,7 +181,9 @@ def test_must_configure_container_properly_image_no_debug( self.assertEqual(get_config_mock()["WorkingDir"], container._working_dir) self.assertEqual(self.code_dir, container._host_dir) self.assertEqual(ports, container._exposed_ports) - self.assertEqual(LambdaContainer._DEFAULT_ENTRYPOINT + get_config_mock()["Entrypoint"], container._entrypoint) + self.assertEqual( + LambdaContainer._get_default_entry_point() + get_config_mock()["Entrypoint"], container._entrypoint + ) self.assertEqual({**expected_env_vars, **{"AWS_LAMBDA_FUNCTION_HANDLER": "mycommand"}}, container._env_vars) self.assertEqual(self.memory_mb, container._memory_limit_mb) @@ -256,7 +258,7 @@ def test_must_configure_container_properly_image_debug( self.assertEqual(ports, container._exposed_ports) # Dis-regard Entrypoint when debug args are present. self.assertEqual( - LambdaContainer._DEFAULT_ENTRYPOINT + self.debug_options.debug_args.split(" "), container._entrypoint + LambdaContainer._get_default_entry_point() + self.debug_options.debug_args.split(" "), container._entrypoint ) self.assertEqual(expected_env_vars, container._env_vars) self.assertEqual(self.memory_mb, container._memory_limit_mb) @@ -331,7 +333,7 @@ def test_must_configure_container_properly_image_with_imageconfig_debug( self.assertEqual(self.code_dir, container._host_dir) self.assertEqual(ports, container._exposed_ports) self.assertEqual( - LambdaContainer._DEFAULT_ENTRYPOINT + self.debug_options.debug_args.split(" "), container._entrypoint + LambdaContainer._get_default_entry_point() + self.debug_options.debug_args.split(" "), container._entrypoint ) self.assertEqual( {**expected_env_vars, **{"AWS_LAMBDA_FUNCTION_HANDLER": "my-imageconfig-command"}}, container._env_vars @@ -382,7 +384,7 @@ def test_must_configure_container_properly_image_with_imageconfig_no_debug( "WorkingDir": "/var/mytask", } get_exposed_ports_mock.return_value = ports - get_debug_settings_mock.return_value = (LambdaContainer._DEFAULT_ENTRYPOINT, {}) + get_debug_settings_mock.return_value = (LambdaContainer._get_default_entry_point(), {}) get_additional_options_mock.return_value = addtl_options get_additional_volumes_mock.return_value = addtl_volumes expected_env_vars = {**self.env_var} @@ -411,7 +413,9 @@ def test_must_configure_container_properly_image_with_imageconfig_no_debug( self.assertEqual(self.code_dir, container._host_dir) self.assertEqual(ports, container._exposed_ports) self.assertEqual( - LambdaContainer._DEFAULT_ENTRYPOINT + self.image_config["EntryPoint"], container._entrypoint, "x86_64" + LambdaContainer._get_default_entry_point() + self.image_config["EntryPoint"], + container._entrypoint, + "x86_64", ) self.assertEqual( {**expected_env_vars, **{"AWS_LAMBDA_FUNCTION_HANDLER": "my-imageconfig-command"}}, container._env_vars @@ -445,6 +449,23 @@ def test_must_fail_for_unsupported_runtime(self): self.assertEqual(str(context.exception), "Unsupported Lambda runtime foo") + @parameterized.expand( + [ + ( + None, + "error", + ), + ( + "0", + "error", + ), + ("1", "debug"), + ] + ) + def test_rie_debug_levels(self, rie_env_var, expected_log_level): + with patch("samcli.local.docker.lambda_container.os.environ", {RIE_LOG_LEVEL_ENV_VAR: rie_env_var}): + self.assertIn(expected_log_level, LambdaContainer._get_default_entry_point()) + class TestLambdaContainer_get_exposed_ports(TestCase): def test_must_map_same_port_on_host_and_container(self): @@ -508,7 +529,7 @@ def setUp(self): def test_must_skip_if_debug_port_is_not_specified(self): self.assertEqual( - (LambdaContainer._DEFAULT_ENTRYPOINT, {}), + (LambdaContainer._get_default_entry_point(), {}), LambdaContainer._get_debug_settings("runtime", None), "Must not provide entrypoint if debug port is not given", )