From 29357db2c30ec7923ddfceed170ef241e3c8575a Mon Sep 17 00:00:00 2001 From: Murat Yukselen Date: Wed, 11 Oct 2023 00:46:28 -0400 Subject: [PATCH 1/8] add: expose Docker --add-host to local invoke command Docker supports providing host to ip settings via add-host cli option. This change exposes this option similarly and utilizes in docker container creation. --- samcli/commands/local/cli_common/invoke_context.py | 12 ++++++++++++ samcli/commands/local/cli_common/options.py | 5 +++++ samcli/commands/local/invoke/cli.py | 4 ++++ samcli/commands/local/lib/local_lambda.py | 4 ++++ samcli/local/docker/container.py | 6 ++++++ samcli/local/docker/lambda_container.py | 4 ++++ samcli/local/lambdafn/runtime.py | 8 ++++++-- 7 files changed, 41 insertions(+), 2 deletions(-) diff --git a/samcli/commands/local/cli_common/invoke_context.py b/samcli/commands/local/cli_common/invoke_context.py index 30dc8b4c03..be6d0b5605 100644 --- a/samcli/commands/local/cli_common/invoke_context.py +++ b/samcli/commands/local/cli_common/invoke_context.py @@ -97,6 +97,7 @@ def __init__( shutdown: bool = False, container_host: Optional[str] = None, container_host_interface: Optional[str] = None, + add_host: Optional[list] = None, invoke_images: Optional[str] = None, ) -> None: """ @@ -148,6 +149,8 @@ def __init__( Optional. Host of locally emulated Lambda container container_host_interface string Optional. Interface that Docker host binds ports to + add_host list(string) + Optional. Docker --add-host flag support invoke_images dict Optional. A dictionary that defines the custom invoke image URI of each function """ @@ -177,6 +180,14 @@ def __init__( self._container_host = container_host self._container_host_interface = container_host_interface + + self._extra_hosts: Optional[Dict] = None + if add_host and len(add_host) > 0: + self._extra_hosts = {} + for host_to_ip in add_host: + host, ip = host_to_ip.split(":", maxsplit=1) + self._extra_hosts[host] = ip + self._invoke_images = invoke_images self._containers_mode = ContainersMode.COLD @@ -396,6 +407,7 @@ def local_lambda_runner(self) -> LocalLambdaRunner: debug_context=self._debug_context, container_host=self._container_host, container_host_interface=self._container_host_interface, + extra_hosts=self._extra_hosts, ) return self._local_lambda_runner diff --git a/samcli/commands/local/cli_common/options.py b/samcli/commands/local/cli_common/options.py index 3372a61647..01aa60d18c 100644 --- a/samcli/commands/local/cli_common/options.py +++ b/samcli/commands/local/cli_common/options.py @@ -64,6 +64,11 @@ def local_common_options(f): help="IP address of the host network interface that container ports should bind to. " "Use 0.0.0.0 to bind to all interfaces.", ), + click.option( + "--add-host", + multiple=True, + help="Utilize hostname to IP mapping via docker --add-host flag. Can be multiple." + ), click.option( "--invoke-image", "-ii", diff --git a/samcli/commands/local/invoke/cli.py b/samcli/commands/local/invoke/cli.py index ac3856bb00..a31d68386d 100644 --- a/samcli/commands/local/invoke/cli.py +++ b/samcli/commands/local/invoke/cli.py @@ -90,6 +90,7 @@ def cli( config_env, container_host, container_host_interface, + add_host, invoke_image, hook_name, skip_prepare_infra, @@ -121,6 +122,7 @@ def cli( parameter_overrides, container_host, container_host_interface, + add_host, invoke_image, hook_name, ) # pragma: no cover @@ -147,6 +149,7 @@ def do_cli( # pylint: disable=R0914 parameter_overrides, container_host, container_host_interface, + add_host, invoke_image, hook_name, ): @@ -195,6 +198,7 @@ def do_cli( # pylint: disable=R0914 shutdown=shutdown, container_host=container_host, container_host_interface=container_host_interface, + add_host=add_host, invoke_images=processed_invoke_images, ) as context: # Invoke the function diff --git a/samcli/commands/local/lib/local_lambda.py b/samcli/commands/local/lib/local_lambda.py index d0d1446b5c..30a11f6d75 100644 --- a/samcli/commands/local/lib/local_lambda.py +++ b/samcli/commands/local/lib/local_lambda.py @@ -51,6 +51,7 @@ def __init__( debug_context: Optional[DebugContext] = None, container_host: Optional[str] = None, container_host_interface: Optional[str] = None, + extra_hosts: Optional[dict] = None, ) -> None: """ Initializes the class @@ -65,6 +66,7 @@ def __init__( :param DebugContext debug_context: Optional. Debug context for the function (includes port, args, and path). :param string container_host: Optional. Host of locally emulated Lambda container :param string container_host_interface: Optional. Interface that Docker host binds ports to + :param dict extra_hosts: Optional. Dict of hostname to IP resolutions """ self.local_runtime = local_runtime @@ -78,6 +80,7 @@ def __init__( self._boto3_region: Optional[str] = None self.container_host = container_host self.container_host_interface = container_host_interface + self.extra_hosts = extra_hosts def invoke( self, @@ -149,6 +152,7 @@ def invoke( stderr=stderr, container_host=self.container_host, container_host_interface=self.container_host_interface, + extra_hosts=self.extra_hosts, ) except ContainerResponseException: # NOTE(sriram-mv): This should still result in a exit code zero to avoid regressions. diff --git a/samcli/local/docker/container.py b/samcli/local/docker/container.py index 2cf41db27c..61e88c7cc1 100644 --- a/samcli/local/docker/container.py +++ b/samcli/local/docker/container.py @@ -77,6 +77,7 @@ def __init__( container_host_interface="127.0.0.1", mount_with_write: bool = False, host_tmp_dir: Optional[str] = None, + extra_hosts: Optional[dict] = None ): """ Initializes the class with given configuration. This does not automatically create or run the container. @@ -98,6 +99,7 @@ def __init__( :param bool mount_with_write: Optional. Mount source code directory with write permissions when building on container :param string host_tmp_dir: Optional. Temporary directory on the host when mounting with write permissions. + :param dict extra_hosts: Optional. Dict of hostname to IP resolutions """ self._image = image @@ -112,6 +114,7 @@ def __init__( self._container_opts = container_opts self._additional_volumes = additional_volumes self._logs_thread = None + self._extra_hosts = extra_hosts # Use the given Docker client or create new one self.docker_client = docker_client or docker.from_env(version=DOCKER_MIN_API_VERSION) @@ -209,6 +212,9 @@ def create(self): # Ex: 128m => 128MB kwargs["mem_limit"] = "{}m".format(self._memory_limit_mb) + if self._extra_hosts: + kwargs["extra_hosts"] = self._extra_hosts + real_container = self.docker_client.containers.create(self._image, **kwargs) self.id = real_container.id diff --git a/samcli/local/docker/lambda_container.py b/samcli/local/docker/lambda_container.py index e7a89e4b94..425ee27092 100644 --- a/samcli/local/docker/lambda_container.py +++ b/samcli/local/docker/lambda_container.py @@ -49,6 +49,7 @@ def __init__( debug_options=None, container_host=None, container_host_interface=None, + extra_hosts=None, function_full_path=None, ): """ @@ -85,6 +86,8 @@ def __init__( Optional. Host of locally emulated Lambda container container_host_interface Optional. Interface that Docker host binds ports to + extra_hosts + Optional. Dict of hostname to IP resolutions function_full_path str Optional. The function full path, unique in all stacks """ @@ -136,6 +139,7 @@ def __init__( additional_volumes=additional_volumes, container_host=container_host, container_host_interface=container_host_interface, + extra_hosts=extra_hosts, ) @staticmethod diff --git a/samcli/local/lambdafn/runtime.py b/samcli/local/lambdafn/runtime.py index 0272604656..f82ec78bb5 100644 --- a/samcli/local/lambdafn/runtime.py +++ b/samcli/local/lambdafn/runtime.py @@ -46,7 +46,7 @@ def __init__(self, container_manager, image_builder): self._image_builder = image_builder self._temp_uncompressed_paths_to_be_cleaned = [] - def create(self, function_config, debug_context=None, container_host=None, container_host_interface=None): + def create(self, function_config, debug_context=None, container_host=None, container_host_interface=None, extra_hosts=None): """ Create a new Container for the passed function, then store it in a dictionary using the function name, so it can be retrieved later and used in the other functions. Make sure to use the debug_context only @@ -97,6 +97,7 @@ def create(self, function_config, debug_context=None, container_host=None, conta debug_options=debug_context, container_host=container_host, container_host_interface=container_host_interface, + extra_hosts=extra_hosts, function_full_path=function_config.full_path, ) try: @@ -159,6 +160,7 @@ def invoke( stderr: Optional[StreamWriter] = None, container_host=None, container_host_interface=None, + extra_hosts=None, ): """ Invoke the given Lambda function locally. @@ -181,12 +183,14 @@ def invoke( Host of locally emulated Lambda container :param string container_host_interface: Optional. Interface that Docker host binds ports to + :param dict extra_hosts: Optional. + Dict of hostname to IP resolutions :raises Keyboard """ container = None try: # Start the container. This call returns immediately after the container starts - container = self.create(function_config, debug_context, container_host, container_host_interface) + container = self.create(function_config, debug_context, container_host, container_host_interface, extra_hosts) container = self.run(container, function_config, debug_context) # Setup appropriate interrupt - timeout or Ctrl+C - before function starts executing and # get callback function to start timeout timer From d876cb01b8abffdc9f97b2dcca80476fc999ce1e Mon Sep 17 00:00:00 2001 From: Murat Yukselen Date: Wed, 11 Oct 2023 00:52:13 -0400 Subject: [PATCH 2/8] lint: formatting long lines --- samcli/local/lambdafn/runtime.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/samcli/local/lambdafn/runtime.py b/samcli/local/lambdafn/runtime.py index f82ec78bb5..a967aef293 100644 --- a/samcli/local/lambdafn/runtime.py +++ b/samcli/local/lambdafn/runtime.py @@ -46,7 +46,14 @@ def __init__(self, container_manager, image_builder): self._image_builder = image_builder self._temp_uncompressed_paths_to_be_cleaned = [] - def create(self, function_config, debug_context=None, container_host=None, container_host_interface=None, extra_hosts=None): + def create( + self, + function_config, + debug_context=None, + container_host=None, + container_host_interface=None, + extra_hosts=None + ): """ Create a new Container for the passed function, then store it in a dictionary using the function name, so it can be retrieved later and used in the other functions. Make sure to use the debug_context only @@ -190,7 +197,9 @@ def invoke( container = None try: # Start the container. This call returns immediately after the container starts - container = self.create(function_config, debug_context, container_host, container_host_interface, extra_hosts) + container = self.create( + function_config, debug_context, container_host, container_host_interface, extra_hosts + ) container = self.run(container, function_config, debug_context) # Setup appropriate interrupt - timeout or Ctrl+C - before function starts executing and # get callback function to start timeout timer From c31bf76adf37252bbcabc45ea1d5e32e8c195f28 Mon Sep 17 00:00:00 2001 From: Murat Yukselen Date: Fri, 13 Oct 2023 00:38:52 -0400 Subject: [PATCH 3/8] fix: unit tests for add-host cli option With these fixes, unit tests are aligned to handle add-host cli option and extra_hosts dictionary for Docker container creation. --- samcli/commands/local/cli_common/options.py | 1 + samcli/commands/local/invoke/core/options.py | 1 + samcli/commands/local/start_api/cli.py | 2 + .../commands/local/start_api/core/options.py | 1 + samcli/commands/local/start_lambda/cli.py | 2 + .../local/start_lambda/core/options.py | 1 + samcli/local/lambdafn/runtime.py | 4 +- .../local/cli_common/test_invoke_context.py | 92 +++++++++++++++++++ tests/unit/commands/local/invoke/test_cli.py | 4 + .../commands/local/lib/test_local_lambda.py | 4 + .../unit/commands/samconfig/test_samconfig.py | 5 + tests/unit/local/lambdafn/test_runtime.py | 8 ++ 12 files changed, 123 insertions(+), 2 deletions(-) diff --git a/samcli/commands/local/cli_common/options.py b/samcli/commands/local/cli_common/options.py index 01aa60d18c..ceec1c4914 100644 --- a/samcli/commands/local/cli_common/options.py +++ b/samcli/commands/local/cli_common/options.py @@ -66,6 +66,7 @@ def local_common_options(f): ), click.option( "--add-host", + default=None, multiple=True, help="Utilize hostname to IP mapping via docker --add-host flag. Can be multiple." ), diff --git a/samcli/commands/local/invoke/core/options.py b/samcli/commands/local/invoke/core/options.py index 25a9576b21..ff23f857f5 100644 --- a/samcli/commands/local/invoke/core/options.py +++ b/samcli/commands/local/invoke/core/options.py @@ -32,6 +32,7 @@ "shutdown", "container_host", "container_host_interface", + "add_host", "invoke_image", ] diff --git a/samcli/commands/local/start_api/cli.py b/samcli/commands/local/start_api/cli.py index c1929e1444..6b418af621 100644 --- a/samcli/commands/local/start_api/cli.py +++ b/samcli/commands/local/start_api/cli.py @@ -109,6 +109,7 @@ def cli( debug_function, container_host, container_host_interface, + add_host, invoke_image, hook_name, skip_prepare_infra, @@ -142,6 +143,7 @@ def cli( debug_function, container_host, container_host_interface, + add_host, invoke_image, hook_name, ) # pragma: no cover diff --git a/samcli/commands/local/start_api/core/options.py b/samcli/commands/local/start_api/core/options.py index 9ec4c03ce4..820709fd7c 100644 --- a/samcli/commands/local/start_api/core/options.py +++ b/samcli/commands/local/start_api/core/options.py @@ -36,6 +36,7 @@ "shutdown", "container_host", "container_host_interface", + "add_host", "invoke_image", ] diff --git a/samcli/commands/local/start_lambda/cli.py b/samcli/commands/local/start_lambda/cli.py index 338e76332c..859c07a0e2 100644 --- a/samcli/commands/local/start_lambda/cli.py +++ b/samcli/commands/local/start_lambda/cli.py @@ -96,6 +96,7 @@ def cli( debug_function, container_host, container_host_interface, + add_host, invoke_image, hook_name, skip_prepare_infra, @@ -128,6 +129,7 @@ def cli( debug_function, container_host, container_host_interface, + add_host, invoke_image, hook_name, ) # pragma: no cover diff --git a/samcli/commands/local/start_lambda/core/options.py b/samcli/commands/local/start_lambda/core/options.py index 73d3f97310..1a35f564ea 100644 --- a/samcli/commands/local/start_lambda/core/options.py +++ b/samcli/commands/local/start_lambda/core/options.py @@ -34,6 +34,7 @@ "shutdown", "container_host", "container_host_interface", + "add_host", "invoke_image", ] diff --git a/samcli/local/lambdafn/runtime.py b/samcli/local/lambdafn/runtime.py index a967aef293..4ac2efff1d 100644 --- a/samcli/local/lambdafn/runtime.py +++ b/samcli/local/lambdafn/runtime.py @@ -364,7 +364,7 @@ def __init__(self, container_manager, image_builder, observer=None): super().__init__(container_manager, image_builder) - def create(self, function_config, debug_context=None, container_host=None, container_host_interface=None): + def create(self, function_config, debug_context=None, container_host=None, container_host_interface=None, extra_hosts=None): """ Create a new Container for the passed function, then store it in a dictionary using the function name, so it can be retrieved later and used in the other functions. Make sure to use the debug_context only @@ -418,7 +418,7 @@ def create(self, function_config, debug_context=None, container_host=None, conta self._observer.watch(function_config) self._observer.start() - container = super().create(function_config, debug_context, container_host, container_host_interface) + container = super().create(function_config, debug_context, container_host, container_host_interface, extra_hosts) self._function_configs[function_config.full_path] = function_config self._containers[function_config.full_path] = container 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 b89d5b6115..8a4bbf733a 100644 --- a/tests/unit/commands/local/cli_common/test_invoke_context.py +++ b/tests/unit/commands/local/cli_common/test_invoke_context.py @@ -630,6 +630,7 @@ def test_must_create_runner( aws_region="region", container_host=None, container_host_interface=None, + extra_hosts=None, ) result = self.context.local_lambda_runner @@ -708,6 +709,7 @@ def test_must_create_runner_using_warm_containers( aws_region="region", container_host=None, container_host_interface=None, + extra_hosts=None, ) result = self.context.local_lambda_runner @@ -792,6 +794,95 @@ def test_must_create_runner_with_container_host_option( aws_region="region", container_host="abcdef", container_host_interface="192.168.100.101", + extra_hosts=None, + ) + + result = self.context.local_lambda_runner + self.assertEqual(result, runner_mock) + # assert that lambda runner is created only one time, and the cached version used in the second call + self.assertEqual(LocalLambdaMock.call_count, 1) + + @patch("samcli.local.lambdafn.runtime.LambdaFunctionObserver") + @patch("samcli.commands.local.cli_common.invoke_context.LambdaImage") + @patch("samcli.commands.local.cli_common.invoke_context.LayerDownloader") + @patch("samcli.commands.local.cli_common.invoke_context.LambdaRuntime") + @patch("samcli.commands.local.cli_common.invoke_context.LocalLambdaRunner") + @patch("samcli.commands.local.cli_common.invoke_context.SamFunctionProvider") + def test_must_create_runner_with_extra_hosts_option( + self, + SamFunctionProviderMock, + LocalLambdaMock, + LambdaRuntimeMock, + download_layers_mock, + lambda_image_patch, + LambdaFunctionObserver_patch, + ): + runtime_mock = Mock() + LambdaRuntimeMock.return_value = runtime_mock + + runner_mock = Mock() + LocalLambdaMock.return_value = runner_mock + + download_mock = Mock() + download_layers_mock.return_value = download_mock + + image_mock = Mock() + lambda_image_patch.return_value = image_mock + + LambdaFunctionObserver_mock = Mock() + LambdaFunctionObserver_patch.return_value = LambdaFunctionObserver_mock + + cwd = "cwd" + self.context = InvokeContext( + template_file="template_file", + function_identifier="id", + env_vars_file="env_vars_file", + docker_volume_basedir="volumedir", + docker_network="network", + log_file="log_file", + skip_pull_image=True, + force_image_build=True, + debug_ports=[1111], + debugger_path="path-to-debugger", + debug_args="args", + aws_profile="profile", + aws_region="region", + container_host="abcdef", + add_host=["prod-na.host:10.11.12.13", "gamma-na.host:10.22.23.24"], + ) + self.context.get_cwd = Mock() + self.context.get_cwd.return_value = cwd + + self.context._get_stacks = Mock() + self.context._get_stacks.return_value = [Mock()] + self.context._get_env_vars_value = Mock() + self.context._setup_log_file = Mock() + self.context._get_debug_context = Mock(return_value=None) + + container_manager_mock = Mock() + container_manager_mock.is_docker_reachable = PropertyMock(return_value=True) + self.context._get_container_manager = Mock(return_value=container_manager_mock) + + with self.context: + result = self.context.local_lambda_runner + self.assertEqual(result, runner_mock) + + LambdaRuntimeMock.assert_called_with(container_manager_mock, image_mock) + lambda_image_patch.assert_called_once_with(download_mock, True, True, invoke_images=None) + LocalLambdaMock.assert_called_with( + local_runtime=runtime_mock, + function_provider=ANY, + cwd=cwd, + debug_context=None, + env_vars_values=ANY, + aws_profile="profile", + aws_region="region", + container_host="abcdef", + container_host_interface=None, + extra_hosts={ + "prod-na.host":"10.11.12.13", + "gamma-na.host":"10.22.23.24", + } ) result = self.context.local_lambda_runner @@ -875,6 +966,7 @@ def test_must_create_runner_with_invoke_image_option( aws_region="region", container_host=None, container_host_interface=None, + extra_hosts=None, ) result = self.context.local_lambda_runner diff --git a/tests/unit/commands/local/invoke/test_cli.py b/tests/unit/commands/local/invoke/test_cli.py index bf17f13cb9..899e93d9dc 100644 --- a/tests/unit/commands/local/invoke/test_cli.py +++ b/tests/unit/commands/local/invoke/test_cli.py @@ -43,6 +43,7 @@ def setUp(self): self.profile = "profile" self.container_host = "localhost" self.container_host_interface = "127.0.0.1" + self.add_host = ("prod-na.host:10.11.12.13",), self.invoke_image = ("amazon/aws-sam-cli-emulation-image-python3.9",) self.hook_name = None @@ -72,6 +73,7 @@ def call_cli(self): shutdown=self.shutdown, container_host=self.container_host, container_host_interface=self.container_host_interface, + add_host=self.add_host, invoke_image=self.invoke_image, hook_name=self.hook_name, ) @@ -108,6 +110,7 @@ def test_cli_must_setup_context_and_invoke(self, get_event_mock, InvokeContextMo aws_profile=self.profile, container_host=self.container_host, container_host_interface=self.container_host_interface, + add_host=self.add_host, invoke_images={None: "amazon/aws-sam-cli-emulation-image-python3.9"}, ) @@ -147,6 +150,7 @@ def test_cli_must_invoke_with_no_event(self, get_event_mock, InvokeContextMock): aws_profile=self.profile, container_host=self.container_host, container_host_interface=self.container_host_interface, + add_host=self.add_host, invoke_images={None: "amazon/aws-sam-cli-emulation-image-python3.9"}, ) diff --git a/tests/unit/commands/local/lib/test_local_lambda.py b/tests/unit/commands/local/lib/test_local_lambda.py index dc5f4384bd..c759349c2d 100644 --- a/tests/unit/commands/local/lib/test_local_lambda.py +++ b/tests/unit/commands/local/lib/test_local_lambda.py @@ -569,6 +569,7 @@ def test_must_work(self, patched_validate_architecture_runtime): stderr=stderr, container_host=None, container_host_interface=None, + extra_hosts=None, ) @patch("samcli.commands.local.lib.local_lambda.validate_architecture_runtime") @@ -594,6 +595,7 @@ def test_must_work_packagetype_ZIP(self, patched_validate_architecture_runtime): stderr=stderr, container_host=None, container_host_interface=None, + extra_hosts=None, ) @patch("samcli.commands.local.lib.local_lambda.validate_architecture_runtime") @@ -677,6 +679,7 @@ def test_works_if_imageuri_and_Image_packagetype(self, patched_validate_architec stderr=stderr, container_host=None, container_host_interface=None, + extra_hosts=None, ) def test_must_raise_if_imageuri_not_found(self): @@ -756,6 +759,7 @@ def test_must_work(self, patched_validate_architecture_runtime): stderr=stderr, container_host="localhost", container_host_interface="127.0.0.1", + extra_hosts=None, ) diff --git a/tests/unit/commands/samconfig/test_samconfig.py b/tests/unit/commands/samconfig/test_samconfig.py index b2e0822c78..0d2276f342 100644 --- a/tests/unit/commands/samconfig/test_samconfig.py +++ b/tests/unit/commands/samconfig/test_samconfig.py @@ -392,6 +392,7 @@ def test_local_invoke(self, do_cli_mock): {"Key": "Value", "Key2": "Value2"}, "localhost", "127.0.0.1", + (), ("image",), None, ) @@ -456,6 +457,7 @@ def test_local_start_api(self, do_cli_mock): None, "localhost", "127.0.0.1", + (), ("image",), None, ) @@ -518,6 +520,7 @@ def test_local_start_lambda(self, do_cli_mock): None, "localhost", "127.0.0.1", + (), ("image",), None, ) @@ -1128,6 +1131,7 @@ def test_override_with_cli_params(self, do_cli_mock): None, "localhost", "127.0.0.1", + (), ("image",), None, ) @@ -1222,6 +1226,7 @@ def test_override_with_cli_params_and_envvars(self, do_cli_mock): None, "localhost", "127.0.0.1", + (), ("image",), None, ) diff --git a/tests/unit/local/lambdafn/test_runtime.py b/tests/unit/local/lambdafn/test_runtime.py index 42087ebd00..f0a963a0a8 100644 --- a/tests/unit/local/lambdafn/test_runtime.py +++ b/tests/unit/local/lambdafn/test_runtime.py @@ -91,6 +91,7 @@ def test_must_create_lambda_container(self, LambdaContainerMock, LogMock): memory_mb=self.DEFAULT_MEMORY, container_host=None, container_host_interface=None, + extra_hosts=None, function_full_path=self.full_path, ) # Run the container and get results @@ -161,6 +162,7 @@ def test_must_log_if_template_has_runtime_version(self, LambdaContainerMock, Log memory_mb=self.DEFAULT_MEMORY, container_host=None, container_host_interface=None, + extra_hosts=None, function_full_path=self.full_path, ) # Run the container and get results @@ -337,6 +339,7 @@ def test_must_run_container_and_wait_for_result(self, LambdaContainerMock): memory_mb=self.DEFAULT_MEMORY, container_host=None, container_host_interface=None, + extra_hosts=None, function_full_path=self.full_path, ) @@ -690,6 +693,7 @@ def test_must_run_container_then_wait_for_result_and_container_not_stopped( memory_mb=self.DEFAULT_MEMORY, container_host=None, container_host_interface=None, + extra_hosts=None, function_full_path=self.full_path, ) @@ -791,6 +795,7 @@ def test_must_create_non_cached_container(self, LambdaContainerMock, LambdaFunct memory_mb=self.DEFAULT_MEMORY, container_host=None, container_host_interface=None, + extra_hosts=None, function_full_path=self.full_path, ) @@ -837,6 +842,7 @@ def test_must_create_incase_function_config_changed(self, LambdaContainerMock, L memory_mb=self.DEFAULT_MEMORY, container_host=None, container_host_interface=None, + extra_hosts=None, function_full_path=self.full_path, ), call( @@ -854,6 +860,7 @@ def test_must_create_incase_function_config_changed(self, LambdaContainerMock, L memory_mb=self.DEFAULT_MEMORY, container_host=None, container_host_interface=None, + extra_hosts=None, function_full_path=self.full_path, ), ] @@ -925,6 +932,7 @@ def test_must_ignore_debug_options_if_function_name_is_not_debug_function( memory_mb=self.DEFAULT_MEMORY, container_host=None, container_host_interface=None, + extra_hosts=None, function_full_path=self.full_path, ) self.manager_mock.create.assert_called_with(container) From c7d6febe810ecd84bd77c983fd56aa28aaddae0f Mon Sep 17 00:00:00 2001 From: Murat Yukselen Date: Mon, 30 Oct 2023 14:14:28 -0400 Subject: [PATCH 4/8] fix: start-lambda cli is missing add_host for InvokeContext --- samcli/commands/local/start_lambda/cli.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/samcli/commands/local/start_lambda/cli.py b/samcli/commands/local/start_lambda/cli.py index 859c07a0e2..88a5078d7e 100644 --- a/samcli/commands/local/start_lambda/cli.py +++ b/samcli/commands/local/start_lambda/cli.py @@ -157,6 +157,7 @@ def do_cli( # pylint: disable=R0914 debug_function, container_host, container_host_interface, + add_host, invoke_image, hook_name, ): @@ -202,6 +203,7 @@ def do_cli( # pylint: disable=R0914 shutdown=shutdown, container_host=container_host, container_host_interface=container_host_interface, + add_host=add_host, invoke_images=processed_invoke_images, ) as invoke_context: service = LocalLambdaService(lambda_invoke_context=invoke_context, port=port, host=host) From de4cc11db6db3172dd202645989791b4224407de Mon Sep 17 00:00:00 2001 From: Murat Yukselen Date: Fri, 24 Nov 2023 13:16:54 -0500 Subject: [PATCH 5/8] refactor: move add_host parsing from InvokeContext This change moves add_host parameter parsing into its own type DockerAdditionalHostType . --- samcli/cli/types.py | 27 +++++++++++++++++++ samcli/commands/_utils/options.py | 15 +++++++++++ .../local/cli_common/invoke_context.py | 13 +++------ samcli/commands/local/cli_common/options.py | 18 ++++++++++--- samcli/local/docker/container.py | 2 +- samcli/local/lambdafn/runtime.py | 15 +++++------ .../local/cli_common/test_invoke_context.py | 8 +++--- tests/unit/commands/local/invoke/test_cli.py | 2 +- .../commands/local/start_lambda/test_cli.py | 3 +++ .../unit/commands/samconfig/test_samconfig.py | 10 +++---- .../passing_tests/local_invokecmd.toml | 4 ++- .../passing_tests/local_start_apicmd.toml | 4 ++- .../passing_tests/local_start_lambdacmd.toml | 4 ++- 13 files changed, 91 insertions(+), 34 deletions(-) diff --git a/samcli/cli/types.py b/samcli/cli/types.py index 04f8f27446..51f11e3aca 100644 --- a/samcli/cli/types.py +++ b/samcli/cli/types.py @@ -452,6 +452,33 @@ def convert(self, value, param, ctx): return {key: _value} +class DockerAdditionalHostType(click.ParamType): + """ + Custom Parameter Type for managing Docker container's host file for local commands + """ + + name = "list" + MIN_KEY_VALUE_PAIR_LENGTH = 2 + + def convert(self, value, param, ctx): + """Converts the user provided parameters value with the format "host:IP" to dict + {"host": "IP"} + + Parameters + ------------ + value: User provided value for the click option + param: click parameter + ctx: Context + """ + host_ip_pair = value.split(":", maxsplit=1) + if len(host_ip_pair) < self.MIN_KEY_VALUE_PAIR_LENGTH: + raise click.BadParameter(f"{param.opts[0]} is not a valid format, it needs to be of the form hostname:IP") + host = host_ip_pair[0] + ip = host_ip_pair[1] + LOG.debug("Converting provided %s option value to dict", param.opts[0]) + return {host: ip} + + class RemoteInvokeOutputFormatType(click.Choice): """ Custom Parameter Type for output-format option of remote invoke command. diff --git a/samcli/commands/_utils/options.py b/samcli/commands/_utils/options.py index 737c8ecdd2..735bff97e6 100644 --- a/samcli/commands/_utils/options.py +++ b/samcli/commands/_utils/options.py @@ -145,6 +145,21 @@ def remote_invoke_boto_parameter_callback(ctx, param, provided_value): return boto_api_parameters +def local_add_host_callback(ctx, param, provided_value): + """ + Create a dictionary of hostnames to IP addresses to add into Docker container's hosts file. + :param ctx: Click Context + :param param: Param name + :param provided_value: Value provided by Click, after being processed by DockerAdditionalHostType. + :return: dictionary of hostnames to IP addresses. + """ + extra_hosts = {} + for value in provided_value: + extra_hosts.update(value) + + return extra_hosts + + def artifact_callback(ctx, param, provided_value, artifact): """ Provide an error if there are zip/image artifact based resources, diff --git a/samcli/commands/local/cli_common/invoke_context.py b/samcli/commands/local/cli_common/invoke_context.py index be6d0b5605..fc7ca7020d 100644 --- a/samcli/commands/local/cli_common/invoke_context.py +++ b/samcli/commands/local/cli_common/invoke_context.py @@ -97,7 +97,7 @@ def __init__( shutdown: bool = False, container_host: Optional[str] = None, container_host_interface: Optional[str] = None, - add_host: Optional[list] = None, + add_host: Optional[dict] = None, invoke_images: Optional[str] = None, ) -> None: """ @@ -149,8 +149,8 @@ def __init__( Optional. Host of locally emulated Lambda container container_host_interface string Optional. Interface that Docker host binds ports to - add_host list(string) - Optional. Docker --add-host flag support + add_host dict + Optional. Docker extra hosts support from --add-host parameters invoke_images dict Optional. A dictionary that defines the custom invoke image URI of each function """ @@ -181,12 +181,7 @@ def __init__( self._container_host = container_host self._container_host_interface = container_host_interface - self._extra_hosts: Optional[Dict] = None - if add_host and len(add_host) > 0: - self._extra_hosts = {} - for host_to_ip in add_host: - host, ip = host_to_ip.split(":", maxsplit=1) - self._extra_hosts[host] = ip + self._extra_hosts: Optional[Dict] = add_host self._invoke_images = invoke_images diff --git a/samcli/commands/local/cli_common/options.py b/samcli/commands/local/cli_common/options.py index ceec1c4914..869a6c8395 100644 --- a/samcli/commands/local/cli_common/options.py +++ b/samcli/commands/local/cli_common/options.py @@ -5,7 +5,13 @@ import click -from samcli.commands._utils.options import docker_click_options, parameter_override_click_option, template_click_option +from samcli.cli.types import DockerAdditionalHostType +from samcli.commands._utils.options import ( + docker_click_options, + local_add_host_callback, + parameter_override_click_option, + template_click_option, +) from samcli.commands.local.cli_common.invoke_context import ContainersInitializationMode @@ -66,9 +72,15 @@ def local_common_options(f): ), click.option( "--add-host", - default=None, multiple=True, - help="Utilize hostname to IP mapping via docker --add-host flag. Can be multiple." + type=DockerAdditionalHostType(), + callback=local_add_host_callback, + required=False, + help="Passes a hostname to IP address mapping to the Docker container's host file. " + "This parameter can be passed multiple times." + "" + "Example:" + "--add-host example.com:127.0.0.1", ), click.option( "--invoke-image", diff --git a/samcli/local/docker/container.py b/samcli/local/docker/container.py index 61e88c7cc1..4c54d4a63c 100644 --- a/samcli/local/docker/container.py +++ b/samcli/local/docker/container.py @@ -77,7 +77,7 @@ def __init__( container_host_interface="127.0.0.1", mount_with_write: bool = False, host_tmp_dir: Optional[str] = None, - extra_hosts: Optional[dict] = None + extra_hosts: Optional[dict] = None, ): """ Initializes the class with given configuration. This does not automatically create or run the container. diff --git a/samcli/local/lambdafn/runtime.py b/samcli/local/lambdafn/runtime.py index 4ac2efff1d..cfea640b74 100644 --- a/samcli/local/lambdafn/runtime.py +++ b/samcli/local/lambdafn/runtime.py @@ -47,12 +47,7 @@ def __init__(self, container_manager, image_builder): self._temp_uncompressed_paths_to_be_cleaned = [] def create( - self, - function_config, - debug_context=None, - container_host=None, - container_host_interface=None, - extra_hosts=None + self, function_config, debug_context=None, container_host=None, container_host_interface=None, extra_hosts=None ): """ Create a new Container for the passed function, then store it in a dictionary using the function name, @@ -364,7 +359,9 @@ def __init__(self, container_manager, image_builder, observer=None): super().__init__(container_manager, image_builder) - def create(self, function_config, debug_context=None, container_host=None, container_host_interface=None, extra_hosts=None): + def create( + self, function_config, debug_context=None, container_host=None, container_host_interface=None, extra_hosts=None + ): """ Create a new Container for the passed function, then store it in a dictionary using the function name, so it can be retrieved later and used in the other functions. Make sure to use the debug_context only @@ -418,7 +415,9 @@ def create(self, function_config, debug_context=None, container_host=None, conta self._observer.watch(function_config) self._observer.start() - container = super().create(function_config, debug_context, container_host, container_host_interface, extra_hosts) + container = super().create( + function_config, debug_context, container_host, container_host_interface, extra_hosts + ) self._function_configs[function_config.full_path] = function_config self._containers[function_config.full_path] = container 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 8a4bbf733a..82678fd648 100644 --- a/tests/unit/commands/local/cli_common/test_invoke_context.py +++ b/tests/unit/commands/local/cli_common/test_invoke_context.py @@ -848,7 +848,7 @@ def test_must_create_runner_with_extra_hosts_option( aws_profile="profile", aws_region="region", container_host="abcdef", - add_host=["prod-na.host:10.11.12.13", "gamma-na.host:10.22.23.24"], + add_host={"prod-na.host":"10.11.12.13", "gamma-na.host":"10.22.23.24"}, ) self.context.get_cwd = Mock() self.context.get_cwd.return_value = cwd @@ -880,9 +880,9 @@ def test_must_create_runner_with_extra_hosts_option( container_host="abcdef", container_host_interface=None, extra_hosts={ - "prod-na.host":"10.11.12.13", - "gamma-na.host":"10.22.23.24", - } + "prod-na.host": "10.11.12.13", + "gamma-na.host": "10.22.23.24", + }, ) result = self.context.local_lambda_runner diff --git a/tests/unit/commands/local/invoke/test_cli.py b/tests/unit/commands/local/invoke/test_cli.py index 899e93d9dc..eae55f915a 100644 --- a/tests/unit/commands/local/invoke/test_cli.py +++ b/tests/unit/commands/local/invoke/test_cli.py @@ -43,7 +43,7 @@ def setUp(self): self.profile = "profile" self.container_host = "localhost" self.container_host_interface = "127.0.0.1" - self.add_host = ("prod-na.host:10.11.12.13",), + self.add_host = ["prod-na.host:10.11.12.13"], self.invoke_image = ("amazon/aws-sam-cli-emulation-image-python3.9",) self.hook_name = None diff --git a/tests/unit/commands/local/start_lambda/test_cli.py b/tests/unit/commands/local/start_lambda/test_cli.py index 4eb6dcdaeb..aa779ed871 100644 --- a/tests/unit/commands/local/start_lambda/test_cli.py +++ b/tests/unit/commands/local/start_lambda/test_cli.py @@ -42,6 +42,7 @@ def setUp(self): self.container_host = "localhost" self.container_host_interface = "127.0.0.1" + self.add_host = {} self.invoke_image = () self.hook_name = None @@ -81,6 +82,7 @@ def test_cli_must_setup_context_and_start_service(self, local_lambda_service_moc shutdown=self.shutdown, container_host=self.container_host, container_host_interface=self.container_host_interface, + add_host=self.add_host, invoke_images={}, ) @@ -180,6 +182,7 @@ def call_cli(self): shutdown=self.shutdown, container_host=self.container_host, container_host_interface=self.container_host_interface, + add_host=self.add_host, invoke_image=self.invoke_image, hook_name=self.hook_name, ) diff --git a/tests/unit/commands/samconfig/test_samconfig.py b/tests/unit/commands/samconfig/test_samconfig.py index 0d2276f342..f8c4d43ac9 100644 --- a/tests/unit/commands/samconfig/test_samconfig.py +++ b/tests/unit/commands/samconfig/test_samconfig.py @@ -392,7 +392,7 @@ def test_local_invoke(self, do_cli_mock): {"Key": "Value", "Key2": "Value2"}, "localhost", "127.0.0.1", - (), + {}, ("image",), None, ) @@ -457,7 +457,7 @@ def test_local_start_api(self, do_cli_mock): None, "localhost", "127.0.0.1", - (), + {}, ("image",), None, ) @@ -520,7 +520,7 @@ def test_local_start_lambda(self, do_cli_mock): None, "localhost", "127.0.0.1", - (), + {}, ("image",), None, ) @@ -1131,7 +1131,7 @@ def test_override_with_cli_params(self, do_cli_mock): None, "localhost", "127.0.0.1", - (), + {}, ("image",), None, ) @@ -1226,7 +1226,7 @@ def test_override_with_cli_params_and_envvars(self, do_cli_mock): None, "localhost", "127.0.0.1", - (), + {}, ("image",), None, ) diff --git a/tests/unit/schema/testdata/passing_tests/local_invokecmd.toml b/tests/unit/schema/testdata/passing_tests/local_invokecmd.toml index d5cd5f24a3..5acd318938 100644 --- a/tests/unit/schema/testdata/passing_tests/local_invokecmd.toml +++ b/tests/unit/schema/testdata/passing_tests/local_invokecmd.toml @@ -21,6 +21,7 @@ force_image_build = false shutdown = false container_host = "Container host" container_host_interface = "Container host interface" +add_host = [] invoke_image = "Invoke image" beta_features = false debug = false @@ -35,5 +36,6 @@ debug_port = 20 skip_pull_image = true force_image_build = true shutdown = true +add_host = ["example.com:127.0.0.1"] beta_features = true -debug = true \ No newline at end of file +debug = true diff --git a/tests/unit/schema/testdata/passing_tests/local_start_apicmd.toml b/tests/unit/schema/testdata/passing_tests/local_start_apicmd.toml index bb833a2419..e011c7977b 100644 --- a/tests/unit/schema/testdata/passing_tests/local_start_apicmd.toml +++ b/tests/unit/schema/testdata/passing_tests/local_start_apicmd.toml @@ -24,6 +24,7 @@ debug_function = "Debug function" shutdown = false container_host = "Container host" container_host_interface = "Container host interface" +add_host = [] invoke_image = "Invoke image" beta_features = false debug = false @@ -39,5 +40,6 @@ skip_pull_image = true force_image_build = true warm_containers = "LAZY" shutdown = true +add_host = ["example.com:127.0.0.1"] beta_features = true -debug = true \ No newline at end of file +debug = true diff --git a/tests/unit/schema/testdata/passing_tests/local_start_lambdacmd.toml b/tests/unit/schema/testdata/passing_tests/local_start_lambdacmd.toml index b738f8639b..f99641e18b 100644 --- a/tests/unit/schema/testdata/passing_tests/local_start_lambdacmd.toml +++ b/tests/unit/schema/testdata/passing_tests/local_start_lambdacmd.toml @@ -23,6 +23,7 @@ debug_function = "Debug function" shutdown = false container_host = "Container host" container_host_interface = "Container host interface" +add_host = [] invoke_image = "Invoke image" beta_features = false debug = false @@ -38,5 +39,6 @@ skip_pull_image = true force_image_build = true warm_containers = "LAZY" shutdown = true +add_host = ["example.com:127.0.0.1"] beta_features = true -debug = true \ No newline at end of file +debug = true From d2428c67d92a95b7c83b893cb19badfe629d6b15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Murat=20Y=C3=BCkselen?= Date: Tue, 12 Dec 2023 17:09:17 -0500 Subject: [PATCH 6/8] Update lambda_container.py deleting the extra line --- samcli/local/docker/lambda_container.py | 1 - 1 file changed, 1 deletion(-) diff --git a/samcli/local/docker/lambda_container.py b/samcli/local/docker/lambda_container.py index b1f0ffdba7..0e3a96efad 100644 --- a/samcli/local/docker/lambda_container.py +++ b/samcli/local/docker/lambda_container.py @@ -52,7 +52,6 @@ def __init__( container_host=None, container_host_interface=DEFAULT_CONTAINER_HOST_INTERFACE, extra_hosts=None, - container_host_interface=DEFAULT_CONTAINER_HOST_INTERFACE, function_full_path=None, ): """ From b7eab61bb474d0fae855f1470105832f24662678 Mon Sep 17 00:00:00 2001 From: Murat Yukselen Date: Fri, 15 Dec 2023 14:01:44 -0500 Subject: [PATCH 7/8] style: applied formatting --- tests/unit/commands/local/cli_common/test_invoke_context.py | 2 +- tests/unit/commands/local/invoke/test_cli.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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 82678fd648..f30a9574fc 100644 --- a/tests/unit/commands/local/cli_common/test_invoke_context.py +++ b/tests/unit/commands/local/cli_common/test_invoke_context.py @@ -848,7 +848,7 @@ def test_must_create_runner_with_extra_hosts_option( aws_profile="profile", aws_region="region", container_host="abcdef", - add_host={"prod-na.host":"10.11.12.13", "gamma-na.host":"10.22.23.24"}, + add_host={"prod-na.host": "10.11.12.13", "gamma-na.host": "10.22.23.24"}, ) self.context.get_cwd = Mock() self.context.get_cwd.return_value = cwd diff --git a/tests/unit/commands/local/invoke/test_cli.py b/tests/unit/commands/local/invoke/test_cli.py index eae55f915a..a033905b8c 100644 --- a/tests/unit/commands/local/invoke/test_cli.py +++ b/tests/unit/commands/local/invoke/test_cli.py @@ -43,7 +43,7 @@ def setUp(self): self.profile = "profile" self.container_host = "localhost" self.container_host_interface = "127.0.0.1" - self.add_host = ["prod-na.host:10.11.12.13"], + self.add_host = (["prod-na.host:10.11.12.13"],) self.invoke_image = ("amazon/aws-sam-cli-emulation-image-python3.9",) self.hook_name = None From 6a3299329c0745412b9de87ecfaedcd731821557 Mon Sep 17 00:00:00 2001 From: Murat Yukselen Date: Mon, 18 Dec 2023 17:20:51 -0500 Subject: [PATCH 8/8] fix: add missing schema changes for add-host cli option --- schema/samcli.json | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/schema/samcli.json b/schema/samcli.json index c620315e8c..b7cacb9e4c 100644 --- a/schema/samcli.json +++ b/schema/samcli.json @@ -403,7 +403,7 @@ "properties": { "parameters": { "title": "Parameters for the local invoke command", - "description": "Available parameters for the local invoke command:\n* terraform_plan_file:\nUsed for passing a custom plan file when executing the Terraform hook.\n* hook_name:\nHook package id to extend AWS SAM CLI commands functionality. \n\nExample: `terraform` to extend AWS SAM CLI commands functionality to support terraform applications. \n\nAvailable Hook Names: ['terraform']\n* skip_prepare_infra:\nSkip preparation stage when there are no infrastructure changes. Only used in conjunction with --hook-name.\n* event:\nJSON file containing event data passed to the Lambda function during invoke. If this option is not specified, no event is assumed. Pass in the value '-' to input JSON via stdin\n* no_event:\nDEPRECATED: By default no event is assumed.\n* template_file:\nAWS SAM template which references built artifacts for resources in the template. (if applicable)\n* env_vars:\nJSON file containing values for Lambda function's environment variables.\n* parameter_overrides:\nString that contains AWS CloudFormation parameter overrides encoded as key=value pairs.\n* debug_port:\nWhen specified, Lambda function container will start in debug mode and will expose this port on localhost.\n* debugger_path:\nHost path to a debugger that will be mounted into the Lambda container.\n* debug_args:\nAdditional arguments to be passed to the debugger.\n* container_env_vars:\nJSON file containing additional environment variables to be set within the container when used in a debugging session locally.\n* docker_volume_basedir:\nSpecify the location basedir where the SAM template exists. If Docker is running on a remote machine, Path of the SAM template must be mounted on the Docker machine and modified to match the remote machine.\n* log_file:\nFile to capture output logs.\n* layer_cache_basedir:\nSpecify the location basedir where the lambda layers used by the template will be downloaded to.\n* skip_pull_image:\nSkip pulling down the latest Docker image for Lambda runtime.\n* docker_network:\nName or ID of an existing docker network for AWS Lambda docker containers to connect to, along with the default bridge network. If not specified, the Lambda containers will only connect to the default bridge docker network.\n* force_image_build:\nForce rebuilding the image used for invoking functions with layers.\n* shutdown:\nEmulate a shutdown event after invoke completes, to test extension handling of shutdown behavior.\n* container_host:\nHost of locally emulated Lambda container. This option is useful when the container runs on a different host than AWS SAM CLI. For example, if one wants to run AWS SAM CLI in a Docker container on macOS, this option could specify `host.docker.internal`\n* container_host_interface:\nIP address of the host network interface that container ports should bind to. Use 0.0.0.0 to bind to all interfaces.\n* invoke_image:\nContainer image URIs for invoking functions or starting api and function. One can specify the image URI used for the local function invocation (--invoke-image public.ecr.aws/sam/build-nodejs14.x:latest). One can also specify for each individual function with (--invoke-image Function1=public.ecr.aws/sam/build-nodejs14.x:latest). If a function does not have invoke image specified, the default AWS SAM CLI emulation image will be used.\n* beta_features:\nEnable/Disable beta features.\n* debug:\nTurn on debug logging to print debug message generated by AWS SAM CLI and display timestamps.\n* profile:\nSelect a specific profile from your credential file to get AWS credentials.\n* region:\nSet the AWS Region of the service. (e.g. us-east-1)\n* save_params:\nSave the parameters provided via the command line to the configuration file.", + "description": "Available parameters for the local invoke command:\n* terraform_plan_file:\nUsed for passing a custom plan file when executing the Terraform hook.\n* hook_name:\nHook package id to extend AWS SAM CLI commands functionality. \n\nExample: `terraform` to extend AWS SAM CLI commands functionality to support terraform applications. \n\nAvailable Hook Names: ['terraform']\n* skip_prepare_infra:\nSkip preparation stage when there are no infrastructure changes. Only used in conjunction with --hook-name.\n* event:\nJSON file containing event data passed to the Lambda function during invoke. If this option is not specified, no event is assumed. Pass in the value '-' to input JSON via stdin\n* no_event:\nDEPRECATED: By default no event is assumed.\n* template_file:\nAWS SAM template which references built artifacts for resources in the template. (if applicable)\n* env_vars:\nJSON file containing values for Lambda function's environment variables.\n* parameter_overrides:\nString that contains AWS CloudFormation parameter overrides encoded as key=value pairs.\n* debug_port:\nWhen specified, Lambda function container will start in debug mode and will expose this port on localhost.\n* debugger_path:\nHost path to a debugger that will be mounted into the Lambda container.\n* debug_args:\nAdditional arguments to be passed to the debugger.\n* container_env_vars:\nJSON file containing additional environment variables to be set within the container when used in a debugging session locally.\n* docker_volume_basedir:\nSpecify the location basedir where the SAM template exists. If Docker is running on a remote machine, Path of the SAM template must be mounted on the Docker machine and modified to match the remote machine.\n* log_file:\nFile to capture output logs.\n* layer_cache_basedir:\nSpecify the location basedir where the lambda layers used by the template will be downloaded to.\n* skip_pull_image:\nSkip pulling down the latest Docker image for Lambda runtime.\n* docker_network:\nName or ID of an existing docker network for AWS Lambda docker containers to connect to, along with the default bridge network. If not specified, the Lambda containers will only connect to the default bridge docker network.\n* force_image_build:\nForce rebuilding the image used for invoking functions with layers.\n* shutdown:\nEmulate a shutdown event after invoke completes, to test extension handling of shutdown behavior.\n* container_host:\nHost of locally emulated Lambda container. This option is useful when the container runs on a different host than AWS SAM CLI. For example, if one wants to run AWS SAM CLI in a Docker container on macOS, this option could specify `host.docker.internal`\n* container_host_interface:\nIP address of the host network interface that container ports should bind to. Use 0.0.0.0 to bind to all interfaces.\n* add_host:\nPasses a hostname to IP address mapping to the Docker container's host file. This parameter can be passed multiple times.Example:--add-host example.com:127.0.0.1\n* invoke_image:\nContainer image URIs for invoking functions or starting api and function. One can specify the image URI used for the local function invocation (--invoke-image public.ecr.aws/sam/build-nodejs14.x:latest). One can also specify for each individual function with (--invoke-image Function1=public.ecr.aws/sam/build-nodejs14.x:latest). If a function does not have invoke image specified, the default AWS SAM CLI emulation image will be used.\n* beta_features:\nEnable/Disable beta features.\n* debug:\nTurn on debug logging to print debug message generated by AWS SAM CLI and display timestamps.\n* profile:\nSelect a specific profile from your credential file to get AWS credentials.\n* region:\nSet the AWS Region of the service. (e.g. us-east-1)\n* save_params:\nSave the parameters provided via the command line to the configuration file.", "type": "object", "properties": { "terraform_plan_file": { @@ -521,6 +521,14 @@ "description": "IP address of the host network interface that container ports should bind to. Use 0.0.0.0 to bind to all interfaces.", "default": "127.0.0.1" }, + "add_host": { + "title": "add_host", + "type": "array", + "description": "Passes a hostname to IP address mapping to the Docker container's host file. This parameter can be passed multiple times.Example:--add-host example.com:127.0.0.1", + "items": { + "type": "string" + } + }, "invoke_image": { "title": "invoke_image", "type": "string", @@ -564,7 +572,7 @@ "properties": { "parameters": { "title": "Parameters for the local start api command", - "description": "Available parameters for the local start api command:\n* terraform_plan_file:\nUsed for passing a custom plan file when executing the Terraform hook.\n* hook_name:\nHook package id to extend AWS SAM CLI commands functionality. \n\nExample: `terraform` to extend AWS SAM CLI commands functionality to support terraform applications. \n\nAvailable Hook Names: ['terraform']\n* skip_prepare_infra:\nSkip preparation stage when there are no infrastructure changes. Only used in conjunction with --hook-name.\n* host:\nLocal hostname or IP address to bind to (default: '127.0.0.1')\n* port:\nLocal port number to listen on (default: '3000')\n* static_dir:\nAny static assets (e.g. CSS/Javascript/HTML) files located in this directory will be presented at /\n* disable_authorizer:\nDisable custom Lambda Authorizers from being parsed and invoked.\n* ssl_cert_file:\nPath to SSL certificate file (default: None)\n* ssl_key_file:\nPath to SSL key file (default: None)\n* template_file:\nAWS SAM template which references built artifacts for resources in the template. (if applicable)\n* env_vars:\nJSON file containing values for Lambda function's environment variables.\n* parameter_overrides:\nString that contains AWS CloudFormation parameter overrides encoded as key=value pairs.\n* debug_port:\nWhen specified, Lambda function container will start in debug mode and will expose this port on localhost.\n* debugger_path:\nHost path to a debugger that will be mounted into the Lambda container.\n* debug_args:\nAdditional arguments to be passed to the debugger.\n* container_env_vars:\nJSON file containing additional environment variables to be set within the container when used in a debugging session locally.\n* docker_volume_basedir:\nSpecify the location basedir where the SAM template exists. If Docker is running on a remote machine, Path of the SAM template must be mounted on the Docker machine and modified to match the remote machine.\n* log_file:\nFile to capture output logs.\n* layer_cache_basedir:\nSpecify the location basedir where the lambda layers used by the template will be downloaded to.\n* skip_pull_image:\nSkip pulling down the latest Docker image for Lambda runtime.\n* docker_network:\nName or ID of an existing docker network for AWS Lambda docker containers to connect to, along with the default bridge network. If not specified, the Lambda containers will only connect to the default bridge docker network.\n* force_image_build:\nForce rebuilding the image used for invoking functions with layers.\n* warm_containers:\nOptional. Specifies how AWS SAM CLI manages \ncontainers for each function.\nTwo modes are available:\nEAGER: Containers for all functions are \nloaded at startup and persist between \ninvocations.\nLAZY: Containers are only loaded when each \nfunction is first invoked. Those containers \npersist for additional invocations.\n* debug_function:\nOptional. Specifies the Lambda Function logicalId to apply debug options to when --warm-containers is specified. This parameter applies to --debug-port, --debugger-path, and --debug-args.\n* shutdown:\nEmulate a shutdown event after invoke completes, to test extension handling of shutdown behavior.\n* container_host:\nHost of locally emulated Lambda container. This option is useful when the container runs on a different host than AWS SAM CLI. For example, if one wants to run AWS SAM CLI in a Docker container on macOS, this option could specify `host.docker.internal`\n* container_host_interface:\nIP address of the host network interface that container ports should bind to. Use 0.0.0.0 to bind to all interfaces.\n* invoke_image:\nContainer image URIs for invoking functions or starting api and function. One can specify the image URI used for the local function invocation (--invoke-image public.ecr.aws/sam/build-nodejs14.x:latest). One can also specify for each individual function with (--invoke-image Function1=public.ecr.aws/sam/build-nodejs14.x:latest). If a function does not have invoke image specified, the default AWS SAM CLI emulation image will be used.\n* beta_features:\nEnable/Disable beta features.\n* debug:\nTurn on debug logging to print debug message generated by AWS SAM CLI and display timestamps.\n* profile:\nSelect a specific profile from your credential file to get AWS credentials.\n* region:\nSet the AWS Region of the service. (e.g. us-east-1)\n* save_params:\nSave the parameters provided via the command line to the configuration file.", + "description": "Available parameters for the local start api command:\n* terraform_plan_file:\nUsed for passing a custom plan file when executing the Terraform hook.\n* hook_name:\nHook package id to extend AWS SAM CLI commands functionality. \n\nExample: `terraform` to extend AWS SAM CLI commands functionality to support terraform applications. \n\nAvailable Hook Names: ['terraform']\n* skip_prepare_infra:\nSkip preparation stage when there are no infrastructure changes. Only used in conjunction with --hook-name.\n* host:\nLocal hostname or IP address to bind to (default: '127.0.0.1')\n* port:\nLocal port number to listen on (default: '3000')\n* static_dir:\nAny static assets (e.g. CSS/Javascript/HTML) files located in this directory will be presented at /\n* disable_authorizer:\nDisable custom Lambda Authorizers from being parsed and invoked.\n* ssl_cert_file:\nPath to SSL certificate file (default: None)\n* ssl_key_file:\nPath to SSL key file (default: None)\n* template_file:\nAWS SAM template which references built artifacts for resources in the template. (if applicable)\n* env_vars:\nJSON file containing values for Lambda function's environment variables.\n* parameter_overrides:\nString that contains AWS CloudFormation parameter overrides encoded as key=value pairs.\n* debug_port:\nWhen specified, Lambda function container will start in debug mode and will expose this port on localhost.\n* debugger_path:\nHost path to a debugger that will be mounted into the Lambda container.\n* debug_args:\nAdditional arguments to be passed to the debugger.\n* container_env_vars:\nJSON file containing additional environment variables to be set within the container when used in a debugging session locally.\n* docker_volume_basedir:\nSpecify the location basedir where the SAM template exists. If Docker is running on a remote machine, Path of the SAM template must be mounted on the Docker machine and modified to match the remote machine.\n* log_file:\nFile to capture output logs.\n* layer_cache_basedir:\nSpecify the location basedir where the lambda layers used by the template will be downloaded to.\n* skip_pull_image:\nSkip pulling down the latest Docker image for Lambda runtime.\n* docker_network:\nName or ID of an existing docker network for AWS Lambda docker containers to connect to, along with the default bridge network. If not specified, the Lambda containers will only connect to the default bridge docker network.\n* force_image_build:\nForce rebuilding the image used for invoking functions with layers.\n* warm_containers:\nOptional. Specifies how AWS SAM CLI manages \ncontainers for each function.\nTwo modes are available:\nEAGER: Containers for all functions are \nloaded at startup and persist between \ninvocations.\nLAZY: Containers are only loaded when each \nfunction is first invoked. Those containers \npersist for additional invocations.\n* debug_function:\nOptional. Specifies the Lambda Function logicalId to apply debug options to when --warm-containers is specified. This parameter applies to --debug-port, --debugger-path, and --debug-args.\n* shutdown:\nEmulate a shutdown event after invoke completes, to test extension handling of shutdown behavior.\n* container_host:\nHost of locally emulated Lambda container. This option is useful when the container runs on a different host than AWS SAM CLI. For example, if one wants to run AWS SAM CLI in a Docker container on macOS, this option could specify `host.docker.internal`\n* container_host_interface:\nIP address of the host network interface that container ports should bind to. Use 0.0.0.0 to bind to all interfaces.\n* add_host:\nPasses a hostname to IP address mapping to the Docker container's host file. This parameter can be passed multiple times.Example:--add-host example.com:127.0.0.1\n* invoke_image:\nContainer image URIs for invoking functions or starting api and function. One can specify the image URI used for the local function invocation (--invoke-image public.ecr.aws/sam/build-nodejs14.x:latest). One can also specify for each individual function with (--invoke-image Function1=public.ecr.aws/sam/build-nodejs14.x:latest). If a function does not have invoke image specified, the default AWS SAM CLI emulation image will be used.\n* beta_features:\nEnable/Disable beta features.\n* debug:\nTurn on debug logging to print debug message generated by AWS SAM CLI and display timestamps.\n* profile:\nSelect a specific profile from your credential file to get AWS credentials.\n* region:\nSet the AWS Region of the service. (e.g. us-east-1)\n* save_params:\nSave the parameters provided via the command line to the configuration file.", "type": "object", "properties": { "terraform_plan_file": { @@ -718,6 +726,14 @@ "description": "IP address of the host network interface that container ports should bind to. Use 0.0.0.0 to bind to all interfaces.", "default": "127.0.0.1" }, + "add_host": { + "title": "add_host", + "type": "array", + "description": "Passes a hostname to IP address mapping to the Docker container's host file. This parameter can be passed multiple times.Example:--add-host example.com:127.0.0.1", + "items": { + "type": "string" + } + }, "invoke_image": { "title": "invoke_image", "type": "string", @@ -776,7 +792,7 @@ "properties": { "parameters": { "title": "Parameters for the local start lambda command", - "description": "Available parameters for the local start lambda command:\n* terraform_plan_file:\nUsed for passing a custom plan file when executing the Terraform hook.\n* hook_name:\nHook package id to extend AWS SAM CLI commands functionality. \n\nExample: `terraform` to extend AWS SAM CLI commands functionality to support terraform applications. \n\nAvailable Hook Names: ['terraform']\n* skip_prepare_infra:\nSkip preparation stage when there are no infrastructure changes. Only used in conjunction with --hook-name.\n* host:\nLocal hostname or IP address to bind to (default: '127.0.0.1')\n* port:\nLocal port number to listen on (default: '3001')\n* template_file:\nAWS SAM template which references built artifacts for resources in the template. (if applicable)\n* env_vars:\nJSON file containing values for Lambda function's environment variables.\n* parameter_overrides:\nString that contains AWS CloudFormation parameter overrides encoded as key=value pairs.\n* debug_port:\nWhen specified, Lambda function container will start in debug mode and will expose this port on localhost.\n* debugger_path:\nHost path to a debugger that will be mounted into the Lambda container.\n* debug_args:\nAdditional arguments to be passed to the debugger.\n* container_env_vars:\nJSON file containing additional environment variables to be set within the container when used in a debugging session locally.\n* docker_volume_basedir:\nSpecify the location basedir where the SAM template exists. If Docker is running on a remote machine, Path of the SAM template must be mounted on the Docker machine and modified to match the remote machine.\n* log_file:\nFile to capture output logs.\n* layer_cache_basedir:\nSpecify the location basedir where the lambda layers used by the template will be downloaded to.\n* skip_pull_image:\nSkip pulling down the latest Docker image for Lambda runtime.\n* docker_network:\nName or ID of an existing docker network for AWS Lambda docker containers to connect to, along with the default bridge network. If not specified, the Lambda containers will only connect to the default bridge docker network.\n* force_image_build:\nForce rebuilding the image used for invoking functions with layers.\n* warm_containers:\nOptional. Specifies how AWS SAM CLI manages \ncontainers for each function.\nTwo modes are available:\nEAGER: Containers for all functions are \nloaded at startup and persist between \ninvocations.\nLAZY: Containers are only loaded when each \nfunction is first invoked. Those containers \npersist for additional invocations.\n* debug_function:\nOptional. Specifies the Lambda Function logicalId to apply debug options to when --warm-containers is specified. This parameter applies to --debug-port, --debugger-path, and --debug-args.\n* shutdown:\nEmulate a shutdown event after invoke completes, to test extension handling of shutdown behavior.\n* container_host:\nHost of locally emulated Lambda container. This option is useful when the container runs on a different host than AWS SAM CLI. For example, if one wants to run AWS SAM CLI in a Docker container on macOS, this option could specify `host.docker.internal`\n* container_host_interface:\nIP address of the host network interface that container ports should bind to. Use 0.0.0.0 to bind to all interfaces.\n* invoke_image:\nContainer image URIs for invoking functions or starting api and function. One can specify the image URI used for the local function invocation (--invoke-image public.ecr.aws/sam/build-nodejs14.x:latest). One can also specify for each individual function with (--invoke-image Function1=public.ecr.aws/sam/build-nodejs14.x:latest). If a function does not have invoke image specified, the default AWS SAM CLI emulation image will be used.\n* beta_features:\nEnable/Disable beta features.\n* debug:\nTurn on debug logging to print debug message generated by AWS SAM CLI and display timestamps.\n* profile:\nSelect a specific profile from your credential file to get AWS credentials.\n* region:\nSet the AWS Region of the service. (e.g. us-east-1)\n* save_params:\nSave the parameters provided via the command line to the configuration file.", + "description": "Available parameters for the local start lambda command:\n* terraform_plan_file:\nUsed for passing a custom plan file when executing the Terraform hook.\n* hook_name:\nHook package id to extend AWS SAM CLI commands functionality. \n\nExample: `terraform` to extend AWS SAM CLI commands functionality to support terraform applications. \n\nAvailable Hook Names: ['terraform']\n* skip_prepare_infra:\nSkip preparation stage when there are no infrastructure changes. Only used in conjunction with --hook-name.\n* host:\nLocal hostname or IP address to bind to (default: '127.0.0.1')\n* port:\nLocal port number to listen on (default: '3001')\n* template_file:\nAWS SAM template which references built artifacts for resources in the template. (if applicable)\n* env_vars:\nJSON file containing values for Lambda function's environment variables.\n* parameter_overrides:\nString that contains AWS CloudFormation parameter overrides encoded as key=value pairs.\n* debug_port:\nWhen specified, Lambda function container will start in debug mode and will expose this port on localhost.\n* debugger_path:\nHost path to a debugger that will be mounted into the Lambda container.\n* debug_args:\nAdditional arguments to be passed to the debugger.\n* container_env_vars:\nJSON file containing additional environment variables to be set within the container when used in a debugging session locally.\n* docker_volume_basedir:\nSpecify the location basedir where the SAM template exists. If Docker is running on a remote machine, Path of the SAM template must be mounted on the Docker machine and modified to match the remote machine.\n* log_file:\nFile to capture output logs.\n* layer_cache_basedir:\nSpecify the location basedir where the lambda layers used by the template will be downloaded to.\n* skip_pull_image:\nSkip pulling down the latest Docker image for Lambda runtime.\n* docker_network:\nName or ID of an existing docker network for AWS Lambda docker containers to connect to, along with the default bridge network. If not specified, the Lambda containers will only connect to the default bridge docker network.\n* force_image_build:\nForce rebuilding the image used for invoking functions with layers.\n* warm_containers:\nOptional. Specifies how AWS SAM CLI manages \ncontainers for each function.\nTwo modes are available:\nEAGER: Containers for all functions are \nloaded at startup and persist between \ninvocations.\nLAZY: Containers are only loaded when each \nfunction is first invoked. Those containers \npersist for additional invocations.\n* debug_function:\nOptional. Specifies the Lambda Function logicalId to apply debug options to when --warm-containers is specified. This parameter applies to --debug-port, --debugger-path, and --debug-args.\n* shutdown:\nEmulate a shutdown event after invoke completes, to test extension handling of shutdown behavior.\n* container_host:\nHost of locally emulated Lambda container. This option is useful when the container runs on a different host than AWS SAM CLI. For example, if one wants to run AWS SAM CLI in a Docker container on macOS, this option could specify `host.docker.internal`\n* container_host_interface:\nIP address of the host network interface that container ports should bind to. Use 0.0.0.0 to bind to all interfaces.\n* add_host:\nPasses a hostname to IP address mapping to the Docker container's host file. This parameter can be passed multiple times.Example:--add-host example.com:127.0.0.1\n* invoke_image:\nContainer image URIs for invoking functions or starting api and function. One can specify the image URI used for the local function invocation (--invoke-image public.ecr.aws/sam/build-nodejs14.x:latest). One can also specify for each individual function with (--invoke-image Function1=public.ecr.aws/sam/build-nodejs14.x:latest). If a function does not have invoke image specified, the default AWS SAM CLI emulation image will be used.\n* beta_features:\nEnable/Disable beta features.\n* debug:\nTurn on debug logging to print debug message generated by AWS SAM CLI and display timestamps.\n* profile:\nSelect a specific profile from your credential file to get AWS credentials.\n* region:\nSet the AWS Region of the service. (e.g. us-east-1)\n* save_params:\nSave the parameters provided via the command line to the configuration file.", "type": "object", "properties": { "terraform_plan_file": { @@ -909,6 +925,14 @@ "description": "IP address of the host network interface that container ports should bind to. Use 0.0.0.0 to bind to all interfaces.", "default": "127.0.0.1" }, + "add_host": { + "title": "add_host", + "type": "array", + "description": "Passes a hostname to IP address mapping to the Docker container's host file. This parameter can be passed multiple times.Example:--add-host example.com:127.0.0.1", + "items": { + "type": "string" + } + }, "invoke_image": { "title": "invoke_image", "type": "string",