Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 16 additions & 7 deletions powertools-batch/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -50,19 +50,23 @@
<artifactId>powertools-serialization</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>software.amazon.lambda</groupId>
<artifactId>powertools-common</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>sdk-core</artifactId>
<scope>provided</scope>
</dependency>

<!-- Test dependencies -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>2.0.17</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
Expand All @@ -83,6 +87,11 @@
<artifactId>slf4j-simple</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>s3</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

</project>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright 2023 Amazon.com, Inc. or its affiliates.
* Licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package software.amazon.lambda.powertools.batch.internal;

import software.amazon.awssdk.core.SdkRequest;
import software.amazon.awssdk.core.interceptor.Context;
import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
import software.amazon.awssdk.core.interceptor.ExecutionInterceptor;
import software.amazon.lambda.powertools.common.internal.UserAgentConfigurator;

/**
* Global interceptor that configures the User-Agent for all AWS SDK clients
* when the powertools-batch module is on the classpath.
*/
public final class BatchUserAgentInterceptor implements ExecutionInterceptor {
static {
UserAgentConfigurator.configureUserAgent("batch");
}

@Override
public SdkRequest modifyRequest(Context.ModifyRequest context, ExecutionAttributes executionAttributes) {
// This is a no-op interceptor. We use this class to configure the PT User-Agent in the static block. It is
// loaded by AWS SDK Global Interceptors.
return context.request();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
software.amazon.lambda.powertools.batch.internal.BatchUserAgentInterceptor
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright 2023 Amazon.com, Inc. or its affiliates.
* Licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package software.amazon.lambda.powertools.batch.internal;

import org.junit.jupiter.api.Test;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;

import static org.assertj.core.api.Assertions.assertThat;

class BatchUserAgentInterceptorTest {

@Test
void shouldConfigureUserAgentWhenCreatingAwsSdkClient() {
// WHEN creating an AWS SDK client, the interceptor should be loaded
// We use S3 client but it can be any arbitrary AWS SDK client
S3Client.builder().region(Region.US_EAST_1).build();

// THEN the user agent system property should be set
String userAgent = System.getProperty("sdk.ua.appId");
assertThat(userAgent).contains("PT/BATCH/");
}
}
14 changes: 14 additions & 0 deletions powertools-cloudformation/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@
<groupId>software.amazon.awssdk</groupId>
<artifactId>url-connection-client</artifactId>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>sdk-core</artifactId>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-lambda-java-core</artifactId>
Expand All @@ -58,6 +62,11 @@
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
</dependency>
<dependency>
<groupId>software.amazon.lambda</groupId>
<artifactId>powertools-common</artifactId>
<version>${project.version}</version>
</dependency>

<!-- Test dependencies -->
<dependency>
Expand Down Expand Up @@ -102,6 +111,11 @@
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>s3</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<profiles>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright 2023 Amazon.com, Inc. or its affiliates.
* Licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package software.amazon.lambda.powertools.cloudformation.internal;

import software.amazon.awssdk.core.SdkRequest;
import software.amazon.awssdk.core.interceptor.Context;
import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
import software.amazon.awssdk.core.interceptor.ExecutionInterceptor;
import software.amazon.lambda.powertools.common.internal.UserAgentConfigurator;

/**
* Global interceptor that configures the User-Agent for all AWS SDK clients
* when the powertools-cloudformation module is on the classpath.
*/
public final class CloudformationUserAgentInterceptor implements ExecutionInterceptor {
static {
UserAgentConfigurator.configureUserAgent("cloudformation");
}

@Override
public SdkRequest modifyRequest(Context.ModifyRequest context, ExecutionAttributes executionAttributes) {
// This is a no-op interceptor. We use this class to configure the PT User-Agent in the static block. It is
// loaded by AWS SDK Global Interceptors.
return context.request();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -428,5 +428,9 @@
{
"name":"sun.security.x509.SubjectKeyIdentifierExtension",
"methods":[{"name":"<init>","parameterTypes":["java.lang.Boolean","java.lang.Object"] }]
},
{
"name":"software.amazon.lambda.powertools.cloudformation.internal.CloudformationUserAgentInterceptor",
"methods":[{"name":"<init>","parameterTypes":[] }]
}
]
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
"pattern":"\\Qorg/eclipse/jetty/version/build.properties\\E"
}, {
"pattern":"\\Qorg/publicsuffix/list/effective_tld_names.dat\\E"
}, {
"pattern":"\\Qsoftware/amazon/awssdk/global/handlers/execution.interceptors\\E"
}]},
"bundles":[{
"name":"jakarta.servlet.LocalStrings",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
software.amazon.lambda.powertools.cloudformation.internal.CloudformationUserAgentInterceptor
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* Copyright 2023 Amazon.com, Inc. or its affiliates.
* Licensed under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package software.amazon.lambda.powertools.cloudformation.internal;

import org.junit.jupiter.api.Test;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;

import static org.assertj.core.api.Assertions.assertThat;

class CloudformationUserAgentInterceptorTest {

@Test
void shouldConfigureUserAgentWhenCreatingAwsSdkClient() {
// WHEN creating an AWS SDK client, the interceptor should be loaded
// We use S3 client but it can be any arbitrary AWS SDK client
S3Client.builder().region(Region.US_EAST_1).build();

// THEN the user agent system property should be set
String userAgent = System.getProperty("sdk.ua.appId");
assertThat(userAgent).contains("PT/CLOUDFORMATION/");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,26 +18,27 @@

import java.io.IOException;
import java.io.InputStream;
import java.util.Locale;
import java.util.Properties;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
* Can be used to create a string that can server as a User-Agent suffix in requests made with the AWS SDK clients
*/
public class UserAgentConfigurator {

public final class UserAgentConfigurator {
public static final String NA = "NA";
public static final String VERSION_KEY = "powertools.version";
public static final String PT_FEATURE_VARIABLE = "${PT_FEATURE}";
public static final String PT_EXEC_ENV_VARIABLE = "${PT_EXEC_ENV}";
public static final String VERSION_PROPERTIES_FILENAME = "version.properties";
public static final String AWS_EXECUTION_ENV = "AWS_EXECUTION_ENV";
private static final String SDK_USER_AGENT_APP_ID = "sdk.ua.appId";
private static final Logger LOG = LoggerFactory.getLogger(UserAgentConfigurator.class);
private static final String NO_OP = "no-op";
private static final String POWERTOOLS_VERSION = getProjectVersion();
private static final String USER_AGENT_PATTERN = "PT/" + PT_FEATURE_VARIABLE + "/" + POWERTOOLS_VERSION + " PTEnv/"
private static final String USER_AGENT_PATTERN = "PT/" + PT_FEATURE_VARIABLE + "/" + POWERTOOLS_VERSION + " PTENV/"
+ PT_EXEC_ENV_VARIABLE;

private UserAgentConfigurator() {
Expand All @@ -53,7 +54,6 @@ static String getProjectVersion() {
return getVersionFromProperties(VERSION_PROPERTIES_FILENAME, VERSION_KEY);
}


/**
* Retrieves the project version from a properties file.
* The file should be in the resources folder.
Expand All @@ -64,28 +64,46 @@ static String getProjectVersion() {
* @return the version of the project as configured in the given properties file
*/
static String getVersionFromProperties(String propertyFileName, String versionKey) {

InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(propertyFileName);

if (is != null) {
try {
try (InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(propertyFileName)) {
if (is != null) {
Properties properties = new Properties();
properties.load(is);
String version = properties.getProperty(versionKey);
if (version != null && !version.isEmpty()) {
return version;
}
} catch (IOException e) {
LOG.warn("Unable to read {} file. Using default version.", propertyFileName);
LOG.debug("Exception:", e);
}
} catch (IOException e) {
LOG.warn("Unable to read {} file. Using default version.", propertyFileName);
LOG.debug("Exception:", e);
}
return NA;
}

/**
* Configures the AWS SDK to use Powertools user agent by setting the sdk.ua.appId system property.
* If the property is already set and not empty, appends the Powertools user agent with a "/" separator.
* This should be called during library initialization to ensure the user agent is properly configured.
*/
public static void configureUserAgent(String ptFeature) {
try {
String existingValue = System.getProperty(SDK_USER_AGENT_APP_ID);
String powertoolsUserAgent = getUserAgent(ptFeature);

if (existingValue != null && !existingValue.isEmpty()) {
System.setProperty(SDK_USER_AGENT_APP_ID, existingValue + "/" + powertoolsUserAgent);
} else {
System.setProperty(SDK_USER_AGENT_APP_ID, powertoolsUserAgent);
}
} catch (Exception e) {
// We don't re-raise since we don't want to break the user if something in this logic doesn't work
LOG.warn("Unable to configure user agent system property", e);
}
}

/**
* Retrieves the user agent string for the Powertools for AWS Lambda.
* It follows the pattern PT/{PT_FEATURE}/{PT_VERSION} PTEnv/{PT_EXEC_ENV}
* It follows the pattern PT/{PT_FEATURE}/{PT_VERSION} PTENV/{PT_EXEC_ENV}
* The version of the project is automatically retrieved.
* The PT_EXEC_ENV is automatically retrieved from the AWS_EXECUTION_ENV environment variable.
* If it AWS_EXECUTION_ENV is not set, PT_EXEC_ENV defaults to "NA"
Expand All @@ -96,7 +114,6 @@ static String getVersionFromProperties(String propertyFileName, String versionKe
* @return the user agent string
*/
public static String getUserAgent(String ptFeature) {

String awsExecutionEnv = getenv(AWS_EXECUTION_ENV);
String ptExecEnv = awsExecutionEnv != null ? awsExecutionEnv : NA;
String userAgent = USER_AGENT_PATTERN.replace(PT_EXEC_ENV_VARIABLE, ptExecEnv);
Expand All @@ -105,7 +122,7 @@ public static String getUserAgent(String ptFeature) {
ptFeature = NO_OP;
}
return userAgent
.replace(PT_FEATURE_VARIABLE, ptFeature)
.replace(PT_FEATURE_VARIABLE, ptFeature.toUpperCase(Locale.ROOT))
.replace(PT_EXEC_ENV_VARIABLE, ptExecEnv);
}
}
Loading
Loading