aboutsummaryrefslogtreecommitdiffstats
path: root/service-monitor
diff options
context:
space:
mode:
authorHåkon Hallingstad <hakon@verizonmedia.com>2020-02-28 17:49:28 +0100
committerHåkon Hallingstad <hakon@verizonmedia.com>2020-02-28 17:49:28 +0100
commite4a06ace71acac5aa1e18176f7253649883fbaed (patch)
treeea3ba924e2b50f7248f0b14d7f75779fb9abfe1b /service-monitor
parentd38df0da567e9f57082214961bc653a9e5a7c336 (diff)
Moved to more specific methods on ServiceMonitor
Diffstat (limited to 'service-monitor')
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/duper/DuperModel.java5
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/duper/DuperModelManager.java6
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/model/ApplicationInstanceGenerator.java126
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/model/ModelGenerator.java54
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/model/ServiceModelCache.java13
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/model/ServiceModelProvider.java64
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/model/ServiceMonitorImpl.java49
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/monitor/ServiceMonitor.java41
-rw-r--r--service-monitor/src/test/java/com/yahoo/vespa/service/model/ModelGeneratorTest.java5
-rw-r--r--service-monitor/src/test/java/com/yahoo/vespa/service/model/ServiceModelCacheTest.java20
-rw-r--r--service-monitor/src/test/java/com/yahoo/vespa/service/model/ServiceModelProviderTest.java4
11 files changed, 308 insertions, 79 deletions
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/duper/DuperModel.java b/service-monitor/src/main/java/com/yahoo/vespa/service/duper/DuperModel.java
index 1cfb70560b8..aa0b9e81c44 100644
--- a/service-monitor/src/main/java/com/yahoo/vespa/service/duper/DuperModel.java
+++ b/service-monitor/src/main/java/com/yahoo/vespa/service/duper/DuperModel.java
@@ -9,6 +9,7 @@ import com.yahoo.vespa.service.monitor.DuperModelListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.TreeMap;
import java.util.logging.Logger;
@@ -49,6 +50,10 @@ public class DuperModel {
}
}
+ public Optional<ApplicationInfo> getApplicationInfo(ApplicationId applicationId) {
+ return Optional.ofNullable(applications.get(applicationId));
+ }
+
public List<ApplicationInfo> getApplicationInfos() {
logger.log(LogLevel.DEBUG, "Applications in duper model: " + applications.values().size());
return List.copyOf(applications.values());
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/duper/DuperModelManager.java b/service-monitor/src/main/java/com/yahoo/vespa/service/duper/DuperModelManager.java
index 15c461c7f59..9c819d89fb2 100644
--- a/service-monitor/src/main/java/com/yahoo/vespa/service/duper/DuperModelManager.java
+++ b/service-monitor/src/main/java/com/yahoo/vespa/service/duper/DuperModelManager.java
@@ -173,6 +173,12 @@ public class DuperModelManager implements DuperModelProvider, DuperModelInfraApi
}
}
+ public Optional<ApplicationInfo> getApplicationInfo(ApplicationId applicationId) {
+ synchronized (monitor) {
+ return duperModel.getApplicationInfo(applicationId);
+ }
+ }
+
public List<ApplicationInfo> getApplicationInfos() {
synchronized (monitor) {
return duperModel.getApplicationInfos();
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/model/ApplicationInstanceGenerator.java b/service-monitor/src/main/java/com/yahoo/vespa/service/model/ApplicationInstanceGenerator.java
index 5cc2d538c24..db15c2789d5 100644
--- a/service-monitor/src/main/java/com/yahoo/vespa/service/model/ApplicationInstanceGenerator.java
+++ b/service-monitor/src/main/java/com/yahoo/vespa/service/model/ApplicationInstanceGenerator.java
@@ -5,9 +5,13 @@ import com.yahoo.config.model.api.ApplicationInfo;
import com.yahoo.config.model.api.HostInfo;
import com.yahoo.config.model.api.ServiceInfo;
import com.yahoo.config.provision.ApplicationId;
+import com.yahoo.config.provision.ApplicationName;
+import com.yahoo.config.provision.InstanceName;
+import com.yahoo.config.provision.TenantName;
import com.yahoo.config.provision.Zone;
import com.yahoo.vespa.applicationmodel.ApplicationInstance;
import com.yahoo.vespa.applicationmodel.ApplicationInstanceId;
+import com.yahoo.vespa.applicationmodel.ApplicationInstanceReference;
import com.yahoo.vespa.applicationmodel.ClusterId;
import com.yahoo.vespa.applicationmodel.ConfigId;
import com.yahoo.vespa.applicationmodel.HostName;
@@ -24,7 +28,9 @@ import com.yahoo.vespa.service.monitor.ServiceStatusProvider;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
+import java.util.function.Predicate;
import java.util.stream.Collectors;
/**
@@ -37,23 +43,100 @@ public class ApplicationInstanceGenerator {
private final ApplicationInfo applicationInfo;
private final Zone zone;
- private ApplicationId configServerApplicationId;
+
+ // This is cheating a bit, but we don't expect DuperModel's config server application ID to be different.
+ // We do this to avoid passing through the ID through multiple levels.
+ private static ApplicationId configServerApplicationId = new ConfigServerApplication().getApplicationId();
public ApplicationInstanceGenerator(ApplicationInfo applicationInfo, Zone zone) {
this.applicationInfo = applicationInfo;
this.zone = zone;
-
- // This is cheating a bit, but we don't expect DuperModel's config server application ID to be different.
- // We do this to avoid passing through the ID through multiple levels.
- this.configServerApplicationId = new ConfigServerApplication().getApplicationId();
}
public ApplicationInstance makeApplicationInstance(ServiceStatusProvider serviceStatusProvider) {
+ return makeApplicationInstanceLimitedToHosts(serviceStatusProvider, hostname -> true);
+ }
+
+ public static ServiceId getServiceId(ApplicationInfo applicationInfo, ServiceInfo serviceInfo) {
+ return new ServiceId(
+ applicationInfo.getApplicationId(),
+ getClusterId(serviceInfo),
+ toServiceType(serviceInfo),
+ toConfigId(serviceInfo));
+ }
+
+ public ApplicationInstanceReference toApplicationInstanceReference() {
+ TenantId tenantId = new TenantId(applicationInfo.getApplicationId().tenant().toString());
+ ApplicationInstanceId applicationInstanceId = toApplicationInstanceId(applicationInfo.getApplicationId(), zone);
+ return new ApplicationInstanceReference(tenantId, applicationInstanceId);
+ }
+
+ public boolean containsHostname(HostName hostname) {
+ return applicationInfo.getModel().getHosts().stream()
+ .map(HostInfo::getHostname)
+ .anyMatch(hostnameString -> Objects.equals(hostnameString, hostname.s()));
+ }
+
+ public ApplicationInstance makeApplicationInstanceLimitedTo(
+ HostName hostname, ServiceStatusProvider serviceStatusProvider) {
+ return makeApplicationInstanceLimitedToHosts(
+ serviceStatusProvider, candidateHostname -> candidateHostname.equals(hostname));
+ }
+
+ /** Reverse of toApplicationInstanceId, put in this file because it its inverse is. */
+ public static ApplicationId toApplicationId(ApplicationInstanceReference reference) {
+
+ String appNameStr = reference.asString();
+ String[] appNameParts = appNameStr.split(":");
+
+ // Env, region and instance seems to be optional due to the hardcoded config server app
+ // Assume here that first two are tenant and application name.
+ if (appNameParts.length == 2) {
+ return ApplicationId.from(TenantName.from(appNameParts[0]),
+ ApplicationName.from(appNameParts[1]),
+ InstanceName.defaultName());
+ }
+
+ // Other normal application should have 5 parts.
+ if (appNameParts.length != 5) {
+ throw new IllegalArgumentException("Application reference not valid (not 5 parts): " + reference);
+ }
+
+ return ApplicationId.from(TenantName.from(appNameParts[0]),
+ ApplicationName.from(appNameParts[1]),
+ InstanceName.from(appNameParts[4]));
+ }
+
+ private static ApplicationInstanceId toApplicationInstanceId(ApplicationId applicationId, Zone zone) {
+ if (applicationId.equals(configServerApplicationId)) {
+ // Removing this historical discrepancy would break orchestration during rollout.
+ // An alternative may be to use a feature flag and flip it between releases,
+ // once that's available.
+ return new ApplicationInstanceId(applicationId.application().value());
+ } else {
+ return new ApplicationInstanceId(String.format("%s:%s:%s:%s",
+ applicationId.application().value(),
+ zone.environment().value(),
+ zone.region().value(),
+ applicationId.instance().value()));
+ }
+ }
+
+ private static ClusterId getClusterId(ServiceInfo serviceInfo) {
+ return new ClusterId(serviceInfo.getProperty(CLUSTER_ID_PROPERTY_NAME).orElse(""));
+ }
+
+ private ApplicationInstance makeApplicationInstanceLimitedToHosts(ServiceStatusProvider serviceStatusProvider,
+ Predicate<HostName> includeHostPredicate) {
Map<ServiceClusterKey, Set<ServiceInstance>> groupedServiceInstances = new HashMap<>();
for (HostInfo host : applicationInfo.getModel().getHosts()) {
HostName hostName = new HostName(host.getHostname());
+ if (!includeHostPredicate.test(hostName)) {
+ continue;
+ }
+
for (ServiceInfo serviceInfo : host.getServices()) {
ServiceClusterKey serviceClusterKey = toServiceClusterKey(serviceInfo);
@@ -77,10 +160,8 @@ public class ApplicationInstanceGenerator {
entry.getValue()))
.collect(Collectors.toSet());
- ApplicationInstance applicationInstance = new ApplicationInstance(
- new TenantId(applicationInfo.getApplicationId().tenant().toString()),
- toApplicationInstanceId(applicationInfo, zone),
- serviceClusters);
+ ApplicationInstanceReference reference = toApplicationInstanceReference();
+ ApplicationInstance applicationInstance = new ApplicationInstance(reference, serviceClusters);
// Fill back-references
for (ServiceCluster serviceCluster : applicationInstance.serviceClusters()) {
@@ -106,33 +187,6 @@ public class ApplicationInstanceGenerator {
return new ServiceInstance(configId, hostName, status);
}
- private ApplicationInstanceId toApplicationInstanceId(ApplicationInfo applicationInfo, Zone zone) {
- if (applicationInfo.getApplicationId().equals(configServerApplicationId)) {
- // Removing this historical discrepancy would break orchestration during rollout.
- // An alternative may be to use a feature flag and flip it between releases,
- // once that's available.
- return new ApplicationInstanceId(applicationInfo.getApplicationId().application().value());
- } else {
- return new ApplicationInstanceId(String.format("%s:%s:%s:%s",
- applicationInfo.getApplicationId().application().value(),
- zone.environment().value(),
- zone.region().value(),
- applicationInfo.getApplicationId().instance().value()));
- }
- }
-
- public static ServiceId getServiceId(ApplicationInfo applicationInfo, ServiceInfo serviceInfo) {
- return new ServiceId(
- applicationInfo.getApplicationId(),
- getClusterId(serviceInfo),
- toServiceType(serviceInfo),
- toConfigId(serviceInfo));
- }
-
- public static ClusterId getClusterId(ServiceInfo serviceInfo) {
- return new ClusterId(serviceInfo.getProperty(CLUSTER_ID_PROPERTY_NAME).orElse(""));
- }
-
private static ServiceClusterKey toServiceClusterKey(ServiceInfo serviceInfo) {
ClusterId clusterId = getClusterId(serviceInfo);
ServiceType serviceType = toServiceType(serviceInfo);
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/model/ModelGenerator.java b/service-monitor/src/main/java/com/yahoo/vespa/service/model/ModelGenerator.java
index a6bf41d6c9b..45a9d1c77c5 100644
--- a/service-monitor/src/main/java/com/yahoo/vespa/service/model/ModelGenerator.java
+++ b/service-monitor/src/main/java/com/yahoo/vespa/service/model/ModelGenerator.java
@@ -5,11 +5,15 @@ import com.yahoo.config.model.api.ApplicationInfo;
import com.yahoo.config.provision.Zone;
import com.yahoo.vespa.applicationmodel.ApplicationInstance;
import com.yahoo.vespa.applicationmodel.ApplicationInstanceReference;
+import com.yahoo.vespa.applicationmodel.HostName;
+import com.yahoo.vespa.applicationmodel.ServiceInstance;
import com.yahoo.vespa.service.monitor.ServiceModel;
import com.yahoo.vespa.service.monitor.ServiceStatusProvider;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
@@ -18,6 +22,11 @@ import java.util.stream.Collectors;
*/
public class ModelGenerator {
public static final String CLUSTER_ID_PROPERTY_NAME = "clustername";
+ private final Zone zone;
+
+ public ModelGenerator(Zone zone) {
+ this.zone = zone;
+ }
/**
* Create service model based primarily on super model.
@@ -25,7 +34,6 @@ public class ModelGenerator {
* If the configServerhosts is non-empty, a config server application is added.
*/
public ServiceModel toServiceModel(List<ApplicationInfo> allApplicationInfos,
- Zone zone,
ServiceStatusProvider serviceStatusProvider) {
Map<ApplicationInstanceReference, ApplicationInstance> applicationInstances =
allApplicationInfos.stream()
@@ -36,4 +44,48 @@ public class ModelGenerator {
return new ServiceModel(applicationInstances);
}
+ public Set<ApplicationInstanceReference> toApplicationInstanceReferenceSet(List<ApplicationInfo> infos) {
+ return infos.stream()
+ .map(info -> new ApplicationInstanceGenerator(info, zone).toApplicationInstanceReference())
+ .collect(Collectors.toSet());
+ }
+
+ public Optional<ApplicationInstance> toApplication(List<ApplicationInfo> applicationInfos,
+ HostName hostname,
+ ServiceStatusProvider serviceStatusProvider) {
+ for (var applicationInfo : applicationInfos) {
+ var generator = new ApplicationInstanceGenerator(applicationInfo, zone);
+ if (generator.containsHostname(hostname)) {
+ return Optional.of(generator.makeApplicationInstance(serviceStatusProvider));
+ }
+ }
+
+ return Optional.empty();
+ }
+
+ public ApplicationInstance toApplication(ApplicationInfo applicationInfo,
+ ServiceStatusProvider serviceStatusProvider) {
+ var generator = new ApplicationInstanceGenerator(applicationInfo, zone);
+ return generator.makeApplicationInstance(serviceStatusProvider);
+ }
+
+ public List<ServiceInstance> toServices(List<ApplicationInfo> applicationInfos,
+ HostName hostname,
+ ServiceStatusProvider serviceStatusProvider) {
+ for (var applicationInfo : applicationInfos) {
+ var generator = new ApplicationInstanceGenerator(applicationInfo, zone);
+ ApplicationInstance applicationInstance = generator.makeApplicationInstanceLimitedTo(
+ hostname, serviceStatusProvider);
+
+ List<ServiceInstance> serviceInstances = applicationInstance.serviceClusters().stream()
+ .flatMap(cluster -> cluster.serviceInstances().stream())
+ .collect(Collectors.toList());
+
+ if (serviceInstances.size() > 0) {
+ return serviceInstances;
+ }
+ }
+
+ return List.of();
+ }
}
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/model/ServiceModelCache.java b/service-monitor/src/main/java/com/yahoo/vespa/service/model/ServiceModelCache.java
index 1b37555a554..29b2832efd0 100644
--- a/service-monitor/src/main/java/com/yahoo/vespa/service/model/ServiceModelCache.java
+++ b/service-monitor/src/main/java/com/yahoo/vespa/service/model/ServiceModelCache.java
@@ -4,6 +4,7 @@ package com.yahoo.vespa.service.model;
import com.yahoo.jdisc.Timer;
import com.yahoo.vespa.service.monitor.ServiceModel;
+import com.yahoo.vespa.service.monitor.ServiceMonitor;
import java.util.function.Supplier;
@@ -12,12 +13,11 @@ import java.util.function.Supplier;
*
* @author hakonhall
*/
-public class ServiceModelCache implements Supplier<ServiceModel> {
+public class ServiceModelCache implements ServiceMonitor {
public static final long EXPIRY_MILLIS = 10000;
private final Supplier<ServiceModel> expensiveSupplier;
private final Timer timer;
- private final boolean useCache;
private volatile ServiceModel snapshot;
private boolean updatePossiblyInProgress = false;
@@ -25,18 +25,13 @@ public class ServiceModelCache implements Supplier<ServiceModel> {
private final Object updateMonitor = new Object();
private long snapshotMillis;
- public ServiceModelCache(Supplier<ServiceModel> expensiveSupplier, Timer timer, boolean useCache) {
+ public ServiceModelCache(Supplier<ServiceModel> expensiveSupplier, Timer timer) {
this.expensiveSupplier = expensiveSupplier;
this.timer = timer;
- this.useCache = useCache;
}
@Override
- public ServiceModel get() {
- if (!useCache) {
- return expensiveSupplier.get();
- }
-
+ public ServiceModel getServiceModelSnapshot() {
if (snapshot == null) {
synchronized (updateMonitor) {
if (snapshot == null) {
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/model/ServiceModelProvider.java b/service-monitor/src/main/java/com/yahoo/vespa/service/model/ServiceModelProvider.java
index c6947810fa0..641bc5ca7ff 100644
--- a/service-monitor/src/main/java/com/yahoo/vespa/service/model/ServiceModelProvider.java
+++ b/service-monitor/src/main/java/com/yahoo/vespa/service/model/ServiceModelProvider.java
@@ -2,33 +2,40 @@
package com.yahoo.vespa.service.model;
import com.yahoo.config.model.api.ApplicationInfo;
+import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.Zone;
+import com.yahoo.vespa.applicationmodel.ApplicationInstance;
+import com.yahoo.vespa.applicationmodel.ApplicationInstanceReference;
+import com.yahoo.vespa.applicationmodel.HostName;
+import com.yahoo.vespa.applicationmodel.ServiceInstance;
+import com.yahoo.vespa.service.duper.DuperModelManager;
import com.yahoo.vespa.service.monitor.ServiceModel;
+import com.yahoo.vespa.service.monitor.ServiceMonitor;
import com.yahoo.vespa.service.monitor.ServiceStatusProvider;
-import com.yahoo.vespa.service.manager.MonitorManager;
-import com.yahoo.vespa.service.duper.DuperModelManager;
import java.util.List;
-import java.util.function.Supplier;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
/**
* An uncached supplier of ServiceModel based on the DuperModel and MonitorManager.
*
* @author hakonhall
*/
-public class ServiceModelProvider implements Supplier<ServiceModel> {
+public class ServiceModelProvider implements ServiceMonitor {
private final ServiceMonitorMetrics metrics;
private final DuperModelManager duperModelManager;
private final ModelGenerator modelGenerator;
private final Zone zone;
- private final MonitorManager monitorManager;
+ private final ServiceStatusProvider serviceStatusProvider;
- public ServiceModelProvider(MonitorManager monitorManager,
+ public ServiceModelProvider(ServiceStatusProvider serviceStatusProvider,
ServiceMonitorMetrics metrics,
DuperModelManager duperModelManager,
ModelGenerator modelGenerator,
Zone zone) {
- this.monitorManager = monitorManager;
+ this.serviceStatusProvider = serviceStatusProvider;
this.metrics = metrics;
this.duperModelManager = duperModelManager;
this.modelGenerator = modelGenerator;
@@ -36,13 +43,46 @@ public class ServiceModelProvider implements Supplier<ServiceModel> {
}
@Override
- public ServiceModel get() {
+ public ServiceModel getServiceModelSnapshot() {
try (LatencyMeasurement measurement = metrics.startServiceModelSnapshotLatencyMeasurement()) {
- // WARNING: The monitor manager may be out-of-sync with duper model (no locking)
- List<ApplicationInfo> applicationInfos = duperModelManager.getApplicationInfos();
-
- return modelGenerator.toServiceModel(applicationInfos, zone, (ServiceStatusProvider) monitorManager);
+ return modelGenerator.toServiceModel(applicationInfos(), serviceStatusProvider);
}
}
+ @Override
+ public Set<ApplicationInstanceReference> getAllApplicationInstanceReferences() {
+ return modelGenerator.toApplicationInstanceReferenceSet(applicationInfos());
+ }
+
+ @Override
+ public Optional<ApplicationInstance> getApplication(HostName hostname) {
+ // TODO(hakonhall): Lookup the applicationInfo from the hostname.
+ return modelGenerator.toApplication(applicationInfos(), hostname, serviceStatusProvider);
+ }
+
+ @Override
+ public Optional<ApplicationInstance> getApplication(ApplicationInstanceReference reference) {
+ return getApplicationInfo(reference)
+ .map(applicationInfo -> modelGenerator.toApplication(applicationInfo, serviceStatusProvider));
+ }
+
+ @Override
+ public List<ServiceInstance> getServiceInstancesOn(HostName hostname) {
+ // TODO(hakonhall): Lookup the applicationInfo from the hostname.
+ return modelGenerator.toServices(applicationInfos(), hostname, serviceStatusProvider);
+ }
+
+ @Override
+ public Map<HostName, List<ServiceInstance>> getServicesByHostname() {
+ return getServiceModelSnapshot().getServiceInstancesByHostName();
+ }
+
+ private Optional<ApplicationInfo> getApplicationInfo(ApplicationInstanceReference reference) {
+ ApplicationId applicationId = ApplicationInstanceGenerator.toApplicationId(reference);
+ return duperModelManager.getApplicationInfo(applicationId);
+ }
+
+ private List<ApplicationInfo> applicationInfos() {
+ return duperModelManager.getApplicationInfos();
+ }
}
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/model/ServiceMonitorImpl.java b/service-monitor/src/main/java/com/yahoo/vespa/service/model/ServiceMonitorImpl.java
index 67b4e890c29..a37a52f775e 100644
--- a/service-monitor/src/main/java/com/yahoo/vespa/service/model/ServiceMonitorImpl.java
+++ b/service-monitor/src/main/java/com/yahoo/vespa/service/model/ServiceMonitorImpl.java
@@ -5,6 +5,10 @@ import com.google.inject.Inject;
import com.yahoo.config.provision.Zone;
import com.yahoo.jdisc.Metric;
import com.yahoo.jdisc.Timer;
+import com.yahoo.vespa.applicationmodel.ApplicationInstance;
+import com.yahoo.vespa.applicationmodel.ApplicationInstanceReference;
+import com.yahoo.vespa.applicationmodel.HostName;
+import com.yahoo.vespa.applicationmodel.ServiceInstance;
import com.yahoo.vespa.flags.FlagSource;
import com.yahoo.vespa.flags.Flags;
import com.yahoo.vespa.service.duper.DuperModelManager;
@@ -12,9 +16,14 @@ import com.yahoo.vespa.service.manager.UnionMonitorManager;
import com.yahoo.vespa.service.monitor.ServiceModel;
import com.yahoo.vespa.service.monitor.ServiceMonitor;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+
public class ServiceMonitorImpl implements ServiceMonitor {
- private final ServiceModelCache serviceModelProvider;
+ private final ServiceMonitor delegate;
@Inject
public ServiceMonitorImpl(DuperModelManager duperModelManager,
@@ -25,19 +34,47 @@ public class ServiceMonitorImpl implements ServiceMonitor {
FlagSource flagSource) {
duperModelManager.registerListener(monitorManager);
- ServiceModelProvider uncachedServiceModelProvider = new ServiceModelProvider(
+ ServiceMonitor serviceMonitor = new ServiceModelProvider(
monitorManager,
new ServiceMonitorMetrics(metric, timer),
duperModelManager,
- new ModelGenerator(),
+ new ModelGenerator(zone),
zone);
- boolean cache = Flags.SERVICE_MODEL_CACHE.bindTo(flagSource).value();
- serviceModelProvider = new ServiceModelCache(uncachedServiceModelProvider, timer, cache);
+
+ if (Flags.SERVICE_MODEL_CACHE.bindTo(flagSource).value()) {
+ delegate = new ServiceModelCache(serviceMonitor::getServiceModelSnapshot, timer);
+ } else {
+ delegate = serviceMonitor;
+ }
}
@Override
public ServiceModel getServiceModelSnapshot() {
- return serviceModelProvider.get();
+ return delegate.getServiceModelSnapshot();
+ }
+
+ @Override
+ public Set<ApplicationInstanceReference> getAllApplicationInstanceReferences() {
+ return delegate.getAllApplicationInstanceReferences();
+ }
+
+ @Override
+ public Optional<ApplicationInstance> getApplication(HostName hostname) {
+ return delegate.getApplication(hostname);
}
+ @Override
+ public Optional<ApplicationInstance> getApplication(ApplicationInstanceReference reference) {
+ return delegate.getApplication(reference);
+ }
+
+ @Override
+ public List<ServiceInstance> getServiceInstancesOn(HostName hostname) {
+ return delegate.getServiceInstancesOn(hostname);
+ }
+
+ @Override
+ public Map<HostName, List<ServiceInstance>> getServicesByHostname() {
+ return delegate.getServicesByHostname();
+ }
}
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/ServiceMonitor.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/ServiceMonitor.java
index 49539c61e5d..8ad77213bc1 100644
--- a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/ServiceMonitor.java
+++ b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/ServiceMonitor.java
@@ -1,6 +1,17 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.service.monitor;
+import com.yahoo.vespa.applicationmodel.ApplicationInstance;
+import com.yahoo.vespa.applicationmodel.ApplicationInstanceReference;
+import com.yahoo.vespa.applicationmodel.HostName;
+import com.yahoo.vespa.applicationmodel.ServiceInstance;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+
/**
* The service monitor interface. A service monitor provides up to date information about the liveness status
* (up, down or not known) of each service instance in a Vespa zone
@@ -12,7 +23,37 @@ public interface ServiceMonitor {
/**
* Returns a ServiceModel which contains the current liveness status (up, down or unknown) of all instances
* of all services of all clusters of all applications in a zone.
+ * Deprecated: Please use the more specific methods below.
*/
ServiceModel getServiceModelSnapshot();
+ default Set<ApplicationInstanceReference> getAllApplicationInstanceReferences() {
+ return getServiceModelSnapshot().getAllApplicationInstances().keySet();
+ }
+
+ default Optional<ApplicationInstance> getApplication(HostName hostname) {
+ return Optional.ofNullable(getServiceModelSnapshot().getApplicationsByHostName().get(hostname));
+ }
+
+ default Optional<ApplicationInstance> getApplication(ApplicationInstanceReference reference) {
+ return getServiceModelSnapshot().getApplicationInstance(reference);
+ }
+
+ default List<ServiceInstance> getServiceInstancesOn(HostName hostname) {
+ ApplicationInstance application = getServiceModelSnapshot().getApplicationsByHostName().get(hostname);
+ if (application == null) {
+ return List.of();
+ }
+
+ return application
+ .serviceClusters().stream()
+ .flatMap(cluster -> cluster.serviceInstances().stream())
+ .filter(serviceInstance -> hostname.equals(serviceInstance.hostName()))
+ .collect(Collectors.toList());
+ }
+
+ default Map<HostName, List<ServiceInstance>> getServicesByHostname() {
+ return getServiceModelSnapshot().getServiceInstancesByHostName();
+ }
+
}
diff --git a/service-monitor/src/test/java/com/yahoo/vespa/service/model/ModelGeneratorTest.java b/service-monitor/src/test/java/com/yahoo/vespa/service/model/ModelGeneratorTest.java
index ce13cf60082..7be4ff38a7f 100644
--- a/service-monitor/src/test/java/com/yahoo/vespa/service/model/ModelGeneratorTest.java
+++ b/service-monitor/src/test/java/com/yahoo/vespa/service/model/ModelGeneratorTest.java
@@ -38,9 +38,9 @@ public class ModelGeneratorTest {
@Test
public void toApplicationModel() throws Exception {
- ModelGenerator modelGenerator = new ModelGenerator();
-
Zone zone = new Zone(Environment.from(ENVIRONMENT), RegionName.from(REGION));
+ ModelGenerator modelGenerator = new ModelGenerator(zone);
+
SlobrokMonitorManagerImpl slobrokMonitorManager = mock(SlobrokMonitorManagerImpl.class);
when(slobrokMonitorManager.getStatus(any(), any(), any(), any()))
@@ -49,7 +49,6 @@ public class ModelGeneratorTest {
ServiceModel serviceModel =
modelGenerator.toServiceModel(
getExampleApplicationInfos(),
- zone,
slobrokMonitorManager);
Map<ApplicationInstanceReference,
diff --git a/service-monitor/src/test/java/com/yahoo/vespa/service/model/ServiceModelCacheTest.java b/service-monitor/src/test/java/com/yahoo/vespa/service/model/ServiceModelCacheTest.java
index c2314be1e0f..21c6a49cc18 100644
--- a/service-monitor/src/test/java/com/yahoo/vespa/service/model/ServiceModelCacheTest.java
+++ b/service-monitor/src/test/java/com/yahoo/vespa/service/model/ServiceModelCacheTest.java
@@ -16,27 +16,27 @@ import static org.mockito.Mockito.when;
public class ServiceModelCacheTest {
@SuppressWarnings("unchecked")
- private final Supplier<ServiceModel> rawSupplier = mock(Supplier.class);
+ private final Supplier<ServiceModel> expensiveServiceMonitor = mock(Supplier.class);
private final Timer timer = mock(Timer.class);
- private final ServiceModelCache cache = new ServiceModelCache(rawSupplier, timer, true);
+ private final ServiceModelCache cache = new ServiceModelCache(expensiveServiceMonitor, timer);
@Test
public void sanityCheck() {
ServiceModel serviceModel = mock(ServiceModel.class);
- when(rawSupplier.get()).thenReturn(serviceModel);
+ when(expensiveServiceMonitor.get()).thenReturn(serviceModel);
long timeMillis = 0;
when(timer.currentTimeMillis()).thenReturn(timeMillis);
// Will always populate cache the first time
- ServiceModel actualServiceModel = cache.get();
+ ServiceModel actualServiceModel = cache.getServiceModelSnapshot();
assertTrue(actualServiceModel == serviceModel);
- verify(rawSupplier, times(1)).get();
+ verify(expensiveServiceMonitor, times(1)).get();
// Cache hit
timeMillis += ServiceModelCache.EXPIRY_MILLIS / 2;
when(timer.currentTimeMillis()).thenReturn(timeMillis);
- actualServiceModel = cache.get();
+ actualServiceModel = cache.getServiceModelSnapshot();
assertTrue(actualServiceModel == serviceModel);
// Cache expired
@@ -44,17 +44,17 @@ public class ServiceModelCacheTest {
when(timer.currentTimeMillis()).thenReturn(timeMillis);
ServiceModel serviceModel2 = mock(ServiceModel.class);
- when(rawSupplier.get()).thenReturn(serviceModel2);
+ when(expensiveServiceMonitor.get()).thenReturn(serviceModel2);
- actualServiceModel = cache.get();
+ actualServiceModel = cache.getServiceModelSnapshot();
assertTrue(actualServiceModel == serviceModel2);
// '2' because it's cumulative with '1' from the first times(1).
- verify(rawSupplier, times(2)).get();
+ verify(expensiveServiceMonitor, times(2)).get();
// Cache hit #2
timeMillis += 1;
when(timer.currentTimeMillis()).thenReturn(timeMillis);
- actualServiceModel = cache.get();
+ actualServiceModel = cache.getServiceModelSnapshot();
assertTrue(actualServiceModel == serviceModel2);
}
} \ No newline at end of file
diff --git a/service-monitor/src/test/java/com/yahoo/vespa/service/model/ServiceModelProviderTest.java b/service-monitor/src/test/java/com/yahoo/vespa/service/model/ServiceModelProviderTest.java
index 13f6da1534d..f34d61970ef 100644
--- a/service-monitor/src/test/java/com/yahoo/vespa/service/model/ServiceModelProviderTest.java
+++ b/service-monitor/src/test/java/com/yahoo/vespa/service/model/ServiceModelProviderTest.java
@@ -37,8 +37,8 @@ public class ServiceModelProviderTest {
.collect(Collectors.toList());
when(duperModelManager.getApplicationInfos()).thenReturn(applications);
- ServiceModel serviceModel = provider.get();
+ ServiceModel serviceModel = provider.getServiceModelSnapshot();
verify(duperModelManager, times(1)).getApplicationInfos();
- verify(modelGenerator).toServiceModel(applications, zone, slobrokMonitorManager);
+ verify(modelGenerator).toServiceModel(applications, slobrokMonitorManager);
}
} \ No newline at end of file