Introducing a new client in the AWS SDK for Java 2.x for retrieving EC2 Instance Metadata

Introducing a new client in the AWS SDK for Java 2.x for retrieving EC2 Instance Metadata

You can now use AWS SDK for Java 2.x to easily retrieve instance metadata for an Amazon Elastic Compute Cloud (Amazon EC2) instance! We are pleased to announce the general availability of new Java SDK EC2 Instance Metadata Clients in the AWS SDK for Java 2.x (version 2.19.29 or later). You can use this new feature to access local EC2 instance metadata in your JVM-based applications.

There are now two new clients classes available with the AWS SDK for Java 2.x: a synchronous client for blocking operations and an asynchronous client for non-blocking operations. The new clients use IMDSv2 (Instance Metadata Service v2), which uses session-oriented requests.

This blog post shows how to use the new clients to retrieve metadata in your application and takes a deeper look at some of the new features.

Getting Started

To use the EC2 Instance Metadata Client, first add the dependency to your project.

<dependency>
    <groupId>software.amazon.awssdk</groupId>
    <artifactId>imds</artifactId> 
    <version>${imds.version}</version> 
</dependency>

You will also need classes for an SdkHttpClient (or SdkAsyncHttpClient for the asynchronous variant) on the classpath, since its required by the metadata clients. You can learn more details on this in the Configurable HTTP client section.

Sending requests

To retrieve instance metadata, simply instantiate the EC2MetadataClient class and call the get method with a path parameter that specifies the instance metadata category. The following example will print the value associated with the ami-id key to the console.

Ec2MetadataClient client = Ec2MetadataClient.create();
Ec2MetadataResponse response = client.get("/latest/meta-data/ami-id");
System.out.println(response.asString());
client.close(); // closes the internal resources used by the Ec2MetadataClient class

If an invalid path is specified, the get method throws an exception.

Remember that you don’t need to create a new client for every request. You can reuse the same instance for multiple requests, but remember to close the client, when it is no longer needed, by calling the close method on the client instance. The client method can no longer be used once the close method is called.

Parsing response

EC2 instance metadata can be output in different formats. Since Plain text and JSON are the most commonly used formats, the metadata clients offer easy ways to work with these formats.

As the following example shows, use the asString method to get the data as a simple Java String. You can also use the asList method to separate a plain text response that returns multiple lines.

Ec2MetadataClient client = Ec2MetadataClient.create();
Ec2MetadataResponse response = client.get("/latest/meta-data/");
String fullResponse = response.asString();
List<String> splits = response.asList();

If the response is in JSON, use the Ec2MetadataResponse#asDocument method to parse the JSON response into a Document instance.

Document fullResponse = response.asDocument();

The client will throw an exception if the format of the metadata is not in JSON. If the response is successfully parsed, the document API can then be use to inspect the response in more detail. Consult the instance metadata category chart to find out which metadata categories return JSON formatted responses.

Configuring the EC2 Metadata Client

You can configure the EC2 Instance Metadata Client with a retry policy. Retries allow requests that fail for unexpected reason to be automatically retried by the client. By default, the client will retry 3 times on a failed request with an exponential backoff time between attempts.

Since majority of applications require only the default retry configuration, we recommend you keep the default retry policy for your projects. However, if your use cases require unique configuration, modifying the retry mechanism is quite easy. The following example shows a synchronous client configured with a fixed delay between attempts and 5 retry attempts.

BackoffStrategy fixedBackoffStrategy = 
    FixedDelayBackoffStrategy.create(Duration.ofSeconds(2));
Ec2MetadataClient client =
    Ec2MetadataClient.builder()
                     .retryPolicy(retryPolicyBuilder -> 
                         retryPolicyBuilder.numRetries(5)
                                           .backoffStrategy(fixedBackoffStrategy))
                     .build();

You can also disable the retry mechanism entirely using the following snippet.

Ec2MetadataClient client =
    Ec2MetadataClient.builder()
                     .retryPolicy(Ec2MetadataRetryPolicy.none())
                     .build(); 

Using Ec2MetadataRetryPolicy.none() will make sure no retries are attempted. There are many different BackoffStrategies already available in the AWS SDK for Java v2.x that you can use with the metadata clients.

Key Features

Asynchronous Client

To use the non-blocking version of the client, instantiate an instance of the Ec2MetadataAsyncClient class. The code in the following example creates an asynchronous client with default settings and uses the get method to retrieve the value for the ami-id key.

Ec2MetadataAsyncClient asyncClient = Ec2MetadataAsyncClient.create();
CompletableFuture<Ec2MetadataResponse> response = asyncClient.get("/latest/meta-data/ami-id");

The java.util.concurrent.CompletableFuture returned by the get method completes when a response is returned. The following example prints the ami-id metadata to the console.

response.thenAccept(metadata -> System.out.println(metadata.asString()));

If your workload does not require asynchronous programming, use the synchronous Ec2MetadataClient instead.

Configurable HTTP client

The following example shows how you can customize a UrlConnectionHttpClient instance or a NettyNioAsyncHttpClient instance and use it with its respective synchronous or asynchronous Metadata Client.

Sync Client

Async Client

SdkHttpClient httpClient =
    UrlConnectionHttpClient.builder()
    // your custom configuration here
    .build();
Ec2MetadataClient client =
    Ec2MetadataClient.builder()
                     .httpClient(httpClient)
                     .build();
SdkAsyncHttpClient asyncHttpClient =
    NettyNioAsyncHttpClient.builder()
    // your custom configuration here
    .build();
Ec2MetadataAsyncClient asyncClient=
    Ec2MetadataAsyncClient.builder()
                          .httpClient(asyncHttpClient)
                          .build();

Use an HTTP client to configure common options related to HTTP requests, such as timeouts or proxy options. To configure and use an HTTP client, add the artifacts to your project dependencies. Other implementations of synchronous HTTP clients and asynchronous HTTP clients are available in the AWS SDK for Java v2.x. They all work with the metadata client.

Token Caching

All requests are associated with a session, because the new EC2 instance metadata client uses IMDSv2. A session is defined by a token that has an expiration, and is managed by the metadata client. Every metadata request automatically reuses the token until it expires.

By default, a token will last for 6 hours (21,600 seconds), but that duration is configurable using the tokentTtl builder method. For example, the following code snippet creates a client with a session duration of 5 minutes.

Ec2MetadataClient client =
    Ec2MetadataClient.builder()
                     .tokenTtl(Duration.ofMinutes(5))
                     .build();

If you omit calling the tokenTtl method on the builder, the default of 21,600 would be used instead. We recommend you keep the default time-to-live value unless your specific use case requires advanced configurations.

Conclusion

In this blog post, we showed the key features of the new Java SDK EC2 Instance Metadata Clients available in the AWS SDK for Java v2.x. We provided examples to show how to use these clients and retrieve EC2 instance metadata. Tell us how you use EC2’s IMDS (Instance Metadata Service) and the new clients in your enterprise Java applications by commenting on this blog or by contacting us in GitHub! Don’t hesitate to open an issue or a pull request if you have ideas for improvements. You can also refer to the Java (v2) SDK Developer Guide and API reference to learn more about using these clients.

This content was originally published here.