-
Notifications
You must be signed in to change notification settings - Fork 90
/
Copy pathApp.java
169 lines (152 loc) · 8.35 KB
/
App.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
package helloworld;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.events.CloudFormationCustomResourceEvent;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import software.amazon.awssdk.awscore.exception.AwsServiceException;
import software.amazon.awssdk.core.exception.SdkClientException;
import software.amazon.awssdk.core.waiters.WaiterResponse;
import software.amazon.awssdk.http.apache.ApacheHttpClient;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.*;
import software.amazon.awssdk.services.s3.waiters.S3Waiter;
import software.amazon.lambda.powertools.cloudformation.AbstractCustomResourceHandler;
import software.amazon.lambda.powertools.cloudformation.Response;
import java.util.Objects;
/**
* Handler for requests to Lambda function.
*/
public class App extends AbstractCustomResourceHandler {
private final static Logger log = LogManager.getLogger(App.class);
private final S3Client s3Client;
public App() {
super();
s3Client = S3Client.builder().httpClientBuilder(ApacheHttpClient.builder()).build();
}
/**
* This method is invoked when CloudFormation Creates the Custom Resource.
* In this example, the method creates an Amazon S3 Bucket with the provided `BucketName`
*
* @param cloudFormationCustomResourceEvent Create Event from CloudFormation
* @param context Lambda Context
* @return Response to send to CloudFormation
*/
@Override
protected Response create(CloudFormationCustomResourceEvent cloudFormationCustomResourceEvent, Context context) {
// Validate the CloudFormation Custom Resource event
Objects.requireNonNull(cloudFormationCustomResourceEvent, "cloudFormationCustomResourceEvent cannot be null.");
Objects.requireNonNull(cloudFormationCustomResourceEvent.getResourceProperties().get("BucketName"),
"BucketName cannot be null.");
log.info(cloudFormationCustomResourceEvent);
String bucketName = (String) cloudFormationCustomResourceEvent.getResourceProperties().get("BucketName");
log.info("Bucket Name {}", bucketName);
try {
// Create the S3 bucket with the given bucketName
createBucket(bucketName);
// Return a successful response with the bucketName as the physicalResourceId
return Response.success(bucketName);
} catch (AwsServiceException | SdkClientException e) {
// In case of error, return a failed response, with the bucketName as the physicalResourceId
log.error(e);
return Response.failed(bucketName);
}
}
/**
* This method is invoked when CloudFormation Updates the Custom Resource.
* In this example, the method creates an Amazon S3 Bucket with the provided `BucketName`, if the `BucketName` differs from the previous `BucketName` (for initial creation)
*
* @param cloudFormationCustomResourceEvent Update Event from CloudFormation
* @param context Lambda Context
* @return Response to send to CloudFormation
*/
@Override
protected Response update(CloudFormationCustomResourceEvent cloudFormationCustomResourceEvent, Context context) {
// Validate the CloudFormation Custom Resource event
Objects.requireNonNull(cloudFormationCustomResourceEvent, "cloudFormationCustomResourceEvent cannot be null.");
Objects.requireNonNull(cloudFormationCustomResourceEvent.getResourceProperties().get("BucketName"),
"BucketName cannot be null.");
log.info(cloudFormationCustomResourceEvent);
// Get the physicalResourceId. physicalResourceId is the value returned to CloudFormation in the Create request, and passed in on subsequent requests (e.g. UPDATE or DELETE)
String physicalResourceId = cloudFormationCustomResourceEvent.getPhysicalResourceId();
log.info("Physical Resource ID {}", physicalResourceId);
// Get the BucketName from the CloudFormation Event
String newBucketName = (String) cloudFormationCustomResourceEvent.getResourceProperties().get("BucketName");
// Check if the physicalResourceId equals the new BucketName
if (!physicalResourceId.equals(newBucketName)) {
// The bucket name has changed - create a new bucket
try {
// Create a new bucket with the newBucketName
createBucket(newBucketName);
// Return a successful response with the newBucketName
return Response.success(newBucketName);
} catch (AwsServiceException | SdkClientException e) {
log.error(e);
return Response.failed(newBucketName);
}
} else {
// Bucket name has not changed, and no changes are needed.
// Return a successful response with the previous physicalResourceId
return Response.success(physicalResourceId);
}
}
/**
* This method is invoked when CloudFormation Deletes the Custom Resource.
* NOTE: CloudFormation will DELETE a resource, if during the UPDATE a new physicalResourceId is returned.
* Refer to the <a href="https://docs.powertools.aws.dev/lambda/java/utilities/custom_resources/#understanding-the-cloudformation-custom-resource-lifecycle">Powertools Java Documentation</a> for more details.
*
* @param cloudFormationCustomResourceEvent Delete Event from CloudFormation
* @param context Lambda Context
* @return Response to send to CloudFormation
*/
@Override
protected Response delete(CloudFormationCustomResourceEvent cloudFormationCustomResourceEvent, Context context) {
// Validate the CloudFormation Custom Resource event
Objects.requireNonNull(cloudFormationCustomResourceEvent, "cloudFormationCustomResourceEvent cannot be null.");
Objects.requireNonNull(cloudFormationCustomResourceEvent.getPhysicalResourceId(),
"PhysicalResourceId cannot be null.");
log.info(cloudFormationCustomResourceEvent);
// Get the physicalResourceId. physicalResourceId is the value provided to CloudFormation in the Create request.
String bucketName = cloudFormationCustomResourceEvent.getPhysicalResourceId();
log.info("Bucket Name {}", bucketName);
// Check if a bucket with bucketName exists
if (bucketExists(bucketName)) {
try {
// If it exists, delete the bucket
s3Client.deleteBucket(DeleteBucketRequest.builder().bucket(bucketName).build());
log.info("Bucket Deleted {}", bucketName);
// Return a successful response with bucketName as the physicalResourceId
return Response.success(bucketName);
} catch (AwsServiceException | SdkClientException e) {
// Return a failed response in case of errors during the bucket deletion
log.error(e);
return Response.failed(bucketName);
}
} else {
// If the bucket does not exist, return a successful response with the bucketName as the physicalResourceId
log.info("Bucket already deleted - no action");
return Response.success(bucketName);
}
}
private boolean bucketExists(String bucketName) {
try {
HeadBucketResponse headBucketResponse =
s3Client.headBucket(HeadBucketRequest.builder().bucket(bucketName).build());
if (headBucketResponse.sdkHttpResponse().isSuccessful()) {
return true;
}
} catch (NoSuchBucketException e) {
log.info("Bucket does not exist");
return false;
}
return false;
}
private void createBucket(String bucketName) {
S3Waiter waiter = s3Client.waiter();
CreateBucketRequest createBucketRequest = CreateBucketRequest.builder().bucket(bucketName).build();
s3Client.createBucket(createBucketRequest);
WaiterResponse<HeadBucketResponse> waiterResponse =
waiter.waitUntilBucketExists(HeadBucketRequest.builder().bucket(bucketName).build());
waiterResponse.matched().response().ifPresent(log::info);
log.info("Bucket Created {}", bucketName);
}
}