newrelic-lambda-cli 0.9.2__py2.py3-none-any.whl → 0.9.4__py2.py3-none-any.whl

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.
@@ -21,6 +21,9 @@ from newrelic_lambda_cli.types import (
21
21
  IntegrationInstall,
22
22
  IntegrationUpdate,
23
23
  LayerInstall,
24
+ OtelIngestionInstall,
25
+ OtelIngestionUninstall,
26
+ OtelIngestionUpdate,
24
27
  )
25
28
  from newrelic_lambda_cli.utils import parse_arn
26
29
 
@@ -333,7 +336,17 @@ class NewRelicGQL(object):
333
336
 
334
337
 
335
338
  def validate_gql_credentials(input):
336
- assert isinstance(input, (IntegrationInstall, IntegrationUpdate, LayerInstall))
339
+
340
+ assert isinstance(
341
+ input,
342
+ (
343
+ IntegrationInstall,
344
+ IntegrationUpdate,
345
+ LayerInstall,
346
+ OtelIngestionInstall,
347
+ OtelIngestionUpdate,
348
+ ),
349
+ )
337
350
 
338
351
  try:
339
352
  return NewRelicGQL(input.nr_account_id, input.nr_api_key, input.nr_region)
@@ -2,7 +2,13 @@
2
2
 
3
3
  import click
4
4
 
5
- from newrelic_lambda_cli.cli import functions, integrations, layers, subscriptions
5
+ from newrelic_lambda_cli.cli import (
6
+ functions,
7
+ integrations,
8
+ layers,
9
+ otel_ingestions,
10
+ subscriptions,
11
+ )
6
12
 
7
13
 
8
14
  @click.group()
@@ -17,6 +23,7 @@ def cli(ctx, verbose):
17
23
  def register_groups(group):
18
24
  functions.register(group)
19
25
  integrations.register(group)
26
+ otel_ingestions.register(group)
20
27
  layers.register(group)
21
28
  subscriptions.register(group)
22
29
 
@@ -0,0 +1,219 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ import boto3
4
+ import click
5
+
6
+ from newrelic_lambda_cli import api, otel_ingestions, permissions, integrations
7
+ from newrelic_lambda_cli.types import (
8
+ OtelIngestionInstall,
9
+ OtelIngestionUninstall,
10
+ OtelIngestionUpdate,
11
+ )
12
+ from newrelic_lambda_cli.cli.decorators import add_options, AWS_OPTIONS, NR_OPTIONS
13
+ from newrelic_lambda_cli.cliutils import done, failure
14
+
15
+
16
+ @click.group(name="otel-ingestions")
17
+ def ingestion_group():
18
+ """Manage New Relic AWS Lambda Otel Log Ingestion lambda"""
19
+ pass
20
+
21
+
22
+ def register(group):
23
+ group.add_command(ingestion_group)
24
+ ingestion_group.add_command(install)
25
+ ingestion_group.add_command(uninstall)
26
+ ingestion_group.add_command(update)
27
+
28
+
29
+ @click.command(name="install")
30
+ @add_options(AWS_OPTIONS)
31
+ @click.option(
32
+ "--aws-role-policy",
33
+ help="Alternative AWS role policy to use for integration",
34
+ metavar="<arn>",
35
+ )
36
+ @click.option(
37
+ "--stackname",
38
+ default=otel_ingestions.OTEL_INGEST_STACK_NAME,
39
+ help=f"The AWS Cloudformation stack name which contains the {otel_ingestions.OTEL_INGEST_LAMBDA_NAME} lambda function",
40
+ metavar="<arn>",
41
+ show_default=False,
42
+ required=False,
43
+ )
44
+ @click.option(
45
+ "--memory-size",
46
+ "-m",
47
+ default=128,
48
+ help="Memory size (in MiB) for the log ingestion function",
49
+ metavar="<size>",
50
+ show_default=True,
51
+ type=click.INT,
52
+ )
53
+ @add_options(NR_OPTIONS)
54
+ @click.option(
55
+ "--timeout",
56
+ "-t",
57
+ default=30,
58
+ help="Timeout (in seconds) for the New Relic log ingestion function",
59
+ metavar="<secs>",
60
+ show_default=True,
61
+ type=click.INT,
62
+ )
63
+ @click.option(
64
+ "--role-name",
65
+ default=None,
66
+ help="The name of a pre-created execution role for the log ingest function",
67
+ metavar="<role_name>",
68
+ show_default=False,
69
+ )
70
+ @click.option(
71
+ "--tag",
72
+ "tags",
73
+ default=[],
74
+ help="A tag to be added to the CloudFormation Stack (can be used multiple times)",
75
+ metavar="<key> <value>",
76
+ multiple=True,
77
+ nargs=2,
78
+ )
79
+ @click.pass_context
80
+ def install(ctx, **kwargs):
81
+ """Install New Relic AWS OTEL Ingestion Lambda"""
82
+ input = OtelIngestionInstall(session=None, verbose=ctx.obj["VERBOSE"], **kwargs)
83
+
84
+ input = input._replace(
85
+ session=boto3.Session(
86
+ profile_name=input.aws_profile, region_name=input.aws_region
87
+ )
88
+ )
89
+
90
+ if input.aws_permissions_check:
91
+ permissions.ensure_integration_install_permissions(input)
92
+
93
+ click.echo("Validating New Relic credentials")
94
+ gql_client = api.validate_gql_credentials(input)
95
+
96
+ click.echo("Retrieving integration license key")
97
+ nr_license_key = api.retrieve_license_key(gql_client)
98
+
99
+ install_success = True
100
+
101
+ click.echo(
102
+ f"Creating {otel_ingestions.OTEL_INGEST_LAMBDA_NAME} Lambda function in AWS account"
103
+ )
104
+ res = otel_ingestions.install_otel_log_ingestion(input, nr_license_key)
105
+ install_success = res and install_success
106
+
107
+
108
+ @click.command(name="uninstall")
109
+ @add_options(AWS_OPTIONS)
110
+ @click.option(
111
+ "--nr-account-id",
112
+ "-a",
113
+ envvar="NEW_RELIC_ACCOUNT_ID",
114
+ help="New Relic Account ID",
115
+ metavar="<id>",
116
+ required=False,
117
+ type=click.INT,
118
+ )
119
+ @click.option(
120
+ "--stackname",
121
+ default=otel_ingestions.OTEL_INGEST_STACK_NAME,
122
+ help=f"The AWS Cloudformation stack name which contains the {otel_ingestions.OTEL_INGEST_LAMBDA_NAME} lambda function",
123
+ metavar="<arn>",
124
+ show_default=False,
125
+ required=False,
126
+ )
127
+ @click.option("--force", "-f", help="Force uninstall non-interactively", is_flag=True)
128
+ def uninstall(**kwargs):
129
+ """Uninstall New Relic AWS OTEL Ingestion Lambda"""
130
+ input = OtelIngestionUninstall(session=None, **kwargs)
131
+
132
+ input = input._replace(
133
+ session=boto3.Session(
134
+ profile_name=input.aws_profile, region_name=input.aws_region
135
+ )
136
+ )
137
+
138
+ if input.aws_permissions_check:
139
+ permissions.ensure_integration_uninstall_permissions(input)
140
+
141
+ integrations.remove_log_ingestion_function(input, otel=True)
142
+
143
+ done("Uninstall Complete")
144
+
145
+
146
+ @click.command(name="update")
147
+ @add_options(AWS_OPTIONS)
148
+ @click.option(
149
+ "--stackname",
150
+ default=otel_ingestions.OTEL_INGEST_STACK_NAME,
151
+ help=f"The AWS Cloudformation stack name which contains the {otel_ingestions.OTEL_INGEST_LAMBDA_NAME} lambda function",
152
+ metavar="<arn>",
153
+ show_default=False,
154
+ required=False,
155
+ )
156
+ @click.option(
157
+ "--memory-size",
158
+ "-m",
159
+ help="Memory size (in MiB) for the log ingestion function",
160
+ metavar="<size>",
161
+ type=click.INT,
162
+ )
163
+ @add_options(NR_OPTIONS)
164
+ @click.option(
165
+ "--timeout",
166
+ "-t",
167
+ help="Timeout (in seconds) for the New Relic log ingestion function",
168
+ metavar="<secs>",
169
+ type=click.INT,
170
+ )
171
+ @click.option(
172
+ "--role-name",
173
+ default=None,
174
+ help="The name of a new pre-created execution role for the log ingest function",
175
+ metavar="<role_name>",
176
+ show_default=False,
177
+ )
178
+ @click.option(
179
+ "--stackname",
180
+ default="NewRelicOtelLogIngestion",
181
+ help="The AWS Cloudformation stack name which contains the newrelic-log-ingestion lambda function",
182
+ metavar="<arn>",
183
+ show_default=False,
184
+ required=False,
185
+ )
186
+ @click.option(
187
+ "--tag",
188
+ "tags",
189
+ default=[],
190
+ help="A tag to be added to the CloudFormation Stack (can be used multiple times)",
191
+ metavar="<key> <value>",
192
+ multiple=True,
193
+ nargs=2,
194
+ )
195
+ def update(**kwargs):
196
+ """UpdateNew New Relic AWS OTEL Ingestion Lambda"""
197
+ input = OtelIngestionUpdate(session=None, **kwargs)
198
+
199
+ input = input._replace(
200
+ session=boto3.Session(
201
+ profile_name=input.aws_profile, region_name=input.aws_region
202
+ )
203
+ )
204
+
205
+ if input.aws_permissions_check:
206
+ permissions.ensure_integration_install_permissions(input)
207
+
208
+ update_success = True
209
+
210
+ click.echo(
211
+ f"Updating {otel_ingestions.OTEL_INGEST_LAMBDA_NAME} Lambda function in AWS account"
212
+ )
213
+ res = otel_ingestions.update_otel_log_ingestion(input)
214
+ update_success = res and update_success
215
+
216
+ if update_success:
217
+ done("Update Complete")
218
+ else:
219
+ failure("Update Incomplete. See messages above for details.", exit=True)
@@ -61,9 +61,23 @@ def register(group):
61
61
  metavar="<pattern>",
62
62
  show_default=False,
63
63
  )
64
+ @click.option(
65
+ "--otel",
66
+ "-o",
67
+ help="Subscribe to OTEL log ingestion function",
68
+ is_flag=True,
69
+ )
64
70
  def install(**kwargs):
65
71
  """Install New Relic AWS Lambda Log Subscriptions"""
66
72
  input = SubscriptionInstall(session=None, **kwargs)
73
+ if input.otel and input.filter_pattern == DEFAULT_FILTER_PATTERN:
74
+ input = input._replace(
75
+ filter_pattern="",
76
+ )
77
+ if input.otel and input.stackname == "NewRelicLogIngestion":
78
+ input = input._replace(
79
+ stackname="NewRelicOtelLogIngestion",
80
+ )
67
81
  input = input._replace(
68
82
  session=boto3.Session(
69
83
  profile_name=input.aws_profile, region_name=input.aws_region
@@ -75,18 +89,32 @@ def install(**kwargs):
75
89
  functions = get_aliased_functions(input)
76
90
 
77
91
  with ThreadPoolExecutor() as executor:
78
- futures = [
79
- executor.submit(
80
- subscriptions.create_log_subscription,
81
- input._replace(
82
- session=boto3.Session(
83
- profile_name=input.aws_profile, region_name=input.aws_region
84
- )
85
- ),
86
- function,
87
- )
88
- for function in functions
89
- ]
92
+ if input.otel:
93
+ futures = [
94
+ executor.submit(
95
+ subscriptions.create_otel_log_subscription,
96
+ input._replace(
97
+ session=boto3.Session(
98
+ profile_name=input.aws_profile, region_name=input.aws_region
99
+ )
100
+ ),
101
+ function,
102
+ )
103
+ for function in functions
104
+ ]
105
+ else:
106
+ futures = [
107
+ executor.submit(
108
+ subscriptions.create_log_subscription,
109
+ input._replace(
110
+ session=boto3.Session(
111
+ profile_name=input.aws_profile, region_name=input.aws_region
112
+ )
113
+ ),
114
+ function,
115
+ )
116
+ for function in functions
117
+ ]
90
118
  install_success = all(future.result() for future in as_completed(futures))
91
119
 
92
120
  if install_success:
@@ -106,14 +134,6 @@ def install(**kwargs):
106
134
  multiple=True,
107
135
  required=True,
108
136
  )
109
- @click.option(
110
- "--stackname",
111
- default="NewRelicLogIngestion",
112
- help="The AWS Cloudformation stack name which contains the newrelic-log-ingestion lambda function",
113
- metavar="<arn>",
114
- show_default=False,
115
- required=False,
116
- )
117
137
  @click.option(
118
138
  "excludes",
119
139
  "--exclude",
@@ -122,6 +142,12 @@ def install(**kwargs):
122
142
  metavar="<name>",
123
143
  multiple=True,
124
144
  )
145
+ @click.option(
146
+ "--otel",
147
+ "-o",
148
+ help="Subscribe to OTEL log ingestion function",
149
+ is_flag=True,
150
+ )
125
151
  def uninstall(**kwargs):
126
152
  """Uninstall New Relic AWS Lambda Log Subscriptions"""
127
153
  input = SubscriptionUninstall(session=None, **kwargs)
@@ -136,18 +162,32 @@ def uninstall(**kwargs):
136
162
  functions = get_aliased_functions(input)
137
163
 
138
164
  with ThreadPoolExecutor() as executor:
139
- futures = [
140
- executor.submit(
141
- subscriptions.remove_log_subscription,
142
- input._replace(
143
- session=boto3.Session(
144
- profile_name=input.aws_profile, region_name=input.aws_region
145
- )
146
- ),
147
- function,
148
- )
149
- for function in functions
150
- ]
165
+ if input.otel:
166
+ futures = [
167
+ executor.submit(
168
+ subscriptions.remove_otel_log_subscription,
169
+ input._replace(
170
+ session=boto3.Session(
171
+ profile_name=input.aws_profile, region_name=input.aws_region
172
+ )
173
+ ),
174
+ function,
175
+ )
176
+ for function in functions
177
+ ]
178
+ else:
179
+ futures = [
180
+ executor.submit(
181
+ subscriptions.remove_log_subscription,
182
+ input._replace(
183
+ session=boto3.Session(
184
+ profile_name=input.aws_profile, region_name=input.aws_region
185
+ )
186
+ ),
187
+ function,
188
+ )
189
+ for function in functions
190
+ ]
151
191
  uninstall_success = all(future.result() for future in as_completed(futures))
152
192
 
153
193
  if uninstall_success:
@@ -1,21 +1,20 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
3
  import click
4
- import emoji
5
4
 
6
5
  from click.exceptions import Exit
7
6
 
8
7
 
9
8
  def done(message):
10
9
  """Prints a done message to the terminal"""
11
- click.echo(emoji.emojize(":sparkles: %s :sparkles:" % message, language="alias"))
10
+ click.echo(f"✔️ {message} ✔️")
12
11
 
13
12
 
14
13
  def failure(message, exit=False):
15
14
  """Prints a failure message to the terminal"""
16
- click.echo(
17
- emoji.emojize(":heavy_multiplication_x: %s" % message, language="alias"),
18
- color="red",
15
+ click.secho(
16
+ f" {message}",
17
+ fg="red",
19
18
  err=True,
20
19
  )
21
20
  if exit:
@@ -24,15 +23,15 @@ def failure(message, exit=False):
24
23
 
25
24
  def success(message):
26
25
  """Prints a success message to the terminal"""
27
- click.echo(
28
- emoji.emojize(":heavy_check_mark: %s" % message, language="alias"),
29
- color="green",
26
+ click.secho(
27
+ f"✔️ {message}",
28
+ fg="green",
30
29
  )
31
30
 
32
31
 
33
32
  def warning(message):
34
- """Prints a warningmessage to the terminal"""
35
- click.echo(
36
- emoji.emojize(":heavy_exclamation_mark: %s" % message, language="alias"),
37
- color="blue",
33
+ """Prints a warning message to the terminal"""
34
+ click.secho(
35
+ f"⚠️ {message}",
36
+ fg="blue",
38
37
  )
@@ -14,6 +14,7 @@ from newrelic_lambda_cli.types import (
14
14
  IntegrationInstall,
15
15
  IntegrationUninstall,
16
16
  IntegrationUpdate,
17
+ OtelIngestionUninstall,
17
18
  )
18
19
  from newrelic_lambda_cli.utils import catch_boto_errors, NR_DOCS_ACT_LINKING_URL
19
20
 
@@ -165,9 +166,11 @@ def _create_role(input):
165
166
  {"ParameterKey": "PolicyName", "ParameterValue": role_policy_name},
166
167
  ],
167
168
  Capabilities=["CAPABILITY_NAMED_IAM"],
168
- Tags=[{"Key": key, "Value": value} for key, value in input.tags]
169
- if input.tags
170
- else [],
169
+ Tags=(
170
+ [{"Key": key, "Value": value} for key, value in input.tags]
171
+ if input.tags
172
+ else []
173
+ ),
171
174
  )
172
175
 
173
176
  click.echo("Waiting for stack creation to complete... ", nl=False)
@@ -268,9 +271,11 @@ def _import_log_ingestion_function(input, nr_license_key):
268
271
  TemplateBody=template.read(),
269
272
  Parameters=parameters,
270
273
  Capabilities=capabilities,
271
- Tags=[{"Key": key, "Value": value} for key, value in input.tags]
272
- if input.tags
273
- else [],
274
+ Tags=(
275
+ [{"Key": key, "Value": value} for key, value in input.tags]
276
+ if input.tags
277
+ else []
278
+ ),
274
279
  ChangeSetType="IMPORT",
275
280
  ChangeSetName=change_set_name,
276
281
  ResourcesToImport=[
@@ -311,9 +316,11 @@ def _create_log_ingestion_function(
311
316
  TemplateURL=template_url,
312
317
  Parameters=parameters,
313
318
  Capabilities=capabilities,
314
- Tags=[{"Key": key, "Value": value} for key, value in input.tags]
315
- if input.tags
316
- else [],
319
+ Tags=(
320
+ [{"Key": key, "Value": value} for key, value in input.tags]
321
+ if input.tags
322
+ else []
323
+ ),
317
324
  ChangeSetType=mode,
318
325
  ChangeSetName=change_set_name,
319
326
  )
@@ -444,9 +451,11 @@ def update_log_ingestion_function(input):
444
451
  TemplateBody=json.dumps(template_body),
445
452
  Parameters=params,
446
453
  Capabilities=["CAPABILITY_IAM"],
447
- Tags=[{"Key": key, "Value": value} for key, value in input.tags]
448
- if input.tags
449
- else [],
454
+ Tags=(
455
+ [{"Key": key, "Value": value} for key, value in input.tags]
456
+ if input.tags
457
+ else []
458
+ ),
450
459
  )
451
460
 
452
461
  try:
@@ -496,18 +505,20 @@ def update_log_ingestion_function(input):
496
505
 
497
506
 
498
507
  @catch_boto_errors
499
- def remove_log_ingestion_function(input):
500
- assert isinstance(input, IntegrationUninstall)
501
-
508
+ def remove_log_ingestion_function(input, otel: bool = False):
509
+ assert isinstance(input, (IntegrationUninstall, OtelIngestionUninstall))
510
+ log_ingestion_lambda = "log ingestion" if not otel else "OTEL log ingestion"
502
511
  client = input.session.client("cloudformation")
503
512
  stack_status = _check_for_ingest_stack(input.session, input.stackname)
504
513
  if stack_status is None:
505
514
  click.echo(
506
- "No New Relic AWS Lambda log ingestion found in region %s, skipping"
507
- % input.session.region_name
515
+ "No New Relic AWS Lambda %s found in region %s, skipping"
516
+ % (log_ingestion_lambda, input.session.region_name)
508
517
  )
509
518
  return
510
- click.echo("Deleting New Relic log ingestion stack '%s'" % input.stackname)
519
+ click.echo(
520
+ "Deleting New Relic %s stack '%s'" % (log_ingestion_lambda, input.stackname)
521
+ )
511
522
  client.delete_stack(StackName=input.stackname)
512
523
  click.echo(
513
524
  "Waiting for stack deletion to complete, this may take a minute... ", nl=False
@@ -755,9 +766,11 @@ def install_license_key(input, nr_license_key, policy_name=None):
755
766
  TemplateBody=template.read(),
756
767
  Parameters=parameters,
757
768
  Capabilities=["CAPABILITY_NAMED_IAM"],
758
- Tags=[{"Key": key, "Value": value} for key, value in input.tags]
759
- if input.tags
760
- else [],
769
+ Tags=(
770
+ [{"Key": key, "Value": value} for key, value in input.tags]
771
+ if input.tags
772
+ else []
773
+ ),
761
774
  ChangeSetType=mode,
762
775
  ChangeSetName=change_set_name,
763
776
  )
@@ -0,0 +1,276 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ import json
4
+ import os
5
+ import time
6
+
7
+ import botocore
8
+ import click
9
+ import json
10
+
11
+ from newrelic_lambda_cli.cliutils import failure, success, warning
12
+ from newrelic_lambda_cli.functions import get_function
13
+ from newrelic_lambda_cli.integrations import _exec_change_set
14
+ from newrelic_lambda_cli.types import (
15
+ OtelIngestionInstall,
16
+ OtelIngestionUpdate,
17
+ )
18
+ from newrelic_lambda_cli.utils import catch_boto_errors, NR_DOCS_ACT_LINKING_URL
19
+
20
+ OTEL_INGEST_STACK_NAME = "NewRelicOtelLogIngestion"
21
+ OTEL_INGEST_LAMBDA_NAME = "newrelic-aws-otel-log-ingestion"
22
+ OTEL_SAR_APP_ID = (
23
+ "arn:aws:serverlessrepo:us-east-1:451483290750:applications/"
24
+ + OTEL_INGEST_LAMBDA_NAME
25
+ )
26
+
27
+
28
+ def _check_for_ingest_stack(session, stack_name):
29
+ return _get_cf_stack_status(session, stack_name)
30
+
31
+
32
+ def _get_cf_stack_status(session, stack_name, nr_account_id=None):
33
+ """Returns the status of the CloudFormation stack if it exists"""
34
+ try:
35
+ res = session.client("cloudformation").describe_stacks(StackName=stack_name)
36
+ except botocore.exceptions.ClientError as e:
37
+ if (
38
+ e.response
39
+ and "ResponseMetadata" in e.response
40
+ and "HTTPStatusCode" in e.response["ResponseMetadata"]
41
+ and e.response["ResponseMetadata"]["HTTPStatusCode"] in (400, 404)
42
+ ):
43
+ return None
44
+ raise click.UsageError(str(e))
45
+ else:
46
+ return res["Stacks"][0]["StackStatus"]
47
+
48
+
49
+ def get_unique_newrelic_otel_log_ingestion_name(session, stackname=None):
50
+ if not stackname:
51
+ stackname = OTEL_INGEST_STACK_NAME
52
+ stack_id = _get_otel_cf_stack_id(session, stack_name=stackname)
53
+ if stack_id:
54
+ return "%s-%s" % (OTEL_INGEST_LAMBDA_NAME, stack_id.split("/")[2].split("-")[4])
55
+
56
+
57
+ def get_newrelic_otel_log_ingestion_function(session, stackname=None):
58
+ unique_log_ingestion_name = get_unique_newrelic_otel_log_ingestion_name(
59
+ session, stackname
60
+ )
61
+ if unique_log_ingestion_name:
62
+ function = get_function(session, unique_log_ingestion_name)
63
+ return function
64
+
65
+
66
+ def _get_otel_cf_stack_id(session, stack_name, nr_account_id=None):
67
+ """Returns the StackId of the CloudFormation stack if it exists"""
68
+ try:
69
+ res = session.client("cloudformation").describe_stacks(StackName=stack_name)
70
+ except botocore.exceptions.ClientError as e:
71
+ if (
72
+ e.response
73
+ and "ResponseMetadata" in e.response
74
+ and "HTTPStatusCode" in e.response["ResponseMetadata"]
75
+ and e.response["ResponseMetadata"]["HTTPStatusCode"] in (400, 404)
76
+ ):
77
+ return None
78
+ raise click.UsageError(str(e))
79
+ else:
80
+ return res["Stacks"][0]["StackId"]
81
+
82
+
83
+ def _get_otel_sar_template_url(session):
84
+ sar_client = session.client("serverlessrepo")
85
+ template_details = sar_client.create_cloud_formation_template(
86
+ ApplicationId=OTEL_SAR_APP_ID
87
+ )
88
+ return template_details["TemplateUrl"]
89
+
90
+
91
+ def _create_otel_log_ingest_parameters(input, nr_license_key, mode="CREATE"):
92
+ assert isinstance(input, (OtelIngestionInstall, OtelIngestionUpdate))
93
+
94
+ update_mode = mode == "UPDATE"
95
+ parameters = []
96
+
97
+ if input.memory_size is not None:
98
+ parameters.append(
99
+ {"ParameterKey": "MemorySize", "ParameterValue": str(input.memory_size)}
100
+ )
101
+ elif update_mode:
102
+ parameters.append({"ParameterKey": "MemorySize", "UsePreviousValue": True})
103
+
104
+ if nr_license_key is not None:
105
+ parameters.append(
106
+ {"ParameterKey": "NRLicenseKey", "ParameterValue": nr_license_key}
107
+ )
108
+ elif update_mode:
109
+ parameters.append({"ParameterKey": "NRLicenseKey", "UsePreviousValue": True})
110
+
111
+ if input.timeout is not None:
112
+ parameters.append(
113
+ {"ParameterKey": "Timeout", "ParameterValue": str(input.timeout)}
114
+ )
115
+ elif update_mode:
116
+ parameters.append({"ParameterKey": "Timeout", "UsePreviousValue": True})
117
+
118
+ capabilities = ["CAPABILITY_IAM"]
119
+ if input.role_name is not None:
120
+ parameters.append(
121
+ {"ParameterKey": "FunctionRole", "ParameterValue": input.role_name}
122
+ )
123
+ capabilities = []
124
+ elif mode != "CREATE":
125
+ parameters.append({"ParameterKey": "FunctionRole", "UsePreviousValue": True})
126
+ capabilities = []
127
+
128
+ return parameters, capabilities
129
+
130
+
131
+ def _create_otel_log_ingestion_function(
132
+ input,
133
+ nr_license_key,
134
+ mode="CREATE",
135
+ ):
136
+ assert isinstance(input, (OtelIngestionInstall, OtelIngestionUpdate))
137
+
138
+ parameters, capabilities = _create_otel_log_ingest_parameters(
139
+ input, nr_license_key, mode
140
+ )
141
+
142
+ client = input.session.client("cloudformation")
143
+
144
+ click.echo("Fetching new CloudFormation template url for OTEL log ingestion")
145
+ template_url = _get_otel_sar_template_url(input.session)
146
+ change_set_name = "%s-%s-%d" % (input.stackname, mode, int(time.time()))
147
+ click.echo("Creating change set: %s" % change_set_name)
148
+ try:
149
+ change_set = client.create_change_set(
150
+ StackName=input.stackname,
151
+ TemplateURL=template_url,
152
+ Parameters=parameters,
153
+ Capabilities=capabilities,
154
+ Tags=(
155
+ [{"Key": key, "Value": value} for key, value in input.tags]
156
+ if input.tags
157
+ else []
158
+ ),
159
+ ChangeSetType=mode,
160
+ ChangeSetName=change_set_name,
161
+ )
162
+ except Exception as e:
163
+ print(f"Error: {e}")
164
+ _exec_change_set(client, change_set, mode, input.stackname)
165
+
166
+
167
+ @catch_boto_errors
168
+ def update_otel_log_ingestion_function(input):
169
+ assert isinstance(input, OtelIngestionUpdate)
170
+
171
+ client = input.session.client("cloudformation")
172
+
173
+ _create_otel_log_ingestion_function(
174
+ input,
175
+ nr_license_key=None,
176
+ mode="UPDATE",
177
+ )
178
+
179
+
180
+ @catch_boto_errors
181
+ def install_otel_log_ingestion(
182
+ input,
183
+ nr_license_key,
184
+ ):
185
+ """
186
+ Installs the New Relic AWS Lambda log ingestion function and role.
187
+
188
+ Returns True for success and False for failure.
189
+ """
190
+ assert isinstance(input, OtelIngestionInstall)
191
+ function = get_function(input.session, OTEL_INGEST_LAMBDA_NAME)
192
+ if function:
193
+ warning(
194
+ "It looks like an old log ingestion function is present in this region. "
195
+ "Consider manually deleting this as it is no longer used and "
196
+ "has been replaced by a log ingestion function specific to the stack."
197
+ )
198
+ stack_status = _check_for_ingest_stack(input.session, input.stackname)
199
+ if stack_status is None:
200
+ click.echo(
201
+ "Setting up CloudFormation Stack %s in region: %s"
202
+ % (input.stackname, input.session.region_name)
203
+ )
204
+ try:
205
+ _create_otel_log_ingestion_function(
206
+ input,
207
+ nr_license_key,
208
+ )
209
+ return True
210
+ except Exception as e:
211
+ failure(
212
+ "CloudFormation Stack %s exists (status: %s).\n"
213
+ "Please manually delete the stack and re-run this command."
214
+ % (input.stackname, stack_status)
215
+ )
216
+ return False
217
+ else:
218
+ function = get_newrelic_otel_log_ingestion_function(
219
+ input.session, input.stackname
220
+ )
221
+
222
+ if function is None:
223
+ failure(
224
+ "CloudFormation Stack %s exists (status: %s), but "
225
+ "%s Lambda function does not.\n"
226
+ "Please manually delete the stack and re-run this command."
227
+ % (input.stackname, stack_status, OTEL_INGEST_LAMBDA_NAME)
228
+ )
229
+ return False
230
+ else:
231
+ success(
232
+ "The CloudFormation Stack %s and "
233
+ "%s function already exists in region %s, "
234
+ "skipping"
235
+ % (input.stackname, OTEL_INGEST_LAMBDA_NAME, input.session.region_name)
236
+ )
237
+ return True
238
+
239
+
240
+ @catch_boto_errors
241
+ def update_otel_log_ingestion(input):
242
+ """
243
+ Updates the New Relic AWS Lambda log ingestion function and role.
244
+
245
+ Returns True for success and False for failure.
246
+ """
247
+ assert isinstance(input, OtelIngestionUpdate)
248
+
249
+ stack_status = _check_for_ingest_stack(input.session, input.stackname)
250
+ if stack_status is None:
251
+ failure(
252
+ "No '%s' stack in region '%s'. "
253
+ "This likely means the New Relic otel log ingestion function was "
254
+ "installed manually. "
255
+ "In order to install via the CLI, please delete this function and "
256
+ "run 'newrelic-lambda otel-ingestion install'."
257
+ % (OTEL_INGEST_STACK_NAME, input.session.region_name)
258
+ )
259
+ return False
260
+
261
+ function = get_newrelic_otel_log_ingestion_function(input.session, input.stackname)
262
+ if function is None:
263
+ failure(
264
+ "No %s function in region '%s'. "
265
+ "Run 'newrelic-lambda otel-ingestion install' to install it."
266
+ % (OTEL_INGEST_LAMBDA_NAME, input.session.region_name)
267
+ )
268
+ return False
269
+
270
+ try:
271
+ update_otel_log_ingestion_function(input)
272
+ except Exception as e:
273
+ failure("Failed to update newrelic-log-ingestion function: %s" % e)
274
+ return False
275
+ else:
276
+ return True
@@ -7,6 +7,7 @@ from newrelic_lambda_cli.cliutils import failure, success, warning
7
7
  from newrelic_lambda_cli.functions import get_function
8
8
  from newrelic_lambda_cli.integrations import get_unique_newrelic_log_ingestion_name
9
9
  from newrelic_lambda_cli.integrations import get_newrelic_log_ingestion_function
10
+ from newrelic_lambda_cli.otel_ingestions import get_newrelic_otel_log_ingestion_function
10
11
  from newrelic_lambda_cli.types import (
11
12
  LayerInstall,
12
13
  SubscriptionInstall,
@@ -48,12 +49,16 @@ def _get_subscription_filters(session, function_name):
48
49
 
49
50
 
50
51
  def _create_subscription_filter(
51
- session, function_name, destination_arn, filter_pattern
52
+ session,
53
+ function_name,
54
+ destination_arn,
55
+ filter_pattern,
56
+ filter_name="NewRelicLogStreaming",
52
57
  ):
53
58
  try:
54
59
  session.client("logs").put_subscription_filter(
55
60
  logGroupName=_get_log_group_name(function_name),
56
- filterName="NewRelicLogStreaming",
61
+ filterName=filter_name,
57
62
  filterPattern=filter_pattern,
58
63
  destinationArn=destination_arn,
59
64
  )
@@ -95,8 +100,8 @@ def create_log_subscription(input, function_name):
95
100
  destination = get_newrelic_log_ingestion_function(input.session, input.stackname)
96
101
  if destination is None:
97
102
  failure(
98
- "Could not find newrelic-log-ingestion function. Is the New Relic AWS "
99
- "integration installed?"
103
+ "Could not find newrelic-log-ingestion function in stack: %s. Is the New Relic AWS "
104
+ "integration installed?" % input.stackname
100
105
  )
101
106
  return False
102
107
  destination_arn = destination["Configuration"]["FunctionArn"]
@@ -137,6 +142,66 @@ def create_log_subscription(input, function_name):
137
142
  return True
138
143
 
139
144
 
145
+ @catch_boto_errors
146
+ def create_otel_log_subscription(input, function_name):
147
+ assert isinstance(input, SubscriptionInstall)
148
+
149
+ destination = get_newrelic_otel_log_ingestion_function(
150
+ input.session, input.stackname
151
+ )
152
+ if destination is None:
153
+ failure(
154
+ "Could not find newrelic-otel-log-ingestion function. Is the New Relic AWS "
155
+ "integration installed?"
156
+ )
157
+ return False
158
+ destination_arn = destination["Configuration"]["FunctionArn"]
159
+
160
+ subscription_filters = _get_subscription_filters(input.session, function_name)
161
+ if subscription_filters is None:
162
+ return False
163
+ newrelic_filters = [
164
+ filter
165
+ for filter in subscription_filters
166
+ if "NewRelicOtelLogStreaming" in filter["filterName"]
167
+ ]
168
+ if len(subscription_filters) > len(newrelic_filters):
169
+ warning(
170
+ "WARNING: Found otel log subscription filter that was not installed by New "
171
+ "Relic. This may prevent the New Relic log subscription filter from being "
172
+ "installed. If you know you don't need this log subscription filter, you "
173
+ "should first remove it and rerun this command. If your organization "
174
+ "requires this log subscription filter, please contact New Relic at "
175
+ "serverless@newrelic.com for assistance with getting the AWS log "
176
+ "subscription filter limit increased."
177
+ )
178
+ if not newrelic_filters:
179
+ click.echo("Adding New Relic otel log subscription to '%s'" % function_name)
180
+ return _create_subscription_filter(
181
+ input.session,
182
+ function_name,
183
+ destination_arn,
184
+ input.filter_pattern,
185
+ "NewRelicOtelLogStreaming",
186
+ )
187
+ else:
188
+ click.echo(
189
+ "Found log subscription for '%s', verifying configuration" % function_name
190
+ )
191
+ newrelic_filter = newrelic_filters[0]
192
+ if newrelic_filter["filterPattern"] != input.filter_pattern:
193
+ return _remove_subscription_filter(
194
+ input.session, function_name, newrelic_filter["filterName"]
195
+ ) and _create_subscription_filter(
196
+ input.session,
197
+ function_name,
198
+ destination_arn,
199
+ input.filter_pattern,
200
+ "NewRelicOtelLogStreaming",
201
+ )
202
+ return True
203
+
204
+
140
205
  @catch_boto_errors
141
206
  def remove_log_subscription(input, function_name):
142
207
  assert isinstance(input, (LayerInstall, SubscriptionUninstall))
@@ -158,3 +223,27 @@ def remove_log_subscription(input, function_name):
158
223
  return _remove_subscription_filter(
159
224
  input.session, function_name, newrelic_filter["filterName"]
160
225
  )
226
+
227
+
228
+ @catch_boto_errors
229
+ def remove_otel_log_subscription(input, function_name):
230
+ assert isinstance(input, (SubscriptionUninstall))
231
+ subscription_filters = _get_subscription_filters(input.session, function_name)
232
+ if subscription_filters is None:
233
+ return False
234
+ newrelic_filters = [
235
+ filter
236
+ for filter in subscription_filters
237
+ if "NewRelicOtelLogStreaming" in filter["filterName"]
238
+ ]
239
+ if not newrelic_filters:
240
+ click.echo(
241
+ "No New Relic otel subscription filters found for '%s', skipping"
242
+ % function_name
243
+ )
244
+ return True
245
+ newrelic_filter = newrelic_filters[0]
246
+ click.echo("Removing New Relic otel log subscription from '%s'" % function_name)
247
+ return _remove_subscription_filter(
248
+ input.session, function_name, newrelic_filter["filterName"]
249
+ )
@@ -49,6 +49,48 @@ INTEGRATION_UPDATE_KEYS = [
49
49
  "tags",
50
50
  ]
51
51
 
52
+ OTEL_INGESTION_INSTALL_KEYS = [
53
+ "session",
54
+ "verbose",
55
+ "aws_profile",
56
+ "aws_region",
57
+ "aws_permissions_check",
58
+ "aws_role_policy",
59
+ "stackname",
60
+ "memory_size",
61
+ "nr_account_id",
62
+ "nr_api_key",
63
+ "nr_region",
64
+ "timeout",
65
+ "role_name",
66
+ "tags",
67
+ ]
68
+
69
+ OTEL_INGESTION_UNINSTALL_KEYS = [
70
+ "session",
71
+ "aws_profile",
72
+ "aws_region",
73
+ "aws_permissions_check",
74
+ "stackname",
75
+ "nr_account_id",
76
+ "force",
77
+ ]
78
+
79
+ OTEL_INGESTION_UPDATE_KEYS = [
80
+ "session",
81
+ "aws_profile",
82
+ "aws_region",
83
+ "aws_permissions_check",
84
+ "stackname",
85
+ "memory_size",
86
+ "nr_account_id",
87
+ "nr_api_key",
88
+ "nr_region",
89
+ "timeout",
90
+ "role_name",
91
+ "tags",
92
+ ]
93
+
52
94
  LAYER_INSTALL_KEYS = [
53
95
  "session",
54
96
  "verbose",
@@ -86,6 +128,7 @@ SUBSCRIPTION_INSTALL_KEYS = [
86
128
  "stackname",
87
129
  "excludes",
88
130
  "filter_pattern",
131
+ "otel",
89
132
  ]
90
133
 
91
134
  SUBSCRIPTION_UNINSTALL_KEYS = [
@@ -94,8 +137,8 @@ SUBSCRIPTION_UNINSTALL_KEYS = [
94
137
  "aws_region",
95
138
  "aws_permissions_check",
96
139
  "functions",
97
- "stackname",
98
140
  "excludes",
141
+ "otel",
99
142
  ]
100
143
 
101
144
 
@@ -103,6 +146,13 @@ IntegrationInstall = namedtuple("IntegrationInstall", INTEGRATION_INSTALL_KEYS)
103
146
  IntegrationUninstall = namedtuple("IntegrationUninstall", INTEGRATION_UNINSTALL_KEYS)
104
147
  IntegrationUpdate = namedtuple("IntegrationUpdate", INTEGRATION_UPDATE_KEYS)
105
148
 
149
+ OtelIngestionInstall = namedtuple("OtelIngestionInstall", OTEL_INGESTION_INSTALL_KEYS)
150
+ OtelIngestionUninstall = namedtuple(
151
+ "OtelIngestionUninstall", OTEL_INGESTION_UNINSTALL_KEYS
152
+ )
153
+ OtelIngestionUpdate = namedtuple("OtelIngestionUpdate", OTEL_INGESTION_UPDATE_KEYS)
154
+
155
+
106
156
  LayerInstall = namedtuple("LayerInstall", LAYER_INSTALL_KEYS)
107
157
  LayerUninstall = namedtuple("LayerUninstall", LAYER_UNINSTALL_KEYS)
108
158
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: newrelic-lambda-cli
3
- Version: 0.9.2
3
+ Version: 0.9.4
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
@@ -8,12 +8,11 @@ Author-email: serverless-dev@newrelic.com
8
8
  Requires-Python: >=3.3
9
9
  Description-Content-Type: text/markdown
10
10
  License-File: LICENSE
11
- Requires-Dist: boto3 <5
12
- Requires-Dist: click >=7.1.2
11
+ Requires-Dist: boto3<5
12
+ Requires-Dist: click>=7.1.2
13
13
  Requires-Dist: colorama
14
- Requires-Dist: emoji <3,>=2
15
- Requires-Dist: gql <3,>=2
16
- Requires-Dist: requests <3
14
+ Requires-Dist: gql<3,>=2
15
+ Requires-Dist: requests<3
17
16
  Requires-Dist: tabulate
18
17
 
19
18
  [![Community Plus header](https://github.com/newrelic/opensource-website/raw/master/src/images/categories/Community_Plus.png)](https://opensource.newrelic.com/oss-category/#community-plus)
@@ -34,6 +33,9 @@ A CLI to install the New Relic AWS Lambda integration and layers.
34
33
  * [AWS Lambda Layers](#aws-lambda-layers)
35
34
  * [AWS Lambda Functions](#aws-lambda-functions)
36
35
  * [NewRelic Log Subscription](#newRelic-log-subscription)
36
+ * [NewRelic Otel Log Ingestions](#newRelic-otel-ingestions-install)
37
+ * [NewRelic Otel Log Subscription](#newRelic-otel-log-subscription)
38
+
37
39
  * **[Docker](#docker)**
38
40
  * **[Contributing](#contributing)**
39
41
  * **[Code Style](#code-style)**
@@ -63,6 +65,7 @@ A CLI to install the New Relic AWS Lambda integration and layers.
63
65
  * nodejs20.x
64
66
  * provided
65
67
  * provided.al2
68
+ * provided.al2023
66
69
  * python3.7
67
70
  * python3.8
68
71
  * python3.9
@@ -272,6 +275,72 @@ newrelic-lambda subscriptions uninstall --function <name or arn>
272
275
  | `--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. |
273
276
  | `--aws-region` or `-r` | No | The AWS region this function is located. Can use `AWS_DEFAULT_REGION` environment variable. Defaults to AWS session region. |
274
277
 
278
+ ### NewRelic Otel Ingestions Install
279
+
280
+ #### Install Otel Log Ingestion
281
+
282
+ ```bash
283
+ newrelic-lambda otel-ingestions install \
284
+ --nr-account-id <account id> \
285
+ --nr-api-key <api key>
286
+ ```
287
+
288
+ | Option | Required? | Description |
289
+ |--------|-----------|-------------|
290
+ | `--nr-account-id` or `-a` | Yes | The [New Relic Account ID](https://docs.newrelic.com/docs/accounts/install-new-relic/account-setup/account-id) for this integration. Can also use the `NEW_RELIC_ACCOUNT_ID` environment variable. |
291
+ | `--nr-api-key` or `-k` | Yes | Your [New Relic User API Key](https://docs.newrelic.com/docs/apis/get-started/intro-apis/types-new-relic-api-keys#user-api-key). Can also use the `NEW_RELIC_API_KEY` environment variable. |
292
+ | `--memory-size` or `-m` | No | Memory size (in MiB) for the New Relic log ingestion function. Default to 128MB. |
293
+ | `--nr-region` | No | The New Relic region to use for the integration. Can use the `NEW_RELIC_REGION` environment variable. Can be either `eu` or `us`. Defaults to `us`. |
294
+ | `--timeout` or `-t` | No | Timeout (in seconds) for the New Relic log ingestion function. Defaults to 30 seconds. |
295
+ | `--role-name` | No | Role name for the ingestion function. If you prefer to create and manage an IAM role for the function to assume out of band, do so and specify that role's name here. This avoids needing CAPABILITY_IAM. |
296
+ | `--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. |
297
+ | `--aws-region` or `-r` | No | The AWS region for the integration. Can use `AWS_DEFAULT_REGION` environment variable. Defaults to AWS session region. |
298
+ | `--aws-role-policy` | No | Specify an alternative IAM role policy ARN for this integration. |
299
+ | `--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`. |
300
+ | `--stackname` | No | The AWS Cloudformation stack name which contains the newrelic-aws-otel-log-ingestion lambda function. If no value is provided, the command searches for the NewRelicOtelLogIngestion stack |
301
+
302
+
303
+ #### Uninstall Otel Log Ingestion
304
+
305
+ ```bash
306
+ newrelic-lambda otel-ingestions uninstall
307
+ ```
308
+
309
+ | Option | Required? | Description |
310
+ |--------|-----------|-------------|
311
+ | `--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. |
312
+ | `--aws-region` or `-r` | No | The AWS region for the integration. Can use `AWS_DEFAULT_REGION` environment variable. Defaults to AWS session region. |
313
+ | `--force` or `-f` | No | Forces uninstall non-interactively |
314
+ | `--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. |
315
+ | `--stackname` | No | The AWS Cloudformation stack name which contains the newrelic-aws-otel-log-ingestion lambda function. If no value is provided, the command searches for the NewRelicOtelLogIngestion stack |
316
+
317
+ ### NewRelic Otel Log Subscription
318
+
319
+ #### Install Otel Log Subscription
320
+
321
+ ```bash
322
+ newrelic-lambda subscriptions install --function <name or arn> --otel
323
+ ```
324
+
325
+ | Option | Required? | Description |
326
+ |--------|-----------|-------------|
327
+ | `--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`. |
328
+ | `--otel` or `-o` | Yes | Use this flag to install subscription filters for Lambdas that are instrumented with OpenTelemetry (Otel) |
329
+ | `--stackname` | No | The AWS Cloudformation stack name which contains the newrelic-aws-otel-log-ingestion lambda function. If no value is provided, the command searches for the NewRelicOtelLogIngestion stack |
330
+
331
+
332
+ #### Uninstall Otel Log Subscription
333
+
334
+ ```bash
335
+ newrelic-lambda subscriptions uninstall --function <name or arn> --otel
336
+ ```
337
+
338
+ | Option | Required? | Description |
339
+ |--------|-----------|-------------|
340
+ | `--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`. |
341
+ | `--otel` or `-o` | Yes | Use this flag to install subscription filters for Lambdas that are instrumented with OpenTelemetry (Otel) |
342
+ | `--stackname` | No | The AWS Cloudformation stack name which contains the newrelic-aws-otel-log-ingestion lambda function. If no value is provided, the command searches for the NewRelicOtelLogIngestion stack |
343
+
275
344
  ## Docker
276
345
 
277
346
  Now, you can run newrelic-lambda-cli as a container.
@@ -307,7 +376,7 @@ Using these together will auto format your git commits.
307
376
  ## Running Tests
308
377
 
309
378
  ```bash
310
- python setup.py test
379
+ pytest tests
311
380
  ```
312
381
 
313
382
  ## Troubleshooting
@@ -1,25 +1,27 @@
1
1
  newrelic_lambda_cli/__init__.py,sha256=u4cy7hwbrNjK3xtldGQD_51aoNgSqGQ3IzFYsuvaIM4,149
2
- newrelic_lambda_cli/api.py,sha256=tkjuR_qkD2uZgXfXPFR6YKnmRiNYkrEmqQEeUgDtNn8,14848
3
- newrelic_lambda_cli/cliutils.py,sha256=x2pWlL3DJ9t98QNElp_rhawNQoIZ0vd55R2jpo3_oI0,902
2
+ newrelic_lambda_cli/api.py,sha256=b75XwylRhW9pcA6aZ9EjBW1yIFOGHhhULDD5hNhMyes,15065
3
+ newrelic_lambda_cli/cliutils.py,sha256=XDtvTlgbf2uVg01yCJrfJmmgxbF0nIL9x58ETyvefk8,685
4
4
  newrelic_lambda_cli/functions.py,sha256=p57ZUw424BaSUA_Gw8DrYsJOYKROEHEaXgARadqwcP0,2800
5
- newrelic_lambda_cli/integrations.py,sha256=X9OuBK_sNfjb1cjbZ1dctd_YTVyEeCCGsPaJp0Bni1U,30864
5
+ newrelic_lambda_cli/integrations.py,sha256=r0gxfEqVHTGu3xbr4dOCDwm0-Yhoz3KntfeQRWvoWrQ,31266
6
6
  newrelic_lambda_cli/layers.py,sha256=7ntl48RVEoRO4iiD3yzsxgqNkx013vXO5wQuoP6M0-I,14805
7
+ newrelic_lambda_cli/otel_ingestions.py,sha256=vi1Mlfc9nRvRWV7STwK7fDXZGozG8ufKohmpHcaWGic,9250
7
8
  newrelic_lambda_cli/permissions.py,sha256=H7v5IMpKaJIWC4Dff2YcTis4BKAAFIJr9IHWUj1LnF4,9093
8
- newrelic_lambda_cli/subscriptions.py,sha256=wh6vroU8RfSEwqAMObjPNVPb0TbBxUYYPO_c3mY7miA,6166
9
- newrelic_lambda_cli/types.py,sha256=kzubT5cGiI-k6h_8b_iTaj3bnsNwolhjgSbpFJT9iBk,2304
9
+ newrelic_lambda_cli/subscriptions.py,sha256=-BYkltqiDLdmhUB_Ot4w-5vvrKcQC6aHcTBLl1mlUlI,9564
10
+ newrelic_lambda_cli/types.py,sha256=z4K_ALDhF-iOKpyQUekbzETa586mr9bMpK9RCuffVQ8,3293
10
11
  newrelic_lambda_cli/utils.py,sha256=dYcSFZj7Mpgr5f8YSaAjt80N1q9akcOj1_puL8iRHak,5324
11
- newrelic_lambda_cli/cli/__init__.py,sha256=n_QPd3oJqkFxryy-pJ-Y_AsqsmgbTb3dlQCjPJueaYQ,544
12
+ newrelic_lambda_cli/cli/__init__.py,sha256=FciF2RVqQbpMKqEiN8qjO6qmdLB6Yv8LyyyPYcfJNrc,622
12
13
  newrelic_lambda_cli/cli/decorators.py,sha256=a3agkVfy8omkUSL4aKblwSX95xtxYOGASULDYcJDPHk,1786
13
14
  newrelic_lambda_cli/cli/functions.py,sha256=RSh2Cowe1_oQup8q5YRidp03z-BITo2uzvDh4zvLr4I,2601
14
15
  newrelic_lambda_cli/cli/integrations.py,sha256=aQAWcCCU2kBmbF8fLKwKB9bzSY0uipvnojajjTkhqEs,10461
15
16
  newrelic_lambda_cli/cli/layers.py,sha256=3CTukG79vM2Gzx3NFXsqUEjy5mNQ4rawIh53oQeCyCI,6180
16
- newrelic_lambda_cli/cli/subscriptions.py,sha256=fmFkGq8AGExOaHzQxMhYfOCmpxhnCwUWbeJUOuTWi60,4545
17
+ newrelic_lambda_cli/cli/otel_ingestions.py,sha256=4rTm9iYUo2qdMeqxJSrYLCA6ZXHy5bJnjDn9x54pCYc,6096
18
+ newrelic_lambda_cli/cli/subscriptions.py,sha256=bUupv5iv3mUkC8t31nnI3BahoKxDnUJ8Rgq4QHJcFNU,5890
17
19
  newrelic_lambda_cli/templates/import-template.yaml,sha256=0r1yeoqpnqtEMggWomALkPG10NiANPWWBqz03rChch8,3771
18
20
  newrelic_lambda_cli/templates/license-key-secret.yaml,sha256=ZldQaLXsyF1K2I4X_AsLdH7kRmLkPUYI3talmhqQyHg,1849
19
21
  newrelic_lambda_cli/templates/nr-lambda-integration-role.yaml,sha256=s7T73B_k-mAwgzJrD2xn8YGUNgn2E1V7Exifrl81ViU,2874
20
- newrelic_lambda_cli-0.9.2.dist-info/LICENSE,sha256=uuxDzQm0yfq_tNZX0tQYzsZUVRIF0jm3dBLZUojSYzI,11345
21
- newrelic_lambda_cli-0.9.2.dist-info/METADATA,sha256=jkaZoQkVvvW6PWth1X6xRGrjMNUjK0VvH1IDU2hyBwI,21723
22
- newrelic_lambda_cli-0.9.2.dist-info/WHEEL,sha256=DZajD4pwLWue70CAfc7YaxT1wLUciNBvN_TTcvXpltE,110
23
- newrelic_lambda_cli-0.9.2.dist-info/entry_points.txt,sha256=iks2k9Y4WNgIecsDzreIvMV9pGCjwwKTf33LKKvl2A8,65
24
- newrelic_lambda_cli-0.9.2.dist-info/top_level.txt,sha256=dxX2w58VgSUFiPD8C_lFuY-T2C1kjfeY0xi8iTh0r44,20
25
- newrelic_lambda_cli-0.9.2.dist-info/RECORD,,
22
+ newrelic_lambda_cli-0.9.4.dist-info/LICENSE,sha256=uuxDzQm0yfq_tNZX0tQYzsZUVRIF0jm3dBLZUojSYzI,11345
23
+ newrelic_lambda_cli-0.9.4.dist-info/METADATA,sha256=K1KLdhwr6VrkOIyaGBIoJkNcwKV4QSkXj-fbRYx8EvI,26780
24
+ newrelic_lambda_cli-0.9.4.dist-info/WHEEL,sha256=AHX6tWk3qWuce7vKLrj7lnulVHEdWoltgauo8bgCXgU,109
25
+ newrelic_lambda_cli-0.9.4.dist-info/entry_points.txt,sha256=iks2k9Y4WNgIecsDzreIvMV9pGCjwwKTf33LKKvl2A8,65
26
+ newrelic_lambda_cli-0.9.4.dist-info/top_level.txt,sha256=dxX2w58VgSUFiPD8C_lFuY-T2C1kjfeY0xi8iTh0r44,20
27
+ newrelic_lambda_cli-0.9.4.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.43.0)
2
+ Generator: setuptools (75.1.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py2-none-any
5
5
  Tag: py3-none-any