Skip to content

Commit 29c17a0

Browse files
committed
added S3 Express Scenario
1 parent 60dcd5d commit 29c17a0

File tree

5 files changed

+1190
-0
lines changed

5 files changed

+1190
-0
lines changed
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package com.example.s3.express;
5+
6+
import org.slf4j.Logger;
7+
import org.slf4j.LoggerFactory;
8+
import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration;
9+
import software.amazon.awssdk.core.retry.RetryMode;
10+
import software.amazon.awssdk.http.async.SdkAsyncHttpClient;
11+
import software.amazon.awssdk.http.nio.netty.NettyNioAsyncHttpClient;
12+
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;
18+
import software.amazon.awssdk.services.cloudformation.model.Stack;
19+
import software.amazon.awssdk.services.cloudformation.waiters.CloudFormationAsyncWaiter;
20+
21+
import java.io.IOException;
22+
import java.net.URISyntaxException;
23+
import java.nio.file.Files;
24+
import java.nio.file.Path;
25+
import java.nio.file.Paths;
26+
import java.time.Duration;
27+
import java.util.HashMap;
28+
import java.util.List;
29+
import java.util.Map;
30+
import java.util.concurrent.CompletableFuture;
31+
32+
public class CloudFormationHelper {
33+
private static final String CFN_TEMPLATE = "s3_express_template.yaml";
34+
private static final Logger logger = LoggerFactory.getLogger(CloudFormationHelper.class);
35+
36+
private static CloudFormationAsyncClient cloudFormationClient;
37+
38+
private static CloudFormationAsyncClient getCloudFormationClient() {
39+
if (cloudFormationClient == null) {
40+
SdkAsyncHttpClient httpClient = NettyNioAsyncHttpClient.builder()
41+
.maxConcurrency(100)
42+
.connectionTimeout(Duration.ofSeconds(60))
43+
.readTimeout(Duration.ofSeconds(60))
44+
.writeTimeout(Duration.ofSeconds(60))
45+
.build();
46+
47+
ClientOverrideConfiguration overrideConfig = ClientOverrideConfiguration.builder()
48+
.apiCallTimeout(Duration.ofMinutes(2))
49+
.apiCallAttemptTimeout(Duration.ofSeconds(90))
50+
.retryStrategy(RetryMode.STANDARD)
51+
.build();
52+
53+
cloudFormationClient = CloudFormationAsyncClient.builder()
54+
.httpClient(httpClient)
55+
.overrideConfiguration(overrideConfig)
56+
.build();
57+
}
58+
return cloudFormationClient;
59+
}
60+
61+
public static void deployCloudFormationStack(String stackName) {
62+
String templateBody;
63+
boolean doesExist = describeStack(stackName);
64+
if (!doesExist) {
65+
try {
66+
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
67+
Path filePath = Paths.get(classLoader.getResource(CFN_TEMPLATE).toURI());
68+
templateBody = Files.readString(filePath);
69+
} catch (IOException | URISyntaxException e) {
70+
throw new RuntimeException(e);
71+
}
72+
73+
getCloudFormationClient().createStack(b -> b.stackName(stackName)
74+
.templateBody(templateBody)
75+
.capabilities(Capability.CAPABILITY_IAM))
76+
.whenComplete((csr, t) -> {
77+
if (csr != null) {
78+
System.out.println("Stack creation requested, ARN is " + csr.stackId());
79+
try (CloudFormationAsyncWaiter waiter = getCloudFormationClient().waiter()) {
80+
waiter.waitUntilStackCreateComplete(request -> request.stackName(stackName))
81+
.whenComplete((dsr, th) -> {
82+
if (th != null) {
83+
System.out.println("Error waiting for stack creation: " + th.getMessage());
84+
} else {
85+
dsr.matched().response().orElseThrow(() -> new RuntimeException("Failed to deploy"));
86+
System.out.println("Stack created successfully");
87+
}
88+
}).join();
89+
}
90+
} else {
91+
System.out.format("Error creating stack: " + t.getMessage(), t);
92+
throw new RuntimeException(t.getCause().getMessage(), t);
93+
}
94+
}).join();
95+
} else {
96+
logger.info("{} stack already exists", CFN_TEMPLATE);
97+
}
98+
}
99+
100+
// Check to see if the Stack exists before deploying it
101+
public static Boolean describeStack(String stackName) {
102+
try {
103+
CompletableFuture<?> future = getCloudFormationClient().describeStacks();
104+
DescribeStacksResponse stacksResponse = (DescribeStacksResponse) future.join();
105+
List<Stack> stacks = stacksResponse.stacks();
106+
for (Stack myStack : stacks) {
107+
if (myStack.stackName().compareTo(stackName) == 0) {
108+
return true;
109+
}
110+
}
111+
} catch (CloudFormationException e) {
112+
System.err.println(e.getMessage());
113+
}
114+
return false;
115+
}
116+
117+
public static void destroyCloudFormationStack(String stackName) {
118+
getCloudFormationClient().deleteStack(b -> b.stackName(stackName))
119+
.whenComplete((dsr, t) -> {
120+
if (dsr != null) {
121+
System.out.println("Delete stack requested ....");
122+
try (CloudFormationAsyncWaiter waiter = getCloudFormationClient().waiter()) {
123+
waiter.waitUntilStackDeleteComplete(request -> request.stackName(stackName))
124+
.whenComplete((waiterResponse, throwable) ->
125+
System.out.println("Stack deleted successfully."))
126+
.join();
127+
}
128+
} else {
129+
System.out.format("Error deleting stack: " + t.getMessage(), t);
130+
throw new RuntimeException(t.getCause().getMessage(), t);
131+
}
132+
}).join();
133+
}
134+
135+
public static CompletableFuture<Map<String, String>> getStackOutputsAsync(String stackName) {
136+
CloudFormationAsyncClient cloudFormationAsyncClient = getCloudFormationClient();
137+
138+
DescribeStacksRequest describeStacksRequest = DescribeStacksRequest.builder()
139+
.stackName(stackName)
140+
.build();
141+
142+
return cloudFormationAsyncClient.describeStacks(describeStacksRequest)
143+
.handle((describeStacksResponse, throwable) -> {
144+
if (throwable != null) {
145+
throw new RuntimeException("Failed to get stack outputs for: " + stackName, throwable);
146+
}
147+
148+
// Process the result
149+
if (describeStacksResponse.stacks().isEmpty()) {
150+
throw new RuntimeException("Stack not found: " + stackName);
151+
}
152+
153+
Stack stack = describeStacksResponse.stacks().get(0);
154+
Map<String, String> outputs = new HashMap<>();
155+
for (Output output : stack.outputs()) {
156+
outputs.put(output.outputKey(), output.outputValue());
157+
}
158+
159+
return outputs;
160+
});
161+
}
162+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package com.example.s3.express;
2+
3+
import software.amazon.awssdk.regions.Region;
4+
import software.amazon.awssdk.services.s3.S3Client;
5+
import software.amazon.awssdk.services.s3.model.BucketInfo;
6+
import software.amazon.awssdk.services.s3.model.BucketType;
7+
import software.amazon.awssdk.services.s3.model.CreateBucketConfiguration;
8+
import software.amazon.awssdk.services.s3.model.CreateBucketRequest;
9+
import software.amazon.awssdk.services.s3.model.CreateBucketResponse;
10+
import software.amazon.awssdk.services.s3.model.DataRedundancy;
11+
import software.amazon.awssdk.services.s3.model.LocationInfo;
12+
import software.amazon.awssdk.services.s3.model.LocationType;
13+
import software.amazon.awssdk.services.s3.model.S3Exception;
14+
15+
public class CreateDirectoryBucket {
16+
17+
public static void main(String[] args){
18+
String bucketName = "test-bucket-" + System.currentTimeMillis() + "--usw2-az1--x-s3";
19+
Region region = Region.US_WEST_2;
20+
String zone = "usw2-az1";
21+
S3Client s3Client = S3Client.builder()
22+
.region(region)
23+
.build();
24+
25+
createDirectoryBucket(s3Client, bucketName, zone);
26+
27+
}
28+
29+
/**
30+
* Creates a new S3 directory bucket in a specified Zone (For example, a
31+
* specified Availability Zone in this code example).
32+
*
33+
* @param s3Client The S3 client used to create the bucket
34+
* @param bucketName The name of the bucket to be created
35+
* @param zone The region where the bucket will be created
36+
37+
*/
38+
public static void createDirectoryBucket(S3Client s3Client, String bucketName, String zone) throws S3Exception {
39+
System.out.println("Creating bucket: " +bucketName);
40+
41+
CreateBucketConfiguration bucketConfiguration = CreateBucketConfiguration.builder()
42+
.location(LocationInfo.builder()
43+
.type(LocationType.AVAILABILITY_ZONE)
44+
.name(zone).build())
45+
.bucket(BucketInfo.builder()
46+
.type(BucketType.DIRECTORY)
47+
.dataRedundancy(DataRedundancy.SINGLE_AVAILABILITY_ZONE)
48+
.build())
49+
.build();
50+
try {
51+
CreateBucketRequest bucketRequest = CreateBucketRequest.builder()
52+
.bucket(bucketName)
53+
.createBucketConfiguration(bucketConfiguration).build();
54+
CreateBucketResponse response = s3Client.createBucket(bucketRequest);
55+
System.out.println("Bucket created successfully with location: " +response.location());
56+
} catch (S3Exception e) {
57+
System.out.println("Error creating bucket: - Error code: {}" +e.awsErrorDetails().errorMessage());
58+
throw e;
59+
}
60+
}
61+
}

0 commit comments

Comments
 (0)