diff options
author | Morten Tokle <mortent@verizonmedia.com> | 2020-06-10 14:28:15 +0200 |
---|---|---|
committer | Morten Tokle <mortent@verizonmedia.com> | 2020-06-15 12:34:46 +0200 |
commit | a19da10e4ab5997e3398754cdffc4e948f5ede60 (patch) | |
tree | 84e894cf0b3194ec6e8eff73c820e63610ccf16e /cloud-tenant-cd | |
parent | 5a5221dd531c1a927685a5d18f2fb9eb3e2a474c (diff) |
Rename tenant-cd-impl -> cloud-tenant-cd
Diffstat (limited to 'cloud-tenant-cd')
5 files changed, 225 insertions, 0 deletions
diff --git a/cloud-tenant-cd/pom.xml b/cloud-tenant-cd/pom.xml new file mode 100644 index 00000000000..1ba509d1a11 --- /dev/null +++ b/cloud-tenant-cd/pom.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Copyright Verizon Media. 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/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <artifactId>cloud-tenant-cd</artifactId> + <name>Vespa Cloud tenant CD implementation</name> + <description>Test library implementation for Vespa Cloud applications.</description> + <url>https://github.com/vespa-engine</url> + <packaging>jar</packaging> + + <parent> + <groupId>com.yahoo.vespa</groupId> + <artifactId>parent</artifactId> + <version>7-SNAPSHOT</version> + <relativePath>../parent</relativePath> + </parent> + + <dependencies> + <dependency> + <groupId>com.yahoo.vespa</groupId> + <artifactId>tenant-cd</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>com.yahoo.vespa</groupId> + <artifactId>security-utils</artifactId> + <version>${project.version}</version> + </dependency> + + <dependency> + <groupId>com.yahoo.vespa</groupId> + <artifactId>vespajlib</artifactId> + <version>${project.version}</version> + </dependency> + + <dependency> + <groupId>com.yahoo.vespa</groupId> + <artifactId>config-provisioning</artifactId> + <version>${project.version}</version> + </dependency> + + <dependency> + <groupId>com.yahoo.vespa</groupId> + <artifactId>tenant-auth</artifactId> + <version>${project.version}</version> + </dependency> + + <dependency> + <groupId>com.yahoo.vespa</groupId> + <artifactId>hosted-api</artifactId> + <version>${project.version}</version> + </dependency> + </dependencies> +</project>
\ No newline at end of file diff --git a/cloud-tenant-cd/src/main/java/ai/vespa/hosted/cd/VespaTestRuntime.java b/cloud-tenant-cd/src/main/java/ai/vespa/hosted/cd/VespaTestRuntime.java new file mode 100644 index 00000000000..f77716064e5 --- /dev/null +++ b/cloud-tenant-cd/src/main/java/ai/vespa/hosted/cd/VespaTestRuntime.java @@ -0,0 +1,62 @@ +// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package ai.vespa.hosted.cd; + +import ai.vespa.hosted.api.ControllerHttpClient; +import ai.vespa.hosted.api.Properties; +import ai.vespa.hosted.api.TestConfig; +import ai.vespa.hosted.cd.http.HttpDeployment; +import com.yahoo.config.provision.ApplicationId; +import com.yahoo.config.provision.Environment; +import com.yahoo.config.provision.zone.ZoneId; + +import java.nio.file.Files; +import java.nio.file.Paths; + +/** + * @author mortent + */ +public class VespaTestRuntime implements TestRuntime { + private final TestConfig config; + private final Deployment deploymentToTest; + + public VespaTestRuntime() { + String configPath = System.getProperty("vespa.test.config"); + TestConfig config = configPath != null ? fromFile(configPath) : fromController(); + this.config = config; + this.deploymentToTest = new HttpDeployment(config.deployments().get(config.zone()), new ai.vespa.hosted.auth.EndpointAuthenticator(config.system())); + } + +// In use ? +// /** Returns a copy of this runtime, with the given endpoint authenticator. */ +// public TestRuntime with(EndpointAuthenticator authenticator) { +// return new TestRuntime(config, authenticator); +// } + + /** Returns the full id of the application this is testing. */ + public ApplicationId application() { return config.application(); } + + /** Returns the zone of the deployment this is testing. */ + public ZoneId zone() { return config.zone(); } + + /** Returns the deployment this is testing. */ + @Override + public Deployment deploymentToTest() { return deploymentToTest; } + + private static TestConfig fromFile(String path) { + try { + return TestConfig.fromJson(Files.readAllBytes(Paths.get(path))); + } + catch (Exception e) { + throw new IllegalArgumentException("Failed reading config from '" + path + "'!", e); + } + } + + private static TestConfig fromController() { + ControllerHttpClient controller = new ai.vespa.hosted.auth.ApiAuthenticator().controller(); + ApplicationId id = Properties.application(); + Environment environment = Properties.environment().orElse(Environment.dev); + ZoneId zone = Properties.region().map(region -> ZoneId.from(environment, region)) + .orElseGet(() -> controller.defaultZone(environment)); + return controller.testConfig(id, zone); + } +} diff --git a/cloud-tenant-cd/src/main/java/ai/vespa/hosted/cd/http/HttpDeployment.java b/cloud-tenant-cd/src/main/java/ai/vespa/hosted/cd/http/HttpDeployment.java new file mode 100644 index 00000000000..80d5416ab34 --- /dev/null +++ b/cloud-tenant-cd/src/main/java/ai/vespa/hosted/cd/http/HttpDeployment.java @@ -0,0 +1,37 @@ +// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package ai.vespa.hosted.cd.http; + +import ai.vespa.hosted.api.EndpointAuthenticator; +import ai.vespa.hosted.cd.Deployment; +import ai.vespa.hosted.cd.Endpoint; + +import java.net.URI; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.stream.Collectors; + +/** + * A remote deployment of a Vespa application, reachable over HTTP. Contains {@link HttpEndpoint}s. + * + * @author jonmv + */ +public class HttpDeployment implements Deployment { + + private final Map<String, HttpEndpoint> endpoints; + + /** Creates a representation of the given deployment endpoints, using the authenticator for data plane access. */ + public HttpDeployment(Map<String, URI> endpoints, EndpointAuthenticator authenticator) { + this.endpoints = endpoints.entrySet().stream() + .collect(Collectors.toUnmodifiableMap(entry -> entry.getKey(), + entry -> new HttpEndpoint(entry.getValue(), authenticator))); + } + + @Override + public Endpoint endpoint(String id) { + if ( ! endpoints.containsKey(id)) + throw new NoSuchElementException("No cluster with id '" + id + "'"); + + return endpoints.get(id); + } + +} diff --git a/cloud-tenant-cd/src/main/java/ai/vespa/hosted/cd/http/HttpEndpoint.java b/cloud-tenant-cd/src/main/java/ai/vespa/hosted/cd/http/HttpEndpoint.java new file mode 100644 index 00000000000..a803fc3e0e2 --- /dev/null +++ b/cloud-tenant-cd/src/main/java/ai/vespa/hosted/cd/http/HttpEndpoint.java @@ -0,0 +1,68 @@ +// Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package ai.vespa.hosted.cd.http; + +import ai.vespa.hosted.api.EndpointAuthenticator; +import ai.vespa.hosted.cd.Endpoint; + +import javax.net.ssl.SSLParameters; +import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.time.Duration; +import java.util.Map; +import java.util.stream.Collectors; + +import static java.net.URLEncoder.encode; +import static java.nio.charset.StandardCharsets.UTF_8; +import static java.util.Objects.requireNonNull; + +/** + * A remote endpoint in a {@link HttpDeployment} of a Vespa application, reachable over HTTP. + * + * @author jonmv + */ +public class HttpEndpoint implements Endpoint { + + private final URI endpoint; + private final HttpClient client; + private final EndpointAuthenticator authenticator; + + public HttpEndpoint(URI endpoint, EndpointAuthenticator authenticator) { + this.endpoint = requireNonNull(endpoint); + this.authenticator = requireNonNull(authenticator); + SSLParameters sslParameters = new SSLParameters(); + sslParameters.setProtocols(new String[] {"TLSv1.2" }); + this.client = HttpClient.newBuilder() + .sslContext(authenticator.sslContext()) + .connectTimeout(Duration.ofSeconds(5)) + .version(HttpClient.Version.HTTP_1_1) + .sslParameters(sslParameters) + .build(); + } + + @Override + public URI uri() { + return endpoint; + } + + @Override + public <T> HttpResponse<T> send(HttpRequest.Builder request, HttpResponse.BodyHandler<T> handler) { + try { + return client.send(authenticator.authenticated(request).build(), handler); + } + catch (IOException | InterruptedException e) { + throw new RuntimeException(request.build() + " failed: " + e.getMessage(), e); + } + } + + @Override + public HttpRequest.Builder request(String path, Map<String, String> properties) { + return HttpRequest.newBuilder(endpoint.resolve(path + + properties.entrySet().stream() + .map(entry -> encode(entry.getKey(), UTF_8) + "=" + encode(entry.getValue(), UTF_8)) + .collect(Collectors.joining("&", path.contains("?") ? "&" : "?", "")))); + } + +} diff --git a/cloud-tenant-cd/src/main/resources/META-INF/services/ai.vespa.hosted.cd.TestRuntime b/cloud-tenant-cd/src/main/resources/META-INF/services/ai.vespa.hosted.cd.TestRuntime new file mode 100644 index 00000000000..695fe363e4e --- /dev/null +++ b/cloud-tenant-cd/src/main/resources/META-INF/services/ai.vespa.hosted.cd.TestRuntime @@ -0,0 +1,2 @@ +# Copyright Verizon Media. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +ai.vespa.hosted.cd.VespaTestRuntime
\ No newline at end of file |