Skip to content

Commit

Permalink
Add integ test for EC2 special network addresses (elastic#118560) (el…
Browse files Browse the repository at this point in the history
…astic#118616)

Replaces the `Ec2NetworkTests` unit test suite with an integ test suite
to cover the resolution process end-to-end.
  • Loading branch information
DaveCTurner authored Dec 17, 2024
1 parent bc7aae5 commit 788cac4
Show file tree
Hide file tree
Showing 11 changed files with 247 additions and 195 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public class RepositoryS3ImdsV1CredentialsRestIT extends AbstractRepositoryS3Res
public static ElasticsearchCluster cluster = ElasticsearchCluster.local()
.module("repository-s3")
.setting("s3.client." + CLIENT + ".endpoint", s3Fixture::getAddress)
.systemProperty("com.amazonaws.sdk.ec2MetadataServiceEndpointOverride", ec2ImdsHttpFixture::getAddress)
.systemProperty(Ec2ImdsHttpFixture.ENDPOINT_OVERRIDE_SYSPROP_NAME, ec2ImdsHttpFixture::getAddress)
.build();

@ClassRule
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public class RepositoryS3ImdsV2CredentialsRestIT extends AbstractRepositoryS3Res
public static ElasticsearchCluster cluster = ElasticsearchCluster.local()
.module("repository-s3")
.setting("s3.client." + CLIENT + ".endpoint", s3Fixture::getAddress)
.systemProperty("com.amazonaws.sdk.ec2MetadataServiceEndpointOverride", ec2ImdsHttpFixture::getAddress)
.systemProperty(Ec2ImdsHttpFixture.ENDPOINT_OVERRIDE_SYSPROP_NAME, ec2ImdsHttpFixture::getAddress)
.build();

@ClassRule
Expand Down
5 changes: 4 additions & 1 deletion plugins/discovery-ec2/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import org.elasticsearch.gradle.internal.info.BuildParams
* License v3.0 only", or the "Server Side Public License, v 1".
*/
apply plugin: 'elasticsearch.internal-java-rest-test'
apply plugin: 'elasticsearch.internal-cluster-test'

esplugin {
description 'The EC2 discovery plugin allows to use AWS API for the unicast discovery mechanism.'
Expand All @@ -31,6 +32,8 @@ dependencies {

javaRestTestImplementation project(':plugins:discovery-ec2')
javaRestTestImplementation project(':test:fixtures:ec2-imds-fixture')

internalClusterTestImplementation project(':test:fixtures:ec2-imds-fixture')
}

tasks.named("dependencyLicenses").configure {
Expand Down Expand Up @@ -84,7 +87,7 @@ tasks.register("writeTestJavaPolicy") {
}
}

tasks.named("test").configure {
tasks.withType(Test).configureEach {
dependsOn "writeTestJavaPolicy"
// this is needed for insecure plugins, remove if possible!
systemProperty 'tests.artifact', project.name
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
* Public License v 1"; you may not use this file except in compliance with, at
* your election, the "Elastic License 2.0", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/

package org.elasticsearch.discovery.ec2;

import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.CollectionUtils;
import org.elasticsearch.http.HttpServerTransport;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.test.ESIntegTestCase;

import java.io.IOException;
import java.util.Collection;

@ESIntegTestCase.ClusterScope(numDataNodes = 0)
public abstract class DiscoveryEc2NetworkAddressesTestCase extends ESIntegTestCase {

@Override
protected Collection<Class<? extends Plugin>> nodePlugins() {
return CollectionUtils.appendToCopyNoNullElements(super.nodePlugins(), Ec2DiscoveryPlugin.class);
}

@Override
protected boolean addMockHttpTransport() {
return false;
}

void verifyPublishAddress(String publishAddressSetting, String expectedAddress) throws IOException {
final var node = internalCluster().startNode(Settings.builder().put("http.publish_host", publishAddressSetting));
assertEquals(
expectedAddress,
internalCluster().getInstance(HttpServerTransport.class, node).boundAddress().publishAddress().getAddress()
);
internalCluster().stopNode(node);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
* Public License v 1"; you may not use this file except in compliance with, at
* your election, the "Elastic License 2.0", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/

package org.elasticsearch.discovery.ec2;

import fixture.aws.imds.Ec2ImdsHttpFixture;
import fixture.aws.imds.Ec2ImdsServiceBuilder;
import fixture.aws.imds.Ec2ImdsVersion;

import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.transport.BindTransportException;

import java.io.IOException;
import java.util.concurrent.ExecutionException;

import static org.hamcrest.Matchers.containsString;

public class DiscoveryEc2RegularNetworkAddressesIT extends DiscoveryEc2NetworkAddressesTestCase {
public void testLocalIgnoresImds() {
Ec2ImdsHttpFixture.runWithFixture(new Ec2ImdsServiceBuilder(randomFrom(Ec2ImdsVersion.values())), imdsFixture -> {
try (var ignored = Ec2ImdsHttpFixture.withEc2MetadataServiceEndpointOverride(imdsFixture.getAddress())) {
verifyPublishAddress("_local_", "127.0.0.1");
}
});
}

public void testImdsNotAvailable() throws IOException {
try (var ignored = Ec2ImdsHttpFixture.withEc2MetadataServiceEndpointOverride("http://127.0.0.1")) {
// if IMDS is not running, regular values like `_local_` should still work
verifyPublishAddress("_local_", "127.0.0.1");

// but EC2 addresses will cause the node to fail to start
final var assertionError = expectThrows(
AssertionError.class,
() -> internalCluster().startNode(Settings.builder().put("http.publish_host", "_ec2_"))
);
final var executionException = asInstanceOf(ExecutionException.class, assertionError.getCause());
final var bindTransportException = asInstanceOf(BindTransportException.class, executionException.getCause());
assertEquals("Failed to resolve publish address", bindTransportException.getMessage());
final var ioException = asInstanceOf(IOException.class, bindTransportException.getCause());
assertThat(ioException.getMessage(), containsString("/latest/meta-data/local-ipv4"));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
* Public License v 1"; you may not use this file except in compliance with, at
* your election, the "Elastic License 2.0", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/

package org.elasticsearch.discovery.ec2;

import fixture.aws.imds.Ec2ImdsHttpFixture;
import fixture.aws.imds.Ec2ImdsServiceBuilder;
import fixture.aws.imds.Ec2ImdsVersion;

import com.carrotsearch.randomizedtesting.annotations.Name;
import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;

import java.util.Map;
import java.util.stream.Stream;

public class DiscoveryEc2SpecialNetworkAddressesIT extends DiscoveryEc2NetworkAddressesTestCase {

private final String imdsAddressName;
private final String elasticsearchAddressName;
private final Ec2ImdsVersion imdsVersion;

public DiscoveryEc2SpecialNetworkAddressesIT(
@Name("imdsAddressName") String imdsAddressName,
@Name("elasticsearchAddressName") String elasticsearchAddressName,
@Name("imdsVersion") Ec2ImdsVersion imdsVersion
) {
this.imdsAddressName = imdsAddressName;
this.elasticsearchAddressName = elasticsearchAddressName;
this.imdsVersion = imdsVersion;
}

@ParametersFactory
public static Iterable<Object[]> parameters() {
return Map.of(
"_ec2:privateIpv4_",
"local-ipv4",
"_ec2:privateDns_",
"local-hostname",
"_ec2:publicIpv4_",
"public-ipv4",
"_ec2:publicDns_",
"public-hostname",
"_ec2:publicIp_",
"public-ipv4",
"_ec2:privateIp_",
"local-ipv4",
"_ec2_",
"local-ipv4"
)
.entrySet()
.stream()
.flatMap(
addresses -> Stream.of(Ec2ImdsVersion.values())
.map(ec2ImdsVersion -> new Object[] { addresses.getValue(), addresses.getKey(), ec2ImdsVersion })
)
.toList();
}

public void testSpecialNetworkAddresses() {
final var publishAddress = "10.0." + between(0, 255) + "." + between(0, 255);
Ec2ImdsHttpFixture.runWithFixture(
new Ec2ImdsServiceBuilder(imdsVersion).addInstanceAddress(imdsAddressName, publishAddress),
imdsFixture -> {
try (var ignored = Ec2ImdsHttpFixture.withEc2MetadataServiceEndpointOverride(imdsFixture.getAddress())) {
verifyPublishAddress(elasticsearchAddressName, publishAddress);
}
}
);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

package org.elasticsearch.discovery.ec2;

import fixture.aws.imds.Ec2ImdsHttpFixture;

import org.elasticsearch.client.Request;
import org.elasticsearch.common.util.concurrent.ConcurrentCollections;
import org.elasticsearch.test.cluster.ElasticsearchCluster;
Expand All @@ -34,7 +36,7 @@ protected static ElasticsearchCluster buildCluster(Supplier<String> imdsFixtureA
return ElasticsearchCluster.local()
.plugin("discovery-ec2")
.setting(AwsEc2Service.AUTO_ATTRIBUTE_SETTING.getKey(), "true")
.systemProperty("com.amazonaws.sdk.ec2MetadataServiceEndpointOverride", imdsFixtureAddressSupplier)
.systemProperty(Ec2ImdsHttpFixture.ENDPOINT_OVERRIDE_SYSPROP_NAME, imdsFixtureAddressSupplier)
.build();
}

Expand Down
Loading

0 comments on commit 788cac4

Please sign in to comment.