diff options
author | Harald Musum <musum@verizonmedia.com> | 2020-11-19 13:08:04 +0100 |
---|---|---|
committer | Harald Musum <musum@verizonmedia.com> | 2020-11-19 13:08:04 +0100 |
commit | 8cf510b52c3ad9da66dac723d0e9c4097755ac7a (patch) | |
tree | 78c2ae881605d29df14d37bdb5770689e9bb1942 /clustercontroller-core | |
parent | 5fd44d7a3e068bdb230b055511ecc66dcc1999e6 (diff) |
Remove code in StatusPageServer, keep some inner classes temporarily
Diffstat (limited to 'clustercontroller-core')
4 files changed, 14 insertions, 655 deletions
diff --git a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/status/statuspage/StatusPageServer.java b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/status/statuspage/StatusPageServer.java index 3d3de32c356..5920a7d651a 100644 --- a/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/status/statuspage/StatusPageServer.java +++ b/clustercontroller-core/src/main/java/com/yahoo/vespa/clustercontroller/core/status/statuspage/StatusPageServer.java @@ -1,25 +1,10 @@ // Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.clustercontroller.core.status.statuspage; -import com.yahoo.exception.ExceptionUtils; -import java.util.logging.Level; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.net.InetSocketAddress; -import java.net.ServerSocket; -import java.net.Socket; -import java.net.SocketTimeoutException; -import java.text.DateFormat; -import java.text.SimpleDateFormat; import java.util.ArrayList; -import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.TimeZone; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -27,238 +12,10 @@ import java.util.regex.Pattern; /** * Shows status pages with debug information through a very simple HTTP interface. */ -public class StatusPageServer implements Runnable, StatusPageServerInterface { +public class StatusPageServer { public static Logger log = Logger.getLogger(StatusPageServer.class.getName()); - private final com.yahoo.vespa.clustercontroller.core.Timer timer; - private final Object monitor; - private ServerSocket ssocket; - private final Thread runner; - private int port = 0; - private boolean running = true; - private boolean shouldBeConnected = false; - private HttpRequest currentHttpRequest = null; - private StatusPageResponse currentResponse = null; - private long lastConnectErrorTime = 0; - private String lastConnectError = ""; - private PatternRequestRouter staticContentRouter = new PatternRequestRouter(); - private Date startTime = new Date(); - - public StatusPageServer(com.yahoo.vespa.clustercontroller.core.Timer timer, Object monitor, int port) throws java.io.IOException, InterruptedException { - this.timer = timer; - this.monitor = monitor; - this.port = port; - connect(); - runner = new Thread(this); - runner.start(); - } - - public boolean isConnected() { - if (ssocket != null && ssocket.isBound() && (ssocket.getLocalPort() == port || port == 0)) { - return true; - } else { - log.log(Level.FINEST, "Status page server socket is no longer connected: "+ (ssocket != null) + " " + ssocket.isBound() + " " + ssocket.getLocalPort() + " " + port); - return false; - } - } - - public void connect() throws java.io.IOException, InterruptedException { - synchronized(monitor) { - if (ssocket != null) { - if (ssocket.isBound() && ssocket.getLocalPort() == port) { - return; - } - disconnect(); - } - ssocket = new ServerSocket(); - if (port != 0) { - ssocket.setReuseAddress(true); - } - ssocket.setSoTimeout(100); - ssocket.bind(new InetSocketAddress(port)); - shouldBeConnected = true; - for (int i=0; i<200; ++i) { - if (isConnected()) break; - Thread.sleep(10); - } - if (!isConnected()) { - log.log(Level.INFO, "Fleetcontroller: Server Socket not ready after connect()"); - } - log.log(Level.FINE, "Fleet controller status page viewer listening to " + ssocket.getLocalSocketAddress()); - monitor.notifyAll(); - } - } - - public void disconnect() throws java.io.IOException { - synchronized(monitor) { - shouldBeConnected = false; - if (ssocket != null) ssocket.close(); - ssocket = null; - monitor.notifyAll(); - } - } - - public void setPort(int port) throws java.io.IOException, InterruptedException { - // Only bother to reconnect if we were connected to begin with, we care about what port it runs on, and it's not already running there - if (port != 0 && isConnected() && port != ((InetSocketAddress) ssocket.getLocalSocketAddress()).getPort()) { - log.log(Level.INFO, "Exchanging port used by status server. Moving from port " - + ((InetSocketAddress) ssocket.getLocalSocketAddress()).getPort() + " to port " + port); - disconnect(); - this.port = port; - if (ssocket == null || !ssocket.isBound() || ssocket.getLocalPort() != port) { - connect(); - } - } else { - this.port = port; - } - } - - public int getPort() { - // Cannot use this.port, because of tests using port 0 to get any address - if (ssocket == null || !ssocket.isBound()) { - throw new IllegalStateException("Cannot ask for port before server socket is bound"); - } - return ((InetSocketAddress) ssocket.getLocalSocketAddress()).getPort(); - } - - public void shutdown() throws InterruptedException, java.io.IOException { - running = false; - runner.interrupt(); - runner.join(); - disconnect(); - } - - public void run() { - try{ - while (running) { - Socket connection = null; - ServerSocket serverSocket = null; - synchronized(monitor) { - if (ssocket == null || !ssocket.isBound()) { - monitor.wait(1000); - continue; - } - serverSocket = ssocket; - } - try{ - connection = serverSocket.accept(); - } catch (SocketTimeoutException e) { - // Ignore, since timeout is set to 100 ms - } catch (java.io.IOException e) { - log.log(shouldBeConnected ? Level.WARNING : Level.FINE, "Caught IO exception in ServerSocket.accept(): " + e.getMessage()); - } - if (connection == null) continue; - log.log(Level.FINE, "Got a status page request."); - String requestString = ""; - OutputStream output = null; - try (BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()))) { - StringBuilder sb = new StringBuilder(); - while (true) { - String s = br.readLine(); - if (s == null) throw new java.io.IOException("No data in HTTP request on socket " + connection.toString()); - if (s.length() > 4 && s.substring(0,4).equals("GET ")) { - int nextSpace = s.indexOf(' ', 4); - if (nextSpace == -1) { - requestString = s.substring(4); - } else { - requestString = s.substring(4, nextSpace); - } - } - if (s == null || s.equals("")) break; - sb.append(s).append("\n"); - } - log.log(Level.FINE, "Got HTTP request: " + sb.toString()); - - HttpRequest httpRequest = null; - StatusPageResponse response = null; - try { - httpRequest = new HttpRequest(requestString); - // Static files are served directly by the HTTP server thread, since - // it makes no sense to go via the fleetcontroller logic for these. - RequestHandler contentHandler = staticContentRouter.resolveHandler(httpRequest); - if (contentHandler != null) { - response = contentHandler.handle(httpRequest); - } - } catch (Exception e) { - response = new StatusPageResponse(); - response.setResponseCode(StatusPageResponse.ResponseCode.INTERNAL_SERVER_ERROR); - StringBuilder content = new StringBuilder(); - response.writeHtmlHeader(content, "Internal Server Error"); - response.writeHtmlFooter(content, ExceptionUtils.getStackTraceAsString(e)); - response.writeContent(content.toString()); - } - if (response == null) { - synchronized(monitor) { - currentHttpRequest = httpRequest; - currentResponse = null; - while (running) { - if (currentResponse != null) { - response = currentResponse; - break; - } - monitor.wait(100); - } - } - } - if (response == null) { - response = new StatusPageResponse(); - StringBuilder content = new StringBuilder(); - response.setContentType("text/html"); - response.writeHtmlHeader(content, "Failed to get response. Fleet controller probably in the process of shutting down."); - response.writeHtmlFooter(content, ""); - response.writeContent(content.toString()); - } - - output = connection.getOutputStream(); - StringBuilder header = new StringBuilder(); - // TODO: per-response cache control - header.append("HTTP/1.1 ") - .append(response.getResponseCode().getCode()) - .append(" ") - .append(response.getResponseCode().getMessage()) - .append("\r\n") - .append("Date: ").append(new Date().toString()).append("\r\n") - .append("Connection: Close\r\n") - .append("Content-type: ").append(response.getContentType()).append("\r\n"); - if (response.isClientCachingEnabled()) { - // TODO(vekterli): would be better to let HTTP handlers set header values in response - DateFormat df = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss z"); - df.setTimeZone(TimeZone.getTimeZone("GMT")); - header.append("Last-Modified: ").append(df.format(startTime)).append("\r\n"); - } else { - header.append("Expires: Fri, 01 Jan 1990 00:00:00 GMT\r\n") - .append("Pragma: no-cache\r\n") - .append("Cache-control: no-cache, must-revalidate\r\n"); - } - header.append("\r\n"); - output.write(header.toString().getBytes()); - output.write(response.getOutputStream().toByteArray()); - } catch (java.io.IOException e) { - log.log(e.getMessage().indexOf("Broken pipe") >= 0 ? Level.FINE : Level.INFO, - "Failed to process HTTP request : " + e.getMessage()); - } catch (Exception e) { - log.log(Level.WARNING, "Caught exception in HTTP server thread: " - + e.getClass().getName() + ": " + e.getMessage()); - } finally { - if (output != null) try { - output.close(); - } catch (IOException e) { - log.log(e.getMessage().indexOf("Broken pipe") >= 0 ? Level.FINE : Level.INFO, - "Failed to close output stream on socket " + connection + ": " + e.getMessage()); - } - if (connection != null) try{ - connection.close(); - } catch (IOException e) { - log.log(Level.INFO, "Failed to close socket " + connection + ": " + e.getMessage()); - } - } - } - } catch (InterruptedException e) { - log.log(Level.FINE, "Status processing thread shut down by interrupt exception: " + e); - } - } - /** * Very simple HTTP request class. This should be replaced the second * the fleetcontroller e.g. moves into the container. @@ -377,29 +134,4 @@ public class StatusPageServer implements Runnable, StatusPageServerInterface { } } - public HttpRequest getCurrentHttpRequest() { - synchronized (monitor) { - return currentHttpRequest; - } - } - - public void answerCurrentStatusRequest(StatusPageResponse r) { - if (!isConnected()) { - long time = timer.getCurrentTimeInMillis(); - try{ - connect(); - } catch (Exception e) { - if (!e.getMessage().equals(lastConnectError) || time - lastConnectErrorTime > 60 * 1000) { - lastConnectError = e.getMessage(); - lastConnectErrorTime = time; - log.log(Level.WARNING, "Failed to initialize HTTP status server server socket: " + e.getMessage()); - } - } - } - synchronized (monitor) { - currentResponse = r; - currentHttpRequest = null; // Avoid fleetcontroller processing request more than once - } - } - } diff --git a/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/FleetControllerTest.java b/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/FleetControllerTest.java index 1587e2696b8..f8bf387ce41 100644 --- a/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/FleetControllerTest.java +++ b/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/FleetControllerTest.java @@ -9,7 +9,6 @@ import com.yahoo.jrt.Target; import com.yahoo.jrt.Transport; import com.yahoo.jrt.slobrok.api.BackOffPolicy; import com.yahoo.jrt.slobrok.server.Slobrok; -import java.util.logging.Level; import com.yahoo.log.LogSetup; import com.yahoo.vdslib.distribution.ConfiguredNode; import com.yahoo.vdslib.state.ClusterState; @@ -22,7 +21,7 @@ import com.yahoo.vespa.clustercontroller.core.database.ZooKeeperDatabaseFactory; import com.yahoo.vespa.clustercontroller.core.rpc.RPCCommunicator; import com.yahoo.vespa.clustercontroller.core.rpc.RpcServer; import com.yahoo.vespa.clustercontroller.core.rpc.SlobrokClient; -import com.yahoo.vespa.clustercontroller.core.status.statuspage.StatusPageServer; +import com.yahoo.vespa.clustercontroller.core.status.StatusHandler; import com.yahoo.vespa.clustercontroller.core.status.statuspage.StatusPageServerInterface; import com.yahoo.vespa.clustercontroller.core.testutils.WaitCondition; import com.yahoo.vespa.clustercontroller.core.testutils.WaitTask; @@ -40,9 +39,11 @@ import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; +import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -149,6 +150,7 @@ public abstract class FleetControllerTest implements Waiter { } FleetController createFleetController(boolean useFakeTimer, FleetControllerOptions options, boolean startThread, StatusPageServerInterface status) throws Exception { + Objects.requireNonNull(status, "status server cannot be null"); Timer timer = useFakeTimer ? this.timer : new RealTimer(); MetricUpdater metricUpdater = new MetricUpdater(new NoMetricReporter(), options.fleetControllerIndex); EventLog log = new EventLog(timer, metricUpdater); @@ -169,9 +171,6 @@ public abstract class FleetControllerTest implements Waiter { options.nodeStateRequestRoundTripTimeMaxSeconds); SlobrokClient lookUp = new SlobrokClient(timer); lookUp.setSlobrokConnectionSpecs(new String[0]); - if (status == null) { - status = new StatusPageServer(timer, timer, options.httpPort); - } RpcServer rpcServer = new RpcServer(timer, timer, options.clusterName, options.fleetControllerIndex, options.slobrokBackOffPolicy); DatabaseHandler database = new DatabaseHandler(new ZooKeeperDatabaseFactory(), timer, options.zooKeeperServerAddress, options.fleetControllerIndex, timer); StateChangeHandler stateGenerator = new StateChangeHandler(timer, log, metricUpdater); @@ -189,7 +188,7 @@ public abstract class FleetControllerTest implements Waiter { } protected void setUpFleetController(boolean useFakeTimer, FleetControllerOptions options, boolean startThread) throws Exception { - setUpFleetController(useFakeTimer, options, startThread, null); + setUpFleetController(useFakeTimer, options, startThread, new StatusHandler.ContainerStatusPageServer()); } protected void setUpFleetController(boolean useFakeTimer, FleetControllerOptions options, boolean startThread, StatusPageServerInterface status) throws Exception { if (slobrok == null) setUpSystem(useFakeTimer, options); @@ -209,7 +208,7 @@ public abstract class FleetControllerTest implements Waiter { void startFleetController() throws Exception { if (fleetController == null) { - fleetController = createFleetController(usingFakeTimer, options, true, null); + fleetController = createFleetController(usingFakeTimer, options, true, new StatusHandler.ContainerStatusPageServer()); } else { log.log(Level.WARNING, "already started fleetcontroller, not starting another"); } diff --git a/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/MasterElectionTest.java b/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/MasterElectionTest.java index d14f6701288..896f73ce6bf 100644 --- a/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/MasterElectionTest.java +++ b/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/MasterElectionTest.java @@ -12,6 +12,7 @@ import com.yahoo.vdslib.state.ClusterState; import com.yahoo.vdslib.state.NodeState; import com.yahoo.vdslib.state.NodeType; import com.yahoo.vdslib.state.State; +import com.yahoo.vespa.clustercontroller.core.status.StatusHandler; import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; @@ -60,7 +61,7 @@ public class MasterElectionTest extends FleetControllerTest { for (int i=0; i<count; ++i) { FleetControllerOptions nodeOptions = options.clone(); nodeOptions.fleetControllerIndex = i; - fleetControllers.add(createFleetController(usingFakeTimer, nodeOptions, true, null)); + fleetControllers.add(createFleetController(usingFakeTimer, nodeOptions, true, new StatusHandler.ContainerStatusPageServer())); } } @@ -143,14 +144,15 @@ public class MasterElectionTest extends FleetControllerTest { assertFalse("Fleet controller " + i, fleetControllers.get(i).isMaster()); } + StatusHandler.ContainerStatusPageServer statusPageServer = new StatusHandler.ContainerStatusPageServer(); log.log(Level.INFO, "STARTING FLEET CONTROLLER 2"); - fleetControllers.set(2, createFleetController(usingFakeTimer, fleetControllers.get(2).getOptions(), true, null)); + fleetControllers.set(2, createFleetController(usingFakeTimer, fleetControllers.get(2).getOptions(), true, statusPageServer)); waitForMaster(2); log.log(Level.INFO, "STARTING FLEET CONTROLLER 0"); - fleetControllers.set(0, createFleetController(usingFakeTimer, fleetControllers.get(0).getOptions(), true, null)); + fleetControllers.set(0, createFleetController(usingFakeTimer, fleetControllers.get(0).getOptions(), true, statusPageServer)); waitForMaster(0); log.log(Level.INFO, "STARTING FLEET CONTROLLER 1"); - fleetControllers.set(1, createFleetController(usingFakeTimer, fleetControllers.get(1).getOptions(), true, null)); + fleetControllers.set(1, createFleetController(usingFakeTimer, fleetControllers.get(1).getOptions(), true, statusPageServer)); waitForMaster(0); log.log(Level.INFO, "SHUTTING DOWN FLEET CONTROLLER 4"); @@ -538,7 +540,7 @@ public class MasterElectionTest extends FleetControllerTest { waitForMaster(1); waitForCompleteCycle(1); - fleetControllers.set(0, createFleetController(usingFakeTimer, fleetControllers.get(0).getOptions(), true, null)); + fleetControllers.set(0, createFleetController(usingFakeTimer, fleetControllers.get(0).getOptions(), true, new StatusHandler.ContainerStatusPageServer())); waitForMaster(0); waitForCompleteCycle(0); diff --git a/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/StatusPagesTest.java b/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/StatusPagesTest.java deleted file mode 100644 index f761538cf1e..00000000000 --- a/clustercontroller-core/src/test/java/com/yahoo/vespa/clustercontroller/core/StatusPagesTest.java +++ /dev/null @@ -1,374 +0,0 @@ -// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.vespa.clustercontroller.core; - -import com.yahoo.vdslib.distribution.Distribution; -import com.yahoo.vdslib.state.Node; -import com.yahoo.vdslib.state.NodeState; -import com.yahoo.vdslib.state.NodeType; -import com.yahoo.vdslib.state.State; -import com.yahoo.vespa.clustercontroller.core.status.StatusHandler; -import com.yahoo.vespa.clustercontroller.core.status.statuspage.StatusPageResponse; -import com.yahoo.vespa.clustercontroller.core.status.statuspage.StatusPageServer; -import com.yahoo.vespa.clustercontroller.utils.communication.http.HttpRequest; -import com.yahoo.vespa.clustercontroller.utils.communication.http.HttpResult; -import org.codehaus.jettison.json.JSONObject; -import org.junit.Test; - -import java.io.BufferedWriter; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStreamWriter; -import java.net.Socket; -import java.nio.charset.StandardCharsets; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.HashMap; -import java.util.Map; -import java.util.TimeZone; -import java.util.logging.Logger; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -public class StatusPagesTest extends FleetControllerTest { - - public static Logger log = Logger.getLogger(StatusPagesTest.class.getName()); - - private String doHttpGetRequest(String request, Date ifModifiedSince) throws IOException { - int statusPort = fleetController.getHttpPort(); - Socket socket = new Socket("localhost", statusPort); - - BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); - bw.write("GET " + request + " HTTP/1.1\r\n"); - if (ifModifiedSince != null) { - DateFormat df = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss z"); - df.setTimeZone(TimeZone.getTimeZone("GMT")); - bw.write("If-Modified-Since: " + df.format(ifModifiedSince) + "\r\n"); - } - bw.write("\r\n"); - bw.flush(); - - InputStream stream = socket.getInputStream(); - ByteArrayOutputStream output = new ByteArrayOutputStream(); - try { - byte [] buf = new byte[4096]; - while (true) { - int read = stream.read(buf); - if (read<=0) { - break; - } - output.write(buf, 0, read); - } - output.close(); - return output.toString(); - } finally { - stream.close(); - bw.close(); - } - } - - private String doHttpGetRequest(String request) throws IOException { - return doHttpGetRequest(request, null); - } - - @Test - public void testStatusThroughContainer() throws Exception { - startingTest("StatusPagesTest::testStatusThroughContainer()"); - FleetControllerOptions options = defaultOptions("mycluster"); - options.setStorageDistribution(new Distribution(Distribution.getDefaultDistributionConfig(3, 10))); - final StatusHandler.ContainerStatusPageServer statusServer = new StatusHandler.ContainerStatusPageServer(); - setUpFleetController(true, options, true, statusServer); - setUpVdsNodes(true, new DummyVdsNodeOptions()); - waitForStableSystem(); - - //ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 100, 100, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(1000)); - //FleetControllerComponent fcComp = new FleetControllerComponent(); - //fcComp.addFleetController("mycluster", fleetController, statusServer); - StatusHandler comp = new StatusHandler(new StatusHandler.ClusterStatusPageServerSet() { - @Override - public StatusHandler.ContainerStatusPageServer get(String cluster) { - return ("mycluster".equals(cluster) ? statusServer : null); - } - - @Override - public Map<String, StatusHandler.ContainerStatusPageServer> getAll() { - Map<String, StatusHandler.ContainerStatusPageServer> map = new HashMap<>(); - map.put("mycluster", statusServer); - return map; - } - }); - - { - HttpRequest request = new HttpRequest().setPath("/clustercontroller-status/v1"); - HttpResult result = comp.handleRequest(request); - assertEquals(result.toString(true), 200, result.getHttpReturnCode()); - assertEquals("<title>clusters</title>\n<a href=\"./mycluster\">mycluster</a><br>\n", result.getContent().toString()); - } - { - HttpRequest request = new HttpRequest().setPath("/clustercontroller-status/v1/"); - HttpResult result = comp.handleRequest(request); - assertEquals(result.toString(true), 200, result.getHttpReturnCode()); - assertEquals("<title>clusters</title>\n<a href=\"./mycluster\">mycluster</a><br>\n", result.getContent().toString()); - } - { - HttpRequest request = new HttpRequest().setPath("/clustercontroller-status/v1/mycluster"); - HttpResult result = comp.handleRequest(request); - assertEquals(result.toString(true), 200, result.getHttpReturnCode()); - assertTrue(result.toString(true), result.getContent().toString().contains( - "mycluster Cluster Controller 0 Status Page")); - } - { - HttpRequest request = new HttpRequest().setPath("/clustercontroller-status/v1/mycluster/"); - HttpResult result = comp.handleRequest(request); - assertEquals(result.toString(true), 200, result.getHttpReturnCode()); - assertTrue(result.toString(true), result.getContent().toString().contains( - "mycluster Cluster Controller 0 Status Page")); - assertTrue(result.toString(true), result.getContent().toString().contains( - "href=\"mycluster/node=distributor.0\"")); - assertTrue(result.toString(true), result.getContent().toString().contains( - "href=\"mycluster/node=storage.0\"")); - } - { - HttpRequest request = new HttpRequest().setPath("/clustercontroller-status/v1/mycluster/node=storage.0"); - HttpResult result = comp.handleRequest(request); - assertEquals(result.toString(true), 200, result.getHttpReturnCode()); - assertTrue(result.toString(true), result.getContent().toString().contains( - "Node status for storage.0")); - assertTrue(result.toString(true), result.getContent().toString().contains( - "href=\"..\"")); - } - { - HttpRequest request = new HttpRequest().setPath("/clustercontroller-status/v1/foo"); - HttpResult result = comp.handleRequest(request); - assertEquals(result.toString(true), 404, result.getHttpReturnCode()); - } - { - HttpRequest request = new HttpRequest().setPath("/foobar/v1/mycluster/"); - HttpResult result = comp.handleRequest(request); - assertEquals(result.toString(true), 404, result.getHttpReturnCode()); - } - { - HttpRequest request = new HttpRequest().setPath("/clustercontroller-status/v2/"); - HttpResult result = comp.handleRequest(request); - assertEquals(result.toString(true), 404, result.getHttpReturnCode()); - } - //executor.shutdown(); - } - - @Test - public void testZooKeeperAddressSplitting() { - String rawAddress = "conc1.foo.yahoo.com:2181,conc2.foo.yahoo.com:2181," - + "dp1.foo.yahoo.com:2181,dp2.foo.yahoo.com:2181," - + "dp3.foo.yahoo.com:2181"; - String result = "conc1.foo.yahoo.com:2181, conc2.foo.yahoo.com:2181, " - + "dp1.foo.yahoo.com:2181, dp2.foo.yahoo.com:2181, " - + "dp3.foo.yahoo.com:2181"; - String split = FleetControllerOptions.splitZooKeeperAddress(rawAddress); - assertEquals(result, split); - } - - @Test - public void testSimpleConnectionWithSomeContent() throws Exception { - // Set this to true temporary if you want to check status page from browser. Should be false in checked in code always. - boolean haltTestToViewStatusPage = false; - startingTest("StatusPagesTest::testSimpleConnectionWithSomeContent()"); - FleetControllerOptions options = defaultOptions("mycluster"); - options.setStorageDistribution(new Distribution(Distribution.getDefaultDistributionConfig(3, 10))); - //options.minRatioOfStorageNodesUp = 0.99; - if (haltTestToViewStatusPage) { - options.httpPort = 19234; - } - setUpFleetController(true, options); - setUpVdsNodes(true, new DummyVdsNodeOptions()); - waitForStableSystem(); - - nodes.get(2).disconnectBreakConnection(); - nodes.get(5).disconnectAsShutdown(); - nodes.get(7).disconnectSlobrok(); - - fleetController.getCluster().getNodeInfo(new Node(NodeType.STORAGE, 3)).setWantedState(new NodeState(NodeType.STORAGE, State.MAINTENANCE).setDescription("Test&<>special")); - - String content = doHttpGetRequest("/"); - - assertTrue(content, content.contains("<html>")); - assertTrue(content, content.contains("</html>")); - assertTrue(content, content.contains("Baseline cluster state")); - assertTrue(content, content.contains("Cluster states")); - assertTrue(content, content.contains("Event log")); - - if (haltTestToViewStatusPage) { - System.err.println(content); - try{ - Thread.sleep(1000000); - } catch (InterruptedException e) {} - } - } - - @Test - public void testNodePage() throws Exception { - startingTest("StatusPagesTest::testNodePage()"); - FleetControllerOptions options = defaultOptions("mycluster"); - options.setStorageDistribution(new Distribution(Distribution.getDefaultDistributionConfig(3, 10))); - setUpFleetController(true, options); - setUpVdsNodes(true, new DummyVdsNodeOptions()); - waitForStableSystem(); - - String content = doHttpGetRequest("/node=storage.0"); - - assertTrue(content, content.contains("<html>")); - assertTrue(content, content.contains("</html>")); - assertTrue(content, content.contains("Node status for storage.0")); - assertTrue(content, content.contains("REPORTED")); - assertTrue(content, content.contains("Altered node state in cluster state from")); - //System.err.println(sb.toString()); - } - - @Test - public void testErrorResponseCode() throws Exception { - startingTest("StatusPagesTest::testNodePage()"); - FleetControllerOptions options = defaultOptions("mycluster"); - options.setStorageDistribution(new Distribution(Distribution.getDefaultDistributionConfig(3, 10))); - setUpFleetController(true, options); - setUpVdsNodes(true, new DummyVdsNodeOptions()); - waitForStableSystem(); - - String content = doHttpGetRequest("/fraggle/rock"); - - assertTrue(content.contains("404 Not Found")); - //System.err.println(sb.toString()); - } - - private StatusPageServer.HttpRequest makeHttpRequest(String request) { - return new StatusPageServer.HttpRequest(request); - } - - @Test - public void testHttpRequestParsing() { - { - StatusPageServer.HttpRequest request = makeHttpRequest("/") ; - assertEquals("/", request.getPath()); - assertFalse(request.hasQueryParameters()); - } - { - StatusPageServer.HttpRequest request = makeHttpRequest("/foo/bar"); - assertEquals("/foo/bar", request.getPath()); - assertFalse(request.hasQueryParameters()); - } - { - StatusPageServer.HttpRequest request = makeHttpRequest("/foo/bar?baz=baff"); - assertEquals("/foo/bar", request.getPath()); - assertTrue(request.hasQueryParameters()); - assertEquals("baff", request.getQueryParameter("baz")); - } - { - StatusPageServer.HttpRequest request = makeHttpRequest("/?baz=baff&blarg=blee"); - assertEquals("/", request.getPath()); - assertTrue(request.hasQueryParameters()); - assertEquals("baff", request.getQueryParameter("baz")); - assertEquals("blee", request.getQueryParameter("blarg")); - } - { - StatusPageServer.HttpRequest request = makeHttpRequest("/node=storage.101?showlocal"); - assertEquals("/node=storage.101", request.getPath()); - assertTrue(request.hasQueryParameters()); - assertTrue(request.hasQueryParameter("showlocal")); - assertNull(request.getQueryParameter("showlocal")); - } - } - - private static class DummyRequestHandler implements StatusPageServer.RequestHandler { - private String returnData; - DummyRequestHandler(String returnData) { - this.returnData = returnData; - } - - @Override - public StatusPageResponse handle(StatusPageServer.HttpRequest request) { - StatusPageResponse response = new StatusPageResponse(); - response.writeContent(returnData); - return response; - } - } - - private String invokeHandler(StatusPageServer.RequestRouter router, String request) { - StatusPageServer.HttpRequest httpRequest = makeHttpRequest(request); - StatusPageServer.RequestHandler handler = router.resolveHandler(httpRequest); - if (handler == null) { - return null; - } - return handler.handle(httpRequest).getOutputStream().toString(StandardCharsets.UTF_8); - } - - @Test - public void testRequestRouting() { - StatusPageServer.PatternRequestRouter router = new StatusPageServer.PatternRequestRouter(); - router.addHandler("^/alerts/red.*", new DummyRequestHandler("red alert!")); - router.addHandler("^/alerts.*", new DummyRequestHandler("beige alert")); - router.addHandler("^/$", new DummyRequestHandler("root")); - assertEquals("root", invokeHandler(router, "/")); - assertEquals("beige alert", invokeHandler(router, "/alerts")); - assertEquals("beige alert", invokeHandler(router, "/alerts?foo")); - assertEquals("red alert!", invokeHandler(router, "/alerts/red")); - assertEquals("red alert!", invokeHandler(router, "/alerts/red/blue")); - assertNull(invokeHandler(router, "/blarg")); - } - - private String[] getResponseParts(String response) { - int offset = response.indexOf("\r\n\r\n"); - if (offset == -1) { - throw new IllegalStateException("No HTTP header delimiter found"); - } - return new String[] { - response.substring(0, offset + 2), // all header lines must have linebreaks - response.substring(offset + 4) - }; - } - - @Test - public void testStateServing() throws Exception { - startingTest("StatusPagesTest::testStateServing()"); - FleetControllerOptions options = defaultOptions("mycluster"); - setUpFleetController(true, options); - fleetController.updateOptions(options, 5); - waitForCompleteCycle(); - { - String content = doHttpGetRequest("/state/v1/health"); - String[] parts = getResponseParts(content); - String body = parts[1]; - String expected = - "{\n" + - " \"status\" : {\n" + - " \"code\" : \"up\"\n" + - " },\n" + - " \"config\" : {\n" + - " \"component\" : {\n" + - " \"generation\" : 5\n" + - " }\n" + - " }\n" + - "}"; - assertEquals(expected, body); - // Check that it actually parses - new JSONObject(expected); - } - } - - @Test - public void testClusterStateServing() throws Exception { - startingTest("StatusPagesTest::testClusterStateServing()"); - FleetControllerOptions options = defaultOptions("mycluster"); - setUpFleetController(true, options); - fleetController.updateOptions(options, 5); - waitForCompleteCycle(); - { - String content = doHttpGetRequest("/clusterstate"); - String[] parts = getResponseParts(content); - String body = parts[1]; - String expected = "version:2 cluster:d"; - assertEquals(expected, body); - } - } -} |