+ * Example: + *
+ * {@code
+ *
+ * Ec2Metadata ec2Metadata = Ec2Metadata.create();
+ * MetadataResponse metadataResponse = client.get("/latest/meta-data/ami-id");
+ * String response = metadataResponse.asString();
+ * }
+ *
+ */
+ public String asString() {
+ return body;
+
+ }
+
+ /**
+ * Parses the response String into a list of Strings split by delimiter ("\n"). This method can be used for parsing the
+ * list-type metadata from IMDS.
+ *
+ * @return List Representation of the Metadata Response Body.
+ *
+ * + * Example: + *
+ * {@code
+ *
+ * Ec2Metadata ec2Metadata = Ec2Metadata.create();
+ * MetadataResponse metadataResponse = client.get("/latest/meta-data/ancestor-ami-ids");
+ * Listresponse = metadataResponse.asList();
+ * }
+ *
+ */
+ public List+ * Example: + *
+ * {@code
+ *
+ * Ec2Metadata ec2Metadata = Ec2Metadata.create();
+ * MetadataResponse metadataResponse = client.get("/latest/dynamic/instance-identity/document");
+ * Document document = metadataResponse.asDocument();
+ * }
+ *
+ */
+
+ public Document asDocument() throws IOException {
+
+ JsonNode node = JSON_NODE_PARSER.parse(body);
+ return node.visit(new DocumentUnmarshaller());
+ }
+
+
+}
diff --git a/core/imds/src/main/java/software/amazon/awssdk/imds/internal/DefaultEc2Metadata.java b/core/imds/src/main/java/software/amazon/awssdk/imds/internal/DefaultEc2Metadata.java
index da9335da5520..5d1d415d9b2e 100644
--- a/core/imds/src/main/java/software/amazon/awssdk/imds/internal/DefaultEc2Metadata.java
+++ b/core/imds/src/main/java/software/amazon/awssdk/imds/internal/DefaultEc2Metadata.java
@@ -36,6 +36,7 @@
import software.amazon.awssdk.http.SdkHttpMethod;
import software.amazon.awssdk.http.urlconnection.UrlConnectionHttpClient;
import software.amazon.awssdk.imds.Ec2Metadata;
+import software.amazon.awssdk.imds.MetadataResponse;
import software.amazon.awssdk.utils.IoUtils;
/**
@@ -145,11 +146,12 @@ public String toString() {
/**
* Gets the specified instance metadata value by the given path.
* @param path Input path
- * @return Instance metadata value
+ * @return Instance metadata value as part of MetadataResponse Object
*/
@Override
- public String get(String path) {
+ public MetadataResponse get(String path) {
+ MetadataResponse metadataResponse = null;
String data = null;
AbortableInputStream abortableInputStream = null;
try {
@@ -164,6 +166,7 @@ public String get(String path) {
if (statusCode == HttpURLConnection.HTTP_OK && responseBody.isPresent()) {
abortableInputStream = responseBody.get();
data = IoUtils.toUtf8String(abortableInputStream);
+ metadataResponse = new MetadataResponse(data);
} else if (statusCode == HttpURLConnection.HTTP_NOT_FOUND) {
throw SdkServiceException.builder()
.message("The requested metadata at path ( " + path + " ) is not found ").build();
@@ -184,7 +187,7 @@ public String get(String path) {
IoUtils.closeQuietly(abortableInputStream, log);
}
- return data;
+ return metadataResponse;
}
private String getToken() throws IOException {
diff --git a/core/imds/src/test/java/software/amazon/awssdk/imds/Ec2MetadataTest.java b/core/imds/src/test/java/software/amazon/awssdk/imds/Ec2MetadataTest.java
index cc3a1f2d53dd..70bf073ed144 100644
--- a/core/imds/src/test/java/software/amazon/awssdk/imds/Ec2MetadataTest.java
+++ b/core/imds/src/test/java/software/amazon/awssdk/imds/Ec2MetadataTest.java
@@ -40,7 +40,8 @@
import org.mockito.junit.MockitoJUnitRunner;
import software.amazon.awssdk.core.SdkSystemSetting;
import software.amazon.awssdk.core.exception.SdkServiceException;
-import software.amazon.awssdk.http.ExecutableHttpRequest;
+import software.amazon.awssdk.protocols.jsoncore.JsonNode;
+import software.amazon.awssdk.protocols.jsoncore.JsonNodeParser;
/**
* Unit Tests to test the Ec2Metadata Client functionality
@@ -65,6 +66,8 @@ public class Ec2MetadataTest {
@Rule
public WireMockRule mockMetadataEndpoint = new WireMockRule();
+ private static final JsonNodeParser jsonParser = JsonNode.parser();
+
@Before
public void methodSetup() {
System.setProperty(SdkSystemSetting.AWS_EC2_METADATA_SERVICE_ENDPOINT.property(), "http://localhost:" + mockMetadataEndpoint.port());
@@ -74,8 +77,9 @@ public void methodSetup() {
@Test
public void when_dummy_string_is_returned(){
- when(ec2Metadata.get("/ami-id")).thenReturn("IMDS");
- assertThat(ec2Metadata.get("/ami-id")).isEqualTo("IMDS");
+ MetadataResponse metadataResponse = new MetadataResponse("IMDS");
+ when(ec2Metadata.get("/ami-id")).thenReturn(metadataResponse);
+ assertThat(ec2Metadata.get("/ami-id").asString()).isEqualTo("IMDS");
}
@@ -93,9 +97,9 @@ public void get_AmiId_onMetadataResource_200_Success() throws IOException {
stubFor(get(urlPathEqualTo(AMI_ID_RESOURCE)).willReturn(aResponse().withBody("{}")));
Ec2Metadata ec2Metadata = Ec2Metadata.builder().endpoint(URI.create("http://localhost:8080")).build();
- String data = ec2Metadata.get("/latest/meta-data/ami-id");
- assertThat(data).isEqualTo("{}");
+ MetadataResponse metadataResponse = ec2Metadata.get("/latest/meta-data/ami-id");
+ assertThat(metadataResponse.asString()).isEqualTo("{}");
WireMock.verify(putRequestedFor(urlPathEqualTo(TOKEN_RESOURCE_PATH)).withHeader(EC2_METADATA_TOKEN_TTL_HEADER, equalTo("21600")));
WireMock.verify(getRequestedFor(urlPathEqualTo(AMI_ID_RESOURCE)).withHeader(TOKEN_HEADER, equalTo("some-token")));
@@ -111,7 +115,7 @@ public void get_AmiId_onMetadataResource_404Error_throws() throws IOException {
stubFor(get(urlPathEqualTo(AMI_ID_RESOURCE)).willReturn(aResponse().withBody("{}").withStatus(404)));
Ec2Metadata ec2Metadata = Ec2Metadata.builder().endpoint(URI.create("http://localhost:8080")).build();
- String data = ec2Metadata.get("/latest/meta-data/ami-id");
+ MetadataResponse metadataResponse = ec2Metadata.get("/latest/meta-data/ami-id");
}
@Test
@@ -121,9 +125,8 @@ public void get_AmiId_onMetadataResource_401Error_throws() throws IOException {
stubFor(get(urlPathEqualTo(AMI_ID_RESOURCE)).willReturn(aResponse().withBody("{}").withStatus(401)));
Ec2Metadata ec2Metadata = Ec2Metadata.builder().endpoint(URI.create("http://localhost:8080")).build();
- String data = ec2Metadata.get("/latest/meta-data/ami-id");
-
- assertThat(data).isNull();
+ MetadataResponse metadataResponse = ec2Metadata.get("/latest/meta-data/ami-id");
+ assertThat(metadataResponse).isNull();
}
@Test
@@ -133,9 +136,9 @@ public void get_AmiId_onMetadataResource_IOException_throws() {
stubFor(get(urlPathEqualTo(AMI_ID_RESOURCE)).willReturn(aResponse().withFixedDelay(Integer.MAX_VALUE)));
Ec2Metadata ec2Metadata = Ec2Metadata.builder().endpoint(URI.create("http://localhost:8080")).build();
- String data = ec2Metadata.get("/latest/meta-data/ami-id");
- assertThat(data).isNull();
+ MetadataResponse metadataResponse = ec2Metadata.get("/latest/meta-data/ami-id");
+ assertThat(metadataResponse).isNull();
WireMock.verify(putRequestedFor(urlPathEqualTo(TOKEN_RESOURCE_PATH)).withHeader(EC2_METADATA_TOKEN_TTL_HEADER, equalTo("21600")));
WireMock.verify(getRequestedFor(urlPathEqualTo(AMI_ID_RESOURCE)).withHeader(TOKEN_HEADER, equalTo("some-token")));
@@ -151,7 +154,7 @@ public void get_AmiId_onTokenResource_403Error_throws() throws IOException {
stubFor(get(urlPathEqualTo(AMI_ID_RESOURCE)).willReturn(aResponse().withBody("{}")));
Ec2Metadata ec2Metadata = Ec2Metadata.builder().endpoint(URI.create("http://localhost:8080")).build();
- String data = ec2Metadata.get("/latest/meta-data/ami-id");
+ MetadataResponse metadataResponse = ec2Metadata.get("/latest/meta-data/ami-id");
}
@Test
@@ -161,9 +164,9 @@ public void get_AmiId_onTokenResource_401Error_throws() throws IOException {
stubFor(get(urlPathEqualTo(AMI_ID_RESOURCE)).willReturn(aResponse().withBody("{}")));
Ec2Metadata ec2Metadata = Ec2Metadata.builder().endpoint(URI.create("http://localhost:8080")).build();
- String data = ec2Metadata.get("/latest/meta-data/ami-id");
- assertThat(data).isNull();
+ MetadataResponse metadataResponse = ec2Metadata.get("/latest/meta-data/ami-id");
+ assertThat(metadataResponse).isNull();
WireMock.verify(putRequestedFor(urlPathEqualTo(TOKEN_RESOURCE_PATH)).withHeader(EC2_METADATA_TOKEN_TTL_HEADER, equalTo("21600")));
}
@@ -174,12 +177,10 @@ public void getAmiId_onTokenResource_IOError_throws() throws IOException {
stubFor(get(urlPathEqualTo(AMI_ID_RESOURCE)).willReturn(aResponse().withBody("{}")));
Ec2Metadata ec2Metadata = Ec2Metadata.builder().endpoint(URI.create("http://localhost:8080")).build();
- String data = ec2Metadata.get("/latest/meta-data/ami-id");
-
- assertThat(data).isNull();
+ MetadataResponse metadataResponse = ec2Metadata.get("/latest/meta-data/ami-id");
+ assertThat(metadataResponse).isNull();
WireMock.verify(putRequestedFor(urlPathEqualTo(TOKEN_RESOURCE_PATH)).withHeader(EC2_METADATA_TOKEN_TTL_HEADER, equalTo("21600")));
- // WireMock.verify(getRequestedFor(urlPathEqualTo(AMI_ID_RESOURCE)).withHeader(TOKEN_HEADER, equalTo("some-token")));
}
@Test
public void getAmiId_onTokenResource_200() throws IOException {
@@ -187,9 +188,9 @@ public void getAmiId_onTokenResource_200() throws IOException {
stubFor(get(urlPathEqualTo(AMI_ID_RESOURCE)).willReturn(aResponse().withBody("{}")));
Ec2Metadata ec2Metadata = Ec2Metadata.builder().endpoint(URI.create("http://localhost:8080")).build();
- String data = ec2Metadata.get("/latest/meta-data/ami-id");
- assertThat(data).isEqualTo("{}");
+ MetadataResponse metadataResponse = ec2Metadata.get("/latest/meta-data/ami-id");
+ assertThat(metadataResponse.asString()).isEqualTo("{}");
WireMock.verify(putRequestedFor(urlPathEqualTo(TOKEN_RESOURCE_PATH)).withHeader(EC2_METADATA_TOKEN_TTL_HEADER, equalTo("21600")));
WireMock.verify(getRequestedFor(urlPathEqualTo(AMI_ID_RESOURCE)).withHeader(TOKEN_HEADER, equalTo("some-token")));
diff --git a/core/imds/src/test/java/software/amazon/awssdk/imds/MetadataResponseTest.java b/core/imds/src/test/java/software/amazon/awssdk/imds/MetadataResponseTest.java
new file mode 100644
index 000000000000..e41050922315
--- /dev/null
+++ b/core/imds/src/test/java/software/amazon/awssdk/imds/MetadataResponseTest.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License").
+ * You may not use this file except in compliance with the License.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. This file is distributed
+ * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package software.amazon.awssdk.imds;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import software.amazon.awssdk.core.document.Document;
+
+/**
+ * The class tests the utility methods provided by MetadataResponse Class .
+ */
+public class MetadataResponseTest {
+
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ @Test
+ public void check_asString_success() throws IOException {
+
+ String response = "foobar";
+
+ MetadataResponse metadataResponse = new MetadataResponse(response);
+ String result = metadataResponse.asString();
+ assertThat(result).isEqualTo(response);
+
+ }
+
+ @Test
+ public void check_asString_failure() throws IOException {
+
+ thrown.expect(NullPointerException.class);
+ thrown.expectMessage("Metadata is null");
+
+ MetadataResponse metadataResponse = new MetadataResponse(null);
+ String result = metadataResponse.asString();
+ }
+
+ @Test
+ public void check_asList_success_with_delimiter() throws IOException {
+
+ String response = "sai\ntest";
+
+ MetadataResponse metadataResponse = new MetadataResponse(response);
+ List