diff --git a/README.md b/README.md index bb19aa2..d7b3fa1 100644 --- a/README.md +++ b/README.md @@ -156,4 +156,12 @@ When you installed `awsmeter` using **jmeter-plugins** and executed JMeter with ![Screenshot](https://raw.githubusercontent.com/JoseLuisSR/awsmeter/main/doc/img/awsmeter-compiled-issue.png) -To fix it, please install Java 11 and execute JMeter with this version or install `awsmeter` following the steps described in the [Install](https://github.com/JoseLuisSR/awsmeter#install) section and execute JMeter with th version of Java you have (minimum 8). \ No newline at end of file +To fix it, please install Java 11 and execute JMeter with this version or install `awsmeter` following the steps described in the [Install](https://github.com/JoseLuisSR/awsmeter#install) section and execute JMeter with th version of Java you have (minimum 8). + +# Localstack Support +If you need to use the Localstack instead of real AWS - you should change **aws_endpoint_custom** parameter in plugin GUI from empty stirng to some URL of your Localstack instance (with Localstack Edge port) + +To avoid a problem with SSL validation - please add SSL certificate of your Localstack to JVM cacerts: +``` +keytool -alias ANY_NAME -import -keystore "%JAVA_HOME%\lib\security\cacerts" -file some_localstack_selfsigned_certificate.crt +``` \ No newline at end of file diff --git a/src/main/java/org/apache/jmeter/protocol/aws/AWSClient.java b/src/main/java/org/apache/jmeter/protocol/aws/AWSClient.java index ff8c6df..00aa8c6 100644 --- a/src/main/java/org/apache/jmeter/protocol/aws/AWSClient.java +++ b/src/main/java/org/apache/jmeter/protocol/aws/AWSClient.java @@ -87,6 +87,18 @@ default String getAWSSessionToken(Map credentials){ }); } + /** + * Get custom AWS endpoint from input of JMeter Java Request parameter. + * @param credentials + * Represents the input of JMeter Java Request parameters. + * @return AWS endpoint String. + */ + default String getAWSEndpoint(Map credentials){ + return Optional.ofNullable(credentials.get(AWSSampler.AWS_ENDPOINT_CUSTOM)) + .filter(Predicate.not(String::isEmpty)) + .orElse(""); + } + /** * Function to get DefaultAwsRegionProviderChain from profile file. */ diff --git a/src/main/java/org/apache/jmeter/protocol/aws/AWSSampler.java b/src/main/java/org/apache/jmeter/protocol/aws/AWSSampler.java index 44c77f2..945fb53 100644 --- a/src/main/java/org/apache/jmeter/protocol/aws/AWSSampler.java +++ b/src/main/java/org/apache/jmeter/protocol/aws/AWSSampler.java @@ -1,12 +1,17 @@ package org.apache.jmeter.protocol.aws; +import com.amazonaws.client.builder.AwsClientBuilder; +import com.amazonaws.client.builder.AwsSyncClientBuilder; +import com.amazonaws.regions.Regions; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.jmeter.config.Argument; import org.apache.jmeter.protocol.java.sampler.JavaSamplerClient; import org.apache.jmeter.samplers.SampleResult; +import software.amazon.awssdk.core.client.builder.SdkClientBuilder; +import java.net.URI; import java.util.List; import java.util.Optional; import java.util.function.Predicate; @@ -52,6 +57,11 @@ public abstract class AWSSampler implements JavaSamplerClient{ */ protected static final String AWS_DEFAULT_PROFILE = "default"; + /** + * Custom AWS endpoint. + */ + protected static final String AWS_ENDPOINT_CUSTOM = "aws_endpoint_custom"; + /** * Fail code. */ @@ -105,6 +115,7 @@ public abstract class AWSSampler implements JavaSamplerClient{ new Argument(AWS_SECRET_ACCESS_KEY, EMPTY), new Argument(AWS_SESSION_TOKEN, EMPTY), new Argument(AWS_REGION, EMPTY), + new Argument(AWS_ENDPOINT_CUSTOM, EMPTY), new Argument(AWS_CONFIG_PROFILE, AWS_DEFAULT_PROFILE)) .collect(Collectors.toList()); @@ -188,4 +199,31 @@ protected List readMsgAttributes(final String msgAttributes) t .collect(Collectors.toList()); } + protected T wrapClientForLocalstack( + T sdkClientBuilder, + String customEndpoint, + String region + ) { + if (customEndpoint.isBlank()) { + return (T) sdkClientBuilder.withRegion(Regions.fromName(region)); + } else { + return (T) sdkClientBuilder.withEndpointConfiguration( + new AwsClientBuilder.EndpointConfiguration(customEndpoint, region) + ); + } + } + + protected T wrapClientForLocalstack( + T sdkClientBuilder, + String customEndpoint + ) { + if (customEndpoint.isBlank()) { + return sdkClientBuilder; + } else { + return (T) sdkClientBuilder.endpointOverride( + URI.create(customEndpoint) + ); + } + } + } diff --git a/src/main/java/org/apache/jmeter/protocol/aws/cognito/CognitoProducerSampler.java b/src/main/java/org/apache/jmeter/protocol/aws/cognito/CognitoProducerSampler.java index 758ab7b..c74eb11 100644 --- a/src/main/java/org/apache/jmeter/protocol/aws/cognito/CognitoProducerSampler.java +++ b/src/main/java/org/apache/jmeter/protocol/aws/cognito/CognitoProducerSampler.java @@ -91,7 +91,7 @@ public abstract class CognitoProducerSampler extends AWSSampler implements AWSCl */ @Override public SdkClient createSdkClient(Map credentials) { - return CognitoIdentityProviderClient.builder() + return wrapClientForLocalstack(CognitoIdentityProviderClient.builder(), getAWSEndpoint(credentials)) .region(Region.of(getAWSRegion(credentials))) .credentialsProvider(getAwsCredentialsProvider(credentials)) .build(); diff --git a/src/main/java/org/apache/jmeter/protocol/aws/kinesis/KinesisProducerSampler.java b/src/main/java/org/apache/jmeter/protocol/aws/kinesis/KinesisProducerSampler.java index ac91897..0513a51 100644 --- a/src/main/java/org/apache/jmeter/protocol/aws/kinesis/KinesisProducerSampler.java +++ b/src/main/java/org/apache/jmeter/protocol/aws/kinesis/KinesisProducerSampler.java @@ -73,7 +73,7 @@ public class KinesisProducerSampler extends AWSSampler implements AWSClientSDK2 */ @Override public SdkClient createSdkClient(Map credentials) { - return KinesisClient.builder() + return wrapClientForLocalstack(KinesisClient.builder(), getAWSEndpoint(credentials)) .region(Region.of(getAWSRegion(credentials))) .credentialsProvider(getAwsCredentialsProvider(credentials)) .build(); diff --git a/src/main/java/org/apache/jmeter/protocol/aws/sns/SNSProducerSampler.java b/src/main/java/org/apache/jmeter/protocol/aws/sns/SNSProducerSampler.java index d99b2c5..6c1f286 100644 --- a/src/main/java/org/apache/jmeter/protocol/aws/sns/SNSProducerSampler.java +++ b/src/main/java/org/apache/jmeter/protocol/aws/sns/SNSProducerSampler.java @@ -76,9 +76,9 @@ public abstract class SNSProducerSampler extends AWSSampler implements AWSClient */ @Override public AwsSyncClientBuilder createAWSClient(Map credentials) { - return AmazonSNSClient.builder() - .withCredentials(getAWSCredentialsProvider(credentials)) - .withRegion(Regions.fromName(getAWSRegion(credentials))); + String awsRegion = getAWSRegion(credentials); + return wrapClientForLocalstack(AmazonSNSClient.builder(), getAWSEndpoint(credentials), awsRegion) + .withCredentials(getAWSCredentialsProvider(credentials)); } /** diff --git a/src/main/java/org/apache/jmeter/protocol/aws/sqs/SQSProducerSampler.java b/src/main/java/org/apache/jmeter/protocol/aws/sqs/SQSProducerSampler.java index 3716212..f96387d 100644 --- a/src/main/java/org/apache/jmeter/protocol/aws/sqs/SQSProducerSampler.java +++ b/src/main/java/org/apache/jmeter/protocol/aws/sqs/SQSProducerSampler.java @@ -84,7 +84,7 @@ public abstract class SQSProducerSampler extends AWSSampler implements AWSClient */ @Override public SdkClient createSdkClient(Map credentials) { - return SqsClient.builder() + return wrapClientForLocalstack(SqsClient.builder(), getAWSEndpoint(credentials)) .region(Region.of(getAWSRegion(credentials))) .credentialsProvider(getAwsCredentialsProvider(credentials)) .build();