diff options
41 files changed, 0 insertions, 1881 deletions
diff --git a/configserver/pom.xml b/configserver/pom.xml index 110099421d1..b254e8420d4 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> 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); - } - -} diff --git a/controller-api/pom.xml b/controller-api/pom.xml index 5b81b793534..dc2ec981e66 100644 --- a/controller-api/pom.xml +++ b/controller-api/pom.xml @@ -34,13 +34,6 @@ <dependency> <groupId>com.yahoo.vespa</groupId> - <artifactId>serviceview</artifactId> - <scope>provided</scope> - <version>${project.version}</version> - </dependency> - - <dependency> - <groupId>com.yahoo.vespa</groupId> <artifactId>config-provisioning</artifactId> <scope>provided</scope> <version>${project.version}</version> diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/application/v4/EnvironmentResource.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/application/v4/EnvironmentResource.java index 389cda605af..7953fbc4055 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/application/v4/EnvironmentResource.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/application/v4/EnvironmentResource.java @@ -70,9 +70,6 @@ public interface EnvironmentResource { @PathParam("instanceId") InstanceId instanceId, @QueryParam("timeout") long timeoutInSeconds); - @Path("{environmentId}/region/{regionId}/instance/{instanceId}/service") - ServiceViewResource service(); - @PUT @Path("{environmentId}/region/{regionId}/instance/{instanceId}/global-rotation/override") String setRotationOut(@PathParam("tenantId") TenantId tenantId, diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/application/v4/ServiceViewResource.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/application/v4/ServiceViewResource.java deleted file mode 100644 index 1d2860f5dd3..00000000000 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/application/v4/ServiceViewResource.java +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.vespa.hosted.controller.api.application.v4; - -import com.yahoo.vespa.serviceview.bindings.ApplicationView; - -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; -import java.util.HashMap; - -/** - * @author Stian Kristoffersen - */ -@Path("") -@Produces(MediaType.APPLICATION_JSON) -public interface ServiceViewResource { - - @GET - @Path("") - @Produces(MediaType.APPLICATION_JSON) - ApplicationView getUserInfo(); - - @GET - @Path("{serviceIdentifier}/{apiParams: .*}") - @Produces(MediaType.APPLICATION_JSON) - @SuppressWarnings("rawtypes") - HashMap singleService(@PathParam("serviceIdentifier") String identifier, - @PathParam("apiParams") String apiParams); - -} diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/ConfigServer.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/ConfigServer.java index 6dccf493d92..cc0baf09c6b 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/ConfigServer.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/configserver/ConfigServer.java @@ -18,7 +18,6 @@ import com.yahoo.vespa.hosted.controller.api.integration.deployment.TestReport; import com.yahoo.vespa.hosted.controller.api.integration.deployment.TesterCloud; import com.yahoo.vespa.hosted.controller.api.integration.noderepository.RestartFilter; import com.yahoo.vespa.hosted.controller.api.integration.secrets.TenantSecretStore; -import com.yahoo.vespa.serviceview.bindings.ApplicationView; import java.io.InputStream; import java.net.URI; @@ -53,10 +52,6 @@ public interface ConfigServer { boolean isSuspended(DeploymentId deployment); - ApplicationView getApplicationView(String tenantName, String applicationName, String instanceName, String environment, String region); - - Map<?,?> getServiceApiResponse(DeploymentId deployment, String serviceName, Path restPath); - /** Returns a proxied response from a given path running on a given service and node */ ProxyResponse getServiceNodePage(DeploymentId deployment, String serviceName, DomainName node, Path subPath, Query query); diff --git a/controller-server/pom.xml b/controller-server/pom.xml index 5697d849b0f..5cf53929a98 100644 --- a/controller-server/pom.xml +++ b/controller-server/pom.xml @@ -56,13 +56,6 @@ <dependency> <groupId>com.yahoo.vespa</groupId> - <artifactId>serviceview</artifactId> - <version>${project.version}</version> - <scope>provided</scope> - </dependency> - - <dependency> - <groupId>com.yahoo.vespa</groupId> <artifactId>config-provisioning</artifactId> <version>${project.version}</version> <scope>provided</scope> diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/Controller.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/Controller.java index be88aede1eb..c28cfb4ec6f 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/Controller.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/Controller.java @@ -28,14 +28,12 @@ import com.yahoo.vespa.hosted.controller.persistence.CuratorDb; import com.yahoo.vespa.hosted.controller.persistence.JobControlFlags; import com.yahoo.vespa.hosted.controller.security.AccessControl; import com.yahoo.vespa.hosted.controller.support.access.SupportAccessControl; -import com.yahoo.vespa.hosted.controller.api.identifiers.ControllerVersion; import com.yahoo.vespa.hosted.controller.versions.OsVersion; import com.yahoo.vespa.hosted.controller.versions.OsVersionStatus; import com.yahoo.vespa.hosted.controller.versions.OsVersionTarget; import com.yahoo.vespa.hosted.controller.versions.VersionStatus; import com.yahoo.vespa.hosted.controller.versions.VespaVersion; import com.yahoo.vespa.hosted.rotation.config.RotationsConfig; -import com.yahoo.vespa.serviceview.bindings.ApplicationView; import com.yahoo.yolean.concurrent.Sleeper; import java.time.Clock; @@ -49,7 +47,6 @@ import java.util.Set; import java.util.TreeSet; import java.util.function.Function; import java.util.function.Predicate; -import java.util.function.Supplier; import java.util.logging.Logger; import java.util.stream.Collectors; @@ -172,11 +169,6 @@ public class Controller extends AbstractComponent { public ControllerConfig controllerConfig() { return controllerConfig; } - public ApplicationView getApplicationView(String tenantName, String applicationName, String instanceName, - String environment, String region) { - return serviceRegistry.configServer().getApplicationView(tenantName, applicationName, instanceName, environment, region); - } - /** Replace the current version status by a new one */ public void updateVersionStatus(VersionStatus newStatus) { VersionStatus currentStatus = readVersionStatus(); diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java index 59240960dd1..a9d1386c032 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiHandler.java @@ -119,7 +119,6 @@ import com.yahoo.vespa.hosted.controller.tenant.TenantContacts; import com.yahoo.vespa.hosted.controller.tenant.TenantInfo; import com.yahoo.vespa.hosted.controller.versions.VersionStatus; import com.yahoo.vespa.hosted.controller.versions.VespaVersion; -import com.yahoo.vespa.serviceview.bindings.ApplicationView; import com.yahoo.yolean.Exceptions; import javax.ws.rs.ForbiddenException; @@ -268,8 +267,6 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler { if (path.matches("/application/v4/tenant/{tenant}/application/{application}/instance/{instance}/environment/{environment}/region/{region}")) return deployment(path.get("tenant"), path.get("application"), path.get("instance"), path.get("environment"), path.get("region"), request); if (path.matches("/application/v4/tenant/{tenant}/application/{application}/instance/{instance}/environment/{environment}/region/{region}/reindexing")) return getReindexing(path.get("tenant"), path.get("application"), path.get("instance"), path.get("environment"), path.get("region"), request); if (path.matches("/application/v4/tenant/{tenant}/application/{application}/instance/{instance}/environment/{environment}/region/{region}/suspended")) return suspended(path.get("tenant"), path.get("application"), path.get("instance"), path.get("environment"), path.get("region"), request); - if (path.matches("/application/v4/tenant/{tenant}/application/{application}/instance/{instance}/environment/{environment}/region/{region}/service")) return services(path.get("tenant"), path.get("application"), path.get("instance"), path.get("environment"), path.get("region"), request); - if (path.matches("/application/v4/tenant/{tenant}/application/{application}/instance/{instance}/environment/{environment}/region/{region}/service/{service}/state/v1/{*}")) return service(path.get("tenant"), path.get("application"), path.get("instance"), path.get("environment"), path.get("region"), path.get("service"), path.getRest(), request); if (path.matches("/application/v4/tenant/{tenant}/application/{application}/instance/{instance}/environment/{environment}/region/{region}/service/{service}/{host}/status/{*}")) return status(path.get("tenant"), path.get("application"), path.get("instance"), path.get("environment"), path.get("region"), path.get("service"), path.get("host"), path.getRest(), request); if (path.matches("/application/v4/tenant/{tenant}/application/{application}/instance/{instance}/environment/{environment}/region/{region}/service/{service}/{host}/state/v1/{*}")) return stateV1(path.get("tenant"), path.get("application"), path.get("instance"), path.get("environment"), path.get("region"), path.get("service"), path.get("host"), path.getRest(), request); if (path.matches("/application/v4/tenant/{tenant}/application/{application}/instance/{instance}/environment/{environment}/region/{region}/nodes")) return nodes(path.get("tenant"), path.get("application"), path.get("instance"), path.get("environment"), path.get("region")); @@ -284,8 +281,6 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler { if (path.matches("/application/v4/tenant/{tenant}/application/{application}/environment/{environment}/region/{region}/instance/{instance}")) return deployment(path.get("tenant"), path.get("application"), path.get("instance"), path.get("environment"), path.get("region"), request); if (path.matches("/application/v4/tenant/{tenant}/application/{application}/environment/{environment}/region/{region}/instance/{instance}")) return deployment(path.get("tenant"), path.get("application"), path.get("instance"), path.get("environment"), path.get("region"), request); if (path.matches("/application/v4/tenant/{tenant}/application/{application}/environment/{environment}/region/{region}/instance/{instance}/suspended")) return suspended(path.get("tenant"), path.get("application"), path.get("instance"), path.get("environment"), path.get("region"), request); - if (path.matches("/application/v4/tenant/{tenant}/application/{application}/environment/{environment}/region/{region}/instance/{instance}/service")) return services(path.get("tenant"), path.get("application"), path.get("instance"), path.get("environment"), path.get("region"), request); - if (path.matches("/application/v4/tenant/{tenant}/application/{application}/environment/{environment}/region/{region}/instance/{instance}/service/{service}/state/v1/{*}")) return service(path.get("tenant"), path.get("application"), path.get("instance"), path.get("environment"), path.get("region"), path.get("service"), path.getRest(), request); if (path.matches("/application/v4/tenant/{tenant}/application/{application}/environment/{environment}/region/{region}/instance/{instance}/service/{service}/{host}/status/{*}")) return status(path.get("tenant"), path.get("application"), path.get("instance"), path.get("environment"), path.get("region"), path.get("service"), path.get("host"), path.getRest(), request); if (path.matches("/application/v4/tenant/{tenant}/application/{application}/environment/{environment}/region/{region}/instance/{instance}/nodes")) return nodes(path.get("tenant"), path.get("application"), path.get("instance"), path.get("environment"), path.get("region")); if (path.matches("/application/v4/tenant/{tenant}/application/{application}/environment/{environment}/region/{region}/instance/{instance}/clusters")) return clusters(path.get("tenant"), path.get("application"), path.get("instance"), path.get("environment"), path.get("region")); @@ -1782,17 +1777,6 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler { return new SlimeJsonResponse(slime); } - private HttpResponse services(String tenantName, String applicationName, String instanceName, String environment, String region, HttpRequest request) { - ApplicationView applicationView = controller.getApplicationView(tenantName, applicationName, instanceName, environment, region); - ZoneId zone = requireZone(environment, region); - ServiceApiResponse response = new ServiceApiResponse(zone, - new ApplicationId.Builder().tenant(tenantName).applicationName(applicationName).instanceName(instanceName).build(), - List.of(controller.zoneRegistry().getConfigServerVipUri(zone)), - request.getUri()); - response.setResponse(applicationView); - return response; - } - private HttpResponse status(String tenantName, String applicationName, String instanceName, String environment, String region, String serviceName, String host, HttpURL.Path restPath, HttpRequest request) { DeploymentId deploymentId = new DeploymentId(ApplicationId.from(tenantName, applicationName, instanceName), requireZone(environment, region)); return controller.serviceRegistry().configServer().getServiceNodePage(deploymentId, @@ -1810,17 +1794,6 @@ public class ApplicationApiHandler extends AuditLoggingRequestHandler { deploymentId, serviceName, DomainName.of(host), HttpURL.Path.parse("/state/v1").append(rest), query); } - private HttpResponse service(String tenantName, String applicationName, String instanceName, String environment, String region, String serviceName, HttpURL.Path restPath, HttpRequest request) { - DeploymentId deploymentId = new DeploymentId(ApplicationId.from(tenantName, applicationName, instanceName), requireZone(environment, region)); - Map<?,?> result = controller.serviceRegistry().configServer().getServiceApiResponse(deploymentId, serviceName, restPath); - ServiceApiResponse response = new ServiceApiResponse(deploymentId.zoneId(), - deploymentId.applicationId(), - List.of(controller.zoneRegistry().getConfigServerVipUri(deploymentId.zoneId())), - request.getUri()); - response.setResponse(result, serviceName, HttpURL.Path.parse("/state/v1").append(restPath)); - return response; - } - private HttpResponse content(String tenantName, String applicationName, String instanceName, String environment, String region, HttpURL.Path restPath, HttpRequest request) { DeploymentId deploymentId = new DeploymentId(ApplicationId.from(tenantName, applicationName, instanceName), requireZone(environment, region)); return controller.serviceRegistry().configServer().getApplicationPackageContent(deploymentId, restPath, request.getUri()); diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ServiceApiResponse.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ServiceApiResponse.java deleted file mode 100644 index ee4ed1b31f9..00000000000 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/restapi/application/ServiceApiResponse.java +++ /dev/null @@ -1,197 +0,0 @@ -// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.vespa.hosted.controller.restapi.application; - -import ai.vespa.http.HttpURL; -import ai.vespa.http.HttpURL.Path; -import ai.vespa.http.HttpURL.Query; -import com.yahoo.config.provision.ApplicationId; -import com.yahoo.config.provision.zone.ZoneId; -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.serviceview.bindings.ApplicationView; -import com.yahoo.vespa.serviceview.bindings.ClusterView; -import com.yahoo.vespa.serviceview.bindings.ServiceView; - -import java.io.IOException; -import java.io.OutputStream; -import java.net.URI; -import java.util.List; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * A response containing a service view for an application deployment. - * This does not define the API response but merely proxies the API response provided by Vespa, with URLs - * rewritten to include zone and application information allow proxying through the controller - * - * @author Steinar Knutsen - * @author bratseth - */ -class ServiceApiResponse extends HttpResponse { - - private final ZoneId zone; - private final ApplicationId application; - private final List<URI> configServerURIs; - private final Slime slime; - private final HttpURL requestUri; - - // Only set for one of the setResponse calls - private String serviceName = null; - private Path restPath = null; - - public ServiceApiResponse(ZoneId zone, ApplicationId application, List<URI> configServerURIs, URI requestUri) { - super(200); - this.zone = zone; - this.application = application; - this.configServerURIs = configServerURIs; - this.slime = new Slime(); - this.requestUri = HttpURL.from(requestUri).withQuery(Query.empty()); - } - - public void setResponse(ApplicationView applicationView) { - Cursor clustersArray = slime.setObject().setArray("clusters"); - for (ClusterView clusterView : applicationView.clusters) { - Cursor clusterObject = clustersArray.addObject(); - clusterObject.setString("name", clusterView.name); - clusterObject.setString("type", clusterView.type); - setNullableString("url", rewriteIfUrl(clusterView.url, requestUri), clusterObject); - Cursor servicesArray = clusterObject.setArray("services"); - for (ServiceView serviceView : clusterView.services) { - Cursor serviceObject = servicesArray.addObject(); - setNullableString("url", rewriteIfUrl(serviceView.url, requestUri), serviceObject); - serviceObject.setString("serviceType", serviceView.serviceType); - serviceObject.setString("serviceName", serviceView.serviceName); - serviceObject.setString("configId", serviceView.configId); - serviceObject.setString("host", serviceView.host); - } - } - } - - public void setResponse(Map<?,?> responseData, String serviceName, Path restPath) { - this.serviceName = serviceName; - this.restPath = restPath; - mapToSlime(responseData, slime.setObject()); - } - - @Override - public void render(OutputStream stream) throws IOException { - new JsonFormat(true).encode(stream, slime); - } - - @Override - public String getContentType() { - return "application/json"; - } - - @SuppressWarnings("unchecked") - private void mapToSlime(Map<?,?> data, Cursor object) { - for (Map.Entry<String, Object> entry : ((Map<String, Object>)data).entrySet()) - fieldToSlime(entry.getKey(), entry.getValue(), object); - } - - private void fieldToSlime(String key, Object value, Cursor object) { - if (value instanceof String) { - if (key.equals("url") || key.equals("link")) - value = rewriteIfUrl((String)value, generateLocalLinkPrefix(serviceName, restPath)); - setNullableString(key, (String)value, object); - } - else if (value instanceof Integer) { - object.setLong(key, (int)value); - } - else if (value instanceof Long) { - object.setLong(key, (long)value); - } - else if (value instanceof Float) { - object.setDouble(key, (double)value); - } - else if (value instanceof Double) { - object.setDouble(key, (double)value); - } - else if (value instanceof List) { - listToSlime((List)value, object.setArray(key)); - } - else if (value instanceof Map) { - mapToSlime((Map<?,?>)value, object.setObject(key)); - } - } - - private void listToSlime(List<?> list, Cursor array) { - for (Object entry : list) - entryToSlime(entry, array); - } - - private void entryToSlime(Object entry, Cursor array) { - if (entry instanceof String) - addNullableString(rewriteIfUrl((String)entry, generateLocalLinkPrefix(serviceName, restPath)), array); - else if (entry instanceof Integer) - array.addLong((long)entry); - else if (entry instanceof Long) - array.addLong((long)entry); - else if (entry instanceof Float) - array.addDouble((double)entry); - else if (entry instanceof Double) - array.addDouble((double)entry); - else if (entry instanceof List) - listToSlime((List)entry, array.addArray()); - else if (entry instanceof Map) - mapToSlime((Map)entry, array.addObject()); - } - - private String rewriteIfUrl(String urlOrAnyString, HttpURL requestUri) { - if (urlOrAnyString == null) return null; - - String hostPattern = "(" + - String.join( - "|", configServerURIs.stream() - .map(URI::toString) - .map(s -> s.substring(0, s.length() -1)) - .map(Pattern::quote) - .toArray(String[]::new)) - + ")"; - - String remoteServicePath = "/serviceview/" - + "v1/tenant/" + application.tenant().value() - + "/application/" + application.application().value() - + "/environment/" + zone.environment().value() - + "/region/" + zone.region().value() - + "/instance/" + application.instance() - + "/service/"; - - Pattern remoteServiceResourcePattern = Pattern.compile("^(" + hostPattern + Pattern.quote(remoteServicePath) + ")"); - Matcher matcher = remoteServiceResourcePattern.matcher(urlOrAnyString); - - if (matcher.find()) { - String proxiedPath = urlOrAnyString.substring(matcher.group().length()); - return requestUri.withPath(requestUri.path().append(Path.parse(proxiedPath))).asURI().toString(); - } else { - return urlOrAnyString; // not a service url - } - } - - private HttpURL generateLocalLinkPrefix(String identifier, Path restPath) { - Path proxiedPath = Path.parse(identifier).append(restPath); - if (requestUri.path().tail(proxiedPath.length()).equals(proxiedPath)) { - return requestUri.withPath(requestUri.path().cut(proxiedPath.length())); - } else { - throw new IllegalStateException("Expected the resource " + requestUri.path() + " to end with " + proxiedPath); - } - } - - private void setNullableString(String key, String valueOrNull, Cursor receivingObject) { - if (valueOrNull == null) - receivingObject.setNix(key); - else - receivingObject.setString(key, valueOrNull); - } - - private void addNullableString(String valueOrNull, Cursor receivingArray) { - if (valueOrNull == null) - receivingArray.addNix(); - else - receivingArray.addString(valueOrNull); - } - -} diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ConfigServerMock.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ConfigServerMock.java index 9eb1a375e6f..6eb87a47779 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ConfigServerMock.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/integration/ConfigServerMock.java @@ -45,9 +45,6 @@ import com.yahoo.vespa.hosted.controller.api.integration.noderepository.RestartF import com.yahoo.vespa.hosted.controller.api.integration.secrets.TenantSecretStore; import com.yahoo.vespa.hosted.controller.application.SystemApplication; import com.yahoo.vespa.hosted.controller.application.pkg.ApplicationPackage; -import com.yahoo.vespa.serviceview.bindings.ApplicationView; -import com.yahoo.vespa.serviceview.bindings.ClusterView; -import com.yahoo.vespa.serviceview.bindings.ServiceView; import java.io.ByteArrayInputStream; import java.io.InputStream; @@ -486,32 +483,6 @@ public class ConfigServerMock extends AbstractComponent implements ConfigServer removeLoadBalancers(deployment.applicationId(), deployment.zoneId()); } - // Returns a canned example response - @Override - public ApplicationView getApplicationView(String tenantName, String applicationName, String instanceName, - String environment, String region) { - String cfgHostname = Text.format("https://cfg.%s.%s.test.vip:4443", environment, region); - String cfgServiceUrlPrefix = Text.format("%s/serviceview/v1/tenant/%s/application/%s/environment/%s/region/%s/instance/%s/service", - cfgHostname, tenantName, applicationName, - environment, region, instanceName); - ApplicationView applicationView = new ApplicationView(); - ClusterView cluster = new ClusterView(); - cluster.name = "cluster1"; - cluster.type = "content"; - cluster.url = cfgServiceUrlPrefix + "/container-clustercontroller-6s8slgtps7ry8uh6lx21ejjiv/cluster/v2/cluster1"; - ServiceView service = new ServiceView(); - service.configId = "cluster1/storage/0"; - service.host = "host1"; - service.serviceName = "storagenode"; - service.serviceType = "storagenode"; - service.url = cfgServiceUrlPrefix + "/storagenode-awe3slno6mmq2fye191y324jl/state/v1/"; - cluster.services = new ArrayList<>(); - cluster.services.add(service); - applicationView.clusters = new ArrayList<>(); - applicationView.clusters.add(cluster); - return applicationView; - } - @Override public List<ClusterMetrics> getDeploymentMetrics(DeploymentId deployment) { return Collections.unmodifiableList(clusterMetrics.getOrDefault(deployment, List.of())); @@ -522,18 +493,6 @@ public class ConfigServerMock extends AbstractComponent implements ConfigServer return this.protonMetrics; } - // Returns a canned example response - @Override - public Map<?,?> getServiceApiResponse(DeploymentId deployment, String serviceName, Path restPath) { - Map<String,List<?>> root = new HashMap<>(); - List<Map<?,?>> resources = new ArrayList<>(); - Map<String,String> resource = new HashMap<>(); - resource.put("url", "http://localhost:8080/application/v4/tenant/tenant1/application/application1/environment/prod/region/us-west-1/instance/default/service/filedistributorservice-dud1f4w037qdxdrn0ovxfdtgw/state/v1/config"); - resources.add(resource); - root.put("resources", resources); - return root; - } - @Override public ProxyResponse getServiceNodePage(DeploymentId deployment, String serviceName, DomainName node, Path subPath, Query query) { return new ProxyResponse((subPath + " and " + query).getBytes(StandardCharsets.UTF_8), "text/html", 200); diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java index a9164ddfa9e..483f9f26b19 100644 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java +++ b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ApplicationApiTest.java @@ -694,21 +694,6 @@ public class ApplicationApiTest extends ControllerContainerTest { .userIdentity(USER_ID), new File("suspended.json")); - // GET services - tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/environment/prod/region/us-central-1/instance/instance1/service", GET) - .userIdentity(USER_ID), - new File("services.json")); - - // GET service - tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/environment/prod/region/us-central-1/instance/instance1/service/storagenode-awe3slno6mmq2fye191y324jl/state/v1/", GET) - .userIdentity(USER_ID), - new File("service.json")); - - // GET service/state/v1 - tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/instance/instance1/environment/prod/region/us-central-1/service/storagenode/host.com/state/v1/?foo=bar", GET) - .userIdentity(USER_ID), - new File("service")); - // DELETE application with active deployments fails tester.assertResponse(request("/application/v4/tenant/tenant1/application/application1/instance/instance1", DELETE) .userIdentity(USER_ID) @@ -1640,32 +1625,6 @@ public class ApplicationApiTest extends ControllerContainerTest { } @Test - public void testServiceView() { - createAthenzDomainWithAdmin(ATHENZ_TENANT_DOMAIN, USER_ID); - String serviceApi="/application/v4/tenant/tenant1/application/application1/environment/prod/region/us-central-1/instance/instance1/service"; - // Not allowed to request apis not listed in feature flag allowed-service-view-apis. e.g /document/v1 - tester.assertResponse(request(serviceApi + "/storagenode-awe3slno6mmq2fye191y324jl/document/v1/", GET) - .userIdentity(USER_ID) - .oAuthCredentials(OKTA_CREDENTIALS), - "{\"error-code\":\"NOT_FOUND\",\"message\":\"Nothing at path '/application/v4/tenant/tenant1/application/application1/environment/prod/region/us-central-1/instance/instance1/service/storagenode-awe3slno6mmq2fye191y324jl/document/v1/'\"}", - 404); - - // Test path traversal - tester.assertResponse(request(serviceApi + "/storagenode-awe3slno6mmq2fye191y324jl/state/v1/../../document/v1/", GET) - .userIdentity(USER_ID) - .oAuthCredentials(OKTA_CREDENTIALS), - "{\"error-code\":\"NOT_FOUND\",\"message\":\"Nothing at path '/application/v4/tenant/tenant1/application/application1/environment/prod/region/us-central-1/instance/instance1/service/storagenode-awe3slno6mmq2fye191y324jl/document/v1/'\"}", - 404); - - // Test urlencoded path traversal - tester.assertResponse(request(serviceApi + "/storagenode-awe3slno6mmq2fye191y324jl/state%2Fv1%2F..%2F..%2Fdocument%2Fv1%2F", GET) - .userIdentity(USER_ID) - .oAuthCredentials(OKTA_CREDENTIALS), - accessDenied, - 403); - } - - @Test public void create_application_on_deploy() { // Setup createAthenzDomainWithAdmin(ATHENZ_TENANT_DOMAIN, USER_ID); diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ServiceApiResponseTest.java b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ServiceApiResponseTest.java deleted file mode 100644 index c69cd51e20d..00000000000 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/ServiceApiResponseTest.java +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -package com.yahoo.vespa.hosted.controller.restapi.application; - -import com.yahoo.config.provision.ApplicationId; -import com.yahoo.config.provision.Environment; -import com.yahoo.config.provision.RegionName; -import com.yahoo.config.provision.zone.ZoneId; -import com.yahoo.io.IOUtils; -import com.yahoo.slime.Slime; -import com.yahoo.slime.SlimeUtils; -import com.yahoo.vespa.serviceview.bindings.ApplicationView; -import com.yahoo.vespa.serviceview.bindings.ClusterView; -import com.yahoo.vespa.serviceview.bindings.ServiceView; -import org.junit.Test; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.IOException; -import java.net.URI; -import java.net.URISyntaxException; -import java.nio.charset.StandardCharsets; -import java.util.Collections; - -import static org.junit.Assert.assertEquals; - -/** - * @author bratseth - */ -public class ServiceApiResponseTest { - - private final static String responseFiles = "src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/"; - - @Test - public void testServiceViewResponse() throws URISyntaxException, IOException { - ServiceApiResponse response = new ServiceApiResponse(ZoneId.from(Environment.prod, RegionName.from("us-west-1")), - ApplicationId.from("tenant1", "application1", "default"), - Collections.singletonList(new URI("config-server1")), - new URI("http://server1:4080/request/path?foo=bar")); - ApplicationView applicationView = new ApplicationView(); - ClusterView clusterView = new ClusterView(); - clusterView.type = "container"; - clusterView.name = "cluster1"; - clusterView.url = "cluster-url"; - ServiceView serviceView = new ServiceView(); - serviceView.url = null; - serviceView.serviceType = "container"; - serviceView.serviceName = "service1"; - serviceView.configId = "configId1"; - serviceView.host = "host1"; - serviceView.legacyStatusPages = "legacyPages"; - clusterView.services = Collections.singletonList(serviceView); - applicationView.clusters = Collections.singletonList(clusterView); - response.setResponse(applicationView); - ByteArrayOutputStream stream = new ByteArrayOutputStream(); - response.render(stream); - Slime responseSlime = SlimeUtils.jsonToSlime(stream.toByteArray()); - Slime expectedSlime = SlimeUtils.jsonToSlime(IOUtils.readFile(new File(responseFiles + "service-api-response.json")).getBytes(StandardCharsets.UTF_8)); - - assertEquals("service-api-response.json", - new String(SlimeUtils.toJsonBytes(expectedSlime), StandardCharsets.UTF_8), - new String(SlimeUtils.toJsonBytes(responseSlime), StandardCharsets.UTF_8)); - } - - @Test - public void testServiceViewResponseWithURLs() throws URISyntaxException, IOException { - ServiceApiResponse response = new ServiceApiResponse(ZoneId.from(Environment.prod, RegionName.from("us-west-1")), - ApplicationId.from("tenant2", "application2", "default"), - Collections.singletonList(new URI("http://cfg1.test/")), - new URI("http://cfg1.test/serviceview/v1/tenant/tenant2/application/application2/environment/prod/region/us-west-1/instance/default/service/searchnode-9dujk1pa0vufxrj6n4yvmi8uc/state/v1")); - ApplicationView applicationView = new ApplicationView(); - ClusterView clusterView = new ClusterView(); - clusterView.type = "container"; - clusterView.name = "cluster1"; - clusterView.url = "http://cfg1.test/serviceview/v1/tenant/tenant2/application/application2/environment/prod/region/us-west-1/instance/default/service/searchnode-9dujk1pa0vufxrj6n4yvmi8uc/state/v1/health"; - ServiceView serviceView = new ServiceView(); - serviceView.url = null; - serviceView.serviceType = "container"; - serviceView.serviceName = "service1"; - serviceView.configId = "configId1"; - serviceView.host = "host1"; - serviceView.legacyStatusPages = "legacyPages"; - clusterView.services = Collections.singletonList(serviceView); - applicationView.clusters = Collections.singletonList(clusterView); - response.setResponse(applicationView); - ByteArrayOutputStream stream = new ByteArrayOutputStream(); - response.render(stream); - Slime responseSlime = SlimeUtils.jsonToSlime(stream.toByteArray()); - Slime expectedSlime = SlimeUtils.jsonToSlime(IOUtils.readFile(new File(responseFiles + "service-api-response-with-urls.json")).getBytes(StandardCharsets.UTF_8)); - - assertEquals("service-api-response.json", - new String(SlimeUtils.toJsonBytes(expectedSlime), StandardCharsets.UTF_8), - new String(SlimeUtils.toJsonBytes(responseSlime), StandardCharsets.UTF_8)); - } - -} diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/service-api-response-with-urls.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/service-api-response-with-urls.json deleted file mode 100644 index 0e610c4d4b2..00000000000 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/service-api-response-with-urls.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "clusters": [ - { - "name": "cluster1", - "type": "container", - "url": "http://cfg1.test/serviceview/v1/tenant/tenant2/application/application2/environment/prod/region/us-west-1/instance/default/service/searchnode-9dujk1pa0vufxrj6n4yvmi8uc/state/v1/searchnode-9dujk1pa0vufxrj6n4yvmi8uc/state/v1/health", - "services": [ - { - "url": null, - "serviceType": "container", - "serviceName": "service1", - "configId": "configId1", - "host": "host1" - } - ] - } - ] -} diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/service-api-response.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/service-api-response.json deleted file mode 100644 index 3380eb26911..00000000000 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/service-api-response.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "clusters": [ - { - "name": "cluster1", - "type": "container", - "url": "cluster-url", - "services": [ - { - "url": null, - "serviceType": "container", - "serviceName": "service1", - "configId": "configId1", - "host": "host1" - } - ] - } - ] -}
\ No newline at end of file diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/service.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/service.json deleted file mode 100644 index 81892fd547e..00000000000 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/service.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "resources": [ - { - "url": "http://localhost:8080/application/v4/tenant/tenant1/application/application1/environment/prod/region/us-west-1/instance/default/service/filedistributorservice-dud1f4w037qdxdrn0ovxfdtgw/state/v1/config" - } - ] -} diff --git a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/services.json b/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/services.json deleted file mode 100644 index 1a434afafbb..00000000000 --- a/controller-server/src/test/java/com/yahoo/vespa/hosted/controller/restapi/application/responses/services.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "clusters": [ - { - "name": "cluster1", - "type": "content", - "url": "http://localhost:8080/application/v4/tenant/tenant1/application/application1/environment/prod/region/us-central-1/instance/instance1/service/container-clustercontroller-6s8slgtps7ry8uh6lx21ejjiv/cluster/v2/cluster1", - "services": [ - { - "url": "http://localhost:8080/application/v4/tenant/tenant1/application/application1/environment/prod/region/us-central-1/instance/instance1/service/storagenode-awe3slno6mmq2fye191y324jl/state/v1/", - "serviceType": "storagenode", - "serviceName": "storagenode", - "configId": "cluster1/storage/0", - "host": "host1" - } - ] - } - ] -} @@ -117,7 +117,6 @@ <module>searchsummary</module> <module>security-tools</module> <module>security-utils</module> - <module>serviceview</module> <module>service-monitor</module> <module>socket_test</module> <module>standalone-container</module> diff --git a/serviceview/OWNERS b/serviceview/OWNERS deleted file mode 100644 index 338ed581212..00000000000 --- a/serviceview/OWNERS +++ /dev/null @@ -1 +0,0 @@ -hmusum diff --git a/serviceview/README.md b/serviceview/README.md deleted file mode 100644 index e74c32feab4..00000000000 --- a/serviceview/README.md +++ /dev/null @@ -1,2 +0,0 @@ -<!-- Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. --> -# REST API for getting a view of services and hosts for an application diff --git a/serviceview/pom.xml b/serviceview/pom.xml deleted file mode 100644 index fb124f49624..00000000000 --- a/serviceview/pom.xml +++ /dev/null @@ -1,44 +0,0 @@ -<?xml version="1.0"?> -<!-- Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. --> -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> - <modelVersion>4.0.0</modelVersion> - - <parent> - <groupId>com.yahoo.vespa</groupId> - <artifactId>parent</artifactId> - <version>7-SNAPSHOT</version> - <relativePath>../parent/pom.xml</relativePath> - </parent> - <artifactId>serviceview</artifactId> - <packaging>container-plugin</packaging> - <version>7-SNAPSHOT</version> - <name>serviceview</name> - <description>REST API that is shared between the Vespa Config Server and others.</description> - <dependencies> - <dependency> - <groupId>com.yahoo.vespa</groupId> - <artifactId>container-dev</artifactId> - <version>${project.version}</version> - <scope>provided</scope> - </dependency> - <dependency> - <groupId>junit</groupId> - <artifactId>junit</artifactId> - <scope>test</scope> - </dependency> - </dependencies> - <build> - <plugins> - <plugin> - <groupId>com.yahoo.vespa</groupId> - <artifactId>bundle-plugin</artifactId> - <extensions>true</extensions> - </plugin> - <plugin> - <!-- Explicit for IntelliJ to detect correct language level from parent --> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-compiler-plugin</artifactId> - </plugin> - </plugins> - </build> -</project> diff --git a/serviceview/src/main/java/com/yahoo/vespa/serviceview/bindings/ApplicationView.java b/serviceview/src/main/java/com/yahoo/vespa/serviceview/bindings/ApplicationView.java deleted file mode 100644 index 2b6c2a718c3..00000000000 --- a/serviceview/src/main/java/com/yahoo/vespa/serviceview/bindings/ApplicationView.java +++ /dev/null @@ -1,15 +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.bindings; - -import java.util.List; - -/** - * All clusters of a deployed application. - * - * @author Steinar Knutsen - */ -public class ApplicationView { - - public List<ClusterView> clusters; - -} diff --git a/serviceview/src/main/java/com/yahoo/vespa/serviceview/bindings/ClusterView.java b/serviceview/src/main/java/com/yahoo/vespa/serviceview/bindings/ClusterView.java deleted file mode 100644 index 47dbc5193be..00000000000 --- a/serviceview/src/main/java/com/yahoo/vespa/serviceview/bindings/ClusterView.java +++ /dev/null @@ -1,20 +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.bindings; - -import java.util.List; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonInclude.Include; - -/** - * The response binding for a complete cluster. - * - * @author Steinar Knutsen - */ -public class ClusterView { - public String name; - public String type; - @JsonInclude(value = Include.NON_NULL) - public String url; - public List<ServiceView> services; -} diff --git a/serviceview/src/main/java/com/yahoo/vespa/serviceview/bindings/ConfigClient.java b/serviceview/src/main/java/com/yahoo/vespa/serviceview/bindings/ConfigClient.java deleted file mode 100644 index f0dff70eece..00000000000 --- a/serviceview/src/main/java/com/yahoo/vespa/serviceview/bindings/ConfigClient.java +++ /dev/null @@ -1,25 +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.bindings; - -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; - -/** - * Client to fetch the model config from the configserver. - * - * @author Steinar Knutsen - */ -public interface ConfigClient { - - @GET - @Path("/config/v2/tenant/{tenantName}/application/{applicationName}/environment/{environmentName}/region/{regionName}/instance/{instanceName}/cloud.config.model") - @Produces(MediaType.APPLICATION_JSON) - ModelResponse getServiceModel(@PathParam("tenantName") String tenantName, - @PathParam("applicationName") String applicationName, - @PathParam("environmentName") String environmentName, - @PathParam("regionName") String regionName, - @PathParam("instanceName") String instanceName); -} diff --git a/serviceview/src/main/java/com/yahoo/vespa/serviceview/bindings/HealthClient.java b/serviceview/src/main/java/com/yahoo/vespa/serviceview/bindings/HealthClient.java deleted file mode 100644 index 41b7e10f511..00000000000 --- a/serviceview/src/main/java/com/yahoo/vespa/serviceview/bindings/HealthClient.java +++ /dev/null @@ -1,23 +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.bindings; - -import java.util.HashMap; - -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; - -/** - * Client to fetch the model config from the configserver. - * - * @author Steinar Knutsen - */ -public interface HealthClient { - - @SuppressWarnings("rawtypes") - @GET - @Path("") - @Produces(MediaType.APPLICATION_JSON) - public HashMap getHealthInfo(); -} diff --git a/serviceview/src/main/java/com/yahoo/vespa/serviceview/bindings/HostService.java b/serviceview/src/main/java/com/yahoo/vespa/serviceview/bindings/HostService.java deleted file mode 100644 index 97425235cef..00000000000 --- a/serviceview/src/main/java/com/yahoo/vespa/serviceview/bindings/HostService.java +++ /dev/null @@ -1,19 +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.bindings; - -import java.util.List; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -/** - * View of {@link com.yahoo.cloud.config.ModelConfig.Hosts}. - * - * @author mortent - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public class HostService { - - public String name; - public List<Service> services; - -} diff --git a/serviceview/src/main/java/com/yahoo/vespa/serviceview/bindings/ModelResponse.java b/serviceview/src/main/java/com/yahoo/vespa/serviceview/bindings/ModelResponse.java deleted file mode 100644 index 9ce331605ef..00000000000 --- a/serviceview/src/main/java/com/yahoo/vespa/serviceview/bindings/ModelResponse.java +++ /dev/null @@ -1,17 +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.bindings; - -import java.util.List; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -/** - * View of {@link com.yahoo.cloud.config.ModelConfig}. - * - * @author mortent - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public class ModelResponse { - public List<HostService> hosts; - public String vespaVersion; -} diff --git a/serviceview/src/main/java/com/yahoo/vespa/serviceview/bindings/Service.java b/serviceview/src/main/java/com/yahoo/vespa/serviceview/bindings/Service.java deleted file mode 100644 index 4f38f1275f0..00000000000 --- a/serviceview/src/main/java/com/yahoo/vespa/serviceview/bindings/Service.java +++ /dev/null @@ -1,23 +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.bindings; - -import java.util.List; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; - -/** - * View of {@link com.yahoo.cloud.config.ModelConfig.Hosts.Services}. - * - * @author mortent - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public class Service { - public String name; - public String type; - public String configid; - public String clustertype; - public String clustername; - public long index; - public List<ServicePort> ports; - -} diff --git a/serviceview/src/main/java/com/yahoo/vespa/serviceview/bindings/ServicePort.java b/serviceview/src/main/java/com/yahoo/vespa/serviceview/bindings/ServicePort.java deleted file mode 100644 index 29fa07b46e7..00000000000 --- a/serviceview/src/main/java/com/yahoo/vespa/serviceview/bindings/ServicePort.java +++ /dev/null @@ -1,41 +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.bindings; - -import java.util.List; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.google.common.base.Splitter; - -/** - * View of {@link com.yahoo.cloud.config.ModelConfig.Hosts.Services.Ports}. - * - * @author mortent - * @author Steinar Knutsen - */ -@JsonIgnoreProperties(value = { "splitOnSpace" }, ignoreUnknown = true) -public class ServicePort { - public int number; - public String tags; - private static final Splitter splitOnSpace = Splitter.on(' '); - - /** - * Return true if all argument tags are present for this port. - * - * @param tag - * one or more tag names to check for - * @return true if all argument tags are present for this port, false - * otherwise - */ - public boolean hasTags(String... tag) { - if (tags == null) { - return false; - } - List<String> isTaggedWith = splitOnSpace.splitToList(tags); - for (String t : tag) { - if (!isTaggedWith.contains(t)) { - return false; - } - } - return true; - } -} diff --git a/serviceview/src/main/java/com/yahoo/vespa/serviceview/bindings/ServiceView.java b/serviceview/src/main/java/com/yahoo/vespa/serviceview/bindings/ServiceView.java deleted file mode 100644 index e9fece65758..00000000000 --- a/serviceview/src/main/java/com/yahoo/vespa/serviceview/bindings/ServiceView.java +++ /dev/null @@ -1,20 +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.bindings; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonInclude.Include; - -/** - * The response wrapper for the link to a single service state API. - * - * @author Steinar Knutsen - */ -public class ServiceView { - public String url; - public String serviceType; - public String serviceName; - public String configId; - public String host; - @JsonInclude(value = Include.NON_NULL) - public String legacyStatusPages; -} diff --git a/serviceview/src/main/java/com/yahoo/vespa/serviceview/bindings/StateClient.java b/serviceview/src/main/java/com/yahoo/vespa/serviceview/bindings/StateClient.java deleted file mode 100644 index 66e518e23e5..00000000000 --- a/serviceview/src/main/java/com/yahoo/vespa/serviceview/bindings/StateClient.java +++ /dev/null @@ -1,41 +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.bindings; - -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; -import java.util.HashMap; - -/** - * @author Steinar Knutsen - */ -public interface StateClient { - - @GET - @Path("v1/") - @Produces(MediaType.APPLICATION_JSON) - ApplicationView getDefaultUserInfo(); - - @GET - @Path("v1/tenant/{tenantName}/application/{applicationName}/environment/{environmentName}/region/{regionName}/instance/{instanceName}") - @Produces(MediaType.APPLICATION_JSON) - ApplicationView getUserInfo(@PathParam("tenantName") String tenantName, - @PathParam("applicationName") String applicationName, - @PathParam("environmentName") String environmentName, - @PathParam("regionName") String regionName, - @PathParam("instanceName") String instanceName); - - @SuppressWarnings("rawtypes") - @GET - @Path("v1/tenant/{tenantName}/application/{applicationName}/environment/{environmentName}/region/{regionName}/instance/{instanceName}/service/{serviceIdentifier}/{apiParams: .*}") - @Produces(MediaType.APPLICATION_JSON) - HashMap singleService(@PathParam("tenantName") String tenantName, - @PathParam("applicationName") String applicationName, - @PathParam("environmentName") String environmentName, - @PathParam("regionName") String regionName, - @PathParam("instanceName") String instanceName, - @PathParam("serviceIdentifier") String identifier, - @PathParam("apiParams") String apiParams); -} diff --git a/serviceview/src/main/java/com/yahoo/vespa/serviceview/bindings/package-info.java b/serviceview/src/main/java/com/yahoo/vespa/serviceview/bindings/package-info.java deleted file mode 100644 index d73a9023b7f..00000000000 --- a/serviceview/src/main/java/com/yahoo/vespa/serviceview/bindings/package-info.java +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. -/** - * The API bindings for the serviceview and underlying state APIs. - * - * <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.bindings; - -import com.yahoo.osgi.annotation.ExportPackage; diff --git a/serviceview/src/test/java/com/yahoo/vespa/serviceview/bindings/ServicePortTest.java b/serviceview/src/test/java/com/yahoo/vespa/serviceview/bindings/ServicePortTest.java deleted file mode 100644 index 2e3d0315c4a..00000000000 --- a/serviceview/src/test/java/com/yahoo/vespa/serviceview/bindings/ServicePortTest.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.bindings; - -import static org.junit.Assert.*; - -import org.junit.Test; - -/** - * Functional test of tag checking. - * - * @author <a href="mailto:steinar@yahoo-inc.com">Steinar Knutsen</a> - */ -public class ServicePortTest { - - @Test - public final void testNullTags() { - ServicePort s = new ServicePort(); - s.tags = null; - assertFalse(s.hasTags("http")); - } - - @Test - public final void testEmptyTags() { - ServicePort s = new ServicePort(); - s.tags = ""; - assertFalse(s.hasTags("http")); - } - - @Test - public final void testSubsetInArgs() { - ServicePort s = new ServicePort(); - s.tags = "http state status"; - assertTrue(s.hasTags("http", "state")); - } - - @Test - public final void testSupersetInArgs() { - ServicePort s = new ServicePort(); - s.tags = "http"; - assertFalse(s.hasTags("http", "rpc")); - } - - @Test - public final void testIdenticalInArgs() { - ServicePort s = new ServicePort(); - s.tags = "http rpc"; - assertTrue(s.hasTags("http", "rpc")); - } - - @Test - public final void testDisjunctBetweenArgsAndTags() { - ServicePort s = new ServicePort(); - s.tags = "http state moo"; - assertFalse(s.hasTags("http", "state", "rpc")); - } - - @Test - public final void testTagNameStartsWithOther() { - ServicePort s = new ServicePort(); - s.tags = "http state moo"; - assertFalse(s.hasTags("htt")); - } - - @Test - public final void testTagNameEndsWithOther() { - ServicePort s = new ServicePort(); - s.tags = "http state moo"; - assertFalse(s.hasTags("tp")); - } - - @Test - public final void testTagNameIsSubstringofOther() { - ServicePort s = new ServicePort(); - s.tags = "http state moo"; - assertFalse(s.hasTags("tt")); - } - -} |