Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PR-1123 Add Support for Graviton 2 / ARM Architecture (conflict fix) #1209

Closed
wants to merge 21 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
repos:
- repo: local
hooks:
- id: black-check
name: black-check
entry: make black-check
language: system
always_run: true
pass_filenames: false
- id: isort-check
name: isort-check
entry: make isort-check
language: system
always_run: true
pass_filenames: false
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -887,6 +887,7 @@ to change Zappa's behavior. Use these at your own risk!
"assume_policy": "my_assume_policy.json", // optional, IAM assume policy JSON file
"attach_policy": "my_attach_policy.json", // optional, IAM attach policy JSON file
"apigateway_policy": "my_apigateway_policy.json", // optional, API Gateway resource policy JSON file
"architecture": "x86_64", // optional, Set Lambda Architecture, defaults to x86_64. For Graviton 2 use: arm64
"async_source": "sns", // Source of async tasks. Defaults to "lambda"
"async_resources": true, // Create the SNS topic and DynamoDB table to use. Defaults to true.
"async_response_table": "your_dynamodb_table_name", // the DynamoDB table name to use for captured async responses; defaults to None (can't capture)
Expand Down
16 changes: 15 additions & 1 deletion test_settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -142,5 +142,19 @@
"delete_local_zip": true,
"binary_support": true,
"additional_text_mimetypes": ["application/custommimetype"]
}
},
"arch_arm64": {
"s3_bucket": "lmbda",
"app_function": "tests.test_app.hello_world",
"delete_local_zip": true,
"debug": true,
"architecture": "arm64"
},
"archfail": {
"s3_bucket": "lmbda",
"app_function": "tests.test_app.hello_world",
"delete_local_zip": true,
"debug": true,
"architecture": "invalid_architecture"
}
}
2 changes: 1 addition & 1 deletion tests/test_bad_circular_extends_settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
]
}
}
]
],
},
"devor": {
"s3_bucket": "lmbda",
Expand Down
20 changes: 20 additions & 0 deletions tests/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -1183,6 +1183,21 @@ def test_load_extended_settings(self):
zappa_cli.load_settings("test_settings.json")
self.assertEqual("lmbda", zappa_cli.stage_config["s3_bucket"])
self.assertEqual(True, zappa_cli.stage_config["touch"])
self.assertIn("x86_64", zappa_cli.architecture)

if sys.version_info.major == 3 and sys.version_info.minor < 8:
with self.assertRaises(ValueError):
zappa_cli = ZappaCLI()
zappa_cli.api_stage = "arch_arm64"
zappa_cli.load_settings("test_settings.json")
self.assertIn("arm64", zappa_cli.stage_config["architecture"])
self.assertIn("arm64", zappa_cli.architecture)
else:
zappa_cli = ZappaCLI()
zappa_cli.api_stage = "arch_arm64"
zappa_cli.load_settings("test_settings.json")
self.assertIn("arm64", zappa_cli.stage_config["architecture"])
self.assertIn("arm64", zappa_cli.architecture)

zappa_cli = ZappaCLI()
zappa_cli.api_stage = "extendofail"
Expand All @@ -1201,6 +1216,11 @@ def test_load_extended_settings(self):
self.assertTrue(zappa_cli.stage_config["touch"]) # First Extension
self.assertTrue(zappa_cli.stage_config["delete_local_zip"]) # The base

zappa_cli = ZappaCLI()
zappa_cli.api_stage = "archfail"
with self.assertRaises(ValueError):
zappa_cli.load_settings("test_settings.json")

def test_load_settings__lambda_concurrency_enabled(self):
zappa_cli = ZappaCLI()
zappa_cli.api_stage = "lambda_concurrency_enabled"
Expand Down
4 changes: 3 additions & 1 deletion zappa/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ class ZappaCLI:
additional_text_mimetypes = None
tags = []
layers = None
architecture = None

stage_name_env_pattern = re.compile("^[a-zA-Z0-9_]+$")

Expand Down Expand Up @@ -2253,7 +2254,7 @@ def load_settings(self, settings_file=None, session=None):
self.dead_letter_config = {"TargetArn": dead_letter_arn} if dead_letter_arn else {}
self.cognito = self.stage_config.get("cognito", None)
self.num_retained_versions = self.stage_config.get("num_retained_versions", None)

self.architecture = [self.stage_config.get("architecture", "x86_64")]
gaborschulz marked this conversation as resolved.
Show resolved Hide resolved
# Check for valid values of num_retained_versions
if self.num_retained_versions is not None and type(self.num_retained_versions) is not int:
raise ClickException(
Expand Down Expand Up @@ -2322,6 +2323,7 @@ def load_settings(self, settings_file=None, session=None):
tags=self.tags,
endpoint_urls=self.stage_config.get("aws_endpoint_urls", {}),
xray_tracing=self.xray_tracing,
architecture=self.architecture,
)

for setting in CUSTOM_SETTINGS:
Expand Down
22 changes: 18 additions & 4 deletions zappa/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import shutil
import string
import subprocess
import sys
import tarfile
import tempfile
import time
Expand Down Expand Up @@ -265,7 +266,7 @@ class Zappa:
apigateway_policy = None
cloudwatch_log_levels = ["OFF", "ERROR", "INFO"]
xray_tracing = False

architecture = None
##
# Credentials
##
Expand All @@ -285,6 +286,7 @@ def __init__(
tags=(),
endpoint_urls={},
xray_tracing=False,
architecture=None,
):
"""
Instantiate this new Zappa instance, loading any custom credentials if necessary.
Expand Down Expand Up @@ -319,13 +321,24 @@ def __init__(
else:
self.manylinux_suffix_start = "cp311"

if not architecture:
architecture = ["x86_64"]
if not set(architecture).issubset({"x86_64", "arm64"}):
raise ValueError("Invalid architecture. Please, use x86_64 or arm64.")
if sys.version_info.major == 3 and sys.version_info.minor < 8 and "arm64" in architecture:
raise ValueError("arm64 support requires Python 3.8 or newer.")

self.architecture = architecture
gaborschulz marked this conversation as resolved.
Show resolved Hide resolved
gaborschulz marked this conversation as resolved.
Show resolved Hide resolved

# AWS Lambda supports manylinux1/2010, manylinux2014, and manylinux_2_24
manylinux_suffixes = ("_2_24", "2014", "2010", "1")
self.arch_suffixes = ("x86_64", "arm64", "aarch64")
self.manylinux_wheel_file_match = re.compile(
rf'^.*{self.manylinux_suffix_start}-(manylinux_\d+_\d+_x86_64[.])?manylinux({"|".join(manylinux_suffixes)})_x86_64[.]whl$' # noqa: E501
rf'^.*{self.manylinux_suffix_start}-(manylinux_\d+_\d+_({"|".join(self.arch_suffixes)})'
rf'[.])?manylinux({"|".join(manylinux_suffixes)})_({"|".join(self.arch_suffixes)})[.]whl$'
)
self.manylinux_wheel_abi3_file_match = re.compile(
rf'^.*cp3.-abi3-manylinux({"|".join(manylinux_suffixes)})_x86_64.whl$'
f'^.*cp3.-abi3-manylinux({"|".join(manylinux_suffixes)})_({"|".join(self.arch_suffixes)}).whl$'
)

self.endpoint_urls = endpoint_urls
Expand Down Expand Up @@ -918,7 +931,7 @@ def get_cached_manylinux_wheel(self, package_name, package_version, disable_prog
else:
# Check if we already have a cached copy
wheel_name = re.sub(r"[^\w\d.]+", "_", package_name, re.UNICODE)
wheel_file = f"{wheel_name}-{package_version}-*_x86_64.whl"
wheel_file = f"{wheel_name}-{package_version}-*_{self.architecture[0]}.whl"
wheel_path = os.path.join(cached_wheels_dir, wheel_file)

for pathname in glob.iglob(wheel_path):
Expand Down Expand Up @@ -1154,6 +1167,7 @@ def create_lambda_function(
KMSKeyArn=aws_kms_key_arn,
TracingConfig={"Mode": "Active" if self.xray_tracing else "PassThrough"},
Layers=layers,
Architectures=self.architecture,
)
if not docker_image_uri:
kwargs["Runtime"] = runtime
Expand Down