aboutsummaryrefslogtreecommitdiffstats
path: root/controller-server/src/main/java
diff options
context:
space:
mode:
authorValerij Fredriksen <valerijf@yahooinc.com>2023-10-23 12:01:00 +0200
committerValerij Fredriksen <valerijf@yahooinc.com>2023-10-23 12:01:00 +0200
commit73d0fe6d694d87912798d9278f49575ca7e4ac07 (patch)
treee91a467e8c29e95a9cc10093a11e8f59e53eaa43 /controller-server/src/main/java
parentdeeaaa25850bf36c9c73840290c8686a40843756 (diff)
Use ConsoleUrls instead of ZoneRegistry
Diffstat (limited to 'controller-server/src/main/java')
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/Controller.java4
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/application/MailVerifier.java6
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/deployment/InternalStepRunner.java3
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/maintenance/CloudTrialExpirer.java2
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/notification/FormattedNotification.java3
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/notification/MailTemplating.java32
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/notification/NotificationFormatter.java86
-rw-r--r--controller-server/src/main/java/com/yahoo/vespa/hosted/controller/notification/Notifier.java47
8 files changed, 54 insertions, 129 deletions
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<String, Object> 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<Environment, URI> 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<Notification> 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) {