diff --git a/plugins/discovery-ec2/qa/amazon-ec2/build.gradle b/plugins/discovery-ec2/qa/amazon-ec2/build.gradle
index 2e1328d172194..90fac9e80cd78 100644
--- a/plugins/discovery-ec2/qa/amazon-ec2/build.gradle
+++ b/plugins/discovery-ec2/qa/amazon-ec2/build.gradle
@@ -28,12 +28,6 @@ dependencies {
testCompile project(path: ':plugins:discovery-ec2', configuration: 'runtime')
}
-forbiddenApisTest {
- // we are using jdk-internal instead of jdk-non-portable to allow for com.sun.net.httpserver.* usage
- bundledSignatures -= 'jdk-non-portable'
- bundledSignatures += 'jdk-internal'
-}
-
final int ec2NumberOfNodes = 3
File ec2DiscoveryFile = new File(project.buildDir, 'generated-resources/nodes.uri')
@@ -69,7 +63,7 @@ integTestCluster {
ec2DiscoveryFile.setText(integTest.nodes.collect { n -> "${n.transportUri()}" }.join('\n'), 'UTF-8')
File tmpFile = new File(node.cwd, 'wait.success')
- ant.get(src: "http://${node.httpUri()}/_cluster/health?wait_for_nodes=>=${ec2NumberOfNodes}&wait_for_status=yellow",
+ ant.get(src: "http://${node.httpUri()}/",
dest: tmpFile.toString(),
ignoreerrors: true,
retries: 10)
diff --git a/plugins/discovery-ec2/qa/amazon-ec2/src/test/java/org/elasticsearch/discovery/ec2/AmazonEC2Fixture.java b/plugins/discovery-ec2/qa/amazon-ec2/src/test/java/org/elasticsearch/discovery/ec2/AmazonEC2Fixture.java
index 7382d45e84fe1..0cf4cbdeadb34 100644
--- a/plugins/discovery-ec2/qa/amazon-ec2/src/test/java/org/elasticsearch/discovery/ec2/AmazonEC2Fixture.java
+++ b/plugins/discovery-ec2/qa/amazon-ec2/src/test/java/org/elasticsearch/discovery/ec2/AmazonEC2Fixture.java
@@ -18,264 +18,177 @@
*/
package org.elasticsearch.discovery.ec2;
-import com.amazonaws.util.IOUtils;
-import com.sun.net.httpserver.Headers;
-import com.sun.net.httpserver.HttpExchange;
-import com.sun.net.httpserver.HttpHandler;
-import com.sun.net.httpserver.HttpServer;
import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URLEncodedUtils;
import org.elasticsearch.common.SuppressForbidden;
-import org.elasticsearch.mocksocket.MockHttpServer;
import org.elasticsearch.rest.RestStatus;
+import org.elasticsearch.test.fixture.AbstractHttpFixture;
import javax.xml.XMLConstants;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamWriter;
import java.io.IOException;
import java.io.StringWriter;
-import java.lang.management.ManagementFactory;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.SocketAddress;
-import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
-import java.nio.file.StandardCopyOption;
-import java.util.List;
+import java.util.Objects;
import java.util.UUID;
-import java.util.function.Predicate;
-import static java.util.Collections.singleton;
-import static java.util.Collections.singletonList;
+import static java.nio.charset.StandardCharsets.UTF_8;
/**
* {@link AmazonEC2Fixture} is a fixture that emulates an AWS EC2 service.
- *
- * It starts an asynchronous socket server that binds to a random local port.
*/
-public class AmazonEC2Fixture {
+public class AmazonEC2Fixture extends AbstractHttpFixture {
+
+ private final Path nodes;
+
+ private AmazonEC2Fixture(final String workingDir, final String nodesUriPath) {
+ super(workingDir);
+ this.nodes = toPath(Objects.requireNonNull(nodesUriPath));
+ }
public static void main(String[] args) throws Exception {
if (args == null || args.length != 2) {
throw new IllegalArgumentException("AmazonEC2Fixture ");
}
- final InetSocketAddress socketAddress = new InetSocketAddress(InetAddress.getLoopbackAddress(), 0);
- final HttpServer httpServer = MockHttpServer.createHttp(socketAddress, 0);
-
- try {
- final Path workingDirectory = toPath(args[0]);
- /// Writes the PID of the current Java process in a `pid` file located in the working directory
- writeFile(workingDirectory, "pid", ManagementFactory.getRuntimeMXBean().getName().split("@")[0]);
-
- final String addressAndPort = addressToString(httpServer.getAddress());
- // Writes the address and port of the http server in a `ports` file located in the working directory
- writeFile(workingDirectory, "ports", addressAndPort);
-
- httpServer.createContext("/", new ResponseHandler(toPath(args[1])));
- httpServer.start();
-
- // Wait to be killed
- Thread.sleep(Long.MAX_VALUE);
-
- } finally {
- httpServer.stop(0);
- }
- }
-
- @SuppressForbidden(reason = "Paths#get is fine - we don't have environment here")
- private static Path toPath(final String dir) {
- return Paths.get(dir);
- }
-
- private static void writeFile(final Path dir, final String fileName, final String content) throws IOException {
- final Path tempPidFile = Files.createTempFile(dir, null, null);
- Files.write(tempPidFile, singleton(content));
- Files.move(tempPidFile, dir.resolve(fileName), StandardCopyOption.ATOMIC_MOVE);
- }
-
- private static String addressToString(final SocketAddress address) {
- final InetSocketAddress inetSocketAddress = (InetSocketAddress) address;
- if (inetSocketAddress.getAddress() instanceof Inet6Address) {
- return "[" + inetSocketAddress.getHostString() + "]:" + inetSocketAddress.getPort();
- } else {
- return inetSocketAddress.getHostString() + ":" + inetSocketAddress.getPort();
- }
+ final AmazonEC2Fixture fixture = new AmazonEC2Fixture(args[0], args[1]);
+ fixture.listen();
}
- static class ResponseHandler implements HttpHandler {
-
- private final Path discoveryPath;
-
- ResponseHandler(final Path discoveryPath) {
- this.discoveryPath = discoveryPath;
- }
-
- @Override
- public void handle(HttpExchange exchange) throws IOException {
- RestStatus responseStatus = RestStatus.INTERNAL_SERVER_ERROR;
- String responseBody = null;
- String responseContentType = "text/plain";
-
- final String path = exchange.getRequestURI().getRawPath();
- if ("/".equals(path)) {
- final String method = exchange.getRequestMethod();
- final Headers headers = exchange.getRequestHeaders();
-
- if ("GET".equals(method) && matchingHeader(headers, "User-agent", v -> v.startsWith("Apache Ant"))) {
- // Replies to the fixture's waiting condition
- responseStatus = RestStatus.OK;
- responseBody = "AmazonEC2Fixture";
-
- } else if ("POST".equals(method) && matchingHeader(headers, "User-agent", v -> v.startsWith("aws-sdk-java"))) {
- // Simulate an EC2 DescribeInstancesResponse
- responseStatus = RestStatus.OK;
- responseContentType = "text/xml; charset=UTF-8";
-
- for (NameValuePair parse : URLEncodedUtils.parse(IOUtils.toString(exchange.getRequestBody()), StandardCharsets.UTF_8)) {
- if ("Action".equals(parse.getName())) {
- responseBody = generateDescribeInstancesResponse();
- break;
- }
- }
- }
- }
-
- final byte[] response = responseBody != null ? responseBody.getBytes(StandardCharsets.UTF_8) : new byte[0];
- exchange.sendResponseHeaders(responseStatus.getStatus(), response.length);
- exchange.getResponseHeaders().put("Content-Type", singletonList(responseContentType));
- if (response.length > 0) {
- exchange.getResponseBody().write(response);
- }
- exchange.close();
- }
-
- /** Checks if the given {@link Headers} contains a header with a given name which has a value that matches a predicate **/
- private boolean matchingHeader(final Headers headers, final String headerName, final Predicate predicate) {
- if (headers != null && headers.isEmpty() == false) {
- final List values = headers.get(headerName);
- if (values != null) {
- for (String value : values) {
- if (predicate.test(value)) {
- return true;
- }
+ @Override
+ protected Response handle(final Request request) throws IOException {
+ if ("/".equals(request.getPath()) && ("POST".equals(request.getMethod()))) {
+ final String userAgent = request.getHeader("User-Agent");
+ if (userAgent != null && userAgent.startsWith("aws-sdk-java")) {
+ // Simulate an EC2 DescribeInstancesResponse
+ byte[] responseBody = EMPTY_BYTE;
+ for (NameValuePair parse : URLEncodedUtils.parse(new String(request.getBody(), UTF_8), UTF_8)) {
+ if ("Action".equals(parse.getName())) {
+ responseBody = generateDescribeInstancesResponse();
+ break;
}
}
+ return new Response(RestStatus.OK.getStatus(), contentType("text/xml; charset=UTF-8"), responseBody);
}
- return false;
}
+ return null;
+ }
- /**
- * Generates a XML response that describe the EC2 instances
- */
- private String generateDescribeInstancesResponse() {
- final XMLOutputFactory xmlOutputFactory = XMLOutputFactory.newFactory();
- xmlOutputFactory.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, true);
-
- final StringWriter out = new StringWriter();
- XMLStreamWriter sw;
- try {
- sw = xmlOutputFactory.createXMLStreamWriter(out);
- sw.writeStartDocument();
+ /**
+ * Generates a XML response that describe the EC2 instances
+ */
+ private byte[] generateDescribeInstancesResponse() {
+ final XMLOutputFactory xmlOutputFactory = XMLOutputFactory.newFactory();
+ xmlOutputFactory.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, true);
- String namespace = "http://ec2.amazonaws.com/doc/2013-02-01/";
- sw.setDefaultNamespace(namespace);
- sw.writeStartElement(XMLConstants.DEFAULT_NS_PREFIX, "DescribeInstancesResponse", namespace);
+ final StringWriter out = new StringWriter();
+ XMLStreamWriter sw;
+ try {
+ sw = xmlOutputFactory.createXMLStreamWriter(out);
+ sw.writeStartDocument();
+
+ String namespace = "http://ec2.amazonaws.com/doc/2013-02-01/";
+ sw.setDefaultNamespace(namespace);
+ sw.writeStartElement(XMLConstants.DEFAULT_NS_PREFIX, "DescribeInstancesResponse", namespace);
+ {
+ sw.writeStartElement("requestId");
+ sw.writeCharacters(UUID.randomUUID().toString());
+ sw.writeEndElement();
+
+ sw.writeStartElement("reservationSet");
{
- sw.writeStartElement("requestId");
- sw.writeCharacters(UUID.randomUUID().toString());
- sw.writeEndElement();
+ if (Files.exists(nodes)) {
+ for (String address : Files.readAllLines(nodes)) {
- sw.writeStartElement("reservationSet");
- {
- if (Files.exists(discoveryPath)) {
- for (String address : Files.readAllLines(discoveryPath)) {
+ sw.writeStartElement("item");
+ {
+ sw.writeStartElement("reservationId");
+ sw.writeCharacters(UUID.randomUUID().toString());
+ sw.writeEndElement();
- sw.writeStartElement("item");
+ sw.writeStartElement("instancesSet");
{
- sw.writeStartElement("reservationId");
- sw.writeCharacters(UUID.randomUUID().toString());
- sw.writeEndElement();
-
- sw.writeStartElement("instancesSet");
+ sw.writeStartElement("item");
{
- sw.writeStartElement("item");
- {
- sw.writeStartElement("instanceId");
- sw.writeCharacters(UUID.randomUUID().toString());
- sw.writeEndElement();
-
- sw.writeStartElement("imageId");
- sw.writeCharacters(UUID.randomUUID().toString());
- sw.writeEndElement();
-
- sw.writeStartElement("instanceState");
- {
- sw.writeStartElement("code");
- sw.writeCharacters("16");
- sw.writeEndElement();
+ sw.writeStartElement("instanceId");
+ sw.writeCharacters(UUID.randomUUID().toString());
+ sw.writeEndElement();
- sw.writeStartElement("name");
- sw.writeCharacters("running");
- sw.writeEndElement();
- }
- sw.writeEndElement();
+ sw.writeStartElement("imageId");
+ sw.writeCharacters(UUID.randomUUID().toString());
+ sw.writeEndElement();
- sw.writeStartElement("privateDnsName");
- sw.writeCharacters(address);
+ sw.writeStartElement("instanceState");
+ {
+ sw.writeStartElement("code");
+ sw.writeCharacters("16");
sw.writeEndElement();
- sw.writeStartElement("dnsName");
- sw.writeCharacters(address);
+ sw.writeStartElement("name");
+ sw.writeCharacters("running");
sw.writeEndElement();
+ }
+ sw.writeEndElement();
- sw.writeStartElement("instanceType");
- sw.writeCharacters("m1.medium");
- sw.writeEndElement();
+ sw.writeStartElement("privateDnsName");
+ sw.writeCharacters(address);
+ sw.writeEndElement();
- sw.writeStartElement("placement");
- {
- sw.writeStartElement("availabilityZone");
- sw.writeCharacters("use-east-1e");
- sw.writeEndElement();
+ sw.writeStartElement("dnsName");
+ sw.writeCharacters(address);
+ sw.writeEndElement();
- sw.writeEmptyElement("groupName");
+ sw.writeStartElement("instanceType");
+ sw.writeCharacters("m1.medium");
+ sw.writeEndElement();
- sw.writeStartElement("tenancy");
- sw.writeCharacters("default");
- sw.writeEndElement();
- }
+ sw.writeStartElement("placement");
+ {
+ sw.writeStartElement("availabilityZone");
+ sw.writeCharacters("use-east-1e");
sw.writeEndElement();
- sw.writeStartElement("privateIpAddress");
- sw.writeCharacters(address);
- sw.writeEndElement();
+ sw.writeEmptyElement("groupName");
- sw.writeStartElement("ipAddress");
- sw.writeCharacters(address);
+ sw.writeStartElement("tenancy");
+ sw.writeCharacters("default");
sw.writeEndElement();
}
sw.writeEndElement();
+
+ sw.writeStartElement("privateIpAddress");
+ sw.writeCharacters(address);
+ sw.writeEndElement();
+
+ sw.writeStartElement("ipAddress");
+ sw.writeCharacters(address);
+ sw.writeEndElement();
}
sw.writeEndElement();
}
sw.writeEndElement();
}
+ sw.writeEndElement();
}
- sw.writeEndElement();
}
sw.writeEndElement();
-
- sw.writeEndDocument();
- sw.flush();
}
- } catch (Exception e) {
- throw new RuntimeException(e);
+ sw.writeEndElement();
+
+ sw.writeEndDocument();
+ sw.flush();
}
- return out.toString();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
}
+ return out.toString().getBytes(UTF_8);
+ }
+
+ @SuppressForbidden(reason = "Paths#get is fine - we don't have environment here")
+ private static Path toPath(final String dir) {
+ return Paths.get(dir);
}
}
diff --git a/plugins/discovery-ec2/qa/amazon-ec2/src/test/resources/rest-api-spec/test/discovery_ec2/10_basic.yml b/plugins/discovery-ec2/qa/amazon-ec2/src/test/resources/rest-api-spec/test/discovery_ec2/10_basic.yml
index f9d42eee088a3..682327b72dd9e 100644
--- a/plugins/discovery-ec2/qa/amazon-ec2/src/test/resources/rest-api-spec/test/discovery_ec2/10_basic.yml
+++ b/plugins/discovery-ec2/qa/amazon-ec2/src/test/resources/rest-api-spec/test/discovery_ec2/10_basic.yml
@@ -1,4 +1,10 @@
# Integration tests for discovery-ec2
+setup:
+ - do:
+ cluster.health:
+ wait_for_status: green
+ wait_for_nodes: ${expected_nodes}
+
---
"All nodes are correctly discovered":