11from __future__ import annotations
22
3- from datetime import datetime
3+ from datetime import UTC , datetime
4+ from enum import Enum
45import logging
56import os
67import sys
3435 from troposphere import AWSObject
3536 import botocore .client
3637 from e3 .aws .troposphere import Stack
38+ from python_on_whales import DockerClient
3739
3840logger = logging .getLogger ("e3.aws.troposphere.awslambda" )
3941
4042
43+ class Architecture (Enum ):
44+ X86_64 = "x86_64"
45+ ARM64 = "arm64"
46+
47+
48+ class UnknownPlatform (Exception ):
49+ """Unknown platform exception."""
50+
51+ def __init__ (self , architecture : Architecture ):
52+ super ().__init__ (f"Unknown platform for architecture { architecture } ." )
53+
54+
4155def package_pyfunction_code (
4256 filename : str ,
4357 / ,
@@ -263,6 +277,7 @@ def __init__(
263277 code_version : int | None = None ,
264278 timeout : int = 3 ,
265279 runtime : str | None = None ,
280+ architecture : Architecture | None = None ,
266281 memory_size : int | None = None ,
267282 ephemeral_storage_size : int | None = None ,
268283 logs_retention_in_days : int | None = 731 ,
@@ -288,6 +303,7 @@ def __init__(
288303 :param code_version: code version
289304 :param timeout: maximum execution time (default: 3s)
290305 :param runtime: runtime to use
306+ :param architecture: x86_64 or arm64. (default: x86_64)
291307 :param memory_size: the amount of memory available to the function at
292308 runtime. The value can be any multiple of 1 MB.
293309 :param ephemeral_storage_size: The size of the function’s /tmp directory
@@ -317,6 +333,7 @@ def __init__(
317333 self .runtime = runtime
318334 self .role = role
319335 self .handler = handler
336+ self .architecture = architecture
320337 self .memory_size = memory_size
321338 self .ephemeral_storage_size = ephemeral_storage_size
322339 self .logs_retention_in_days = logs_retention_in_days
@@ -450,6 +467,9 @@ def lambda_resources(
450467 if self .handler is not None :
451468 params ["Handler" ] = self .handler
452469
470+ if self .architecture is not None :
471+ params ["Architectures" ] = [self .architecture .value ]
472+
453473 if self .memory_size is not None :
454474 params ["MemorySize" ] = self .memory_size
455475
@@ -592,9 +612,14 @@ def __init__(
592612 repository_name : str ,
593613 image_tag : str ,
594614 timeout : int = 3 ,
615+ architecture : Architecture | None = None ,
595616 memory_size : int | None = None ,
617+ logs_retention_in_days : int | None = 731 ,
618+ environment : dict [str , str ] | None = None ,
596619 logging_config : awslambda .LoggingConfig | None = None ,
597620 dl_config : awslambda .DeadLetterConfig | None = None ,
621+ docker_client : DockerClient | None = None ,
622+ ** build_args : Any ,
598623 ):
599624 """Initialize an AWS lambda function using a Docker image.
600625
@@ -605,26 +630,48 @@ def __init__(
605630 :param repository_name: ECR repository name
606631 :param image_tag: docker image version
607632 :param timeout: maximum execution time (default: 3s)
633+ :param architecture: x86_64 or arm64. (default: x86_64)
608634 :param memory_size: the amount of memory available to the function at
609635 runtime. The value can be any multiple of 1 MB.
636+ :param logs_retention_in_days: The number of days to retain the log
637+ events in the lambda log group
638+ :param environment: Environment variables that are accessible from
639+ function code during execution
610640 :param logging_config: The function's Amazon CloudWatch Logs settings
611- :param dl_config: The dead letter config that specifies the topic or queue where
612- lambda sends asynchronous events when they fail processing
641+ :param dl_config: The dead letter config that specifies the topic or
642+ queue where lambda sends asynchronous events when they fail processing
643+ :param docker_client: Docker client to use for building and pushing.
644+ This is here in case the user wants to customize the Docker client,
645+ for example to use podman.
646+ :param build_args: args to pass to docker build
613647 """
614648 super ().__init__ (
615649 name = name ,
616650 description = description ,
617651 role = role ,
618652 timeout = timeout ,
653+ architecture = architecture ,
619654 memory_size = memory_size ,
655+ logs_retention_in_days = logs_retention_in_days ,
656+ environment = environment ,
620657 logging_config = logging_config ,
621658 dl_config = dl_config ,
622659 )
623660 self .source_dir : str = source_dir
624661 self .repository_name : str = repository_name
625- timestamp = datetime .utcnow ( ).strftime ("%Y-%m-%d-%H-%M-%S-%f" )
662+ timestamp = datetime .now ( UTC ).strftime ("%Y-%m-%d-%H-%M-%S-%f" )
626663 self .image_tag : str = f"{ image_tag } -{ timestamp } "
627664 self .image_uri : str | None = None
665+ self .docker_client = docker_client
666+ self .build_args = build_args
667+ if "platforms" not in self .build_args :
668+ match self .architecture :
669+ case Architecture .ARM64 :
670+ self .build_args ["platforms" ] = ["linux/arm64" ]
671+ case Architecture .X86_64 | None :
672+ self .build_args ["platforms" ] = ["linux/amd64" ]
673+ case _:
674+ raise UnknownPlatform (self .architecture )
628675
629676 def resources (self , stack : Stack ) -> list [AWSObject ]:
630677 """Compute AWS resources for the construct.
@@ -641,6 +688,9 @@ def resources(self, stack: Stack) -> list[AWSObject]:
641688 self .repository_name ,
642689 self .image_tag ,
643690 stack .deploy_session ,
691+ push = True ,
692+ docker_client = self .docker_client ,
693+ ** self .build_args ,
644694 )
645695
646696 return self .lambda_resources (image_uri = self .image_uri )
0 commit comments