-
Notifications
You must be signed in to change notification settings - Fork 52
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
9 changed files
with
531 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
# Byte-compiled / optimized / DLL files | ||
__pycache__/ | ||
*.py[cod] | ||
*$py.class | ||
|
||
# C extensions | ||
*.so | ||
|
||
# Distribution / packaging | ||
.Python | ||
.DS_Store | ||
*.DS_Store | ||
function.zip | ||
lambda_output.txt | ||
nr_tmp_env.sh | ||
env/ | ||
build/ | ||
develop-eggs/ | ||
dist/ | ||
downloads/ | ||
eggs/ | ||
.eggs/ | ||
lib/ | ||
lib64/ | ||
parts/ | ||
sdist/ | ||
var/ | ||
*.egg-info/ | ||
.installed.cfg | ||
*.egg | ||
|
||
# PyInstaller | ||
# Usually these files are written by a python script from a template | ||
# before PyInstaller builds the exe, so as to inject date/other infos into it. | ||
*.manifest | ||
*.spec | ||
|
||
# Installer logs | ||
pip-log.txt | ||
pip-delete-this-directory.txt | ||
|
||
# Unit test / coverage reports | ||
htmlcov/ | ||
.tox/ | ||
.coverage | ||
.coverage.* | ||
.cache | ||
nosetests.xml | ||
coverage.xml | ||
*,cover | ||
.hypothesis/ | ||
|
||
# Translations | ||
*.mo | ||
*.pot | ||
|
||
# Django stuff: | ||
*.log | ||
local_settings.py | ||
|
||
# Flask stuff: | ||
instance/ | ||
.webassets-cache | ||
|
||
# Scrapy stuff: | ||
.scrapy | ||
|
||
# Sphinx documentation | ||
docs/_build/ | ||
|
||
# PyBuilder | ||
target/ | ||
|
||
# IPython Notebook | ||
.ipynb_checkpoints | ||
|
||
# pyenv | ||
.python-version | ||
|
||
# celery beat schedule file | ||
celerybeat-schedule | ||
|
||
# dotenv | ||
.env | ||
|
||
# virtualenv | ||
venv/ | ||
ENV/ | ||
|
||
# Spyder project settings | ||
.spyderproject | ||
|
||
# Rope project settings | ||
.ropeproject |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
## Local Testing | ||
|
||
To test the extension on a AWS test account, follow the steps: | ||
1. Configure the credentials for the AWS test account `aws configure` | ||
2. Update the environment.json file with the test account and other variables. | ||
3. Modify the fetch_extension url in publish.sh to your forked repo's extension release url | ||
4. Run `./publish.sh` to publish the layers to your test account `us-west-2` region | ||
5. Publish script will create 4 lambda layers for runtimes - Python 3.12 [[Amazon Linux 2023](https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html)] & Python 3.11 [[Amazon Linux 2](https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html)] and architectures - x86 & ARM | ||
6. Run `./test.sh` to create lambda with test layer published in step 2 | ||
7. Go to your AWS test account and check the logs of the lambda with suffix - `NR_EXTENSION_TEST_LAMBDA_` for any error in extension | ||
8. After the tests, delete the test infra created, using `./delete_infra.sh`. It will delete the 4 test lambda functions. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
#!/bin/bash | ||
|
||
# Variables | ||
REGION="us-west-2" # Preferred AWS region | ||
|
||
runtimes=("python3.11" "python3.12") | ||
architectures=("x86_64" "arm64") | ||
|
||
for arch in "${architectures[@]}"; do | ||
for runtime in "${runtimes[@]}"; do | ||
FUNCTION_NAME_SUFFIX="${arch}_${runtime//./}" | ||
FUNCTION_NAME="NR_EXTENSION_TEST_LAMBDA_${FUNCTION_NAME_SUFFIX}" | ||
if aws lambda delete-function --function-name "$FUNCTION_NAME" --region "$REGION"; then | ||
echo "Successfully deleted $FUNCTION_NAME" | ||
else | ||
echo "Failed to delete $FUNCTION_NAME" | ||
fi | ||
done | ||
done |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
{ | ||
"Variables": { | ||
"NEW_RELIC_ACCOUNT_ID": "", | ||
"NEW_RELIC_EXTENSION_SEND_FUNCTION_LOGS": "true", | ||
"NEW_RELIC_LAMBDA_EXTENSION_ENABLED": "true", | ||
"NEW_RELIC_LAMBDA_HANDLER": "lambda_function.lambda_handler", | ||
"NEW_RELIC_LICENSE_KEY": "", | ||
"NEW_RELIC_LOG_ENDPOINT": "", | ||
"NEW_RELIC_TELEMETRY_ENDPOINT": "" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
def handler(event, context): | ||
# Your code here | ||
return { | ||
'statusCode': 200, | ||
'body': 'Hello from Lambda!' | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
# -*- coding: utf-8 -*- | ||
|
||
import importlib | ||
import os | ||
import sys | ||
import warnings | ||
|
||
os.environ.setdefault("NEW_RELIC_APP_NAME", os.getenv("AWS_LAMBDA_FUNCTION_NAME", "")) | ||
os.environ.setdefault("NEW_RELIC_NO_CONFIG_FILE", "true") | ||
os.environ.setdefault("NEW_RELIC_DISTRIBUTED_TRACING_ENABLED", "true") | ||
os.environ.setdefault("NEW_RELIC_SERVERLESS_MODE_ENABLED", "true") | ||
os.environ.setdefault( | ||
"NEW_RELIC_TRUSTED_ACCOUNT_KEY", os.getenv("NEW_RELIC_ACCOUNT_ID", "") | ||
) | ||
|
||
# The agent will load some environment variables on module import so we need | ||
# to perform the import after setting the necessary environment variables. | ||
import newrelic.agent # noqa | ||
from newrelic_lambda.lambda_handler import lambda_handler # noqa | ||
|
||
newrelic.agent.initialize() | ||
|
||
|
||
class IOpipeNoOp(object): | ||
def __call__(self, *args, **kwargs): | ||
warnings.warn( | ||
"Use of context.iopipe.* is no longer supported. " | ||
"Please see New Relic Python agent documentation here: " | ||
"https://docs.newrelic.com/docs/agents/python-agent" | ||
) | ||
|
||
def __getattr__(self, name): | ||
return IOpipeNoOp() | ||
|
||
|
||
def get_handler(): | ||
if ( | ||
"NEW_RELIC_LAMBDA_HANDLER" not in os.environ | ||
or not os.environ["NEW_RELIC_LAMBDA_HANDLER"] | ||
): | ||
raise ValueError( | ||
"No value specified in NEW_RELIC_LAMBDA_HANDLER environment variable" | ||
) | ||
|
||
try: | ||
module_path, handler_name = os.environ["NEW_RELIC_LAMBDA_HANDLER"].rsplit( | ||
".", 1 | ||
) | ||
except ValueError: | ||
raise ValueError( | ||
"Improperly formated handler value: %s" | ||
% os.environ["NEW_RELIC_LAMBDA_HANDLER"] | ||
) | ||
|
||
try: | ||
# Use the same check as | ||
# https://github.com/aws/aws-lambda-python-runtime-interface-client/blob/97dee252434edc56be4cafd54a9af1e7fa041eaf/awslambdaric/bootstrap.py#L33 | ||
if module_path.split(".")[0] in sys.builtin_module_names: | ||
raise ImportError( | ||
"Cannot use built-in module %s as a handler module" % module_path | ||
) | ||
|
||
module = importlib.import_module(module_path.replace("/", ".")) | ||
except Exception as e: | ||
raise ImportError("Failed to import module '%s': %s" % (module_path, e)) | ||
|
||
try: | ||
handler = getattr(module, handler_name) | ||
except AttributeError: | ||
raise AttributeError( | ||
"No handler '%s' in module '%s'" % (handler_name, module_path) | ||
) | ||
|
||
return handler | ||
|
||
|
||
# Greedily load the handler during cold start, so we don't pay for it on first invoke | ||
wrapped_handler = get_handler() | ||
|
||
|
||
@lambda_handler() | ||
def handler(event, context): | ||
context.iopipe = IOpipeNoOp() | ||
return wrapped_handler(event, context) |
Oops, something went wrong.