From 73d0fe6d694d87912798d9278f49575ca7e4ac07 Mon Sep 17 00:00:00 2001 From: Valerij Fredriksen Date: Mon, 23 Oct 2023 12:01:00 +0200 Subject: Use ConsoleUrls instead of ZoneRegistry --- .../yahoo/vespa/hosted/controller/Controller.java | 4 +- .../controller/application/MailVerifier.java | 6 +- .../controller/deployment/InternalStepRunner.java | 3 +- .../controller/maintenance/CloudTrialExpirer.java | 2 +- .../notification/FormattedNotification.java | 3 +- .../controller/notification/MailTemplating.java | 32 ++------ .../notification/NotificationFormatter.java | 86 +++++----------------- .../hosted/controller/notification/Notifier.java | 47 +++++------- 8 files changed, 54 insertions(+), 129 deletions(-) (limited to 'controller-server/src/main/java') 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 bab86e7bfde..0b693bb9894 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 @@ -131,10 +131,10 @@ public class Controller extends AbstractComponent { auditLogger = new AuditLogger(curator, clock); jobControl = new JobControl(new JobControlFlags(curator, flagSource)); archiveBucketDb = new CuratorArchiveBucketDb(this); - notifier = new Notifier(curator, serviceRegistry.zoneRegistry(), serviceRegistry.mailer(), flagSource); + notifier = new Notifier(curator, serviceRegistry.consoleUrls(), serviceRegistry.mailer(), flagSource); notificationsDb = new NotificationsDb(this); supportAccessControl = new SupportAccessControl(this); - mailVerifier = new MailVerifier(serviceRegistry.zoneRegistry(), tenantController, serviceRegistry.mailer(), curator, clock); + mailVerifier = new MailVerifier(serviceRegistry.consoleUrls(), tenantController, serviceRegistry.mailer(), curator, clock); dataplaneTokenService = new DataplaneTokenService(this); // Record the version of this controller diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/MailVerifier.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/MailVerifier.java index 7d8f0d260fc..9ff3206ee06 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/MailVerifier.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/MailVerifier.java @@ -4,9 +4,9 @@ package com.yahoo.vespa.hosted.controller.application; import com.yahoo.config.provision.TenantName; import com.yahoo.vespa.hosted.controller.LockedTenant; import com.yahoo.vespa.hosted.controller.TenantController; +import com.yahoo.vespa.hosted.controller.api.integration.ConsoleUrls; import com.yahoo.vespa.hosted.controller.api.integration.organization.Mail; import com.yahoo.vespa.hosted.controller.api.integration.organization.Mailer; -import com.yahoo.vespa.hosted.controller.api.integration.zone.ZoneRegistry; import com.yahoo.vespa.hosted.controller.notification.MailTemplating; import com.yahoo.vespa.hosted.controller.persistence.CuratorDb; import com.yahoo.vespa.hosted.controller.tenant.CloudTenant; @@ -35,12 +35,12 @@ public class MailVerifier { private final Clock clock; private final MailTemplating mailTemplating; - public MailVerifier(ZoneRegistry zoneRegistry, TenantController tenantController, Mailer mailer, CuratorDb curatorDb, Clock clock) { + public MailVerifier(ConsoleUrls consoleUrls, TenantController tenantController, Mailer mailer, CuratorDb curatorDb, Clock clock) { this.tenantController = tenantController; this.mailer = mailer; this.curatorDb = curatorDb; this.clock = clock; - this.mailTemplating = new MailTemplating(zoneRegistry); + this.mailTemplating = new MailTemplating(consoleUrls); } public PendingMailVerification sendMailVerification(TenantName tenantName, String email, PendingMailVerification.MailType mailType) { diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunner.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunner.java index c9719c3dd55..d62e477a51f 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunner.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunner.java @@ -86,7 +86,6 @@ import static com.yahoo.vespa.hosted.controller.deployment.RunStatus.running; import static com.yahoo.vespa.hosted.controller.deployment.RunStatus.success; import static com.yahoo.vespa.hosted.controller.deployment.RunStatus.testFailure; import static com.yahoo.vespa.hosted.controller.deployment.Step.Status.succeeded; -import static com.yahoo.vespa.hosted.controller.deployment.Step.Status.unfinished; import static com.yahoo.vespa.hosted.controller.deployment.Step.copyVespaLogs; import static com.yahoo.vespa.hosted.controller.deployment.Step.deactivateReal; import static com.yahoo.vespa.hosted.controller.deployment.Step.deactivateTester; @@ -128,7 +127,7 @@ public class InternalStepRunner implements StepRunner { public InternalStepRunner(Controller controller) { this.controller = controller; this.testConfigSerializer = new TestConfigSerializer(controller.system()); - this.mails = new DeploymentFailureMails(controller.zoneRegistry()); + this.mails = new DeploymentFailureMails(controller.serviceRegistry().consoleUrls()); this.timeouts = Timeouts.of(controller.system()); } diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/CloudTrialExpirer.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/CloudTrialExpirer.java index d0426416349..9121c139b00 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/CloudTrialExpirer.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/CloudTrialExpirer.java @@ -166,7 +166,7 @@ public class CloudTrialExpirer extends ControllerMaintainer { .with("mailMessageTemplate", "cloud-trial-notification") .with("cloudTrialMessage", emailMsg) .with("mailTitle", emailSubject) - .with("consoleLink", controller().zoneRegistry().dashboardUrl(tenant.name()).toString()) + .with("consoleLink", controller().serviceRegistry().consoleUrls().tenantOverview(tenant.name())) .build()); var source = NotificationSource.from(tenant.name()); // Remove previous notification to ensure new notification is sent by email diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/notification/FormattedNotification.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/notification/FormattedNotification.java index 9402092f789..bed053d592f 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/notification/FormattedNotification.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/notification/FormattedNotification.java @@ -1,7 +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.notification; -import java.net.URI; import java.util.Objects; /** @@ -10,7 +9,7 @@ import java.util.Objects; * * @author enygaard */ -public record FormattedNotification(Notification notification, String prettyType, String messagePrefix, URI uri) { +public record FormattedNotification(Notification notification, String prettyType, String messagePrefix, String uri) { public FormattedNotification { Objects.requireNonNull(prettyType); diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/notification/MailTemplating.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/notification/MailTemplating.java index e8fb7289f4c..1c05330702e 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/notification/MailTemplating.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/notification/MailTemplating.java @@ -1,10 +1,8 @@ // Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. - package com.yahoo.vespa.hosted.controller.notification; import com.yahoo.config.provision.TenantName; -import com.yahoo.restapi.UriBuilder; -import com.yahoo.vespa.hosted.controller.api.integration.zone.ZoneRegistry; +import com.yahoo.vespa.hosted.controller.api.integration.ConsoleUrls; import com.yahoo.vespa.hosted.controller.tenant.PendingMailVerification; import com.yahoo.yolean.Exceptions; import org.apache.velocity.VelocityContext; @@ -15,7 +13,6 @@ import org.apache.velocity.runtime.resource.util.StringResourceRepository; import org.apache.velocity.tools.generic.EscapeTool; import java.io.StringWriter; -import java.net.URI; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.Map; @@ -43,19 +40,19 @@ public class MailTemplating { private final VelocityEngine velocity; private final EscapeTool escapeTool = new EscapeTool(); - private final URI dashboardUri; + private final ConsoleUrls consoleUrls; - public MailTemplating(ZoneRegistry zoneRegistry) { + public MailTemplating(ConsoleUrls consoleUrls) { this.velocity = createTemplateEngine(); - this.dashboardUri = zoneRegistry.dashboardUrl(); + this.consoleUrls = consoleUrls; } public String generateDefaultMailHtml(Template mailBodyTemplate, Map params, TenantName tenant) { var ctx = createVelocityContext(); - ctx.put("accountNotificationLink", accountNotificationsUri(tenant)); + ctx.put("accountNotificationLink", consoleUrls.tenantNotifications(tenant)); ctx.put("privacyPolicyLink", "https://legal.yahoo.com/xw/en/yahoo/privacy/topic/b2bprivacypolicy/index.html"); - ctx.put("termsOfServiceLink", consoleUri("terms-of-service-trial.html")); - ctx.put("supportLink", consoleUri("support")); + ctx.put("termsOfServiceLink", consoleUrls.termsOfService()); + ctx.put("supportLink", consoleUrls.support()); ctx.put("mailBodyTemplate", mailBodyTemplate.getId()); params.forEach(ctx::put); return render(ctx, Template.MAIL); @@ -63,9 +60,8 @@ public class MailTemplating { public String generateMailVerificationHtml(PendingMailVerification pmf) { var ctx = createVelocityContext(); - ctx.put("consoleLink", dashboardUri.getHost()); + ctx.put("verifyLink", consoleUrls.verifyEmail(pmf.getVerificationCode())); ctx.put("email", pmf.getMailAddress()); - ctx.put("code", pmf.getVerificationCode()); return render(ctx, Template.MAIL_VERIFICATION); } @@ -102,16 +98,4 @@ public class MailTemplating { }); repo.putStringResource(name, templateStr); } - - private String accountNotificationsUri(TenantName tenant) { - return new UriBuilder(dashboardUri) - .append("tenant/") - .append(tenant.value()) - .append("account/notifications") - .toString(); - } - - private String consoleUri(String path) { - return new UriBuilder(dashboardUri).append(path).toString(); - } } diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/notification/NotificationFormatter.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/notification/NotificationFormatter.java index de99d03cc82..243e1af8f35 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/notification/NotificationFormatter.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/notification/NotificationFormatter.java @@ -2,17 +2,13 @@ package com.yahoo.vespa.hosted.controller.notification; import com.yahoo.config.provision.ApplicationId; -import com.yahoo.config.provision.Environment; import com.yahoo.text.Text; -import com.yahoo.vespa.hosted.controller.api.integration.deployment.RunId; -import com.yahoo.vespa.hosted.controller.api.integration.zone.ZoneRegistry; -import org.apache.http.client.utils.URIBuilder; +import com.yahoo.vespa.hosted.controller.api.integration.ConsoleUrls; -import java.net.URI; -import java.net.URISyntaxException; import java.util.Objects; import java.util.Optional; -import java.util.function.Function; + +import static com.yahoo.vespa.hosted.controller.notification.Notifier.notificationLink; /** * Created a NotificationContent for a given Notification. @@ -22,10 +18,10 @@ import java.util.function.Function; * @author enygaard */ public class NotificationFormatter { - private final ZoneRegistry zoneRegistry; + private final ConsoleUrls consoleUrls; - public NotificationFormatter(ZoneRegistry zoneRegistry) { - this.zoneRegistry = Objects.requireNonNull(zoneRegistry); + public NotificationFormatter(ConsoleUrls consoleUrls) { + this.consoleUrls = Objects.requireNonNull(consoleUrls); } public FormattedNotification format(Notification n) { @@ -35,7 +31,7 @@ public class NotificationFormatter { case testPackage -> testPackage(n); case reindex -> reindex(n); case feedBlock -> feedBlock(n); - default -> new FormattedNotification(n, n.type().name(), "", zoneRegistry.dashboardUrl(n.source().tenant())); + default -> new FormattedNotification(n, n.type().name(), "", consoleUrls.tenantOverview(n.source().tenant())); }; } @@ -47,8 +43,7 @@ public class NotificationFormatter { application, instance, levelText(n.level(), n.messages().size())); - var uri = zoneRegistry.dashboardUrl(ApplicationId.from(source.tenant(), application, instance)); - return new FormattedNotification(n, "Application package", message, uri); + return new FormattedNotification(n, "Application package", message, notificationLink(consoleUrls, n.source())); } private FormattedNotification deployment(Notification n) { @@ -58,7 +53,7 @@ public class NotificationFormatter { requirePresent(source.application(), "application"), requirePresent(source.instance(), "instance"), levelText(n.level(), n.messages().size())); - return new FormattedNotification(n,"Deployment", message, jobLink(n.source())); + return new FormattedNotification(n,"Deployment", message, notificationLink(consoleUrls, n.source())); } private FormattedNotification testPackage(Notification n) { @@ -68,68 +63,23 @@ public class NotificationFormatter { n.messages().size() > 1 ? "are problems" : "is a problem", application, source.instance().map(i -> "."+i).orElse("")); - var uri = zoneRegistry.dashboardUrl(source.tenant(), application); - return new FormattedNotification(n, "Test package", message, uri); + return new FormattedNotification(n, "Test package", message, notificationLink(consoleUrls, n.source())); } private FormattedNotification reindex(Notification n) { var message = Text.format("%s is reindexing", clusterInfo(n.source())); - var source = n.source(); - var application = requirePresent(source.application(), "application"); - var instance = requirePresent(source.instance(), "instance"); - var clusterId = requirePresent(source.clusterId(), "clusterId"); - var zone = requirePresent(source.zoneId(), "zoneId"); - var instanceURI = zoneRegistry.dashboardUrl(ApplicationId.from(source.tenant(), application, instance)); - try { - var uri = new URIBuilder(instanceURI) - .setParameter( - String.format("%s.%s.%s", instance, zone.environment(), zone.region()), - String.format("clusters,%s=status", clusterId.value())) - .build(); - return new FormattedNotification(n, "Reindex", message, uri); - } catch (URISyntaxException e) { - throw new IllegalArgumentException(e); - } + var application = requirePresent(n.source().application(), "application"); + var instance = requirePresent(n.source().instance(), "instance"); + var clusterId = requirePresent(n.source().clusterId(), "clusterId"); + var zone = requirePresent(n.source().zoneId(), "zoneId"); + return new FormattedNotification(n, "Reindex", message, + consoleUrls.clusterReindexing(ApplicationId.from(n.source().tenant(), application, instance), zone, clusterId)); } private FormattedNotification feedBlock(Notification n) { - String type; - if (n.level() == Notification.Level.warning) { - type = "Nearly feed blocked"; - } else { - type = "Feed blocked"; - } + String type = n.level() == Notification.Level.warning ? "Nearly feed blocked" : "Feed blocked"; var message = Text.format("%s is %s", clusterInfo(n.source()), type.toLowerCase()); - var source = n.source(); - var application = requirePresent(source.application(), "application"); - var instance = requirePresent(source.instance(), "instance"); - var clusterId = requirePresent(source.clusterId(), "clusterId"); - var zone = requirePresent(source.zoneId(), "zoneId"); - var instanceURI = zoneRegistry.dashboardUrl(ApplicationId.from(source.tenant(), application, instance)); - try { - var uri = new URIBuilder(instanceURI) - .setParameter( - String.format("%s.%s.%s", instance, zone.environment(), zone.region()), - String.format("clusters,%s", clusterId.value())) - .build(); - return new FormattedNotification(n, type, message, uri); - } catch (URISyntaxException e) { - throw new IllegalArgumentException(e); - } - } - - private URI jobLink(NotificationSource source) { - var application = requirePresent(source.application(), "application"); - var instance = requirePresent(source.instance(), "instance"); - var jobType = requirePresent(source.jobType(), "jobType"); - var runNumber = source.runNumber().orElseThrow(() -> new MissingOptionalException("runNumber")); - var applicationId = ApplicationId.from(source.tenant(), application, instance); - Function link = (Environment env) -> zoneRegistry.dashboardUrl(new RunId(applicationId, jobType, runNumber)); - var environment = jobType.zone().environment(); - return switch (environment) { - case dev, perf -> link.apply(environment); - default -> link.apply(Environment.prod); - }; + return new FormattedNotification(n, type, message, notificationLink(consoleUrls, n.source())); } private String jobText(NotificationSource source) { diff --git a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/notification/Notifier.java b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/notification/Notifier.java index e3bfb8b4c56..b0b43866fae 100644 --- a/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/notification/Notifier.java +++ b/controller-server/src/main/java/com/yahoo/vespa/hosted/controller/notification/Notifier.java @@ -2,21 +2,22 @@ package com.yahoo.vespa.hosted.controller.notification; import com.google.common.annotations.VisibleForTesting; +import com.yahoo.config.provision.ApplicationId; import com.yahoo.config.provision.Environment; -import com.yahoo.restapi.UriBuilder; +import com.yahoo.config.provision.zone.ZoneId; import com.yahoo.text.Text; import com.yahoo.vespa.flags.FetchVector; import com.yahoo.vespa.flags.FlagSource; import com.yahoo.vespa.flags.PermanentFlags; +import com.yahoo.vespa.hosted.controller.api.integration.ConsoleUrls; +import com.yahoo.vespa.hosted.controller.api.integration.deployment.RunId; import com.yahoo.vespa.hosted.controller.api.integration.organization.Mail; import com.yahoo.vespa.hosted.controller.api.integration.organization.Mailer; import com.yahoo.vespa.hosted.controller.api.integration.organization.MailerException; -import com.yahoo.vespa.hosted.controller.api.integration.zone.ZoneRegistry; import com.yahoo.vespa.hosted.controller.persistence.CuratorDb; import com.yahoo.vespa.hosted.controller.tenant.CloudTenant; import com.yahoo.vespa.hosted.controller.tenant.TenantContacts; -import java.net.URI; import java.util.Collection; import java.util.List; import java.util.Objects; @@ -34,8 +35,8 @@ public class Notifier { private final CuratorDb curatorDb; private final Mailer mailer; private final FlagSource flagSource; + private final ConsoleUrls consoleUrls; private final NotificationFormatter formatter; - private final URI dashboardUri; private final MailTemplating mailTemplating; private static final Logger log = Logger.getLogger(Notifier.class.getName()); @@ -43,13 +44,13 @@ public class Notifier { // Minimal url pattern matcher to detect hardcoded URLs in Notification messages private static final Pattern urlPattern = Pattern.compile("https://[\\w\\d./]+"); - public Notifier(CuratorDb curatorDb, ZoneRegistry zoneRegistry, Mailer mailer, FlagSource flagSource) { + public Notifier(CuratorDb curatorDb, ConsoleUrls consoleUrls, Mailer mailer, FlagSource flagSource) { this.curatorDb = Objects.requireNonNull(curatorDb); this.mailer = Objects.requireNonNull(mailer); this.flagSource = Objects.requireNonNull(flagSource); - this.formatter = new NotificationFormatter(zoneRegistry); - this.dashboardUri = zoneRegistry.dashboardUrl(); - this.mailTemplating = new MailTemplating(zoneRegistry); + this.consoleUrls = Objects.requireNonNull(consoleUrls); + this.formatter = new NotificationFormatter(consoleUrls); + this.mailTemplating = new MailTemplating(consoleUrls); } public void dispatch(List notifications, NotificationSource source) { @@ -133,7 +134,7 @@ public class Notifier { .with("mailTitle", "Vespa Cloud Notifications") .with("notificationHeader", f.messagePrefix()) .with("notificationItems", items) - .with("consoleLink", notificationLink(f.notification().source())) + .with("consoleLink", notificationLink(consoleUrls, f.notification().source())) .build(); } @@ -150,24 +151,16 @@ public class Notifier { return sb.toString(); } - private String notificationLink(NotificationSource source) { - var uri = new UriBuilder(dashboardUri); - uri = uri.append("tenant").append(source.tenant().value()); - if (source.application().isPresent()) - uri = uri.append("application").append(source.application().get().value()); - if (source.isProduction()) { - uri = uri.append("prod/instance"); - if (source.jobType().isPresent()) { - uri = uri.append(source.instance().get().value()); - } - } - else { - uri = uri.append("dev/instance/").append(source.instance().get().value()); - } - if (source.jobType().isPresent()) { - uri = uri.append("job").append(source.jobType().get().jobName()).append("run").append(String.valueOf(source.runNumber().getAsLong())); - } - return uri.toString(); + static String notificationLink(ConsoleUrls consoleUrls, NotificationSource source) { + if (source.application().isEmpty()) return consoleUrls.tenantOverview(source.tenant()); + if (source.instance().isEmpty()) return consoleUrls.prodApplicationOverview(source.tenant(), source.application().get()); + + ApplicationId application = ApplicationId.from(source.tenant(), source.application().get(), source.instance().get()); + if (source.jobType().isPresent()) + return consoleUrls.deploymentRun(new RunId(application, source.jobType().get(), source.runNumber().getAsLong())); + if (source.clusterId().isPresent()) + return consoleUrls.clusterOverview(application, source.zoneId().get(), source.clusterId().get()); + return consoleUrls.instanceOverview(application, source.zoneId().map(ZoneId::environment).orElse(Environment.prod)); } private static String capitalise(String m) { -- cgit v1.2.3