Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ newrelic-lambda layers install \
| `--esm` | No | For Node.js functions using ES Modules (ESM), enable the specific ESM wrapper during installation (e.g., using the --esm flag). This sets the Lambda handler to `/opt/nodejs/node_modules/newrelic-esm-lambda-wrapper/index.handler`. |
| `--extension-logs-enabled` | No | Set `NEW_RELIC_EXTENSION_LOGS_ENABLED=true` to enable `[NR_EXT]` extension log output in CloudWatch. This is the default extension behaviour.|
| `--extension-logs-disabled` | No | Set `NEW_RELIC_EXTENSION_LOGS_ENABLED=false` to suppress `[NR_EXT]` extension log output in CloudWatch. |
| `--app-name` | No | Set the `NEW_RELIC_APP_NAME` environment variable on instrumented functions. If a different value is passed during an upgrade (`--upgrade`), the existing `NEW_RELIC_APP_NAME` will be updated to the new value. |

#### Uninstall Layer

Expand Down
9 changes: 9 additions & 0 deletions newrelic_lambda_cli/cli/layers.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,15 @@ def register(group):
"log output in CloudWatch, reducing CloudWatch log volume without affecting "
"telemetry delivery to New Relic",
)
@click.option(
"--app-name",
"app_name",
help="Set the NEW_RELIC_APP_NAME environment variable on instrumented functions. "
"If a different value is passed during an upgrade (--upgrade), the existing "
"NEW_RELIC_APP_NAME will be updated to the new value.",
metavar="<name>",
default=None,
)
@click.pass_context
def install(ctx, **kwargs):
"""Install New Relic AWS Lambda Layers"""
Expand Down
10 changes: 10 additions & 0 deletions newrelic_lambda_cli/layers.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

NEW_RELIC_ENV_VARS = (
"NEW_RELIC_ACCOUNT_ID",
"NEW_RELIC_APP_NAME",
"NEW_RELIC_EXTENSION_LOGS_ENABLED",
"NEW_RELIC_EXTENSION_SEND_EXTENSION_LOGS",
"NEW_RELIC_EXTENSION_SEND_FUNCTION_LOGS",
Expand Down Expand Up @@ -222,6 +223,15 @@ def _add_new_relic(input, config, nr_license_key):
input.nr_account_id
)

if input.app_name:
update_kwargs["Environment"]["Variables"]["NEW_RELIC_APP_NAME"] = str(
input.app_name
)
success(
"Successfully set NEW_RELIC_APP_NAME to '%s' for the function"
% input.app_name
)

# Update the NEW_RELIC_LAMBDA_HANDLER envvars only when it's a new install.
if runtime_handler and handler != runtime_handler:
if "nodejs" in runtime:
Expand Down
1 change: 1 addition & 0 deletions newrelic_lambda_cli/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@
"esm",
"slim",
"extension_logs_enabled",
"app_name",
]

LAYER_UNINSTALL_KEYS = [
Expand Down
46 changes: 46 additions & 0 deletions tests/cli/test_layers.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
import pytest
from click.testing import CliRunner
from moto import mock_aws

from newrelic_lambda_cli.cli import cli, register_groups


@pytest.fixture(scope="module")
def cli_runner():
try:
return CliRunner(mix_stderr=False)
except TypeError:
return CliRunner()


@mock_aws
def test_layers_install(aws_credentials, cli_runner):
"""
Expand Down Expand Up @@ -65,6 +75,42 @@ def test_layers_install(aws_credentials, cli_runner):
assert "Could not find function: foobar" in result2.stderr


@mock_aws
def test_layers_install_app_name_flag(aws_credentials, cli_runner):
"""
Assert that 'newrelic-lambda layers install --app-name' accepts the flag
and passes it through without raising an unrecognized option error
"""
register_groups(cli)

result = cli_runner.invoke(
cli,
[
"layers",
"install",
"--no-aws-permissions-check",
"--function",
"foobar",
"--nr-account-id",
"12345678",
"--aws-region",
"us-east-1",
"--app-name",
"my-custom-app",
],
env={
"AWS_ACCESS_KEY_ID": "testing",
"AWS_SECRET_ACCESS_KEY": "testing",
"AWS_SECURITY_TOKEN": "testing",
"AWS_SESSION_TOKEN": "testing",
},
)

assert "no such option" not in result.output
assert result.exit_code == 1
assert "Could not find function: foobar" in result.stderr


@mock_aws
def test_layers_uninstall(aws_credentials, cli_runner):
"""
Expand Down
119 changes: 119 additions & 0 deletions tests/test_layers.py
Original file line number Diff line number Diff line change
Expand Up @@ -1809,3 +1809,122 @@ def test_extension_logs_removed_on_uninstall(aws_credentials, mock_function_conf
"NEW_RELIC_EXTENSION_LOGS_ENABLED"
not in update_kwargs["Environment"]["Variables"]
)


@mock_aws
def test_sets_app_name_from_flag(aws_credentials, mock_function_config):
"""Sets NEW_RELIC_APP_NAME when --app-name flag is provided"""
session = boto3.Session(region_name="us-east-1")
config = mock_function_config("python3.12")

update_kwargs = _add_new_relic(
layer_install(
session=session,
aws_region="us-east-1",
nr_account_id=12345,
enable_extension=True,
app_name="my-custom-app",
),
config,
nr_license_key=None,
)

assert (
update_kwargs["Environment"]["Variables"]["NEW_RELIC_APP_NAME"]
== "my-custom-app"
)


@mock_aws
def test_app_name_flag_overrides_existing_value(aws_credentials, mock_function_config):
"""--app-name flag overrides existing NEW_RELIC_APP_NAME already set on the function"""
session = boto3.Session(region_name="us-east-1")
config = mock_function_config("python3.12")
config["Configuration"]["Environment"]["Variables"][
"NEW_RELIC_APP_NAME"
] = "existing-app"

update_kwargs = _add_new_relic(
layer_install(
session=session,
aws_region="us-east-1",
nr_account_id=12345,
enable_extension=True,
app_name="new-app-name",
upgrade=True,
),
config,
nr_license_key=None,
)

assert (
update_kwargs["Environment"]["Variables"]["NEW_RELIC_APP_NAME"]
== "new-app-name"
)


@mock_aws
def test_app_name_not_set_when_flag_omitted(aws_credentials, mock_function_config):
"""NEW_RELIC_APP_NAME is not set when --app-name flag is not provided"""
session = boto3.Session(region_name="us-east-1")
config = mock_function_config("python3.12")

update_kwargs = _add_new_relic(
layer_install(
session=session,
aws_region="us-east-1",
nr_account_id=12345,
enable_extension=True,
),
config,
nr_license_key=None,
)

assert "NEW_RELIC_APP_NAME" not in update_kwargs["Environment"]["Variables"]


@mock_aws
def test_existing_app_name_preserved_when_flag_omitted_on_upgrade(
aws_credentials, mock_function_config
):
"""Existing NEW_RELIC_APP_NAME is preserved when --app-name is not passed during upgrade"""
session = boto3.Session(region_name="us-east-1")
config = mock_function_config("python3.12")
config["Configuration"]["Environment"]["Variables"][
"NEW_RELIC_APP_NAME"
] = "previously-set-app"

update_kwargs = _add_new_relic(
layer_install(
session=session,
aws_region="us-east-1",
nr_account_id=12345,
enable_extension=True,
upgrade=True,
),
config,
nr_license_key=None,
)

assert (
update_kwargs["Environment"]["Variables"]["NEW_RELIC_APP_NAME"]
== "previously-set-app"
)


@mock_aws
def test_app_name_removed_on_uninstall(aws_credentials, mock_function_config):
"""NEW_RELIC_APP_NAME is removed during uninstall"""
session = boto3.Session(region_name="us-east-1")
config = mock_function_config("python3.12")
config["Configuration"]["Handler"] = "newrelic_lambda_wrapper.handler"
config["Configuration"]["Environment"]["Variables"][
"NEW_RELIC_LAMBDA_HANDLER"
] = "original_handler"
config["Configuration"]["Environment"]["Variables"]["NEW_RELIC_APP_NAME"] = "my-app"

update_kwargs = _remove_new_relic(
layer_uninstall(session=session, aws_region="us-east-1"), config
)

assert "NEW_RELIC_APP_NAME" not in update_kwargs["Environment"]["Variables"]
Loading