diff options
Diffstat (limited to 'controller-api')
6 files changed, 140 insertions, 29 deletions
diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/ConsoleUrls.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/ConsoleUrls.java new file mode 100644 index 00000000000..872cbd67780 --- /dev/null +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/ConsoleUrls.java @@ -0,0 +1,87 @@ +// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.hosted.controller.api.integration; + +import com.yahoo.config.provision.ApplicationId; +import com.yahoo.config.provision.ApplicationName; +import com.yahoo.config.provision.ClusterSpec; +import com.yahoo.config.provision.Environment; +import com.yahoo.config.provision.TenantName; +import com.yahoo.config.provision.zone.ZoneId; +import com.yahoo.vespa.hosted.controller.api.integration.deployment.RunId; + +import java.net.URI; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; + +/** + * Generates URLs to various views in the Console. Prefer to create new methods and return + * String instead of URI to make it easier to track which views are linked from where. + * + * @author freva + */ +public class ConsoleUrls { + private final String root; + public ConsoleUrls(URI root) { + this.root = root.toString().replaceFirst("/$", ""); // Remove trailing slash + } + + public String root() { + return root; + } + + public String tenantOverview(TenantName tenantName) { + return "%s/tenant/%s".formatted(root, tenantName.value()); + } + + /** Returns URL to notification settings view for the given tenant */ + public String tenantNotifications(TenantName tenantName) { + return "%s/tenant/%s/account/notifications".formatted(root, tenantName.value()); + } + + public String prodApplicationOverview(TenantName tenantName, ApplicationName applicationName) { + return "%s/tenant/%s/application/%s/prod/instance".formatted(root, tenantName.value(), applicationName.value()); + } + + public String instanceOverview(ApplicationId application, Environment environment) { + return "%s/tenant/%s/application/%s/%s/instance/%s".formatted(root, + application.tenant().value(), + application.application().value(), + environment.isManuallyDeployed() ? environment.value() : "prod", + application.instance().value()); + } + + public String clusterOverview(ApplicationId application, ZoneId zone, ClusterSpec.Id clusterId) { + return cluster(application, zone, clusterId, null); + } + + public String clusterReindexing(ApplicationId application, ZoneId zone, ClusterSpec.Id clusterId) { + return cluster(application, zone, clusterId, "reindexing"); + } + + public String deploymentRun(RunId id) { + return "%s/job/%s/run/%s".formatted( + instanceOverview(id.application(), id.type().environment()), id.type().jobName(), id.number()); + } + + /** Returns URL used to request support from the Vespa team. */ + public String support() { + return root + "/support"; + } + + /** Returns URL to verify an email address with the given verification code */ + public String verifyEmail(String verifyCode) { + return "%s/verify?%s".formatted(root, queryParam("code", verifyCode)); + } + + public String termsOfService() { return root + "/terms-of-service-trial.html"; } + + private String cluster(ApplicationId application, ZoneId zone, ClusterSpec.Id clusterId, String viewOrNull) { + return instanceOverview(application, zone.environment()) + '?' + + queryParam("%s.%s.%s".formatted(application.instance().value(), zone.environment().value(), zone.region().value()), + "clusters," + clusterId.value() + (viewOrNull == null ? "" : '=' + viewOrNull)); + } + + private static String queryParam(String key, String value) { + return URLEncoder.encode(key, StandardCharsets.UTF_8) + '=' + URLEncoder.encode(value, StandardCharsets.UTF_8); + } +} diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/ServiceRegistry.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/ServiceRegistry.java index 0eead322df5..e39a8cf38b7 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/ServiceRegistry.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/ServiceRegistry.java @@ -32,8 +32,8 @@ import com.yahoo.vespa.hosted.controller.api.integration.organization.OwnershipI import com.yahoo.vespa.hosted.controller.api.integration.organization.SystemMonitor; import com.yahoo.vespa.hosted.controller.api.integration.resource.CostReportConsumer; import com.yahoo.vespa.hosted.controller.api.integration.resource.ResourceDatabaseClient; -import com.yahoo.vespa.hosted.controller.api.integration.secrets.GcpSecretStore; import com.yahoo.vespa.hosted.controller.api.integration.secrets.EndpointSecretManager; +import com.yahoo.vespa.hosted.controller.api.integration.secrets.GcpSecretStore; import com.yahoo.vespa.hosted.controller.api.integration.secrets.TenantSecretService; import com.yahoo.vespa.hosted.controller.api.integration.user.RoleMaintainer; import com.yahoo.vespa.hosted.controller.api.integration.vcmr.ChangeRequestClient; @@ -90,6 +90,8 @@ public interface ServiceRegistry { ZoneRegistry zoneRegistry(); + ConsoleUrls consoleUrls(); + ResourceTagger resourceTagger(); EnclaveAccessService enclaveAccessService(); diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/organization/DeploymentFailureMails.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/organization/DeploymentFailureMails.java index ef08c3a9adc..72728966dbc 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/organization/DeploymentFailureMails.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/organization/DeploymentFailureMails.java @@ -1,9 +1,9 @@ // Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.hosted.controller.api.integration.organization; +import com.yahoo.vespa.hosted.controller.api.integration.ConsoleUrls; import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType; import com.yahoo.vespa.hosted.controller.api.integration.deployment.RunId; -import com.yahoo.vespa.hosted.controller.api.integration.zone.ZoneRegistry; import java.util.Collection; @@ -14,10 +14,10 @@ import java.util.Collection; */ public class DeploymentFailureMails { - private final ZoneRegistry registry; + private final ConsoleUrls consoleUrls; - public DeploymentFailureMails(ZoneRegistry registry) { - this.registry = registry; + public DeploymentFailureMails(ConsoleUrls consoleUrls) { + this.consoleUrls = consoleUrls; } public Mail nodeAllocationFailure(RunId id, Collection<String> recipients) { @@ -66,8 +66,8 @@ public class DeploymentFailureMails { jobToString(id.type()), id.application(), messageDetail, - registry.dashboardUrl(id), - registry.supportUrl())); + consoleUrls.deploymentRun(id), + consoleUrls.support())); } private String jobToString(JobType type) { diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/zone/ZoneRegistry.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/zone/ZoneRegistry.java index 747c6b72172..92c0a6b1fbb 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/zone/ZoneRegistry.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/api/integration/zone/ZoneRegistry.java @@ -1,8 +1,6 @@ // Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.vespa.hosted.controller.api.integration.zone; -import com.yahoo.config.provision.ApplicationId; -import com.yahoo.config.provision.ApplicationName; import com.yahoo.config.provision.AthenzDomain; import com.yahoo.config.provision.CloudAccount; import com.yahoo.config.provision.CloudName; @@ -18,7 +16,6 @@ import com.yahoo.config.provision.zone.ZoneFilter; import com.yahoo.config.provision.zone.ZoneId; import com.yahoo.vespa.athenz.api.AthenzIdentity; import com.yahoo.vespa.hosted.controller.api.identifiers.DeploymentId; -import com.yahoo.vespa.hosted.controller.api.integration.deployment.RunId; import java.net.URI; import java.time.Duration; @@ -97,24 +94,6 @@ public interface ZoneRegistry { /** Returns the routing method used by given zone */ RoutingMethod routingMethod(ZoneId zone); - /** Returns a URL where an informative dashboard can be found. */ - URI dashboardUrl(); - - /** Returns a URL which displays information about the given tenant. */ - URI dashboardUrl(TenantName id); - - /** Returns a URL which displays information about the given application. */ - URI dashboardUrl(TenantName tenantName, ApplicationName applicationName); - - /** Returns a URL which displays information about the given application instance. */ - URI dashboardUrl(ApplicationId id); - - /** Returns a URL which displays information about the given job run. */ - URI dashboardUrl(RunId id); - - /** Returns a URL used to request support from the Vespa team. */ - URI supportUrl(); - /** Returns a URL to the controller's api endpoint */ URI apiUrl(); diff --git a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/tenant/Email.java b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/tenant/Email.java index 995f1b1864f..c1c8a780df1 100644 --- a/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/tenant/Email.java +++ b/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/tenant/Email.java @@ -25,7 +25,7 @@ public class Email { } public static Email empty() { - return new Email("", true); + return new Email("", false); } public Email withEmailAddress(String emailAddress) { diff --git a/controller-api/src/test/java/com/yahoo/vespa/hosted/controller/api/integration/ConsoleUrlsTest.java b/controller-api/src/test/java/com/yahoo/vespa/hosted/controller/api/integration/ConsoleUrlsTest.java new file mode 100644 index 00000000000..62e79c3be50 --- /dev/null +++ b/controller-api/src/test/java/com/yahoo/vespa/hosted/controller/api/integration/ConsoleUrlsTest.java @@ -0,0 +1,43 @@ +// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.hosted.controller.api.integration; + +import com.yahoo.config.provision.ApplicationId; +import com.yahoo.config.provision.ClusterSpec; +import com.yahoo.config.provision.Environment; +import com.yahoo.config.provision.zone.ZoneId; +import com.yahoo.vespa.hosted.controller.api.integration.deployment.JobType; +import com.yahoo.vespa.hosted.controller.api.integration.deployment.RunId; +import org.junit.jupiter.api.Test; + +import java.net.URI; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +/** + * @author freva + */ +class ConsoleUrlsTest { + + private final ConsoleUrls urls = new ConsoleUrls(URI.create("https://console.tld/")); + + @Test + void urls() { + ApplicationId app = ApplicationId.from("t1", "a1", "i1"); + ZoneId prod = ZoneId.from("prod", "us-north-1"); + ZoneId dev = ZoneId.from("dev", "eu-west-2"); + ZoneId test = ZoneId.from("test", "ap-east-3"); + ClusterSpec.Id cluster = ClusterSpec.Id.from("c1"); + + assertEquals("https://console.tld", urls.root()); + assertEquals("https://console.tld/tenant/t1", urls.tenantOverview(app.tenant())); + assertEquals("https://console.tld/tenant/t1/account/notifications", urls.tenantNotifications(app.tenant())); + assertEquals("https://console.tld/tenant/t1/application/a1/prod/instance", urls.prodApplicationOverview(app.tenant(), app.application())); + assertEquals("https://console.tld/tenant/t1/application/a1/prod/instance/i1", urls.instanceOverview(app, Environment.test)); + assertEquals("https://console.tld/tenant/t1/application/a1/dev/instance/i1?i1.dev.eu-west-2=clusters%2Cc1", urls.clusterOverview(app, dev, cluster)); + assertEquals("https://console.tld/tenant/t1/application/a1/prod/instance/i1?i1.prod.us-north-1=clusters%2Cc1%3Dreindexing", urls.clusterReindexing(app, prod, cluster)); + assertEquals("https://console.tld/tenant/t1/application/a1/prod/instance/i1/job/production-us-north-1/run/1", urls.deploymentRun(new RunId(app, JobType.deploymentTo(prod), 1))); + assertEquals("https://console.tld/tenant/t1/application/a1/prod/instance/i1/job/system-test/run/1", urls.deploymentRun(new RunId(app, JobType.deploymentTo(test), 1))); + assertEquals("https://console.tld/tenant/t1/application/a1/dev/instance/i1/job/dev-eu-west-2/run/1", urls.deploymentRun(new RunId(app, JobType.deploymentTo(dev), 1))); + assertEquals("https://console.tld/verify?code=test123", urls.verifyEmail("test123")); + } +} |