Skip to content

Commit 62e9dbd

Browse files
committed
aws-lambda: changing ARN assembly to accept different types of function references
1 parent fc8cf8f commit 62e9dbd

File tree

9 files changed

+360
-426
lines changed

9 files changed

+360
-426
lines changed

instrumentation/aws-java-sdk-lambda-1.11.280/src/main/java/com/agent/instrumentation/awsjavasdk1/services/lambda/LambdaUtil.java

Lines changed: 43 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,26 @@
1010
import com.newrelic.agent.bridge.AgentBridge;
1111
import com.newrelic.api.agent.CloudAccountInfo;
1212
import com.newrelic.api.agent.CloudParameters;
13+
import com.newrelic.api.agent.NewRelic;
1314

1415
import java.util.function.Function;
16+
import java.util.logging.Level;
17+
import java.util.regex.Matcher;
18+
import java.util.regex.Pattern;
1519

1620
public class LambdaUtil {
1721

1822
private static final String PLATFORM = "aws_lambda";
1923
private static final String NULL_ARN = "";
24+
private static final FunctionProcessedData NULL_DATA = new FunctionProcessedData(NULL_ARN, NULL_ARN);
2025
private static final String PREFIX = "arn:aws:lambda:";
26+
private static final Pattern FUNC_REF_PATTERN = Pattern.compile(
27+
"(arn:(aws[a-zA-Z-]*)?:lambda:)?" + // arn prefix
28+
"((?<region>[a-z]{2}((-gov)|(-iso([a-z]?)))?-[a-z]+-\\d{1}):)?" + // region
29+
"((?<accountId>\\d{12}):)?" + // account id
30+
"(function:)?" + // constant
31+
"(?<functionName>[a-zA-Z0-9-\\.]+)" + // function name (only required part)
32+
"(:(?<qualifier>\\$LATEST|[a-zA-Z0-9-]+))?"); // qualifier: version or alias
2133
private static final Function<FunctionRawData, FunctionProcessedData> CACHE =
2234
AgentBridge.collectionFactory.createAccessTimeBasedCache(3600, 8, LambdaUtil::processData);
2335

@@ -53,66 +65,47 @@ public static CloudParameters getCloudParameters(FunctionRawData functionRawData
5365
*/
5466
// Visible for testing
5567
static FunctionProcessedData processData(FunctionRawData data) {
56-
String functionRef = data.getFunctionRef();
57-
58-
String[] parts = functionRef.split(":");
59-
60-
String functionName = NULL_ARN;
6168
String arn = NULL_ARN;
6269

63-
if (parts.length == 1) {
64-
// function name: {function-name}
65-
String accountId = getAccountId(data.getSdkClient());
66-
if (accountId != null) {
67-
String qualifier = data.getQualifier();
68-
if (qualifier == null) {
69-
arn = PREFIX + data.getRegion() + ":" + accountId + ":function:" + functionRef;
70-
} else {
71-
arn = PREFIX + data.getRegion() + ":" + accountId + ":function:" + functionRef + ":" + qualifier;
72-
}
73-
}
74-
functionName = functionRef;
70+
String functionRef = data.getFunctionRef();
71+
Matcher matcher = FUNC_REF_PATTERN.matcher(functionRef);
72+
if (!matcher.matches()) {
73+
return NULL_DATA;
74+
}
75+
String region = matcher.group("region");
76+
String accountId = matcher.group("accountId");
77+
String qualifier = matcher.group("qualifier");
78+
String functionName = matcher.group("functionName");
79+
80+
if (functionName == null) {
81+
// will not be able to add any data
82+
NewRelic.getAgent().getLogger().log(Level.INFO, "aws-lambda: Unable to assemble ARN: " + functionRef);
83+
return NULL_DATA;
84+
}
7585

76-
} else if (parts.length == 2) {
77-
// function name + qualifier: {function-name}:{qualifier}
78-
String accountId = getAccountId(data.getSdkClient());
79-
if (accountId != null) {
80-
arn = PREFIX + data.getRegion() + ":" + accountId + ":function:" + functionRef;
81-
}
82-
functionName = parts[0];
86+
if (region == null) {
87+
// if region is not provided, we will try to get it from the SDK client
88+
region = data.getRegion();
89+
}
90+
91+
if (accountId == null) {
92+
// if account id is not provided, we will try to get it from the config
93+
accountId = getAccountId(data.getSdkClient());
94+
}
8395

84-
} else if (parts.length == 3) {
85-
// partial ARN: {account-id}:function:{function-name}
86-
functionName = parts[2];
87-
String qualifier = data.getQualifier();
96+
if (region != null && accountId != null) {
8897
if (qualifier == null) {
89-
arn = PREFIX + data.getRegion() + ":" + functionRef;
90-
} else {
91-
arn = PREFIX + data.getRegion() + ":" + functionRef + ":" + qualifier;
98+
qualifier = data.getQualifier();
9299
}
93100

94-
} else if (parts.length == 4) {
95-
// partial ARN with qualifier: {account-id}:function:{function-name}:{qualifier}
96-
functionName = parts[2];
97-
arn = PREFIX + data.getRegion() + ":" + functionRef;
98-
99-
} else if (parts.length == 7) {
100-
// full ARN: arn:aws:lambda:{region}:{account-id}:function:{function-name}
101-
functionName = parts[6];
102-
String qualifier = data.getQualifier();
103-
if (qualifier == null) {
104-
arn = functionRef;
101+
if (qualifier == null || qualifier.isEmpty() || "$LATEST".equals(qualifier)) {
102+
arn = PREFIX + region + ":" + accountId + ":function:" + functionName;
105103
} else {
106-
arn = functionRef + ":" + qualifier;
104+
arn = PREFIX + region + ":" + accountId + ":function:" + functionName + ":" + qualifier;
107105
}
108-
109-
} else if (parts.length == 8) {
110-
// full ARN with qualifier: arn:aws:lambda:{region}:{account-id}:function:{function-name}:{qualifier}
111-
functionName = parts[6];
112-
arn = functionRef;
106+
} else {
107+
NewRelic.getAgent().getLogger().log(Level.INFO, "aws-lambda: Missing information to assemble ARN.");
113108
}
114-
// reference should be invalid if the number of parts do not match any of the expected cases
115-
116109
return new FunctionProcessedData(functionName, arn);
117110
}
118111

instrumentation/aws-java-sdk-lambda-1.11.280/src/main/java/com/amazonaws/services/lambda/AWSLambdaAsyncClient_Instrumentation.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ public abstract class AWSLambdaAsyncClient_Instrumentation {
2727
protected abstract String getSigningRegion();
2828

2929
public Future<InvokeResult> invokeAsync(final InvokeRequest request, AsyncHandler<InvokeRequest, InvokeResult> asyncHandler) {
30-
FunctionRawData functionRawData = new FunctionRawData(request.getFunctionName(), request.getQualifier(), getSigningRegion(), this);
30+
FunctionRawData functionRawData = new FunctionRawData(request.getFunctionName(), request.getQualifier(), this.getSigningRegion(), this);
3131
CloudParameters cloudParameters = LambdaUtil.getCloudParameters(functionRawData);
3232
String functionName = LambdaUtil.getSimpleFunctionName(functionRawData);
3333
Segment segment = NewRelic.getAgent().getTransaction().startSegment("Lambda", "invoke/" + functionName);

instrumentation/aws-java-sdk-lambda-1.11.280/src/main/java/com/amazonaws/services/lambda/AWSLambdaClient_Instrumentation.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public abstract class AWSLambdaClient_Instrumentation {
2626

2727
@Trace(leaf = true)
2828
public InvokeResult invoke(InvokeRequest invokeRequest) {
29-
FunctionRawData functionRawData = new FunctionRawData(invokeRequest.getFunctionName(), invokeRequest.getQualifier(), getSigningRegion(), this);
29+
FunctionRawData functionRawData = new FunctionRawData(invokeRequest.getFunctionName(), invokeRequest.getQualifier(), this.getSigningRegion(), this);
3030
CloudParameters cloudParameters = LambdaUtil.getCloudParameters(functionRawData);
3131
TracedMethod tracedMethod = NewRelic.getAgent().getTracedMethod();
3232
tracedMethod.reportAsExternal(cloudParameters);

instrumentation/aws-java-sdk-lambda-1.11.280/src/test/java/com/agent/instrumentation/awsjavasdk1/services/lambda/LambdaUtilTest.java

Lines changed: 0 additions & 157 deletions
Original file line numberDiff line numberDiff line change
@@ -64,163 +64,6 @@ public void testGetCloudParamArnQualifier() {
6464
assertEquals("arn:aws:lambda:us-east-1:123456789012:function:my-function:alias", cloudParameters.getResourceId());
6565
}
6666

67-
@Test
68-
public void testGetArnFunctionName() {
69-
FunctionProcessedData data = LambdaUtil.processData(data("my-function", null));
70-
assertEquals("", data.getArn());
71-
assertEquals("my-function", data.getFunctionName());
72-
}
73-
74-
@Test
75-
public void testGetArnFunctionNameClient() {
76-
mockCloudApiClient();
77-
FunctionProcessedData data = LambdaUtil.processData(data("my-function", null));
78-
assertEquals("arn:aws:lambda:us-east-1:123456789012:function:my-function", data.getArn());
79-
assertEquals("my-function", data.getFunctionName());
80-
}
81-
82-
@Test
83-
public void testGetArnFunctionNameWithAlias() {
84-
FunctionProcessedData data = LambdaUtil.processData(data("my-function:alias", null));
85-
assertEquals("", data.getArn());
86-
assertEquals("my-function", data.getFunctionName());
87-
}
88-
89-
@Test
90-
public void testGetArnFunctionNameWithAliasClient() {
91-
mockCloudApiClient();
92-
FunctionProcessedData data = LambdaUtil.processData(data("my-function:alias", null));
93-
assertEquals("arn:aws:lambda:us-east-1:123456789012:function:my-function:alias", data.getArn());
94-
assertEquals("my-function", data.getFunctionName());
95-
}
96-
97-
@Test
98-
public void testGetArnFunctionNameWithVersion() {
99-
FunctionProcessedData data = LambdaUtil.processData(data("my-function:123", null));
100-
assertEquals("", data.getArn());
101-
assertEquals("my-function", data.getFunctionName());
102-
}
103-
104-
@Test
105-
public void testGetArnFunctionNameWithVersionClient() {
106-
mockCloudApiClient();
107-
FunctionProcessedData data = LambdaUtil.processData(data("my-function:123", null));
108-
assertEquals("arn:aws:lambda:us-east-1:123456789012:function:my-function:123", data.getArn());
109-
assertEquals("my-function", data.getFunctionName());
110-
}
111-
112-
@Test
113-
public void testGetArnFunctionNameAndAliasQualifier() {
114-
FunctionProcessedData data = LambdaUtil.processData(data("my-function", "alias"));
115-
assertEquals("", data.getArn());
116-
assertEquals("my-function", data.getFunctionName());
117-
}
118-
119-
@Test
120-
public void testGetArnFunctionNameAndAliasQualifierClient() {
121-
mockCloudApiClient();
122-
FunctionProcessedData data = LambdaUtil.processData(data("my-function", "alias"));
123-
assertEquals("arn:aws:lambda:us-east-1:123456789012:function:my-function:alias", data.getArn());
124-
assertEquals("my-function", data.getFunctionName());
125-
}
126-
127-
@Test
128-
public void testGetArnFunctionNameAndVersionQualifier() {
129-
FunctionProcessedData data = LambdaUtil.processData(data("my-function", "123"));
130-
assertEquals("", data.getArn());
131-
assertEquals("my-function", data.getFunctionName());
132-
}
133-
134-
@Test
135-
public void testGetArnFunctionNameAndVersionQualifierClient() {
136-
mockCloudApiClient();
137-
FunctionProcessedData data = LambdaUtil.processData(data("my-function", "123"));
138-
assertEquals("arn:aws:lambda:us-east-1:123456789012:function:my-function:123", data.getArn());
139-
assertEquals("my-function", data.getFunctionName());
140-
}
141-
142-
@Test
143-
public void testGetArnPartialArn() {
144-
FunctionProcessedData data = LambdaUtil.processData(data("123456789012:function:my-function", null));
145-
assertEquals("arn:aws:lambda:us-east-1:123456789012:function:my-function", data.getArn());
146-
assertEquals("my-function", data.getFunctionName());
147-
}
148-
149-
@Test
150-
public void testGetArnPartialArnWithAlias() {
151-
FunctionProcessedData data = LambdaUtil.processData(data("123456789012:function:my-function:alias", null));
152-
assertEquals("arn:aws:lambda:us-east-1:123456789012:function:my-function:alias", data.getArn());
153-
assertEquals("my-function", data.getFunctionName());
154-
}
155-
156-
@Test
157-
public void testGetArnPartialArnWithVersion() {
158-
FunctionProcessedData data = LambdaUtil.processData(data("123456789012:function:my-function:123", null));
159-
assertEquals("arn:aws:lambda:us-east-1:123456789012:function:my-function:123", data.getArn());
160-
assertEquals("my-function", data.getFunctionName());
161-
}
162-
163-
@Test
164-
public void testGetArnPartialArnAndAliasQualifier() {
165-
FunctionProcessedData data = LambdaUtil.processData(data("123456789012:function:my-function", "alias"));
166-
assertEquals("arn:aws:lambda:us-east-1:123456789012:function:my-function:alias", data.getArn());
167-
assertEquals("my-function", data.getFunctionName());
168-
}
169-
170-
@Test
171-
public void testGetArnPartialArnAndVersionQualifier() {
172-
FunctionProcessedData data = LambdaUtil.processData(data("123456789012:function:my-function", "123"));
173-
assertEquals("arn:aws:lambda:us-east-1:123456789012:function:my-function:123", data.getArn());
174-
assertEquals("my-function", data.getFunctionName());
175-
}
176-
177-
@Test
178-
public void testGetArnFullArn() {
179-
FunctionProcessedData data = LambdaUtil.processData(data("arn:aws:lambda:us-east-1:123456789012:function:my-function", null));
180-
assertEquals("arn:aws:lambda:us-east-1:123456789012:function:my-function", data.getArn());
181-
assertEquals("my-function", data.getFunctionName());
182-
}
183-
184-
@Test
185-
public void testGetArnFullArnWithAlias() {
186-
FunctionProcessedData data = LambdaUtil.processData(data("arn:aws:lambda:us-east-1:123456789012:function:my-function:alias", null));
187-
assertEquals("arn:aws:lambda:us-east-1:123456789012:function:my-function:alias", data.getArn());
188-
assertEquals("my-function", data.getFunctionName());
189-
}
190-
191-
@Test
192-
public void testGetArnFullArnWithVersion() {
193-
FunctionProcessedData data = LambdaUtil.processData(data("arn:aws:lambda:us-east-1:123456789012:function:my-function:123", null));
194-
assertEquals("arn:aws:lambda:us-east-1:123456789012:function:my-function:123", data.getArn());
195-
assertEquals("my-function", data.getFunctionName());
196-
}
197-
198-
@Test
199-
public void testGetArnFullArnAndAliasQualifier() {
200-
FunctionProcessedData data = LambdaUtil.processData(data("arn:aws:lambda:us-east-1:123456789012:function:my-function", "alias"));
201-
assertEquals("arn:aws:lambda:us-east-1:123456789012:function:my-function:alias", data.getArn());
202-
assertEquals("my-function", data.getFunctionName());
203-
}
204-
205-
@Test
206-
public void testGetArnFullArnAndVersionQualifier() {
207-
FunctionProcessedData data = LambdaUtil.processData(data("arn:aws:lambda:us-east-1:123456789012:function:my-function", "123"));
208-
assertEquals("arn:aws:lambda:us-east-1:123456789012:function:my-function:123", data.getArn());
209-
assertEquals("my-function", data.getFunctionName());
210-
}
211-
212-
@Test
213-
public void testGetArnDifferentRegion() {
214-
FunctionProcessedData data = LambdaUtil.processData(data("arn:aws:lambda:us-west-2:123456789012:function:my-function", null));
215-
assertEquals("arn:aws:lambda:us-west-2:123456789012:function:my-function", data.getArn());
216-
assertEquals("my-function", data.getFunctionName());
217-
}
218-
219-
private static void mockCloudApiClient() {
220-
when(AgentBridge.cloud.getAccountInfo(any(), eq(CloudAccountInfo.AWS_ACCOUNT_ID)))
221-
.thenReturn("123456789012");
222-
}
223-
22467
private FunctionRawData data(String functionRef, String qualifier) {
22568
return new FunctionRawData(functionRef, qualifier, Regions.US_EAST_1.getName(), this);
22669
}

0 commit comments

Comments
 (0)