Skip to content

Commit 552017a

Browse files
Load AWS Lambda secrets in Github CI (#2153)
Make sure our AWS Lambda test setup is correct and the tests work as expected and also in a timely manner. We run our test in AWS Lambda and then parse the log output to see what events/envelopes where sent. Because Lambda truncates this log output to 4kb, I had to change the tests to make the events/envelopes smaller in size to get the whole event/envelop in the log output. When the AWS env vars where not set, the tests where skipped but it looked like they where successful. I made them now fail loudly in that case, so we see if they do not run. Also made the code easier to comprehend. --------- Co-authored-by: Ivana Kellyerova <[email protected]>
1 parent 0ce9021 commit 552017a

13 files changed

+581
-280
lines changed

.craft.yml

+2
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ targets:
1818
# On the other hand, AWS Lambda does not support every Python runtime.
1919
# The supported runtimes are available in the following link:
2020
# https://docs.aws.amazon.com/lambda/latest/dg/lambda-python.html
21+
- python3.7
22+
- python3.8
2123
- python3.9
2224
- python3.10
2325
- python3.11

.github/workflows/test-integration-aws_lambda.yml

+3-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ permissions:
1818
contents: read
1919

2020
env:
21+
SENTRY_PYTHON_TEST_AWS_ACCESS_KEY_ID: ${{ secrets.SENTRY_PYTHON_TEST_AWS_ACCESS_KEY_ID }}
22+
SENTRY_PYTHON_TEST_AWS_SECRET_ACCESS_KEY: ${{ secrets.SENTRY_PYTHON_TEST_AWS_SECRET_ACCESS_KEY }}
2123
BUILD_CACHE_KEY: ${{ github.sha }}
2224
CACHED_BUILD_PATHS: |
2325
${{ github.workspace }}/dist-serverless
@@ -31,7 +33,7 @@ jobs:
3133
strategy:
3234
fail-fast: false
3335
matrix:
34-
python-version: ["3.7"]
36+
python-version: ["3.9"]
3537
# python3.6 reached EOL and is no longer being supported on
3638
# new versions of hosted runners on Github Actions
3739
# ubuntu-20.04 is the last version that supported python3.6

Makefile

+1-2
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@ apidocs-hotfix: apidocs
6060
.PHONY: apidocs-hotfix
6161

6262
aws-lambda-layer: dist
63-
$(VENV_PATH)/bin/pip install urllib3
64-
$(VENV_PATH)/bin/pip install certifi
63+
$(VENV_PATH)/bin/pip install -r aws-lambda-layer-requirements.txt
6564
$(VENV_PATH)/bin/python -m scripts.build_aws_lambda_layer
6665
.PHONY: aws-lambda-layer

aws-lambda-layer-requirements.txt

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
certifi
2+
3+
# In Lambda functions botocore is used, and botocore is not
4+
# yet supporting urllib3 1.27.0 never mind 2+.
5+
# So we pin this here to make our Lambda layer work with
6+
# Lambda Function using Python 3.7+
7+
urllib3<1.27

scripts/aws-cleanup.sh

100644100755
+11-4
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
11
#!/bin/sh
2-
# Delete all AWS Lambda functions
2+
#
3+
# Helper script to clean up AWS Lambda functions created
4+
# by the test suite (tests/integrations/aws_lambda/test_aws.py).
5+
#
6+
# This will delete all Lambda functions named `test_function_*`.
7+
#
38

9+
export AWS_DEFAULT_REGION="us-east-1"
410
export AWS_ACCESS_KEY_ID="$SENTRY_PYTHON_TEST_AWS_ACCESS_KEY_ID"
511
export AWS_SECRET_ACCESS_KEY="$SENTRY_PYTHON_TEST_AWS_SECRET_ACCESS_KEY"
6-
export AWS_IAM_ROLE="$SENTRY_PYTHON_TEST_AWS_IAM_ROLE"
712

8-
for func in $(aws lambda list-functions | jq -r .Functions[].FunctionName); do
13+
for func in $(aws lambda list-functions --output text --query 'Functions[?starts_with(FunctionName, `test_`) == `true`].FunctionName'); do
914
echo "Deleting $func"
10-
aws lambda delete-function --function-name $func
15+
aws lambda delete-function --function-name "$func"
1116
done
17+
18+
echo "All done! Have a nice day!"

scripts/aws-deploy-local-layer.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ aws lambda publish-layer-version \
2222
--region "eu-central-1" \
2323
--zip-file "fileb://dist/$ZIP" \
2424
--description "Local test build of SentryPythonServerlessSDK (can be deleted)" \
25-
--compatible-runtimes python3.6 python3.7 python3.8 python3.9
25+
--compatible-runtimes python3.7 python3.8 python3.9 python3.10 python3.11 \
2626
--no-cli-pager
2727

2828
echo "Done deploying zipped Lambda layer to AWS as 'SentryPythonServerlessSDK-local-dev'."

scripts/build_aws_lambda_layer.py

+55-8
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
import os
22
import shutil
33
import subprocess
4+
import sys
45
import tempfile
6+
from typing import TYPE_CHECKING
57

68
from sentry_sdk.consts import VERSION as SDK_VERSION
79

10+
if TYPE_CHECKING:
11+
from typing import Optional
12+
813
DIST_PATH = "dist" # created by "make dist" that is called by "make aws-lambda-layer"
914
PYTHON_SITE_PACKAGES = "python" # see https://docs.aws.amazon.com/lambda/latest/dg/configuration-layers.html#configuration-layers-path
1015

@@ -13,18 +18,38 @@ class LayerBuilder:
1318
def __init__(
1419
self,
1520
base_dir, # type: str
21+
out_zip_filename=None, # type: Optional[str]
1622
):
1723
# type: (...) -> None
1824
self.base_dir = base_dir
1925
self.python_site_packages = os.path.join(self.base_dir, PYTHON_SITE_PACKAGES)
20-
self.out_zip_filename = f"sentry-python-serverless-{SDK_VERSION}.zip"
26+
self.out_zip_filename = (
27+
f"sentry-python-serverless-{SDK_VERSION}.zip"
28+
if out_zip_filename is None
29+
else out_zip_filename
30+
)
2131

2232
def make_directories(self):
2333
# type: (...) -> None
2434
os.makedirs(self.python_site_packages)
2535

2636
def install_python_packages(self):
2737
# type: (...) -> None
38+
# Install requirements for Lambda Layer (these are more limited than the SDK requirements,
39+
# because Lambda does not support the newest versions of some packages)
40+
subprocess.check_call(
41+
[
42+
sys.executable,
43+
"-m",
44+
"pip",
45+
"install",
46+
"-r",
47+
"aws-lambda-layer-requirements.txt",
48+
"--target",
49+
self.python_site_packages,
50+
],
51+
)
52+
2853
sentry_python_sdk = os.path.join(
2954
DIST_PATH,
3055
f"sentry_sdk-{SDK_VERSION}-py2.py3-none-any.whl", # this is generated by "make dist" that is called by "make aws-lamber-layer"
@@ -34,6 +59,7 @@ def install_python_packages(self):
3459
"pip",
3560
"install",
3661
"--no-cache-dir", # always access PyPI
62+
"--no-deps", # the right depencencies have been installed in the call above
3763
"--quiet",
3864
sentry_python_sdk,
3965
"--target",
@@ -80,13 +106,34 @@ def zip(self):
80106
)
81107

82108

83-
def build_packaged_zip():
84-
with tempfile.TemporaryDirectory() as base_dir:
85-
layer_builder = LayerBuilder(base_dir)
86-
layer_builder.make_directories()
87-
layer_builder.install_python_packages()
88-
layer_builder.create_init_serverless_sdk_package()
89-
layer_builder.zip()
109+
def build_packaged_zip(base_dir=None, make_dist=False, out_zip_filename=None):
110+
if base_dir is None:
111+
base_dir = tempfile.mkdtemp()
112+
113+
if make_dist:
114+
# Same thing that is done by "make dist"
115+
# (which is a dependency of "make aws-lambda-layer")
116+
subprocess.check_call(
117+
[sys.executable, "setup.py", "sdist", "bdist_wheel", "-d", DIST_PATH],
118+
)
119+
120+
layer_builder = LayerBuilder(base_dir, out_zip_filename=out_zip_filename)
121+
layer_builder.make_directories()
122+
layer_builder.install_python_packages()
123+
layer_builder.create_init_serverless_sdk_package()
124+
layer_builder.zip()
125+
126+
# Just for debugging
127+
dist_path = os.path.abspath(DIST_PATH)
128+
print("Created Lambda Layer package with this information:")
129+
print(" - Base directory for generating package: {}".format(layer_builder.base_dir))
130+
print(
131+
" - Created Python SDK distribution (in `{}`): {}".format(dist_path, make_dist)
132+
)
133+
if not make_dist:
134+
print(" If 'False' we assume it was already created (by 'make dist')")
135+
print(" - Package zip filename: {}".format(layer_builder.out_zip_filename))
136+
print(" - Copied package zip to: {}".format(dist_path))
90137

91138

92139
if __name__ == "__main__":
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
SENTRY_PYTHON_TEST_AWS_ACCESS_KEY_ID: ${{ secrets.SENTRY_PYTHON_TEST_AWS_ACCESS_KEY_ID }}
2+
SENTRY_PYTHON_TEST_AWS_SECRET_ACCESS_KEY: ${{ secrets.SENTRY_PYTHON_TEST_AWS_SECRET_ACCESS_KEY }}

scripts/split-tox-gh-actions/ci-yaml.txt

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ permissions:
1818
contents: read
1919

2020
env:
21+
{{ aws_credentials }}
2122
BUILD_CACHE_KEY: ${{ github.sha }}
2223
CACHED_BUILD_PATHS: |
2324
${{ github.workspace }}/dist-serverless

scripts/split-tox-gh-actions/split-tox-gh-actions.py

+10
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
TEMPLATE_FILE = TEMPLATE_DIR / "ci-yaml.txt"
2929
TEMPLATE_FILE_SERVICES = TEMPLATE_DIR / "ci-yaml-services.txt"
3030
TEMPLATE_FILE_SETUP_DB = TEMPLATE_DIR / "ci-yaml-setup-db.txt"
31+
TEMPLATE_FILE_AWS_CREDENTIALS = TEMPLATE_DIR / "ci-yaml-aws-credentials.txt"
3132
TEMPLATE_SNIPPET_TEST = TEMPLATE_DIR / "ci-yaml-test-snippet.txt"
3233
TEMPLATE_SNIPPET_TEST_PY27 = TEMPLATE_DIR / "ci-yaml-test-py27-snippet.txt"
3334

@@ -40,6 +41,10 @@
4041
"clickhouse_driver",
4142
]
4243

44+
FRAMEWORKS_NEEDING_AWS = [
45+
"aws_lambda",
46+
]
47+
4348
MATRIX_DEFINITION = """
4449
strategy:
4550
fail-fast: false
@@ -128,6 +133,11 @@ def write_yaml_file(
128133
f = open(TEMPLATE_FILE_SETUP_DB, "r")
129134
out += "".join(f.readlines())
130135

136+
elif template_line.strip() == "{{ aws_credentials }}":
137+
if current_framework in FRAMEWORKS_NEEDING_AWS:
138+
f = open(TEMPLATE_FILE_AWS_CREDENTIALS, "r")
139+
out += "".join(f.readlines())
140+
131141
elif template_line.strip() == "{{ additional_uses }}":
132142
if current_framework in FRAMEWORKS_NEEDING_CLICKHOUSE:
133143
out += ADDITIONAL_USES_CLICKHOUSE

0 commit comments

Comments
 (0)