Skip to content

Commit d4fd647

Browse files
Updated initial hook example boilerplate code to target real resource type (#398)
1 parent b877c1b commit d4fd647

9 files changed

+311
-326
lines changed

python/rpdk/java/templates/init/guided_aws/HookTranslator.java

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
package {{ package_name }};
22

3-
4-
import {{ package_name }}.model.my.example.resource.MyExampleResourceTargetModel;
5-
import {{ package_name }}.model.other.example.resource.OtherExampleResourceTargetModel;
63
import software.amazon.awssdk.awscore.AwsRequest;
74
import software.amazon.cloudformation.proxy.hook.targetmodel.HookTargetModel;
85

@@ -20,28 +17,10 @@ public class Translator {
2017
* @return awsRequest the aws service request
2118
*/
2219
static AwsRequest translateToRequest(final HookTargetModel targetModel) {
23-
final AwsRequest awsRequest;
24-
if (targetModel instanceof MyExampleResourceTargetModel) {
25-
awsRequest = translateToRequest((MyExampleResourceTargetModel) targetModel);
26-
} else if (targetModel instanceof OtherExampleResourceTargetModel) {
27-
awsRequest = translateToRequest((OtherExampleResourceTargetModel) targetModel);
28-
} else {
29-
// TODO: construct a request
30-
awsRequest = null;
31-
}
32-
33-
return awsRequest;
34-
}
35-
36-
static AwsRequest translateToRequest(final MyExampleResourceTargetModel targetModel) {
3720
final AwsRequest awsRequest = null;
3821
// TODO: construct a request
39-
return awsRequest;
40-
}
22+
// e.g. https://github.com/aws-cloudformation/aws-cloudformation-resource-providers-logs/blob/2077c92299aeb9a68ae8f4418b5e932b12a8b186/aws-logs-loggroup/src/main/java/com/aws/logs/loggroup/Translator.java#L39-L43
4123

42-
static AwsRequest translateToRequest(final OtherExampleResourceTargetModel targetModel) {
43-
final AwsRequest awsRequest = null;
44-
// TODO: construct a request
4524
return awsRequest;
4625
}
4726

python/rpdk/java/templates/init/guided_aws/StubPreCreateHookHandler.java

Lines changed: 50 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
package {{ package_name }};
22

3-
import {{ package_name }}.model.my.example.resource.MyExampleResource;
4-
import {{ package_name }}.model.my.example.resource.MyExampleResourceTargetModel;
3+
import {{ package_name }}.model.aws.s3.bucket.AwsS3Bucket;
4+
import {{ package_name }}.model.aws.s3.bucket.AwsS3BucketTargetModel;
5+
import {{ package_name }}.model.aws.s3.bucket.BucketEncryption;
6+
import {{ package_name }}.model.aws.s3.bucket.ServerSideEncryptionByDefault;
7+
import {{ package_name }}.model.aws.s3.bucket.ServerSideEncryptionRule;
58
import software.amazon.awssdk.core.SdkClient;
6-
import software.amazon.cloudformation.exceptions.UnsupportedTargetException;
9+
import software.amazon.cloudformation.proxy.HandlerErrorCode;
710
import software.amazon.cloudformation.proxy.Logger;
811
import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy;
912
import software.amazon.cloudformation.proxy.OperationStatus;
@@ -28,41 +31,66 @@ public ProgressEvent<HookTargetModel, CallbackContext> handleRequest(
2831
final HookContext hookContext = request.getHookContext();
2932
final String targetName = hookContext.getTargetName();
3033

31-
if (!"My::Example::Resource".equals(targetName)) {
32-
throw new UnsupportedTargetException(targetName);
33-
}
34-
3534
logger.log(String.format("Successfully invoked {{ operation }}HookHandler for target %s.", targetName));
3635

3736
final String expectedEncryptionAlgorithm = typeConfiguration.getEncryptionAlgorithm();
3837
logger.log(String.format("Verifying server side encryption for target %s, expecting target server side encryption algorithm to be %s.",
3938
targetName, expectedEncryptionAlgorithm));
4039

41-
final ResourceHookTargetModel<MyExampleResource> targetModel = hookContext.getTargetModel(MyExampleResourceTargetModel.class);
40+
final ResourceHookTargetModel<AwsS3Bucket> targetModel = hookContext.getTargetModel(AwsS3BucketTargetModel.class);
41+
42+
final AwsS3Bucket resourceProperties = targetModel.getResourceProperties();
4243

43-
final MyExampleResource resourceProperties = targetModel.getResourceProperties();
44-
final String targetEncryptionAlgorithm = (String) resourceProperties.get("MyEncryptionAlgorithm");
44+
final String bucketName = resourceProperties.getBucketName();
4545

46-
if (targetEncryptionAlgorithm == null) {
47-
final String failureMessage = String.format("Failed to verify server side encryption for target %s, target does not have server side encryption enabled.",
48-
targetName);
46+
final BucketEncryption bucketEncryption = resourceProperties.getBucketEncryption();
47+
if (bucketEncryption == null) {
48+
String failureMessage = String.format("Bucket Encryption not configured for bucket: %s", bucketName);
4949
logger.log(failureMessage);
5050

5151
return ProgressEvent.<HookTargetModel, CallbackContext>builder()
52-
.status(OperationStatus.FAILED)
53-
.message(failureMessage)
54-
.build();
52+
.status(OperationStatus.FAILED)
53+
.errorCode(HandlerErrorCode.NonCompliant)
54+
.message(failureMessage)
55+
.build();
5556
}
5657

57-
if (!targetEncryptionAlgorithm.equals(expectedEncryptionAlgorithm)) {
58-
final String failureMessage = String.format("Failed to verify server side encryption for target %s, expecting encryption algorithm to be %s, acutal encryption algorithm is %s",
59-
targetName, expectedEncryptionAlgorithm, targetEncryptionAlgorithm);
58+
if (bucketEncryption.getServerSideEncryptionConfiguration() == null || bucketEncryption.getServerSideEncryptionConfiguration().isEmpty()) {
59+
String failureMessage = String.format("Server side encryption not configured for bucket: %s", bucketName);
6060
logger.log(failureMessage);
6161

6262
return ProgressEvent.<HookTargetModel, CallbackContext>builder()
63-
.status(OperationStatus.FAILED)
64-
.message(failureMessage)
65-
.build();
63+
.status(OperationStatus.FAILED)
64+
.errorCode(HandlerErrorCode.NonCompliant)
65+
.message(failureMessage)
66+
.build();
67+
}
68+
69+
for (final ServerSideEncryptionRule rule : bucketEncryption.getServerSideEncryptionConfiguration()) {
70+
final ServerSideEncryptionByDefault encryption = rule.getServerSideEncryptionByDefault();
71+
if (encryption == null || encryption.getSSEAlgorithm() == null) {
72+
final String failureMessage = String.format("Failed to verify server side encryption for target %s, target does not have server side encryption enabled.", targetName);
73+
logger.log(failureMessage);
74+
75+
return ProgressEvent.<HookTargetModel, CallbackContext>builder()
76+
.status(OperationStatus.FAILED)
77+
.errorCode(HandlerErrorCode.NonCompliant)
78+
.message(failureMessage)
79+
.build();
80+
}
81+
82+
if (!expectedEncryptionAlgorithm.equals(encryption.getSSEAlgorithm())) {
83+
final String failureMessage = String.format("Failed to verify server side encryption for target %s, expecting encryption algorithm to be %s, actual encryption algorithm is %s",
84+
targetName, expectedEncryptionAlgorithm, encryption.getSSEAlgorithm());
85+
logger.log(failureMessage);
86+
87+
return ProgressEvent.<HookTargetModel, CallbackContext>builder()
88+
.status(OperationStatus.FAILED)
89+
.errorCode(HandlerErrorCode.NonCompliant)
90+
.message(failureMessage)
91+
.build();
92+
}
93+
6694
}
6795

6896
final String successMessage = String.format("Successfully verified server side encryption for target %s.", targetName);

python/rpdk/java/templates/init/guided_aws/StubPreCreateHookHandlerTest.java

Lines changed: 74 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,26 @@
11
package {{ package_name }};
22

3-
import java.util.Map;
4-
import java.util.HashMap;
5-
import software.amazon.cloudformation.proxy.Logger;
6-
import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy;
7-
import software.amazon.cloudformation.proxy.OperationStatus;
8-
import software.amazon.cloudformation.proxy.ProgressEvent;
9-
import software.amazon.cloudformation.proxy.hook.HookHandlerRequest;
10-
import software.amazon.cloudformation.proxy.hook.HookContext;
11-
import software.amazon.cloudformation.proxy.hook.targetmodel.HookTargetModel;
3+
import {{ package_name }}.model.aws.s3.bucket.AwsS3Bucket;
4+
import {{ package_name }}.model.aws.s3.bucket.BucketEncryption;
5+
import {{ package_name }}.model.aws.s3.bucket.ServerSideEncryptionByDefault;
6+
import {{ package_name }}.model.aws.s3.bucket.ServerSideEncryptionRule;
127
import org.junit.jupiter.api.BeforeEach;
138
import org.junit.jupiter.api.Test;
149
import org.junit.jupiter.api.extension.ExtendWith;
1510
import org.mockito.Mock;
1611
import org.mockito.junit.jupiter.MockitoExtension;
12+
import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy;
13+
import software.amazon.cloudformation.proxy.HandlerErrorCode;
14+
import software.amazon.cloudformation.proxy.Logger;
15+
import software.amazon.cloudformation.proxy.OperationStatus;
16+
import software.amazon.cloudformation.proxy.ProgressEvent;
17+
import software.amazon.cloudformation.proxy.hook.HookContext;
18+
import software.amazon.cloudformation.proxy.hook.HookHandlerRequest;
19+
import software.amazon.cloudformation.proxy.hook.targetmodel.HookTargetModel;
20+
21+
import java.util.Collections;
22+
import java.util.HashMap;
23+
import java.util.Map;
1724

1825
import static org.assertj.core.api.Assertions.assertThat;
1926
import static org.mockito.Mockito.mock;
@@ -41,13 +48,28 @@ public void handleRequest_SimpleSuccess() {
4148
final TypeConfigurationModel typeConfiguration = mock(TypeConfigurationModel.class);
4249
when(typeConfiguration.getEncryptionAlgorithm()).thenReturn("AES256");
4350

51+
final ServerSideEncryptionByDefault serverSideEncryptionByDefault = ServerSideEncryptionByDefault.builder()
52+
.sSEAlgorithm("AES256")
53+
.build();
54+
final ServerSideEncryptionRule serverSideEncryptionRule = ServerSideEncryptionRule.builder()
55+
.serverSideEncryptionByDefault(serverSideEncryptionByDefault)
56+
.build();
57+
58+
final BucketEncryption encryption = BucketEncryption.builder()
59+
.serverSideEncryptionConfiguration(Collections.singletonList(serverSideEncryptionRule))
60+
.build();
61+
62+
final AwsS3Bucket resourceProperties = AwsS3Bucket.builder()
63+
.bucketName("MyBucket")
64+
.bucketEncryption(encryption)
65+
.build();
66+
67+
4468
final Map<String, Object> targetModel = new HashMap<>();
45-
final Map<String, Object> resourceProperties = new HashMap<>();
46-
resourceProperties.put("MyEncryptionAlgorithm", "AES256");
4769
targetModel.put("ResourceProperties", resourceProperties);
4870

4971
final HookHandlerRequest request = HookHandlerRequest.builder()
50-
.hookContext(HookContext.builder().targetName("My::Example::Resource").targetModel(HookTargetModel.of(targetModel)).build())
72+
.hookContext(HookContext.builder().targetName("AWS::S3::Bucket").targetModel(HookTargetModel.of(targetModel)).build())
5173
.build();
5274

5375
final ProgressEvent<HookTargetModel, CallbackContext> response = handler.handleRequest(proxy, request, null, logger, typeConfiguration);
@@ -56,7 +78,46 @@ public void handleRequest_SimpleSuccess() {
5678
assertThat(response.getStatus()).isEqualTo(OperationStatus.SUCCESS);
5779
assertThat(response.getCallbackContext()).isNull();
5880
assertThat(response.getCallbackDelaySeconds()).isEqualTo(0);
59-
assertThat(response.getMessage()).isNotNull();
6081
assertThat(response.getErrorCode()).isNull();
6182
}
83+
84+
@Test
85+
public void handleRequest_nonCompliant() {
86+
final {{ operation }}HookHandler handler = new {{ operation }}HookHandler();
87+
88+
final TypeConfigurationModel typeConfiguration = mock(TypeConfigurationModel.class);
89+
when(typeConfiguration.getEncryptionAlgorithm()).thenReturn("AES256");
90+
91+
final ServerSideEncryptionByDefault serverSideEncryptionByDefault = ServerSideEncryptionByDefault.builder()
92+
.sSEAlgorithm("AES128")
93+
.build();
94+
final ServerSideEncryptionRule serverSideEncryptionRule = ServerSideEncryptionRule.builder()
95+
.serverSideEncryptionByDefault(serverSideEncryptionByDefault)
96+
.build();
97+
98+
final BucketEncryption encryption = BucketEncryption.builder()
99+
.serverSideEncryptionConfiguration(Collections.singletonList(serverSideEncryptionRule))
100+
.build();
101+
102+
final AwsS3Bucket resourceProperties = AwsS3Bucket.builder()
103+
.bucketName("MyBucket")
104+
.bucketEncryption(encryption)
105+
.build();
106+
107+
108+
final Map<String, Object> targetModel = new HashMap<>();
109+
targetModel.put("ResourceProperties", resourceProperties);
110+
111+
final HookHandlerRequest request = HookHandlerRequest.builder()
112+
.hookContext(HookContext.builder().targetName("AWS::S3::Bucket").targetModel(HookTargetModel.of(targetModel)).build())
113+
.build();
114+
115+
final ProgressEvent<HookTargetModel, CallbackContext> response = handler.handleRequest(proxy, request, null, logger, typeConfiguration);
116+
117+
assertThat(response).isNotNull();
118+
assertThat(response.getStatus()).isEqualTo(OperationStatus.FAILED);
119+
assertThat(response.getCallbackContext()).isNull();
120+
assertThat(response.getCallbackDelaySeconds()).isEqualTo(0);
121+
assertThat(response.getErrorCode()).isEqualTo(HandlerErrorCode.NonCompliant);
122+
}
62123
}
Lines changed: 24 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
package {{ package_name }};
22

3-
import {{ package_name }}.model.other.example.resource.OtherExampleResource;
4-
import {{ package_name }}.model.other.example.resource.OtherExampleResourceTargetModel;
3+
import com.google.common.collect.ImmutableSet;
4+
import {{ package_name }}.model.aws.s3.bucket.AwsS3Bucket;
5+
import {{ package_name }}.model.aws.s3.bucket.AwsS3BucketTargetModel;
56
import software.amazon.awssdk.core.SdkClient;
6-
import software.amazon.cloudformation.exceptions.UnsupportedTargetException;
7-
import software.amazon.cloudformation.proxy.Logger;
87
import software.amazon.cloudformation.proxy.AmazonWebServicesClientProxy;
8+
import software.amazon.cloudformation.proxy.HandlerErrorCode;
9+
import software.amazon.cloudformation.proxy.Logger;
910
import software.amazon.cloudformation.proxy.OperationStatus;
1011
import software.amazon.cloudformation.proxy.ProgressEvent;
1112
import software.amazon.cloudformation.proxy.ProxyClient;
@@ -14,8 +15,14 @@
1415
import software.amazon.cloudformation.proxy.hook.targetmodel.HookTargetModel;
1516
import software.amazon.cloudformation.proxy.hook.targetmodel.ResourceHookTargetModel;
1617

18+
import java.util.Collection;
19+
1720
public class {{ operation }}HookHandler extends BaseHookHandlerStd {
1821

22+
private static final Collection<String> DO_NOT_DELETE_IDENTIFIERS = ImmutableSet.of(
23+
"DO_NOT_DELETE", "DO-NOT-DELETE", "do_not_delete", "do-not-delete"
24+
);
25+
1926
@Override
2027
public ProgressEvent<HookTargetModel, CallbackContext> handleRequest(
2128
final AmazonWebServicesClientProxy proxy,
@@ -28,47 +35,25 @@ public ProgressEvent<HookTargetModel, CallbackContext> handleRequest(
2835
final HookContext hookContext = request.getHookContext();
2936
final String targetName = hookContext.getTargetName();
3037

31-
if (!"Other::Example::Resource".equals(targetName)) {
32-
throw new UnsupportedTargetException(targetName);
33-
}
34-
3538
logger.log(String.format("Successfully invoked {{ operation }}HookHandler for target %s.", targetName));
3639

37-
final String expectedEncryptionAlgorithm = typeConfiguration.getEncryptionAlgorithm();
38-
logger.log(String.format("Verifying server side encryption for target %s, expecting target server side encryption algorithm to be %s.",
39-
targetName, expectedEncryptionAlgorithm));
40-
41-
final ResourceHookTargetModel<OtherExampleResource> targetModel = hookContext.getTargetModel(OtherExampleResourceTargetModel.class);
40+
final ResourceHookTargetModel<AwsS3Bucket> targetModel = hookContext.getTargetModel(AwsS3BucketTargetModel.class);
4241

43-
final OtherExampleResource resourceProperties = targetModel.getResourceProperties();
44-
final String targetEncryptionAlgorithm = (String) resourceProperties.get("OtherEncryptionAlgorithm");
42+
final AwsS3Bucket resourceProperties = targetModel.getResourceProperties();
4543

46-
if (targetEncryptionAlgorithm == null) {
47-
final String failureMessage = String.format("Failed to verify server side encryption for target %s, target does not have server side encryption enabled.",
48-
targetName);
49-
logger.log(failureMessage);
50-
51-
return ProgressEvent.<HookTargetModel, CallbackContext>builder()
52-
.status(OperationStatus.FAILED)
53-
.message(failureMessage)
54-
.build();
44+
final String bucketName = resourceProperties.getBucketName();
45+
for (final String identifier : DO_NOT_DELETE_IDENTIFIERS) {
46+
if (bucketName.contains(identifier)) {
47+
return ProgressEvent.<HookTargetModel, CallbackContext>builder()
48+
.status(OperationStatus.FAILED)
49+
.errorCode(HandlerErrorCode.NonCompliant)
50+
.message(String.format("Bucket name contains a 'DO_NOT_DELETE' identifier: %s", bucketName))
51+
.build();
52+
}
5553
}
5654

57-
if (!targetEncryptionAlgorithm.equals(expectedEncryptionAlgorithm)) {
58-
final String failureMessage = String.format("Failed to verify server side encryption for target %s, expecting encryption algorithm to be %s, acutal encryption algorithm is %s",
59-
targetName, expectedEncryptionAlgorithm, targetEncryptionAlgorithm);
60-
logger.log(failureMessage);
61-
62-
return ProgressEvent.<HookTargetModel, CallbackContext>builder()
63-
.status(OperationStatus.FAILED)
64-
.message(failureMessage)
65-
.build();
66-
}
67-
68-
final String successMessage = String.format("Successfully verified server side encryption for target %s.", targetName);
6955
return ProgressEvent.<HookTargetModel, CallbackContext>builder()
70-
.status(OperationStatus.SUCCESS)
71-
.message(successMessage)
72-
.build();
56+
.status(OperationStatus.SUCCESS)
57+
.build();
7358
}
7459
}

0 commit comments

Comments
 (0)