in resources/custom-resources/clear-s3-bucket/src/main/java/com/amazon/aws/partners/saasfactory/saasboost/ClearS3Bucket.java [50:179]
public Object handleRequest(Map<String, Object> event, Context context) {
Utils.logRequestEvent(event);
final String requestType = (String) event.get("RequestType");
Map<String, Object> resourceProperties = (Map<String, Object>) event.get("ResourceProperties");
final String bucket = (String) resourceProperties.get("Bucket");
ExecutorService service = Executors.newSingleThreadExecutor();
ObjectNode responseData = JsonNodeFactory.instance.objectNode();
try {
Runnable r = () -> {
if ("Create".equalsIgnoreCase(requestType) || "Update".equalsIgnoreCase(requestType)) {
LOGGER.info("CREATE or UPDATE");
sendResponse(event, context, "SUCCESS", responseData);
} else if ("Delete".equalsIgnoreCase(requestType)) {
LOGGER.info("DELETE");
// The list of objects in the bucket to delete
List<ObjectIdentifier> toDelete = new ArrayList<>();
// Is the bucket versioned?
GetBucketVersioningResponse versioningResponse = s3.getBucketVersioning(request -> request.bucket(bucket));
if (BucketVersioningStatus.ENABLED == versioningResponse.status() || BucketVersioningStatus.SUSPENDED == versioningResponse.status()) {
LOGGER.info("Bucket " + bucket + " is versioned (" + versioningResponse.status() + ")");
ListObjectVersionsResponse response;
String keyMarker = null;
String versionIdMarker = null;
do {
ListObjectVersionsRequest request;
if (Utils.isNotBlank(keyMarker) && Utils.isNotBlank(versionIdMarker)) {
request = ListObjectVersionsRequest.builder()
.bucket(bucket)
.keyMarker(keyMarker)
.versionIdMarker(versionIdMarker)
.build();
} else if (Utils.isNotBlank(keyMarker)) {
request = ListObjectVersionsRequest.builder()
.bucket(bucket)
.keyMarker(keyMarker)
.build();
} else {
request = ListObjectVersionsRequest.builder()
.bucket(bucket)
.build();
}
response = s3.listObjectVersions(request);
keyMarker = response.nextKeyMarker();
versionIdMarker = response.nextVersionIdMarker();
response.versions()
.stream()
.map(version ->
ObjectIdentifier.builder()
.key(version.key())
.versionId(version.versionId())
.build()
)
.forEachOrdered(toDelete::add);
} while (response.isTruncated());
} else {
LOGGER.info("Bucket " + bucket + " is not versioned (" + versioningResponse.status() + ")");
ListObjectsV2Response response;
String token = null;
do {
ListObjectsV2Request request;
if (Utils.isNotBlank(token)) {
request = ListObjectsV2Request.builder()
.bucket(bucket)
.continuationToken(token)
.build();
} else {
request = ListObjectsV2Request.builder()
.bucket(bucket)
.build();
}
response = s3.listObjectsV2(request);
token = response.nextContinuationToken();
response.contents()
.stream()
.map(obj ->
ObjectIdentifier.builder()
.key(obj.key())
.build()
)
.forEachOrdered(toDelete::add);
} while (response.isTruncated());
}
if (!toDelete.isEmpty()) {
LOGGER.info("Deleting " + toDelete.size() + " objects");
final int maxBatchSize = 1000;
int batchStart = 0;
int batchEnd = 0;
while (batchEnd < toDelete.size()) {
batchStart = batchEnd;
batchEnd += maxBatchSize;
if (batchEnd > toDelete.size()) {
batchEnd = toDelete.size();
}
Delete delete = Delete.builder()
.objects(toDelete.subList(batchStart, batchEnd))
.build();
DeleteObjectsResponse deleteResponse = s3.deleteObjects(builder -> builder
.bucket(bucket)
.delete(delete)
);
LOGGER.info("Cleaned up " + deleteResponse.deleted().size() + " objects in bucket " + bucket);
}
} else {
LOGGER.info("Bucket " + bucket + " is empty. No objects to clean up.");
}
sendResponse(event, context, "SUCCESS", responseData);
} else {
LOGGER.error("FAILED unknown requestType " + requestType);
responseData.put("Reason", "Unknown RequestType " + requestType);
sendResponse(event, context, "FAILED", responseData);
}
};
Future<?> f = service.submit(r);
f.get(context.getRemainingTimeInMillis() - 1000, TimeUnit.MILLISECONDS);
} catch (final TimeoutException | InterruptedException | ExecutionException e) {
// Timed out
LOGGER.error("FAILED unexpected error or request timed out " + e.getMessage());
String stackTrace = Utils.getFullStackTrace(e);
LOGGER.error(stackTrace);
responseData.put("Reason", stackTrace);
sendResponse(event, context, "FAILED", responseData);
} finally {
service.shutdown();
}
return null;
}