Skip to content

Commit

Permalink
update to subscriptionfilter handler (aws-cloudformation#103)
Browse files Browse the repository at this point in the history
  • Loading branch information
markkuhn authored Jan 28, 2023
1 parent 2e4692d commit 548e7b2
Show file tree
Hide file tree
Showing 11 changed files with 193 additions and 190 deletions.
146 changes: 0 additions & 146 deletions aws-logs-subscriptionfilter/inputs/bootstrap.yaml

This file was deleted.

7 changes: 0 additions & 7 deletions aws-logs-subscriptionfilter/inputs/inputs_1_create.json

This file was deleted.

4 changes: 0 additions & 4 deletions aws-logs-subscriptionfilter/inputs/inputs_1_invalid.json

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,28 @@
import software.amazon.awssdk.awscore.exception.AwsServiceException;
import software.amazon.awssdk.core.exception.AbortedException;
import software.amazon.awssdk.services.cloudwatchlogs.CloudWatchLogsClient;
import software.amazon.awssdk.services.cloudwatchlogs.model.*;
import software.amazon.awssdk.services.cloudwatchlogs.model.CloudWatchLogsException;
import software.amazon.awssdk.services.cloudwatchlogs.model.DescribeSubscriptionFiltersRequest;
import software.amazon.awssdk.services.cloudwatchlogs.model.DescribeSubscriptionFiltersResponse;
import software.amazon.awssdk.services.cloudwatchlogs.model.InvalidParameterException;
import software.amazon.awssdk.services.cloudwatchlogs.model.LimitExceededException;
import software.amazon.awssdk.services.cloudwatchlogs.model.ResourceAlreadyExistsException;
import software.amazon.awssdk.services.cloudwatchlogs.model.ResourceNotFoundException;
import software.amazon.cloudformation.exceptions.*;
import software.amazon.cloudformation.proxy.*;
import software.amazon.awssdk.services.cloudwatchlogs.model.ServiceUnavailableException;
import software.amazon.cloudformation.exceptions.CfnAccessDeniedException;
import software.amazon.cloudformation.exceptions.CfnAlreadyExistsException;
import software.amazon.cloudformation.exceptions.CfnGeneralServiceException;
import software.amazon.cloudformation.exceptions.CfnInvalidRequestException;
import software.amazon.cloudformation.exceptions.CfnNotFoundException;
import software.amazon.cloudformation.exceptions.CfnServiceInternalErrorException;
import software.amazon.cloudformation.exceptions.CfnServiceLimitExceededException;
import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy;
import software.amazon.cloudformation.proxy.CallChain;
import software.amazon.cloudformation.proxy.HandlerErrorCode;
import software.amazon.cloudformation.proxy.Logger;
import software.amazon.cloudformation.proxy.ProgressEvent;
import software.amazon.cloudformation.proxy.ProxyClient;
import software.amazon.cloudformation.proxy.ResourceHandlerRequest;

import java.util.NoSuchElementException;

Expand Down Expand Up @@ -67,7 +85,7 @@ protected boolean isAccessDeniedError(Exception e, final Logger logger) {
e.getMessage(), e.getCause()));

if (e instanceof CloudWatchLogsException) {
if (e.getMessage() != null && e.getMessage().contains("is not authorized to perform: logs:DescribeSubscriptionFilters")) {
if (e.getMessage() != null && e.getMessage().contains("is not authorized to perform: logs:")) {
logger.log("AccessDenied exception in AccessDeniedCheck, passing");
return true;
}
Expand All @@ -90,12 +108,19 @@ protected void handleException(Exception e, Logger logger, final String stackId)
logExceptionDetails(e, logger, stackId);

if (e instanceof InvalidParameterException) {
throw new CfnInvalidRequestException(e);
throw new CfnInvalidRequestException(String.format("%s. %s", ResourceModel.TYPE_NAME, e.getMessage()), e);
} else if (e instanceof ResourceAlreadyExistsException) {
throw new CfnAlreadyExistsException(e);
} else if (e instanceof ResourceNotFoundException) {
throw new CfnNotFoundException(e);
} else if (e instanceof ServiceUnavailableException) {
throw new CfnServiceInternalErrorException(e);
} else if (e instanceof LimitExceededException) {
throw new CfnServiceLimitExceededException(e);
} else if (isAccessDeniedError(e, logger)) {
throw new CfnAccessDeniedException(e);
}
throw new CfnGeneralServiceException(e);
}

protected HandlerErrorCode getExceptionDetails(final Exception e, final Logger logger, final String stackId) {
Expand Down Expand Up @@ -133,4 +158,44 @@ protected boolean shouldThrowRetryException(final Exception e) {
|| e.getMessage().equals(ERROR_CODE_OPERATION_ABORTED_EXCEPTION);
}

protected CallChain.Completed<DescribeSubscriptionFiltersRequest, DescribeSubscriptionFiltersResponse, CloudWatchLogsClient, ResourceModel, CallbackContext> preCreateCheck(
final AmazonWebServicesClientProxy proxy, final CallbackContext callbackContext,
final ProxyClient<CloudWatchLogsClient> proxyClient, final ResourceModel model) {
return proxy.initiate("AWS-Logs-SubscriptionFilter::Create::PreExistenceCheck", proxyClient, model, callbackContext)
.translateToServiceRequest(Translator::translateToReadRequest)
.makeServiceCall((awsRequest, sdkProxyClient) -> sdkProxyClient.injectCredentialsAndInvokeV2(awsRequest,
sdkProxyClient.client()::describeSubscriptionFilters))
.handleError((request, exception, client, model1, context1) -> {
ProgressEvent<ResourceModel, CallbackContext> progress;
if (exception instanceof InvalidParameterException) {
progress = ProgressEvent.failed(model, callbackContext, HandlerErrorCode.InvalidRequest,
exception.getMessage());
} else if (exception instanceof ServiceUnavailableException) {
progress = ProgressEvent.failed(model, callbackContext, HandlerErrorCode.ServiceInternalError,
exception.getMessage());
} else if (exception instanceof ResourceNotFoundException) {
progress = ProgressEvent.progress(model, callbackContext);
} else if (exception instanceof CloudWatchLogsException) {
progress =
ProgressEvent.failed(model, callbackContext, HandlerErrorCode.GeneralServiceException,
exception.getMessage());
} else {
throw exception;
}
return progress;
});
}

protected boolean filterNameExists(final DescribeSubscriptionFiltersResponse response, ResourceModel model) {
if (response == null || response.subscriptionFilters() == null) {
return false;
}
if (!response.hasSubscriptionFilters()) {
return false;
}
if (response.subscriptionFilters().isEmpty()) {
return false;
}
return model.getFilterName().equals(response.subscriptionFilters().get(0).filterName());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,24 @@ protected ProgressEvent<ResourceModel, CallbackContext> handleRequest(
logger.log(String.format("Filter name not present. Generated: %s as FilterName for stackID: %s", resourceIdentifier, request.getStackId()));
}

return ProgressEvent.progress(request.getDesiredResourceState(), callbackContext)
return ProgressEvent.progress(model, callbackContext)
.then(progress ->
preCreateCheck(proxy, callbackContext, proxyClient, model).done(response -> {
if (filterNameExists(response, model)) {
return ProgressEvent.defaultFailureHandler(
new CfnAlreadyExistsException(ResourceModel.TYPE_NAME, model.getPrimaryIdentifier().toString()),
HandlerErrorCode.AlreadyExists
);
}
return ProgressEvent.progress(model, callbackContext);
}))
.then(progress ->
proxy.initiate(CALL_GRAPH_STRING, proxyClient, model, callbackContext)
.translateToServiceRequest(Translator::translateToCreateRequest)
.makeServiceCall((putLifecycleHookRequest, client) -> client
.injectCredentialsAndInvokeV2(putLifecycleHookRequest,
.makeServiceCall((filterRequest, client) -> client
.injectCredentialsAndInvokeV2(filterRequest,
client.client()::putSubscriptionFilter))
.handleError((autoScalingRequest, e, proxyClient1, model1, context) -> {
.handleError((req, e, proxyClient1, model1, context) -> {
// invalid parameter exception needs to be retried
if (e instanceof AwsServiceException && ((AwsServiceException)e).awsErrorDetails() != null) {
final AwsServiceException awsServiceException = (AwsServiceException) e;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package software.amazon.logs.subscriptionfilter;

import software.amazon.awssdk.services.cloudwatchlogs.CloudWatchLogsClient;
import software.amazon.cloudformation.exceptions.ResourceNotFoundException;
import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy;
import software.amazon.cloudformation.proxy.Logger;
import software.amazon.cloudformation.proxy.OperationStatus;
Expand Down Expand Up @@ -28,21 +29,26 @@ protected ProgressEvent<ResourceModel, CallbackContext> handleRequest(

return proxy.initiate(CALL_GRAPH_STRING, proxyClient, model, callbackContext)
.translateToServiceRequest(Translator::translateToReadRequest)
.makeServiceCall((cloudWatchLogsRequest, sdkProxyClient) -> {
return sdkProxyClient.injectCredentialsAndInvokeV2(cloudWatchLogsRequest,
sdkProxyClient.client()::describeSubscriptionFilters);
}).handleError((cloudWatchLogsRequest, e, _proxyClient, _model, ctx) -> {
if (isAccessDeniedError(e, logger)) {
return ProgressEvent.success(model, ctx);
} else {
final HandlerErrorCode handlerErrorCode = getExceptionDetails(e, logger, stackId);
return ProgressEvent.failed(model, callbackContext, handlerErrorCode, e.getMessage());
}
})
.makeServiceCall((cloudWatchLogsRequest, sdkProxyClient) -> sdkProxyClient.injectCredentialsAndInvokeV2(cloudWatchLogsRequest,
sdkProxyClient.client()::describeSubscriptionFilters))
.handleError((cloudWatchLogsRequest, e, pc, md, ctx) -> handleError(e, model, ctx, stackId))
.done(awsResponse -> ProgressEvent.<ResourceModel, CallbackContext>builder()
.status(OperationStatus.SUCCESS)
.resourceModel(Translator.translateFromReadResponse(awsResponse))
.build());
}

private ProgressEvent<ResourceModel, CallbackContext> handleError(
final Exception e,
final ResourceModel model,
final CallbackContext callbackContext,
final String stackId) {

if (isAccessDeniedError(e, logger) || e instanceof ResourceNotFoundException) {
return ProgressEvent.success(model, callbackContext);
}

final HandlerErrorCode handlerErrorCode = getExceptionDetails(e, logger, stackId);
return ProgressEvent.failed(model, callbackContext, handlerErrorCode, e.getMessage());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,15 @@
public class Translator {
private static final int RESPONSE_LIMIT = 50;
public static BaseHandlerException translateException(final AwsServiceException e) {
if (e instanceof LimitExceededException) {
if (e instanceof InvalidParameterException) {
return new CfnInvalidRequestException(String.format("%s. %s", ResourceModel.TYPE_NAME, e.getMessage()), e);
} else if (e instanceof LimitExceededException) {
return new CfnServiceLimitExceededException(e);
}
if (e instanceof OperationAbortedException) {
} else if (e instanceof OperationAbortedException) {
return new CfnResourceConflictException(e);
}
if (e instanceof InvalidParameterException) {
return new CfnInvalidRequestException(e);
}
else if (e instanceof ResourceNotFoundException) {
} else if (e instanceof ResourceNotFoundException) {
return new CfnNotFoundException(e);
}
else if (e instanceof ServiceUnavailableException) {
} else if (e instanceof ServiceUnavailableException) {
return new CfnServiceInternalErrorException(e);
}
return new CfnGeneralServiceException(e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,17 @@ public CloudWatchLogsClient client() {
}

static ResourceModel buildDefaultModel() {
return buildDefaultModel("filter-name");
}

static ResourceModel buildDefaultModel(String filterName) {
return ResourceModel.builder()
.filterName("filter-name")
.filterName(filterName)
.destinationArn("destination-arn")
.filterPattern("[pattern]")
.logGroupName("log-group-name")
.roleArn("role-arn")
.build();

}
}
Loading

0 comments on commit 548e7b2

Please sign in to comment.