From 6bb409e29d2e684bb392afc23190e67bf8591bdb Mon Sep 17 00:00:00 2001 From: Bert Blommers Date: Fri, 10 Jun 2022 14:09:13 +0000 Subject: [PATCH] AWSlambda: Support creation of functions with PackageType=Image (#5213) --- docs/docs/services/lambda.rst | 4 +++ moto/awslambda/models.py | 38 ++++++++++++++++++++--------- tests/test_awslambda/test_lambda.py | 31 +++++++++++++++++++++++ 3 files changed, 61 insertions(+), 12 deletions(-) diff --git a/docs/docs/services/lambda.rst b/docs/docs/services/lambda.rst index 9432bc7ce..4ea379fcc 100644 --- a/docs/docs/services/lambda.rst +++ b/docs/docs/services/lambda.rst @@ -60,6 +60,10 @@ lambda - [X] get_policy - [ ] get_provisioned_concurrency_config - [X] invoke + + Invoking a Function with PackageType=Image is not yet supported. + + - [ ] invoke_async - [ ] list_aliases - [ ] list_code_signing_configs diff --git a/moto/awslambda/models.py b/moto/awslambda/models.py index 17f5a5a77..f2e414680 100644 --- a/moto/awslambda/models.py +++ b/moto/awslambda/models.py @@ -380,9 +380,9 @@ class LambdaFunction(CloudFormationModel, DockerModel): self.region = region self.code = spec["Code"] self.function_name = spec["FunctionName"] - self.handler = spec["Handler"] + self.handler = spec.get("Handler") self.role = spec["Role"] - self.run_time = spec["Runtime"] + self.run_time = spec.get("Runtime") self.logs_backend = logs_backends[self.region] self.environment_vars = spec.get("Environment", {}).get("Variables", {}) self.policy = None @@ -423,7 +423,7 @@ class LambdaFunction(CloudFormationModel, DockerModel): # TODO: we should be putting this in a lambda bucket self.code["UUID"] = str(uuid.uuid4()) self.code["S3Key"] = "{}-{}".format(self.function_name, self.code["UUID"]) - else: + elif "S3Bucket" in self.code: key = _validate_s3_bucket_and_key(self.code) if key: ( @@ -436,6 +436,11 @@ class LambdaFunction(CloudFormationModel, DockerModel): self.code_bytes = "" self.code_size = 0 self.code_sha_256 = "" + elif "ImageUri" in self.code: + self.code_sha_256 = hashlib.sha256( + self.code["ImageUri"].encode("utf-8") + ).hexdigest() + self.code_size = 0 self.function_arn = make_function_arn( self.region, get_account_id(), self.function_name @@ -521,26 +526,33 @@ class LambdaFunction(CloudFormationModel, DockerModel): return config def get_code(self): - code = { - "Code": { + resp = {"Configuration": self.get_configuration()} + if "S3Key" in self.code: + resp["Code"] = { "Location": "s3://awslambda-{0}-tasks.s3-{0}.amazonaws.com/{1}".format( self.region, self.code["S3Key"] ), "RepositoryType": "S3", - }, - "Configuration": self.get_configuration(), - } + } + elif "ImageUri" in self.code: + resp["Code"] = { + "RepositoryType": "ECR", + "ImageUri": self.code.get("ImageUri"), + "ResolvedImageUri": self.code.get("ImageUri").split(":")[0] + + "@sha256:" + + self.code_sha_256, + } if self.tags: - code["Tags"] = self.tags + resp["Tags"] = self.tags if self.reserved_concurrency: - code.update( + resp.update( { "Concurrency": { "ReservedConcurrentExecutions": self.reserved_concurrency } } ) - return code + return resp def update_configuration(self, config_updates): for key, value in config_updates.items(): @@ -745,7 +757,6 @@ class LambdaFunction(CloudFormationModel, DockerModel): ) def invoke(self, body, request_headers, response_headers): - if body: body = json.loads(body) else: @@ -1640,6 +1651,9 @@ class LambdaBackend(BaseBackend): return fn.update_configuration(body) if fn else None def invoke(self, function_name, qualifier, body, headers, response_headers): + """ + Invoking a Function with PackageType=Image is not yet supported. + """ fn = self.get_function(function_name, qualifier) if fn: payload = fn.invoke(body, headers, response_headers) diff --git a/tests/test_awslambda/test_lambda.py b/tests/test_awslambda/test_lambda.py index 9f4f60a96..e409e06d3 100644 --- a/tests/test_awslambda/test_lambda.py +++ b/tests/test_awslambda/test_lambda.py @@ -213,6 +213,37 @@ def test_create_function__with_tracingmode(tracing_mode): result.should.have.key("TracingConfig").should.equal({"Mode": output}) +@mock_lambda +def test_create_function_from_image(): + lambda_client = boto3.client("lambda", "us-east-1") + fn_name = str(uuid4())[0:6] + image_uri = "111122223333.dkr.ecr.us-east-1.amazonaws.com/testlambda:latest" + dic = { + "FunctionName": fn_name, + "Role": get_role_name(), + "Code": {"ImageUri": image_uri}, + "PackageType": "Image", + "Timeout": 100, + } + resp = lambda_client.create_function(**dic) + + resp.should.have.key("FunctionName").equals(fn_name) + resp.should.have.key("CodeSize").equals(0) + resp.should.have.key("CodeSha256") + resp.should.have.key("PackageType").equals("Image") + + result = lambda_client.get_function(FunctionName=fn_name) + result.should.have.key("Configuration") + config = result["Configuration"] + result.should.have.key("Code") + code = result["Code"] + code.should.have.key("RepositoryType").equals("ECR") + code.should.have.key("ImageUri").equals(image_uri) + image_uri_without_tag = image_uri.split(":")[0] + resolved_image_uri = f"{image_uri_without_tag}@sha256:{config['CodeSha256']}" + code.should.have.key("ResolvedImageUri").equals(resolved_image_uri) + + @mock_lambda @mock_s3 @freeze_time("2015-01-01 00:00:00")