diff --git a/pom.xml b/pom.xml index 675e69c..8a1d4ac 100644 --- a/pom.xml +++ b/pom.xml @@ -45,6 +45,17 @@ + + + + software.amazon.awssdk + bom + 2.21.17 + pom + import + + + org.jgroups @@ -62,9 +73,12 @@ - com.amazonaws - aws-java-sdk-ec2 - 1.11.125 + software.amazon.awssdk + ec2 + + + software.amazon.awssdk + regions org.slf4j @@ -91,8 +105,8 @@ org.mockito - mockito-all - 1.9.5 + mockito-core + 5.7.0 test diff --git a/src/main/java/com/meltmedia/jgroups/aws/AWSFaultLogger.java b/src/main/java/com/meltmedia/jgroups/aws/AWSFaultLogger.java deleted file mode 100644 index c044c1d..0000000 --- a/src/main/java/com/meltmedia/jgroups/aws/AWSFaultLogger.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.meltmedia.jgroups.aws; - -import com.amazonaws.AmazonServiceException; -import com.amazonaws.Request; -import com.amazonaws.handlers.RequestHandler; -import com.amazonaws.transform.Unmarshaller; -import com.amazonaws.util.TimingInfo; -import org.jgroups.logging.Log; -import org.jgroups.logging.LogFactory; -import org.w3c.dom.Node; - -import javax.xml.transform.Result; -import javax.xml.transform.Source; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerFactory; -import java.io.StringWriter; - -/** - * This class will log the request along with the response from the AWS ec2 service on fault only. - * - * @author John McEntire - */ -@SuppressWarnings("deprecation") -class AWSFaultLogger implements Unmarshaller, RequestHandler { - private static Log log = LogFactory.getLog(AWS_PING.class); - private final ThreadLocal> request = new ThreadLocal<>(); - - @Override - public AmazonServiceException unmarshall(Node node) throws Exception { - try { - final TransformerFactory tfactory = TransformerFactory.newInstance(); - final Transformer xform = tfactory.newTransformer(); - final Source src = new javax.xml.transform.dom.DOMSource(node); - final StringWriter writer = new StringWriter(); - final Result result = new javax.xml.transform.stream.StreamResult(writer); - - xform.transform(src, result); - log.error("AWS Exception: [%s] For request [%s]", writer, request.get()); - } catch (Throwable t) { - log.debug("Failed to log xml soap fault message.", t); - } finally { - request.remove(); - } - return null; - } - - @Override - public void afterError(Request request, Exception e) { - this.request.remove(); - } - - @Override - public void afterResponse(Request request, Object obj, TimingInfo timing) { - this.request.remove(); - } - - @Override - public void beforeRequest(Request request) { - this.request.set(request); - } -} diff --git a/src/main/java/com/meltmedia/jgroups/aws/AWS_PING.java b/src/main/java/com/meltmedia/jgroups/aws/AWS_PING.java index a9ef5ce..a530408 100644 --- a/src/main/java/com/meltmedia/jgroups/aws/AWS_PING.java +++ b/src/main/java/com/meltmedia/jgroups/aws/AWS_PING.java @@ -15,12 +15,6 @@ */ package com.meltmedia.jgroups.aws; -import com.amazonaws.services.ec2.AmazonEC2; -import com.amazonaws.services.ec2.model.DescribeInstancesRequest; -import com.amazonaws.services.ec2.model.Filter; -import com.amazonaws.services.ec2.model.Instance; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClients; import org.jgroups.Address; import org.jgroups.Event; import org.jgroups.Message; @@ -32,6 +26,12 @@ import org.jgroups.stack.IpAddress; import org.jgroups.util.NameCache; import org.jgroups.util.Responses; +import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider; +import software.amazon.awssdk.regions.internal.util.EC2MetadataUtils; +import software.amazon.awssdk.services.ec2.Ec2Client; +import software.amazon.awssdk.services.ec2.model.DescribeInstancesRequest; +import software.amazon.awssdk.services.ec2.model.Filter; +import software.amazon.awssdk.services.ec2.model.Instance; import java.util.List; import java.util.Objects; @@ -124,7 +124,7 @@ public class AWS_PING extends Discovery { } @Property(description = "The AWS Credentials Chain Class to use when searching for the account.") - protected String credentials_provider_class = com.amazonaws.auth.DefaultAWSCredentialsProviderChain.class.getName(); + protected String credentials_provider_class = DefaultCredentialsProvider.class.getName(); @Property(description = "The AWS Access Key for the account to search.") protected String access_key; @Property(description = "The AWS Secret Key for the account to search.") @@ -145,12 +145,12 @@ public class AWS_PING extends Discovery { /** * This is looked up using the endpoint http://instance-data/latest/dynamic/instance-identity/document */ - private InstanceIdentity instanceIdentity; + private EC2MetadataUtils.InstanceInfo instanceInfo; /** * The Service for all AWS related stuff */ - private AmazonEC2 ec2; + private Ec2Client ec2; /** * Utility for expanding one ip address + port and range to multiple address:port @@ -175,24 +175,21 @@ public void init() throws Exception { super.init(); //get the instance identity - try (CloseableHttpClient client = HttpClients.createDefault()) { - this.instanceIdentity = InstanceIdentity.getIdentity(client); - } + this.instanceInfo = EC2MetadataUtils.getInstanceInfo(); //setup ec2 client this.ec2 = EC2Factory.create( - instanceIdentity, + instanceInfo, access_key, secret_key, credentials_provider_class, - new CredentialsProviderFactory(), - log_aws_error_messages); + new CredentialsProviderFactory()); this.ipAddressUtils = new IPAddressUtils(port_number, port_range); - this.tagUtils = new TagsUtils(ec2, instanceIdentity, tags).validateTags(); + this.tagUtils = new TagsUtils(ec2, instanceInfo, tags).validateTags(); this.filterUtils = new FilterUtils(filters, tagUtils); - log.info("Configured for instance: " + instanceIdentity.instanceId); + log.info("Configured for instance: " + instanceInfo.getInstanceId()); filterUtils.getAwsFilters().ifPresent(f -> log.info("Configured with filters [%s]", f)); tagUtils.getAwsTagNames().ifPresent(t -> log.info("Configured with tags [%s]", t)); } @@ -204,7 +201,7 @@ public void init() throws Exception { public void stop() { try { if (ec2 != null) { - ec2.shutdown(); + ec2.close(); } } finally { super.stop(); @@ -264,7 +261,7 @@ private List getPrivateIpAddresses() { // if there are aws filters defined, add them to the list. filterUtils.getAwsFilters().ifPresent(filters::addAll); - final DescribeInstancesRequest request = new DescribeInstancesRequest().withFilters(filters); + final DescribeInstancesRequest request = DescribeInstancesRequest.builder().filters(filters).build(); if (log.isDebugEnabled()) { log.debug("Describing AWS instances with the following filters [%s]", filters); @@ -273,9 +270,9 @@ private List getPrivateIpAddresses() { // NOTE: the reservations group nodes together by when they were started. We // need to dig through all of the reservations. - final List result = ec2.describeInstances(request).getReservations().stream() - .flatMap(reservation -> reservation.getInstances().stream()) - .map(Instance::getPrivateIpAddress) + final List result = ec2.describeInstancesPaginator(request).reservations().stream() + .flatMap(reservation -> reservation.instances().stream()) + .map(Instance::privateIpAddress) .filter(Objects::nonNull) .collect(Collectors.toList()); diff --git a/src/main/java/com/meltmedia/jgroups/aws/CredentialsProviderFactory.java b/src/main/java/com/meltmedia/jgroups/aws/CredentialsProviderFactory.java index de38bb6..1749a25 100644 --- a/src/main/java/com/meltmedia/jgroups/aws/CredentialsProviderFactory.java +++ b/src/main/java/com/meltmedia/jgroups/aws/CredentialsProviderFactory.java @@ -1,9 +1,9 @@ package com.meltmedia.jgroups.aws; -import com.amazonaws.auth.AWSCredentialsProvider; import org.jgroups.logging.Log; import org.jgroups.logging.LogFactory; import org.jgroups.util.Util; +import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; public class CredentialsProviderFactory { private final Log log; @@ -24,16 +24,14 @@ public CredentialsProviderFactory(final Log log) { * @throws ClassNotFoundException if the implementation could not be found. * @throws InstantiationException if the implementation does not have a no argument constructor. */ - public AWSCredentialsProvider createCredentialsProvider(final String credentialProviderClass) throws Exception { + public AwsCredentialsProvider createCredentialsProvider(final String credentialProviderClass) throws Exception { try { final Class credsProviderClazz = Util.loadClass(credentialProviderClass, getClass()); - return (AWSCredentialsProvider) credsProviderClazz.newInstance(); + return (AwsCredentialsProvider) credsProviderClazz.getMethod("create").invoke(null); + } catch (NoSuchMethodException e) { + throw new Exception("unable to find create method on credentials provider class " + credentialProviderClass); } catch (ClassNotFoundException e) { throw new Exception("unable to load credentials provider class " + credentialProviderClass); - } catch (InstantiationException e) { - log.error("an instance of " + credentialProviderClass + " could not be created. Please check that it implements" + - " interface AWSCredentialsProvider and that is has a public empty constructor !"); - throw e; } } } diff --git a/src/main/java/com/meltmedia/jgroups/aws/EC2Factory.java b/src/main/java/com/meltmedia/jgroups/aws/EC2Factory.java index 05400b7..d4abdaa 100644 --- a/src/main/java/com/meltmedia/jgroups/aws/EC2Factory.java +++ b/src/main/java/com/meltmedia/jgroups/aws/EC2Factory.java @@ -1,17 +1,11 @@ package com.meltmedia.jgroups.aws; -import com.amazonaws.AmazonServiceException; -import com.amazonaws.auth.AWSCredentialsProvider; -import com.amazonaws.auth.BasicAWSCredentials; -import com.amazonaws.handlers.RequestHandler; -import com.amazonaws.internal.StaticCredentialsProvider; -import com.amazonaws.services.ec2.AmazonEC2; -import com.amazonaws.services.ec2.AmazonEC2Client; -import com.amazonaws.transform.Unmarshaller; -import org.w3c.dom.Node; - -import java.lang.reflect.Field; -import java.util.List; +import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; +import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; +import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.regions.internal.util.EC2MetadataUtils; +import software.amazon.awssdk.services.ec2.Ec2Client; /** @@ -19,71 +13,37 @@ */ @SuppressWarnings("deprecation") public class EC2Factory { - private static String EC2_ENDPOINT_TEMPLATE = "ec2.{REGION}.amazonaws.com"; - - public static AmazonEC2 create( - final InstanceIdentity instanceIdentity, + public static Ec2Client create( + final EC2MetadataUtils.InstanceInfo instanceInfo, final String accessKey, final String secretKey, final String credentialsProviderClass, - final CredentialsProviderFactory credentialsProviderFactory, - final Boolean logAwsErrorMessages) throws Exception { + final CredentialsProviderFactory credentialsProviderFactory + ) throws Exception { - final AmazonEC2 ec2 = setupEC2Client( - instanceIdentity.region, + return setupEC2Client( + instanceInfo.getRegion(), accessKey, secretKey, credentialsProviderClass, credentialsProviderFactory); - - //Lets do some good old reflection work to add a unmarshaller to the AmazonEC2Client just to log the exceptions from soap. - if (logAwsErrorMessages) { - setupAWSExceptionLogging(ec2); - } - return ec2; } - private static AmazonEC2 setupEC2Client( + private static Ec2Client setupEC2Client( final String region, final String accessKey, final String secretKey, final String credentialsProviderClass, final CredentialsProviderFactory credentialsProviderFactory) throws Exception { - final String endpoint = EC2_ENDPOINT_TEMPLATE.replace("{REGION}", region); - final AWSCredentialsProvider credentialsProvider = accessKey == null && secretKey == null ? + final AwsCredentialsProvider credentialsProvider = accessKey == null && secretKey == null ? credentialsProviderFactory.createCredentialsProvider(credentialsProviderClass) : - new StaticCredentialsProvider(new BasicAWSCredentials(accessKey, secretKey)); - - final AmazonEC2 ec2 = new AmazonEC2Client(credentialsProvider); - ec2.setEndpoint(endpoint); - return ec2; - } + StaticCredentialsProvider.create(AwsBasicCredentials.create(accessKey, secretKey)); - /** - * Sets up the AmazonEC2Client to log soap faults from the AWS EC2 api server. - */ - private static void setupAWSExceptionLogging(AmazonEC2 ec2) { - boolean accessible = false; - Field exceptionUnmarshallersField = null; - try { - exceptionUnmarshallersField = AmazonEC2Client.class.getDeclaredField("exceptionUnmarshallers"); - accessible = exceptionUnmarshallersField.isAccessible(); - exceptionUnmarshallersField.setAccessible(true); - @SuppressWarnings("unchecked") final List> exceptionUnmarshallers = (List>) exceptionUnmarshallersField.get(ec2); - exceptionUnmarshallers.add(0, new AWSFaultLogger()); - ((AmazonEC2Client) ec2).addRequestHandler((RequestHandler) exceptionUnmarshallers.get(0)); - } catch (Throwable t) { - //I don't care about this. - } finally { - if (exceptionUnmarshallersField != null) { - try { - exceptionUnmarshallersField.setAccessible(accessible); - } catch (SecurityException se) { - //I don't care about this. - } - } - } + return Ec2Client.builder() + .credentialsProvider(credentialsProvider) + .region(Region.of(region)) + .build(); } } diff --git a/src/main/java/com/meltmedia/jgroups/aws/FilterUtils.java b/src/main/java/com/meltmedia/jgroups/aws/FilterUtils.java index 351bd0f..6eaebec 100644 --- a/src/main/java/com/meltmedia/jgroups/aws/FilterUtils.java +++ b/src/main/java/com/meltmedia/jgroups/aws/FilterUtils.java @@ -1,14 +1,13 @@ package com.meltmedia.jgroups.aws; -import com.amazonaws.services.ec2.model.Filter; import org.jgroups.util.Tuple; +import software.amazon.awssdk.services.ec2.model.Filter; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; -import java.util.stream.Stream; public class FilterUtils { private final TagsUtils tagsUtils; @@ -40,13 +39,12 @@ public Optional> getAwsFilters() { */ @SuppressWarnings("OptionalUsedAsFieldOrParameterType") public List instanceTagNamesToFilters() { - return tagsUtils.getAwsTagNames().map(Stream::of).orElseGet(Stream::empty) - .map(tagNames -> new Tuple<>(tagNames, tagsUtils.getInstanceTags())) - .flatMap(namesAndTags -> namesAndTags.getVal2() - .stream() - .filter(tag -> namesAndTags.getVal1().contains(tag.getKey()))) - .map(tag -> new Filter("tag:" + tag.getKey(), Collections.singletonList(tag.getValue()))) - .collect(Collectors.toList()); + return tagsUtils.getAwsTagNames().map(tagNames -> + tagsUtils.getInstanceTags().stream() + .filter(tag -> tagNames.contains(tag.key())) + .map(tag -> Filter.builder().name("tag:" + tag.key()).values(tag.value()).build()) + .collect(Collectors.toList()) + ).orElseGet(Collections::emptyList); } /** @@ -73,7 +71,11 @@ private static List parseFilters(String filters) { .map(String::trim) .filter(s -> !s.isEmpty()) .map(FilterUtils::splitToTuple) - .map(keyAndValue -> new Filter(keyAndValue.getVal1(), splitValues(keyAndValue.getVal2()))) + .map(keyAndValue -> Filter.builder() + .name(keyAndValue.getVal1()) + .values(splitValues(keyAndValue.getVal2())) + .build() + ) .collect(Collectors.toList()); } diff --git a/src/main/java/com/meltmedia/jgroups/aws/InstanceIdentity.java b/src/main/java/com/meltmedia/jgroups/aws/InstanceIdentity.java deleted file mode 100644 index 3f86ef6..0000000 --- a/src/main/java/com/meltmedia/jgroups/aws/InstanceIdentity.java +++ /dev/null @@ -1,83 +0,0 @@ -package com.meltmedia.jgroups.aws; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.apache.http.HttpResponse; -import org.apache.http.HttpStatus; -import org.apache.http.client.HttpClient; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.util.EntityUtils; - -import java.io.IOException; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.Objects; - -@JsonIgnoreProperties(ignoreUnknown = true) -public class InstanceIdentity { - - private static final String INSTANCE_DATA = System.getProperty("instance.data", "169.254.169.254"); - private static final String INSTANCE_IDENTITY_URL = String.format("http://%s/latest/dynamic/instance-identity/document", INSTANCE_DATA); - - private static URI INSTANCE_IDENTITY_URI; - - static { - try { - INSTANCE_IDENTITY_URI = new URI(INSTANCE_IDENTITY_URL); - } catch (URISyntaxException e) { - throw new RuntimeException("this should never happen"); - } - } - - - public final String availabilityZone; - public final String privateIp; - public final String instanceId; - public final String instanceType; - public final String imageId; - public final String architecture; - public final String region; - - public InstanceIdentity( - @JsonProperty("availabilityZone") final String availabilityZone, - @JsonProperty("privateIp") final String privateIp, - @JsonProperty("instanceId") final String instanceId, - @JsonProperty("instanceType") final String instanceType, - @JsonProperty("imageId") final String imageId, - @JsonProperty("architecture") final String architecture, - @JsonProperty("region") final String region) { - this.availabilityZone = Objects.requireNonNull(availabilityZone, "availabilityZone cannot be null"); - this.privateIp = Objects.requireNonNull(privateIp, "privateIp cannot be null"); - this.instanceId = Objects.requireNonNull(instanceId, "instanceId cannot be null"); - this.instanceType = Objects.requireNonNull(instanceType, "instanceType cannot be null"); - this.imageId = Objects.requireNonNull(imageId, "imageId cannot be null"); - this.architecture = Objects.requireNonNull(architecture, "architecture cannot be null"); - this.region = Objects.requireNonNull(region, "region cannot be null"); - } - - public static InstanceIdentity getIdentity(final HttpClient client) throws IOException { - return new ObjectMapper().readValue(getIdentityDocument(client), InstanceIdentity.class); - } - - /** - * Gets the body of the content returned from a GET request to uri. - * - * @param client - * @return the body of the message returned from the GET request. - * @throws IOException if there is an error encountered while getting the content. - */ - private static String getIdentityDocument(final HttpClient client) throws IOException { - try { - final HttpGet getInstance = new HttpGet(); - getInstance.setURI(INSTANCE_IDENTITY_URI); - final HttpResponse response = client.execute(getInstance); - if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) { - throw new IOException("failed to get instance identity, tried: " + INSTANCE_IDENTITY_URL + ", response: " + response.getStatusLine().getReasonPhrase()); - } - return EntityUtils.toString(response.getEntity()); - } catch (Exception e) { - throw new IOException("failed to get instance identity", e); - } - } -} \ No newline at end of file diff --git a/src/main/java/com/meltmedia/jgroups/aws/TagsUtils.java b/src/main/java/com/meltmedia/jgroups/aws/TagsUtils.java index 148b87f..188f098 100644 --- a/src/main/java/com/meltmedia/jgroups/aws/TagsUtils.java +++ b/src/main/java/com/meltmedia/jgroups/aws/TagsUtils.java @@ -1,26 +1,25 @@ package com.meltmedia.jgroups.aws; -import com.amazonaws.services.ec2.AmazonEC2; -import com.amazonaws.services.ec2.model.DescribeInstancesRequest; -import com.amazonaws.services.ec2.model.DescribeInstancesResult; -import com.amazonaws.services.ec2.model.Tag; +import software.amazon.awssdk.regions.internal.util.EC2MetadataUtils; +import software.amazon.awssdk.services.ec2.Ec2Client; +import software.amazon.awssdk.services.ec2.model.Tag; +import software.amazon.awssdk.services.ec2.paginators.DescribeInstancesIterable; import java.util.Arrays; -import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; import java.util.stream.Stream; public class TagsUtils { - private final AmazonEC2 ec2; - private final InstanceIdentity instanceIdentity; + private final Ec2Client ec2; + private final EC2MetadataUtils.InstanceInfo instanceInfo; @SuppressWarnings("OptionalUsedAsFieldOrParameterType") private final Optional> awsTagNames; - public TagsUtils(final AmazonEC2 ec2, final InstanceIdentity instanceIdentity, final String configuredTags) { + public TagsUtils(final Ec2Client ec2, final EC2MetadataUtils.InstanceInfo instanceInfo, final String configuredTags) { this.ec2 = ec2; - this.instanceIdentity = instanceIdentity; + this.instanceInfo = instanceInfo; this.awsTagNames = Optional.ofNullable(configuredTags) .map(String::trim) .filter(tags -> !tags.isEmpty()) @@ -41,13 +40,12 @@ public Optional> getAwsTagNames() { * @return a list of the Tag objects that were found on the instance. */ public List getInstanceTags() { - final DescribeInstancesResult response = ec2 - .describeInstances(new DescribeInstancesRequest() - .withInstanceIds(Collections.singletonList(instanceIdentity.instanceId))); + final DescribeInstancesIterable response = ec2 + .describeInstancesPaginator(b -> b.instanceIds(instanceInfo.getInstanceId())); - return response.getReservations().stream() - .flatMap(reservation -> reservation.getInstances().stream()) - .flatMap(instance -> instance.getTags().stream()) + return response.reservations().stream() + .flatMap(reservation -> reservation.instances().stream()) + .flatMap(instance -> instance.tags().stream()) .collect(Collectors.toList()); } @@ -60,7 +58,7 @@ public List getInstanceTags() { */ public TagsUtils validateTags() { final List instanceTags = getInstanceTags().stream() - .map(Tag::getKey) + .map(Tag::key) .collect(Collectors.toList()); final List missingTags = getAwsTagNames().map(List::stream).orElse(Stream.empty()) @@ -68,7 +66,7 @@ public TagsUtils validateTags() { .collect(Collectors.toList()); if(!missingTags.isEmpty()) { - throw new IllegalStateException("expected instance tag(s) missing: " + missingTags.stream().collect(Collectors.joining(", "))); + throw new IllegalStateException("expected instance tag(s) missing: " + String.join(", ", missingTags)); } return this; diff --git a/src/test/java/com/meltmedia/jgroups/aws/FilterUtilsTest.java b/src/test/java/com/meltmedia/jgroups/aws/FilterUtilsTest.java index 73ba4b5..bced94c 100644 --- a/src/test/java/com/meltmedia/jgroups/aws/FilterUtilsTest.java +++ b/src/test/java/com/meltmedia/jgroups/aws/FilterUtilsTest.java @@ -1,8 +1,9 @@ package com.meltmedia.jgroups.aws; -import com.amazonaws.services.ec2.model.Filter; -import com.amazonaws.services.ec2.model.Tag; import org.junit.Test; +import software.amazon.awssdk.regions.internal.util.EC2MetadataUtils; +import software.amazon.awssdk.services.ec2.model.Filter; +import software.amazon.awssdk.services.ec2.model.Tag; import java.util.List; @@ -10,18 +11,27 @@ import static org.junit.Assert.*; public class FilterUtilsTest { - private static InstanceIdentity instanceIdentity = new InstanceIdentity( - "zone", - "1.2.3.4", - "instance_id", + static final EC2MetadataUtils.InstanceInfo instanceInfo = new EC2MetadataUtils.InstanceInfo( + "pending_time", "instance_type", "image_id", + "instance_id", + new String[]{"billing_products"}, "architecture", - "region"); + "account_id", + "kernel_id", + "ramdisk_id", + "region", + "version", + "zone", + "1.2.3.4", + new String[]{"dev_product_codes"}, + new String[]{"market_place_product_codes"} + ); @Test public void canHandleNullFilterString() { - final TagsUtils tagsUtils = new TagsUtils(ec2Mock(), instanceIdentity, null); + final TagsUtils tagsUtils = new TagsUtils(ec2Mock(), instanceInfo, null); final FilterUtils filterUtils = new FilterUtils(null, tagsUtils); assertFalse(filterUtils.getAwsFilters().isPresent()); @@ -29,7 +39,7 @@ public void canHandleNullFilterString() { @Test public void canHandleEmptyFilterString() { - final TagsUtils tagsUtils = new TagsUtils(ec2Mock(), instanceIdentity, null); + final TagsUtils tagsUtils = new TagsUtils(ec2Mock(), instanceInfo, null); final FilterUtils filterUtils = new FilterUtils(" ", tagsUtils); assertFalse(filterUtils.getAwsFilters().isPresent()); @@ -37,44 +47,44 @@ public void canHandleEmptyFilterString() { @Test public void canParseAwsFilters() { - final TagsUtils tagsUtils = new TagsUtils(ec2Mock(), instanceIdentity, null); + final TagsUtils tagsUtils = new TagsUtils(ec2Mock(), instanceInfo, null); final FilterUtils filterUtils = new FilterUtils("filter1=valueA, valueB; filter2=valueC", tagsUtils); assertTrue(filterUtils.getAwsFilters().isPresent()); filterUtils.getAwsFilters().ifPresent(filters -> { assertEquals(2, filters.size()); Filter filter1 = filters.get(0); - assertEquals("filter1", filter1.getName()); - assertEquals(2, filter1.getValues().size()); - assertEquals("valueA", filter1.getValues().get(0)); - assertEquals("valueB", filter1.getValues().get(1)); + assertEquals("filter1", filter1.name()); + assertEquals(2, filter1.values().size()); + assertEquals("valueA", filter1.values().get(0)); + assertEquals("valueB", filter1.values().get(1)); Filter filter2 = filters.get(1); - assertEquals("filter2", filter2.getName()); - assertEquals(1, filter2.getValues().size()); - assertEquals("valueC", filter2.getValues().get(0)); + assertEquals("filter2", filter2.name()); + assertEquals(1, filter2.values().size()); + assertEquals("valueC", filter2.values().get(0)); }); } @Test public void canCreateFiltersFromMatchingTags() { - final Tag instanceTag1 = new Tag("tag1", "value1"); - final Tag instanceTag2 = new Tag("tag2", "value2"); - final Tag instanceTag3 = new Tag("tag3", "value3"); - final TagsUtils tagsUtils = new TagsUtils(ec2Mock(instanceTag1, instanceTag2, instanceTag3), instanceIdentity, "tag2, tag3"); + final Tag instanceTag1 = Tag.builder().key("tag1").value("value1").build(); + final Tag instanceTag2 = Tag.builder().key("tag2").value("value2").build(); + final Tag instanceTag3 = Tag.builder().key("tag3").value("value3").build(); + final TagsUtils tagsUtils = new TagsUtils(ec2Mock(instanceTag1, instanceTag2, instanceTag3), instanceInfo, "tag2, tag3"); final FilterUtils filterUtils = new FilterUtils(null, tagsUtils); final List filters = filterUtils.instanceTagNamesToFilters(); assertEquals(2, filters.size()); Filter filter1 = filters.get(0); - assertEquals("tag:tag2", filter1.getName()); - assertEquals(1, filter1.getValues().size()); - assertEquals("value2", filter1.getValues().get(0)); + assertEquals("tag:tag2", filter1.name()); + assertEquals(1, filter1.values().size()); + assertEquals("value2", filter1.values().get(0)); Filter filter2 = filters.get(1); - assertEquals("tag:tag3", filter2.getName()); - assertEquals(1, filter2.getValues().size()); - assertEquals("value3", filter2.getValues().get(0)); + assertEquals("tag:tag3", filter2.name()); + assertEquals(1, filter2.values().size()); + assertEquals("value3", filter2.values().get(0)); } } diff --git a/src/test/java/com/meltmedia/jgroups/aws/InstanceIdentityTest.java b/src/test/java/com/meltmedia/jgroups/aws/InstanceIdentityTest.java deleted file mode 100644 index 386776e..0000000 --- a/src/test/java/com/meltmedia/jgroups/aws/InstanceIdentityTest.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.meltmedia.jgroups.aws; - -import com.google.common.io.Resources; -import org.apache.http.HttpEntity; -import org.apache.http.HttpResponse; -import org.apache.http.HttpStatus; -import org.apache.http.StatusLine; -import org.apache.http.client.HttpClient; -import org.junit.Test; - -import java.io.ByteArrayInputStream; - -import static com.google.common.io.Resources.getResource; -import static org.junit.Assert.assertEquals; -import static org.mockito.Matchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class InstanceIdentityTest { - @Test - public void fromResponse() throws Exception { - final HttpClient client = mock(HttpClient.class); - final HttpResponse response = mock(HttpResponse.class); - final StatusLine statusLine = mock(StatusLine.class); - final HttpEntity responseEntity = mock(HttpEntity.class); - - when(responseEntity.getContent()).thenReturn(new ByteArrayInputStream(Resources.toByteArray(getResource("instance-identity.json")))); - when(responseEntity.getContentLength()).thenReturn(-1L); - when(statusLine.getStatusCode()).thenReturn(HttpStatus.SC_OK); - when(response.getStatusLine()).thenReturn(statusLine); - when(response.getEntity()).thenReturn(responseEntity); - when(client.execute(any())).thenReturn(response); - - InstanceIdentity instanceIdentity = InstanceIdentity.getIdentity(client); - - assertEquals("us-west-2b", instanceIdentity.availabilityZone); - assertEquals("10.158.112.84", instanceIdentity.privateIp); - assertEquals("i-1234567890abcdef0", instanceIdentity.instanceId); - assertEquals("t2.micro", instanceIdentity.instanceType); - assertEquals("ami-5fb8c835", instanceIdentity.imageId); - assertEquals("x86_64", instanceIdentity.architecture); - assertEquals("us-west-2", instanceIdentity.region); - } -} \ No newline at end of file diff --git a/src/test/java/com/meltmedia/jgroups/aws/LoadCredentialsProviderTest.java b/src/test/java/com/meltmedia/jgroups/aws/LoadCredentialsProviderTest.java index eeb1519..8496a08 100644 --- a/src/test/java/com/meltmedia/jgroups/aws/LoadCredentialsProviderTest.java +++ b/src/test/java/com/meltmedia/jgroups/aws/LoadCredentialsProviderTest.java @@ -1,16 +1,19 @@ package com.meltmedia.jgroups.aws; -import static org.junit.Assert.*; - +import org.jgroups.logging.Log; import org.junit.Test; import org.mockito.Mockito; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; -import org.jgroups.logging.Log; +import software.amazon.awssdk.auth.credentials.AwsCredentials; +import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; +import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider; +import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity; +import software.amazon.awssdk.identity.spi.ResolveIdentityRequest; -import com.amazonaws.auth.AWSCredentials; -import com.amazonaws.auth.AWSCredentialsProvider; +import java.util.concurrent.CompletableFuture; +import static org.junit.Assert.fail; import static org.mockito.Mockito.*; /** @@ -75,7 +78,7 @@ public void exceptionOnMissingNoArgConstructor() throws Exception { public void noContextClassLoader() throws Exception { Log log = Mockito.mock(Log.class); - doCall(null, com.amazonaws.auth.DefaultAWSCredentialsProviderChain.class.getName(), log); + doCall(null, DefaultCredentialsProvider.class.getName(), log); } public static Answer answerWith(final Object o) { @@ -90,35 +93,35 @@ public Object answer(InvocationOnMock invocation) throws Throwable { /** * A credentials provider with no real implementation. */ - public static class UnsupportedAWSCredentialProvider implements AWSCredentialsProvider { + public static class UnsupportedAWSCredentialProvider implements AwsCredentialsProvider { @Override - public AWSCredentials getCredentials() { + public AwsCredentials resolveCredentials() { throw new UnsupportedOperationException(); } @Override - public void refresh() { - throw new UnsupportedOperationException(); - } + public Class identityType() { + return AwsCredentialsProvider.super.identityType(); + } + + @Override + public CompletableFuture resolveIdentity(ResolveIdentityRequest request) { + return AwsCredentialsProvider.super.resolveIdentity(request); + } + + public static UnsupportedAWSCredentialProvider create() { + return new UnsupportedAWSCredentialProvider(); + } } /** * A credentials provider that does not supply the needed constructor. */ - public static class BadConstructorAWSCredentialsProvider implements AWSCredentialsProvider { - public BadConstructorAWSCredentialsProvider( String tooManyArgs) {} - @Override - public AWSCredentials getCredentials() { - throw new UnsupportedOperationException(); - } + public static class BadConstructorAWSCredentialsProvider extends UnsupportedAWSCredentialProvider { - @Override - public void refresh() { - throw new UnsupportedOperationException(); - } } - public static AWSCredentialsProvider doCall( ClassLoader contextClassLoader, String className, Log log) throws Exception + public static AwsCredentialsProvider doCall( ClassLoader contextClassLoader, String className, Log log) throws Exception { ClassLoader oldCtx = Thread.currentThread().getContextClassLoader(); try { diff --git a/src/test/java/com/meltmedia/jgroups/aws/Mocks.java b/src/test/java/com/meltmedia/jgroups/aws/Mocks.java index cab33e5..7ea251e 100644 --- a/src/test/java/com/meltmedia/jgroups/aws/Mocks.java +++ b/src/test/java/com/meltmedia/jgroups/aws/Mocks.java @@ -1,25 +1,30 @@ package com.meltmedia.jgroups.aws; -import com.amazonaws.services.ec2.AmazonEC2; -import com.amazonaws.services.ec2.model.*; +import software.amazon.awssdk.services.ec2.Ec2Client; +import software.amazon.awssdk.services.ec2.model.Instance; +import software.amazon.awssdk.services.ec2.model.Reservation; +import software.amazon.awssdk.services.ec2.model.Tag; +import software.amazon.awssdk.services.ec2.paginators.DescribeInstancesIterable; import java.util.Arrays; +import java.util.Collections; +import java.util.function.Consumer; -import static org.mockito.Matchers.any; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; public class Mocks { - public static AmazonEC2 ec2Mock(Tag... tags) { - final AmazonEC2 ec2 = mock(AmazonEC2.class); + public static Ec2Client ec2Mock(Tag... tags) { + final Ec2Client ec2 = mock(Ec2Client.class); - final DescribeInstancesResult describeInstancesResult = mock(DescribeInstancesResult.class); final Reservation reservation = mock(Reservation.class); final Instance instance = mock(Instance.class); - when(instance.getTags()).thenReturn(Arrays.asList(tags)); - when(reservation.getInstances()).thenReturn(Arrays.asList(instance)); - when(describeInstancesResult.getReservations()).thenReturn(Arrays.asList(reservation)); - when(ec2.describeInstances(any(DescribeInstancesRequest.class))).thenReturn(describeInstancesResult); + when(instance.tags()).thenReturn(Arrays.asList(tags)); + when(reservation.instances()).thenReturn(Collections.singletonList(instance)); + DescribeInstancesIterable paginator = mock(DescribeInstancesIterable.class); + when(paginator.reservations()).thenReturn(() -> Collections.singletonList(reservation).iterator()); + when(ec2.describeInstancesPaginator(any(Consumer.class))).thenReturn(paginator); return ec2; } diff --git a/src/test/java/com/meltmedia/jgroups/aws/TagUtilsTest.java b/src/test/java/com/meltmedia/jgroups/aws/TagUtilsTest.java index 21bcf59..056a1e2 100644 --- a/src/test/java/com/meltmedia/jgroups/aws/TagUtilsTest.java +++ b/src/test/java/com/meltmedia/jgroups/aws/TagUtilsTest.java @@ -1,7 +1,7 @@ package com.meltmedia.jgroups.aws; -import com.amazonaws.services.ec2.model.Tag; import org.junit.Test; +import software.amazon.awssdk.services.ec2.model.Tag; import java.util.List; @@ -9,33 +9,25 @@ import static org.junit.Assert.*; public class TagUtilsTest { - private static InstanceIdentity instanceIdentity = new InstanceIdentity( - "zone", - "1.2.3.4", - "instance_id", - "instance_type", - "image_id", - "architecture", - "region"); @Test public void canHandleNullTagString() { - final TagsUtils tagsUtils = new TagsUtils(ec2Mock(), instanceIdentity, null); + final TagsUtils tagsUtils = new TagsUtils(ec2Mock(), FilterUtilsTest.instanceInfo, null); assertFalse(tagsUtils.getAwsTagNames().isPresent()); } @Test public void canHandleEmptyTagString() { - final TagsUtils tagsUtils = new TagsUtils(ec2Mock(), instanceIdentity, ""); + final TagsUtils tagsUtils = new TagsUtils(ec2Mock(), FilterUtilsTest.instanceInfo, ""); assertFalse(tagsUtils.getAwsTagNames().isPresent()); } @Test public void willParseConfiguredTags() { - final Tag instanceTag1 = new Tag("tag1", "value1"); - final Tag instanceTag2 = new Tag("tag2", "value2"); + final Tag instanceTag1 = Tag.builder().key("tag1").value("value1").build(); + final Tag instanceTag2 = Tag.builder().key("tag2").value("value2").build(); - final TagsUtils tagsUtils = new TagsUtils(ec2Mock(instanceTag1, instanceTag2), instanceIdentity, "tag1, tag2").validateTags(); + final TagsUtils tagsUtils = new TagsUtils(ec2Mock(instanceTag1, instanceTag2), FilterUtilsTest.instanceInfo, "tag1, tag2").validateTags(); assertTrue(tagsUtils.getAwsTagNames().isPresent()); tagsUtils.getAwsTagNames().ifPresent(tags -> { assertEquals(2, tags.size()); @@ -45,27 +37,27 @@ public void willParseConfiguredTags() { @Test public void canGetInstanceTags() { - final Tag instanceTag1 = new Tag("instanceTag1", "value1"); - final Tag instanceTag2 = new Tag("instanceTag2", "value2"); + final Tag instanceTag1 = Tag.builder().key("instanceTag1").value("value1").build(); + final Tag instanceTag2 = Tag.builder().key("instanceTag2").value("value2").build(); - final TagsUtils tagsUtils = new TagsUtils(ec2Mock(instanceTag1, instanceTag2), instanceIdentity, null).validateTags(); + final TagsUtils tagsUtils = new TagsUtils(ec2Mock(instanceTag1, instanceTag2), FilterUtilsTest.instanceInfo, null).validateTags(); final List tags = tagsUtils.getInstanceTags(); assertEquals(2, tags.size()); Tag tag1 = tags.get(0); Tag tag2 = tags.get(1); - assertEquals("instanceTag1", tag1.getKey()); - assertEquals("value1", tag1.getValue()); - assertEquals("instanceTag2", tag2.getKey()); - assertEquals("value2", tag2.getValue()); + assertEquals("instanceTag1", tag1.key()); + assertEquals("value1", tag1.value()); + assertEquals("instanceTag2", tag2.key()); + assertEquals("value2", tag2.value()); } @Test(expected = IllegalStateException.class) public void missingInstanceTagsShouldThrowException() { - final Tag instanceTag1 = new Tag("tag1", "value1"); - final Tag instanceTag2 = new Tag("tag2", "value2"); + final Tag instanceTag1 = Tag.builder().key("tag1").value("value1").build(); + final Tag instanceTag2 = Tag.builder().key("tag2").value("value2").build(); - new TagsUtils(ec2Mock(instanceTag1, instanceTag2), instanceIdentity, "tag1, tag2, tag3").validateTags(); + new TagsUtils(ec2Mock(instanceTag1, instanceTag2), FilterUtilsTest.instanceInfo, "tag1, tag2, tag3").validateTags(); } }