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
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>software.amazon.cloudformation</groupId>
<artifactId>aws-cloudformation-rpdk-java-plugin</artifactId>
<version>1.0.1</version>
<version>1.0.4</version>
<name>AWS CloudFormation RPDK Java Plugin</name>
<description>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.
</description>
Expand Down Expand Up @@ -65,7 +65,7 @@
<dependency>
<groupId>software.amazon.cloudformation</groupId>
<artifactId>aws-cloudformation-resource-schema</artifactId>
<version>2.0.0</version>
<version>2.0.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.dataformat/jackson-databind -->
<dependency>
Expand Down
6 changes: 5 additions & 1 deletion python/rpdk/java/templates/HandlerWrapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
public final class HandlerWrapper extends LambdaWrapper<{{ pojo_name }}, CallbackContext> {

private final Configuration configuration = new Configuration();
private JSONObject resourceSchema;
private final Map<Action, BaseHandler<CallbackContext>> handlers = new HashMap<>();
private final static TypeReference<HandlerRequest<{{ pojo_name }}, CallbackContext>> REQUEST_REFERENCE =
new TypeReference<HandlerRequest<{{ pojo_name }}, CallbackContext>>() {};
Expand Down Expand Up @@ -111,7 +112,10 @@ public void testEntrypoint(

@Override
public JSONObject provideResourceSchemaJSONObject() {
return this.configuration.resourceSchemaJSONObject();
if (resourceSchema == null) {
resourceSchema = this.configuration.resourceSchemaJSONObject();
}
return resourceSchema;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
import software.amazon.cloudformation.proxy.ProgressEvent;
import software.amazon.cloudformation.proxy.RequestContext;
import software.amazon.cloudformation.proxy.ResourceHandlerRequest;
import software.amazon.cloudformation.resource.ResourceTypeSchema;
import software.amazon.cloudformation.resource.SchemaValidator;
import software.amazon.cloudformation.resource.Serializer;
import software.amazon.cloudformation.resource.Validator;
Expand Down Expand Up @@ -226,7 +227,8 @@ private void initialiseRuntime(final String resourceType,

if (this.callbackAdapter == null) {
this.callbackAdapter = new CloudFormationCallbackAdapter<>(this.cloudFormationProvider, this.loggerProxy,
this.serializer);
this.serializer, ResourceTypeSchema
.load(provideResourceSchemaJSONObject()));
}
this.callbackAdapter.refreshClient();

Expand Down Expand Up @@ -495,7 +497,7 @@ private void writeResponse(final OutputStream outputStream, final Response<Resou
private void validateModel(final JSONObject modelObject) throws ValidationException, IOException {
JSONObject resourceSchemaJSONObject = provideResourceSchemaJSONObject();
if (resourceSchemaJSONObject == null) {
throw new ValidationException("Unable to validate incoming model as no schema was provided.", null, null);
throw new TerminalException("Unable to validate incoming model as no schema was provided.");
}

TypeReference<ResourceT> modelTypeReference = getModelTypeReference();
Expand All @@ -507,7 +509,6 @@ private void validateModel(final JSONObject modelObject) throws ValidationExcept
} catch (UnrecognizedPropertyException e) {
throw new ValidationException(String.format("#: extraneous key [%s] is not permitted", e.getPropertyName()),
"additionalProperties", "#");

}

JSONObject serializedModel = new JSONObject(this.serializer.serialize(deserializedModel));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,14 @@

import java.util.UUID;

import org.json.JSONObject;

import software.amazon.awssdk.services.cloudformation.CloudFormationClient;
import software.amazon.awssdk.services.cloudformation.model.RecordHandlerProgressRequest;
import software.amazon.awssdk.services.cloudformation.model.RecordHandlerProgressResponse;
import software.amazon.cloudformation.exceptions.TerminalException;
import software.amazon.cloudformation.injection.CloudFormationProvider;
import software.amazon.cloudformation.resource.ResourceTypeSchema;
import software.amazon.cloudformation.resource.Serializer;

public class CloudFormationCallbackAdapter<T> implements CallbackAdapter<T> {
Expand All @@ -35,12 +38,16 @@ public class CloudFormationCallbackAdapter<T> implements CallbackAdapter<T> {

private Serializer serializer;

private ResourceTypeSchema resourceTypeSchema;

public CloudFormationCallbackAdapter(final CloudFormationProvider cloudFormationProvider,
final LoggerProxy loggerProxy,
final Serializer serializer) {
final Serializer serializer,
final ResourceTypeSchema resourceTypeSchema) {
this.cloudFormationProvider = cloudFormationProvider;
this.loggerProxy = loggerProxy;
this.serializer = serializer;
this.resourceTypeSchema = resourceTypeSchema;
}

public void refreshClient() {
Expand All @@ -62,8 +69,10 @@ public void reportProgress(final String bearerToken,

if (resourceModel != null) {
try {
JSONObject jsonModel = new JSONObject(this.serializer.serialize(resourceModel));
resourceTypeSchema.removeWriteOnlyProperties(jsonModel);
// expect return type to be non-null
requestBuilder.resourceModel(this.serializer.serialize(resourceModel));
requestBuilder.resourceModel(jsonModel.toString());
} catch (JsonProcessingException e) {
throw new TerminalException("Unable to serialize resource model for reporting progress", e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@

import java.util.UUID;

import org.json.JSONObject;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
Expand All @@ -43,6 +44,7 @@
import software.amazon.awssdk.services.cloudformation.model.RecordHandlerProgressResponse;
import software.amazon.cloudformation.TestModel;
import software.amazon.cloudformation.injection.CloudFormationProvider;
import software.amazon.cloudformation.resource.ResourceTypeSchema;
import software.amazon.cloudformation.resource.Serializer;

@ExtendWith(MockitoExtension.class)
Expand All @@ -57,12 +59,15 @@ public class CloudFormationCallbackAdapterTest {
@Mock
private Serializer serializer;

@Mock
private ResourceTypeSchema resourceTypeSchema;

@Test
public void testReportProgress_withoutRefreshingClient() {
final CloudFormationClient client = mock(CloudFormationClient.class);

final CloudFormationCallbackAdapter<
TestModel> adapter = new CloudFormationCallbackAdapter<TestModel>(cloudFormationProvider, loggerProxy, serializer);
TestModel> adapter = new CloudFormationCallbackAdapter<TestModel>(cloudFormationProvider, loggerProxy, serializer,
resourceTypeSchema);
final AssertionError expectedException = assertThrows(AssertionError.class, () -> adapter.reportProgress("bearer-token",
HandlerErrorCode.InvalidRequest, OperationStatus.FAILED, OperationStatus.IN_PROGRESS, null, "some error"),
"Expected assertion exception");
Expand All @@ -84,7 +89,8 @@ public void testReportProgress_Failed() {
when(client.recordHandlerProgress(any(RecordHandlerProgressRequest.class))).thenReturn(response);

final CloudFormationCallbackAdapter<
TestModel> adapter = new CloudFormationCallbackAdapter<TestModel>(cloudFormationProvider, loggerProxy, serializer);
TestModel> adapter = new CloudFormationCallbackAdapter<TestModel>(cloudFormationProvider, loggerProxy, serializer,
resourceTypeSchema);
adapter.refreshClient();

adapter.reportProgress("bearer-token", HandlerErrorCode.InvalidRequest, OperationStatus.FAILED,
Expand All @@ -111,12 +117,13 @@ public void testReportProgress_IN_PROGRESS() throws JsonProcessingException {
when(response.responseMetadata()).thenReturn(responseMetadata);

when(cloudFormationProvider.get()).thenReturn(client);
when(serializer.serialize(any())).thenReturn("");
when(serializer.serialize(any())).thenReturn("{}");

when(client.recordHandlerProgress(any(RecordHandlerProgressRequest.class))).thenReturn(response);

final CloudFormationCallbackAdapter<
TestModel> adapter = new CloudFormationCallbackAdapter<TestModel>(cloudFormationProvider, loggerProxy, serializer);
TestModel> adapter = new CloudFormationCallbackAdapter<TestModel>(cloudFormationProvider, loggerProxy, serializer,
resourceTypeSchema);

adapter.refreshClient();

Expand All @@ -131,6 +138,8 @@ public void testReportProgress_IN_PROGRESS() throws JsonProcessingException {
assertThat(argument.getValue().operationStatus()).isEqualTo(IN_PROGRESS);
assertThat(argument.getValue().currentOperationStatus()).isEqualTo(PENDING);
assertThat(argument.getValue().statusMessage()).isEqualTo("doing it");

verify(resourceTypeSchema).removeWriteOnlyProperties(any(JSONObject.class));
}

@Test
Expand All @@ -147,7 +156,8 @@ public void testReportProgress_SUCCESS() {
when(client.recordHandlerProgress(any(RecordHandlerProgressRequest.class))).thenReturn(response);

final CloudFormationCallbackAdapter<
TestModel> adapter = new CloudFormationCallbackAdapter<TestModel>(cloudFormationProvider, loggerProxy, serializer);
TestModel> adapter = new CloudFormationCallbackAdapter<TestModel>(cloudFormationProvider, loggerProxy, serializer,
resourceTypeSchema);
adapter.refreshClient();

adapter.reportProgress("bearer-token", null, OperationStatus.SUCCESS, OperationStatus.IN_PROGRESS, null, "Succeeded");
Expand Down