summaryrefslogtreecommitdiffstats
path: root/node-repository
diff options
context:
space:
mode:
authorMartin Polden <mpolden@mpolden.no>2019-01-10 13:44:45 +0100
committerMartin Polden <mpolden@mpolden.no>2019-01-10 15:23:21 +0100
commit5fb219640514a98b65275c0d485ea371f58ac0df (patch)
tree38e136b3d2a95afbe904a1343f1667ec78547463 /node-repository
parenta9c77576da201d3da009e8f86800d23070284a41 (diff)
Add /loadbalancers/v1/
Diffstat (limited to 'node-repository')
-rw-r--r--node-repository/src/main/config/node-repository.xml5
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/v2/LoadBalancersApiHandler.java52
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/v2/LoadBalancersResponse.java78
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/ContainerConfig.java55
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNodeRepository.java3
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/RestApiTest.java7
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/flags1.json2
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/flags2.json1
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/load-balancers.json43
9 files changed, 219 insertions, 27 deletions
diff --git a/node-repository/src/main/config/node-repository.xml b/node-repository/src/main/config/node-repository.xml
index 9276ce0e7c9..22ab615bfad 100644
--- a/node-repository/src/main/config/node-repository.xml
+++ b/node-repository/src/main/config/node-repository.xml
@@ -11,5 +11,10 @@
<binding>https://*/nodes/v2/*</binding>
</handler>
+<handler id="com.yahoo.vespa.hosted.provision.restapi.v2.LoadBalancersApiHandler" bundle="node-repository">
+ <binding>http://*/loadbalancers/v1/*</binding>
+ <binding>https://*/loadbalancers/v1/*</binding>
+</handler>
+
<preprocess:include file="node-flavors.xml" required="false" />
<preprocess:include file="node-repository-config.xml" required="false" />
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/v2/LoadBalancersApiHandler.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/v2/LoadBalancersApiHandler.java
new file mode 100644
index 00000000000..6ffac2c0fbc
--- /dev/null
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/v2/LoadBalancersApiHandler.java
@@ -0,0 +1,52 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.hosted.provision.restapi.v2;
+
+import com.yahoo.container.jdisc.HttpRequest;
+import com.yahoo.container.jdisc.HttpResponse;
+import com.yahoo.container.jdisc.LoggingRequestHandler;
+import com.yahoo.vespa.hosted.provision.NoSuchNodeException;
+import com.yahoo.vespa.hosted.provision.NodeRepository;
+import com.yahoo.yolean.Exceptions;
+
+import javax.inject.Inject;
+import java.util.logging.Level;
+
+/**
+ * @author mpolden
+ */
+public class LoadBalancersApiHandler extends LoggingRequestHandler {
+
+ private final NodeRepository nodeRepository;
+
+ @Inject
+ public LoadBalancersApiHandler(LoggingRequestHandler.Context parentCtx, NodeRepository nodeRepository) {
+ super(parentCtx);
+ this.nodeRepository = nodeRepository;
+ }
+
+ @Override
+ public HttpResponse handle(HttpRequest request) {
+ try {
+ switch (request.getMethod()) {
+ case GET: return handleGET(request);
+ default: return ErrorResponse.methodNotAllowed("Method '" + request.getMethod() + "' is not supported");
+ }
+ }
+ catch (NotFoundException | NoSuchNodeException e) {
+ return ErrorResponse.notFoundError(Exceptions.toMessageString(e));
+ }
+ catch (IllegalArgumentException e) {
+ return ErrorResponse.badRequest(Exceptions.toMessageString(e));
+ }
+ catch (RuntimeException e) {
+ log.log(Level.WARNING, "Unexpected error handling '" + request.getUri() + "'", e);
+ return ErrorResponse.internalServerError(Exceptions.toMessageString(e));
+ }
+ }
+
+ private HttpResponse handleGET(HttpRequest request) {
+ String path = request.getUri().getPath();
+ if (path.equals("/loadbalancers/v1/")) return new LoadBalancersResponse(request, nodeRepository);
+ throw new NotFoundException("Nothing at path '" + path + "'");
+ }
+}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/v2/LoadBalancersResponse.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/v2/LoadBalancersResponse.java
new file mode 100644
index 00000000000..04a1cdaeeda
--- /dev/null
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/restapi/v2/LoadBalancersResponse.java
@@ -0,0 +1,78 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.hosted.provision.restapi.v2;
+
+import com.yahoo.config.provision.ApplicationId;
+import com.yahoo.container.jdisc.HttpRequest;
+import com.yahoo.container.jdisc.HttpResponse;
+import com.yahoo.slime.Cursor;
+import com.yahoo.slime.JsonFormat;
+import com.yahoo.slime.Slime;
+import com.yahoo.vespa.hosted.provision.NodeRepository;
+import com.yahoo.vespa.hosted.provision.lb.LoadBalancer;
+import com.yahoo.vespa.hosted.provision.node.filter.ApplicationFilter;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * @author mpolden
+ */
+public class LoadBalancersResponse extends HttpResponse {
+
+ private final NodeRepository nodeRepository;
+ private final HttpRequest request;
+
+ public LoadBalancersResponse(HttpRequest request, NodeRepository nodeRepository) {
+ super(200);
+ this.request = request;
+ this.nodeRepository = nodeRepository;
+ }
+
+ private Optional<ApplicationId> application() {
+ return Optional.ofNullable(request.getProperty("application")).map(ApplicationFilter::toApplicationId);
+ }
+
+ private List<LoadBalancer> loadBalancers() {
+ return application().map(nodeRepository.database()::readLoadBalancers)
+ .orElseGet(() -> new ArrayList<>(nodeRepository.database().readLoadBalancers().values()));
+ }
+
+ @Override
+ public String getContentType() { return "application/json"; }
+
+ @Override
+ public void render(OutputStream stream) throws IOException {
+ Slime slime = new Slime();
+ Cursor root = slime.setObject();
+ Cursor loadBalancerArray = root.setArray("loadBalancers");
+
+ loadBalancers().forEach(lb -> {
+ Cursor lbObject = loadBalancerArray.addObject();
+ lbObject.setString("id", lb.id().serializedForm());
+ lbObject.setString("application", lb.id().application().application().value());
+ lbObject.setString("tenant", lb.id().application().tenant().value());
+ lbObject.setString("instance", lb.id().application().instance().value());
+ lbObject.setString("cluster", lb.id().cluster().value());
+ lbObject.setString("hostname", lb.hostname().value());
+
+ Cursor portArray = lbObject.setArray("ports");
+ lb.ports().forEach(portArray::addLong);
+
+ Cursor realArray = lbObject.setArray("reals");
+ lb.reals().forEach(real -> {
+ Cursor realObject = realArray.addObject();
+ realObject.setString("hostname", real.hostname().value());
+ realObject.setString("ipAddress", real.ipAddress());
+ realObject.setLong("port", real.port());
+ });
+
+ lbObject.setBool("inactive", lb.inactive());
+ });
+
+ new JsonFormat(true).encode(stream, slime);
+ }
+
+}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/ContainerConfig.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/ContainerConfig.java
index 110d0ca94d0..bc8772af952 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/ContainerConfig.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/ContainerConfig.java
@@ -9,31 +9,34 @@ package com.yahoo.vespa.hosted.provision.testutils;
*/
public class ContainerConfig {
- public static String servicesXmlV2(int port) {
- return "<jdisc version='1.0'>\n" +
- " <config name=\"container.handler.threadpool\">\n" +
- " <maxthreads>10</maxthreads>\n" +
- " </config> \n" +
- " <component id='com.yahoo.test.ManualClock'/>\n" +
- " <component id='com.yahoo.vespa.curator.mock.MockCurator'/>\n" +
- " <component id='com.yahoo.vespa.hosted.provision.testutils.OrchestratorMock'/>\n" +
- " <component id='com.yahoo.vespa.hosted.provision.testutils.MockDeployer'/>\n" +
- " <component id='com.yahoo.vespa.hosted.provision.testutils.MockProvisioner'/>\n" +
- " <component id='com.yahoo.vespa.hosted.provision.testutils.TestHostLivenessTracker'/>\n" +
- " <component id='com.yahoo.vespa.hosted.provision.testutils.ServiceMonitorStub'/>\n" +
- " <component id='com.yahoo.vespa.hosted.provision.testutils.MockDuperModel'/>\n" +
- " <component id='com.yahoo.vespa.hosted.provision.testutils.MockNodeFlavors'/>\n" +
- " <component id='com.yahoo.vespa.hosted.provision.testutils.MockNodeRepository'/>\n" +
- " <component id='com.yahoo.vespa.hosted.provision.lb.LoadBalancerServiceMock'/>\n" +
- " <component id='com.yahoo.vespa.hosted.provision.maintenance.NodeRepositoryMaintenance'/>\n" +
- " <component id='com.yahoo.config.provision.Zone'/>\n" +
- " <handler id='com.yahoo.vespa.hosted.provision.restapi.v2.NodesApiHandler'>\n" +
- " <binding>http://*/nodes/v2/*</binding>\n" +
- " </handler>\n" +
- " <http>\n" +
- " <server id='myServer' port='" + port + "'/>\n" +
- " </http>\n" +
- "</jdisc>";
- }
+ public static String servicesXmlV2(int port) {
+ return "<jdisc version='1.0'>\n" +
+ " <config name=\"container.handler.threadpool\">\n" +
+ " <maxthreads>10</maxthreads>\n" +
+ " </config> \n" +
+ " <component id='com.yahoo.test.ManualClock'/>\n" +
+ " <component id='com.yahoo.vespa.curator.mock.MockCurator'/>\n" +
+ " <component id='com.yahoo.vespa.hosted.provision.testutils.OrchestratorMock'/>\n" +
+ " <component id='com.yahoo.vespa.hosted.provision.testutils.MockDeployer'/>\n" +
+ " <component id='com.yahoo.vespa.hosted.provision.testutils.MockProvisioner'/>\n" +
+ " <component id='com.yahoo.vespa.hosted.provision.testutils.TestHostLivenessTracker'/>\n" +
+ " <component id='com.yahoo.vespa.hosted.provision.testutils.ServiceMonitorStub'/>\n" +
+ " <component id='com.yahoo.vespa.hosted.provision.testutils.MockDuperModel'/>\n" +
+ " <component id='com.yahoo.vespa.hosted.provision.testutils.MockNodeFlavors'/>\n" +
+ " <component id='com.yahoo.vespa.hosted.provision.testutils.MockNodeRepository'/>\n" +
+ " <component id='com.yahoo.vespa.hosted.provision.lb.LoadBalancerServiceMock'/>\n" +
+ " <component id='com.yahoo.vespa.hosted.provision.maintenance.NodeRepositoryMaintenance'/>\n" +
+ " <component id='com.yahoo.config.provision.Zone'/>\n" +
+ " <handler id='com.yahoo.vespa.hosted.provision.restapi.v2.NodesApiHandler'>\n" +
+ " <binding>http://*/nodes/v2/*</binding>\n" +
+ " </handler>\n" +
+ " <handler id='com.yahoo.vespa.hosted.provision.restapi.v2.LoadBalancersApiHandler'>\n" +
+ " <binding>http://*/loadbalancers/v1/*</binding>\n" +
+ " </handler>\n" +
+ " <http>\n" +
+ " <server id='myServer' port='" + port + "'/>\n" +
+ " </http>\n" +
+ "</jdisc>";
+ }
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNodeRepository.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNodeRepository.java
index 1b8ae58a97d..183255db06b 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNodeRepository.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockNodeRepository.java
@@ -18,6 +18,7 @@ import com.yahoo.transaction.NestedTransaction;
import com.yahoo.vespa.curator.mock.MockCurator;
import com.yahoo.vespa.hosted.provision.Node;
import com.yahoo.vespa.hosted.provision.NodeRepository;
+import com.yahoo.vespa.hosted.provision.flag.FlagId;
import com.yahoo.vespa.hosted.provision.lb.LoadBalancerServiceMock;
import com.yahoo.vespa.hosted.provision.node.Agent;
import com.yahoo.vespa.hosted.provision.node.Status;
@@ -111,6 +112,8 @@ public class MockNodeRepository extends NodeRepository {
dirtyRecursively("host55.yahoo.com", Agent.system, getClass().getSimpleName());
ApplicationId zoneApp = ApplicationId.from(TenantName.from("zoneapp"), ApplicationName.from("zoneapp"), InstanceName.from("zoneapp"));
+ // TODO: Remove this once feature flag is removed
+ this.flags().setEnabled(FlagId.exclusiveLoadBalancer, zoneApp, true);
ClusterSpec zoneCluster = ClusterSpec.request(ClusterSpec.Type.container,
ClusterSpec.Id.from("node-admin"),
Version.fromString("6.42"),
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/RestApiTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/RestApiTest.java
index ae7f3f14975..ec09805ff5d 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/RestApiTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/RestApiTest.java
@@ -706,6 +706,13 @@ public class RestApiTest {
}
}
+ @Test
+ public void test_load_balancers() throws Exception {
+ assertFile(new Request("http://localhost:8080/loadbalancers/v1/"), "load-balancers.json");
+ assertFile(new Request("http://localhost:8080/loadbalancers/v1/?application=zoneapp.zoneapp.zoneapp"), "load-balancers.json");
+ assertResponse(new Request("http://localhost:8080/loadbalancers/v1/?application=tenant.nonexistent.default"), "{\"loadBalancers\":[]}");
+ }
+
private String asDockerNodeJson(String hostname, String parentHostname, int additionalIpCount, String... ipAddress) {
return "{\"hostname\":\"" + hostname + "\", \"parentHostname\":\"" + parentHostname + "\"," +
createIpAddresses(ipAddress) +
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/flags1.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/flags1.json
index f27545f6094..33bf1e1cf42 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/flags1.json
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/flags1.json
@@ -4,7 +4,7 @@
"id": "exclusive-load-balancer",
"enabled": false,
"enabledHostnames": [],
- "enabledApplications": []
+ "enabledApplications": ["zoneapp:zoneapp:zoneapp"]
},
{
"id": "new-cache-counting",
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/flags2.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/flags2.json
index a0e9954bec4..8d6859f550a 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/flags2.json
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/flags2.json
@@ -7,6 +7,7 @@
"host1"
],
"enabledApplications": [
+ "zoneapp:zoneapp:zoneapp",
"foo:bar:default"
]
},
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/load-balancers.json b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/load-balancers.json
new file mode 100644
index 00000000000..c882f7652d8
--- /dev/null
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/restapi/v2/responses/load-balancers.json
@@ -0,0 +1,43 @@
+{
+ "loadBalancers": [
+ {
+ "id": "zoneapp:zoneapp:zoneapp:node-admin",
+ "application": "zoneapp",
+ "tenant": "zoneapp",
+ "instance": "zoneapp",
+ "cluster": "node-admin",
+ "hostname": "lb-zoneapp.zoneapp.zoneapp-node-admin",
+ "ports": [
+ 4443
+ ],
+ "reals": [
+ {
+ "hostname": "dockerhost4.yahoo.com",
+ "ipAddress": "127.0.0.1",
+ "port": 4443
+ },
+ {
+ "hostname": "dockerhost5.yahoo.com",
+ "ipAddress": "127.0.0.1",
+ "port": 4443
+ },
+ {
+ "hostname": "dockerhost2.yahoo.com",
+ "ipAddress": "127.0.0.1",
+ "port": 4443
+ },
+ {
+ "hostname": "dockerhost3.yahoo.com",
+ "ipAddress": "127.0.0.1",
+ "port": 4443
+ },
+ {
+ "hostname": "dockerhost1.yahoo.com",
+ "ipAddress": "127.0.0.1",
+ "port": 4443
+ }
+ ],
+ "inactive": false
+ }
+ ]
+}