diff --git a/core/regions/src/it/java/software/amazon/awssdk/regions/util/EC2MetadataUtilsIntegrationTest.java b/core/regions/src/it/java/software/amazon/awssdk/regions/util/EC2MetadataUtilsIntegrationTest.java index 1764cedb5d9c..b19a2a3703f0 100644 --- a/core/regions/src/it/java/software/amazon/awssdk/regions/util/EC2MetadataUtilsIntegrationTest.java +++ b/core/regions/src/it/java/software/amazon/awssdk/regions/util/EC2MetadataUtilsIntegrationTest.java @@ -64,4 +64,24 @@ public void testInstanceSignature() { String signature = EC2MetadataUtils.getInstanceSignature(); Assert.assertEquals("foobar", signature); } + + @Test + public void testInstanceInfo() { + EC2MetadataUtils.InstanceInfo info = EC2MetadataUtils.getInstanceInfo(); + Assert.assertEquals("2014-08-07T22:07:46Z", info.getPendingTime()); + Assert.assertEquals("m1.small", info.getInstanceType()); + Assert.assertEquals("ami-a49665cc", info.getImageId()); + Assert.assertEquals("i-6b2de041", info.getInstanceId()); + Assert.assertEquals("foo", info.getBillingProducts()[0]); + Assert.assertEquals("x86_64", info.getArchitecture()); + Assert.assertEquals("599169622985", info.getAccountId()); + Assert.assertEquals("aki-919dcaf8", info.getKernelId()); + Assert.assertEquals("baz", info.getRamdiskId()); + Assert.assertEquals("us-east-1", info.getRegion()); + Assert.assertEquals("2010-08-31", info.getVersion()); + Assert.assertEquals("us-east-1b", info.getAvailabilityZone()); + Assert.assertEquals("10.201.215.38", info.getPrivateIp()); + Assert.assertEquals("bar", info.getDevpayProductCodes()[0]); + Assert.assertEquals("qaz", info.getMarketplaceProductCodes()[0]); + } } diff --git a/core/regions/src/main/java/software/amazon/awssdk/regions/internal/util/EC2MetadataUtils.java b/core/regions/src/main/java/software/amazon/awssdk/regions/internal/util/EC2MetadataUtils.java index 5df92523ec8a..e6ba2ff54b3a 100644 --- a/core/regions/src/main/java/software/amazon/awssdk/regions/internal/util/EC2MetadataUtils.java +++ b/core/regions/src/main/java/software/amazon/awssdk/regions/internal/util/EC2MetadataUtils.java @@ -283,6 +283,63 @@ public static String getUserData() { return getData(EC2_USERDATA_ROOT); } + /** + * Retrieve some of the data from http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html as a typed + * object. This entire class will be removed as part of https://github.com/aws/aws-sdk-java-v2/issues/61, so don't rely on + * this sticking around. + * + * This should not be removed until https://github.com/aws/aws-sdk-java-v2/issues/61 is implemented. + */ + public static InstanceInfo getInstanceInfo() { + return doGetInstanceInfo(getData(EC2_DYNAMICDATA_ROOT + INSTANCE_IDENTITY_DOCUMENT)); + } + + static InstanceInfo doGetInstanceInfo(String json) { + if (json != null) { + try { + Map jsonNode = JSON_PARSER.parse(json).asObject(); + return new InstanceInfo(stringValue(jsonNode.get("pendingTime")), + stringValue(jsonNode.get("instanceType")), + stringValue(jsonNode.get("imageId")), + stringValue(jsonNode.get("instanceId")), + stringArrayValue(jsonNode.get("billingProducts")), + stringValue(jsonNode.get("architecture")), + stringValue(jsonNode.get("accountId")), + stringValue(jsonNode.get("kernelId")), + stringValue(jsonNode.get("ramdiskId")), + stringValue(jsonNode.get("region")), + stringValue(jsonNode.get("version")), + stringValue(jsonNode.get("availabilityZone")), + stringValue(jsonNode.get("privateIp")), + stringArrayValue(jsonNode.get("devpayProductCodes")), + stringArrayValue(jsonNode.get("marketplaceProductCodes"))); + } catch (Exception e) { + log.warn("Unable to parse dynamic EC2 instance info (" + json + ") : " + e.getMessage(), e); + } + } + return null; + } + + private static String stringValue(JsonNode jsonNode) { + if (jsonNode == null || !jsonNode.isString()) { + return null; + } + + return jsonNode.asString(); + } + + private static String[] stringArrayValue(JsonNode jsonNode) { + if (jsonNode == null || !jsonNode.isArray()) { + return null; + } + + return jsonNode.asArray() + .stream() + .filter(JsonNode::isString) + .map(JsonNode::asString) + .toArray(String[]::new); + } + public static String getData(String path) { return getData(path, DEFAULT_QUERY_RETRIES); } @@ -587,4 +644,120 @@ public Map headers() { return requestHeaders; } } + + + public static class InstanceInfo { + private final String pendingTime; + private final String instanceType; + private final String imageId; + private final String instanceId; + private final String[] billingProducts; + private final String architecture; + private final String accountId; + private final String kernelId; + private final String ramdiskId; + private final String region; + private final String version; + private final String availabilityZone; + private final String privateIp; + private final String[] devpayProductCodes; + private final String[] marketplaceProductCodes; + + public InstanceInfo( + String pendingTime, + String instanceType, + String imageId, + String instanceId, + String[] billingProducts, + String architecture, + String accountId, + String kernelId, + String ramdiskId, + String region, + String version, + String availabilityZone, + String privateIp, + String[] devpayProductCodes, + String[] marketplaceProductCodes) { + + this.pendingTime = pendingTime; + this.instanceType = instanceType; + this.imageId = imageId; + this.instanceId = instanceId; + this.billingProducts = billingProducts == null + ? null : billingProducts.clone(); + this.architecture = architecture; + this.accountId = accountId; + this.kernelId = kernelId; + this.ramdiskId = ramdiskId; + this.region = region; + this.version = version; + this.availabilityZone = availabilityZone; + this.privateIp = privateIp; + this.devpayProductCodes = devpayProductCodes == null + ? null : devpayProductCodes.clone(); + this.marketplaceProductCodes = marketplaceProductCodes == null + ? null : marketplaceProductCodes.clone(); + } + + public String getPendingTime() { + return pendingTime; + } + + public String getInstanceType() { + return instanceType; + } + + public String getImageId() { + return imageId; + } + + public String getInstanceId() { + return instanceId; + } + + public String[] getBillingProducts() { + return billingProducts == null ? null : billingProducts.clone(); + } + + public String getArchitecture() { + return architecture; + } + + public String getAccountId() { + return accountId; + } + + public String getKernelId() { + return kernelId; + } + + public String getRamdiskId() { + return ramdiskId; + } + + public String getRegion() { + return region; + } + + public String getVersion() { + return version; + } + + public String getAvailabilityZone() { + return availabilityZone; + } + + public String getPrivateIp() { + return privateIp; + } + + public String[] getDevpayProductCodes() { + return devpayProductCodes == null ? null : devpayProductCodes.clone(); + } + + public String[] getMarketplaceProductCodes() { + return marketplaceProductCodes == null ? null : marketplaceProductCodes.clone(); + } + } } diff --git a/core/regions/src/test/java/software/amazon/awssdk/regions/internal/util/Ec2MetadataUtilsTt0049160280Test.java b/core/regions/src/test/java/software/amazon/awssdk/regions/internal/util/Ec2MetadataUtilsTt0049160280Test.java index 74be06885ddc..f58860822c5f 100644 --- a/core/regions/src/test/java/software/amazon/awssdk/regions/internal/util/Ec2MetadataUtilsTt0049160280Test.java +++ b/core/regions/src/test/java/software/amazon/awssdk/regions/internal/util/Ec2MetadataUtilsTt0049160280Test.java @@ -42,4 +42,37 @@ public void getRegionIntern() throws Exception { String region = EC2MetadataUtils.doGetEC2InstanceRegion(JSON); Assert.assertEquals("us-east-1", region); } + + @Test + public void tt0049160280() { + EC2MetadataUtils.InstanceInfo info = EC2MetadataUtils.doGetInstanceInfo(JSON); + String[] billingProducts = info.getBillingProducts(); + Assert.assertTrue(billingProducts.length == 1); + Assert.assertEquals(billingProducts[0], "bp-6ba54002"); + } + + @Test + public void devProductCodes() { + final String JSON = "{" + + " \"privateIp\" : \"172.31.56.174\"," + + " \"devpayProductCodes\" : [\"foo\", \"bar\"]," + + " \"availabilityZone\" : \"us-east-1b\"," + + " \"version\" : \"2010-08-31\"," + + " \"accountId\" : \"123456789012\"," + + " \"instanceId\" : \"i-b32c0064\"," + + " \"billingProducts\" : [\"bp-6ba54002\" ]," + + " \"imageId\" : \"ami-ac3a1cc4\"," + + " \"instanceType\" : \"t2.small\"," + + " \"kernelId\" : null," + + " \"ramdiskId\" : null," + + " \"pendingTime\" : \"2015-04-13T19:57:24Z\"," + + " \"architecture\" : \"x86_64\"," + + " \"region\" : \"us-east-1\"" + + "}"; + EC2MetadataUtils.InstanceInfo info = EC2MetadataUtils.doGetInstanceInfo(JSON); + String[] devpayProductCodes = info.getDevpayProductCodes(); + Assert.assertTrue(devpayProductCodes.length == 2); + Assert.assertEquals(devpayProductCodes[0], "foo"); + Assert.assertEquals(devpayProductCodes[1], "bar"); + } }