Skip to content
Merged
12 changes: 12 additions & 0 deletions samcli/commands/local/cli_common/invoke_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
"""
Expand Down Expand Up @@ -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
"""
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down
6 changes: 6 additions & 0 deletions samcli/commands/local/cli_common/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,12 @@ 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",
default=None,
multiple=True,
help="Utilize hostname to IP mapping via docker --add-host flag. Can be multiple."
),
click.option(
"--invoke-image",
"-ii",
Expand Down
4 changes: 4 additions & 0 deletions samcli/commands/local/invoke/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ def cli(
config_env,
container_host,
container_host_interface,
add_host,
invoke_image,
hook_name,
skip_prepare_infra,
Expand Down Expand Up @@ -121,6 +122,7 @@ def cli(
parameter_overrides,
container_host,
container_host_interface,
add_host,
invoke_image,
hook_name,
) # pragma: no cover
Expand All @@ -147,6 +149,7 @@ def do_cli( # pylint: disable=R0914
parameter_overrides,
container_host,
container_host_interface,
add_host,
invoke_image,
hook_name,
):
Expand Down Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions samcli/commands/local/invoke/core/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
"shutdown",
"container_host",
"container_host_interface",
"add_host",
"invoke_image",
]

Expand Down
4 changes: 4 additions & 0 deletions samcli/commands/local/lib/local_lambda.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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,
Expand Down Expand Up @@ -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.
Expand Down
2 changes: 2 additions & 0 deletions samcli/commands/local/start_api/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ def cli(
debug_function,
container_host,
container_host_interface,
add_host,
invoke_image,
hook_name,
skip_prepare_infra,
Expand Down Expand Up @@ -142,6 +143,7 @@ def cli(
debug_function,
container_host,
container_host_interface,
add_host,
invoke_image,
hook_name,
) # pragma: no cover
Expand Down
1 change: 1 addition & 0 deletions samcli/commands/local/start_api/core/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"shutdown",
"container_host",
"container_host_interface",
"add_host",
"invoke_image",
]

Expand Down
2 changes: 2 additions & 0 deletions samcli/commands/local/start_lambda/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ def cli(
debug_function,
container_host,
container_host_interface,
add_host,
invoke_image,
hook_name,
skip_prepare_infra,
Expand Down Expand Up @@ -128,6 +129,7 @@ def cli(
debug_function,
container_host,
container_host_interface,
add_host,
invoke_image,
hook_name,
) # pragma: no cover
Expand Down
1 change: 1 addition & 0 deletions samcli/commands/local/start_lambda/core/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"shutdown",
"container_host",
"container_host_interface",
"add_host",
"invoke_image",
]

Expand Down
6 changes: 6 additions & 0 deletions samcli/local/docker/container.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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
Expand All @@ -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)
Expand Down Expand Up @@ -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

Expand Down
4 changes: 4 additions & 0 deletions samcli/local/docker/lambda_container.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ def __init__(
debug_options=None,
container_host=None,
container_host_interface=None,
extra_hosts=None,
function_full_path=None,
):
"""
Expand Down Expand Up @@ -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
"""
Expand Down Expand Up @@ -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
Expand Down
21 changes: 17 additions & 4 deletions samcli/local/lambdafn/runtime.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
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
Expand Down Expand Up @@ -97,6 +104,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:
Expand Down Expand Up @@ -159,6 +167,7 @@ def invoke(
stderr: Optional[StreamWriter] = None,
container_host=None,
container_host_interface=None,
extra_hosts=None,
):
"""
Invoke the given Lambda function locally.
Expand All @@ -181,12 +190,16 @@ 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
Expand Down Expand Up @@ -351,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
Expand Down Expand Up @@ -405,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

Expand Down
Loading