From 950aeed56e9e0ee9288e6c3705bd3e8f1826a475 Mon Sep 17 00:00:00 2001 From: Toby Fleming Date: Fri, 13 Dec 2019 13:05:51 -0800 Subject: [PATCH 1/4] Static HTTP client to prevent new connection pools each request --- pom.xml | 5 +- .../amazon/cloudformation/LambdaWrapper.java | 33 ++-- .../injection/AmazonWebServicesProvider.java | 21 ++- .../injection/CloudFormationProvider.java | 8 +- .../injection/CloudWatchEventsProvider.java | 14 +- .../injection/CloudWatchLogsProvider.java | 15 +- .../injection/CloudWatchProvider.java | 15 +- .../proxy/aws/AWSServiceSerdeModule.java | 1 + .../amazonaws/cloudformation/checkstyle.xml | 5 +- .../cloudformation/LambdaWrapperTest.java | 160 ++---------------- .../cloudformation/WrapperOverride.java | 11 +- .../proxy/End2EndCallChainTest.java | 37 ++-- .../proxy/handler/ServiceHandlerWrapper.java | 7 +- 13 files changed, 121 insertions(+), 211 deletions(-) diff --git a/pom.xml b/pom.xml index e678cb4a..66f43670 100644 --- a/pom.xml +++ b/pom.xml @@ -144,7 +144,10 @@ software.amazon.awssdk cloudwatchlogs - 2.5.69 + + + software.amazon.awssdk + apache-client diff --git a/src/main/java/software/amazon/cloudformation/LambdaWrapper.java b/src/main/java/software/amazon/cloudformation/LambdaWrapper.java index 6d63297d..9b57dc24 100644 --- a/src/main/java/software/amazon/cloudformation/LambdaWrapper.java +++ b/src/main/java/software/amazon/cloudformation/LambdaWrapper.java @@ -28,7 +28,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.net.URI; -import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.time.Instant; import java.util.Arrays; import java.util.Date; @@ -44,6 +44,8 @@ import org.json.JSONObject; import org.json.JSONTokener; +import software.amazon.awssdk.http.SdkHttpClient; +import software.amazon.awssdk.http.apache.ApacheHttpClient; import software.amazon.awssdk.utils.StringUtils; import software.amazon.cloudformation.exceptions.BaseHandlerException; import software.amazon.cloudformation.exceptions.FileScrubberException; @@ -80,6 +82,8 @@ public abstract class LambdaWrapper implements RequestStreamHandler { + public static final SdkHttpClient HTTP_CLIENT = ApacheHttpClient.builder().build(); + private static final List MUTATING_ACTIONS = Arrays.asList(Action.CREATE, Action.DELETE, Action.UPDATE); private static final int INVOCATION_TIMEOUT_MS = 60000; @@ -115,11 +119,11 @@ public abstract class LambdaWrapper implements RequestStre protected LambdaWrapper() { this.platformCredentialsProvider = new SessionCredentialsProvider(); this.providerCredentialsProvider = new SessionCredentialsProvider(); - this.cloudFormationProvider = new CloudFormationProvider(this.platformCredentialsProvider); - this.platformCloudWatchProvider = new CloudWatchProvider(this.platformCredentialsProvider); - this.providerCloudWatchProvider = new CloudWatchProvider(this.providerCredentialsProvider); - this.platformCloudWatchEventsProvider = new CloudWatchEventsProvider(this.platformCredentialsProvider); - this.cloudWatchLogsProvider = new CloudWatchLogsProvider(this.providerCredentialsProvider); + this.cloudFormationProvider = new CloudFormationProvider(this.platformCredentialsProvider, HTTP_CLIENT); + this.platformCloudWatchProvider = new CloudWatchProvider(this.platformCredentialsProvider, HTTP_CLIENT); + this.providerCloudWatchProvider = new CloudWatchProvider(this.providerCredentialsProvider, HTTP_CLIENT); + this.platformCloudWatchEventsProvider = new CloudWatchEventsProvider(this.platformCredentialsProvider, HTTP_CLIENT); + this.cloudWatchLogsProvider = new CloudWatchLogsProvider(this.providerCredentialsProvider, HTTP_CLIENT); this.serializer = new Serializer(); this.validator = new Validator(); this.typeReference = getTypeReference(); @@ -137,16 +141,17 @@ public LambdaWrapper(final CallbackAdapter callbackAdapter, final MetricsPublisher providerMetricsPublisher, final CloudWatchScheduler scheduler, final SchemaValidator validator, - final Serializer serializer) { + final Serializer serializer, + final SdkHttpClient httpClient) { this.callbackAdapter = callbackAdapter; this.platformCredentialsProvider = platformCredentialsProvider; this.providerCredentialsProvider = providerCredentialsProvider; - this.cloudFormationProvider = new CloudFormationProvider(this.platformCredentialsProvider); - this.platformCloudWatchProvider = new CloudWatchProvider(this.platformCredentialsProvider); - this.providerCloudWatchProvider = new CloudWatchProvider(this.providerCredentialsProvider); - this.platformCloudWatchEventsProvider = new CloudWatchEventsProvider(this.platformCredentialsProvider); - this.cloudWatchLogsProvider = new CloudWatchLogsProvider(this.providerCredentialsProvider); + this.cloudFormationProvider = new CloudFormationProvider(this.platformCredentialsProvider, httpClient); + this.platformCloudWatchProvider = new CloudWatchProvider(this.platformCredentialsProvider, httpClient); + this.providerCloudWatchProvider = new CloudWatchProvider(this.providerCredentialsProvider, httpClient); + this.platformCloudWatchEventsProvider = new CloudWatchEventsProvider(this.platformCredentialsProvider, httpClient); + this.cloudWatchLogsProvider = new CloudWatchLogsProvider(this.providerCredentialsProvider, httpClient); this.providerEventsLogger = providerEventsLogger; this.platformLambdaLogger = platformEventsLogger; this.platformMetricsPublisher = platformMetricsPublisher; @@ -245,7 +250,7 @@ public void handleRequest(final InputStream inputStream, final OutputStream outp throw new TerminalException("No request object received"); } - String input = IOUtils.toString(inputStream, "UTF-8"); + String input = IOUtils.toString(inputStream, StandardCharsets.UTF_8); JSONObject rawInput = new JSONObject(new JSONTokener(input)); // deserialize incoming payload to modelled request @@ -483,7 +488,7 @@ private Response createProgressResponse(final ProgressEvent response) throws IOException { String output = this.serializer.serialize(response); - outputStream.write(output.getBytes(Charset.forName("UTF-8"))); + outputStream.write(output.getBytes(StandardCharsets.UTF_8)); outputStream.close(); } diff --git a/src/main/java/software/amazon/cloudformation/injection/AmazonWebServicesProvider.java b/src/main/java/software/amazon/cloudformation/injection/AmazonWebServicesProvider.java index ff81801e..ee33f875 100644 --- a/src/main/java/software/amazon/cloudformation/injection/AmazonWebServicesProvider.java +++ b/src/main/java/software/amazon/cloudformation/injection/AmazonWebServicesProvider.java @@ -16,16 +16,35 @@ import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; +import software.amazon.awssdk.awscore.client.builder.AwsClientBuilder; +import software.amazon.awssdk.awscore.client.builder.AwsSyncClientBuilder; +import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; +import software.amazon.awssdk.core.retry.RetryPolicy; +import software.amazon.awssdk.http.SdkHttpClient; public abstract class AmazonWebServicesProvider { + protected static final ClientOverrideConfiguration CONFIGURATION = ClientOverrideConfiguration.builder() + // Default Retry Condition of Retry Policy retries on Throttling and ClockSkew + // Exceptions + .retryPolicy(RetryPolicy.builder().numRetries(16).build()).build(); + protected final CredentialsProvider credentialsProvider; + protected final SdkHttpClient httpClient; - protected AmazonWebServicesProvider(final CredentialsProvider credentialsProvider) { + protected AmazonWebServicesProvider(final CredentialsProvider credentialsProvider, + final SdkHttpClient httpClient) { this.credentialsProvider = credentialsProvider; + this.httpClient = httpClient; } protected AwsCredentialsProvider getCredentialsProvider() { return StaticCredentialsProvider.create(this.credentialsProvider.get()); } + + protected & AwsSyncClientBuilder, + ClientT> BuilderT defaultClient(final BuilderT builder) { + return builder.credentialsProvider(this.getCredentialsProvider()).overrideConfiguration(CONFIGURATION) + .httpClient(httpClient); + } } diff --git a/src/main/java/software/amazon/cloudformation/injection/CloudFormationProvider.java b/src/main/java/software/amazon/cloudformation/injection/CloudFormationProvider.java index 4d64c00b..4f775602 100644 --- a/src/main/java/software/amazon/cloudformation/injection/CloudFormationProvider.java +++ b/src/main/java/software/amazon/cloudformation/injection/CloudFormationProvider.java @@ -16,14 +16,16 @@ import java.net.URI; +import software.amazon.awssdk.http.SdkHttpClient; import software.amazon.awssdk.services.cloudformation.CloudFormationClient; public class CloudFormationProvider extends AmazonWebServicesProvider { private URI callbackEndpoint; - public CloudFormationProvider(final CredentialsProvider credentialsProvider) { - super(credentialsProvider); + public CloudFormationProvider(final CredentialsProvider credentialsProvider, + final SdkHttpClient httpClient) { + super(credentialsProvider, httpClient); } public void setCallbackEndpoint(final URI callbackEndpoint) { @@ -31,7 +33,7 @@ public void setCallbackEndpoint(final URI callbackEndpoint) { } public CloudFormationClient get() { - return CloudFormationClient.builder().credentialsProvider(this.getCredentialsProvider()) + return CloudFormationClient.builder().credentialsProvider(this.getCredentialsProvider()).httpClient(httpClient) .endpointOverride(this.callbackEndpoint).build(); } } diff --git a/src/main/java/software/amazon/cloudformation/injection/CloudWatchEventsProvider.java b/src/main/java/software/amazon/cloudformation/injection/CloudWatchEventsProvider.java index 15b2e349..6c364fd1 100644 --- a/src/main/java/software/amazon/cloudformation/injection/CloudWatchEventsProvider.java +++ b/src/main/java/software/amazon/cloudformation/injection/CloudWatchEventsProvider.java @@ -14,21 +14,17 @@ */ package software.amazon.cloudformation.injection; -import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; -import software.amazon.awssdk.core.retry.RetryPolicy; +import software.amazon.awssdk.http.SdkHttpClient; import software.amazon.awssdk.services.cloudwatchevents.CloudWatchEventsClient; public class CloudWatchEventsProvider extends AmazonWebServicesProvider { - public CloudWatchEventsProvider(final CredentialsProvider credentialsProvider) { - super(credentialsProvider); + public CloudWatchEventsProvider(final CredentialsProvider credentialsProvider, + final SdkHttpClient httpClient) { + super(credentialsProvider, httpClient); } public CloudWatchEventsClient get() { - return CloudWatchEventsClient.builder().overrideConfiguration(ClientOverrideConfiguration.builder() - // Default Retry Condition of Retry Policy retries on Throttling and ClockSkew - // Exceptions - .retryPolicy(RetryPolicy.builder().numRetries(16).build()).build()).credentialsProvider(this.getCredentialsProvider()) - .build(); + return defaultClient(CloudWatchEventsClient.builder()).build(); } } diff --git a/src/main/java/software/amazon/cloudformation/injection/CloudWatchLogsProvider.java b/src/main/java/software/amazon/cloudformation/injection/CloudWatchLogsProvider.java index b2834fbc..1fabaff6 100644 --- a/src/main/java/software/amazon/cloudformation/injection/CloudWatchLogsProvider.java +++ b/src/main/java/software/amazon/cloudformation/injection/CloudWatchLogsProvider.java @@ -14,22 +14,17 @@ */ package software.amazon.cloudformation.injection; -import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; -import software.amazon.awssdk.core.retry.RetryPolicy; +import software.amazon.awssdk.http.SdkHttpClient; import software.amazon.awssdk.services.cloudwatchlogs.CloudWatchLogsClient; public class CloudWatchLogsProvider extends AmazonWebServicesProvider { - public CloudWatchLogsProvider(final CredentialsProvider credentialsProvider) { - super(credentialsProvider); + public CloudWatchLogsProvider(final CredentialsProvider credentialsProvider, + final SdkHttpClient httpClient) { + super(credentialsProvider, httpClient); } public CloudWatchLogsClient get() { - return CloudWatchLogsClient.builder().credentialsProvider(this.getCredentialsProvider()) - .overrideConfiguration(ClientOverrideConfiguration.builder() - // Default Retry Condition of Retry Policy retries on Throttling and ClockSkew - // Exceptions - .retryPolicy(RetryPolicy.builder().numRetries(16).build()).build()) - .build(); + return defaultClient(CloudWatchLogsClient.builder()).build(); } } diff --git a/src/main/java/software/amazon/cloudformation/injection/CloudWatchProvider.java b/src/main/java/software/amazon/cloudformation/injection/CloudWatchProvider.java index aecd8c6b..1d3eef0d 100644 --- a/src/main/java/software/amazon/cloudformation/injection/CloudWatchProvider.java +++ b/src/main/java/software/amazon/cloudformation/injection/CloudWatchProvider.java @@ -14,22 +14,17 @@ */ package software.amazon.cloudformation.injection; -import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; -import software.amazon.awssdk.core.retry.RetryPolicy; +import software.amazon.awssdk.http.SdkHttpClient; import software.amazon.awssdk.services.cloudwatch.CloudWatchClient; public class CloudWatchProvider extends AmazonWebServicesProvider { - public CloudWatchProvider(final CredentialsProvider credentialsProvider) { - super(credentialsProvider); + public CloudWatchProvider(final CredentialsProvider credentialsProvider, + final SdkHttpClient httpClient) { + super(credentialsProvider, httpClient); } public CloudWatchClient get() { - return CloudWatchClient.builder().credentialsProvider(this.getCredentialsProvider()) - .overrideConfiguration(ClientOverrideConfiguration.builder() - // Default Retry Condition of Retry Policy retries on Throttling and ClockSkew - // Exceptions - .retryPolicy(RetryPolicy.builder().numRetries(16).build()).build()) - .build(); + return defaultClient(CloudWatchClient.builder()).build(); } } diff --git a/src/main/java/software/amazon/cloudformation/proxy/aws/AWSServiceSerdeModule.java b/src/main/java/software/amazon/cloudformation/proxy/aws/AWSServiceSerdeModule.java index 0a518eae..73b4e9bc 100644 --- a/src/main/java/software/amazon/cloudformation/proxy/aws/AWSServiceSerdeModule.java +++ b/src/main/java/software/amazon/cloudformation/proxy/aws/AWSServiceSerdeModule.java @@ -29,6 +29,7 @@ import software.amazon.awssdk.core.SdkPojo; import software.amazon.awssdk.utils.builder.SdkBuilder; +@SuppressWarnings("checkstyle:AbbreviationAsWordInName") public class AWSServiceSerdeModule extends Module { public static class AWSSerializers extends Serializers.Base { diff --git a/src/main/resources/com/amazonaws/cloudformation/checkstyle.xml b/src/main/resources/com/amazonaws/cloudformation/checkstyle.xml index 2fb471ef..b2ca4cd2 100644 --- a/src/main/resources/com/amazonaws/cloudformation/checkstyle.xml +++ b/src/main/resources/com/amazonaws/cloudformation/checkstyle.xml @@ -36,8 +36,11 @@ value="${checkstyle.suppressions.file}" default="checkstyle-suppressions.xml"/> - + + + + diff --git a/src/test/java/software/amazon/cloudformation/LambdaWrapperTest.java b/src/test/java/software/amazon/cloudformation/LambdaWrapperTest.java index 82ae22be..55c8a23a 100644 --- a/src/test/java/software/amazon/cloudformation/LambdaWrapperTest.java +++ b/src/test/java/software/amazon/cloudformation/LambdaWrapperTest.java @@ -43,6 +43,7 @@ import java.util.Map; import org.json.JSONObject; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; @@ -52,6 +53,7 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import software.amazon.awssdk.http.SdkHttpClient; import software.amazon.awssdk.services.cloudformation.model.OperationStatusCheckFailedException; import software.amazon.cloudformation.exceptions.ResourceAlreadyExistsException; import software.amazon.cloudformation.exceptions.ResourceNotFoundException; @@ -113,6 +115,18 @@ public class LambdaWrapperTest { @Mock private ResourceHandlerRequest resourceHandlerRequest; + @Mock + private SdkHttpClient httpClient; + + private WrapperOverride wrapper; + + @BeforeEach + public void initWrapper() { + wrapper = new WrapperOverride(callbackAdapter, platformCredentialsProvider, providerLoggingCredentialsProvider, + platformEventsLogger, providerEventsLogger, platformMetricsPublisher, + providerMetricsPublisher, scheduler, validator, httpClient); + } + public static InputStream loadRequestStream(final String fileName) { final File file = new File(String.format(TEST_DATA_BASE_PATH, fileName)); @@ -161,11 +175,6 @@ private void verifyHandlerResponse(final OutputStream out, final HandlerResponse public void invokeHandler_nullResponse_returnsFailure(final String requestDataPath, final String actionAsString) throws IOException { final Action action = Action.valueOf(actionAsString); - final WrapperOverride wrapper = new WrapperOverride(callbackAdapter, platformCredentialsProvider, - providerLoggingCredentialsProvider, platformEventsLogger, - providerEventsLogger, platformMetricsPublisher, - providerMetricsPublisher, scheduler, validator); - final TestModel model = new TestModel(); // a null response is a terminal fault @@ -225,10 +234,6 @@ public void invokeHandlerForCreate_without_customer_loggingCredentials() throws private void invokeHandler_without_customerLoggingCredentials(final String requestDataPath, final Action action) throws IOException { - final WrapperOverride wrapper = new WrapperOverride(callbackAdapter, platformCredentialsProvider, - providerLoggingCredentialsProvider, platformEventsLogger, - providerEventsLogger, platformMetricsPublisher, - providerMetricsPublisher, scheduler, validator); final TestModel model = new TestModel(); // a null response is a terminal fault @@ -284,10 +289,6 @@ private void invokeHandler_without_customerLoggingCredentials(final String reque public void invokeHandler_handlerFailed_returnsFailure(final String requestDataPath, final String actionAsString) throws IOException { final Action action = Action.valueOf(actionAsString); - final WrapperOverride wrapper = new WrapperOverride(callbackAdapter, platformCredentialsProvider, - providerLoggingCredentialsProvider, platformEventsLogger, - providerEventsLogger, platformMetricsPublisher, - providerMetricsPublisher, scheduler, validator); // explicit fault response is treated as an unsuccessful synchronous completion final ProgressEvent pe = ProgressEvent.builder() @@ -333,11 +334,6 @@ public void invokeHandler_handlerFailed_returnsFailure(final String requestDataP @Test public void invokeHandler_withNullInput() throws IOException { - final WrapperOverride wrapper = new WrapperOverride(callbackAdapter, platformCredentialsProvider, - providerLoggingCredentialsProvider, platformEventsLogger, - providerEventsLogger, platformMetricsPublisher, - providerMetricsPublisher, scheduler, validator); - // explicit fault response is treated as an unsuccessful synchronous completion final ProgressEvent pe = ProgressEvent.builder() .status(OperationStatus.FAILED).errorCode(HandlerErrorCode.InternalFailure).message("Custom Fault").build(); @@ -359,10 +355,6 @@ public void invokeHandler_withNullInput() throws IOException { public void invokeHandler_CompleteSynchronously_returnsSuccess(final String requestDataPath, final String actionAsString) throws IOException { final Action action = Action.valueOf(actionAsString); - final WrapperOverride wrapper = new WrapperOverride(callbackAdapter, platformCredentialsProvider, - providerLoggingCredentialsProvider, platformEventsLogger, - providerEventsLogger, platformMetricsPublisher, - providerMetricsPublisher, scheduler, validator); final TestModel model = new TestModel(); // if the handler responds Complete, this is treated as a successful synchronous @@ -456,10 +448,6 @@ public void invokeHandler_DependenciesInitialised_CompleteSynchronously_returnsS public void invokeHandler_InProgress_returnsInProgress(final String requestDataPath, final String actionAsString) throws IOException { final Action action = Action.valueOf(actionAsString); - final WrapperOverride wrapper = new WrapperOverride(callbackAdapter, platformCredentialsProvider, - providerLoggingCredentialsProvider, platformEventsLogger, - providerEventsLogger, platformMetricsPublisher, - providerMetricsPublisher, scheduler, validator); final TestModel model = TestModel.builder().property1("abc").property2(123).build(); // an InProgress response is always re-scheduled. @@ -530,10 +518,6 @@ public void invokeHandler_InProgress_returnsInProgress(final String requestDataP public void reInvokeHandler_InProgress_returnsInProgress(final String requestDataPath, final String actionAsString) throws IOException { final Action action = Action.valueOf(actionAsString); - final WrapperOverride wrapper = new WrapperOverride(callbackAdapter, platformCredentialsProvider, - providerLoggingCredentialsProvider, platformEventsLogger, - providerEventsLogger, platformMetricsPublisher, - providerMetricsPublisher, scheduler, validator); final TestModel model = TestModel.builder().property1("abc").property2(123).build(); // an InProgress response is always re-scheduled. @@ -596,10 +580,6 @@ public void invokeHandler_SchemaValidationFailure(final String requestDataPath, throws IOException { final Action action = Action.valueOf(actionAsString); doThrow(ValidationException.class).when(validator).validateObject(any(JSONObject.class), any(JSONObject.class)); - final WrapperOverride wrapper = new WrapperOverride(callbackAdapter, platformCredentialsProvider, - providerLoggingCredentialsProvider, platformEventsLogger, - providerEventsLogger, platformMetricsPublisher, - providerMetricsPublisher, scheduler, validator); wrapper.setTransformResponse(resourceHandlerRequest); @@ -654,7 +634,7 @@ public void invokeHandler_extraneousModelFields_causesSchemaValidationFailure() providerLoggingCredentialsProvider, platformEventsLogger, providerEventsLogger, platformMetricsPublisher, providerMetricsPublisher, scheduler, new Validator() { - }); + }, httpClient); wrapper.setTransformResponse(resourceHandlerRequest); @@ -701,10 +681,6 @@ providerMetricsPublisher, scheduler, new Validator() { @Test public void invokeHandler_withMalformedRequest_causesSchemaValidationFailure() throws IOException { - final WrapperOverride wrapper = new WrapperOverride(callbackAdapter, platformCredentialsProvider, - providerLoggingCredentialsProvider, platformEventsLogger, - providerEventsLogger, platformMetricsPublisher, - providerMetricsPublisher, scheduler, validator); final TestModel model = new TestModel(); // an InProgress response is always re-scheduled. @@ -733,11 +709,6 @@ public void invokeHandler_withMalformedRequest_causesSchemaValidationFailure() t @Test public void invokeHandler_withoutPlatformCredentials_returnsFailure() throws IOException { - final WrapperOverride wrapper = new WrapperOverride(callbackAdapter, platformCredentialsProvider, - providerLoggingCredentialsProvider, platformEventsLogger, - providerEventsLogger, platformMetricsPublisher, - providerMetricsPublisher, scheduler, validator); - // without platform credentials the handler is unable to do // basic SDK initialization and any such request should fail fast try (final InputStream in = loadRequestStream("create.request-without-platform-credentials.json"); @@ -756,11 +727,6 @@ public void invokeHandler_withoutPlatformCredentials_returnsFailure() throws IOE @Test public void invokeHandler_withoutCallerCredentials_passesNoAWSProxy() throws IOException { - final WrapperOverride wrapper = new WrapperOverride(callbackAdapter, platformCredentialsProvider, - providerLoggingCredentialsProvider, platformEventsLogger, - providerEventsLogger, platformMetricsPublisher, - providerMetricsPublisher, scheduler, validator); - final TestModel model = new TestModel(); model.setProperty1("abc"); model.setProperty2(123); @@ -791,11 +757,6 @@ public void invokeHandler_withoutCallerCredentials_passesNoAWSProxy() throws IOE @Test public void invokeHandler_withDefaultInjection_returnsSuccess() throws IOException { - final WrapperOverride wrapper = new WrapperOverride(callbackAdapter, platformCredentialsProvider, - providerLoggingCredentialsProvider, platformEventsLogger, - providerEventsLogger, platformMetricsPublisher, - providerMetricsPublisher, scheduler, validator); - final TestModel model = new TestModel(); model.setProperty1("abc"); model.setProperty2(123); @@ -826,11 +787,6 @@ public void invokeHandler_withDefaultInjection_returnsSuccess() throws IOExcepti @Test public void invokeHandler_withDefaultInjection_returnsInProgress() throws IOException { - final WrapperOverride wrapper = new WrapperOverride(callbackAdapter, platformCredentialsProvider, - providerLoggingCredentialsProvider, platformEventsLogger, - providerEventsLogger, platformMetricsPublisher, - providerMetricsPublisher, scheduler, validator); - final TestModel model = new TestModel(); model.setProperty1("abc"); model.setProperty2(123); @@ -857,10 +813,6 @@ public void invokeHandler_withDefaultInjection_returnsInProgress() throws IOExce @Test public void invokeHandler_failToRescheduleInvocation() throws IOException { - final WrapperOverride wrapper = new WrapperOverride(callbackAdapter, platformCredentialsProvider, - providerLoggingCredentialsProvider, platformEventsLogger, - providerEventsLogger, platformMetricsPublisher, - providerMetricsPublisher, scheduler, validator); final TestModel model = new TestModel(); model.setProperty1("abc"); model.setProperty2(123); @@ -890,11 +842,6 @@ public void invokeHandler_failToRescheduleInvocation() throws IOException { @Test public void invokeHandler_clientsRefreshedOnEveryInvoke() throws IOException { - final WrapperOverride wrapper = new WrapperOverride(callbackAdapter, platformCredentialsProvider, - providerLoggingCredentialsProvider, platformEventsLogger, - providerEventsLogger, platformMetricsPublisher, - providerMetricsPublisher, scheduler, validator); - Context context = getLambdaContext(); try (InputStream in = loadRequestStream("create.request.json"); OutputStream out = new ByteArrayOutputStream()) { wrapper.handleRequest(in, out, context); @@ -917,11 +864,6 @@ public void invokeHandler_clientsRefreshedOnEveryInvoke() throws IOException { @Test public void invokeHandler_platformCredentialsRefreshedOnEveryInvoke() throws IOException { - final WrapperOverride wrapper = new WrapperOverride(callbackAdapter, platformCredentialsProvider, - providerLoggingCredentialsProvider, platformEventsLogger, - providerEventsLogger, platformMetricsPublisher, - providerMetricsPublisher, scheduler, validator); - Context context = getLambdaContext(); try (InputStream in = loadRequestStream("create.request.json"); OutputStream out = new ByteArrayOutputStream()) { wrapper.handleRequest(in, out, context); @@ -945,11 +887,6 @@ public void invokeHandler_platformCredentialsRefreshedOnEveryInvoke() throws IOE @Test public void invokeHandler_withNoResponseEndpoint_returnsFailure() throws IOException { - final WrapperOverride wrapper = new WrapperOverride(callbackAdapter, platformCredentialsProvider, - providerLoggingCredentialsProvider, platformEventsLogger, - providerEventsLogger, platformMetricsPublisher, - providerMetricsPublisher, scheduler, validator); - final TestModel model = new TestModel(); // an InProgress response is always re-scheduled. @@ -983,11 +920,6 @@ public void invokeHandler_withNoResponseEndpoint_returnsFailure() throws IOExcep @Test public void invokeHandler_localReinvokeWithSufficientRemainingTime() throws IOException { - final WrapperOverride wrapper = new WrapperOverride(callbackAdapter, platformCredentialsProvider, - providerLoggingCredentialsProvider, platformEventsLogger, - providerEventsLogger, platformMetricsPublisher, - providerMetricsPublisher, scheduler, validator); - final TestModel model = TestModel.builder().property1("abc").property2(123).build(); // an InProgress response is always re-scheduled. @@ -1073,11 +1005,6 @@ public void invokeHandler_localReinvokeWithSufficientRemainingTime() throws IOEx @Test public void invokeHandler_localReinvokeWithSufficientRemainingTimeForFirstIterationOnly_SchedulesViaCloudWatch() throws IOException { - final WrapperOverride wrapper = new WrapperOverride(callbackAdapter, platformCredentialsProvider, - providerLoggingCredentialsProvider, platformEventsLogger, - providerEventsLogger, platformMetricsPublisher, - providerMetricsPublisher, scheduler, validator); - final TestModel model = TestModel.builder().property1("abc").property2(123).build(); // an InProgress response is always re-scheduled. @@ -1165,13 +1092,6 @@ public void invokeHandler_localReinvokeWithSufficientRemainingTimeForFirstIterat @Test public void invokeHandler_throwsAmazonServiceException_returnsServiceException() throws IOException { - final WrapperOverride wrapper = new WrapperOverride(callbackAdapter, platformCredentialsProvider, - providerLoggingCredentialsProvider, platformEventsLogger, - providerEventsLogger, platformMetricsPublisher, - providerMetricsPublisher, scheduler, validator); - - final TestModel model = new TestModel(); - // exceptions are caught consistently by LambdaWrapper wrapper.setInvokeHandlerException(new AmazonServiceException("some error")); @@ -1216,11 +1136,6 @@ public void invokeHandler_throwsAmazonServiceException_returnsServiceException() @Test public void invokeHandler_throwsResourceAlreadyExistsException_returnsAlreadyExists() throws IOException { - final WrapperOverride wrapper = new WrapperOverride(callbackAdapter, platformCredentialsProvider, - providerLoggingCredentialsProvider, platformEventsLogger, - providerEventsLogger, platformMetricsPublisher, - providerMetricsPublisher, scheduler, validator); - // exceptions are caught consistently by LambdaWrapper wrapper.setInvokeHandlerException(new ResourceAlreadyExistsException("AWS::Test::TestModel", "id-1234")); @@ -1265,10 +1180,6 @@ public void invokeHandler_throwsResourceAlreadyExistsException_returnsAlreadyExi @Test public void invokeHandler_throwsResourceNotFoundException_returnsNotFound() throws IOException { - final WrapperOverride wrapper = new WrapperOverride(callbackAdapter, platformCredentialsProvider, - providerLoggingCredentialsProvider, platformEventsLogger, - providerEventsLogger, platformMetricsPublisher, - providerMetricsPublisher, scheduler, validator); // exceptions are caught consistently by LambdaWrapper wrapper.setInvokeHandlerException(new ResourceNotFoundException("AWS::Test::TestModel", "id-1234")); @@ -1313,11 +1224,6 @@ public void invokeHandler_throwsResourceNotFoundException_returnsNotFound() thro @Test public void invokeHandler_metricPublisherThrowable_returnsFailureResponse() throws IOException { - final WrapperOverride wrapper = new WrapperOverride(callbackAdapter, platformCredentialsProvider, - providerLoggingCredentialsProvider, platformEventsLogger, - providerEventsLogger, platformMetricsPublisher, - providerMetricsPublisher, scheduler, validator); - // simulate runtime Errors in the metrics publisher (such as dependency // resolution conflicts) doThrow(new Error("not an Exception")).when(platformMetricsPublisher).publishInvocationMetric(any(), any()); @@ -1350,11 +1256,6 @@ public void invokeHandler_metricPublisherThrowable_returnsFailureResponse() thro @Test public void invokeHandler_withInvalidPayload_returnsFailureResponse() throws IOException { - final WrapperOverride wrapper = new WrapperOverride(callbackAdapter, platformCredentialsProvider, - providerLoggingCredentialsProvider, platformEventsLogger, - providerEventsLogger, platformMetricsPublisher, - providerMetricsPublisher, scheduler, validator); - try (final InputStream in = new ByteArrayInputStream(new byte[0]); final OutputStream out = new ByteArrayOutputStream()) { final Context context = getLambdaContext(); @@ -1373,11 +1274,6 @@ public void invokeHandler_withInvalidPayload_returnsFailureResponse() throws IOE @Test public void invokeHandler_withNullInputStream_returnsFailureResponse() throws IOException { - final WrapperOverride wrapper = new WrapperOverride(callbackAdapter, platformCredentialsProvider, - providerLoggingCredentialsProvider, platformEventsLogger, - providerEventsLogger, platformMetricsPublisher, - providerMetricsPublisher, scheduler, validator); - try (final OutputStream out = new ByteArrayOutputStream()) { final Context context = getLambdaContext(); @@ -1395,11 +1291,6 @@ public void invokeHandler_withNullInputStream_returnsFailureResponse() throws IO @Test public void invokeHandler_withEmptyPayload_returnsFailure() throws IOException { - final WrapperOverride wrapper = new WrapperOverride(callbackAdapter, platformCredentialsProvider, - providerLoggingCredentialsProvider, platformEventsLogger, - providerEventsLogger, platformMetricsPublisher, - providerMetricsPublisher, scheduler, validator); - try (final InputStream in = loadRequestStream("empty.request.json"); final OutputStream out = new ByteArrayOutputStream()) { final Context context = getLambdaContext(); @@ -1418,11 +1309,6 @@ public void invokeHandler_withEmptyPayload_returnsFailure() throws IOException { @Test public void invokeHandler_withEmptyResourceProperties_returnsFailure() throws IOException { - final WrapperOverride wrapper = new WrapperOverride(callbackAdapter, platformCredentialsProvider, - providerLoggingCredentialsProvider, platformEventsLogger, - providerEventsLogger, platformMetricsPublisher, - providerMetricsPublisher, scheduler, validator); - try (final InputStream in = loadRequestStream("empty.resource.request.json"); final OutputStream out = new ByteArrayOutputStream()) { final Context context = getLambdaContext(); @@ -1451,7 +1337,7 @@ public void stringifiedPayload_validation_successful() throws IOException { final WrapperOverride wrapper = new WrapperOverride(callbackAdapter, platformCredentialsProvider, providerLoggingCredentialsProvider, platformEventsLogger, providerEventsLogger, platformMetricsPublisher, - providerMetricsPublisher, scheduler, validator); + providerMetricsPublisher, scheduler, validator, httpClient); // explicit fault response is treated as an unsuccessful synchronous completion final ProgressEvent pe = ProgressEvent.builder() @@ -1475,10 +1361,6 @@ public void stringifiedPayload_validation_successful() throws IOException { @Test public void handleRequest_apiThrowsOperationStatusException_returnsFailedStatus() throws IOException { - final WrapperOverride wrapper = new WrapperOverride(callbackAdapter, platformCredentialsProvider, - providerLoggingCredentialsProvider, platformEventsLogger, - providerEventsLogger, platformMetricsPublisher, - providerMetricsPublisher, scheduler, validator); final String errorMessage = "Unexpected status"; final OperationStatusCheckFailedException exception = OperationStatusCheckFailedException.builder().message(errorMessage) .build(); @@ -1514,11 +1396,6 @@ public void handleRequest_apiThrowsOperationStatusException_returnsFailedStatus( @Test public void getDesiredResourceTags_oneStackTagAndOneResourceTag() { - final WrapperOverride wrapper = new WrapperOverride(callbackAdapter, platformCredentialsProvider, - providerLoggingCredentialsProvider, platformEventsLogger, - providerEventsLogger, platformMetricsPublisher, - providerMetricsPublisher, scheduler, validator); - final Map stackTags = new HashMap<>(); stackTags.put("Tag1", "Value1"); @@ -1541,11 +1418,6 @@ public void getDesiredResourceTags_oneStackTagAndOneResourceTag() { @Test public void getDesiredResourceTags_resourceTagOverridesStackTag() { - final WrapperOverride wrapper = new WrapperOverride(callbackAdapter, platformCredentialsProvider, - providerLoggingCredentialsProvider, platformEventsLogger, - providerEventsLogger, platformMetricsPublisher, - providerMetricsPublisher, scheduler, validator); - final Map stackTags = new HashMap<>(); stackTags.put("Tag1", "Value1"); diff --git a/src/test/java/software/amazon/cloudformation/WrapperOverride.java b/src/test/java/software/amazon/cloudformation/WrapperOverride.java index 26f030c0..d7087e63 100644 --- a/src/test/java/software/amazon/cloudformation/WrapperOverride.java +++ b/src/test/java/software/amazon/cloudformation/WrapperOverride.java @@ -17,7 +17,7 @@ import com.fasterxml.jackson.core.type.TypeReference; import java.io.ByteArrayInputStream; -import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -29,6 +29,7 @@ import org.json.JSONObject; import org.json.JSONTokener; +import software.amazon.awssdk.http.SdkHttpClient; import software.amazon.cloudformation.injection.CredentialsProvider; import software.amazon.cloudformation.loggers.CloudWatchLogPublisher; import software.amazon.cloudformation.loggers.LogPublisher; @@ -66,15 +67,17 @@ public WrapperOverride(final CallbackAdapter callbackAdapter, final MetricsPublisher platformMetricsPublisher, final MetricsPublisher providerMetricsPublisher, final CloudWatchScheduler scheduler, - final SchemaValidator validator) { + final SchemaValidator validator, + final SdkHttpClient httpClient) { super(callbackAdapter, platformCredentialsProvider, providerLoggingCredentialsProvider, providerEventsLogger, - platformEventsLogger, platformMetricsPublisher, providerMetricsPublisher, scheduler, validator, new Serializer()); + platformEventsLogger, platformMetricsPublisher, providerMetricsPublisher, scheduler, validator, new Serializer(), + httpClient); } @Override protected JSONObject provideResourceSchemaJSONObject() { return new JSONObject(new JSONTokener(new ByteArrayInputStream("{ \"properties\": { \"property1\": { \"type\": \"string\" }, \"property2\": { \"type\": \"integer\" } }, \"additionalProperties\": false }" - .getBytes(Charset.forName("UTF8"))))); + .getBytes(StandardCharsets.UTF_8)))); } @Override diff --git a/src/test/java/software/amazon/cloudformation/proxy/End2EndCallChainTest.java b/src/test/java/software/amazon/cloudformation/proxy/End2EndCallChainTest.java index a2a5912b..11dec533 100644 --- a/src/test/java/software/amazon/cloudformation/proxy/End2EndCallChainTest.java +++ b/src/test/java/software/amazon/cloudformation/proxy/End2EndCallChainTest.java @@ -42,6 +42,7 @@ import software.amazon.awssdk.awscore.AwsRequestOverrideConfiguration; import software.amazon.awssdk.awscore.exception.AwsErrorDetails; import software.amazon.awssdk.awscore.exception.AwsServiceException; +import software.amazon.awssdk.http.SdkHttpClient; import software.amazon.awssdk.http.SdkHttpResponse; import software.amazon.awssdk.services.cloudwatchevents.CloudWatchEventsClient; import software.amazon.awssdk.services.cloudwatchevents.model.PutRuleRequest; @@ -227,18 +228,20 @@ public AwsErrorDetails awsErrorDetails() { }; when(client.describeRepository(eq(describeRequest))).thenThrow(notFound); + final SdkHttpClient httpClient = mock(SdkHttpClient.class); final ServiceHandlerWrapper wrapper = new ServiceHandlerWrapper(adapter, platformCredentialsProvider, providerLoggingCredentialsProvider, mock(CloudWatchLogPublisher.class), mock(LogPublisher.class), mock(MetricsPublisher.class), mock(MetricsPublisher.class), - new CloudWatchScheduler(new CloudWatchEventsProvider(platformCredentialsProvider) { + new CloudWatchScheduler(new CloudWatchEventsProvider(platformCredentialsProvider, + httpClient) { @Override public CloudWatchEventsClient get() { return mock(CloudWatchEventsClient.class); } }, loggerProxy, serializer), new Validator(), serializer, - client); + client, httpClient); wrapper.handleRequest(stream, output, cxt); verify(client).describeRepository(eq(describeRequest)); @@ -284,18 +287,20 @@ public void createHandler() throws Exception { .repoName(model.getRepoName()).repoArn("some-arn").build(); when(client.describeRepository(eq(describeRequest))).thenReturn(describeResponse); + final SdkHttpClient httpClient = mock(SdkHttpClient.class); final ServiceHandlerWrapper wrapper = new ServiceHandlerWrapper(adapter, platformCredentialsProvider, providerLoggingCredentialsProvider, mock(CloudWatchLogPublisher.class), mock(LogPublisher.class), mock(MetricsPublisher.class), mock(MetricsPublisher.class), - new CloudWatchScheduler(new CloudWatchEventsProvider(platformCredentialsProvider) { + new CloudWatchScheduler(new CloudWatchEventsProvider(platformCredentialsProvider, + httpClient) { @Override public CloudWatchEventsClient get() { return mock(CloudWatchEventsClient.class); } }, loggerProxy, serializer), new Validator(), serializer, - client); + client, httpClient); wrapper.handleRequest(stream, output, cxt); verify(client).createRepository(eq(createRequest)); @@ -349,18 +354,20 @@ public AwsErrorDetails awsErrorDetails() { }; when(client.createRepository(eq(createRequest))).thenThrow(exists); + final SdkHttpClient httpClient = mock(SdkHttpClient.class); final ServiceHandlerWrapper wrapper = new ServiceHandlerWrapper(adapter, platformCredentialsProvider, providerLoggingCredentialsProvider, mock(CloudWatchLogPublisher.class), mock(LogPublisher.class), mock(MetricsPublisher.class), mock(MetricsPublisher.class), - new CloudWatchScheduler(new CloudWatchEventsProvider(platformCredentialsProvider) { + new CloudWatchScheduler(new CloudWatchEventsProvider(platformCredentialsProvider, + httpClient) { @Override public CloudWatchEventsClient get() { return mock(CloudWatchEventsClient.class); } }, loggerProxy, serializer), new Validator(), serializer, - client); + client, httpClient); wrapper.handleRequest(stream, output, cxt); verify(client).createRepository(eq(createRequest)); @@ -423,18 +430,20 @@ public AwsErrorDetails awsErrorDetails() { return PutTargetsResponse.builder().build(); }); + final SdkHttpClient httpClient = mock(SdkHttpClient.class); final ServiceHandlerWrapper wrapper = new ServiceHandlerWrapper(adapter, platformCredentialsProvider, providerLoggingCredentialsProvider, mock(CloudWatchLogPublisher.class), mock(LogPublisher.class), mock(MetricsPublisher.class), mock(MetricsPublisher.class), - new CloudWatchScheduler(new CloudWatchEventsProvider(platformCredentialsProvider) { + new CloudWatchScheduler(new CloudWatchEventsProvider(platformCredentialsProvider, + httpClient) { @Override public CloudWatchEventsClient get() { return cloudWatchEventsClient; } }, loggerProxy, serializer), new Validator(), serializer, - client); + client, httpClient); // Bail early for the handshake. Expect cloudwatch events wrapper.handleRequest(stream, output, cxt); @@ -494,18 +503,20 @@ public AwsErrorDetails awsErrorDetails() { }; when(client.describeRepository(eq(describeRequest))).thenThrow(throttleException); + final SdkHttpClient httpClient = mock(SdkHttpClient.class); final ServiceHandlerWrapper wrapper = new ServiceHandlerWrapper(adapter, platformCredentialsProvider, providerLoggingCredentialsProvider, mock(CloudWatchLogPublisher.class), mock(LogPublisher.class), mock(MetricsPublisher.class), mock(MetricsPublisher.class), - new CloudWatchScheduler(new CloudWatchEventsProvider(platformCredentialsProvider) { + new CloudWatchScheduler(new CloudWatchEventsProvider(platformCredentialsProvider, + httpClient) { @Override public CloudWatchEventsClient get() { return mock(CloudWatchEventsClient.class); } }, loggerProxy, serializer), new Validator(), serializer, - client); + client, httpClient); wrapper.handleRequest(stream, output, cxt); // only 1 call (1, 0s), the next attempt is at 3s which exceed 50 ms remaining @@ -555,18 +566,20 @@ public AwsErrorDetails awsErrorDetails() { }; when(client.describeRepository(eq(describeRequest))).thenThrow(accessDenied); + final SdkHttpClient httpClient = mock(SdkHttpClient.class); final ServiceHandlerWrapper wrapper = new ServiceHandlerWrapper(adapter, platformCredentialsProvider, providerLoggingCredentialsProvider, mock(CloudWatchLogPublisher.class), mock(LogPublisher.class), mock(MetricsPublisher.class), mock(MetricsPublisher.class), - new CloudWatchScheduler(new CloudWatchEventsProvider(platformCredentialsProvider) { + new CloudWatchScheduler(new CloudWatchEventsProvider(platformCredentialsProvider, + httpClient) { @Override public CloudWatchEventsClient get() { return mock(CloudWatchEventsClient.class); } }, loggerProxy, serializer), new Validator(), serializer, - client); + client, httpClient); wrapper.handleRequest(stream, output, cxt); verify(client).describeRepository(eq(describeRequest)); diff --git a/src/test/java/software/amazon/cloudformation/proxy/handler/ServiceHandlerWrapper.java b/src/test/java/software/amazon/cloudformation/proxy/handler/ServiceHandlerWrapper.java index d69fbee1..a5f27c67 100644 --- a/src/test/java/software/amazon/cloudformation/proxy/handler/ServiceHandlerWrapper.java +++ b/src/test/java/software/amazon/cloudformation/proxy/handler/ServiceHandlerWrapper.java @@ -22,6 +22,7 @@ import org.json.JSONTokener; import org.mockito.Mockito; +import software.amazon.awssdk.http.SdkHttpClient; import software.amazon.cloudformation.Action; import software.amazon.cloudformation.LambdaWrapper; import software.amazon.cloudformation.injection.CredentialsProvider; @@ -55,9 +56,11 @@ public ServiceHandlerWrapper(final CallbackAdapter callbackAdapter, final CloudWatchScheduler scheduler, final SchemaValidator validator, final Serializer serializer, - final ServiceClient client) { + final ServiceClient client, + final SdkHttpClient httpClient) { super(callbackAdapter, platformCredentialsProvider, providerLoggingCredentialsProvider, providerEventsLogger, - platformEventsLogger, platformMetricsPublisher, providerMetricsPublisher, scheduler, validator, serializer); + platformEventsLogger, platformMetricsPublisher, providerMetricsPublisher, scheduler, validator, serializer, + httpClient); this.serviceClient = client; } From ddd2ebf4a8f14844b87cda797847e02eb5be5bf0 Mon Sep 17 00:00:00 2001 From: Toby Fleming Date: Sun, 15 Dec 2019 19:30:23 -0800 Subject: [PATCH 2/4] Default retry policy --- .../cloudformation/injection/AmazonWebServicesProvider.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/software/amazon/cloudformation/injection/AmazonWebServicesProvider.java b/src/main/java/software/amazon/cloudformation/injection/AmazonWebServicesProvider.java index ee33f875..53465426 100644 --- a/src/main/java/software/amazon/cloudformation/injection/AmazonWebServicesProvider.java +++ b/src/main/java/software/amazon/cloudformation/injection/AmazonWebServicesProvider.java @@ -25,9 +25,7 @@ public abstract class AmazonWebServicesProvider { protected static final ClientOverrideConfiguration CONFIGURATION = ClientOverrideConfiguration.builder() - // Default Retry Condition of Retry Policy retries on Throttling and ClockSkew - // Exceptions - .retryPolicy(RetryPolicy.builder().numRetries(16).build()).build(); + .retryPolicy(RetryPolicy.defaultRetryPolicy()).build(); protected final CredentialsProvider credentialsProvider; protected final SdkHttpClient httpClient; From f257149e8eec294b7be8043044c397a671f1ef23 Mon Sep 17 00:00:00 2001 From: Toby Fleming Date: Mon, 16 Dec 2019 10:11:52 -0800 Subject: [PATCH 3/4] Bump version for release --- python/rpdk/java/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/rpdk/java/__init__.py b/python/rpdk/java/__init__.py index e6219d37..76b80cb6 100644 --- a/python/rpdk/java/__init__.py +++ b/python/rpdk/java/__init__.py @@ -1,5 +1,5 @@ import logging -__version__ = "0.1.1" +__version__ = "0.1.2" logging.getLogger(__name__).addHandler(logging.NullHandler()) From 9a89e592ddf3603592c24fea55cd72f241842ee8 Mon Sep 17 00:00:00 2001 From: Toby Fleming Date: Mon, 16 Dec 2019 10:40:55 -0800 Subject: [PATCH 4/4] Also bump pom.xml version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 66f43670..6229071c 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 software.amazon.cloudformation aws-cloudformation-rpdk-java-plugin - 1.0 + 1.0.1 AWS CloudFormation RPDK Java Plugin The CloudFormation Resource Provider Development Kit (RPDK) allows you to author your own resource providers that can be used by CloudFormation. This plugin library helps to provide runtime bindings for the execution of your providers by CloudFormation.