diff --git a/moto/awslambda/models.py b/moto/awslambda/models.py index 4a236308c255..d883335b695e 100644 --- a/moto/awslambda/models.py +++ b/moto/awslambda/models.py @@ -964,7 +964,6 @@ def convert(s: Any) -> str: # type: ignore[misc] return s def _invoke_lambda(self, event: Optional[str] = None) -> tuple[str, bool, str]: - import docker import docker.errors # Create the LogGroup if necessary, to write the result to @@ -1000,6 +999,10 @@ def _invoke_lambda(self, event: Optional[str] = None) -> tuple[str, bool, str]: if settings.is_test_proxy_mode(): env_vars["HTTPS_PROXY"] = env_vars["MOTO_HTTP_ENDPOINT"] env_vars["AWS_CA_BUNDLE"] = "/var/task/ca.crt" + else: + # When the proxy is active, we should keep the original URL + # Else: redirect requests to our server + env_vars["AWS_ENDPOINT_URL"] = env_vars["MOTO_HTTP_ENDPOINT"] container = exit_code = None log_config = docker.types.LogConfig(type=docker.types.LogConfig.types.JSON) @@ -1017,9 +1020,8 @@ def _invoke_lambda(self, event: Optional[str] = None) -> tuple[str, bool, str]: elif network_mode: run_kwargs["network_mode"] = network_mode elif settings.TEST_SERVER_MODE: - # AWSLambda can make HTTP requests to a Docker container called 'motoserver' # Only works if our Docker-container is named 'motoserver' - # TODO: should remove this and rely on 'network_mode' instead, as this is too tightly coupled with our own test setup + # TODO: should remove this in 6.x - it's no longer necessary for internal tests, but users may rely on it run_kwargs["links"] = {"motoserver": "motoserver"} # add host.docker.internal host on linux to emulate Mac + Windows behavior @@ -1039,12 +1041,19 @@ def _invoke_lambda(self, event: Optional[str] = None) -> tuple[str, bool, str]: # - lambci/lambda (the repo with older/outdated AWSLambda images # # We'll cycle through all of them - when we find the repo that contains our image, we use it + + idx = re.search("[0-9]", self.run_time).start() # type: ignore[union-attr,arg-type] + language, version = self.run_time[:idx], self.run_time[idx:] # type: ignore[index] + image_repos = { # dict maintains insertion order settings.moto_lambda_image(): None, + f"ghcr.io/shogo82148/lambda-{language}:{version}": None, "mlupin/docker-lambda": None, "lambci/lambda": None, } for image_repo in image_repos: + if not image_repo: + continue image_ref = ( image_repo if ":" in image_repo @@ -1809,7 +1818,7 @@ def del_function(self, name_or_arn: str, qualifier: Optional[str] = None) -> Non else: self._functions[name]["versions"].remove(function) - # If theres no functions left + # If there are no functions left if ( not self._functions[name]["versions"] and not self._functions[name]["latest"] @@ -1907,9 +1916,11 @@ class LambdaBackend(BaseBackend): It is possible to connect from AWS Lambdas to other services, as long as you are running MotoProxy or the MotoServer in a Docker container. - When running the MotoProxy, calls to other AWS services are automatically proxied. + Moto injects the `AWS_ENDPOINT_URL` environment variable into every Lambda, which means that calls to other AWS services are automatically intercepted. + + Note that, if you use a non-standard or older Docker image, the `AWS_ENDPOINT_URL` may not be supported. - When running MotoServer, the Lambda has access to environment variables `MOTO_HOST` and `MOTO_PORT`, which can be used to build the url that MotoServer runs on: + If that is the case, use the environment variables `MOTO_HOST` and `MOTO_PORT` to build the AWS endpoint url and point it to Moto: .. sourcecode:: python @@ -1949,8 +1960,9 @@ def lambda_handler(event, context): The Docker images used by Moto are taken from the following repositories: - - `mlupin/docker-lambda` (for recent versions) - - `lambci/lambda` (for older/outdated versions) + - `shogo82148/lambda-python` (for recent versions) + - `mlupin/docker-lambda` (for older/outdated versions) + - `lambci/lambda` (for even older/outdated versions) Use the following environment variable to configure Moto to look for images in an additional repository: diff --git a/moto/settings.py b/moto/settings.py index 6ac3b2fb51d5..62a79d34c550 100644 --- a/moto/settings.py +++ b/moto/settings.py @@ -126,8 +126,8 @@ def moto_server_host() -> str: return "http://host.docker.internal" -def moto_lambda_image() -> str: - return os.environ.get("MOTO_DOCKER_LAMBDA_IMAGE", "mlupin/docker-lambda") +def moto_lambda_image() -> Optional[str]: + return os.environ.get("MOTO_DOCKER_LAMBDA_IMAGE") def moto_network_name() -> Optional[str]: diff --git a/tests/test_awslambda/__init__.py b/tests/test_awslambda/__init__.py index a919b193515b..fb9b190b74a5 100644 --- a/tests/test_awslambda/__init__.py +++ b/tests/test_awslambda/__init__.py @@ -9,6 +9,8 @@ from moto import mock_aws +from .utilities import PYTHON_VERSION + def lambda_aws_verified(func): """ @@ -98,7 +100,7 @@ def check_iam_role_is_ready_to_use(role_arn: str, role_name: str, region: str): fn_name = f"fn_for_{role_name}" _lambda.create_function( FunctionName=fn_name, - Runtime="python3.11", + Runtime=PYTHON_VERSION, Role=role_arn, Handler="lambda_function.lambda_handler", Code={"ZipFile": get_test_zip_file1()}, diff --git a/tests/test_awslambda/test_lambda.py b/tests/test_awslambda/test_lambda.py index ea6def3aea12..cfc812bcad92 100644 --- a/tests/test_awslambda/test_lambda.py +++ b/tests/test_awslambda/test_lambda.py @@ -19,6 +19,7 @@ from . import lambda_aws_verified from .utilities import ( + PYTHON_VERSION, _process_lambda, create_invalid_lambda, get_role_name, @@ -26,7 +27,6 @@ get_test_zip_file2, ) -PYTHON_VERSION = "python3.11" LAMBDA_FUNC_NAME = "test" _lambda_region = "us-west-2" diff --git a/tests/test_awslambda/test_lambda_alias.py b/tests/test_awslambda/test_lambda_alias.py index a43d5ce8015b..8b25406a9b59 100644 --- a/tests/test_awslambda/test_lambda_alias.py +++ b/tests/test_awslambda/test_lambda_alias.py @@ -10,6 +10,7 @@ from moto.core import DEFAULT_ACCOUNT_ID as ACCOUNT_ID from .utilities import ( + PYTHON_VERSION, get_role_name, get_test_zip_file1, get_test_zip_file2, @@ -17,7 +18,6 @@ # See our Development Tips on writing tests for hints on how to write good tests: # http://docs.getmoto.org/en/latest/docs/contributing/development_tips/tests.html -PYTHON_VERSION = "python3.11" @mock_aws diff --git a/tests/test_awslambda/test_lambda_concurrency.py b/tests/test_awslambda/test_lambda_concurrency.py index 3ec01ddc1b46..7112c3e423b6 100644 --- a/tests/test_awslambda/test_lambda_concurrency.py +++ b/tests/test_awslambda/test_lambda_concurrency.py @@ -5,9 +5,8 @@ from moto import mock_aws -from .utilities import get_role_name, get_test_zip_file1 +from .utilities import PYTHON_VERSION, get_role_name, get_test_zip_file1 -PYTHON_VERSION = "python3.11" _lambda_region = "us-west-2" diff --git a/tests/test_awslambda/test_lambda_eventsourcemapping.py b/tests/test_awslambda/test_lambda_eventsourcemapping.py index 6f3285cb0be3..d9bf4a4b9234 100644 --- a/tests/test_awslambda/test_lambda_eventsourcemapping.py +++ b/tests/test_awslambda/test_lambda_eventsourcemapping.py @@ -14,13 +14,13 @@ from ..markers import requires_docker from .utilities import ( + PYTHON_VERSION, get_role_name, get_test_zip_file3, get_test_zip_file_error, wait_for_log_msg, ) -PYTHON_VERSION = "python3.11" _lambda_region = "us-west-2" botocore_version = sys.modules["botocore"].__version__ @@ -676,7 +676,7 @@ def test_event_source_mapping_tagging_lifecycle(): client = boto3.client("lambda", region_name="us-east-1") client.create_function( FunctionName="any-function-name", - Runtime="python3.6", + Runtime=PYTHON_VERSION, Role=iam_role["Role"]["Arn"], Handler="any-handler", Code={ diff --git a/tests/test_awslambda/test_lambda_invoke.py b/tests/test_awslambda/test_lambda_invoke.py index 373488ee1b09..2d066389941c 100644 --- a/tests/test_awslambda/test_lambda_invoke.py +++ b/tests/test_awslambda/test_lambda_invoke.py @@ -13,6 +13,7 @@ from ..markers import requires_docker from .test_lambda import LooseVersion, boto3_version from .utilities import ( + PYTHON_VERSION, get_lambda_using_environment_port, get_lambda_using_network_mode, get_proxy_zip_file, @@ -24,7 +25,6 @@ get_zip_with_multiple_files, ) -PYTHON_VERSION = "python3.11" _lambda_region = "us-west-2" @@ -278,7 +278,7 @@ def test_invoke_function_with_multiple_files_in_zip(): } -if settings.TEST_SERVER_MODE: +if not settings.TEST_DECORATOR_MODE: @mock_aws def test_invoke_function_get_ec2_volume(): diff --git a/tests/test_awslambda/test_lambda_layers.py b/tests/test_awslambda/test_lambda_layers.py index 0530b6041167..f9e9a82c7ec9 100644 --- a/tests/test_awslambda/test_lambda_layers.py +++ b/tests/test_awslambda/test_lambda_layers.py @@ -14,9 +14,8 @@ from tests.test_awslambda import delete_all_layer_versions from tests.test_s3 import s3_aws_verified -from .utilities import get_role_name, get_test_zip_file1 +from .utilities import PYTHON_VERSION, get_role_name, get_test_zip_file1 -PYTHON_VERSION = "python3.11" _lambda_region = "us-west-2" boto3_version = sys.modules["botocore"].__version__ diff --git a/tests/test_awslambda/test_lambda_layers_invoked.py b/tests/test_awslambda/test_lambda_layers_invoked.py index 923a25835056..953abee8e1b9 100644 --- a/tests/test_awslambda/test_lambda_layers_invoked.py +++ b/tests/test_awslambda/test_lambda_layers_invoked.py @@ -9,7 +9,7 @@ from .utilities import _process_lambda, get_role_name -PYTHON_VERSION = "python3.11" +PYTHON_VERSION = "python3.13" _lambda_region = "us-west-2" @@ -56,7 +56,7 @@ def test_invoke_local_lambda_layers(): function_arn = conn.create_function( FunctionName=lambda_name, - Runtime="python3.11", + Runtime=PYTHON_VERSION, Role=get_role_name(), Handler="lambda_function.lambda_handler", Code={"ZipFile": get_requests_zip_file()}, diff --git a/tests/test_awslambda/utilities.py b/tests/test_awslambda/utilities.py index 8ceb362c4f8b..f8cb19b7efe7 100644 --- a/tests/test_awslambda/utilities.py +++ b/tests/test_awslambda/utilities.py @@ -7,8 +7,9 @@ import pytest from botocore.exceptions import ClientError -from moto import mock_aws, settings +from moto import mock_aws +PYTHON_VERSION = "python3.13" _lambda_region = "us-west-2" @@ -33,21 +34,16 @@ def lambda_handler(event, context): def get_test_zip_file2(): - base_url = ( - "motoserver:5000" - if settings.TEST_SERVER_MODE - else "ec2.us-west-2.amazonaws.com" - ) - func_str = f""" + func_str = """ import boto3 def lambda_handler(event, context): - ec2 = boto3.resource('ec2', region_name='us-west-2', endpoint_url='http://{base_url}') + ec2 = boto3.resource('ec2', region_name='us-west-2') volume_id = event.get('volume_id') vol = ec2.Volume(volume_id) - return {{'id': vol.id, 'state': vol.state, 'size': vol.size}} + return {'id': vol.id, 'state': vol.state, 'size': vol.size} """ return _process_lambda(func_str) @@ -170,7 +166,7 @@ def create_invalid_lambda(role): with pytest.raises(ClientError) as err: conn.create_function( FunctionName=function_name, - Runtime="python3.11", + Runtime=PYTHON_VERSION, Role=role, Handler="lambda_function.handler", Code={"ZipFile": zip_content}, diff --git a/tests/test_secretsmanager/test_secretsmanager.py b/tests/test_secretsmanager/test_secretsmanager.py index 8f6ffe455b2d..b0609867a1c7 100644 --- a/tests/test_secretsmanager/test_secretsmanager.py +++ b/tests/test_secretsmanager/test_secretsmanager.py @@ -1187,10 +1187,7 @@ def test_rotate_secret_rotation_period_too_long(): def get_rotation_zip_file(): - endpoint = "" if allow_aws_request() else 'endpoint_url="http://motoserver:5000"' - - func_str = ( - """ + func_str = """ import boto3 import json import os @@ -1200,9 +1197,7 @@ def lambda_handler(event, context): token = event['ClientRequestToken'] step = event['Step'] - client = boto3.client("secretsmanager", region_name="us-east-1", """ - + endpoint - + """) + client = boto3.client("secretsmanager", region_name="us-east-1") metadata = client.describe_secret(SecretId=arn) metadata.pop('LastChangedDate', None) metadata.pop('LastAccessedDate', None) @@ -1223,9 +1218,7 @@ def lambda_handler(event, context): pending_value = str(e) print(pending_value) - dynamodb = boto3.resource("dynamodb", region_name="us-east-1", """ - + endpoint - + """) + dynamodb = boto3.resource("dynamodb", region_name="us-east-1") table = dynamodb.Table(os.environ["table_name"]) table.put_item(Item={"pk": step, "token": token, "metadata": metadata, "versions": versions, "pending_value": pending_value}) @@ -1276,7 +1269,6 @@ def lambda_handler(event, context): RemoveFromVersionId=token ) """ - ) return _process_lambda(func_str)