newrelic-lambda-cli 0.7.6__tar.gz → 0.9.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. {newrelic-lambda-cli-0.7.6 → newrelic-lambda-cli-0.9.0}/PKG-INFO +10 -4
  2. {newrelic-lambda-cli-0.7.6 → newrelic-lambda-cli-0.9.0}/README.md +9 -3
  3. {newrelic-lambda-cli-0.7.6 → newrelic-lambda-cli-0.9.0}/newrelic_lambda_cli/cli/__init__.py +1 -0
  4. {newrelic-lambda-cli-0.7.6 → newrelic-lambda-cli-0.9.0}/newrelic_lambda_cli/cli/integrations.py +32 -0
  5. {newrelic-lambda-cli-0.7.6 → newrelic-lambda-cli-0.9.0}/newrelic_lambda_cli/cli/subscriptions.py +16 -0
  6. {newrelic-lambda-cli-0.7.6 → newrelic-lambda-cli-0.9.0}/newrelic_lambda_cli/functions.py +2 -2
  7. {newrelic-lambda-cli-0.7.6 → newrelic-lambda-cli-0.9.0}/newrelic_lambda_cli/integrations.py +157 -67
  8. {newrelic-lambda-cli-0.7.6 → newrelic-lambda-cli-0.9.0}/newrelic_lambda_cli/layers.py +1 -1
  9. {newrelic-lambda-cli-0.7.6 → newrelic-lambda-cli-0.9.0}/newrelic_lambda_cli/subscriptions.py +11 -2
  10. {newrelic-lambda-cli-0.7.6 → newrelic-lambda-cli-0.9.0}/newrelic_lambda_cli/templates/import-template.yaml +2 -2
  11. {newrelic-lambda-cli-0.7.6 → newrelic-lambda-cli-0.9.0}/newrelic_lambda_cli/types.py +5 -0
  12. {newrelic-lambda-cli-0.7.6 → newrelic-lambda-cli-0.9.0}/newrelic_lambda_cli/utils.py +7 -11
  13. {newrelic-lambda-cli-0.7.6 → newrelic-lambda-cli-0.9.0}/newrelic_lambda_cli.egg-info/PKG-INFO +10 -4
  14. {newrelic-lambda-cli-0.7.6 → newrelic-lambda-cli-0.9.0}/setup.py +1 -1
  15. {newrelic-lambda-cli-0.7.6 → newrelic-lambda-cli-0.9.0}/tests/test_integrations.py +35 -11
  16. {newrelic-lambda-cli-0.7.6 → newrelic-lambda-cli-0.9.0}/tests/test_layers.py +16 -34
  17. {newrelic-lambda-cli-0.7.6 → newrelic-lambda-cli-0.9.0}/tests/test_subscriptions.py +11 -0
  18. {newrelic-lambda-cli-0.7.6 → newrelic-lambda-cli-0.9.0}/tests/test_utils.py +2 -2
  19. {newrelic-lambda-cli-0.7.6 → newrelic-lambda-cli-0.9.0}/CODE_OF_CONDUCT.md +0 -0
  20. {newrelic-lambda-cli-0.7.6 → newrelic-lambda-cli-0.9.0}/CONTRIBUTING.md +0 -0
  21. {newrelic-lambda-cli-0.7.6 → newrelic-lambda-cli-0.9.0}/LICENSE +0 -0
  22. {newrelic-lambda-cli-0.7.6 → newrelic-lambda-cli-0.9.0}/MANIFEST.in +0 -0
  23. {newrelic-lambda-cli-0.7.6 → newrelic-lambda-cli-0.9.0}/THIRD_PARTY_NOTICES.md +0 -0
  24. {newrelic-lambda-cli-0.7.6 → newrelic-lambda-cli-0.9.0}/newrelic_lambda_cli/__init__.py +0 -0
  25. {newrelic-lambda-cli-0.7.6 → newrelic-lambda-cli-0.9.0}/newrelic_lambda_cli/api.py +0 -0
  26. {newrelic-lambda-cli-0.7.6 → newrelic-lambda-cli-0.9.0}/newrelic_lambda_cli/cli/decorators.py +0 -0
  27. {newrelic-lambda-cli-0.7.6 → newrelic-lambda-cli-0.9.0}/newrelic_lambda_cli/cli/functions.py +0 -0
  28. {newrelic-lambda-cli-0.7.6 → newrelic-lambda-cli-0.9.0}/newrelic_lambda_cli/cli/layers.py +0 -0
  29. {newrelic-lambda-cli-0.7.6 → newrelic-lambda-cli-0.9.0}/newrelic_lambda_cli/cliutils.py +0 -0
  30. {newrelic-lambda-cli-0.7.6 → newrelic-lambda-cli-0.9.0}/newrelic_lambda_cli/permissions.py +0 -0
  31. {newrelic-lambda-cli-0.7.6 → newrelic-lambda-cli-0.9.0}/newrelic_lambda_cli/templates/license-key-secret.yaml +0 -0
  32. {newrelic-lambda-cli-0.7.6 → newrelic-lambda-cli-0.9.0}/newrelic_lambda_cli/templates/nr-lambda-integration-role.yaml +0 -0
  33. {newrelic-lambda-cli-0.7.6 → newrelic-lambda-cli-0.9.0}/newrelic_lambda_cli.egg-info/SOURCES.txt +0 -0
  34. {newrelic-lambda-cli-0.7.6 → newrelic-lambda-cli-0.9.0}/newrelic_lambda_cli.egg-info/dependency_links.txt +0 -0
  35. {newrelic-lambda-cli-0.7.6 → newrelic-lambda-cli-0.9.0}/newrelic_lambda_cli.egg-info/entry_points.txt +0 -0
  36. {newrelic-lambda-cli-0.7.6 → newrelic-lambda-cli-0.9.0}/newrelic_lambda_cli.egg-info/not-zip-safe +0 -0
  37. {newrelic-lambda-cli-0.7.6 → newrelic-lambda-cli-0.9.0}/newrelic_lambda_cli.egg-info/requires.txt +0 -0
  38. {newrelic-lambda-cli-0.7.6 → newrelic-lambda-cli-0.9.0}/newrelic_lambda_cli.egg-info/top_level.txt +0 -0
  39. {newrelic-lambda-cli-0.7.6 → newrelic-lambda-cli-0.9.0}/pyproject.toml +0 -0
  40. {newrelic-lambda-cli-0.7.6 → newrelic-lambda-cli-0.9.0}/setup.cfg +0 -0
  41. {newrelic-lambda-cli-0.7.6 → newrelic-lambda-cli-0.9.0}/tests/test_api.py +0 -0
  42. {newrelic-lambda-cli-0.7.6 → newrelic-lambda-cli-0.9.0}/tests/test_functions.py +0 -0
  43. {newrelic-lambda-cli-0.7.6 → newrelic-lambda-cli-0.9.0}/tests/test_new_relic_gql.py +0 -0
  44. {newrelic-lambda-cli-0.7.6 → newrelic-lambda-cli-0.9.0}/tests/test_permissions.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: newrelic-lambda-cli
3
- Version: 0.7.6
3
+ Version: 0.9.0
4
4
  Summary: A CLI to install the New Relic AWS Lambda integration and layers.
5
5
  Home-page: https://github.com/newrelic/newrelic-lambda-cli
6
6
  Author: New Relic
@@ -55,9 +55,9 @@ A CLI to install the New Relic AWS Lambda integration and layers.
55
55
  * java8.al2
56
56
  * java11
57
57
  * java17
58
- * nodejs12.x
59
- * nodejs14.x
60
58
  * nodejs16.x
59
+ * nodejs18.x
60
+ * nodejs20.x
61
61
  * provided
62
62
  * provided.al2
63
63
  * python3.7
@@ -65,13 +65,14 @@ A CLI to install the New Relic AWS Lambda integration and layers.
65
65
  * python3.9
66
66
  * python3.10
67
67
  * python3.11
68
+ * python3.12
68
69
 
69
70
  **Note:** Automatic handler wrapping is only supported for Node.js, Python and Java. For other runtimes,
70
71
  manual function wrapping is required using the runtime specific New Relic agent.
71
72
 
72
73
  ## Requirements
73
74
 
74
- * Python >= 3.3 <= 3.11
75
+ * Python >= 3.3 <= 3.12
75
76
  * Retrieve your [New relic Account ID](https://docs.newrelic.com/docs/accounts/install-new-relic/account-setup/account-id) and [User API Key](https://docs.newrelic.com/docs/apis/get-started/intro-apis/types-new-relic-api-keys#user-api-key)
76
77
 
77
78
  ## Recommendations
@@ -131,6 +132,7 @@ newrelic-lambda integrations install \
131
132
  | `--aws-role-policy` | No | Specify an alternative IAM role policy ARN for this integration. |
132
133
  | `--disable-license-key-secret` | No | Don't create a managed secret for your account's New Relic License Key |
133
134
  | `--tag <key> <value>` | No | Sets tags on the CloudFormation Stacks this CLI creates. Can be used multiple times, example: `--tag key1 value1 --tag key2 value2`. |
135
+ | `--stackname` | No | The AWS Cloudformation stack name which contains the newrelic-log-ingestion lambda function. If no value is provided, the command searches for the NewRelicLogIngestion stack |
134
136
 
135
137
  #### Uninstall Integration
136
138
 
@@ -144,6 +146,7 @@ newrelic-lambda integrations uninstall
144
146
  | `--aws-region` or `-r` | No | The AWS region for the integration. Can use `AWS_DEFAULT_REGION` environment variable. Defaults to AWS session region. |
145
147
  | `--force` or `-f` | No | Forces uninstall non-interactively |
146
148
  | `--nr-account-id` or `-a` | No | The [New Relic Account ID](https://docs.newrelic.com/docs/accounts/install-new-relic/account-setup/account-id) for the integration. Only required if also uninstalling the New Relic AWS Lambda integration. Can also use the `NEW_RELIC_ACCOUNT_ID` environment variable. |
149
+ | `--stackname` | No | The AWS Cloudformation stack name which contains the newrelic-log-ingestion lambda function. If no value is provided, the command searches for the NewRelicLogIngestion stack |
147
150
 
148
151
  #### Update Integration
149
152
 
@@ -171,6 +174,7 @@ newrelic-lambda integrations update \
171
174
  | `--aws-region` or `-r` | No | The AWS region for the integration. Can use `AWS_DEFAULT_REGION` environment variable. Defaults to AWS session region. |
172
175
  | `--disable-license-key-secret` | No | Disable automatic creation of the license key secret on update. The secret is not created if it exists. |
173
176
  | `--tag <key> <value>` | No | Sets tags on the CloudFormation Stacks this CLI creates. Can be used multiple times, example: `--tag key1 value1 --tag key2 value2`. |
177
+ | `--stackname` | No | The AWS Cloudformation stack name which contains the newrelic-log-ingestion lambda function. If no value is provided, the command searches for the NewRelicLogIngestion stack |
174
178
 
175
179
  ### AWS Lambda Layers
176
180
 
@@ -243,6 +247,7 @@ newrelic-lambda subscriptions install --function <name or arn>
243
247
  | Option | Required? | Description |
244
248
  |--------|-----------|-------------|
245
249
  | `--function` or `-f` | Yes | The AWS Lambda function name or ARN in which to add a log subscription. Can provide multiple `--function` arguments. Will also accept `all`, `installed` and `not-installed` similar to `newrelic-lambda functions list`. |
250
+ | `--stackname` | No | The AWS Cloudformation stack name which contains the newrelic-log-ingestion lambda function. If no value is provided, the command searches for the NewRelicLogIngestion stack |
246
251
  | `--exclude` or `-e` | No | A function name to exclude while installing subscriptions. Can provide multiple `--exclude` arguments. Only checked when `all`, `installed` and `not-installed` are used. See `newrelic-lambda functions list` for function names. |
247
252
  | `--filter-pattern` | No | Specify a custom log subscription filter pattern. To collect all logs use `--filter-pattern ""`. |
248
253
  | `--aws-profile` or `-p` | No | The AWS profile to use for this command. Can also use `AWS_PROFILE`. Will also check `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` environment variables if not using AWS CLI. |
@@ -257,6 +262,7 @@ newrelic-lambda subscriptions uninstall --function <name or arn>
257
262
  | Option | Required? | Description |
258
263
  |--------|-----------|-------------|
259
264
  | `--function` or `-f` | Yes | The AWS Lambda function name or ARN in which to remove a log subscription. Can provide multiple `--function` arguments. Will also accept `all`, `installed` and `not-installed` similar to `newrelic-lambda functions list`. |
265
+ | `--stackname` | No | The AWS Cloudformation stack name which contains the newrelic-log-ingestion lambda function. If no value is provided, the command searches for the NewRelicLogIngestion stack |
260
266
  | `--exclude` or `-e` | No | A function name to exclude while uninstalling subscriptions. Can provide multiple `--exclude` arguments. Only checked when `all`, `installed` and `not-installed` are used. See `newrelic-lambda functions list` for function names. |
261
267
  | `--aws-profile` or `-p` | No | The AWS profile to use for this command. Can also use `AWS_PROFILE`. Will also check `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` environment variables if not using AWS CLI. |
262
268
  | `--aws-region` or `-r` | No | The AWS region this function is located. Can use `AWS_DEFAULT_REGION` environment variable. Defaults to AWS session region. |
@@ -37,9 +37,9 @@ A CLI to install the New Relic AWS Lambda integration and layers.
37
37
  * java8.al2
38
38
  * java11
39
39
  * java17
40
- * nodejs12.x
41
- * nodejs14.x
42
40
  * nodejs16.x
41
+ * nodejs18.x
42
+ * nodejs20.x
43
43
  * provided
44
44
  * provided.al2
45
45
  * python3.7
@@ -47,13 +47,14 @@ A CLI to install the New Relic AWS Lambda integration and layers.
47
47
  * python3.9
48
48
  * python3.10
49
49
  * python3.11
50
+ * python3.12
50
51
 
51
52
  **Note:** Automatic handler wrapping is only supported for Node.js, Python and Java. For other runtimes,
52
53
  manual function wrapping is required using the runtime specific New Relic agent.
53
54
 
54
55
  ## Requirements
55
56
 
56
- * Python >= 3.3 <= 3.11
57
+ * Python >= 3.3 <= 3.12
57
58
  * Retrieve your [New relic Account ID](https://docs.newrelic.com/docs/accounts/install-new-relic/account-setup/account-id) and [User API Key](https://docs.newrelic.com/docs/apis/get-started/intro-apis/types-new-relic-api-keys#user-api-key)
58
59
 
59
60
  ## Recommendations
@@ -113,6 +114,7 @@ newrelic-lambda integrations install \
113
114
  | `--aws-role-policy` | No | Specify an alternative IAM role policy ARN for this integration. |
114
115
  | `--disable-license-key-secret` | No | Don't create a managed secret for your account's New Relic License Key |
115
116
  | `--tag <key> <value>` | No | Sets tags on the CloudFormation Stacks this CLI creates. Can be used multiple times, example: `--tag key1 value1 --tag key2 value2`. |
117
+ | `--stackname` | No | The AWS Cloudformation stack name which contains the newrelic-log-ingestion lambda function. If no value is provided, the command searches for the NewRelicLogIngestion stack |
116
118
 
117
119
  #### Uninstall Integration
118
120
 
@@ -126,6 +128,7 @@ newrelic-lambda integrations uninstall
126
128
  | `--aws-region` or `-r` | No | The AWS region for the integration. Can use `AWS_DEFAULT_REGION` environment variable. Defaults to AWS session region. |
127
129
  | `--force` or `-f` | No | Forces uninstall non-interactively |
128
130
  | `--nr-account-id` or `-a` | No | The [New Relic Account ID](https://docs.newrelic.com/docs/accounts/install-new-relic/account-setup/account-id) for the integration. Only required if also uninstalling the New Relic AWS Lambda integration. Can also use the `NEW_RELIC_ACCOUNT_ID` environment variable. |
131
+ | `--stackname` | No | The AWS Cloudformation stack name which contains the newrelic-log-ingestion lambda function. If no value is provided, the command searches for the NewRelicLogIngestion stack |
129
132
 
130
133
  #### Update Integration
131
134
 
@@ -153,6 +156,7 @@ newrelic-lambda integrations update \
153
156
  | `--aws-region` or `-r` | No | The AWS region for the integration. Can use `AWS_DEFAULT_REGION` environment variable. Defaults to AWS session region. |
154
157
  | `--disable-license-key-secret` | No | Disable automatic creation of the license key secret on update. The secret is not created if it exists. |
155
158
  | `--tag <key> <value>` | No | Sets tags on the CloudFormation Stacks this CLI creates. Can be used multiple times, example: `--tag key1 value1 --tag key2 value2`. |
159
+ | `--stackname` | No | The AWS Cloudformation stack name which contains the newrelic-log-ingestion lambda function. If no value is provided, the command searches for the NewRelicLogIngestion stack |
156
160
 
157
161
  ### AWS Lambda Layers
158
162
 
@@ -225,6 +229,7 @@ newrelic-lambda subscriptions install --function <name or arn>
225
229
  | Option | Required? | Description |
226
230
  |--------|-----------|-------------|
227
231
  | `--function` or `-f` | Yes | The AWS Lambda function name or ARN in which to add a log subscription. Can provide multiple `--function` arguments. Will also accept `all`, `installed` and `not-installed` similar to `newrelic-lambda functions list`. |
232
+ | `--stackname` | No | The AWS Cloudformation stack name which contains the newrelic-log-ingestion lambda function. If no value is provided, the command searches for the NewRelicLogIngestion stack |
228
233
  | `--exclude` or `-e` | No | A function name to exclude while installing subscriptions. Can provide multiple `--exclude` arguments. Only checked when `all`, `installed` and `not-installed` are used. See `newrelic-lambda functions list` for function names. |
229
234
  | `--filter-pattern` | No | Specify a custom log subscription filter pattern. To collect all logs use `--filter-pattern ""`. |
230
235
  | `--aws-profile` or `-p` | No | The AWS profile to use for this command. Can also use `AWS_PROFILE`. Will also check `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` environment variables if not using AWS CLI. |
@@ -239,6 +244,7 @@ newrelic-lambda subscriptions uninstall --function <name or arn>
239
244
  | Option | Required? | Description |
240
245
  |--------|-----------|-------------|
241
246
  | `--function` or `-f` | Yes | The AWS Lambda function name or ARN in which to remove a log subscription. Can provide multiple `--function` arguments. Will also accept `all`, `installed` and `not-installed` similar to `newrelic-lambda functions list`. |
247
+ | `--stackname` | No | The AWS Cloudformation stack name which contains the newrelic-log-ingestion lambda function. If no value is provided, the command searches for the NewRelicLogIngestion stack |
242
248
  | `--exclude` or `-e` | No | A function name to exclude while uninstalling subscriptions. Can provide multiple `--exclude` arguments. Only checked when `all`, `installed` and `not-installed` are used. See `newrelic-lambda functions list` for function names. |
243
249
  | `--aws-profile` or `-p` | No | The AWS profile to use for this command. Can also use `AWS_PROFILE`. Will also check `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` environment variables if not using AWS CLI. |
244
250
  | `--aws-region` or `-r` | No | The AWS region this function is located. Can use `AWS_DEFAULT_REGION` environment variable. Defaults to AWS session region. |
@@ -6,6 +6,7 @@ from newrelic_lambda_cli.cli import functions, integrations, layers, subscriptio
6
6
 
7
7
 
8
8
  @click.group()
9
+ @click.version_option()
9
10
  @click.option("--verbose", "-v", help="Increase verbosity", is_flag=True)
10
11
  @click.pass_context
11
12
  def cli(ctx, verbose):
@@ -39,6 +39,14 @@ def register(group):
39
39
  help="Determines if logs are forwarded to New Relic Logging",
40
40
  is_flag=True,
41
41
  )
42
+ @click.option(
43
+ "--stackname",
44
+ default="NewRelicLogIngestion",
45
+ help="The AWS Cloudformation stack name which contains the newrelic-log-ingestion lambda function",
46
+ metavar="<arn>",
47
+ show_default=False,
48
+ required=False,
49
+ )
42
50
  @click.option(
43
51
  "--memory-size",
44
52
  "-m",
@@ -195,6 +203,14 @@ def install(ctx, **kwargs):
195
203
  required=False,
196
204
  type=click.INT,
197
205
  )
206
+ @click.option(
207
+ "--stackname",
208
+ default="NewRelicLogIngestion",
209
+ help="The AWS Cloudformation stack name which contains the newrelic-log-ingestion lambda function",
210
+ metavar="<arn>",
211
+ show_default=False,
212
+ required=False,
213
+ )
198
214
  @click.option("--force", "-f", help="Force uninstall non-interactively", is_flag=True)
199
215
  def uninstall(**kwargs):
200
216
  """Uninstall New Relic AWS Lambda Integration"""
@@ -250,6 +266,14 @@ def uninstall(**kwargs):
250
266
  default=None,
251
267
  help="Determines if logs are forwarded to New Relic Logging",
252
268
  )
269
+ @click.option(
270
+ "--stackname",
271
+ default="NewRelicLogIngestion",
272
+ help="The AWS Cloudformation stack name which contains the newrelic-log-ingestion lambda function",
273
+ metavar="<arn>",
274
+ show_default=False,
275
+ required=False,
276
+ )
253
277
  @click.option(
254
278
  "--memory-size",
255
279
  "-m",
@@ -272,6 +296,14 @@ def uninstall(**kwargs):
272
296
  metavar="<role_name>",
273
297
  show_default=False,
274
298
  )
299
+ @click.option(
300
+ "--stackname",
301
+ default="NewRelicLogIngestion",
302
+ help="The AWS Cloudformation stack name which contains the newrelic-log-ingestion lambda function",
303
+ metavar="<arn>",
304
+ show_default=False,
305
+ required=False,
306
+ )
275
307
  @click.option(
276
308
  "--enable-license-key-secret/--disable-license-key-secret",
277
309
  default=True,
@@ -37,6 +37,14 @@ def register(group):
37
37
  multiple=True,
38
38
  required=True,
39
39
  )
40
+ @click.option(
41
+ "--stackname",
42
+ default="NewRelicLogIngestion",
43
+ help="The AWS Cloudformation stack name which contains the newrelic-log-ingestion lambda function",
44
+ metavar="<arn>",
45
+ show_default=False,
46
+ required=False,
47
+ )
40
48
  @click.option(
41
49
  "excludes",
42
50
  "--exclude",
@@ -92,6 +100,14 @@ def install(**kwargs):
92
100
  multiple=True,
93
101
  required=True,
94
102
  )
103
+ @click.option(
104
+ "--stackname",
105
+ default="NewRelicLogIngestion",
106
+ help="The AWS Cloudformation stack name which contains the newrelic-log-ingestion lambda function",
107
+ metavar="<arn>",
108
+ show_default=False,
109
+ required=False,
110
+ )
95
111
  @click.option(
96
112
  "excludes",
97
113
  "--exclude",
@@ -70,8 +70,8 @@ def get_aliased_functions(input):
70
70
  functions = [
71
71
  function
72
72
  for function in input.functions
73
- if function.lower()
74
- not in ("all", "installed", "not-installed", "newrelic-log-ingestion")
73
+ if function.lower() not in ("all", "installed", "not-installed")
74
+ and "newrelic-log-ingestion" not in function.lower()
75
75
  and function not in input.excludes
76
76
  ]
77
77
 
@@ -43,8 +43,8 @@ def _get_role(session, role_name):
43
43
  raise click.UsageError(str(e))
44
44
 
45
45
 
46
- def _check_for_ingest_stack(session):
47
- return _get_cf_stack_status(session, INGEST_STACK_NAME)
46
+ def _check_for_ingest_stack(session, stack_name):
47
+ return _get_cf_stack_status(session, stack_name)
48
48
 
49
49
 
50
50
  def _get_cf_stack_status(session, stack_name, nr_account_id=None):
@@ -86,6 +86,62 @@ def _get_cf_stack_status(session, stack_name, nr_account_id=None):
86
86
  return res["Stacks"][0]["StackStatus"]
87
87
 
88
88
 
89
+ def get_unique_newrelic_log_ingestion_name(session, stackname=None):
90
+ if not stackname:
91
+ stackname = INGEST_STACK_NAME
92
+ stack_id = _get_cf_stack_id(session, stack_name=stackname)
93
+ if stack_id:
94
+ return "newrelic-log-ingestion-%s" % (stack_id.split("/")[2].split("-")[4])
95
+
96
+
97
+ def get_newrelic_log_ingestion_function(session, stackname=None):
98
+ unique_log_ingestion_name = get_unique_newrelic_log_ingestion_name(
99
+ session, stackname
100
+ )
101
+ if unique_log_ingestion_name:
102
+ function = get_function(session, unique_log_ingestion_name)
103
+ return function
104
+
105
+
106
+ def _get_cf_stack_id(session, stack_name, nr_account_id=None):
107
+ """Returns the StackId of the CloudFormation stack if it exists"""
108
+ try:
109
+ res = session.client("cloudformation").describe_stacks(StackName=stack_name)
110
+ if nr_account_id is not None:
111
+ stack_output_account_id = _get_stack_output_value(
112
+ session, ["NrAccountId"]
113
+ ).get("NrAccountId")
114
+ # Checking outputs here to protect against installs done
115
+ # with older CLI versions. We don't want to constantly warn users
116
+ # who installed on previous versions with no outputs.
117
+ if stack_output_account_id and stack_output_account_id != str(
118
+ nr_account_id
119
+ ):
120
+ warning(
121
+ "WARNING: Managed secret already exists in this region for "
122
+ "New Relic account {0}.\n"
123
+ "Current CLI behavior limits the setup of one managed "
124
+ "secret per region.\n"
125
+ "To set up an additional secret for New Relic account {1} "
126
+ "see our docs:\n{2}.\n"
127
+ "Or run this command with --disable-license-key-secret to "
128
+ "avoid attempting to create a new managed secret.".format(
129
+ stack_output_account_id, nr_account_id, NR_DOCS_ACT_LINKING_URL
130
+ )
131
+ )
132
+ except botocore.exceptions.ClientError as e:
133
+ if (
134
+ e.response
135
+ and "ResponseMetadata" in e.response
136
+ and "HTTPStatusCode" in e.response["ResponseMetadata"]
137
+ and e.response["ResponseMetadata"]["HTTPStatusCode"] in (400, 404)
138
+ ):
139
+ return None
140
+ raise click.UsageError(str(e))
141
+ else:
142
+ return res["Stacks"][0]["StackId"]
143
+
144
+
89
145
  # TODO: Merge this with create_integration_role?
90
146
  def _create_role(input):
91
147
  assert isinstance(input, IntegrationInstall)
@@ -200,29 +256,35 @@ def _import_log_ingestion_function(input, nr_license_key):
200
256
  )
201
257
 
202
258
  with open(template_path) as template:
203
- change_set_name = "%s-IMPORT-%d" % (INGEST_STACK_NAME, int(time.time()))
204
- click.echo("Creating change set: %s" % change_set_name)
205
-
206
- change_set = client.create_change_set(
207
- StackName=INGEST_STACK_NAME,
208
- TemplateBody=template.read(),
209
- Parameters=parameters,
210
- Capabilities=capabilities,
211
- Tags=[{"Key": key, "Value": value} for key, value in input.tags]
212
- if input.tags
213
- else [],
214
- ChangeSetType="IMPORT",
215
- ChangeSetName=change_set_name,
216
- ResourcesToImport=[
217
- {
218
- "ResourceType": "AWS::Lambda::Function",
219
- "LogicalResourceId": "NewRelicLogIngestionFunctionNoCap",
220
- "ResourceIdentifier": {"FunctionName": "newrelic-log-ingestion"},
221
- }
222
- ],
259
+ unique_log_ingestion_name = get_unique_newrelic_log_ingestion_name(
260
+ input.session
223
261
  )
262
+ if unique_log_ingestion_name:
263
+ change_set_name = "%s-IMPORT-%d" % (INGEST_STACK_NAME, int(time.time()))
264
+ click.echo("Creating change set: %s" % change_set_name)
265
+
266
+ change_set = client.create_change_set(
267
+ StackName=INGEST_STACK_NAME,
268
+ TemplateBody=template.read(),
269
+ Parameters=parameters,
270
+ Capabilities=capabilities,
271
+ Tags=[{"Key": key, "Value": value} for key, value in input.tags]
272
+ if input.tags
273
+ else [],
274
+ ChangeSetType="IMPORT",
275
+ ChangeSetName=change_set_name,
276
+ ResourcesToImport=[
277
+ {
278
+ "ResourceType": "AWS::Lambda::Function",
279
+ "LogicalResourceId": "NewRelicLogIngestionFunctionNoCap",
280
+ "ResourceIdentifier": {
281
+ "FunctionName": unique_log_ingestion_name
282
+ },
283
+ }
284
+ ],
285
+ )
224
286
 
225
- _exec_change_set(client, change_set, "IMPORT")
287
+ _exec_change_set(client, change_set, "IMPORT")
226
288
 
227
289
 
228
290
  def _create_log_ingestion_function(
@@ -241,11 +303,11 @@ def _create_log_ingestion_function(
241
303
  click.echo("Fetching new CloudFormation template url")
242
304
  template_url = _get_sar_template_url(input.session)
243
305
 
244
- change_set_name = "%s-%s-%d" % (INGEST_STACK_NAME, mode, int(time.time()))
306
+ change_set_name = "%s-%s-%d" % (input.stackname, mode, int(time.time()))
245
307
  click.echo("Creating change set: %s" % change_set_name)
246
308
 
247
309
  change_set = client.create_change_set(
248
- StackName=INGEST_STACK_NAME,
310
+ StackName=input.stackname,
249
311
  TemplateURL=template_url,
250
312
  Parameters=parameters,
251
313
  Capabilities=capabilities,
@@ -256,10 +318,10 @@ def _create_log_ingestion_function(
256
318
  ChangeSetName=change_set_name,
257
319
  )
258
320
 
259
- _exec_change_set(client, change_set, mode)
321
+ _exec_change_set(client, change_set, mode, input.stackname)
260
322
 
261
323
 
262
- def _exec_change_set(client, change_set, mode, stack_name=INGEST_STACK_NAME):
324
+ def _exec_change_set(client, change_set, mode, stack_name):
263
325
  click.echo(
264
326
  "Waiting for change set creation to complete, this may take a minute... ",
265
327
  nl=False,
@@ -324,7 +386,6 @@ def update_log_ingestion_function(input):
324
386
  len(stack_resources) > 0
325
387
  and stack_resources[0]["ResourceType"] == "AWS::CloudFormation::Stack"
326
388
  ):
327
-
328
389
  click.echo("Unwrapping nested stack... ", nl=False)
329
390
 
330
391
  # Set the ingest function itself to disallow deletes
@@ -342,9 +403,24 @@ def update_log_ingestion_function(input):
342
403
 
343
404
  # We can't change props during import, so let's set them to their current values
344
405
  lambda_client = input.session.client("lambda")
345
- old_props = lambda_client.get_function_configuration(
346
- FunctionName="newrelic-log-ingestion"
406
+ unique_log_ingestion_name = get_unique_newrelic_log_ingestion_name(
407
+ input.session
347
408
  )
409
+ old_props = {}
410
+ try:
411
+ old_props = lambda_client.get_function_configuration(
412
+ FunctionName=unique_log_ingestion_name
413
+ )
414
+ except lambda_client.exceptions.ResourceNotFoundException:
415
+ old_props = lambda_client.get_function_configuration(
416
+ FunctionName="newrelic-log-ingestion"
417
+ )
418
+ warning(
419
+ "It looks like an old log ingestion function is present in this region. "
420
+ "Consider manually deleting this as it is no longer used and "
421
+ "has been replaced by a log ingestion function specific to the stack."
422
+ )
423
+
348
424
  old_role_name = old_props["Role"].split("/")[-1]
349
425
  old_nr_license_key = old_props["Environment"]["Variables"]["LICENSE_KEY"]
350
426
  old_enable_logs = False
@@ -424,19 +500,19 @@ def remove_log_ingestion_function(input):
424
500
  assert isinstance(input, IntegrationUninstall)
425
501
 
426
502
  client = input.session.client("cloudformation")
427
- stack_status = _check_for_ingest_stack(input.session)
503
+ stack_status = _check_for_ingest_stack(input.session, input.stackname)
428
504
  if stack_status is None:
429
505
  click.echo(
430
506
  "No New Relic AWS Lambda log ingestion found in region %s, skipping"
431
507
  % input.session.region_name
432
508
  )
433
509
  return
434
- click.echo("Deleting New Relic log ingestion stack '%s'" % INGEST_STACK_NAME)
435
- client.delete_stack(StackName=INGEST_STACK_NAME)
510
+ click.echo("Deleting New Relic log ingestion stack '%s'" % input.stackname)
511
+ client.delete_stack(StackName=input.stackname)
436
512
  click.echo(
437
513
  "Waiting for stack deletion to complete, this may take a minute... ", nl=False
438
514
  )
439
- client.get_waiter("stack_delete_complete").wait(StackName=INGEST_STACK_NAME)
515
+ client.get_waiter("stack_delete_complete").wait(StackName=input.stackname)
440
516
  success("Done")
441
517
 
442
518
 
@@ -518,22 +594,35 @@ def install_log_ingestion(
518
594
  """
519
595
  assert isinstance(input, IntegrationInstall)
520
596
  function = get_function(input.session, "newrelic-log-ingestion")
521
- if function is None:
522
- stack_status = _check_for_ingest_stack(input.session)
523
- if stack_status is None:
524
- click.echo(
525
- "Setting up 'newrelic-log-ingestion' function in region: %s"
526
- % input.session.region_name
597
+ if function:
598
+ warning(
599
+ "It looks like an old log ingestion function is present in this region. "
600
+ "Consider manually deleting this as it is no longer used and "
601
+ "has been replaced by a log ingestion function specific to the stack."
602
+ )
603
+ stack_status = _check_for_ingest_stack(input.session, input.stackname)
604
+ if stack_status is None:
605
+ click.echo(
606
+ "Setting up CloudFormation Stack %s in region: %s"
607
+ % (input.stackname, input.session.region_name)
608
+ )
609
+ try:
610
+ _create_log_ingestion_function(
611
+ input,
612
+ nr_license_key,
527
613
  )
528
- try:
529
- _create_log_ingestion_function(
530
- input,
531
- nr_license_key,
532
- )
533
- except Exception as e:
534
- failure("Failed to create 'newrelic-log-ingestion' function: %s" % e)
535
- return False
536
- else:
614
+ return True
615
+ except Exception as e:
616
+ failure(
617
+ "CloudFormation Stack NewRelicLogIngestion exists (status: %s).\n"
618
+ "Please manually delete the stack and re-run this command."
619
+ % stack_status
620
+ )
621
+ return False
622
+ else:
623
+ function = get_newrelic_log_ingestion_function(input.session)
624
+
625
+ if function is None:
537
626
  failure(
538
627
  "CloudFormation Stack NewRelicLogIngestion exists (status: %s), but "
539
628
  "newrelic-log-ingestion Lambda function does not.\n"
@@ -541,12 +630,13 @@ def install_log_ingestion(
541
630
  % stack_status
542
631
  )
543
632
  return False
544
- else:
545
- success(
546
- "The 'newrelic-log-ingestion' function already exists in region %s, "
547
- "skipping" % input.session.region_name
548
- )
549
- return True
633
+ else:
634
+ success(
635
+ "The CloudFormation Stack NewRelicLogIngestion and "
636
+ "newrelic-log-ingestion function already exists in region %s, "
637
+ "skipping" % input.session.region_name
638
+ )
639
+ return True
550
640
 
551
641
 
552
642
  @catch_boto_errors
@@ -558,16 +648,7 @@ def update_log_ingestion(input):
558
648
  """
559
649
  assert isinstance(input, IntegrationUpdate)
560
650
 
561
- function = get_function(input.session, "newrelic-log-ingestion")
562
- if function is None:
563
- failure(
564
- "No 'newrelic-log-ingestion' function in region '%s'. "
565
- "Run 'newrelic-lambda integrations install' to install it."
566
- % input.session.region_name
567
- )
568
- return False
569
-
570
- stack_status = _check_for_ingest_stack(input.session)
651
+ stack_status = _check_for_ingest_stack(input.session, input.stackname)
571
652
  if stack_status is None:
572
653
  failure(
573
654
  "No 'NewRelicLogIngestion' stack in region '%s'. "
@@ -578,10 +659,19 @@ def update_log_ingestion(input):
578
659
  )
579
660
  return False
580
661
 
662
+ function = get_newrelic_log_ingestion_function(input.session, input.stackname)
663
+ if function is None:
664
+ failure(
665
+ "No newrelic-log-ingestion function in region '%s'. "
666
+ "Run 'newrelic-lambda integrations install' to install it."
667
+ % input.session.region_name
668
+ )
669
+ return False
670
+
581
671
  try:
582
672
  update_log_ingestion_function(input)
583
673
  except Exception as e:
584
- failure("Failed to update 'newrelic-log-ingestion' function: %s" % e)
674
+ failure("Failed to update newrelic-log-ingestion function: %s" % e)
585
675
  return False
586
676
  else:
587
677
  return True
@@ -592,7 +682,7 @@ def get_log_ingestion_license_key(session):
592
682
  """
593
683
  Fetches the license key value from the log ingestion function
594
684
  """
595
- function = get_function(session, "newrelic-log-ingestion")
685
+ function = get_newrelic_log_ingestion_function(session)
596
686
  if function:
597
687
  return function["Configuration"]["Environment"]["Variables"]["LICENSE_KEY"]
598
688
  return None
@@ -89,7 +89,7 @@ def _add_new_relic(input, config, nr_license_key):
89
89
  "Unsupported Lambda runtime for '%s': %s"
90
90
  % (config["Configuration"]["FunctionArn"], runtime)
91
91
  )
92
- return True
92
+ return False
93
93
 
94
94
  architectures = config["Configuration"].get("Architectures", ["x86_64"])
95
95
  architecture = architectures[0]
@@ -5,6 +5,8 @@ import click
5
5
 
6
6
  from newrelic_lambda_cli.cliutils import failure, success, warning
7
7
  from newrelic_lambda_cli.functions import get_function
8
+ from newrelic_lambda_cli.integrations import get_unique_newrelic_log_ingestion_name
9
+ from newrelic_lambda_cli.integrations import get_newrelic_log_ingestion_function
8
10
  from newrelic_lambda_cli.types import (
9
11
  LayerInstall,
10
12
  SubscriptionInstall,
@@ -83,10 +85,17 @@ def _remove_subscription_filter(session, function_name, filter_name):
83
85
  @catch_boto_errors
84
86
  def create_log_subscription(input, function_name):
85
87
  assert isinstance(input, SubscriptionInstall)
86
- destination = get_function(input.session, "newrelic-log-ingestion")
88
+ function = get_function(input.session, "newrelic-log-ingestion")
89
+ if function:
90
+ warning(
91
+ "It looks like an old log ingestion function is present in this region. "
92
+ "Consider manually deleting this as it is no longer used and "
93
+ "has been replaced by a log ingestion function specific to the stack."
94
+ )
95
+ destination = get_newrelic_log_ingestion_function(input.session, input.stackname)
87
96
  if destination is None:
88
97
  failure(
89
- "Could not find 'newrelic-log-ingestion' function. Is the New Relic AWS "
98
+ "Could not find newrelic-log-ingestion function. Is the New Relic AWS "
90
99
  "integration installed?"
91
100
  )
92
101
  return False
@@ -62,7 +62,7 @@ Resources:
62
62
  Key: 466768951184/arn:aws:serverlessrepo:us-east-1:463657938898:applications-NewRelic-log-ingestion-versions-2.2.1/2dcb4087-186a-42c8-bc1f-cf93780786c0
63
63
  Description: Sends log data from CloudWatch Logs and S3 to New Relic Infrastructure (Cloud integrations) and New Relic Logging
64
64
  Handler: function.lambda_handler
65
- FunctionName: newrelic-log-ingestion
65
+ FunctionName: !Join ['-', ['newrelic-log-ingestion', !Select [4, !Split ['-', !Select [2, !Split ['/', !Ref AWS::StackId]]]]]]
66
66
  MemorySize:
67
67
  Ref: MemorySize
68
68
  Runtime: python3.9
@@ -84,7 +84,7 @@ Resources:
84
84
  Key: 466768951184/arn:aws:serverlessrepo:us-east-1:463657938898:applications-NewRelic-log-ingestion-versions-2.2.1/2dcb4087-186a-42c8-bc1f-cf93780786c0
85
85
  Description: Sends log data from CloudWatch Logs and S3 to New Relic Infrastructure (Cloud integrations) and New Relic Logging
86
86
  Handler: function.lambda_handler
87
- FunctionName: newrelic-log-ingestion
87
+ FunctionName: !Join ['-', ['newrelic-log-ingestion', !Select [4, !Split ['-', !Select [2, !Split ['/', !Ref AWS::StackId]]]]]]
88
88
  MemorySize:
89
89
  Ref: MemorySize
90
90
  Runtime: python3.9
@@ -8,6 +8,7 @@ INTEGRATION_INSTALL_KEYS = [
8
8
  "aws_permissions_check",
9
9
  "aws_role_policy",
10
10
  "enable_logs",
11
+ "stackname",
11
12
  "memory_size",
12
13
  "linked_account_name",
13
14
  "nr_account_id",
@@ -26,6 +27,7 @@ INTEGRATION_UNINSTALL_KEYS = [
26
27
  "aws_profile",
27
28
  "aws_region",
28
29
  "aws_permissions_check",
30
+ "stackname",
29
31
  "nr_account_id",
30
32
  "force",
31
33
  ]
@@ -36,6 +38,7 @@ INTEGRATION_UPDATE_KEYS = [
36
38
  "aws_region",
37
39
  "aws_permissions_check",
38
40
  "enable_logs",
41
+ "stackname",
39
42
  "memory_size",
40
43
  "nr_account_id",
41
44
  "nr_api_key",
@@ -80,6 +83,7 @@ SUBSCRIPTION_INSTALL_KEYS = [
80
83
  "aws_region",
81
84
  "aws_permissions_check",
82
85
  "functions",
86
+ "stackname",
83
87
  "excludes",
84
88
  "filter_pattern",
85
89
  ]
@@ -90,6 +94,7 @@ SUBSCRIPTION_UNINSTALL_KEYS = [
90
94
  "aws_region",
91
95
  "aws_permissions_check",
92
96
  "functions",
97
+ "stackname",
93
98
  "excludes",
94
99
  ]
95
100
 
@@ -22,28 +22,20 @@ RUNTIME_CONFIG = {
22
22
  "Handler": "com.newrelic.java.HandlerWrapper::",
23
23
  "LambdaExtension": True,
24
24
  },
25
- "nodejs12.x": {
26
- "Handler": "newrelic-lambda-wrapper.handler",
27
- "LambdaExtension": True,
28
- },
29
- "nodejs14.x": {
25
+ "nodejs16.x": {
30
26
  "Handler": "newrelic-lambda-wrapper.handler",
31
27
  "LambdaExtension": True,
32
28
  },
33
- "nodejs16.x": {
29
+ "nodejs18.x": {
34
30
  "Handler": "newrelic-lambda-wrapper.handler",
35
31
  "LambdaExtension": True,
36
32
  },
37
- "nodejs18.x": {
33
+ "nodejs20.x": {
38
34
  "Handler": "newrelic-lambda-wrapper.handler",
39
35
  "LambdaExtension": True,
40
36
  },
41
37
  "provided": {"LambdaExtension": True},
42
38
  "provided.al2": {"LambdaExtension": True},
43
- "python3.6": {
44
- "Handler": "newrelic_lambda_wrapper.handler",
45
- "LambdaExtension": False,
46
- },
47
39
  "python3.7": {
48
40
  "Handler": "newrelic_lambda_wrapper.handler",
49
41
  "LambdaExtension": True,
@@ -64,6 +56,10 @@ RUNTIME_CONFIG = {
64
56
  "Handler": "newrelic_lambda_wrapper.handler",
65
57
  "LambdaExtension": True,
66
58
  },
59
+ "python3.12": {
60
+ "Handler": "newrelic_lambda_wrapper.handler",
61
+ "LambdaExtension": True,
62
+ },
67
63
  }
68
64
 
69
65
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: newrelic-lambda-cli
3
- Version: 0.7.6
3
+ Version: 0.9.0
4
4
  Summary: A CLI to install the New Relic AWS Lambda integration and layers.
5
5
  Home-page: https://github.com/newrelic/newrelic-lambda-cli
6
6
  Author: New Relic
@@ -55,9 +55,9 @@ A CLI to install the New Relic AWS Lambda integration and layers.
55
55
  * java8.al2
56
56
  * java11
57
57
  * java17
58
- * nodejs12.x
59
- * nodejs14.x
60
58
  * nodejs16.x
59
+ * nodejs18.x
60
+ * nodejs20.x
61
61
  * provided
62
62
  * provided.al2
63
63
  * python3.7
@@ -65,13 +65,14 @@ A CLI to install the New Relic AWS Lambda integration and layers.
65
65
  * python3.9
66
66
  * python3.10
67
67
  * python3.11
68
+ * python3.12
68
69
 
69
70
  **Note:** Automatic handler wrapping is only supported for Node.js, Python and Java. For other runtimes,
70
71
  manual function wrapping is required using the runtime specific New Relic agent.
71
72
 
72
73
  ## Requirements
73
74
 
74
- * Python >= 3.3 <= 3.11
75
+ * Python >= 3.3 <= 3.12
75
76
  * Retrieve your [New relic Account ID](https://docs.newrelic.com/docs/accounts/install-new-relic/account-setup/account-id) and [User API Key](https://docs.newrelic.com/docs/apis/get-started/intro-apis/types-new-relic-api-keys#user-api-key)
76
77
 
77
78
  ## Recommendations
@@ -131,6 +132,7 @@ newrelic-lambda integrations install \
131
132
  | `--aws-role-policy` | No | Specify an alternative IAM role policy ARN for this integration. |
132
133
  | `--disable-license-key-secret` | No | Don't create a managed secret for your account's New Relic License Key |
133
134
  | `--tag <key> <value>` | No | Sets tags on the CloudFormation Stacks this CLI creates. Can be used multiple times, example: `--tag key1 value1 --tag key2 value2`. |
135
+ | `--stackname` | No | The AWS Cloudformation stack name which contains the newrelic-log-ingestion lambda function. If no value is provided, the command searches for the NewRelicLogIngestion stack |
134
136
 
135
137
  #### Uninstall Integration
136
138
 
@@ -144,6 +146,7 @@ newrelic-lambda integrations uninstall
144
146
  | `--aws-region` or `-r` | No | The AWS region for the integration. Can use `AWS_DEFAULT_REGION` environment variable. Defaults to AWS session region. |
145
147
  | `--force` or `-f` | No | Forces uninstall non-interactively |
146
148
  | `--nr-account-id` or `-a` | No | The [New Relic Account ID](https://docs.newrelic.com/docs/accounts/install-new-relic/account-setup/account-id) for the integration. Only required if also uninstalling the New Relic AWS Lambda integration. Can also use the `NEW_RELIC_ACCOUNT_ID` environment variable. |
149
+ | `--stackname` | No | The AWS Cloudformation stack name which contains the newrelic-log-ingestion lambda function. If no value is provided, the command searches for the NewRelicLogIngestion stack |
147
150
 
148
151
  #### Update Integration
149
152
 
@@ -171,6 +174,7 @@ newrelic-lambda integrations update \
171
174
  | `--aws-region` or `-r` | No | The AWS region for the integration. Can use `AWS_DEFAULT_REGION` environment variable. Defaults to AWS session region. |
172
175
  | `--disable-license-key-secret` | No | Disable automatic creation of the license key secret on update. The secret is not created if it exists. |
173
176
  | `--tag <key> <value>` | No | Sets tags on the CloudFormation Stacks this CLI creates. Can be used multiple times, example: `--tag key1 value1 --tag key2 value2`. |
177
+ | `--stackname` | No | The AWS Cloudformation stack name which contains the newrelic-log-ingestion lambda function. If no value is provided, the command searches for the NewRelicLogIngestion stack |
174
178
 
175
179
  ### AWS Lambda Layers
176
180
 
@@ -243,6 +247,7 @@ newrelic-lambda subscriptions install --function <name or arn>
243
247
  | Option | Required? | Description |
244
248
  |--------|-----------|-------------|
245
249
  | `--function` or `-f` | Yes | The AWS Lambda function name or ARN in which to add a log subscription. Can provide multiple `--function` arguments. Will also accept `all`, `installed` and `not-installed` similar to `newrelic-lambda functions list`. |
250
+ | `--stackname` | No | The AWS Cloudformation stack name which contains the newrelic-log-ingestion lambda function. If no value is provided, the command searches for the NewRelicLogIngestion stack |
246
251
  | `--exclude` or `-e` | No | A function name to exclude while installing subscriptions. Can provide multiple `--exclude` arguments. Only checked when `all`, `installed` and `not-installed` are used. See `newrelic-lambda functions list` for function names. |
247
252
  | `--filter-pattern` | No | Specify a custom log subscription filter pattern. To collect all logs use `--filter-pattern ""`. |
248
253
  | `--aws-profile` or `-p` | No | The AWS profile to use for this command. Can also use `AWS_PROFILE`. Will also check `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` environment variables if not using AWS CLI. |
@@ -257,6 +262,7 @@ newrelic-lambda subscriptions uninstall --function <name or arn>
257
262
  | Option | Required? | Description |
258
263
  |--------|-----------|-------------|
259
264
  | `--function` or `-f` | Yes | The AWS Lambda function name or ARN in which to remove a log subscription. Can provide multiple `--function` arguments. Will also accept `all`, `installed` and `not-installed` similar to `newrelic-lambda functions list`. |
265
+ | `--stackname` | No | The AWS Cloudformation stack name which contains the newrelic-log-ingestion lambda function. If no value is provided, the command searches for the NewRelicLogIngestion stack |
260
266
  | `--exclude` or `-e` | No | A function name to exclude while uninstalling subscriptions. Can provide multiple `--exclude` arguments. Only checked when `all`, `installed` and `not-installed` are used. See `newrelic-lambda functions list` for function names. |
261
267
  | `--aws-profile` or `-p` | No | The AWS profile to use for this command. Can also use `AWS_PROFILE`. Will also check `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` environment variables if not using AWS CLI. |
262
268
  | `--aws-region` or `-r` | No | The AWS region this function is located. Can use `AWS_DEFAULT_REGION` environment variable. Defaults to AWS session region. |
@@ -6,7 +6,7 @@ README = open(os.path.join(os.path.dirname(__file__), "README.md"), "r").read()
6
6
 
7
7
  setup(
8
8
  name="newrelic-lambda-cli",
9
- version="0.7.6",
9
+ version="0.9.0",
10
10
  python_requires=">=3.3",
11
11
  description="A CLI to install the New Relic AWS Lambda integration and layers.",
12
12
  long_description=README,
@@ -43,7 +43,7 @@ def test__check_for_ingest_stack_none_when_not_found():
43
43
  )
44
44
  }
45
45
  session = MagicMock(**describe_stack_mock)
46
- assert _check_for_ingest_stack(session) is None
46
+ assert _check_for_ingest_stack(session, "test_stack_name") is None
47
47
 
48
48
 
49
49
  def test__check_for_ingest_stack_status_when_found():
@@ -56,7 +56,7 @@ def test__check_for_ingest_stack_status_when_found():
56
56
  }
57
57
  }
58
58
  session = MagicMock(**describe_stack_mock)
59
- assert _check_for_ingest_stack(session) == "CREATE_COMPLETE"
59
+ assert _check_for_ingest_stack(session, "test_stack_name") == "CREATE_COMPLETE"
60
60
 
61
61
 
62
62
  @patch("newrelic_lambda_cli.integrations.success")
@@ -70,7 +70,11 @@ def test__create_log_ingestion_function__defaults(success_mock):
70
70
 
71
71
  _create_log_ingestion_function(
72
72
  integration_install(
73
- session=session, enable_logs=False, memory_size=128, timeout=30
73
+ session=session,
74
+ enable_logs=False,
75
+ memory_size=128,
76
+ timeout=30,
77
+ stackname="NewRelicLogIngestion",
74
78
  ),
75
79
  "test_key",
76
80
  )
@@ -115,6 +119,7 @@ def test__create_log_ingestion_function__opts(success_mock):
115
119
  memory_size=256,
116
120
  role_name="CustomExecRole",
117
121
  timeout=60,
122
+ stackname="NewRelicLogIngestion",
118
123
  ),
119
124
  "test_key",
120
125
  )
@@ -156,8 +161,8 @@ def test_remove_log_ingestion_function(success_mock):
156
161
  session.assert_has_calls(
157
162
  [
158
163
  call.client("cloudformation"),
159
- call.client().describe_stacks(StackName="NewRelicLogIngestion"),
160
- call.client().delete_stack(StackName="NewRelicLogIngestion"),
164
+ call.client().describe_stacks(StackName=None),
165
+ call.client().delete_stack(StackName=None),
161
166
  ],
162
167
  any_order=True,
163
168
  )
@@ -178,7 +183,7 @@ def test_remove_log_ingestion_function_not_present(success_mock):
178
183
  session.assert_has_calls(
179
184
  [
180
185
  call.client("cloudformation"),
181
- call.client().describe_stacks(StackName="NewRelicLogIngestion"),
186
+ call.client().describe_stacks(StackName=None),
182
187
  ],
183
188
  any_order=True,
184
189
  )
@@ -406,7 +411,7 @@ def test_remove_integration_role(aws_credentials):
406
411
  def test_install_log_ingestion(aws_credentials, mock_function_config):
407
412
  mock_session = MagicMock()
408
413
  mock_client = mock_session.client.return_value
409
- mock_client.get_function.return_value = mock_function_config("python3.6")
414
+ mock_client.get_function.return_value = mock_function_config("python3.7")
410
415
 
411
416
  assert (
412
417
  install_log_ingestion(
@@ -418,7 +423,15 @@ def test_install_log_ingestion(aws_credentials, mock_function_config):
418
423
 
419
424
  mock_client.get_function.reset_mock(return_value=True)
420
425
  mock_client.get_function.return_value = None
421
- mock_client.describe_stacks.return_value = {"Stacks": [{"StackStatus": "peachy"}]}
426
+ mock_client.describe_stacks.return_value = {
427
+ "Stacks": [
428
+ {
429
+ "StackId": "arn:aws:cloudformation:us-east-2:363096433263:stack/NewRelicLogIngestion/ec0fa5a0-abdb-11ee-9bc5-0625ef1d38db",
430
+ "StackName": "NewRelicLogIngestion",
431
+ "StackStatus": "CREATE_COMPLETE",
432
+ }
433
+ ]
434
+ }
422
435
  assert (
423
436
  install_log_ingestion(
424
437
  integration_install(nr_account_id=123456789, session=mock_session),
@@ -428,7 +441,10 @@ def test_install_log_ingestion(aws_credentials, mock_function_config):
428
441
  )
429
442
 
430
443
  mock_client.describe_stacks.reset_mock(return_value=True)
431
- mock_client.describe_stacks.return_value = {"Stacks": [{"StackStatus": None}]}
444
+ mock_client.describe_stacks.return_value = {
445
+ "Stacks": [{"StackId": None, "StackName": None, "StackStatus": None}]
446
+ }
447
+ mock_client._check_for_ingest_stack.return_value = None
432
448
  assert (
433
449
  install_log_ingestion(
434
450
  integration_install(nr_account_id=123456789, session=mock_session),
@@ -451,7 +467,7 @@ def test_update_log_ingestion(aws_credentials, mock_function_config):
451
467
  )
452
468
 
453
469
  mock_client.get_function.reset_mock(return_value=True)
454
- mock_client.get_function.return_value = mock_function_config("python3.6")
470
+ mock_client.get_function.return_value = mock_function_config("python3.7")
455
471
  mock_client.describe_stacks.return_value = {"Stacks": [{"StackStatus": None}]}
456
472
 
457
473
  assert (
@@ -462,7 +478,15 @@ def test_update_log_ingestion(aws_credentials, mock_function_config):
462
478
  )
463
479
 
464
480
  mock_client.describe_stacks.reset_mock(return_value=True)
465
- mock_client.describe_stacks.return_value = {"Stacks": [{"StackStatus": "peachy"}]}
481
+ mock_client.describe_stacks.return_value = {
482
+ "Stacks": [
483
+ {
484
+ "StackId": "arn:aws:cloudformation:us-east-2:363096433263:stack/NewRelicLogIngestion/ec0fa5a0-abdb-11ee-9bc5-0625ef1d38db",
485
+ "StackName": "NewRelicLogIngestion",
486
+ "StackStatus": "CREATE_COMPLETE",
487
+ }
488
+ ]
489
+ }
466
490
 
467
491
  assert (
468
492
  update_log_ingestion(
@@ -24,7 +24,7 @@ from .conftest import layer_install, layer_uninstall
24
24
  def test_add_new_relic(aws_credentials, mock_function_config):
25
25
  session = boto3.Session(region_name="us-east-1")
26
26
 
27
- config = mock_function_config("python3.11")
27
+ config = mock_function_config("python3.12")
28
28
 
29
29
  assert config["Configuration"]["Handler"] == "original_handler"
30
30
 
@@ -71,10 +71,10 @@ def test_add_new_relic(aws_credentials, mock_function_config):
71
71
  config,
72
72
  nr_license_key=None,
73
73
  )
74
- is True
74
+ is False
75
75
  )
76
76
 
77
- config = mock_function_config("python3.11")
77
+ config = mock_function_config("python3.12")
78
78
  config["Configuration"]["Layers"] = [{"Arn": get_arn_prefix("us-east-1")}]
79
79
  assert (
80
80
  _add_new_relic(
@@ -93,7 +93,7 @@ def test_add_new_relic(aws_credentials, mock_function_config):
93
93
 
94
94
  with patch("newrelic_lambda_cli.layers.index") as mock_index:
95
95
  mock_index.return_value = []
96
- config = mock_function_config("python3.11")
96
+ config = mock_function_config("python3.12")
97
97
  assert (
98
98
  _add_new_relic(
99
99
  layer_install(
@@ -190,15 +190,15 @@ def test_add_new_relic(aws_credentials, mock_function_config):
190
190
  ) as mock_isatty:
191
191
  mock_isatty.return_value = True
192
192
  mock_prompt.return_value = 0
193
- result = layer_selection(mock_layers, "python3.11", "x86_64")
193
+ result = layer_selection(mock_layers, "python3.12", "x86_64")
194
194
  assert result == "arn:aws:lambda:us-east-1:123456789:layer/javajava"
195
195
 
196
196
  with patch("sys.stdout.isatty") as mock_isatty:
197
197
  mock_isatty.return_value = False
198
198
  with pytest.raises(UsageError):
199
- layer_selection(mock_layers, "python3.11", "x86_64")
199
+ layer_selection(mock_layers, "python3.12", "x86_64")
200
200
 
201
- config = mock_function_config("python3.11")
201
+ config = mock_function_config("python3.12")
202
202
  _add_new_relic(
203
203
  layer_install(
204
204
  session=session,
@@ -216,7 +216,7 @@ def test_add_new_relic(aws_credentials, mock_function_config):
216
216
  in config["Configuration"]["Environment"]["Variables"]
217
217
  )
218
218
 
219
- config = mock_function_config("python3.11")
219
+ config = mock_function_config("python3.12")
220
220
  config["Configuration"]["Environment"]["Variables"]["NEW_RELIC_FOO"] = "bar"
221
221
  config["Configuration"]["Layers"] = [{"Arn": get_arn_prefix("us-east-1")}]
222
222
  update_kwargs = _add_new_relic(
@@ -234,30 +234,12 @@ def test_add_new_relic(aws_credentials, mock_function_config):
234
234
  assert "NEW_RELIC_FOO" in update_kwargs["Environment"]["Variables"]
235
235
  assert update_kwargs["Layers"][0] != get_arn_prefix("us-east-1")
236
236
 
237
- config = mock_function_config("python3.6")
238
- update_kwargs = _add_new_relic(
239
- layer_install(
240
- session=session,
241
- aws_region="us-east-1",
242
- nr_account_id=12345,
243
- enable_extension=True,
244
- enable_extension_function_logs=True,
245
- upgrade=True,
246
- ),
247
- config,
248
- "foobarbaz",
249
- )
250
- assert (
251
- update_kwargs["Environment"]["Variables"]["NEW_RELIC_LAMBDA_EXTENSION_ENABLED"]
252
- == "false"
253
- )
254
-
255
237
 
256
238
  @mock_lambda
257
239
  def test_remove_new_relic(aws_credentials, mock_function_config):
258
240
  session = boto3.Session(region_name="us-east-1")
259
241
 
260
- config = mock_function_config("python3.11")
242
+ config = mock_function_config("python3.12")
261
243
  config["Configuration"]["Handler"] = "newrelic_lambda_wrapper.handler"
262
244
  config["Configuration"]["Environment"]["Variables"][
263
245
  "NEW_RELIC_LAMBDA_HANDLER"
@@ -281,7 +263,7 @@ def test_remove_new_relic(aws_credentials, mock_function_config):
281
263
  is True
282
264
  )
283
265
 
284
- config = mock_function_config("python3.11")
266
+ config = mock_function_config("python3.12")
285
267
  config["Configuration"]["Handler"] = "what is this?"
286
268
  assert (
287
269
  _remove_new_relic(
@@ -352,7 +334,7 @@ def test_install_failure(aws_credentials, mock_function_config):
352
334
  "newrelic_lambda_cli.layers._get_license_key_outputs"
353
335
  ) as mock_get_license_key_outputs:
354
336
  mock_get_license_key_outputs.return_value = ("license_arn", "12345", "policy")
355
- config = mock_function_config("python3.11")
337
+ config = mock_function_config("python3.12")
356
338
  mock_client.get_function.return_value = config
357
339
  with pytest.raises(UsageError):
358
340
  install(
@@ -370,7 +352,7 @@ def test_install(aws_credentials, mock_function_config):
370
352
  mock_client = mock_session.client.return_value
371
353
  mock_client.get_function.reset_mock(return_value=True)
372
354
  mock_get_license_key_outputs.return_value = ("license_arn", "12345", "policy")
373
- config = mock_function_config("python3.11")
355
+ config = mock_function_config("python3.12")
374
356
  mock_client.get_function.return_value = config
375
357
  with pytest.raises(UsageError):
376
358
  install(
@@ -393,11 +375,11 @@ def test_install(aws_credentials, mock_function_config):
393
375
  install(
394
376
  layer_install(nr_account_id=12345, session=mock_session), "foobarbaz"
395
377
  )
396
- is True
378
+ is False
397
379
  )
398
380
 
399
381
  mock_client.get_function.reset_mock(return_value=True)
400
- config = mock_function_config("python3.11")
382
+ config = mock_function_config("python3.12")
401
383
  mock_client.get_function.return_value = config
402
384
  assert (
403
385
  install(
@@ -443,7 +425,7 @@ def test_uninstall(aws_credentials, mock_function_config):
443
425
  assert uninstall(layer_uninstall(session=mock_session), "foobarbaz") is True
444
426
 
445
427
  mock_client.get_function.reset_mock(return_value=True)
446
- config = mock_function_config("python3.11")
428
+ config = mock_function_config("python3.12")
447
429
  mock_client.get_function.return_value = config
448
430
  assert uninstall(layer_uninstall(session=mock_session), "foobarbaz") is False
449
431
 
@@ -476,6 +458,6 @@ def test_uninstall(aws_credentials, mock_function_config):
476
458
 
477
459
 
478
460
  def test_layers_index():
479
- layers = index("ap-southeast-1", "nodejs14.x", "x86_64")
461
+ layers = index("ap-southeast-1", "nodejs20.x", "x86_64")
480
462
 
481
463
  assert len(layers) == 1
@@ -21,13 +21,24 @@ def test__get_log_group_name():
21
21
  @patch("newrelic_lambda_cli.subscriptions._create_subscription_filter", autospec=True)
22
22
  @patch("newrelic_lambda_cli.subscriptions._get_subscription_filters", autospec=True)
23
23
  @patch("newrelic_lambda_cli.subscriptions._remove_subscription_filter", autospec=True)
24
+ @patch("newrelic_lambda_cli.integrations.get_function", autospec=True)
24
25
  @patch("newrelic_lambda_cli.subscriptions.get_function", autospec=True)
26
+ @patch(
27
+ "newrelic_lambda_cli.integrations.get_unique_newrelic_log_ingestion_name",
28
+ autospec=True,
29
+ )
25
30
  def test_create_log_subscription(
31
+ mock_get_unique_newrelic_log_ingestion_name,
32
+ mock_subscriptions_get_function,
26
33
  mock_get_function,
27
34
  mock_remove_subscription_filter,
28
35
  mock_get_subscription_filters,
29
36
  mock_create_subscription_filter,
30
37
  ):
38
+ mock_get_unique_newrelic_log_ingestion_name.return_value = "newrelic-log-ingestion"
39
+
40
+ mock_subscriptions_get_function.side_effect = None
41
+
31
42
  mock_get_function.side_effect = (
32
43
  None,
33
44
  {"Configuration": {"FunctionArn": "FooBarBaz"}},
@@ -80,10 +80,9 @@ def test_supports_lambda_extension():
80
80
  "java17",
81
81
  "java11",
82
82
  "java8.al2",
83
- "nodejs12.x",
84
- "nodejs14.x",
85
83
  "nodejs16.x",
86
84
  "nodejs18.x",
85
+ "nodejs20.x",
87
86
  "provided",
88
87
  "provided.al2",
89
88
  "python3.7",
@@ -91,6 +90,7 @@ def test_supports_lambda_extension():
91
90
  "python3.9",
92
91
  "python3.10",
93
92
  "python3.11",
93
+ "python3.12",
94
94
  )
95
95
  )
96
96
  assert not any(