diff --git a/docs/plugins/discovery-ec2.asciidoc b/docs/plugins/discovery-ec2.asciidoc index 57b5b8468fafb..723bd171b5432 100644 --- a/docs/plugins/discovery-ec2.asciidoc +++ b/docs/plugins/discovery-ec2.asciidoc @@ -52,9 +52,8 @@ Those that must be stored in the keystore are marked as `Secure`. `endpoint`:: - The ec2 service endpoint to connect to. See - http://docs.aws.amazon.com/general/latest/gr/rande.html#ec2_region. This - defaults to `ec2.us-east-1.amazonaws.com`. + The ec2 service endpoint to connect to. See http://docs.aws.amazon.com/general/latest/gr/rande.html#ec2_region. + This defaults to `ec2.us-east-1.amazonaws.com`. `protocol`:: diff --git a/plugins/discovery-ec2/src/main/java/org/elasticsearch/discovery/ec2/AwsEc2ServiceImpl.java b/plugins/discovery-ec2/src/main/java/org/elasticsearch/discovery/ec2/AwsEc2ServiceImpl.java index 5f384c049124e..aa85ee11f2caf 100644 --- a/plugins/discovery-ec2/src/main/java/org/elasticsearch/discovery/ec2/AwsEc2ServiceImpl.java +++ b/plugins/discovery-ec2/src/main/java/org/elasticsearch/discovery/ec2/AwsEc2ServiceImpl.java @@ -23,12 +23,14 @@ import com.amazonaws.auth.AWSCredentials; import com.amazonaws.auth.AWSCredentialsProvider; import com.amazonaws.auth.DefaultAWSCredentialsProviderChain; +import com.amazonaws.client.builder.AwsClientBuilder; import com.amazonaws.http.IdleConnectionReaper; import com.amazonaws.internal.StaticCredentialsProvider; +import com.amazonaws.regions.InstanceMetadataRegionProvider; import com.amazonaws.retry.RetryPolicy; import com.amazonaws.services.ec2.AmazonEC2; -import com.amazonaws.services.ec2.AmazonEC2Client; - +import com.amazonaws.services.ec2.AmazonEC2ClientBuilder; +import com.amazonaws.util.AwsHostNameUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.elasticsearch.ElasticsearchException; @@ -40,7 +42,7 @@ import java.util.concurrent.atomic.AtomicReference; class AwsEc2ServiceImpl implements AwsEc2Service { - + private static final Logger logger = LogManager.getLogger(AwsEc2ServiceImpl.class); private final AtomicReference> lazyClientReference = @@ -49,20 +51,50 @@ class AwsEc2ServiceImpl implements AwsEc2Service { private AmazonEC2 buildClient(Ec2ClientSettings clientSettings) { final AWSCredentialsProvider credentials = buildCredentials(logger, clientSettings); final ClientConfiguration configuration = buildConfiguration(logger, clientSettings); - final AmazonEC2 client = buildClient(credentials, configuration); + + final AwsClientBuilder.EndpointConfiguration endpointConfiguration; if (Strings.hasText(clientSettings.endpoint)) { logger.debug("using explicit ec2 endpoint [{}]", clientSettings.endpoint); - client.setEndpoint(clientSettings.endpoint); + endpointConfiguration = new AwsClientBuilder.EndpointConfiguration(clientSettings.endpoint, + buildRegion(clientSettings.endpoint)); + } else { + logger.debug("No endpoint defined. Using default endpoint [ec2.us-east-1.amazonaws.com]."); + endpointConfiguration = null; } + + final AmazonEC2 client = buildClient(credentials, configuration, endpointConfiguration); return client; } // proxy for testing - AmazonEC2 buildClient(AWSCredentialsProvider credentials, ClientConfiguration configuration) { - final AmazonEC2 client = new AmazonEC2Client(credentials, configuration); + AmazonEC2 buildClient(AWSCredentialsProvider credentials, ClientConfiguration configuration, + AwsClientBuilder.EndpointConfiguration endpointConfiguration) { + + AmazonEC2ClientBuilder builder = AmazonEC2ClientBuilder.standard() + .withCredentials(credentials) + .withClientConfiguration(configuration); + if (endpointConfiguration != null) { + builder.setEndpointConfiguration(endpointConfiguration); + } + final AmazonEC2 client = builder.build(); return client; } + // Package private for tests + static String buildRegion(String endpoint) { + // We try to get the region from the metadata instance information + String region = new InstanceMetadataRegionProvider().getRegion(); + if (region == null) { + // Or we try to get it from the endpoint itself + region = AwsHostNameUtils.parseRegion(endpoint, null); + if (region == null) { + // Endpoint is non-standard + throw new IllegalArgumentException("Can not guess a region from endpoint [" + endpoint + "]."); + } + } + return region; + } + // pkg private for tests static ClientConfiguration buildConfiguration(Logger logger, Ec2ClientSettings clientSettings) { final ClientConfiguration clientConfiguration = new ClientConfiguration(); diff --git a/plugins/discovery-ec2/src/test/java/org/elasticsearch/discovery/ec2/AwsEc2ServiceImplTests.java b/plugins/discovery-ec2/src/test/java/org/elasticsearch/discovery/ec2/AwsEc2ServiceImplTests.java index 148e58d7b3c06..1ecbeb0fa54d5 100644 --- a/plugins/discovery-ec2/src/test/java/org/elasticsearch/discovery/ec2/AwsEc2ServiceImplTests.java +++ b/plugins/discovery-ec2/src/test/java/org/elasticsearch/discovery/ec2/AwsEc2ServiceImplTests.java @@ -132,4 +132,11 @@ protected void launchAWSConfigurationTest(Settings settings, assertThat(configuration.getSocketTimeout(), is(expectedReadTimeout)); } + public void testBuildRegion() { + assertThat(AwsEc2ServiceImpl.buildRegion("ec2.us-east-1.amazonaws.com"), is("us-east-1")); + assertThat(AwsEc2ServiceImpl.buildRegion("ec2.eu-west-3.amazonaws.com"), is("eu-west-3")); + IllegalArgumentException exception = expectThrows(IllegalArgumentException.class, + () -> AwsEc2ServiceImpl.buildRegion("foo.bar.nodomain")); + assertThat(exception.getMessage(), is("Can not guess a region from endpoint [foo.bar.nodomain].")); + } } diff --git a/plugins/discovery-ec2/src/test/java/org/elasticsearch/discovery/ec2/AwsEc2ServiceMock.java b/plugins/discovery-ec2/src/test/java/org/elasticsearch/discovery/ec2/AwsEc2ServiceMock.java index e44087f941349..81b129a5a6373 100644 --- a/plugins/discovery-ec2/src/test/java/org/elasticsearch/discovery/ec2/AwsEc2ServiceMock.java +++ b/plugins/discovery-ec2/src/test/java/org/elasticsearch/discovery/ec2/AwsEc2ServiceMock.java @@ -21,6 +21,7 @@ import com.amazonaws.ClientConfiguration; import com.amazonaws.auth.AWSCredentialsProvider; +import com.amazonaws.client.builder.AwsClientBuilder; import com.amazonaws.services.ec2.AmazonEC2; import com.amazonaws.services.ec2.model.Tag; @@ -37,7 +38,8 @@ public AwsEc2ServiceMock(int nodes, List> tagsList) { } @Override - AmazonEC2 buildClient(AWSCredentialsProvider credentials, ClientConfiguration configuration) { + AmazonEC2 buildClient(AWSCredentialsProvider credentials, ClientConfiguration configuration, + AwsClientBuilder.EndpointConfiguration endpointConfiguration) { return new AmazonEC2Mock(nodes, tagsList, credentials, configuration); }