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
3 changes: 3 additions & 0 deletions .github/workflows/pr-ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ jobs:
- name: Verify java package
run:
mvn verify
- name: Install java package
run:
mvn install
- name: Integration standard e2e
run:
./e2e_test.sh 1
Expand Down
20 changes: 19 additions & 1 deletion python/rpdk/java/codegen.py
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,7 @@ def generate(self, project):
contents = template.render(
package_name=self.package_name,
operations=project.schema.get("handlers", {}).keys(),
contains_type_configuration=project.configuration_schema,
pojo_name="ResourceModel",
wrapper_parent="LambdaWrapper",
)
Expand All @@ -384,12 +385,25 @@ def generate(self, project):
contents = template.render(
package_name=self.package_name,
operations=OPERATIONS,
contains_type_configuration=project.configuration_schema,
pojo_name="ResourceModel",
)
project.overwrite(path, contents)

# generate POJOs
models = resolve_models(project.schema)
if project.configuration_schema:
configuration_schema_path = (
self._get_generated_root(project)
/ project.configuration_schema_filename
)
project.write_configuration_schema(configuration_schema_path)
configuration_models = resolve_models(
project.configuration_schema, "TypeConfigurationModel"
)
else:
configuration_models = {"TypeConfigurationModel": {}}
models.update(configuration_models)

LOG.debug("Writing %d POJOs", len(models))

Expand All @@ -416,6 +430,9 @@ def generate(self, project):
package_name=self.package_name,
model_name=model_name,
properties=properties,
no_args_constructor_required=(
model_name != "TypeConfigurationModel" or len(properties) != 0
),
)
project.overwrite(path, contents)

Expand All @@ -439,6 +456,7 @@ def _write_executable_wrapper_class(self, src, project):
package_name=self.package_name,
operations=project.schema.get("handlers", {}).keys(),
pojo_name="ResourceModel",
contains_type_configuration=project.configuration_schema,
wrapper_parent="ExecutableWrapper",
)
project.overwrite(path, contents)
Expand Down Expand Up @@ -495,7 +513,7 @@ def _find_jar(project):
(project.root / "target").glob("{}-*.jar".format(project.hypenated_name))
)
if not jar_glob:
LOG.debug("No Java ARchives match")
LOG.debug("No Java Archives matched at %s", str(project.root / "target"))
raise JavaArchiveNotFoundError(
"No JAR artifact was found.\n"
"Please run 'mvn package' or the equivalent command "
Expand Down
5 changes: 2 additions & 3 deletions python/rpdk/java/templates/generate/BaseHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,11 @@
import software.amazon.cloudformation.proxy.ProgressEvent;
import software.amazon.cloudformation.proxy.ResourceHandlerRequest;

public abstract class BaseHandler<CallbackT> {
public abstract class BaseHandler<CallbackT{{ ', ConfigurationT' if contains_type_configuration }}> {

public abstract ProgressEvent<{{ pojo_name }}, CallbackT> handleRequest(
final AmazonWebServicesClientProxy proxy,
final ResourceHandlerRequest<{{ pojo_name }}> request,
final CallbackT callbackContext,
final Logger logger);

final Logger logger{{ ',\n final ConfigurationT typeConfiguration' if contains_type_configuration }});
}
46 changes: 27 additions & 19 deletions python/rpdk/java/templates/generate/HandlerWrapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,17 +42,17 @@
import org.json.JSONObject;


public class {{ "HandlerWrapper" if wrapper_parent == "LambdaWrapper" else "HandlerWrapperExecutable" }} extends {{ wrapper_parent }}<{{ pojo_name }}, CallbackContext> {
public class {{ "HandlerWrapper" if wrapper_parent == "LambdaWrapper" else "HandlerWrapperExecutable" }} extends {{ wrapper_parent }}<{{ pojo_name }}, CallbackContext, TypeConfigurationModel> {

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>>() {};
private final Map<Action, BaseHandler<CallbackContext{{ ', TypeConfigurationModel' if contains_type_configuration }}>> handlers = new HashMap<>();
private final static TypeReference<HandlerRequest<{{ pojo_name }}, CallbackContext, TypeConfigurationModel>> REQUEST_REFERENCE =
new TypeReference<HandlerRequest<{{ pojo_name }}, CallbackContext, TypeConfigurationModel>>() {};
private final static TypeReference<{{ pojo_name }}> TYPE_REFERENCE =
new TypeReference<{{ pojo_name }}>() {};
private final static TypeReference<ResourceHandlerTestPayload<{{ pojo_name }}, CallbackContext>> TEST_ENTRY_TYPE_REFERENCE =
new TypeReference<ResourceHandlerTestPayload<{{ pojo_name }}, CallbackContext>>() {};
private final static TypeReference<ResourceHandlerTestPayload<{{ pojo_name }}, CallbackContext, TypeConfigurationModel>> TEST_ENTRY_TYPE_REFERENCE =
new TypeReference<ResourceHandlerTestPayload<{{ pojo_name }}, CallbackContext, TypeConfigurationModel>>() {};


public {{ "HandlerWrapper" if wrapper_parent == "LambdaWrapper" else "HandlerWrapperExecutable" }}() {
Expand All @@ -67,18 +67,22 @@ private void initialiseHandlers() {

@Override
public ProgressEvent<{{ pojo_name }}, CallbackContext> invokeHandler(
final AmazonWebServicesClientProxy proxy,
final ResourceHandlerRequest<{{ pojo_name }}> request,
final Action action,
final CallbackContext callbackContext) {
final AmazonWebServicesClientProxy proxy,
final ResourceHandlerRequest<{{ pojo_name }}> request,
final Action action,
final CallbackContext callbackContext,
final TypeConfigurationModel typeConfiguration) {

final String actionName = (action == null) ? "<null>" : action.toString(); // paranoia
if (!handlers.containsKey(action))
throw new RuntimeException("Unknown action " + actionName);

final BaseHandler<CallbackContext> handler = handlers.get(action);

final BaseHandler<CallbackContext{{ ', TypeConfigurationModel' if contains_type_configuration }}> handler = handlers.get(action);

loggerProxy.log(String.format("[%s] invoking handler...", actionName));
final ProgressEvent<{{ pojo_name }}, CallbackContext> result = handler.handleRequest(proxy, request, callbackContext, loggerProxy);
final ProgressEvent<{{ pojo_name }}, CallbackContext> result = handler.handleRequest(proxy, request,
callbackContext, loggerProxy{{ ', typeConfiguration' if contains_type_configuration }});
loggerProxy.log(String.format("[%s] handler invoked", actionName));
return result;
}
Expand All @@ -94,18 +98,20 @@ public void testEntrypoint(
this.loggerProxy = new LoggerProxy();
this.loggerProxy.addLogPublisher(new LambdaLogPublisher(context.getLogger()));

ProgressEvent<{{ pojo_name }}, CallbackContext> response = ProgressEvent.failed(null, null, HandlerErrorCode.InternalFailure, "Uninitialized");
ProgressEvent<{{ pojo_name }}, CallbackContext> response = ProgressEvent.failed(null, null,
HandlerErrorCode.InternalFailure, "Uninitialized");
try {
final String input = IOUtils.toString(inputStream, "UTF-8");
final ResourceHandlerTestPayload<{{ pojo_name }}, CallbackContext> payload =
final ResourceHandlerTestPayload<{{ pojo_name }}, CallbackContext, TypeConfigurationModel> payload =
this.serializer.deserialize(
input,
TEST_ENTRY_TYPE_REFERENCE);

final AmazonWebServicesClientProxy proxy = new AmazonWebServicesClientProxy(
loggerProxy, payload.getCredentials(), () -> (long) context.getRemainingTimeInMillis());

response = invokeHandler(proxy, payload.getRequest(), payload.getAction(), payload.getCallbackContext());
response = invokeHandler(proxy, payload.getRequest(), payload.getAction(), payload.getCallbackContext(),
payload.getTypeConfiguration());
} catch (final BaseHandlerException e) {
response = ProgressEvent.defaultFailureHandler(e, e.getErrorCode());
} catch (final AmazonServiceException | AwsServiceException e) {
Expand Down Expand Up @@ -135,7 +141,7 @@ public static void main(String[] args) throws IOException {
System.out.println("__CFN_RESOURCE_END_RESPONSE__");
}

private static void readFileToSystemOut(final String fileName) throws IOException {
private static void readFileToSystemOut(final String fileName) throws IOException {
//Create object of FileReader
final FileReader inputFile = new FileReader(fileName);
try(BufferedReader bufferReader = new BufferedReader(inputFile)) {
Expand All @@ -161,8 +167,10 @@ public Map<String, String> provideResourceDefinedTags(final {{ pojo_name}} resou
}

@Override
protected ResourceHandlerRequest<{{ pojo_name }}> transform(final HandlerRequest<{{ pojo_name }}, CallbackContext> request) throws IOException {
final RequestData<{{ pojo_name }}> requestData = request.getRequestData();
protected ResourceHandlerRequest<{{ pojo_name }}> transform(
final HandlerRequest<{{ pojo_name }}, CallbackContext,TypeConfigurationModel> request) throws IOException {

final RequestData<{{ pojo_name }}, TypeConfigurationModel> requestData = request.getRequestData();

return ResourceHandlerRequest.<{{ pojo_name }}>builder()
.clientRequestToken(request.getBearerToken())
Expand All @@ -179,7 +187,7 @@ public Map<String, String> provideResourceDefinedTags(final {{ pojo_name}} resou
}

@Override
protected TypeReference<HandlerRequest<{{ pojo_name }}, CallbackContext>> getTypeReference() {
protected TypeReference<HandlerRequest<{{ pojo_name }}, CallbackContext, TypeConfigurationModel>> getTypeReference() {
return REQUEST_REFERENCE;
}

Expand Down
9 changes: 3 additions & 6 deletions python/rpdk/java/templates/generate/POJO.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,13 @@
import java.util.Map;
import java.util.List;
import java.util.Set;
import lombok.AllArgsConstructor;
import lombok.AllArgsConstructor;{{ '\nimport lombok.NoArgsConstructor;' if no_args_constructor_required }}
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;


@Data
@Builder(toBuilder = true)
@AllArgsConstructor
@NoArgsConstructor
@Builder
@AllArgsConstructor{{ '\n@NoArgsConstructor' if no_args_constructor_required }}
@JsonAutoDetect(fieldVisibility = Visibility.ANY, getterVisibility = Visibility.NONE, setterVisibility = Visibility.NONE)
public class {{ model_name|uppercase_first_letter }} {
{% for name, type in properties.items() %}
Expand Down
41 changes: 24 additions & 17 deletions src/main/java/software/amazon/cloudformation/AbstractWrapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@
import software.amazon.cloudformation.resource.Validator;
import software.amazon.cloudformation.resource.exceptions.ValidationException;

public abstract class AbstractWrapper<ResourceT, CallbackT> {
public abstract class AbstractWrapper<ResourceT, CallbackT, ConfigurationT> {

public static final SdkHttpClient HTTP_CLIENT = ApacheHttpClient.builder().build();

Expand All @@ -90,7 +90,7 @@ public abstract class AbstractWrapper<ResourceT, CallbackT> {
protected final CloudWatchProvider providerCloudWatchProvider;
protected final CloudWatchLogsProvider cloudWatchLogsProvider;
protected final SchemaValidator validator;
protected final TypeReference<HandlerRequest<ResourceT, CallbackT>> typeReference;
protected final TypeReference<HandlerRequest<ResourceT, CallbackT, ConfigurationT>> typeReference;

protected MetricsPublisher providerMetricsPublisher;

Expand Down Expand Up @@ -179,7 +179,7 @@ public void processRequest(final InputStream inputStream, final OutputStream out
TerminalException {

ProgressEvent<ResourceT, CallbackT> handlerResponse = null;
HandlerRequest<ResourceT, CallbackT> request = null;
HandlerRequest<ResourceT, CallbackT, ConfigurationT> request = null;
scrubFiles();
try {
if (inputStream == null) {
Expand Down Expand Up @@ -239,7 +239,8 @@ public void processRequest(final InputStream inputStream, final OutputStream out
}

private ProgressEvent<ResourceT, CallbackT>
processInvocation(final JSONObject rawRequest, final HandlerRequest<ResourceT, CallbackT> request) throws IOException,
processInvocation(final JSONObject rawRequest, final HandlerRequest<ResourceT, CallbackT, ConfigurationT> request)
throws IOException,
TerminalException {
assert request != null : "Invalid request object received";

Expand All @@ -260,6 +261,7 @@ public void processRequest(final InputStream inputStream, final OutputStream out

// transform the request object to pass to caller
ResourceHandlerRequest<ResourceT> resourceHandlerRequest = transform(request);
ConfigurationT typeConfiguration = request.getRequestData().getTypeConfiguration();

if (resourceHandlerRequest != null) {
resourceHandlerRequest.setPreviousResourceTags(getPreviousResourceTags(request));
Expand Down Expand Up @@ -325,7 +327,7 @@ public void processRequest(final InputStream inputStream, final OutputStream out
}

ProgressEvent<ResourceT, CallbackT> handlerResponse = wrapInvocationAndHandleErrors(awsClientProxy,
resourceHandlerRequest, request, callbackContext);
resourceHandlerRequest, request, callbackContext, typeConfiguration);

if (handlerResponse.getStatus() == OperationStatus.IN_PROGRESS && !isMutatingAction) {
throw new TerminalException("READ and LIST handlers must return synchronously.");
Expand All @@ -334,8 +336,9 @@ public void processRequest(final InputStream inputStream, final OutputStream out
return handlerResponse;
}

private void
logUnhandledError(final String errorDescription, final HandlerRequest<ResourceT, CallbackT> request, final Throwable e) {
private void logUnhandledError(final String errorDescription,
final HandlerRequest<ResourceT, CallbackT, ConfigurationT> request,
final Throwable e) {
log(String.format("%s in a %s action on a %s: %s%n%s", errorDescription, request.getAction(), request.getResourceType(),
e.toString(), ExceptionUtils.getStackTrace(e)));
}
Expand All @@ -349,13 +352,14 @@ public void processRequest(final InputStream inputStream, final OutputStream out
private ProgressEvent<ResourceT, CallbackT>
wrapInvocationAndHandleErrors(final AmazonWebServicesClientProxy awsClientProxy,
final ResourceHandlerRequest<ResourceT> resourceHandlerRequest,
final HandlerRequest<ResourceT, CallbackT> request,
final CallbackT callbackContext) {
final HandlerRequest<ResourceT, CallbackT, ConfigurationT> request,
final CallbackT callbackContext,
final ConfigurationT typeConfiguration) {

Date startTime = Date.from(Instant.now());
try {
ProgressEvent<ResourceT, CallbackT> handlerResponse = invokeHandler(awsClientProxy, resourceHandlerRequest,
request.getAction(), callbackContext);
request.getAction(), callbackContext, typeConfiguration);
if (handlerResponse != null) {
this.log(String.format("Handler returned %s", handlerResponse.getStatus()));
} else {
Expand Down Expand Up @@ -384,7 +388,8 @@ public void processRequest(final InputStream inputStream, final OutputStream out

}

protected void writeResponse(final OutputStream outputStream, final ProgressEvent<ResourceT, CallbackT> response)
protected void writeResponse(final OutputStream outputStream,
final ProgressEvent<ResourceT, CallbackT> response)
throws IOException {
if (response.getResourceModel() != null) {
// strip write only properties on final results, we will need the intact model
Expand Down Expand Up @@ -437,7 +442,7 @@ private void validateModel(final JSONObject modelObject) throws ValidationExcept
* and is not needed by the handler implementations
* @return A converted ResourceHandlerRequest model
*/
protected abstract ResourceHandlerRequest<ResourceT> transform(HandlerRequest<ResourceT, CallbackT> request)
protected abstract ResourceHandlerRequest<ResourceT> transform(HandlerRequest<ResourceT, CallbackT, ConfigurationT> request)
throws IOException;

/**
Expand Down Expand Up @@ -465,14 +470,16 @@ protected abstract ResourceHandlerRequest<ResourceT> transform(HandlerRequest<Re
* {@link Action#DELETE}, {@link Action#READ} {@link Action#LIST} or
* {@link Action#UPDATE}
* @param callbackContext the callback context to handle reentrant calls
* @param typeConfiguration the configuration for the type set by type consumer
* @return progress event indicating success, in progress with delay callback or
* failed state
* @throws Exception propagate any unexpected errors
*/
public abstract ProgressEvent<ResourceT, CallbackT> invokeHandler(AmazonWebServicesClientProxy proxy,
ResourceHandlerRequest<ResourceT> request,
Action action,
CallbackT callbackContext)
CallbackT callbackContext,
ConfigurationT typeConfiguration)
throws Exception;

/*
Expand Down Expand Up @@ -512,7 +519,7 @@ private void log(final String message) {
}
}

protected abstract TypeReference<HandlerRequest<ResourceT, CallbackT>> getTypeReference();
protected abstract TypeReference<HandlerRequest<ResourceT, CallbackT, ConfigurationT>> getTypeReference();

protected abstract TypeReference<ResourceT> getModelTypeReference();

Expand All @@ -536,7 +543,7 @@ protected void scrubFiles() {
* @return a Map of Tag names to Tag values
*/
@VisibleForTesting
protected Map<String, String> getDesiredResourceTags(final HandlerRequest<ResourceT, CallbackT> request) {
protected Map<String, String> getDesiredResourceTags(final HandlerRequest<ResourceT, CallbackT, ConfigurationT> request) {
Map<String, String> desiredResourceTags = new HashMap<>();
JSONObject object;

Expand All @@ -559,7 +566,7 @@ protected Map<String, String> getDesiredResourceTags(final HandlerRequest<Resour
* @return a Map of Tag names to Tag values
*/
@VisibleForTesting
protected Map<String, String> getPreviousResourceTags(final HandlerRequest<ResourceT, CallbackT> request) {
protected Map<String, String> getPreviousResourceTags(final HandlerRequest<ResourceT, CallbackT, ConfigurationT> request) {
Map<String, String> previousResourceTags = new HashMap<>();

if (request != null && request.getRequestData() != null) {
Expand All @@ -574,7 +581,7 @@ protected Map<String, String> getPreviousResourceTags(final HandlerRequest<Resou
}

@VisibleForTesting
protected String getStackId(final HandlerRequest<ResourceT, CallbackT> request) {
protected String getStackId(final HandlerRequest<ResourceT, CallbackT, ConfigurationT> request) {
if (request != null) {
return request.getStackId();
}
Expand Down
Loading