Skip to content

Commit 2ab377a

Browse files
committed
fixed a CDK issue and tests now run again
1 parent be8209c commit 2ab377a

File tree

4 files changed

+178
-233
lines changed

4 files changed

+178
-233
lines changed

javav2/example_code/entityresolution/src/main/java/com/example/entity/scenario/CloudFormationHelper.java

Lines changed: 119 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,7 @@
1010
import software.amazon.awssdk.http.async.SdkAsyncHttpClient;
1111
import software.amazon.awssdk.http.nio.netty.NettyNioAsyncHttpClient;
1212
import software.amazon.awssdk.services.cloudformation.CloudFormationAsyncClient;
13-
import software.amazon.awssdk.services.cloudformation.model.Capability;
14-
import software.amazon.awssdk.services.cloudformation.model.CloudFormationException;
15-
import software.amazon.awssdk.services.cloudformation.model.DescribeStacksRequest;
16-
import software.amazon.awssdk.services.cloudformation.model.DescribeStacksResponse;
17-
import software.amazon.awssdk.services.cloudformation.model.Output;
13+
import software.amazon.awssdk.services.cloudformation.model.*;
1814
import software.amazon.awssdk.services.cloudformation.model.Stack;
1915
import software.amazon.awssdk.services.cloudformation.waiters.CloudFormationAsyncWaiter;
2016
import software.amazon.awssdk.services.s3.S3AsyncClient;
@@ -26,9 +22,7 @@
2622
import java.nio.file.Path;
2723
import java.nio.file.Paths;
2824
import java.time.Duration;
29-
import java.util.HashMap;
30-
import java.util.List;
31-
import java.util.Map;
25+
import java.util.*;
3226
import java.util.concurrent.CompletableFuture;
3327
import java.util.stream.Collectors;
3428

@@ -39,150 +33,187 @@ public class CloudFormationHelper {
3933
private static CloudFormationAsyncClient cloudFormationClient;
4034

4135
public static void main(String[] args) {
36+
if (args.length < 1) {
37+
logger.error("Usage: CloudFormationHelper <bucketName>");
38+
return;
39+
}
4240
emptyS3Bucket(args[0]);
4341
}
4442

4543
private static CloudFormationAsyncClient getCloudFormationClient() {
4644
if (cloudFormationClient == null) {
4745
SdkAsyncHttpClient httpClient = NettyNioAsyncHttpClient.builder()
48-
.maxConcurrency(100)
49-
.connectionTimeout(Duration.ofSeconds(60))
50-
.readTimeout(Duration.ofSeconds(60))
51-
.writeTimeout(Duration.ofSeconds(60))
52-
.build();
46+
.maxConcurrency(100)
47+
.connectionTimeout(Duration.ofSeconds(60))
48+
.readTimeout(Duration.ofSeconds(60))
49+
.writeTimeout(Duration.ofSeconds(60))
50+
.build();
5351

5452
ClientOverrideConfiguration overrideConfig = ClientOverrideConfiguration.builder()
55-
.apiCallTimeout(Duration.ofMinutes(2))
56-
.apiCallAttemptTimeout(Duration.ofSeconds(90))
57-
.retryStrategy(RetryMode.STANDARD)
58-
.build();
53+
.apiCallTimeout(Duration.ofMinutes(2))
54+
.apiCallAttemptTimeout(Duration.ofSeconds(90))
55+
.retryStrategy(RetryMode.STANDARD)
56+
.build();
5957

6058
cloudFormationClient = CloudFormationAsyncClient.builder()
61-
.httpClient(httpClient)
62-
.overrideConfiguration(overrideConfig)
63-
.build();
59+
.httpClient(httpClient)
60+
.overrideConfiguration(overrideConfig)
61+
.build();
6462
}
6563
return cloudFormationClient;
6664
}
6765

6866
public static void deployCloudFormationStack(String stackName) {
69-
String templateBody;
67+
logger.info("Deploying CloudFormation stack: {}", stackName);
7068
boolean doesExist = describeStack(stackName);
7169
if (!doesExist) {
70+
String templateBody;
7271
try {
7372
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
74-
Path filePath = Paths.get(classLoader.getResource(CFN_TEMPLATE).toURI());
73+
Path filePath = Paths.get(Objects.requireNonNull(classLoader.getResource(CFN_TEMPLATE)).toURI());
7574
templateBody = Files.readString(filePath);
7675
} catch (IOException | URISyntaxException e) {
76+
logger.error("Failed to read CloudFormation template", e);
7777
throw new RuntimeException(e);
7878
}
7979

8080
getCloudFormationClient().createStack(b -> b.stackName(stackName)
81-
.templateBody(templateBody)
82-
.capabilities(Capability.CAPABILITY_IAM))
83-
.whenComplete((csr, t) -> {
84-
if (csr != null) {
85-
System.out.println("Stack creation requested, ARN is " + csr.stackId());
81+
.templateBody(templateBody)
82+
.capabilities(Capability.CAPABILITY_IAM))
83+
.whenComplete((csr, t) -> {
84+
if (t != null) {
85+
logger.error("Error creating stack {}", stackName, t);
86+
throw new RuntimeException("Stack creation failed", t);
87+
}
88+
89+
logger.info("Stack creation requested. ARN: {}", csr.stackId());
90+
8691
try (CloudFormationAsyncWaiter waiter = getCloudFormationClient().waiter()) {
8792
waiter.waitUntilStackCreateComplete(request -> request.stackName(stackName))
88-
.whenComplete((dsr, th) -> {
89-
if (th != null) {
90-
System.out.println("Error waiting for stack creation: " + th.getMessage());
91-
} else {
92-
dsr.matched().response().orElseThrow(() -> new RuntimeException("Failed to deploy"));
93-
System.out.println("Stack created successfully");
94-
}
95-
}).join();
93+
.whenComplete((dsr, th) -> {
94+
if (th != null) {
95+
logger.error("Error waiting for stack creation: {}", stackName, th);
96+
} else {
97+
dsr.matched().response()
98+
.orElseThrow(() -> new RuntimeException("Stack creation failed for " + stackName));
99+
logger.info("Stack {} created successfully.", stackName);
100+
101+
// Print outputs immediately
102+
getStackOutputsAsync(stackName).whenComplete((outputs, outEx) -> {
103+
if (outEx != null) {
104+
logger.error("Failed to fetch stack outputs", outEx);
105+
} else {
106+
logger.info("Stack Outputs for {}:", stackName);
107+
outputs.forEach((k, v) -> logger.info(" {} = {}", k, v));
108+
}
109+
}).join();
110+
}
111+
}).join();
96112
}
97-
} else {
98-
System.out.format("Error creating stack: " + t.getMessage(), t);
99-
throw new RuntimeException(t.getCause().getMessage(), t);
100-
}
101-
}).join();
113+
}).join();
102114
} else {
103-
logger.info("{} stack already exists", stackName);
115+
logger.info("Stack {} already exists, skipping creation.", stackName);
104116
}
105117
}
106118

107119
// Check to see if the Stack exists before deploying it
108120
public static Boolean describeStack(String stackName) {
109121
try {
110-
CompletableFuture<?> future = getCloudFormationClient().describeStacks();
111-
DescribeStacksResponse stacksResponse = (DescribeStacksResponse) future.join();
112-
List<Stack> stacks = stacksResponse.stacks();
113-
for (Stack myStack : stacks) {
114-
if (myStack.stackName().compareTo(stackName) == 0) {
122+
CompletableFuture<DescribeStacksResponse> future = getCloudFormationClient().describeStacks();
123+
DescribeStacksResponse stacksResponse = future.join();
124+
for (Stack myStack : stacksResponse.stacks()) {
125+
if (myStack.stackName().equals(stackName)) {
126+
logger.info("Stack {} exists already.", stackName);
115127
return true;
116128
}
117129
}
118130
} catch (CloudFormationException e) {
119-
System.err.println(e.getMessage());
131+
logger.error("Error describing stack {}", stackName, e);
120132
}
121133
return false;
122134
}
123135

124136
public static void destroyCloudFormationStack(String stackName) {
137+
logger.info("Deleting CloudFormation stack: {}", stackName);
125138
getCloudFormationClient().deleteStack(b -> b.stackName(stackName))
126-
.whenComplete((dsr, t) -> {
127-
if (dsr != null) {
128-
System.out.println("Delete stack requested ....");
139+
.whenComplete((dsr, t) -> {
140+
if (t != null) {
141+
logger.error("Error deleting stack {}", stackName, t);
142+
throw new RuntimeException("Delete failed", t);
143+
}
144+
145+
logger.info("Delete stack requested: {}", stackName);
129146
try (CloudFormationAsyncWaiter waiter = getCloudFormationClient().waiter()) {
130147
waiter.waitUntilStackDeleteComplete(request -> request.stackName(stackName))
131-
.whenComplete((waiterResponse, throwable) ->
132-
System.out.println("Stack deleted successfully."))
133-
.join();
148+
.whenComplete((waiterResponse, throwable) -> {
149+
if (throwable != null) {
150+
logger.error("Error waiting for stack deletion {}", stackName, throwable);
151+
} else {
152+
logger.info("Stack {} deleted successfully.", stackName);
153+
}
154+
}).join();
134155
}
135-
} else {
136-
System.out.format("Error deleting stack: " + t.getMessage(), t);
137-
throw new RuntimeException(t.getCause().getMessage(), t);
138-
}
139-
}).join();
156+
}).join();
140157
}
141158

142159
public static CompletableFuture<Map<String, String>> getStackOutputsAsync(String stackName) {
143-
CloudFormationAsyncClient cloudFormationAsyncClient = getCloudFormationClient();
160+
logger.info("Fetching stack outputs for {}", stackName);
144161

145162
DescribeStacksRequest describeStacksRequest = DescribeStacksRequest.builder()
146-
.stackName(stackName)
147-
.build();
148-
149-
return cloudFormationAsyncClient.describeStacks(describeStacksRequest)
150-
.handle((describeStacksResponse, throwable) -> {
151-
if (throwable != null) {
152-
throw new RuntimeException("Failed to get stack outputs for: " + stackName, throwable);
153-
}
163+
.stackName(stackName)
164+
.build();
154165

155-
// Process the result
156-
if (describeStacksResponse.stacks().isEmpty()) {
157-
throw new RuntimeException("Stack not found: " + stackName);
158-
}
166+
return getCloudFormationClient().describeStacks(describeStacksRequest)
167+
.handle((describeStacksResponse, throwable) -> {
168+
if (throwable != null) {
169+
logger.error("Failed to get stack outputs for {}", stackName, throwable);
170+
throw new RuntimeException("Failed to get stack outputs for: " + stackName, throwable);
171+
}
159172

160-
Stack stack = describeStacksResponse.stacks().get(0);
161-
Map<String, String> outputs = new HashMap<>();
162-
for (Output output : stack.outputs()) {
163-
outputs.put(output.outputKey(), output.outputValue());
164-
}
173+
if (describeStacksResponse.stacks().isEmpty()) {
174+
throw new RuntimeException("Stack not found: " + stackName);
175+
}
165176

166-
return outputs;
167-
});
177+
Stack stack = describeStacksResponse.stacks().get(0);
178+
Map<String, String> outputs = new HashMap<>();
179+
for (Output output : stack.outputs()) {
180+
outputs.put(output.outputKey(), output.outputValue());
181+
}
182+
return outputs;
183+
});
168184
}
169185

170186
public static void emptyS3Bucket(String bucketName) {
187+
logger.info("Emptying S3 bucket: {}", bucketName);
171188
S3AsyncClient s3Client = S3AsyncClient.builder().build();
172189

173190
s3Client.listObjectsV2(req -> req.bucket(bucketName))
174-
.thenCompose(response -> {
175-
List<CompletableFuture<DeleteObjectResponse>> deleteFutures = response.contents().stream()
176-
.map(s3Object -> s3Client.deleteObject(req -> req
177-
.bucket(bucketName)
178-
.key(s3Object.key())))
179-
.collect(Collectors.toList());
191+
.thenCompose(response -> {
192+
if (response.contents().isEmpty()) {
193+
logger.info("Bucket {} is already empty.", bucketName);
194+
return CompletableFuture.completedFuture(null);
195+
}
180196

181-
return CompletableFuture.allOf(deleteFutures.toArray(new CompletableFuture[0]));
182-
})
183-
.join();
197+
List<CompletableFuture<DeleteObjectResponse>> deleteFutures = response.contents().stream()
198+
.map(s3Object -> {
199+
logger.info("Deleting object: {}", s3Object.key());
200+
return s3Client.deleteObject(req -> req
201+
.bucket(bucketName)
202+
.key(s3Object.key()));
203+
})
204+
.collect(Collectors.toList());
205+
206+
return CompletableFuture.allOf(deleteFutures.toArray(new CompletableFuture[0]));
207+
})
208+
.whenComplete((res, ex) -> {
209+
if (ex != null) {
210+
logger.error("Failed to empty bucket {}", bucketName, ex);
211+
} else {
212+
logger.info("Bucket {} emptied successfully.", bucketName);
213+
}
214+
})
215+
.join();
184216

185217
s3Client.close();
186218
}
187219
}
188-

javav2/example_code/entityresolution/src/main/java/com/example/entity/scenario/EntityResScenario.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
public class EntityResScenario {
2424
private static final Logger logger = LoggerFactory.getLogger(EntityResScenario.class);
2525
public static final String DASHES = new String(new char[80]).replace("\0", "-");
26-
private static final String STACK_NAME = "EntityResolutionCdkStack";
26+
private static final String STACK_NAME = "EntityResolutionCdkStack2";
2727
private static final String ENTITY_RESOLUTION_ROLE_ARN_KEY = "EntityResolutionRoleArn";
2828
private static final String GLUE_DATA_BUCKET_NAME_KEY = "GlueDataBucketName";
2929
private static final String JSON_GLUE_TABLE_ARN_KEY = "JsonErGlueTableArn";

0 commit comments

Comments
 (0)