Skip to content

Commit a5a40da

Browse files
authored
Implement Asynchronous EC2 Metadata Client (#3523)
* IMDS Async client * Fix test classes * JavaDoc * PR comments and added IMDS to test-coverage-reporting - Create a common builder Ec2MetadataClientBuilder - Create a common test class BaseEc2MetadataClientTest - Refactor common initialization logic for both sync and async client in BaseEc2MetadataClient class - Use netty async client in unit tests - fix Async error logic * Improve JavaDoc and rename some variables - fix one failing unit test
1 parent 9d40ec1 commit a5a40da

20 files changed

+1187
-710
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"type": "feature",
3+
"category": "AWS SDK for Java v2",
4+
"contributor": "L-Applin",
5+
"description": "EC2Metadata Asynchronous Client"
6+
}

core/imds/pom.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@
5858
<groupId>software.amazon.awssdk</groupId>
5959
<artifactId>url-connection-client</artifactId>
6060
<version>${awsjavasdk.version}</version>
61-
<scope>compile</scope>
61+
<scope>test</scope>
6262
</dependency>
6363
<dependency>
6464
<groupId>software.amazon.awssdk</groupId>
@@ -114,7 +114,7 @@
114114
</dependency>
115115
<dependency>
116116
<groupId>software.amazon.awssdk</groupId>
117-
<artifactId>apache-client</artifactId>
117+
<artifactId>netty-nio-client</artifactId>
118118
<version>${awsjavasdk.version}</version>
119119
<scope>test</scope>
120120
</dependency>

core/imds/src/main/java/software/amazon/awssdk/imds/Ec2Metadata.java

Lines changed: 0 additions & 106 deletions
This file was deleted.
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
package software.amazon.awssdk.imds;
17+
18+
import java.util.concurrent.CompletableFuture;
19+
import java.util.concurrent.Executors;
20+
import java.util.concurrent.ScheduledExecutorService;
21+
import software.amazon.awssdk.annotations.SdkPublicApi;
22+
import software.amazon.awssdk.core.exception.SdkClientException;
23+
import software.amazon.awssdk.http.async.SdkAsyncHttpClient;
24+
import software.amazon.awssdk.imds.internal.DefaultEc2MetadataAsyncClient;
25+
import software.amazon.awssdk.utils.SdkAutoCloseable;
26+
27+
/**
28+
* Interface to represent the Ec2Metadata Client Class. Used to access instance metadata from a running instance.
29+
*/
30+
@SdkPublicApi
31+
public interface Ec2MetadataAsyncClient extends SdkAutoCloseable {
32+
33+
/**
34+
* Gets the specified instance metadata value by the given path.
35+
*
36+
* @param path Input path
37+
* @return A CompletableFuture that completes when the MetadataResponse is made available.
38+
*/
39+
CompletableFuture<MetadataResponse> get(String path);
40+
41+
/**
42+
* Create an {@link Ec2MetadataAsyncClient} instance using the default values.
43+
*
44+
* @return
45+
*/
46+
static Ec2MetadataAsyncClient create() {
47+
return builder().build();
48+
}
49+
50+
static Ec2MetadataAsyncClient.Builder builder() {
51+
return DefaultEc2MetadataAsyncClient.builder();
52+
}
53+
54+
/**
55+
* The builder definition for a {@link Ec2MetadataClient}. All parameters are optional and have default values if not
56+
* specified. Therefore, an instance can be simply created with {@code Ec2MetadataAsyncClient.builder().build()} or
57+
* {@code Ec2MetadataAsyncClient.create()}, both having the same result.
58+
*/
59+
interface Builder extends Ec2MetadataClientBuilder<Ec2MetadataAsyncClient.Builder, Ec2MetadataAsyncClient> {
60+
61+
/**
62+
* Define the {@link ScheduledExecutorService} used to schedule asynchronous retry attempts. If provided, the
63+
* Ec2MetadataClient will <em>NOT</em> manage the lifetime if the httpClient and must therefore be
64+
* closed explicitly by calling the {@link SdkAsyncHttpClient#close()} method on it.
65+
* <p>
66+
* If not specified, defaults to {@link Executors#newScheduledThreadPool} with a default value of 3 thread in the
67+
* pool.
68+
* </p>
69+
* @param scheduledExecutorService the ScheduledExecutorService to use for retry attempt.
70+
* @return a reference to this builder
71+
*/
72+
Builder scheduledExecutorService(ScheduledExecutorService scheduledExecutorService);
73+
74+
/**
75+
* Define the http client used by the Ec2 Metadata client. If provided, the Ec2MetadataClient will <em>NOT</em> manage the
76+
* lifetime if the httpClient and must therefore be closed explicitly by calling the {@link SdkAsyncHttpClient#close()}
77+
* method on it.
78+
* <p>
79+
* If not specified, the IMDS client will look for a SdkAsyncHttpClient class included in the classpath of the
80+
* application and creates a new instance of that class, managed by the IMDS Client, that will be closed when the IMDS
81+
* Client is closed. If no such class can be found, will throw a {@link SdkClientException}.
82+
* </p>
83+
* @param httpClient the http client
84+
* @return a reference to this builder
85+
*/
86+
Builder httpClient(SdkAsyncHttpClient httpClient);
87+
}
88+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
package software.amazon.awssdk.imds;
17+
18+
import software.amazon.awssdk.annotations.SdkPublicApi;
19+
import software.amazon.awssdk.core.exception.SdkClientException;
20+
import software.amazon.awssdk.http.SdkHttpClient;
21+
import software.amazon.awssdk.http.async.SdkAsyncHttpClient;
22+
import software.amazon.awssdk.imds.internal.DefaultEc2MetadataClient;
23+
import software.amazon.awssdk.utils.SdkAutoCloseable;
24+
25+
26+
/**
27+
* Interface to represent the Ec2Metadata Client Class. Used to access instance metadata from a running instance.
28+
*/
29+
@SdkPublicApi
30+
public interface Ec2MetadataClient extends SdkAutoCloseable {
31+
32+
/**
33+
* Gets the specified instance metadata value by the given path.
34+
* @param path Input path
35+
* @return Instance metadata value as part of MetadataResponse Object
36+
*/
37+
MetadataResponse get(String path);
38+
39+
/**
40+
* Create an {@link Ec2MetadataClient} instance using the default values.
41+
*/
42+
static Ec2MetadataClient create() {
43+
return builder().build();
44+
}
45+
46+
/**
47+
* Creates a default builder for {@link Ec2MetadataClient}.
48+
*/
49+
static Builder builder() {
50+
return DefaultEc2MetadataClient.builder();
51+
}
52+
53+
/**
54+
* The builder definition for a {@link Ec2MetadataClient}.
55+
*/
56+
interface Builder extends Ec2MetadataClientBuilder<Ec2MetadataClient.Builder, Ec2MetadataClient> {
57+
58+
/**
59+
* Define the http client used by the Ec2 Metadata client. If provided, the Ec2MetadataClient will <em>NOT</em> manage the
60+
* lifetime if the httpClient and must therefore be closed explicitly by calling the {@link SdkAsyncHttpClient#close()}
61+
* method on it.
62+
* <p>
63+
* If not specified, the IMDS client will look for a SdkHttpClient class included in the classpath of the
64+
* application and creates a new instance of that class, managed by the IMDS Client, that will be closed when the IMDS
65+
* Client is closed. If no such class can be found, will throw a {@link SdkClientException}.
66+
* </p>
67+
* @param httpClient the http client
68+
* @return a reference to this builder
69+
*/
70+
Builder httpClient(SdkHttpClient httpClient);
71+
}
72+
73+
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
package software.amazon.awssdk.imds;
17+
18+
import java.net.URI;
19+
import java.time.Duration;
20+
import software.amazon.awssdk.annotations.SdkPublicApi;
21+
import software.amazon.awssdk.core.retry.RetryMode;
22+
import software.amazon.awssdk.core.retry.backoff.BackoffStrategy;
23+
import software.amazon.awssdk.imds.internal.Ec2MetadataEndpointProvider;
24+
import software.amazon.awssdk.utils.builder.SdkBuilder;
25+
26+
/**
27+
* Base shared builder interface for Ec2MetadataClient
28+
* @param <B> the Builder Type
29+
* @param <T> the Ec2MetadataClient Type
30+
*/
31+
@SdkPublicApi
32+
public interface Ec2MetadataClientBuilder<B, T> extends SdkBuilder<Ec2MetadataClientBuilder<B, T>, T> {
33+
/**
34+
* Define the retry policy which includes the number of retry attempts for any failed request.
35+
* <p>
36+
* If not specified, defaults to 3 retry attempts and a {@link BackoffStrategy#defaultStrategy()} backoff strategy} that
37+
* uses {@link RetryMode#STANDARD}
38+
* </p>
39+
* @param retryPolicy The retry policy which includes the number of retry attempts for any failed request.
40+
* @return a reference to this builder
41+
*/
42+
B retryPolicy(Ec2MetadataRetryPolicy retryPolicy);
43+
44+
Ec2MetadataRetryPolicy getRetryPolicy();
45+
46+
/**
47+
* Define the endpoint of IMDS.
48+
* <p>
49+
* If not specified, the IMDS client will attempt to automatically resolve the endpoint value
50+
* based on the logic of {@link Ec2MetadataEndpointProvider}.
51+
* </p>
52+
* @param endpoint The endpoint of IMDS.
53+
* @return a reference to this builder
54+
*/
55+
B endpoint(URI endpoint);
56+
57+
URI getEndpoint();
58+
59+
/**
60+
* Define the Time to live (TTL) of the token. The token represents a logical session. The TTL specifies the length of time
61+
* that the token is valid and, therefore, the duration of the session. Defaults to 21,600 seconds (6 hours) if not specified.
62+
*
63+
* @param tokenTtl The Time to live (TTL) of the token.
64+
* @return a reference to this builder
65+
*/
66+
B tokenTtl(Duration tokenTtl);
67+
68+
Duration getTokenTtl();
69+
70+
/**
71+
* Define the endpoint mode of IMDS. Supported values include IPv4 and IPv6. Used to determine the endpoint of the IMDS
72+
* Client only if {@link Ec2MetadataClientBuilder#endpoint(URI)} is not specified. Only one of both endpoint or endpoint mode
73+
* but not both. If both are specified in the Builder, a {@link IllegalArgumentException} will be thrown.
74+
* <p>
75+
* If not specified, the IMDS client will attempt to automatically resolve the endpoint mode value
76+
* based on the logic of {@link Ec2MetadataEndpointProvider}.
77+
* </p>
78+
*
79+
* @param endpointMode The endpoint mode of IMDS. Supported values include IPv4 and IPv6.
80+
* @return a reference to this builder
81+
*/
82+
B endpointMode(EndpointMode endpointMode);
83+
84+
EndpointMode getEndpointMode();
85+
86+
}

core/imds/src/main/java/software/amazon/awssdk/imds/Ec2MetadataRetryPolicy.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,14 @@
3434
@SdkPublicApi
3535
public class Ec2MetadataRetryPolicy implements ToCopyableBuilder<Ec2MetadataRetryPolicy.Builder, Ec2MetadataRetryPolicy> {
3636

37+
private static final int DEFAULT_RETRY_ATTEMPTS = 3;
38+
3739
private final BackoffStrategy backoffStrategy;
3840
private final int numRetries;
3941

4042
private Ec2MetadataRetryPolicy(BuilderImpl builder) {
4143

42-
this.numRetries = builder.numRetries != null ? builder.numRetries : 3;
44+
this.numRetries = builder.numRetries != null ? builder.numRetries : DEFAULT_RETRY_ATTEMPTS;
4345

4446
this.backoffStrategy = builder.backoffStrategy != null ? builder.backoffStrategy :
4547
BackoffStrategy.defaultStrategy(RetryMode.STANDARD);

0 commit comments

Comments
 (0)