Skip to content

Commit a8b93db

Browse files
committed
Correct issues discovered with the self-service integration tests
The self-service integration tests revealed that the handlers had mistakes and needs corrections. These are all the changes necessary to pass self-service integration tests fully when running against Uluru resources.
1 parent 5e8602c commit a8b93db

File tree

18 files changed

+268
-109
lines changed

18 files changed

+268
-109
lines changed

aws-transfer-agreement/.rpdk-config

+3-1
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,7 @@
2222
"protocolVersion": "2.0.0"
2323
},
2424
"logProcessorEnabled": "true",
25-
"executableEntrypoint": "software.amazon.transfer.agreement.HandlerWrapperExecutable"
25+
"executableEntrypoint": "software.amazon.transfer.agreement.HandlerWrapperExecutable",
26+
"contractSettings": {},
27+
"canarySettings": {}
2628
}

aws-transfer-certificate/.rpdk-config

+3-1
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,7 @@
2525
"protocolVersion": "2.0.0"
2626
},
2727
"logProcessorEnabled": "true",
28-
"executableEntrypoint": "software.amazon.transfer.certificate.HandlerWrapperExecutable"
28+
"executableEntrypoint": "software.amazon.transfer.certificate.HandlerWrapperExecutable",
29+
"contractSettings": {},
30+
"canarySettings": {}
2931
}

aws-transfer-connector/.rpdk-config

+3-1
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,7 @@
2222
"protocolVersion": "2.0.0"
2323
},
2424
"logProcessorEnabled": "true",
25-
"executableEntrypoint": "software.amazon.transfer.connector.HandlerWrapperExecutable"
25+
"executableEntrypoint": "software.amazon.transfer.connector.HandlerWrapperExecutable",
26+
"contractSettings": {},
27+
"canarySettings": {}
2628
}

aws-transfer-profile/.rpdk-config

+3-1
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,7 @@
2222
"protocolVersion": "2.0.0"
2323
},
2424
"logProcessorEnabled": "true",
25-
"executableEntrypoint": "software.amazon.transfer.profile.HandlerWrapperExecutable"
25+
"executableEntrypoint": "software.amazon.transfer.profile.HandlerWrapperExecutable",
26+
"contractSettings": {},
27+
"canarySettings": {}
2628
}

aws-transfer-server/.rpdk-config

+3-1
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,7 @@
2626
"protocolVersion": "2.0.0"
2727
},
2828
"logProcessorEnabled": "true",
29-
"executableEntrypoint": "software.amazon.transfer.server.HandlerWrapperExecutable"
29+
"executableEntrypoint": "software.amazon.transfer.server.HandlerWrapperExecutable",
30+
"contractSettings": {},
31+
"canarySettings": {}
3032
}

aws-transfer-server/src/main/java/software/amazon/transfer/server/BaseHandlerStd.java

+3
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,9 @@ protected boolean isVpcServerEndpoint(ResourceModel model) {
310310
}
311311

312312
protected boolean privateIpsAvailable(List<String> allocationIds, ProxyClient<Ec2Client> ec2Client) {
313+
if (allocationIds.isEmpty()) {
314+
return true; // no IPs to check against, so assume available
315+
}
313316
DescribeAddressesRequest request =
314317
DescribeAddressesRequest.builder().allocationIds(allocationIds).build();
315318
try (Ec2Client client = ec2Client.client()) {

aws-transfer-server/src/main/java/software/amazon/transfer/server/CreateHandler.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
import software.amazon.transfer.server.translators.WorkflowDetailsTranslator;
2929

3030
import com.amazonaws.regions.Region;
31-
import com.amazonaws.regions.Regions;
31+
import com.amazonaws.regions.RegionUtils;
3232

3333
public class CreateHandler extends BaseHandlerStd {
3434

@@ -45,7 +45,7 @@ protected ProgressEvent<ResourceModel, CallbackContext> handleRequest(
4545
final String clientRequestToken = request.getClientRequestToken();
4646
ResourceModel newModel = request.getDesiredResourceState();
4747

48-
prepareDesiredResourceModel(request, newModel);
48+
prepareDesiredResourceModel(request, newModel, true);
4949

5050
return ProgressEvent.progress(newModel, callbackContext)
5151
.then(progress -> proxy.initiate(
@@ -106,7 +106,7 @@ private boolean stabilizeAfterCreate(
106106
CallbackContext ignored2) {
107107

108108
String serverId = awsResponse.serverId();
109-
Region region = Region.getRegion(Regions.fromName(request.getRegion()));
109+
Region region = RegionUtils.getRegion(request.getRegion());
110110
ServerArn serverArn = new ServerArn(region, request.getAwsAccountId(), serverId);
111111
model.setArn(serverArn.getArn());
112112
model.setServerId(serverId);

aws-transfer-server/src/main/java/software/amazon/transfer/server/UpdateHandler.java

+73-59
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,16 @@
22

33
import static software.amazon.transfer.server.translators.ResourceModelAdapter.prepareDesiredResourceModel;
44
import static software.amazon.transfer.server.translators.ResourceModelAdapter.preparePreviousResourceModel;
5+
import static software.amazon.transfer.server.translators.Translator.emptyListIfNull;
6+
import static software.amazon.transfer.server.translators.Translator.emptyStringIfNull;
57
import static software.amazon.transfer.server.translators.Translator.translateToSdkProtocols;
68

9+
import java.util.ArrayList;
710
import java.util.Collection;
811
import java.util.Collections;
9-
import java.util.HashSet;
1012
import java.util.List;
1113
import java.util.Map;
1214
import java.util.Objects;
13-
import java.util.Optional;
1415
import java.util.Set;
1516

1617
import org.apache.commons.lang3.StringUtils;
@@ -58,7 +59,7 @@ protected ProgressEvent<ResourceModel, CallbackContext> handleRequest(
5859
Translator.ensureServerIdInModel(oldModel);
5960
Translator.ensureServerIdInModel(newModel);
6061

61-
prepareDesiredResourceModel(request, newModel);
62+
prepareDesiredResourceModel(request, newModel, false);
6263
preparePreviousResourceModel(request, oldModel);
6364

6465
return ProgressEvent.progress(request.getDesiredResourceState(), callbackContext)
@@ -101,13 +102,21 @@ private Boolean stabilizeAfterUpdate(
101102
String serverId = model.getServerId();
102103
DescribedServer describedServer = describeServer(client, model);
103104

105+
// Always check if the VPC endpoint is ready to modify
106+
if (EndpointType.VPC.equals(describedServer.endpointType())) {
107+
String vpcEndpointId = describedServer.endpointDetails().vpcEndpointId();
108+
if (!waitForVpcEndpoint(vpcEndpointId, ec2Client, model)) {
109+
return false;
110+
}
111+
}
112+
104113
List<String> proposedSubnetIds;
105114
List<String> proposedAddressAllocationIds;
106115

107116
if (model.getEndpointDetails() != null) {
108-
proposedSubnetIds = nullableList(model.getEndpointDetails().getSubnetIds());
117+
proposedSubnetIds = emptyListIfNull(model.getEndpointDetails().getSubnetIds());
109118
proposedAddressAllocationIds =
110-
nullableList(model.getEndpointDetails().getAddressAllocationIds());
119+
emptyListIfNull(model.getEndpointDetails().getAddressAllocationIds());
111120
} else {
112121
proposedSubnetIds = Collections.emptyList();
113122
proposedAddressAllocationIds = Collections.emptyList();
@@ -124,15 +133,23 @@ private Boolean stabilizeAfterUpdate(
124133
currentAddressAllocationIds = Collections.emptyList();
125134
}
126135

136+
log(String.format("Endpoint current subnet IDs: %s", currentSubnetIds), serverId);
137+
log(String.format("Endpoint proposed subnet IDs: %s", proposedSubnetIds), serverId);
138+
log(String.format("Endpoint current address allocation IDs: %s", currentAddressAllocationIds), serverId);
139+
log(String.format("Endpoint proposed address allocation IDs: %s", proposedAddressAllocationIds), serverId);
140+
127141
State state = describedServer.state();
128142
switch (state) {
129143
case OFFLINE:
130144
if (!Objects.equals(proposedSubnetIds, currentSubnetIds)) {
131-
EndpointDetails removeAddressAllocationIds = EndpointDetails.builder()
132-
.addressAllocationIds(Collections.emptyList())
133-
.build();
134-
updateServerEndpointDetails(client, serverId, removeAddressAllocationIds);
135-
145+
if (!currentAddressAllocationIds.isEmpty()) {
146+
EndpointDetails removeAddressAllocationIds = EndpointDetails.builder()
147+
.addressAllocationIds(Collections.emptyList())
148+
.build();
149+
log("EIP address allocation IDs are removed for subnet update.", serverId);
150+
updateServerEndpointDetails(client, serverId, removeAddressAllocationIds);
151+
return false;
152+
}
136153
EndpointDetails updateSubnets = EndpointDetails.builder()
137154
.subnetIds(proposedSubnetIds)
138155
.build();
@@ -151,8 +168,7 @@ private Boolean stabilizeAfterUpdate(
151168
return false;
152169
}
153170

154-
if (!currentAddressAllocationIds.isEmpty()
155-
&& !privateIpsAvailable(currentAddressAllocationIds, ec2Client)) {
171+
if (!privateIpsAvailable(currentAddressAllocationIds, ec2Client)) {
156172
log("is waiting for endpoint private IPs", serverId);
157173
return false;
158174
}
@@ -161,14 +177,8 @@ private Boolean stabilizeAfterUpdate(
161177
log("is going ONLINE after update.", serverId);
162178
return false;
163179
case ONLINE:
164-
if (EndpointType.VPC.equals(describedServer.endpointType())) {
165-
String vpcEndpointId = describedServer.endpointDetails().vpcEndpointId();
166-
if (!waitForVpcEndpoint(vpcEndpointId, ec2Client, model)) {
167-
return false;
168-
}
169-
}
170-
171-
if (Objects.equals(proposedAddressAllocationIds, currentAddressAllocationIds)) {
180+
if (Objects.equals(proposedSubnetIds, currentSubnetIds)
181+
&& Objects.equals(proposedAddressAllocationIds, currentAddressAllocationIds)) {
172182
log("update has been stabilized.", serverId);
173183
return true; // no update needed, we are done
174184
}
@@ -182,10 +192,6 @@ private Boolean stabilizeAfterUpdate(
182192
}
183193
}
184194

185-
private List<String> nullableList(List<String> subnetIds) {
186-
return Optional.ofNullable(subnetIds).orElse(Collections.emptyList());
187-
}
188-
189195
private ProgressEvent<ResourceModel, CallbackContext> updateSecurityGroups(
190196
ProgressEvent<ResourceModel, CallbackContext> progress,
191197
ResourceModel oldModel,
@@ -201,52 +207,57 @@ private ProgressEvent<ResourceModel, CallbackContext> updateSecurityGroups(
201207
return progress; // skip this step
202208
}
203209

204-
Set<String> sgIdSet = new HashSet<>();
205-
Set<String> prevSgIdSet = new HashSet<>();
210+
List<String> requested = List.of();
211+
List<String> previous = List.of();
206212
if (isVpcServerEndpoint(oldModel)) {
207-
prevSgIdSet = new HashSet<>(
208-
Optional.ofNullable(oldModel.getEndpointDetails().getSecurityGroupIds())
209-
.orElse(Collections.emptyList()));
213+
previous = emptyListIfNull(oldModel.getEndpointDetails().getSecurityGroupIds());
210214
}
211215
if (isVpcServerEndpoint(newModel)) {
212-
sgIdSet = new HashSet<>(
213-
Optional.ofNullable(newModel.getEndpointDetails().getSecurityGroupIds())
214-
.orElse(Collections.emptyList()));
215-
;
216+
requested = emptyListIfNull(newModel.getEndpointDetails().getSecurityGroupIds());
216217
}
217218

218-
Set<String> sgIdsToAdd = new HashSet<>(sgIdSet);
219-
sgIdsToAdd.removeAll(prevSgIdSet);
220-
Set<String> sgIdsToRemove = new HashSet<>(prevSgIdSet);
221-
sgIdsToRemove.removeAll(sgIdSet);
219+
List<String> toAdd = new ArrayList<>(requested);
220+
toAdd.removeAll(previous);
221+
List<String> toRemove = new ArrayList<>(previous);
222+
toRemove.removeAll(requested);
222223

223-
if (sgIdsToAdd.isEmpty() && sgIdsToRemove.isEmpty()) {
224+
String serverId = newModel.getServerId();
225+
if (toAdd.isEmpty() && toRemove.isEmpty()) {
226+
log("VPC endpoint has no modifications for security groups", serverId);
224227
return progress; // skip this step
225228
}
226229

230+
if (!toAdd.isEmpty()) {
231+
log(String.format("security group IDs to add: %s", toAdd), serverId);
232+
}
233+
if (!toRemove.isEmpty()) {
234+
log(String.format("security group IDs to remove: %s", toRemove), serverId);
235+
}
236+
227237
return proxy.initiate(
228238
"AWS-Transfer-Server::Update::updateSecurityGroups",
229239
proxyEc2Client,
230240
progress.getResourceModel(),
231241
progress.getCallbackContext())
232-
.translateToServiceRequest(m -> modifyVpcEndpointRequest(vpcEndpointId, sgIdsToAdd, sgIdsToRemove))
233-
.makeServiceCall((awsRequest, client) -> {
234-
try (Ec2Client ec2Client = client.client()) {
235-
ModifyVpcEndpointResponse awsResponse =
236-
client.injectCredentialsAndInvokeV2(awsRequest, ec2Client::modifyVpcEndpoint);
237-
log(
238-
"VPC Endpoint has successfully been updated.",
239-
progress.getResourceModel().getServerId());
240-
return awsResponse;
241-
}
242-
})
242+
.translateToServiceRequest(m -> modifyVpcEndpointRequest(vpcEndpointId, toAdd, toRemove))
243+
.makeServiceCall((awsRequest, client) -> modifyVpcEndpoint(serverId, awsRequest, client))
243244
.stabilize((awsRequest, awsResponse, client, model, context) ->
244245
waitForVpcEndpoint(awsRequest.vpcEndpointId(), client, model))
245246
.handleError((ignored, exception, proxyClient1, model1, callbackContext1) ->
246247
handleError(UPDATE, exception, model1, callbackContext1, clientRequestToken))
247248
.progress();
248249
}
249250

251+
private ModifyVpcEndpointResponse modifyVpcEndpoint(
252+
String serverId, ModifyVpcEndpointRequest awsRequest, ProxyClient<Ec2Client> client) {
253+
try (Ec2Client ec2Client = client.client()) {
254+
ModifyVpcEndpointResponse awsResponse =
255+
client.injectCredentialsAndInvokeV2(awsRequest, ec2Client::modifyVpcEndpoint);
256+
log("VPC Endpoint has been updated successfully.", serverId);
257+
return awsResponse;
258+
}
259+
}
260+
250261
private Boolean waitForVpcEndpoint(String vpcEndpointId, ProxyClient<Ec2Client> client, ResourceModel model) {
251262
if (!isVpcEndpointAvailable(vpcEndpointId, client)) {
252263
log("VPC Endpoint is not available yet.", model.getServerId());
@@ -298,14 +309,14 @@ private UpdateServerRequest translateToFirstUpdateRequest(final ResourceModel ol
298309
.endpointType(endpointType)
299310
.endpointDetails(endpointDetails)
300311
.identityProviderDetails(identityProviderDetails)
301-
.loggingRole(newModel.getLoggingRole())
302-
.preAuthenticationLoginBanner(newModel.getPreAuthenticationLoginBanner())
303-
.postAuthenticationLoginBanner(newModel.getPostAuthenticationLoginBanner())
312+
.loggingRole(emptyStringIfNull(newModel.getLoggingRole()))
313+
.preAuthenticationLoginBanner(emptyStringIfNull(newModel.getPreAuthenticationLoginBanner()))
314+
.postAuthenticationLoginBanner(emptyStringIfNull(newModel.getPostAuthenticationLoginBanner()))
304315
.protocols(translateToSdkProtocols(newModel.getProtocols()))
305316
.protocolDetails(ProtocolDetailsTranslator.toSdk(newModel.getProtocolDetails()))
306317
.securityPolicyName(newModel.getSecurityPolicyName())
307318
.serverId(newModel.getServerId())
308-
.structuredLogDestinations(newModel.getStructuredLogDestinations())
319+
.structuredLogDestinations(emptyListIfNull(newModel.getStructuredLogDestinations()))
309320
.workflowDetails(WorkflowDetailsTranslator.toSdk(newModel.getWorkflowDetails(), true))
310321
.s3StorageOptions(S3StorageOptionsTranslator.toSdk(newModel.getS3StorageOptions()))
311322
.build();
@@ -335,12 +346,15 @@ private UpdateServerResponse updateServer(UpdateServerRequest awsRequest, ProxyC
335346
}
336347

337348
private ModifyVpcEndpointRequest modifyVpcEndpointRequest(
338-
String vpcEndpointId, Set<String> sgIdsToAdd, Set<String> sgIdsToRemove) {
339-
return ModifyVpcEndpointRequest.builder()
340-
.vpcEndpointId(vpcEndpointId)
341-
.addSecurityGroupIds(sgIdsToAdd)
342-
.removeSecurityGroupIds(sgIdsToRemove)
343-
.build();
349+
String vpcEndpointId, Collection<String> sgIdsToAdd, Collection<String> sgIdsToRemove) {
350+
var builder = ModifyVpcEndpointRequest.builder().vpcEndpointId(vpcEndpointId);
351+
if (!sgIdsToAdd.isEmpty()) {
352+
builder.addSecurityGroupIds(sgIdsToAdd);
353+
}
354+
if (!sgIdsToRemove.isEmpty()) {
355+
builder.removeSecurityGroupIds(sgIdsToRemove);
356+
}
357+
return builder.build();
344358
}
345359

346360
private ProgressEvent<ResourceModel, CallbackContext> addTags(

aws-transfer-server/src/main/java/software/amazon/transfer/server/translators/EndpointDetailsTranslator.java

+5-7
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
package software.amazon.transfer.server.translators;
22

3+
import static software.amazon.transfer.server.translators.Translator.nullIfEmptyList;
4+
35
import java.util.Collection;
4-
import java.util.Collections;
5-
import java.util.Optional;
66

77
import software.amazon.transfer.server.EndpointDetails;
88

@@ -16,11 +16,9 @@ public static EndpointDetails fromSdk(
1616
return null;
1717
}
1818
return EndpointDetails.builder()
19-
.addressAllocationIds(Optional.ofNullable(endpointDetails.addressAllocationIds())
20-
.orElse(Collections.emptyList()))
21-
.subnetIds(Optional.ofNullable(endpointDetails.subnetIds()).orElse(Collections.emptyList()))
22-
.securityGroupIds(
23-
Optional.ofNullable(endpointDetails.securityGroupIds()).orElse(Collections.emptyList()))
19+
.addressAllocationIds(nullIfEmptyList(endpointDetails.addressAllocationIds()))
20+
.subnetIds(nullIfEmptyList(endpointDetails.subnetIds()))
21+
.securityGroupIds(nullIfEmptyList(endpointDetails.securityGroupIds()))
2422
.vpcId(endpointDetails.vpcId())
2523
.vpcEndpointId(endpointDetails.vpcEndpointId())
2624
.build();

aws-transfer-server/src/main/java/software/amazon/transfer/server/translators/ResourceModelAdapter.java

+8-6
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,13 @@ private ResourceModelAdapter() {}
3131
public static final String DEFAULT_SECURITY_POLICY = "TransferSecurityPolicy-2018-11";
3232

3333
public static void prepareDesiredResourceModel(
34-
ResourceHandlerRequest<ResourceModel> request, ResourceModel resourceModel) {
35-
setDefaults(resourceModel);
34+
ResourceHandlerRequest<ResourceModel> request, ResourceModel resourceModel, boolean create) {
35+
setDefaults(resourceModel, create);
3636
setDesiredTags(request, resourceModel);
3737
}
3838

3939
public static void preparePreviousResourceModel(
4040
ResourceHandlerRequest<ResourceModel> request, ResourceModel resourceModel) {
41-
setDefaults(resourceModel);
4241
setPreviousTags(request, resourceModel);
4342
}
4443

@@ -57,7 +56,7 @@ private static void setPreviousTags(
5756
previousResourceModel.setTags(Translator.translateTagMapToTagList(tagsMap));
5857
}
5958

60-
private static void setDefaults(ResourceModel resourceModel) {
59+
private static void setDefaults(ResourceModel resourceModel, boolean create) {
6160
if (resourceModel.getEndpointType() == null) {
6261
resourceModel.setEndpointType(DEFAULT_ENDPOINT_TYPE);
6362
}
@@ -67,8 +66,11 @@ private static void setDefaults(ResourceModel resourceModel) {
6766
if (resourceModel.getProtocols() == null) {
6867
resourceModel.setProtocols(DEFAULT_PROTOCOLS);
6968
}
70-
if (resourceModel.getSecurityPolicyName() == null) {
71-
resourceModel.setSecurityPolicyName(DEFAULT_SECURITY_POLICY);
69+
// Handle update differently because of https://i.amazon.com/XFER-10446
70+
if (create) {
71+
if (resourceModel.getSecurityPolicyName() == null) {
72+
resourceModel.setSecurityPolicyName(DEFAULT_SECURITY_POLICY);
73+
}
7274
}
7375
}
7476
}

0 commit comments

Comments
 (0)