summaryrefslogtreecommitdiffstats
path: root/configserver
diff options
context:
space:
mode:
authorJon Marius Venstad <jonmv@users.noreply.github.com>2022-04-19 16:18:59 +0200
committerGitHub <noreply@github.com>2022-04-19 16:18:59 +0200
commit5cf282748f208c6c30e4943484042679185334b9 (patch)
tree271bcaefd3863bf4c7f29a6e597e9690bbc08ee6 /configserver
parent926dec1639b088d7a33a88ea3e03e679e7a618d0 (diff)
parentecc1d05760fedf9c49a24a949160aa7930838dcc (diff)
Merge pull request #22119 from vespa-engine/jonmv/no-more-serviceview/v1
Jonmv/no more serviceview/v1
Diffstat (limited to 'configserver')
-rw-r--r--configserver/pom.xml51
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/serviceview/Cluster.java78
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/serviceview/ProxyErrorMapper.java24
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/serviceview/Service.java163
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/serviceview/ServiceModel.java232
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/serviceview/StateRequestHandler.java253
-rw-r--r--configserver/src/main/java/com/yahoo/vespa/serviceview/package-info.java13
-rw-r--r--configserver/src/main/resources/configserver-app/services.xml4
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/serviceview/ServiceModelTest.java111
-rw-r--r--configserver/src/test/java/com/yahoo/vespa/serviceview/StateRequestHandlerTest.java93
10 files changed, 0 insertions, 1022 deletions
diff --git a/configserver/pom.xml b/configserver/pom.xml
index 110099421d1..1a06362e42a 100644
--- a/configserver/pom.xml
+++ b/configserver/pom.xml
@@ -184,11 +184,6 @@
</dependency>
<dependency>
<groupId>com.yahoo.vespa</groupId>
- <artifactId>serviceview</artifactId>
- <version>${project.version}</version>
- </dependency>
- <dependency>
- <groupId>com.yahoo.vespa</groupId>
<artifactId>zookeeper-server-common</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
@@ -246,52 +241,6 @@
<version>${project.version}</version>
</dependency>
- <!-- Jersey, needed by serviceview -->
- <dependency>
- <groupId>javax.ws.rs</groupId>
- <artifactId>javax.ws.rs-api</artifactId>
- <scope>provided</scope> <!-- TODO: Vespa 8: Set to compile if we get rid of the javax.ws.rs-api bundle -->
- </dependency>
- <dependency>
- <groupId>org.glassfish.jersey.core</groupId>
- <artifactId>jersey-client</artifactId>
- </dependency>
- <dependency>
- <groupId>org.glassfish.jersey.core</groupId>
- <artifactId>jersey-server</artifactId>
- <exclusions>
- <exclusion>
- <groupId>org.glassfish.jersey.media</groupId>
- <artifactId>jersey-media-jaxb</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
- <dependency>
- <groupId>org.glassfish.jersey.ext</groupId>
- <artifactId>jersey-proxy-client</artifactId>
- </dependency>
- <dependency>
- <groupId>org.glassfish.jersey.media</groupId>
- <artifactId>jersey-media-json-jackson</artifactId>
- <exclusions>
- <!-- Prevent embedding deps provided by jdisc -->
- <exclusion>
- <groupId>com.fasterxml.jackson.core</groupId>
- <artifactId>jackson-annotations</artifactId>
- </exclusion>
- <exclusion>
- <groupId>com.fasterxml.jackson.core</groupId>
- <artifactId>jackson-core</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
- <dependency>
- <!-- Not needed by configserver, but by controller. Also pulls in mimepull. -->
- <groupId>org.glassfish.jersey.media</groupId>
- <artifactId>jersey-media-multipart</artifactId>
- </dependency>
- <!-- Jersey END -->
-
</dependencies>
<build>
<plugins>
diff --git a/configserver/src/main/java/com/yahoo/vespa/serviceview/Cluster.java b/configserver/src/main/java/com/yahoo/vespa/serviceview/Cluster.java
deleted file mode 100644
index 7e2a83b6b9a..00000000000
--- a/configserver/src/main/java/com/yahoo/vespa/serviceview/Cluster.java
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.serviceview;
-
-import java.util.Arrays;
-import java.util.List;
-
-import com.google.common.collect.ImmutableList;
-
-/**
- * Model a single cluster of services in the Vespa model.
- *
- * @author Steinar Knutsen
- */
-public final class Cluster implements Comparable<Cluster> {
-
- public final String name;
- public final String type;
- /**
- * An ordered list of the service instances in this cluster.
- */
- public final ImmutableList<Service> services;
-
- public Cluster(String name, String type, List<Service> services) {
- this.name = name;
- this.type = type;
- ImmutableList.Builder<Service> builder = ImmutableList.builder();
- Service[] sortingBuffer = services.toArray(new Service[0]);
- Arrays.sort(sortingBuffer);
- builder.add(sortingBuffer);
- this.services = builder.build();
- }
-
- @Override
- public int compareTo(Cluster other) {
- int nameOrder = name.compareTo(other.name);
- if (nameOrder != 0) {
- return nameOrder;
- }
- return type.compareTo(other.type);
- }
-
- @Override
- public int hashCode() {
- final int prime = 761;
- int result = 1;
- result = prime * result + name.hashCode();
- result = prime * result + type.hashCode();
- return result;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null) {
- return false;
- }
- if (getClass() != obj.getClass()) {
- return false;
- }
- Cluster other = (Cluster) obj;
- if (!name.equals(other.name)) {
- return false;
- }
- return type.equals(other.type);
- }
-
- @Override
- public String toString() {
- final int maxLen = 3;
- StringBuilder builder = new StringBuilder();
- builder.append("Cluster [name=").append(name).append(", type=").append(type).append(", services=")
- .append(services.subList(0, Math.min(services.size(), maxLen))).append("]");
- return builder.toString();
- }
-
-}
diff --git a/configserver/src/main/java/com/yahoo/vespa/serviceview/ProxyErrorMapper.java b/configserver/src/main/java/com/yahoo/vespa/serviceview/ProxyErrorMapper.java
deleted file mode 100644
index 545e9b3ddc8..00000000000
--- a/configserver/src/main/java/com/yahoo/vespa/serviceview/ProxyErrorMapper.java
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.serviceview;
-
-import javax.ws.rs.WebApplicationException;
-import javax.ws.rs.core.Response;
-import javax.ws.rs.ext.ExceptionMapper;
-import javax.ws.rs.ext.Provider;
-
-/**
- * Convert exceptions thrown by the internal REST client into a little more helpful responses.
- *
- * @author Steinar Knutsen
- */
-@Provider
-public class ProxyErrorMapper implements ExceptionMapper<WebApplicationException> {
-
- @Override
- public Response toResponse(WebApplicationException exception) {
- StringBuilder msg = new StringBuilder("Invoking (external) web service failed: ");
- msg.append(exception.getMessage());
- return Response.status(500).entity(msg.toString()).type("text/plain").build();
- }
-
-}
diff --git a/configserver/src/main/java/com/yahoo/vespa/serviceview/Service.java b/configserver/src/main/java/com/yahoo/vespa/serviceview/Service.java
deleted file mode 100644
index 280ae1fa6c1..00000000000
--- a/configserver/src/main/java/com/yahoo/vespa/serviceview/Service.java
+++ /dev/null
@@ -1,163 +0,0 @@
-// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.serviceview;
-
-import java.math.BigInteger;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.util.ArrayList;
-import java.util.List;
-
-import com.google.common.collect.ImmutableList;
-import com.yahoo.text.Utf8;
-
-/**
- * Model a single service instance as a sortable object.
- *
- * @author Steinar Knutsen
- */
-public final class Service implements Comparable<Service> {
-
- public final String serviceType;
- public final String host;
- public final int statePort;
- public final String configId;
- public final List<Integer> ports;
- public final String name;
-
- public Service(String serviceType, String host, int statePort, String clusterName, String clusterType,
- String configId, List<Integer> ports, String name) {
- this.serviceType = serviceType;
- this.host = host.toLowerCase();
- this.statePort = statePort;
- this.configId = configId;
- ImmutableList.Builder<Integer> portsBuilder = new ImmutableList.Builder<>();
- portsBuilder.addAll(ports);
- this.ports = portsBuilder.build();
- this.name = name;
- }
-
- @Override
- public int compareTo(Service other) {
- int serviceTypeOrder = serviceType.compareTo(other.serviceType);
- if (serviceTypeOrder != 0) {
- return serviceTypeOrder;
- }
- int hostOrder = host.compareTo(other.host);
- if (hostOrder != 0) {
- return hostOrder;
- }
- return Integer.compare(statePort, other.statePort);
- }
-
- /**
- * Generate an identifier string for one of the ports of this service
- * suitable for using in an URL.
- *
- * @param port
- * port which this identifier pertains to
- * @return an opaque identifier string for this service
- */
- public String getIdentifier(int port) {
- StringBuilder b = new StringBuilder(serviceType);
- b.append("-");
- MessageDigest md5;
- try {
- md5 = MessageDigest.getInstance("MD5");
- } catch (NoSuchAlgorithmException e) {
- throw new RuntimeException("MD5 should by definition always be available in the JVM.", e);
- }
- md5.update(Utf8.toBytes(serviceType));
- md5.update(Utf8.toBytes(configId));
- md5.update(Utf8.toBytes(host));
- for (int i = 3; i >= 0; --i) {
- md5.update((byte) (port >>> i));
- }
- byte[] digest = md5.digest();
- BigInteger digestMarshal = new BigInteger(1, digest);
- b.append(digestMarshal.toString(36));
- return b.toString();
- }
-
- /**
- * All valid identifiers for this object.
- *
- * @return a list with a unique ID for each of this service's ports
- */
- public List<String> getIdentifiers() {
- List<String> ids = new ArrayList<>(ports.size());
- for (int port : ports) {
- ids.add(getIdentifier(port));
- }
- return ids;
- }
-
- /**
- * Find which port number a hash code pertains to.
- *
- * @param identifier a string generated from {@link #getIdentifier(int)}
- * @return a port number, or 0 if no match is found
- */
- public int matchIdentifierWithPort(String identifier) {
- for (int port : ports) {
- if (identifier.equals(getIdentifier(port))) {
- return port;
- }
- }
- throw new IllegalArgumentException("Identifier " + identifier + " matches no ports in " + this);
- }
-
- @Override
- public String toString() {
- final int maxLen = 3;
- StringBuilder builder = new StringBuilder();
- builder.append("Service [serviceType=").append(serviceType).append(", host=").append(host).append(", statePort=")
- .append(statePort).append(", configId=").append(configId).append(", ports=")
- .append(ports.subList(0, Math.min(ports.size(), maxLen))).append(", name=").append(name)
- .append("]");
- return builder.toString();
- }
-
- @Override
- public int hashCode() {
- final int prime = 131;
- int result = 1;
- result = prime * result + configId.hashCode();
- result = prime * result + host.hashCode();
- result = prime * result + name.hashCode();
- result = prime * result + ports.hashCode();
- result = prime * result + serviceType.hashCode();
- result = prime * result + statePort;
- return result;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null) {
- return false;
- }
- if (getClass() != obj.getClass()) {
- return false;
- }
- Service other = (Service) obj;
- if (!configId.equals(other.configId)) {
- return false;
- }
- if (!host.equals(other.host)) {
- return false;
- }
- if (!name.equals(other.name)) {
- return false;
- }
- if (!ports.equals(other.ports)) {
- return false;
- }
- if (!serviceType.equals(other.serviceType)) {
- return false;
- }
- return statePort == other.statePort;
- }
-
-}
diff --git a/configserver/src/main/java/com/yahoo/vespa/serviceview/ServiceModel.java b/configserver/src/main/java/com/yahoo/vespa/serviceview/ServiceModel.java
deleted file mode 100644
index f3e327ead32..00000000000
--- a/configserver/src/main/java/com/yahoo/vespa/serviceview/ServiceModel.java
+++ /dev/null
@@ -1,232 +0,0 @@
-// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.serviceview;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import com.google.common.collect.HashBasedTable;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Table;
-import com.google.common.collect.Table.Cell;
-import com.yahoo.vespa.serviceview.bindings.ApplicationView;
-import com.yahoo.vespa.serviceview.bindings.ClusterView;
-import com.yahoo.vespa.serviceview.bindings.HostService;
-import com.yahoo.vespa.serviceview.bindings.ModelResponse;
-import com.yahoo.vespa.serviceview.bindings.ServicePort;
-import com.yahoo.vespa.serviceview.bindings.ServiceView;
-
-import static com.yahoo.config.model.api.container.ContainerServiceType.CLUSTERCONTROLLER_CONTAINER;
-
-/**
- * A transposed view for cloud.config.model.
- *
- * @author Steinar Knutsen
- */
-public final class ServiceModel {
-
- private static final String CONTENT_CLUSTER_TYPENAME = "content";
-
- private final Map<String, Service> servicesMap;
-
- /**
- * An ordered list of the clusters in this config model.
- */
- public final ImmutableList<Cluster> clusters;
-
- ServiceModel(ModelResponse modelConfig) {
- Table<String, String, List<Service>> services = HashBasedTable.create();
- for (HostService h : modelConfig.hosts) {
- String hostName = h.name;
- for (com.yahoo.vespa.serviceview.bindings.Service s : h.services) {
- addService(services, hostName, s);
- }
- }
- List<Cluster> sortingBuffer = new ArrayList<>();
- for (Cell<String, String, List<Service>> c : services.cellSet()) {
- sortingBuffer.add(new Cluster(c.getRowKey(), c.getColumnKey(), c.getValue()));
- }
- Collections.sort(sortingBuffer);
- ImmutableList.Builder<Cluster> clustersBuilder = new ImmutableList.Builder<>();
- clustersBuilder.addAll(sortingBuffer);
- clusters = clustersBuilder.build();
- Map<String, Service> seenIdentifiers = new HashMap<>();
- for (Cluster c : clusters) {
- for (Service s : c.services) {
- List<String> identifiers = s.getIdentifiers();
- for (String identifier : identifiers) {
- if (seenIdentifiers.containsKey(identifier)) {
- throw new RuntimeException("Hash collision" + " between " +
- seenIdentifiers.get(identifier) + " and " + s + ".");
- }
- seenIdentifiers.put(identifier, s);
- }
- }
- }
- ImmutableMap.Builder<String, Service> servicesBuilder = new ImmutableMap.Builder<>();
- servicesBuilder.putAll(seenIdentifiers);
- servicesMap = servicesBuilder.build();
- }
-
- private static void addService(Table<String, String, List<Service>> services, String hostName,
- com.yahoo.vespa.serviceview.bindings.Service s) {
- boolean hasStateApi = false;
- int statePort = 0;
- List<Integer> ports = new ArrayList<>(s.ports.size());
- for (ServicePort port : s.ports) {
- ports.add(port.number);
- if (!hasStateApi && port.hasTags("http", "state")) {
- hasStateApi = true;
- statePort = port.number;
- }
- }
- // ignore hosts without state API
- if (hasStateApi) {
- Service service = new Service(s.type, hostName, statePort, s.clustername, s.clustertype, s.configid, ports, s.name);
- getAndSetEntry(services, s.clustername, s.clustertype).add(service);
- }
- }
-
- private static List<Service> getAndSetEntry(Table<String, String, List<Service>> services, String clusterName, String clusterType) {
- List<Service> serviceList = services.get(clusterName, clusterType);
- if (serviceList == null) {
- serviceList = new ArrayList<>();
- services.put(clusterName, clusterType, serviceList);
- }
- return serviceList;
- }
-
- /**
- * The top level view of a given application.
- *
- * @return a top level view of the entire application in a form suitable for
- * consumption by a REST API
- */
- public ApplicationView showAllClusters(String uriBase, String applicationIdentifier) {
- ApplicationView response = new ApplicationView();
- List<ClusterView> clusterViews = new ArrayList<>();
- for (Cluster c : clusters) {
- clusterViews.add(showCluster(c, uriBase, applicationIdentifier));
- }
- response.clusters = clusterViews;
- return response;
- }
-
- private ClusterView showCluster(Cluster c, String uriBase, String applicationIdentifier) {
- List<ServiceView> services = new ArrayList<>();
- for (Service s : c.services) {
- ServiceView service = new ServiceView();
- StringBuilder buffer = getLinkBuilder(uriBase).append(applicationIdentifier).append('/');
- service.url = buffer.append("service/").append(s.getIdentifier(s.statePort)).append("/state/v1/").toString();
- service.serviceType = s.serviceType;
- service.serviceName = s.name;
- service.configId = s.configId;
- service.host = s.host;
- addLegacyLink(uriBase, applicationIdentifier, s, service);
- services.add(service);
- }
- ClusterView v = new ClusterView();
- v.services = services;
- v.name = c.name;
- v.type = c.type;
- if (CONTENT_CLUSTER_TYPENAME.equals(c.type)) {
- Service s = getFirstClusterController();
- StringBuilder buffer = getLinkBuilder(uriBase).append(applicationIdentifier).append('/');
- buffer.append("service/").append(s.getIdentifier(s.statePort)).append("/cluster/v2/").append(c.name);
- v.url = buffer.toString();
- } else {
- v.url = null;
- }
- return v;
- }
-
- private void addLegacyLink(String uriBase, String applicationIdentifier, Service s, ServiceView service) {
- if (s.serviceType.equals("storagenode") || s.serviceType.equals("distributor")) {
- StringBuilder legacyBuffer = getLinkBuilder(uriBase);
- legacyBuffer.append("legacy/").append(applicationIdentifier).append('/');
- legacyBuffer.append("service/").append(s.getIdentifier(s.statePort)).append('/');
- service.legacyStatusPages = legacyBuffer.toString();
- }
- }
-
- private Service getFirstServiceInstanceByType(String typeName) {
- for (Cluster c : clusters) {
- for (Service s : c.services) {
- if (typeName.equals(s.serviceType)) {
- return s;
- }
- }
- }
- throw new IllegalStateException("This installation has but no service of required type: "
- + typeName + ".");
- }
-
- private Service getFirstClusterController() {
- // This is used assuming all cluster controllers know of all fleet controllers in an application
- return getFirstServiceInstanceByType(CLUSTERCONTROLLER_CONTAINER.serviceName);
- }
-
- private StringBuilder getLinkBuilder(String uriBase) {
- StringBuilder buffer = new StringBuilder(uriBase);
- if (!uriBase.endsWith("/")) {
- buffer.append('/');
- }
- return buffer;
- }
-
- @Override
- public String toString() {
- final int maxLen = 3;
- StringBuilder builder = new StringBuilder();
- builder.append("ServiceModel [clusters=")
- .append(clusters.subList(0, Math.min(clusters.size(), maxLen))).append("]");
- return builder.toString();
- }
-
-
- /**
- * Match an identifier with a service for this cluster.
- *
- * @param identifier
- * an opaque service identifier generated by the service
- * @return the corresponding Service instance
- */
- public Service getService(String identifier) {
- return servicesMap.get(identifier);
- }
-
- /**
- * Find a service based on host and port.
- *
- * @param host
- * the name of the host running the service
- * @param port
- * a port owned by the service
- * @param self
- * the service which generated the host data
- * @return a service instance fullfilling the criteria
- * @throws IllegalArgumentException
- * if no matching service is found
- */
- public Service resolve(String host, int port, Service self) {
- Integer portAsObject = port;
- String realHost;
- if ("localhost".equals(host)) {
- realHost = self.host;
- } else {
- realHost = host;
- }
- for (Cluster c : clusters) {
- for (Service s : c.services) {
- if (s.host.equals(realHost) && s.ports.contains(portAsObject)) {
- return s;
- }
- }
- }
- throw new IllegalArgumentException("No registered service owns port " + port + " on host " + realHost + ".");
- }
-
-}
diff --git a/configserver/src/main/java/com/yahoo/vespa/serviceview/StateRequestHandler.java b/configserver/src/main/java/com/yahoo/vespa/serviceview/StateRequestHandler.java
deleted file mode 100644
index 59b91a52791..00000000000
--- a/configserver/src/main/java/com/yahoo/vespa/serviceview/StateRequestHandler.java
+++ /dev/null
@@ -1,253 +0,0 @@
-// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.serviceview;
-
-import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;
-import com.google.inject.Inject;
-import com.yahoo.cloud.config.ConfigserverConfig;
-import com.yahoo.container.jdisc.ThreadedHttpRequestHandler;
-import ai.vespa.http.DomainName;
-import ai.vespa.http.HttpURL;
-import ai.vespa.http.HttpURL.Path;
-import ai.vespa.http.HttpURL.Query;
-import ai.vespa.http.HttpURL.Scheme;
-import com.yahoo.restapi.RestApi;
-import com.yahoo.restapi.RestApiRequestHandler;
-import com.yahoo.vespa.serviceview.bindings.ApplicationView;
-import com.yahoo.vespa.serviceview.bindings.ConfigClient;
-import com.yahoo.vespa.serviceview.bindings.HealthClient;
-import com.yahoo.vespa.serviceview.bindings.ModelResponse;
-import org.glassfish.jersey.client.ClientProperties;
-import org.glassfish.jersey.client.proxy.WebResourceFactory;
-
-import javax.ws.rs.client.Client;
-import javax.ws.rs.client.ClientRequestFilter;
-import javax.ws.rs.client.WebTarget;
-import javax.ws.rs.core.HttpHeaders;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.HashMap;
-import java.util.List;
-import java.util.ListIterator;
-import java.util.Map;
-
-/**
- * A web service to discover and proxy Vespa service state info.
- *
- * @author Steinar Knutsen
- * @author bjorncs
- */
-public class StateRequestHandler extends RestApiRequestHandler<StateRequestHandler> {
-
- private static final String USER_AGENT = "service-view-config-server-client";
- private static final String SINGLE_API_LINK = "url";
-
- @SuppressWarnings("removal")
- private final Client client = new ai.vespa.util.http.VespaClientBuilderFactory()
- .newBuilder()
- .property(ClientProperties.CONNECT_TIMEOUT, 10000)
- .property(ClientProperties.READ_TIMEOUT, 10000)
- .register(JacksonJsonProvider.class)
- .register((ClientRequestFilter) ctx -> ctx.getHeaders().put(HttpHeaders.USER_AGENT, List.of(USER_AGENT)))
- .build();
-
- private final int restApiPort;
-
- private static class GiveUpLinkRetargetingException extends Exception {
- public GiveUpLinkRetargetingException(Throwable reason) {
- super(reason);
- }
-
- public GiveUpLinkRetargetingException(String message) {
- super(message);
- }
- }
-
- @Inject
- public StateRequestHandler(ThreadedHttpRequestHandler.Context context,
- ConfigserverConfig configserverConfig) {
- super(context, StateRequestHandler::createRestApiDefinition);
- this.restApiPort = configserverConfig.httpport();
- }
-
- @Override
- protected void destroy() {
- client.close();
- super.destroy();
- }
-
- private static RestApi createRestApiDefinition(StateRequestHandler self) {
- return RestApi.builder()
- .addRoute(RestApi.route("/serviceview/v1")
- .get(self::getDefaultUserInfo))
- .addRoute(RestApi.route("/serviceview/v1/")
- .get(self::getDefaultUserInfo))
- .addRoute(RestApi.route("/serviceview/v1/tenant/{tenantName}/application/{applicationName}/environment/{environmentName}/region/{regionName}/instance/{instanceName}")
- .get(self::getUserInfo))
- .addRoute(RestApi.route("/serviceview/v1/tenant/{tenantName}/application/{applicationName}/environment/{environmentName}/region/{regionName}/instance/{instanceName}/service/{serviceIdentifier}/{*}")
- .get(self::singleService))
- .registerJacksonResponseEntity(HashMap.class)
- .registerJacksonResponseEntity(ApplicationView.class)
- .build();
- }
-
- private ApplicationView getDefaultUserInfo(RestApi.RequestContext context) {
- return getUserInfo(context.baseRequestURL(), "default", "default", "default", "default", "default");
- }
-
- private ApplicationView getUserInfo(RestApi.RequestContext context) {
- String tenantName = context.pathParameters().getStringOrThrow("tenantName");
- String applicationName = context.pathParameters().getStringOrThrow("applicationName");
- String environmentName = context.pathParameters().getStringOrThrow("environmentName");
- String regionName = context.pathParameters().getStringOrThrow("regionName");
- String instanceName = context.pathParameters().getStringOrThrow("instanceName");
- return getUserInfo(context.baseRequestURL(), tenantName, applicationName, environmentName, regionName, instanceName);
- }
-
- public HashMap<?, ?> singleService(RestApi.RequestContext context) {
- String tenantName = context.pathParameters().getStringOrThrow("tenantName");
- String applicationName = context.pathParameters().getStringOrThrow("applicationName");
- String environmentName = context.pathParameters().getStringOrThrow("environmentName");
- String regionName = context.pathParameters().getStringOrThrow("regionName");
- String instanceName = context.pathParameters().getStringOrThrow("instanceName");
- String identifier = context.pathParameters().getStringOrThrow("serviceIdentifier");
- Path apiParams = context.pathParameters().getRest().orElse(Path.empty());
- Query apiQuery = context.queryParameters().getFullQuery();
- return singleService(context.baseRequestURL(), tenantName, applicationName, environmentName, regionName, instanceName, identifier, apiParams, apiQuery);
- }
-
- protected ApplicationView getUserInfo(HttpURL url, String tenantName, String applicationName, String environmentName, String regionName, String instanceName) {
- ServiceModel model = new ServiceModel(
- getModelConfig(tenantName, applicationName, environmentName, regionName, instanceName));
- return model.showAllClusters(
- baseUri(url).toString(),
- applicationIdentifier(tenantName, applicationName, environmentName, regionName, instanceName));
- }
-
- protected ModelResponse getModelConfig(String tenant, String application, String environment, String region, String instance) {
- WebTarget target = client.target("http://localhost:" + restApiPort + "/");
- ConfigClient resource = WebResourceFactory.newResource(ConfigClient.class, target);
- return resource.getServiceModel(tenant, application, environment, region, instance);
- }
-
- protected HashMap<?, ?> singleService(
- HttpURL url, String tenantName, String applicationName, String environmentName, String regionName, String instanceName, String identifier, Path path, Query query) {
- ServiceModel model = new ServiceModel(getModelConfig(tenantName, applicationName, environmentName, regionName, instanceName));
- Service s = model.getService(identifier);
- int requestedPort = s.matchIdentifierWithPort(identifier);
- HealthClient resource = getHealthClient(path, s, requestedPort, query, client);
- HashMap<?, ?> apiResult = resource.getHealthInfo();
- rewriteResourceLinks(url, apiResult, model, s, applicationIdentifier(tenantName, applicationName, environmentName, regionName, instanceName), identifier);
- return apiResult;
- }
-
- protected HealthClient getHealthClient(Path apiParams, Service s, int requestedPort, Query query, Client client) {
- URI uri = HttpURL.create(Scheme.http, DomainName.of(s.host), requestedPort, apiParams, query).asURI();
- WebTarget target = client.target(uri);
- return WebResourceFactory.newResource(HealthClient.class, target);
- }
-
- private String applicationIdentifier(String tenant, String application, String environment, String region, String instance) {
- return "tenant/" + tenant
- + "/application/" + application
- + "/environment/" + environment
- + "/region/" + region
- + "/instance/" + instance;
- }
-
- private void rewriteResourceLinks(HttpURL url,
- Object apiResult,
- ServiceModel model,
- Service self,
- String applicationIdentifier,
- String incomingIdentifier) {
- if (apiResult instanceof List) {
- for (@SuppressWarnings("unchecked") ListIterator<Object> i = ((List<Object>) apiResult).listIterator(); i.hasNext();) {
- Object resource = i.next();
- if (resource instanceof String) {
- try {
- StringBuilder buffer = linkBuffer(url, applicationIdentifier);
- // if it points to a port and host not part of the application, rewriting will not occur, so this is kind of safe
- retarget(model, self, buffer, (String) resource);
- i.set(buffer.toString());
- } catch (GiveUpLinkRetargetingException e) {
- break; // assume relatively homogenous lists when doing rewrites to avoid freezing up on scanning long lists
- }
- } else {
- rewriteResourceLinks(url, resource, model, self, applicationIdentifier, incomingIdentifier);
- }
- }
- } else if (apiResult instanceof Map) {
- @SuppressWarnings("unchecked")
- Map<Object, Object> api = (Map<Object, Object>) apiResult;
- for (Map.Entry<Object, Object> entry : api.entrySet()) {
- if (SINGLE_API_LINK.equals(entry.getKey()) && entry.getValue() instanceof String) {
- try {
- rewriteSingleLink(entry, model, self, linkBuffer(url, applicationIdentifier));
- } catch (GiveUpLinkRetargetingException e) {
- // NOP
- }
- } else if ("link".equals(entry.getKey()) && entry.getValue() instanceof String) {
- buildSingleLink(entry, linkBuffer(url, applicationIdentifier), incomingIdentifier);
- } else {
- rewriteResourceLinks(url, entry.getValue(), model, self, applicationIdentifier, incomingIdentifier);
- }
- }
- }
- }
-
- private void buildSingleLink(Map.Entry<Object, Object> entry,
- StringBuilder newUri,
- String incomingIdentifier) {
- newUri.append("/service/")
- .append(incomingIdentifier);
- newUri.append(entry.getValue());
- entry.setValue(newUri.toString());
- }
-
- private void addQuery(String query, StringBuilder newUri) {
- if (query != null && query.length() > 0) {
- newUri.append('?').append(query);
- }
- }
-
- private StringBuilder linkBuffer(HttpURL url, String applicationIdentifier) {
- return new StringBuilder(baseUri(url).appendPath(Path.parse(applicationIdentifier)).toString());
- }
-
- private void rewriteSingleLink(Map.Entry<Object, Object> entry,
- ServiceModel model,
- Service self,
- StringBuilder newUri) throws GiveUpLinkRetargetingException {
- String url = (String) entry.getValue();
- retarget(model, self, newUri, url);
- entry.setValue(newUri.toString());
- }
-
- private void retarget(ServiceModel model, Service self, StringBuilder newUri, String url) throws GiveUpLinkRetargetingException {
- URI link;
- try {
- link = new URI(url);
- } catch (URISyntaxException e) {
- throw new GiveUpLinkRetargetingException(e);
- }
- if (!link.isAbsolute()) {
- throw new GiveUpLinkRetargetingException("This rewriting only supports absolute URIs.");
- }
- int linkPort = link.getPort();
- if (linkPort == -1) {
- linkPort = 80;
- }
- Service s;
- try {
- s = model.resolve(link.getHost(), linkPort, self);
- } catch (IllegalArgumentException e) {
- throw new GiveUpLinkRetargetingException(e);
- }
- newUri.append("/service/").append(s.getIdentifier(linkPort));
- newUri.append(link.getRawPath());
- }
-
- private static HttpURL baseUri(HttpURL url) {
- return url.withPath(Path.parse("/serviceview/v1/"));
- }
-}
diff --git a/configserver/src/main/java/com/yahoo/vespa/serviceview/package-info.java b/configserver/src/main/java/com/yahoo/vespa/serviceview/package-info.java
deleted file mode 100644
index 72cfaf0d05d..00000000000
--- a/configserver/src/main/java/com/yahoo/vespa/serviceview/package-info.java
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-/**
- * Home of the centralised service view implementation. The service view is a
- * REST API for discovering and accessing the state API for any service in a
- * Vespa cluster.
- *
- * <p>Do note this package is in its prototyping stage and classes <i>will</i>
- * be renamed and moved around a little.</p>
- */
-@ExportPackage
-package com.yahoo.vespa.serviceview;
-
-import com.yahoo.osgi.annotation.ExportPackage;
diff --git a/configserver/src/main/resources/configserver-app/services.xml b/configserver/src/main/resources/configserver-app/services.xml
index b3a37c6f669..3536cfc7942 100644
--- a/configserver/src/main/resources/configserver-app/services.xml
+++ b/configserver/src/main/resources/configserver-app/services.xml
@@ -83,10 +83,6 @@
<binding>http://*/orchestrator/v1/instances</binding>
<binding>http://*/orchestrator/v1/instances/*</binding>
</handler>
- <handler id="com.yahoo.vespa.serviceview.StateRequestHandler" bundle="configserver">
- <binding>http://*/serviceview/v1</binding>
- <binding>http://*/serviceview/v1/*</binding>
- </handler>
<handler id='com.yahoo.vespa.config.server.http.HttpGetConfigHandler' bundle='configserver'>
<binding>http://*/config/v1/*/*</binding>
<binding>http://*/config/v1/*</binding>
diff --git a/configserver/src/test/java/com/yahoo/vespa/serviceview/ServiceModelTest.java b/configserver/src/test/java/com/yahoo/vespa/serviceview/ServiceModelTest.java
deleted file mode 100644
index 44bc2c15e8e..00000000000
--- a/configserver/src/test/java/com/yahoo/vespa/serviceview/ServiceModelTest.java
+++ /dev/null
@@ -1,111 +0,0 @@
-// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.serviceview;
-
-import com.yahoo.vespa.defaults.Defaults;
-import com.yahoo.vespa.serviceview.bindings.ApplicationView;
-import com.yahoo.vespa.serviceview.bindings.HostService;
-import com.yahoo.vespa.serviceview.bindings.ModelResponse;
-import com.yahoo.vespa.serviceview.bindings.ServicePort;
-import com.yahoo.vespa.serviceview.bindings.ServiceView;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-
-import java.util.Arrays;
-import java.util.Collections;
-
-import static com.yahoo.config.model.api.container.ContainerServiceType.CLUSTERCONTROLLER_CONTAINER;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-
-/**
- * Functional tests for the programmatic view of cloud.config.model.
- *
- * @author Steinar Knutsen
- */
-public class ServiceModelTest {
-
- private ServiceModel model;
-
- @Before
- public void setUp() {
- ModelResponse model = syntheticModelResponse();
- this.model = new ServiceModel(model);
- }
-
- static ModelResponse syntheticModelResponse() {
- ModelResponse model = new ModelResponse();
- HostService h = new HostService();
- h.name = "vespa.yahoo.com";
- com.yahoo.vespa.serviceview.bindings.Service service0 = new com.yahoo.vespa.serviceview.bindings.Service();
- {
- service0.clustername = "examplecluster";
- service0.clustertype = "somethingservers";
- service0.index = 1L;
- service0.type = "something";
- service0.name = "examplename";
- service0.configid = "blblb/lbl.0";
- ServicePort port = new ServicePort();
- port.number = Defaults.getDefaults().vespaWebServicePort();
- port.tags = "state http";
- service0.ports = Collections.singletonList(port);
- }
- com.yahoo.vespa.serviceview.bindings.Service service1 = new com.yahoo.vespa.serviceview.bindings.Service();
- {
- service1.clustername = "examplecluster";
- service1.clustertype = "somethingservers";
- service1.index = 2L;
- service1.type = CLUSTERCONTROLLER_CONTAINER.serviceName;
- service1.name = "clustercontroller";
- service1.configid = "clustercontroller/lbl.0";
- ServicePort port = new ServicePort();
- port.number = 4090;
- port.tags = "state http";
- service1.ports = Collections.singletonList(port);
- }
- com.yahoo.vespa.serviceview.bindings.Service service2 = new com.yahoo.vespa.serviceview.bindings.Service();
- {
- service2.clustername = "tralala";
- service2.clustertype = "admin";
- service2.index = 3L;
- service2.type = "configserver";
- service2.name = "configservername";
- service2.configid = "clustercontroller/lbl.0";
- ServicePort port = new ServicePort();
- port.number = 5000;
- port.tags = "state http";
- service2.ports = Collections.singletonList(port);
- }
- h.services = Arrays.asList(service0, service1, service2);
- model.hosts = Collections.singletonList(h);
- return model;
- }
-
- @After
- public void tearDown() {
- model = null;
- }
-
- @Test
- public final void test() {
- final String uriBase = "http://configserver:5000/";
- ApplicationView x = model.showAllClusters(uriBase, "/tenant/default/application/default");
- assertEquals(2, x.clusters.size());
- String urlTracking = null;
- for (com.yahoo.vespa.serviceview.bindings.ClusterView c : x.clusters) {
- for (ServiceView s : c.services) {
- if ("examplename".equals(s.serviceName)) {
- assertEquals("something", s.serviceType);
- urlTracking = s.url;
- break;
- }
- }
- }
- assertNotNull(urlTracking);
- final String serviceIdentifier = urlTracking.substring(urlTracking.indexOf("something"),
- urlTracking.length() - "/state/v1/".length());
- Service y = model.getService(serviceIdentifier);
- assertEquals("examplename", y.name);
- }
-
-}
diff --git a/configserver/src/test/java/com/yahoo/vespa/serviceview/StateRequestHandlerTest.java b/configserver/src/test/java/com/yahoo/vespa/serviceview/StateRequestHandlerTest.java
deleted file mode 100644
index 79ed38b2025..00000000000
--- a/configserver/src/test/java/com/yahoo/vespa/serviceview/StateRequestHandlerTest.java
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.serviceview;
-
-import ai.vespa.http.HttpURL;
-import ai.vespa.http.HttpURL.Query;
-import com.yahoo.cloud.config.ConfigserverConfig;
-import com.yahoo.jdisc.test.MockMetric;
-import ai.vespa.http.HttpURL.Path;
-import com.yahoo.vespa.serviceview.bindings.ApplicationView;
-import com.yahoo.vespa.serviceview.bindings.HealthClient;
-import com.yahoo.vespa.serviceview.bindings.ModelResponse;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mockito;
-
-import javax.ws.rs.client.Client;
-import java.net.URI;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.Executors;
-
-import static org.junit.Assert.assertEquals;
-
-/**
- * Functional test for {@link StateRequestHandler}.
- *
- * @author Steinar Knutsen
- * @author bjorncs
- */
-public class StateRequestHandlerTest {
-
- private static final String EXTERNAL_BASE_URI = "http://someserver:8080/serviceview/v1/";
-
- private static class TestHandler extends StateRequestHandler {
- private static final String BASE_URI = "http://vespa.yahoo.com:8080/state/v1";
-
- TestHandler(ConfigserverConfig config) {
- super(new Context(Executors.newSingleThreadExecutor(), new MockMetric()), config);
- }
-
- @Override
- protected ModelResponse getModelConfig(String tenant, String application, String environment, String region, String instance) {
- return ServiceModelTest.syntheticModelResponse();
- }
-
- @Override
- protected HealthClient getHealthClient(Path apiParams, Service s, int requestedPort, Query query, Client client) {
- HealthClient healthClient = Mockito.mock(HealthClient.class);
- HashMap<Object, Object> dummyHealthData = new HashMap<>();
- HashMap<String, String> dummyLink = new HashMap<>();
- dummyLink.put("url", BASE_URI);
- dummyHealthData.put("resources", Collections.singletonList(dummyLink));
- Mockito.when(healthClient.getHealthInfo()).thenReturn(dummyHealthData);
- return healthClient;
- }
- }
-
- private StateRequestHandler testHandler;
- private ServiceModel correspondingModel;
-
- @Before
- public void setUp() throws Exception {
- testHandler = new TestHandler(new ConfigserverConfig(new ConfigserverConfig.Builder()));
- correspondingModel = new ServiceModel(ServiceModelTest.syntheticModelResponse());
- }
-
- @After
- public void tearDown() {
- testHandler = null;
- correspondingModel = null;
- }
-
- @Test
- public final void test() {
- Service s = correspondingModel.resolve("vespa.yahoo.com", 8080, null);
- String api = "/state/v1";
- HashMap<?, ?> boom = testHandler.singleService(HttpURL.from(URI.create("http://someserver:8080")), "default", "default", "default", "default", "default", s.getIdentifier(8080), Path.parse(api), Query.empty().add("foo", "bar"));
- assertEquals(EXTERNAL_BASE_URI + "tenant/default/application/default/environment/default/region/default/instance/default/service/" + s.getIdentifier(8080) + api,
- ((Map<?, ?>) ((List<?>) boom.get("resources")).get(0)).get("url"));
- }
-
- @Test
- public final void testLinkEquality() {
- ApplicationView explicitParameters = testHandler.getUserInfo(HttpURL.from(URI.create("http://someserver:8080")), "default", "default", "default", "default", "default");
- assertEquals(EXTERNAL_BASE_URI + "tenant/default/application/default/environment/default/region/default/instance" +
- "/default/service/container-clustercontroller-2ul67p8psr451t3w8kdd0qwgg/state/v1/",
- explicitParameters.clusters.get(0).services.get(0).url);
- }
-
-}