From a9f2a2d44cde81f771a38499514e4a2b0036730b Mon Sep 17 00:00:00 2001 From: Daniel Mil <84205762+mildaniel@users.noreply.github.com> Date: Thu, 14 Mar 2024 15:06:23 -0700 Subject: [PATCH] fix: Use container path for file observer in a container (#6702) * fix: Use container path for file observer in a container * Fix existing tests --- .../local/cli_common/invoke_context.py | 3 +++ samcli/commands/local/lib/local_lambda.py | 5 +++++ samcli/lib/utils/file_observer.py | 2 +- samcli/local/lambdafn/config.py | 2 ++ .../local/cli_common/test_invoke_context.py | 5 +++++ .../commands/local/lib/test_local_lambda.py | 19 +++++++++++++++-- tests/unit/lib/utils/test_file_observer.py | 21 +++++++++++++------ 7 files changed, 48 insertions(+), 9 deletions(-) diff --git a/samcli/commands/local/cli_common/invoke_context.py b/samcli/commands/local/cli_common/invoke_context.py index 9255761143..20b30f6744 100644 --- a/samcli/commands/local/cli_common/invoke_context.py +++ b/samcli/commands/local/cli_common/invoke_context.py @@ -393,10 +393,13 @@ def local_lambda_runner(self) -> LocalLambdaRunner: if self._local_lambda_runner: return self._local_lambda_runner + real_path = str(os.path.dirname(os.path.abspath(self._template_file))) + self._local_lambda_runner = LocalLambdaRunner( local_runtime=self.lambda_runtime, function_provider=self._function_provider, cwd=self.get_cwd(), + real_path=real_path, aws_profile=self._aws_profile, aws_region=self._aws_region, env_vars_values=self._env_vars_value, diff --git a/samcli/commands/local/lib/local_lambda.py b/samcli/commands/local/lib/local_lambda.py index e2d0e80b9e..9caacfd270 100644 --- a/samcli/commands/local/lib/local_lambda.py +++ b/samcli/commands/local/lib/local_lambda.py @@ -45,6 +45,7 @@ def __init__( local_runtime: LambdaRuntime, function_provider: SamFunctionProvider, cwd: str, + real_path: str, aws_profile: Optional[str] = None, aws_region: Optional[str] = None, env_vars_values: Optional[Dict[Any, Any]] = None, @@ -72,6 +73,7 @@ def __init__( self.local_runtime = local_runtime self.provider = function_provider self.cwd = cwd + self.real_path = real_path self.aws_profile = aws_profile self.aws_region = aws_region self.env_vars_values = env_vars_values or {} @@ -198,6 +200,8 @@ def get_invoke_config(self, function: Function) -> FunctionConfig: if function.packagetype == ZIP: code_abs_path = resolve_code_path(self.cwd, function.codeuri) LOG.debug("Resolved absolute path to code is %s", code_abs_path) + code_real_path = resolve_code_path(self.real_path, function.codeuri) + LOG.debug("Resolved real code path to %s", code_real_path) function_timeout = function.timeout @@ -222,6 +226,7 @@ def get_invoke_config(self, function: Function) -> FunctionConfig: timeout=function_timeout, env_vars=env_vars, runtime_management_config=function.runtime_management_config, + code_real_path=code_real_path, ) def _make_env_vars(self, function: Function) -> EnvironmentVariables: diff --git a/samcli/lib/utils/file_observer.py b/samcli/lib/utils/file_observer.py index 230f47a7a6..9fe0cbe339 100644 --- a/samcli/lib/utils/file_observer.py +++ b/samcli/lib/utils/file_observer.py @@ -120,7 +120,7 @@ def _get_zip_lambda_function_paths(function_config: FunctionConfig) -> List[str] list[str] List of lambda functions' source code paths to be observed """ - code_paths = [function_config.code_abs_path] + code_paths = [function_config.code_real_path] if function_config.layers: # Non-local layers will not have a codeuri property and don't need to be observed code_paths += [layer.codeuri for layer in function_config.layers if layer.codeuri] diff --git a/samcli/local/lambdafn/config.py b/samcli/local/lambdafn/config.py index ed9ada46e9..cadbfbd9d3 100644 --- a/samcli/local/lambdafn/config.py +++ b/samcli/local/lambdafn/config.py @@ -32,6 +32,7 @@ def __init__( timeout=None, runtime_management_config=None, env_vars=None, + code_real_path=None, ): """ Parameters @@ -80,6 +81,7 @@ def __init__( self.packagetype = packagetype self.handler = handler self.code_abs_path = code_abs_path + self.code_real_path = code_real_path self.layers = layers self.memory = memory or self._DEFAULT_MEMORY self.architecture = architecture diff --git a/tests/unit/commands/local/cli_common/test_invoke_context.py b/tests/unit/commands/local/cli_common/test_invoke_context.py index fce1c37f23..ccdfebaae7 100644 --- a/tests/unit/commands/local/cli_common/test_invoke_context.py +++ b/tests/unit/commands/local/cli_common/test_invoke_context.py @@ -625,6 +625,7 @@ def test_must_create_runner( local_runtime=runtime_mock, function_provider=ANY, cwd=cwd, + real_path=ANY, debug_context=None, env_vars_values=ANY, aws_profile="profile", @@ -704,6 +705,7 @@ def test_must_create_runner_using_warm_containers( local_runtime=runtime_mock, function_provider=ANY, cwd=cwd, + real_path=ANY, debug_context=None, env_vars_values=ANY, aws_profile="profile", @@ -789,6 +791,7 @@ def test_must_create_runner_with_container_host_option( local_runtime=runtime_mock, function_provider=ANY, cwd=cwd, + real_path=ANY, debug_context=None, env_vars_values=ANY, aws_profile="profile", @@ -874,6 +877,7 @@ def test_must_create_runner_with_extra_hosts_option( local_runtime=runtime_mock, function_provider=ANY, cwd=cwd, + real_path=ANY, debug_context=None, env_vars_values=ANY, aws_profile="profile", @@ -961,6 +965,7 @@ def test_must_create_runner_with_invoke_image_option( local_runtime=runtime_mock, function_provider=ANY, cwd=cwd, + real_path=ANY, debug_context=None, env_vars_values=ANY, aws_profile="profile", diff --git a/tests/unit/commands/local/lib/test_local_lambda.py b/tests/unit/commands/local/lib/test_local_lambda.py index 755e6acd0c..a68cfe4a69 100644 --- a/tests/unit/commands/local/lib/test_local_lambda.py +++ b/tests/unit/commands/local/lib/test_local_lambda.py @@ -37,11 +37,13 @@ def setUp(self): self.debug_context = None self.aws_profile = "myprofile" self.aws_region = "region" + self.real_path = "/real/path" self.local_lambda = LocalLambdaRunner( self.runtime_mock, self.function_provider_mock, self.cwd, + real_path=self.real_path, env_vars_values=self.env_vars_values, debug_context=self.debug_context, aws_profile=self.aws_profile, @@ -184,6 +186,7 @@ def setUp(self): self.runtime_mock = Mock() self.function_provider_mock = Mock() self.cwd = "/my/current/working/directory" + self.real_path = "/real/path" self.debug_context = None self.aws_profile = "myprofile" self.aws_region = "region" @@ -195,6 +198,7 @@ def setUp(self): self.runtime_mock, self.function_provider_mock, self.cwd, + real_path=self.real_path, env_vars_values=self.env_vars_values, debug_context=self.debug_context, ) @@ -387,11 +391,13 @@ def setUp(self): self.debug_context = None self.env_vars_values = {} self.aws_region = "region" + self.real_path = "/real/path" self.local_lambda = LocalLambdaRunner( self.runtime_mock, self.function_provider_mock, self.cwd, + real_path=self.real_path, env_vars_values=self.env_vars_values, debug_context=self.debug_context, ) @@ -457,9 +463,10 @@ def test_must_work(self, FunctionConfigMock, is_debugging_mock, resolve_code_pat architecture=ARM64, full_path=function.full_path, runtime_management_config=function.runtime_management_config, + code_real_path=codepath, ) - resolve_code_path_patch.assert_called_with(self.cwd, function.codeuri) + resolve_code_path_patch.assert_called_with(self.real_path, function.codeuri) self.local_lambda._make_env_vars.assert_called_with(function) @patch("samcli.commands.local.lib.local_lambda.resolve_code_path") @@ -526,9 +533,10 @@ def test_timeout_set_to_max_during_debugging( architecture=X86_64, full_path=function.full_path, runtime_management_config=function.runtime_management_config, + code_real_path=codepath, ) - resolve_code_path_patch.assert_called_with(self.cwd, "codeuri") + resolve_code_path_patch.assert_called_with(self.real_path, "codeuri") self.local_lambda._make_env_vars.assert_called_with(function) @@ -541,11 +549,13 @@ def setUp(self): self.aws_profile = "myprofile" self.aws_region = "region" self.env_vars_values = {} + self.real_path = "/real/path" self.local_lambda = LocalLambdaRunner( self.runtime_mock, self.function_provider_mock, self.cwd, + real_path=self.real_path, env_vars_values=self.env_vars_values, debug_context=self.debug_context, ) @@ -729,11 +739,13 @@ def setUp(self): self.env_vars_values = {} self.container_host = "localhost" self.container_host_interface = "127.0.0.1" + self.real_path = "/real/path" self.local_lambda = LocalLambdaRunner( self.runtime_mock, self.function_provider_mock, self.cwd, + real_path=self.real_path, env_vars_values=self.env_vars_values, debug_context=self.debug_context, container_host=self.container_host, @@ -776,11 +788,13 @@ def setUp(self): self.aws_profile = "myprofile" self.aws_region = "region" self.env_vars_values = {} + self.real_path = "/real/path" self.local_lambda = LocalLambdaRunner( self.runtime_mock, self.function_provider_mock, self.cwd, + real_path=self.real_path, env_vars_values=self.env_vars_values, debug_context=self.debug_context, ) @@ -793,6 +807,7 @@ def test_must_be_off(self): self.runtime_mock, self.function_provider_mock, self.cwd, + self.real_path, env_vars_values=self.env_vars_values, debug_context=None, ) diff --git a/tests/unit/lib/utils/test_file_observer.py b/tests/unit/lib/utils/test_file_observer.py index 7fb76b6100..2ff0ff1dc5 100644 --- a/tests/unit/lib/utils/test_file_observer.py +++ b/tests/unit/lib/utils/test_file_observer.py @@ -738,21 +738,23 @@ def test_watch_ZIP_lambda_function(self): lambda_function = Mock() lambda_function.packagetype = ZIP lambda_function.code_abs_path = "path1" + lambda_function.code_real_path = "path2" lambda_function.layers = [] self.lambda_function_observer.watch(lambda_function) self.assertEqual( self.lambda_function_observer._observed_functions, { - ZIP: {"path1": [lambda_function]}, + ZIP: {"path2": [lambda_function]}, IMAGE: {}, }, ) - self.file_observer_mock.watch.assert_called_with("path1") + self.file_observer_mock.watch.assert_called_with("path2") def test_watch_ZIP_lambda_function_with_layers(self): lambda_function = Mock() lambda_function.packagetype = ZIP lambda_function.code_abs_path = "path1" + lambda_function.code_real_path = "path2" layer1_mock = Mock() layer1_mock.codeuri = "layer1_path" layer2_mock = Mock() @@ -764,7 +766,7 @@ def test_watch_ZIP_lambda_function_with_layers(self): self.lambda_function_observer._observed_functions, { ZIP: { - "path1": [lambda_function], + "path2": [lambda_function], "layer1_path": [lambda_function], "layer2_path": [lambda_function], }, @@ -774,7 +776,7 @@ def test_watch_ZIP_lambda_function_with_layers(self): self.assertEqual( self.file_observer_mock.watch.call_args_list, [ - call("path1"), + call("path2"), call("layer1_path"), call("layer2_path"), ], @@ -784,6 +786,7 @@ def test_watch_ZIP_lambda_function_with_non_local_layers(self): lambda_function = Mock() lambda_function.packagetype = ZIP lambda_function.code_abs_path = "path1" + lambda_function.code_real_path = "path2" layer1_mock = LayerVersion(arn="arn", codeuri="layer1_path") layer2_mock = LayerVersion(arn="arn2", codeuri=None) @@ -793,7 +796,7 @@ def test_watch_ZIP_lambda_function_with_non_local_layers(self): self.lambda_function_observer._observed_functions, { ZIP: { - "path1": [lambda_function], + "path2": [lambda_function], "layer1_path": [lambda_function], }, IMAGE: {}, @@ -802,7 +805,7 @@ def test_watch_ZIP_lambda_function_with_non_local_layers(self): self.assertEqual( self.file_observer_mock.watch.call_args_list, [ - call("path1"), + call("path2"), call("layer1_path"), ], ) @@ -836,12 +839,14 @@ def setUp(self, ImageObserverMock, FileObserverMock): self.zip_lambda_function1 = Mock() self.zip_lambda_function1.packagetype = ZIP self.zip_lambda_function1.code_abs_path = "path1" + self.zip_lambda_function1.code_real_path = "path1" self.zip_lambda_function1.layers = [] self.lambda_function_observer.watch(self.zip_lambda_function1) self.zip_lambda_function2 = Mock() self.zip_lambda_function2.packagetype = ZIP self.zip_lambda_function2.code_abs_path = "path2" + self.zip_lambda_function2.code_real_path = "path2" layer1_mock = Mock() layer1_mock.codeuri = "layer1_path1" layer2_mock = Mock() @@ -852,6 +857,7 @@ def setUp(self, ImageObserverMock, FileObserverMock): self.zip_lambda_function3 = Mock() self.zip_lambda_function3.packagetype = ZIP self.zip_lambda_function3.code_abs_path = "path3" + self.zip_lambda_function3.code_real_path = "path3" self.zip_lambda_function3.layers = [layer1_mock] self.lambda_function_observer.watch(self.zip_lambda_function3) @@ -996,12 +1002,14 @@ def setUp(self, ImageObserverMock, FileObserverMock): self.zip_lambda_function1 = Mock() self.zip_lambda_function1.packagetype = ZIP self.zip_lambda_function1.code_abs_path = "path1" + self.zip_lambda_function1.code_real_path = "path1" self.zip_lambda_function1.layers = [] self.lambda_function_observer.watch(self.zip_lambda_function1) self.zip_lambda_function2 = Mock() self.zip_lambda_function2.packagetype = ZIP self.zip_lambda_function2.code_abs_path = "path2" + self.zip_lambda_function2.code_real_path = "path2" layer1_mock = Mock() layer1_mock.codeuri = "layer1_path1" layer2_mock = Mock() @@ -1012,6 +1020,7 @@ def setUp(self, ImageObserverMock, FileObserverMock): self.zip_lambda_function3 = Mock() self.zip_lambda_function3.packagetype = ZIP self.zip_lambda_function3.code_abs_path = "path3" + self.zip_lambda_function3.code_real_path = "path3" self.zip_lambda_function3.layers = [layer1_mock] self.lambda_function_observer.watch(self.zip_lambda_function3)