diff options
author | Harald Musum <musum@verizonmedia.com> | 2020-12-01 14:13:13 +0100 |
---|---|---|
committer | Harald Musum <musum@verizonmedia.com> | 2020-12-01 14:13:13 +0100 |
commit | 9c3c3967f9574c08da66b5d2bea26e6c298f0546 (patch) | |
tree | 32fcd726dad3c760c658852f6790857ad1c57027 /clustercontroller-apps/src | |
parent | 008477111ac92e2eec81596a5037a205bbea53ff (diff) |
Move code in clustercontroller-apputils into clustercontroller-apps
Code in clustercontroller-apputils is now only used from clustercontroller-apps,
so those two modules can be merged
Diffstat (limited to 'clustercontroller-apps/src')
5 files changed, 278 insertions, 0 deletions
diff --git a/clustercontroller-apps/src/main/java/com/yahoo/vespa/clustercontroller/apputil/communication/http/JDiscHttpRequestHandler.java b/clustercontroller-apps/src/main/java/com/yahoo/vespa/clustercontroller/apputil/communication/http/JDiscHttpRequestHandler.java new file mode 100644 index 00000000000..f518fe23fe6 --- /dev/null +++ b/clustercontroller-apps/src/main/java/com/yahoo/vespa/clustercontroller/apputil/communication/http/JDiscHttpRequestHandler.java @@ -0,0 +1,128 @@ +// 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.apputil.communication.http; + +import com.yahoo.container.jdisc.LoggingRequestHandler; +import com.yahoo.jdisc.HeaderFields; +import com.yahoo.jdisc.Response; +import com.yahoo.jdisc.handler.CompletionHandler; +import com.yahoo.text.Utf8; +import com.yahoo.vespa.clustercontroller.utils.communication.http.HttpRequest; +import com.yahoo.vespa.clustercontroller.utils.communication.http.HttpRequestHandler; +import com.yahoo.vespa.clustercontroller.utils.communication.http.HttpResult; + +import java.io.*; +import java.nio.charset.StandardCharsets; +import java.time.Duration; +import java.util.logging.Logger; + +/** + * Note. This class is tested through apache http instance test, using this as other endpoint. + * + * @author Haakon Humberset + * @author Harald Musum + * @author Vegard Sjonfjell + */ +public class JDiscHttpRequestHandler extends LoggingRequestHandler { + + private static final Logger log = Logger.getLogger(JDiscHttpRequestHandler.class.getName()); + private final HttpRequestHandler requestHandler; + + public JDiscHttpRequestHandler(HttpRequestHandler handler, LoggingRequestHandler.Context parentCtx) { + super(parentCtx); + this.requestHandler = handler; + } + + static class EmptyCompletionHandler implements CompletionHandler { + @Override + public void completed() { } + @Override + public void failed(Throwable throwable) { } + } + + @Override + public com.yahoo.container.jdisc.HttpResponse handle(com.yahoo.container.jdisc.HttpRequest request) { + final HttpRequest legacyRequest = new HttpRequest(); + final com.yahoo.jdisc.http.HttpRequest jDiscRequest = request.getJDiscRequest(); + + legacyRequest.setScheme(request.getUri().getScheme()); + legacyRequest.setHost(request.getUri().getHost()); + setOperation(legacyRequest, request.getMethod()); + legacyRequest.setPort(request.getUri().getPort()); + legacyRequest.setPath(request.getUri().getPath()); + copyPostData(request, legacyRequest); + copyRequestHeaders(legacyRequest, jDiscRequest); + copyParameters(legacyRequest, jDiscRequest); + legacyRequest.setTimeout(Duration.ofMinutes(60).toMillis()); + + try { + final HttpResult result = requestHandler.handleRequest(legacyRequest); + log.fine("Got result " + result.toString(true)); + return copyResponse(result); + } catch (Exception e) { + log.warning("Caught exception while handling request: " + e.getMessage()); + return new com.yahoo.container.jdisc.HttpResponse(500) { + @Override + public void render(OutputStream outputStream) throws IOException { + outputStream.write(Utf8.toBytes(e.getMessage())); + } + }; + } + } + + static HttpRequest setOperation(HttpRequest request, com.yahoo.jdisc.http.HttpRequest.Method method) { + switch (method) { + case GET: return request.setHttpOperation(HttpRequest.HttpOp.GET); + case POST: return request.setHttpOperation(HttpRequest.HttpOp.POST); + case PUT: return request.setHttpOperation(HttpRequest.HttpOp.PUT); + case DELETE: return request.setHttpOperation(HttpRequest.HttpOp.DELETE); + default: throw new IllegalStateException("Unhandled method " + method); + } + } + + private com.yahoo.container.jdisc.HttpResponse copyResponse(final HttpResult result) { + return new com.yahoo.container.jdisc.HttpResponse(result.getHttpReturnCode()) { + @Override + public void render(OutputStream outputStream) throws IOException { + outputStream.write(Utf8.toBytes(result.getContent().toString())); + } + + @Override + public void complete(){ + copyResponseHeaders(result, getJdiscResponse()); + } + }; + } + + private void copyPostData(com.yahoo.container.jdisc.HttpRequest request, HttpRequest legacyRequest) { + try { + legacyRequest.setPostContent(new String(request.getData().readAllBytes(), StandardCharsets.UTF_8)); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private static void copyParameters(HttpRequest legacyRequest, com.yahoo.jdisc.http.HttpRequest jDiscRequest) { + for (String key : jDiscRequest.parameters().keySet()) { + for (String value : jDiscRequest.parameters().get(key)) { + legacyRequest.addUrlOption(key, value); + } + } + } + + private static void copyRequestHeaders(HttpRequest legacyRequest, com.yahoo.jdisc.http.HttpRequest jDiscRequest) { + for (String key : jDiscRequest.headers().keySet()) { + for (String value : jDiscRequest.headers().get(key)) { + legacyRequest.addHttpHeader(key, value); + } + } + } + + private static HeaderFields copyResponseHeaders(HttpResult result, Response response) { + HeaderFields headers = new HeaderFields(); + for (HttpRequest.KeyValuePair keyValuePair : result.getHeaders()) { + response.headers().put((keyValuePair.getKey()), keyValuePair.getValue()); + } + return headers; + } + +} diff --git a/clustercontroller-apps/src/main/java/com/yahoo/vespa/clustercontroller/apputil/communication/http/JDiscMetricWrapper.java b/clustercontroller-apps/src/main/java/com/yahoo/vespa/clustercontroller/apputil/communication/http/JDiscMetricWrapper.java new file mode 100644 index 00000000000..559eaee4821 --- /dev/null +++ b/clustercontroller-apps/src/main/java/com/yahoo/vespa/clustercontroller/apputil/communication/http/JDiscMetricWrapper.java @@ -0,0 +1,52 @@ +// 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.apputil.communication.http; + +import com.yahoo.jdisc.Metric; +import com.yahoo.vespa.clustercontroller.utils.util.MetricReporter; + +import java.util.logging.Logger; + +public class JDiscMetricWrapper implements MetricReporter { + + private final Object lock = new Object(); + private Metric m; + + private static class ContextWrapper implements MetricReporter.Context { + Metric.Context wrappedContext; + + public ContextWrapper(Metric.Context wrapped) { + this.wrappedContext = wrapped; + } + } + + public JDiscMetricWrapper(Metric m) { + this.m = m; + } + + public void updateMetricImplementation(Metric m) { + synchronized (lock) { + this.m = m; + } + } + + public void set(String s, Number number, MetricReporter.Context context) { + synchronized (lock) { + ContextWrapper cw = (ContextWrapper) context; + m.set(s, number, cw == null ? null : cw.wrappedContext); + } + } + + public void add(String s, Number number, MetricReporter.Context context) { + synchronized (lock) { + ContextWrapper cw = (ContextWrapper) context; + m.add(s, number, cw == null ? null : cw.wrappedContext); + } + } + + public MetricReporter.Context createContext(java.util.Map<java.lang.String,?> stringMap) { + synchronized (lock) { + return new ContextWrapper(m.createContext(stringMap)); + } + } + +} diff --git a/clustercontroller-apps/src/main/java/com/yahoo/vespa/clustercontroller/apputil/communication/http/package-info.java b/clustercontroller-apps/src/main/java/com/yahoo/vespa/clustercontroller/apputil/communication/http/package-info.java new file mode 100644 index 00000000000..5d09603bea6 --- /dev/null +++ b/clustercontroller-apps/src/main/java/com/yahoo/vespa/clustercontroller/apputil/communication/http/package-info.java @@ -0,0 +1,5 @@ +// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +@ExportPackage +package com.yahoo.vespa.clustercontroller.apputil.communication.http; + +import com.yahoo.osgi.annotation.ExportPackage; diff --git a/clustercontroller-apps/src/test/java/com/yahoo/vespa/clustercontroller/apputil/communication/http/JDiscHttpRequestHandlerTest.java b/clustercontroller-apps/src/test/java/com/yahoo/vespa/clustercontroller/apputil/communication/http/JDiscHttpRequestHandlerTest.java new file mode 100644 index 00000000000..2326189a369 --- /dev/null +++ b/clustercontroller-apps/src/test/java/com/yahoo/vespa/clustercontroller/apputil/communication/http/JDiscHttpRequestHandlerTest.java @@ -0,0 +1,47 @@ +// 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.apputil.communication.http; + +import com.yahoo.vespa.clustercontroller.utils.communication.http.HttpRequest; +import org.junit.Before; +import org.junit.Test; + +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +/** + * The handler is mostly tested through the apache tests, using it as endpoint here.. + * This test class is just to test some special cases. + */ +public class JDiscHttpRequestHandlerTest { + + private ThreadPoolExecutor executor; + + @Before + public void setUp() { + executor = new ThreadPoolExecutor(10, 100, 100, TimeUnit.SECONDS, new ArrayBlockingQueue<>(1000)); + } + + public void tearDown() { + executor.shutdown(); + } + + @Test + public void testInvalidMethod() throws Exception { + try{ + HttpRequest request = new HttpRequest(); + JDiscHttpRequestHandler.setOperation(request, com.yahoo.jdisc.http.HttpRequest.Method.CONNECT); + fail("Control should not reach here"); + } catch (IllegalStateException e) { + assertEquals("Unhandled method CONNECT", e.getMessage()); + } + } + + @Test + public void testNothingButAddCoverage() throws Exception { + new JDiscHttpRequestHandler.EmptyCompletionHandler().failed(null); + } +} diff --git a/clustercontroller-apps/src/test/java/com/yahoo/vespa/clustercontroller/apputil/communication/http/JDiscMetricWrapperTest.java b/clustercontroller-apps/src/test/java/com/yahoo/vespa/clustercontroller/apputil/communication/http/JDiscMetricWrapperTest.java new file mode 100644 index 00000000000..13abfa0ecd5 --- /dev/null +++ b/clustercontroller-apps/src/test/java/com/yahoo/vespa/clustercontroller/apputil/communication/http/JDiscMetricWrapperTest.java @@ -0,0 +1,46 @@ +// 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.apputil.communication.http; + +import com.yahoo.jdisc.Metric; +import org.junit.Test; + +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class JDiscMetricWrapperTest { + + class MetricImpl implements Metric { + int calls = 0; + @Override + public void set(String s, Number number, Context context) { ++calls; } + @Override + public void add(String s, Number number, Context context) { ++calls; } + @Override + public Context createContext(Map<String, ?> stringMap) { + ++calls; + return new Context() {}; + } + }; + + @Test + public void testSimple() { + MetricImpl impl1 = new MetricImpl(); + MetricImpl impl2 = new MetricImpl(); + JDiscMetricWrapper wrapper = new JDiscMetricWrapper(impl1); + wrapper.add("foo", 234, null); + wrapper.set("bar", 234, null); + assertTrue(wrapper.createContext(null) != null); + assertEquals(3, impl1.calls); + impl1.calls = 0; + wrapper.updateMetricImplementation(impl2); + wrapper.add("foo", 234, wrapper.createContext(null)); + wrapper.set("bar", 234, wrapper.createContext(null)); + assertTrue(wrapper.createContext(null) != null); + assertEquals(0, impl1.calls); + assertEquals(5, impl2.calls); + + } + +} |