summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHåkon Hallingstad <hakon@oath.com>2018-06-06 13:13:54 +0200
committerHåkon Hallingstad <hakon@oath.com>2018-06-08 09:22:02 +0200
commit76ec2b9c26c7dfbafa84e38459b47bf33623ea3a (patch)
tree408d30b2f51af2edd72c1bbffcd791dd2c508cc8
parent82b8b6fbe344e0b9582434a83a1b2df5eab31bf6 (diff)
Revert "Revert "Use HTTP and remove Athenz injection""
-rw-r--r--service-monitor/pom.xml23
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/monitor/ServiceStatusProvider.java8
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/ApplicationInstanceGenerator.java141
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/ConfigServerAppGenerator.java67
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/ConfigServerApplication.java50
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/DeployedAppGenerator.java127
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/HostsModel.java75
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/ZoneApplication.java4
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/DuperModel.java38
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/DuperModelListener.java28
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/ModelGenerator.java38
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/MonitorManager.java5
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/ServiceId.java75
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/ServiceMonitorImpl.java23
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/SuperModelListenerImpl.java16
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/UnionMonitorManager.java41
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/health/ApplicationHealthMonitor.java102
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/health/HealthClient.java139
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/health/HealthEndpoint.java57
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/health/HealthInfo.java75
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/health/HealthMonitor.java73
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/health/HealthMonitorManager.java42
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/health/HealthResponse.java35
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/slobrok/SlobrokMonitorManagerImpl.java29
-rw-r--r--service-monitor/src/test/java/com/yahoo/vespa/service/monitor/application/ApplicationInstanceGeneratorTest.java (renamed from service-monitor/src/test/java/com/yahoo/vespa/service/monitor/application/ConfigServerAppGeneratorTest.java)18
-rw-r--r--service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/ConfigserverUtil.java44
-rw-r--r--service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/DuperModelTest.java40
-rw-r--r--service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/ModelGeneratorTest.java45
-rw-r--r--service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/SuperModelListenerImplTest.java13
-rw-r--r--service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/UnionMonitorManagerTest.java97
-rw-r--r--service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/health/ApplicationHealthMonitorTest.java24
-rw-r--r--service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/health/HealthMonitorManagerTest.java49
-rw-r--r--service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/health/HealthMonitorTest.java21
-rw-r--r--service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/slobrok/SlobrokMonitorManagerImplTest.java11
34 files changed, 1255 insertions, 418 deletions
diff --git a/service-monitor/pom.xml b/service-monitor/pom.xml
index 70f9d4aa655..b8065ed3636 100644
--- a/service-monitor/pom.xml
+++ b/service-monitor/pom.xml
@@ -64,6 +64,12 @@
<version>${project.version}</version>
</dependency>
<dependency>
+ <groupId>com.yahoo.vespa</groupId>
+ <artifactId>vespa-athenz</artifactId>
+ <version>${project.version}</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<scope>provided</scope>
@@ -76,6 +82,23 @@
<scope>provided</scope>
</dependency>
<dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-core</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-databind</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.httpcomponents</groupId>
+ <artifactId>httpclient</artifactId>
+ <version>4.5</version>
+ <!-- This is necessary to get 4.4's HostnameVerifier API of SSLConnectionSocketFactory::new -->
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/ServiceStatusProvider.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/ServiceStatusProvider.java
index 35003313775..75e61eef772 100644
--- a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/ServiceStatusProvider.java
+++ b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/ServiceStatusProvider.java
@@ -11,7 +11,13 @@ import com.yahoo.vespa.applicationmodel.ServiceType;
* @author hakon
*/
public interface ServiceStatusProvider {
- /** Get the {@link ServiceStatus} of a particular service. */
+ /**
+ * Get the {@link ServiceStatus} of a particular service.
+ *
+ * <p>{@link ServiceStatus#NOT_CHECKED NOT_CHECKED} must be returned if the
+ * service status provider does does not monitor the service status for
+ * the particular application, cluster, service type, and config id.
+ */
ServiceStatus getStatus(ApplicationId applicationId,
ClusterId clusterId,
ServiceType serviceType,
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/ApplicationInstanceGenerator.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/ApplicationInstanceGenerator.java
index ec2702bcfaf..cbdcce125cc 100644
--- a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/ApplicationInstanceGenerator.java
+++ b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/ApplicationInstanceGenerator.java
@@ -1,13 +1,148 @@
// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.service.monitor.application;
+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.Zone;
import com.yahoo.vespa.applicationmodel.ApplicationInstance;
+import com.yahoo.vespa.applicationmodel.ApplicationInstanceId;
+import com.yahoo.vespa.applicationmodel.ClusterId;
+import com.yahoo.vespa.applicationmodel.ConfigId;
+import com.yahoo.vespa.applicationmodel.HostName;
+import com.yahoo.vespa.applicationmodel.ServiceCluster;
+import com.yahoo.vespa.applicationmodel.ServiceClusterKey;
+import com.yahoo.vespa.applicationmodel.ServiceInstance;
+import com.yahoo.vespa.applicationmodel.ServiceStatus;
+import com.yahoo.vespa.applicationmodel.ServiceType;
+import com.yahoo.vespa.applicationmodel.TenantId;
import com.yahoo.vespa.service.monitor.ServiceStatusProvider;
+import com.yahoo.vespa.service.monitor.internal.ServiceId;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import static com.yahoo.vespa.service.monitor.application.ConfigServerApplication.CONFIG_SERVER_APPLICATION;
/**
+ * Class to generate an ApplicationInstance given service status for a standard (deployed) application.
+ *
* @author hakon
*/
-public interface ApplicationInstanceGenerator {
- /** Make an ApplicationInstance based on current service status. */
- ApplicationInstance makeApplicationInstance(ServiceStatusProvider serviceStatusProvider);
+public class ApplicationInstanceGenerator {
+ public static final String CLUSTER_ID_PROPERTY_NAME = "clustername";
+
+ private final ApplicationInfo applicationInfo;
+ private final Zone zone;
+
+ public ApplicationInstanceGenerator(ApplicationInfo applicationInfo, Zone zone) {
+ this.applicationInfo = applicationInfo;
+ this.zone = zone;
+ }
+
+ public ApplicationInstance makeApplicationInstance(ServiceStatusProvider serviceStatusProvider) {
+ Map<ServiceClusterKey, Set<ServiceInstance>> groupedServiceInstances = new HashMap<>();
+
+ for (HostInfo host : applicationInfo.getModel().getHosts()) {
+ HostName hostName = new HostName(host.getHostname());
+ for (ServiceInfo serviceInfo : host.getServices()) {
+ ServiceClusterKey serviceClusterKey = toServiceClusterKey(serviceInfo);
+ ServiceInstance serviceInstance =
+ toServiceInstance(
+ applicationInfo.getApplicationId(),
+ serviceClusterKey.clusterId(),
+ serviceInfo,
+ hostName,
+ serviceStatusProvider);
+
+ if (!groupedServiceInstances.containsKey(serviceClusterKey)) {
+ groupedServiceInstances.put(serviceClusterKey, new HashSet<>());
+ }
+ groupedServiceInstances.get(serviceClusterKey).add(serviceInstance);
+ }
+ }
+
+ Set<ServiceCluster> serviceClusters = groupedServiceInstances.entrySet().stream()
+ .map(entry -> new ServiceCluster(
+ entry.getKey().clusterId(),
+ entry.getKey().serviceType(),
+ entry.getValue()))
+ .collect(Collectors.toSet());
+
+ ApplicationInstance applicationInstance = new ApplicationInstance(
+ new TenantId(applicationInfo.getApplicationId().tenant().toString()),
+ toApplicationInstanceId(applicationInfo, zone),
+ serviceClusters);
+
+ // Fill back-references
+ for (ServiceCluster serviceCluster : applicationInstance.serviceClusters()) {
+ serviceCluster.setApplicationInstance(applicationInstance);
+ for (ServiceInstance serviceInstance : serviceCluster.serviceInstances()) {
+ serviceInstance.setServiceCluster(serviceCluster);
+ }
+ }
+
+ return applicationInstance;
+ }
+
+ private ServiceInstance toServiceInstance(
+ ApplicationId applicationId,
+ ClusterId clusterId,
+ ServiceInfo serviceInfo,
+ HostName hostName,
+ ServiceStatusProvider serviceStatusProvider) {
+ ConfigId configId = toConfigId(serviceInfo);
+
+ ServiceStatus status = serviceStatusProvider.getStatus(
+ applicationId,
+ clusterId,
+ toServiceType(serviceInfo), configId);
+
+ return new ServiceInstance(configId, hostName, status);
+ }
+
+ private ApplicationInstanceId toApplicationInstanceId(ApplicationInfo applicationInfo, Zone zone) {
+ if (applicationInfo.getApplicationId().equals(CONFIG_SERVER_APPLICATION.getApplicationId())) {
+ // 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));
+ }
+
+ private 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);
+ return new ServiceClusterKey(clusterId, serviceType);
+ }
+
+ private static ServiceType toServiceType(ServiceInfo serviceInfo) {
+ return new ServiceType(serviceInfo.getServiceType());
+ }
+
+ private static ConfigId toConfigId(ServiceInfo serviceInfo) {
+ return new ConfigId(serviceInfo.getConfigId());
+ }
}
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/ConfigServerAppGenerator.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/ConfigServerAppGenerator.java
deleted file mode 100644
index 76ca59cf583..00000000000
--- a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/ConfigServerAppGenerator.java
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.service.monitor.application;
-
-import com.yahoo.vespa.applicationmodel.ApplicationInstance;
-import com.yahoo.vespa.applicationmodel.ConfigId;
-import com.yahoo.vespa.applicationmodel.HostName;
-import com.yahoo.vespa.applicationmodel.ServiceCluster;
-import com.yahoo.vespa.applicationmodel.ServiceInstance;
-import com.yahoo.vespa.applicationmodel.ServiceStatus;
-import com.yahoo.vespa.service.monitor.ServiceStatusProvider;
-
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-/**
- * Class for generating an ApplicationInstance for the synthesized config server application.
- *
- * @author hakon
- */
-public class ConfigServerAppGenerator implements ApplicationInstanceGenerator {
- private final List<String> hostnames;
-
- public ConfigServerAppGenerator(List<String> hostnames) {
- this.hostnames = hostnames;
- }
-
- @Override
- public ApplicationInstance makeApplicationInstance(ServiceStatusProvider statusProvider) {
- Set<ServiceInstance> serviceInstances = hostnames.stream()
- .map(hostname -> makeServiceInstance(hostname, statusProvider))
- .collect(Collectors.toSet());
-
- ServiceCluster serviceCluster = new ServiceCluster(
- ConfigServerApplication.CLUSTER_ID,
- ConfigServerApplication.SERVICE_TYPE,
- serviceInstances);
-
- Set<ServiceCluster> serviceClusters = new HashSet<>();
- serviceClusters.add(serviceCluster);
-
- ApplicationInstance applicationInstance = new ApplicationInstance(
- ConfigServerApplication.TENANT_ID,
- ConfigServerApplication.APPLICATION_INSTANCE_ID,
- serviceClusters);
-
- // Fill back-references
- serviceCluster.setApplicationInstance(applicationInstance);
- for (ServiceInstance serviceInstance : serviceCluster.serviceInstances()) {
- serviceInstance.setServiceCluster(serviceCluster);
- }
-
- return applicationInstance;
- }
-
- private ServiceInstance makeServiceInstance(String hostname, ServiceStatusProvider statusProvider) {
- ConfigId configId = new ConfigId(ConfigServerApplication.CONFIG_ID_PREFIX + hostname);
- ServiceStatus status = statusProvider.getStatus(
- ConfigServerApplication.CONFIG_SERVER_APPLICATION.getApplicationId(),
- ConfigServerApplication.CLUSTER_ID,
- ConfigServerApplication.SERVICE_TYPE,
- configId);
-
- return new ServiceInstance(configId, new HostName(hostname), status);
- }
-}
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/ConfigServerApplication.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/ConfigServerApplication.java
index 132bb0927b8..5ad38cebcfc 100644
--- a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/ConfigServerApplication.java
+++ b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/ConfigServerApplication.java
@@ -1,12 +1,26 @@
// 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.application;
+import com.yahoo.cloud.config.ConfigserverConfig;
+import com.yahoo.config.model.api.ApplicationInfo;
+import com.yahoo.config.model.api.HostInfo;
+import com.yahoo.config.model.api.PortInfo;
+import com.yahoo.config.model.api.ServiceInfo;
import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.config.provision.NodeType;
import com.yahoo.vespa.applicationmodel.ApplicationInstanceId;
import com.yahoo.vespa.applicationmodel.ClusterId;
+import com.yahoo.vespa.applicationmodel.ConfigId;
import com.yahoo.vespa.applicationmodel.ServiceType;
import com.yahoo.vespa.applicationmodel.TenantId;
+import com.yahoo.vespa.service.monitor.internal.ModelGenerator;
+import com.yahoo.vespa.service.monitor.internal.health.ApplicationHealthMonitor;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
/**
* A service/application model of the config server with health status.
@@ -21,8 +35,44 @@ public class ConfigServerApplication extends HostedVespaApplication {
public static final ServiceType SERVICE_TYPE = new ServiceType("configserver");
public static final String CONFIG_ID_PREFIX = "configid.";
+ public static ConfigId configIdFrom(int index) {
+ return new ConfigId(CONFIG_ID_PREFIX + index);
+ }
+
private ConfigServerApplication() {
super("zone-config-servers", NodeType.config,
ClusterSpec.Type.admin, ClusterSpec.Id.from("zone-config-servers"));
}
+
+ public ApplicationInfo makeApplicationInfo(ConfigserverConfig config) {
+ List<HostInfo> hostInfos = new ArrayList<>();
+ List<ConfigserverConfig.Zookeeperserver> zooKeeperServers = config.zookeeperserver();
+ for (int index = 0; index < zooKeeperServers.size(); ++index) {
+ String hostname = zooKeeperServers.get(index).hostname();
+ hostInfos.add(makeHostInfo(hostname, config.httpport(), index));
+ }
+
+ return new ApplicationInfo(
+ CONFIG_SERVER_APPLICATION.getApplicationId(),
+ 0,
+ new HostsModel(hostInfos));
+ }
+
+ private static HostInfo makeHostInfo(String hostname, int port, int configIndex) {
+ PortInfo portInfo = new PortInfo(port, ApplicationHealthMonitor.PORT_TAGS_HEALTH);
+
+ Map<String, String> properties = new HashMap<>();
+ properties.put(ModelGenerator.CLUSTER_ID_PROPERTY_NAME, CLUSTER_ID.s());
+
+ ServiceInfo serviceInfo = new ServiceInfo(
+ // service name == service type for the first service of each type on each host
+ SERVICE_TYPE.s(),
+ SERVICE_TYPE.s(),
+ Collections.singletonList(portInfo),
+ properties,
+ configIdFrom(configIndex).s(),
+ hostname);
+
+ return new HostInfo(hostname, Collections.singletonList(serviceInfo));
+ }
}
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/DeployedAppGenerator.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/DeployedAppGenerator.java
deleted file mode 100644
index 2691a8bf1ee..00000000000
--- a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/DeployedAppGenerator.java
+++ /dev/null
@@ -1,127 +0,0 @@
-// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.service.monitor.application;
-
-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.Zone;
-import com.yahoo.vespa.applicationmodel.ApplicationInstance;
-import com.yahoo.vespa.applicationmodel.ApplicationInstanceId;
-import com.yahoo.vespa.applicationmodel.ClusterId;
-import com.yahoo.vespa.applicationmodel.ConfigId;
-import com.yahoo.vespa.applicationmodel.HostName;
-import com.yahoo.vespa.applicationmodel.ServiceCluster;
-import com.yahoo.vespa.applicationmodel.ServiceClusterKey;
-import com.yahoo.vespa.applicationmodel.ServiceInstance;
-import com.yahoo.vespa.applicationmodel.ServiceStatus;
-import com.yahoo.vespa.applicationmodel.ServiceType;
-import com.yahoo.vespa.applicationmodel.TenantId;
-import com.yahoo.vespa.service.monitor.ServiceStatusProvider;
-
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-/**
- * Class to generate an ApplicationInstance given service status for a standard (deployed) application.
- *
- * @author hakon
- */
-public class DeployedAppGenerator implements ApplicationInstanceGenerator {
- public static final String CLUSTER_ID_PROPERTY_NAME = "clustername";
-
- private final ApplicationInfo applicationInfo;
- private final Zone zone;
-
- public DeployedAppGenerator(ApplicationInfo applicationInfo, Zone zone) {
- this.applicationInfo = applicationInfo;
- this.zone = zone;
- }
-
- @Override
- public ApplicationInstance makeApplicationInstance(ServiceStatusProvider serviceStatusProvider) {
- Map<ServiceClusterKey, Set<ServiceInstance>> groupedServiceInstances = new HashMap<>();
-
- for (HostInfo host : applicationInfo.getModel().getHosts()) {
- HostName hostName = new HostName(host.getHostname());
- for (ServiceInfo serviceInfo : host.getServices()) {
- ServiceClusterKey serviceClusterKey = toServiceClusterKey(serviceInfo);
- ServiceInstance serviceInstance =
- toServiceInstance(
- applicationInfo.getApplicationId(),
- serviceClusterKey.clusterId(),
- serviceInfo,
- hostName,
- serviceStatusProvider);
-
- if (!groupedServiceInstances.containsKey(serviceClusterKey)) {
- groupedServiceInstances.put(serviceClusterKey, new HashSet<>());
- }
- groupedServiceInstances.get(serviceClusterKey).add(serviceInstance);
- }
- }
-
- Set<ServiceCluster> serviceClusters = groupedServiceInstances.entrySet().stream()
- .map(entry -> new ServiceCluster(
- entry.getKey().clusterId(),
- entry.getKey().serviceType(),
- entry.getValue()))
- .collect(Collectors.toSet());
-
- ApplicationInstance applicationInstance = new ApplicationInstance(
- new TenantId(applicationInfo.getApplicationId().tenant().toString()),
- toApplicationInstanceId(applicationInfo, zone),
- serviceClusters);
-
- // Fill back-references
- for (ServiceCluster serviceCluster : applicationInstance.serviceClusters()) {
- serviceCluster.setApplicationInstance(applicationInstance);
- for (ServiceInstance serviceInstance : serviceCluster.serviceInstances()) {
- serviceInstance.setServiceCluster(serviceCluster);
- }
- }
-
- return applicationInstance;
- }
-
- static ClusterId getClusterId(ServiceInfo serviceInfo) {
- return new ClusterId(serviceInfo.getProperty(CLUSTER_ID_PROPERTY_NAME).orElse(""));
- }
-
- private ServiceClusterKey toServiceClusterKey(ServiceInfo serviceInfo) {
- ClusterId clusterId = getClusterId(serviceInfo);
- ServiceType serviceType = toServiceType(serviceInfo);
- return new ServiceClusterKey(clusterId, serviceType);
- }
-
- private ServiceInstance toServiceInstance(
- ApplicationId applicationId,
- ClusterId clusterId,
- ServiceInfo serviceInfo,
- HostName hostName,
- ServiceStatusProvider serviceStatusProvider) {
- ConfigId configId = new ConfigId(serviceInfo.getConfigId());
-
- ServiceStatus status = serviceStatusProvider.getStatus(
- applicationId,
- clusterId,
- toServiceType(serviceInfo), configId);
-
- return new ServiceInstance(configId, hostName, status);
- }
-
- private ApplicationInstanceId toApplicationInstanceId(ApplicationInfo applicationInfo, Zone zone) {
- return new ApplicationInstanceId(String.format("%s:%s:%s:%s",
- applicationInfo.getApplicationId().application().value(),
- zone.environment().value(),
- zone.region().value(),
- applicationInfo.getApplicationId().instance().value()));
- }
-
- private ServiceType toServiceType(ServiceInfo serviceInfo) {
- return new ServiceType(serviceInfo.getServiceType());
- }
-}
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/HostsModel.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/HostsModel.java
new file mode 100644
index 00000000000..225ffb0adbc
--- /dev/null
+++ b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/HostsModel.java
@@ -0,0 +1,75 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.service.monitor.application;
+
+import com.yahoo.config.FileReference;
+import com.yahoo.config.model.api.FileDistribution;
+import com.yahoo.config.model.api.HostInfo;
+import com.yahoo.config.model.api.Model;
+import com.yahoo.config.provision.AllocatedHosts;
+import com.yahoo.vespa.config.ConfigKey;
+import com.yahoo.vespa.config.ConfigPayload;
+import com.yahoo.vespa.config.buildergen.ConfigDefinition;
+
+import java.time.Instant;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Model that only supports the subset necessary to create an ApplicationInstance.
+ *
+ * @author hakon
+ */
+public class HostsModel implements Model {
+ private final Collection<HostInfo> hosts;
+
+ public HostsModel(List<HostInfo> hosts) {
+ this.hosts = Collections.unmodifiableCollection(hosts);
+ }
+
+ @Override
+ public Collection<HostInfo> getHosts() {
+ return hosts;
+ }
+
+ @Override
+ public ConfigPayload getConfig(ConfigKey<?> configKey, ConfigDefinition configDefinition) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Set<ConfigKey<?>> allConfigsProduced() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Set<String> allConfigIds() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void distributeFiles(FileDistribution fileDistribution) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Set<FileReference> fileReferences() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public AllocatedHosts allocatedHosts() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean allowModelVersionMismatch(Instant now) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean skipOldConfigModels(Instant now) {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/ZoneApplication.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/ZoneApplication.java
index 6bbf0cb6d1d..c10015d3bfa 100644
--- a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/ZoneApplication.java
+++ b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/ZoneApplication.java
@@ -21,8 +21,8 @@ public class ZoneApplication {
.createHostedVespaApplicationId("routing");
public static boolean isNodeAdminService(ApplicationId applicationId,
- ClusterId clusterId,
- ServiceType serviceType) {
+ ClusterId clusterId,
+ ServiceType serviceType) {
return Objects.equals(applicationId, ZONE_APPLICATION_ID) &&
Objects.equals(serviceType, ServiceType.CONTAINER) &&
Objects.equals(clusterId, ClusterId.NODE_ADMIN);
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/DuperModel.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/DuperModel.java
new file mode 100644
index 00000000000..d3c6f92312c
--- /dev/null
+++ b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/DuperModel.java
@@ -0,0 +1,38 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.service.monitor.internal;
+
+import com.yahoo.cloud.config.ConfigserverConfig;
+import com.yahoo.config.model.api.ApplicationInfo;
+import com.yahoo.config.model.api.SuperModel;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import static com.yahoo.vespa.service.monitor.application.ConfigServerApplication.CONFIG_SERVER_APPLICATION;
+
+/**
+ * The {@code DuperModel} unites the {@link com.yahoo.config.model.api.SuperModel SuperModel}
+ * with the synthetically produced applications like the config server application.
+ *
+ * @author hakon
+ */
+public class DuperModel {
+ private final List<ApplicationInfo> staticApplicationInfos = new ArrayList<>();
+
+ public DuperModel(ConfigserverConfig configServerConfig) {
+ staticApplicationInfos.add(CONFIG_SERVER_APPLICATION.makeApplicationInfo(configServerConfig));
+ }
+
+ /** For testing. */
+ DuperModel(ApplicationInfo... staticApplicationInfos) {
+ this.staticApplicationInfos.addAll(Arrays.asList(staticApplicationInfos));
+ }
+
+ public List<ApplicationInfo> getApplicationInfos(SuperModel superModelSnapshot) {
+ List<ApplicationInfo> allApplicationInfos = new ArrayList<>();
+ allApplicationInfos.addAll(staticApplicationInfos);
+ allApplicationInfos.addAll(superModelSnapshot.getAllApplicationInfos());
+ return allApplicationInfos;
+ }
+}
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/DuperModelListener.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/DuperModelListener.java
new file mode 100644
index 00000000000..235c7db5c36
--- /dev/null
+++ b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/DuperModelListener.java
@@ -0,0 +1,28 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.service.monitor.internal;
+
+import com.yahoo.config.model.api.ApplicationInfo;
+import com.yahoo.config.model.api.SuperModel;
+import com.yahoo.config.provision.ApplicationId;
+
+/**
+ * Interface for listening for changes to the {@link DuperModel}.
+ *
+ * @author hakon
+ */
+public interface DuperModelListener {
+ /**
+ * An application has been activated:
+ *
+ * <ul>
+ * <li>A synthetic application like the config server application has been added/"activated"
+ * <li>A super model application has been activated (see
+ * {@link com.yahoo.config.model.api.SuperModelListener#applicationActivated(SuperModel, ApplicationInfo)
+ * SuperModelListener}
+ * </ul>
+ */
+ void applicationActivated(ApplicationInfo application);
+
+ /** Application has been removed. */
+ void applicationRemoved(ApplicationId id);
+}
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/ModelGenerator.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/ModelGenerator.java
index 9da449289a7..ad2f223acf8 100644
--- a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/ModelGenerator.java
+++ b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/ModelGenerator.java
@@ -1,56 +1,40 @@
// 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.internal;
-import com.yahoo.config.model.api.SuperModel;
+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.service.monitor.ServiceModel;
import com.yahoo.vespa.service.monitor.ServiceStatusProvider;
import com.yahoo.vespa.service.monitor.application.ApplicationInstanceGenerator;
-import com.yahoo.vespa.service.monitor.application.ConfigServerAppGenerator;
-import com.yahoo.vespa.service.monitor.application.DeployedAppGenerator;
-import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
- * Util to convert SuperModel to ServiceModel and application model classes
+ * Util to make ServiceModel and its related application model classes
*/
public class ModelGenerator {
public static final String CLUSTER_ID_PROPERTY_NAME = "clustername";
- private final List<ApplicationInstanceGenerator> staticGenerators;
-
- public ModelGenerator(List<String> configServerHosts) {
- if (configServerHosts.isEmpty()) {
- staticGenerators = Collections.emptyList();
- } else {
- staticGenerators = Collections.singletonList(new ConfigServerAppGenerator(configServerHosts));
- }
- }
-
/**
* Create service model based primarily on super model.
*
* If the configServerhosts is non-empty, a config server application is added.
*/
- ServiceModel toServiceModel(
- SuperModel superModel,
- Zone zone,
- ServiceStatusProvider serviceStatusProvider) {
- List<ApplicationInstanceGenerator> generators = new ArrayList<>(staticGenerators);
- superModel.getAllApplicationInfos()
- .forEach(info -> generators.add(new DeployedAppGenerator(info, zone)));
-
- Map<ApplicationInstanceReference, ApplicationInstance> applicationInstances = generators.stream()
- .map(generator -> generator.makeApplicationInstance(serviceStatusProvider))
- .collect(Collectors.toMap(ApplicationInstance::reference, Function.identity()));
+ public ServiceModel toServiceModel(List<ApplicationInfo> allApplicationInfos,
+ Zone zone,
+ ServiceStatusProvider serviceStatusProvider) {
+ Map<ApplicationInstanceReference, ApplicationInstance> applicationInstances =
+ allApplicationInfos.stream()
+ .map(info -> new ApplicationInstanceGenerator(info, zone)
+ .makeApplicationInstance(serviceStatusProvider))
+ .collect(Collectors.toMap(ApplicationInstance::reference, Function.identity()));
return new ServiceModel(applicationInstances);
}
+
}
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/MonitorManager.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/MonitorManager.java
index 49863672c43..1edf3a18215 100644
--- a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/MonitorManager.java
+++ b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/MonitorManager.java
@@ -1,11 +1,10 @@
// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
-package com.yahoo.vespa.service.monitor.internal;// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.service.monitor.internal;
-import com.yahoo.config.model.api.SuperModelListener;
import com.yahoo.vespa.service.monitor.ServiceStatusProvider;
/**
* @author hakon
*/
-public interface MonitorManager extends SuperModelListener, ServiceStatusProvider {
+public interface MonitorManager extends DuperModelListener, ServiceStatusProvider {
}
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/ServiceId.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/ServiceId.java
new file mode 100644
index 00000000000..993ea7fed5c
--- /dev/null
+++ b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/ServiceId.java
@@ -0,0 +1,75 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.service.monitor.internal;
+
+import com.yahoo.config.provision.ApplicationId;
+import com.yahoo.vespa.applicationmodel.ClusterId;
+import com.yahoo.vespa.applicationmodel.ConfigId;
+import com.yahoo.vespa.applicationmodel.ServiceType;
+
+import javax.annotation.concurrent.Immutable;
+import java.util.Objects;
+
+/**
+ * Identifies a service.
+ *
+ * @author hakon
+ */
+@Immutable
+public class ServiceId {
+ private final ApplicationId applicationId;
+ private final ClusterId clusterId;
+ private final ServiceType serviceType;
+ private final ConfigId configId;
+
+ public ServiceId(ApplicationId applicationId,
+ ClusterId clusterId,
+ ServiceType serviceType,
+ ConfigId configId) {
+ this.applicationId = applicationId;
+ this.clusterId = clusterId;
+ this.serviceType = serviceType;
+ this.configId = configId;
+ }
+
+ public ApplicationId getApplicationId() {
+ return applicationId;
+ }
+
+ public ClusterId getClusterId() {
+ return clusterId;
+ }
+
+ public ServiceType getServiceType() {
+ return serviceType;
+ }
+
+ public ConfigId getConfigId() {
+ return configId;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ ServiceId serviceId = (ServiceId) o;
+ return Objects.equals(applicationId, serviceId.applicationId) &&
+ Objects.equals(clusterId, serviceId.clusterId) &&
+ Objects.equals(serviceType, serviceId.serviceType) &&
+ Objects.equals(configId, serviceId.configId);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(applicationId, clusterId, serviceType, configId);
+ }
+
+ @Override
+ public String toString() {
+ return "ServiceId{" +
+ "applicationId=" + applicationId +
+ ", clusterId=" + clusterId +
+ ", serviceType=" + serviceType +
+ ", configId=" + configId +
+ '}';
+ }
+}
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/ServiceMonitorImpl.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/ServiceMonitorImpl.java
index 97c4fdda0f3..bd8fd4a50e0 100644
--- a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/ServiceMonitorImpl.java
+++ b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/ServiceMonitorImpl.java
@@ -14,10 +14,7 @@ import com.yahoo.vespa.service.monitor.ServiceMonitor;
import com.yahoo.vespa.service.monitor.internal.health.HealthMonitorManager;
import com.yahoo.vespa.service.monitor.internal.slobrok.SlobrokMonitorManagerImpl;
-import java.util.Collections;
-import java.util.List;
import java.util.Map;
-import java.util.stream.Collectors;
public class ServiceMonitorImpl implements ServiceMonitor {
private final ServiceModelCache serviceModelCache;
@@ -32,30 +29,20 @@ public class ServiceMonitorImpl implements ServiceMonitor {
Zone zone = superModelProvider.getZone();
ServiceMonitorMetrics metrics = new ServiceMonitorMetrics(metric, timer);
- UnionMonitorManager monitorManager = new UnionMonitorManager(
- slobrokMonitorManager,
- healthMonitorManager,
- configserverConfig);
+ DuperModel duperModel = new DuperModel(configserverConfig);
+ UnionMonitorManager monitorManager =
+ new UnionMonitorManager(slobrokMonitorManager, healthMonitorManager);
SuperModelListenerImpl superModelListener = new SuperModelListenerImpl(
monitorManager,
metrics,
- new ModelGenerator(toConfigServerList(configserverConfig)),
+ duperModel,
+ new ModelGenerator(),
zone);
superModelListener.start(superModelProvider);
serviceModelCache = new ServiceModelCache(superModelListener, timer);
}
- private List<String> toConfigServerList(ConfigserverConfig configserverConfig) {
- if (configserverConfig.multitenant()) {
- return configserverConfig.zookeeperserver().stream()
- .map(ConfigserverConfig.Zookeeperserver::hostname)
- .collect(Collectors.toList());
- }
-
- return Collections.emptyList();
- }
-
@Override
public Map<ApplicationInstanceReference, ApplicationInstance> getAllApplicationInstances() {
return serviceModelCache.get().getAllApplicationInstances();
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/SuperModelListenerImpl.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/SuperModelListenerImpl.java
index b2f3617131b..f509809c33d 100644
--- a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/SuperModelListenerImpl.java
+++ b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/SuperModelListenerImpl.java
@@ -8,7 +8,9 @@ import com.yahoo.config.model.api.SuperModelProvider;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.config.provision.Zone;
import com.yahoo.vespa.service.monitor.ServiceModel;
+import com.yahoo.vespa.service.monitor.ServiceStatusProvider;
+import java.util.List;
import java.util.function.Supplier;
import java.util.logging.Logger;
@@ -16,6 +18,7 @@ public class SuperModelListenerImpl implements SuperModelListener, Supplier<Serv
private static final Logger logger = Logger.getLogger(SuperModelListenerImpl.class.getName());
private final ServiceMonitorMetrics metrics;
+ private final DuperModel duperModel;
private final ModelGenerator modelGenerator;
private final Zone zone;
@@ -27,10 +30,12 @@ public class SuperModelListenerImpl implements SuperModelListener, Supplier<Serv
SuperModelListenerImpl(MonitorManager monitorManager,
ServiceMonitorMetrics metrics,
+ DuperModel duperModel,
ModelGenerator modelGenerator,
Zone zone) {
this.monitorManager = monitorManager;
this.metrics = metrics;
+ this.duperModel = duperModel;
this.modelGenerator = modelGenerator;
this.zone = zone;
}
@@ -41,8 +46,7 @@ public class SuperModelListenerImpl implements SuperModelListener, Supplier<Serv
// since applicationActivated()/applicationRemoved() may be called
// asynchronously even before snapshot() returns.
this.superModel = superModelProvider.snapshot(this);
- superModel.getAllApplicationInfos().stream().forEach(application ->
- monitorManager.applicationActivated(superModel, application));
+ duperModel.getApplicationInfos(superModel).forEach(monitorManager::applicationActivated);
}
}
@@ -50,7 +54,7 @@ public class SuperModelListenerImpl implements SuperModelListener, Supplier<Serv
public void applicationActivated(SuperModel superModel, ApplicationInfo application) {
synchronized (monitor) {
this.superModel = superModel;
- monitorManager.applicationActivated(superModel, application);
+ monitorManager.applicationActivated(application);
}
}
@@ -58,7 +62,7 @@ public class SuperModelListenerImpl implements SuperModelListener, Supplier<Serv
public void applicationRemoved(SuperModel superModel, ApplicationId id) {
synchronized (monitor) {
this.superModel = superModel;
- monitorManager.applicationRemoved(superModel, id);
+ monitorManager.applicationRemoved(id);
}
}
@@ -71,7 +75,9 @@ public class SuperModelListenerImpl implements SuperModelListener, Supplier<Serv
dummy(measurement);
// WARNING: The slobrok monitor manager may be out-of-sync with super model (no locking)
- return modelGenerator.toServiceModel(superModel, zone, monitorManager);
+ List<ApplicationInfo> applicationInfos = duperModel.getApplicationInfos(superModel);
+
+ return modelGenerator.toServiceModel(applicationInfos, zone, (ServiceStatusProvider) monitorManager);
}
}
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/UnionMonitorManager.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/UnionMonitorManager.java
index 82d2043bd17..81cf6f2af5e 100644
--- a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/UnionMonitorManager.java
+++ b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/UnionMonitorManager.java
@@ -1,16 +1,12 @@
// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.service.monitor.internal;
-import com.yahoo.cloud.config.ConfigserverConfig;
import com.yahoo.config.model.api.ApplicationInfo;
-import com.yahoo.config.model.api.SuperModel;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.vespa.applicationmodel.ClusterId;
import com.yahoo.vespa.applicationmodel.ConfigId;
import com.yahoo.vespa.applicationmodel.ServiceStatus;
import com.yahoo.vespa.applicationmodel.ServiceType;
-import com.yahoo.vespa.service.monitor.application.ConfigServerApplication;
-import com.yahoo.vespa.service.monitor.application.ZoneApplication;
import com.yahoo.vespa.service.monitor.internal.health.HealthMonitorManager;
import com.yahoo.vespa.service.monitor.internal.slobrok.SlobrokMonitorManagerImpl;
@@ -20,14 +16,11 @@ import com.yahoo.vespa.service.monitor.internal.slobrok.SlobrokMonitorManagerImp
public class UnionMonitorManager implements MonitorManager {
private final SlobrokMonitorManagerImpl slobrokMonitorManager;
private final HealthMonitorManager healthMonitorManager;
- private final ConfigserverConfig configserverConfig;
UnionMonitorManager(SlobrokMonitorManagerImpl slobrokMonitorManager,
- HealthMonitorManager healthMonitorManager,
- ConfigserverConfig configserverConfig) {
+ HealthMonitorManager healthMonitorManager) {
this.slobrokMonitorManager = slobrokMonitorManager;
this.healthMonitorManager = healthMonitorManager;
- this.configserverConfig = configserverConfig;
}
@Override
@@ -35,33 +28,25 @@ public class UnionMonitorManager implements MonitorManager {
ClusterId clusterId,
ServiceType serviceType,
ConfigId configId) {
-
- if (applicationId.equals(ConfigServerApplication.CONFIG_SERVER_APPLICATION.getApplicationId())) {
- // todo: use health
- return ServiceStatus.NOT_CHECKED;
+ // Trust the new health monitoring status if it actually monitors the particular service.
+ ServiceStatus status = healthMonitorManager.getStatus(applicationId, clusterId, serviceType, configId);
+ if (status != ServiceStatus.NOT_CHECKED) {
+ return status;
}
- MonitorManager monitorManager = useHealth(applicationId, clusterId, serviceType) ?
- healthMonitorManager :
- slobrokMonitorManager;
-
- return monitorManager.getStatus(applicationId, clusterId, serviceType, configId);
+ // fallback is the older slobrok
+ return slobrokMonitorManager.getStatus(applicationId, clusterId, serviceType, configId);
}
@Override
- public void applicationActivated(SuperModel superModel, ApplicationInfo application) {
- slobrokMonitorManager.applicationActivated(superModel, application);
- healthMonitorManager.applicationActivated(superModel, application);
+ public void applicationActivated(ApplicationInfo application) {
+ slobrokMonitorManager.applicationActivated(application);
+ healthMonitorManager.applicationActivated(application);
}
@Override
- public void applicationRemoved(SuperModel superModel, ApplicationId id) {
- slobrokMonitorManager.applicationRemoved(superModel, id);
- healthMonitorManager.applicationRemoved(superModel, id);
- }
-
- private boolean useHealth(ApplicationId applicationId, ClusterId clusterId, ServiceType serviceType) {
- return !configserverConfig.nodeAdminInContainer() &&
- ZoneApplication.isNodeAdminService(applicationId, clusterId, serviceType);
+ public void applicationRemoved(ApplicationId id) {
+ slobrokMonitorManager.applicationRemoved(id);
+ healthMonitorManager.applicationRemoved(id);
}
}
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/health/ApplicationHealthMonitor.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/health/ApplicationHealthMonitor.java
new file mode 100644
index 00000000000..bd2658db8aa
--- /dev/null
+++ b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/health/ApplicationHealthMonitor.java
@@ -0,0 +1,102 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.service.monitor.internal.health;
+
+import com.yahoo.config.model.api.ApplicationInfo;
+import com.yahoo.config.model.api.HostInfo;
+import com.yahoo.config.model.api.PortInfo;
+import com.yahoo.config.model.api.ServiceInfo;
+import com.yahoo.config.provision.ApplicationId;
+import com.yahoo.config.provision.HostName;
+import com.yahoo.vespa.applicationmodel.ClusterId;
+import com.yahoo.vespa.applicationmodel.ConfigId;
+import com.yahoo.vespa.applicationmodel.ServiceStatus;
+import com.yahoo.vespa.applicationmodel.ServiceType;
+import com.yahoo.vespa.service.monitor.ServiceStatusProvider;
+import com.yahoo.vespa.service.monitor.application.ApplicationInstanceGenerator;
+import com.yahoo.vespa.service.monitor.internal.ServiceId;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+
+/**
+ * Responsible for monitoring a whole application using /state/v1/health.
+ *
+ * @author hakon
+ */
+public class ApplicationHealthMonitor implements ServiceStatusProvider, AutoCloseable {
+ public static final String PORT_TAG_STATE = "STATE";
+ public static final String PORT_TAG_HTTP = "HTTP";
+ /** Port tags implying /state/v1/health is served */
+ public static final List<String> PORT_TAGS_HEALTH =
+ Collections.unmodifiableList(Arrays.asList(PORT_TAG_HTTP, PORT_TAG_STATE));
+
+ private final Map<ServiceId, HealthMonitor> healthMonitors;
+
+ public static ApplicationHealthMonitor startMonitoring(ApplicationInfo application) {
+ return new ApplicationHealthMonitor(makeHealthMonitors(application));
+ }
+
+ private ApplicationHealthMonitor(Map<ServiceId, HealthMonitor> healthMonitors) {
+ this.healthMonitors = healthMonitors;
+ }
+
+ @Override
+ public ServiceStatus getStatus(ApplicationId applicationId,
+ ClusterId clusterId,
+ ServiceType serviceType,
+ ConfigId configId) {
+ ServiceId serviceId = new ServiceId(applicationId, clusterId, serviceType, configId);
+ HealthMonitor monitor = healthMonitors.get(serviceId);
+ if (monitor == null) {
+ return ServiceStatus.NOT_CHECKED;
+ }
+
+ return monitor.getStatus();
+ }
+
+ @Override
+ public void close() {
+ healthMonitors.values().forEach(HealthMonitor::close);
+ healthMonitors.clear();
+ }
+
+ private static Map<ServiceId, HealthMonitor> makeHealthMonitors(ApplicationInfo application) {
+ Map<ServiceId, HealthMonitor> healthMonitors = new HashMap<>();
+ for (HostInfo hostInfo : application.getModel().getHosts()) {
+ for (ServiceInfo serviceInfo : hostInfo.getServices()) {
+ for (PortInfo portInfo : serviceInfo.getPorts()) {
+ maybeCreateHealthMonitor(
+ application,
+ hostInfo,
+ serviceInfo,
+ portInfo)
+ .ifPresent(healthMonitor -> healthMonitors.put(
+ ApplicationInstanceGenerator.getServiceId(application, serviceInfo),
+ healthMonitor));
+ }
+ }
+ }
+ return healthMonitors;
+ }
+
+ private static Optional<HealthMonitor> maybeCreateHealthMonitor(
+ ApplicationInfo applicationInfo,
+ HostInfo hostInfo,
+ ServiceInfo serviceInfo,
+ PortInfo portInfo) {
+ if (portInfo.getTags().containsAll(PORT_TAGS_HEALTH)) {
+ HostName hostname = HostName.from(hostInfo.getHostname());
+ HealthEndpoint endpoint = HealthEndpoint.forHttp(hostname, portInfo.getPort());
+ // todo: make HealthMonitor
+ // HealthMonitor healthMonitor = new HealthMonitor(endpoint);
+ // healthMonitor.startMonitoring();
+ return Optional.empty();
+ }
+
+ return Optional.empty();
+ }
+}
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/health/HealthClient.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/health/HealthClient.java
new file mode 100644
index 00000000000..43a02a385be
--- /dev/null
+++ b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/health/HealthClient.java
@@ -0,0 +1,139 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.service.monitor.internal.health;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.yahoo.vespa.athenz.api.AthenzService;
+import com.yahoo.vespa.athenz.identity.ServiceIdentityProvider;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.config.Registry;
+import org.apache.http.config.RegistryBuilder;
+import org.apache.http.conn.ConnectionKeepAliveStrategy;
+import org.apache.http.conn.HttpClientConnectionManager;
+import org.apache.http.conn.socket.ConnectionSocketFactory;
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.impl.conn.BasicHttpClientConnectionManager;
+import org.apache.http.protocol.HttpContext;
+import org.apache.http.util.EntityUtils;
+
+import javax.net.ssl.SSLContext;
+
+/**
+ * @author hakon
+ */
+public class HealthClient implements AutoCloseable, ServiceIdentityProvider.Listener {
+ private static final ObjectMapper mapper = new ObjectMapper();
+ private static final long MAX_CONTENT_LENGTH = 1L << 20; // 1 MB
+ private static final int DEFAULT_TIMEOUT_MILLIS = 1_000;
+
+ private static final ConnectionKeepAliveStrategy KEEP_ALIVE_STRATEGY =
+ new DefaultConnectionKeepAliveStrategy() {
+ @Override
+ public long getKeepAliveDuration(HttpResponse response, HttpContext context) {
+ long keepAlive = super.getKeepAliveDuration(response, context);
+ if (keepAlive == -1) {
+ // Keep connections alive 60 seconds if a keep-alive value
+ // has not be explicitly set by the server
+ keepAlive = 60000;
+ }
+ return keepAlive;
+ }
+ };
+
+ private final HealthEndpoint endpoint;
+
+ private volatile CloseableHttpClient httpClient;
+
+ public HealthClient(HealthEndpoint endpoint) {
+ this.endpoint = endpoint;
+ }
+
+ public void start() {
+ endpoint.getServiceIdentityProvider().ifPresent(provider -> {
+ onCredentialsUpdate(provider.getIdentitySslContext(), null);
+ provider.addIdentityListener(this);
+ });
+ }
+
+ @Override
+ public void onCredentialsUpdate(SSLContext sslContext, AthenzService ignored) {
+ SSLConnectionSocketFactory socketFactory =
+ new SSLConnectionSocketFactory(sslContext, endpoint.getHostnameVerifier().orElse(null));
+
+ Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
+ .register("https", socketFactory)
+ .build();
+
+ HttpClientConnectionManager connectionManager = new BasicHttpClientConnectionManager(registry);
+
+ RequestConfig requestConfig = RequestConfig.custom()
+ .setConnectTimeout(DEFAULT_TIMEOUT_MILLIS) // establishment of connection
+ .setConnectionRequestTimeout(DEFAULT_TIMEOUT_MILLIS) // connection from connection manager
+ .setSocketTimeout(DEFAULT_TIMEOUT_MILLIS) // waiting for data
+ .build();
+
+ this.httpClient = HttpClients.custom()
+ .setKeepAliveStrategy(KEEP_ALIVE_STRATEGY)
+ .setConnectionManager(connectionManager)
+ .disableAutomaticRetries()
+ .setDefaultRequestConfig(requestConfig)
+ .build();
+ }
+
+ public HealthInfo getHealthInfo() {
+ try {
+ return probeHealth();
+ } catch (Exception e) {
+ return HealthInfo.fromException(e);
+ }
+ }
+
+ @Override
+ public void close() {
+ endpoint.getServiceIdentityProvider().ifPresent(provider -> provider.removeIdentityListener(this));
+
+ try {
+ httpClient.close();
+ } catch (Exception e) {
+ // ignore
+ }
+ httpClient = null;
+ }
+
+ private HealthInfo probeHealth() throws Exception {
+ HttpGet httpget = new HttpGet(endpoint.getStateV1HealthUrl().toString());
+ CloseableHttpResponse httpResponse;
+
+ CloseableHttpClient httpClient = this.httpClient;
+ if (httpClient == null) {
+ throw new IllegalStateException("HTTP client has closed");
+ }
+
+ httpResponse = httpClient.execute(httpget);
+
+ int httpStatusCode = httpResponse.getStatusLine().getStatusCode();
+ if (httpStatusCode < 200 || httpStatusCode >= 300) {
+ return HealthInfo.fromBadHttpStatusCode(httpStatusCode);
+ }
+
+ HttpEntity bodyEntity = httpResponse.getEntity();
+ long contentLength = bodyEntity.getContentLength();
+ if (contentLength > MAX_CONTENT_LENGTH) {
+ throw new IllegalArgumentException("Content too long: " + contentLength + " bytes");
+ }
+ String body = EntityUtils.toString(bodyEntity);
+ HealthResponse healthResponse = mapper.readValue(body, HealthResponse.class);
+
+ if (healthResponse.status == null || healthResponse.status.code == null) {
+ return HealthInfo.fromHealthStatusCode(HealthResponse.Status.DEFAULT_STATUS);
+ } else {
+ return HealthInfo.fromHealthStatusCode(healthResponse.status.code);
+ }
+ }
+}
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/health/HealthEndpoint.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/health/HealthEndpoint.java
new file mode 100644
index 00000000000..e9d17a9ab70
--- /dev/null
+++ b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/health/HealthEndpoint.java
@@ -0,0 +1,57 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.service.monitor.internal.health;
+
+import com.yahoo.config.provision.HostName;
+import com.yahoo.vespa.athenz.api.AthenzIdentity;
+import com.yahoo.vespa.athenz.identity.ServiceIdentityProvider;
+import com.yahoo.vespa.athenz.tls.AthenzIdentityVerifier;
+
+import javax.net.ssl.HostnameVerifier;
+import java.net.URL;
+import java.util.Collections;
+import java.util.Optional;
+
+import static com.yahoo.yolean.Exceptions.uncheck;
+
+/**
+ * @author hakon
+ */
+class HealthEndpoint {
+ private final URL url;
+ private final Optional<HostnameVerifier> hostnameVerifier;
+ private final Optional<ServiceIdentityProvider> serviceIdentityProvider;
+
+ static HealthEndpoint forHttp(HostName hostname, int port) {
+ URL url = uncheck(() -> new URL("http", hostname.value(), port, "/state/v1/health"));
+ return new HealthEndpoint(url, Optional.empty(), Optional.empty());
+ }
+
+ static HealthEndpoint forHttps(HostName hostname,
+ int port,
+ ServiceIdentityProvider serviceIdentityProvider,
+ AthenzIdentity remoteIdentity) {
+ URL url = uncheck(() -> new URL("https", hostname.value(), port, "/state/v1/health"));
+ HostnameVerifier peerVerifier = new AthenzIdentityVerifier(Collections.singleton(remoteIdentity));
+ return new HealthEndpoint(url, Optional.of(serviceIdentityProvider), Optional.of(peerVerifier));
+ }
+
+ private HealthEndpoint(URL url,
+ Optional<ServiceIdentityProvider> serviceIdentityProvider,
+ Optional<HostnameVerifier> hostnameVerifier) {
+ this.url = url;
+ this.serviceIdentityProvider = serviceIdentityProvider;
+ this.hostnameVerifier = hostnameVerifier;
+ }
+
+ public URL getStateV1HealthUrl() {
+ return url;
+ }
+
+ public Optional<ServiceIdentityProvider> getServiceIdentityProvider() {
+ return serviceIdentityProvider;
+ }
+
+ public Optional<HostnameVerifier> getHostnameVerifier() {
+ return hostnameVerifier;
+ }
+}
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/health/HealthInfo.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/health/HealthInfo.java
new file mode 100644
index 00000000000..a3fe3cb3106
--- /dev/null
+++ b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/health/HealthInfo.java
@@ -0,0 +1,75 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.service.monitor.internal.health;
+
+import com.yahoo.vespa.applicationmodel.ServiceStatus;
+import com.yahoo.yolean.Exceptions;
+
+import java.time.Instant;
+import java.util.Optional;
+import java.util.OptionalInt;
+
+/**
+ * The result of a health lookup.
+ *
+ * @author hakon
+ */
+public class HealthInfo {
+ public static final String UP_STATUS_CODE = "up";
+
+ private final Optional<Exception> exception;
+ private final OptionalInt httpStatusCode;
+ private final Optional<String> healthStatusCode;
+ private final Instant time;
+
+ static HealthInfo fromException(Exception exception) {
+ return new HealthInfo(Optional.of(exception), OptionalInt.empty(), Optional.empty());
+ }
+
+ static HealthInfo fromBadHttpStatusCode(int httpStatusCode) {
+ return new HealthInfo(Optional.empty(), OptionalInt.of(httpStatusCode), Optional.empty());
+ }
+
+ static HealthInfo fromHealthStatusCode(String healthStatusCode) {
+ return new HealthInfo(Optional.empty(), OptionalInt.empty(), Optional.of(healthStatusCode));
+ }
+
+ static HealthInfo empty() {
+ return new HealthInfo(Optional.empty(), OptionalInt.empty(), Optional.empty());
+ }
+
+ private HealthInfo(Optional<Exception> exception,
+ OptionalInt httpStatusCode,
+ Optional<String> healthStatusCode) {
+ this.exception = exception;
+ this.httpStatusCode = httpStatusCode;
+ this.healthStatusCode = healthStatusCode;
+ this.time = Instant.now();
+ }
+
+ public boolean isHealthy() {
+ return healthStatusCode.map(UP_STATUS_CODE::equals).orElse(false);
+ }
+
+ public ServiceStatus toSerivceStatus() {
+ return isHealthy() ? ServiceStatus.UP : ServiceStatus.DOWN;
+ }
+
+ public Instant time() {
+ return time;
+ }
+
+ @Override
+ public String toString() {
+ if (isHealthy()) {
+ return UP_STATUS_CODE;
+ } else if (healthStatusCode.isPresent()) {
+ return "Bad health status code '" + healthStatusCode.get() + "'";
+ } else if (exception.isPresent()) {
+ return Exceptions.toMessageString(exception.get());
+ } else if (httpStatusCode.isPresent()) {
+ return "Bad HTTP response status code " + httpStatusCode.getAsInt();
+ } else {
+ return "No health info available";
+ }
+ }
+}
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/health/HealthMonitor.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/health/HealthMonitor.java
new file mode 100644
index 00000000000..fd809b32918
--- /dev/null
+++ b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/health/HealthMonitor.java
@@ -0,0 +1,73 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.service.monitor.internal.health;
+
+import com.yahoo.log.LogLevel;
+import com.yahoo.vespa.applicationmodel.ServiceStatus;
+
+import java.time.Duration;
+import java.util.Random;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.logging.Logger;
+
+/**
+ * Used to monitor the health of a single URL endpoint.
+ *
+ * @author hakon
+ */
+public class HealthMonitor implements AutoCloseable {
+ private static final Logger logger = Logger.getLogger(HealthMonitor.class.getName());
+ private static final Duration DELAY = Duration.ofSeconds(20);
+ // About 'static': Javadoc says "Instances of java.util.Random are threadsafe."
+ private static final Random random = new Random();
+
+ private final ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1);
+ private final HealthClient healthClient;
+
+ private volatile HealthInfo lastHealthInfo = HealthInfo.empty();
+
+ public HealthMonitor(HealthEndpoint stateV1HealthEndpoint) {
+ this.healthClient = new HealthClient(stateV1HealthEndpoint);
+ }
+
+ /** For testing. */
+ HealthMonitor(HealthClient healthClient) {
+ this.healthClient = healthClient;
+ }
+
+ public void startMonitoring() {
+ healthClient.start();
+ executor.scheduleWithFixedDelay(
+ this::updateSynchronously,
+ initialDelayInSeconds(DELAY.getSeconds()),
+ DELAY.getSeconds(),
+ TimeUnit.SECONDS);
+ }
+
+ public ServiceStatus getStatus() {
+ // todo: return lastHealthInfo.toServiceStatus();
+ return ServiceStatus.NOT_CHECKED;
+ }
+
+ @Override
+ public void close() {
+ executor.shutdown();
+
+ try {
+ executor.awaitTermination(2, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ logger.log(LogLevel.INFO, "Interrupted while waiting for health monitor termination: " +
+ e.getMessage());
+ }
+
+ healthClient.close();
+ }
+
+ private long initialDelayInSeconds(long maxInitialDelayInSeconds) {
+ return random.nextLong() % maxInitialDelayInSeconds;
+ }
+
+ private void updateSynchronously() {
+ lastHealthInfo = healthClient.getHealthInfo();
+ }
+}
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/health/HealthMonitorManager.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/health/HealthMonitorManager.java
index 5a4b7251ae2..473ef5e3a94 100644
--- a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/health/HealthMonitorManager.java
+++ b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/health/HealthMonitorManager.java
@@ -2,8 +2,8 @@
package com.yahoo.vespa.service.monitor.internal.health;
import com.google.inject.Inject;
+import com.yahoo.cloud.config.ConfigserverConfig;
import com.yahoo.config.model.api.ApplicationInfo;
-import com.yahoo.config.model.api.SuperModel;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.vespa.applicationmodel.ClusterId;
import com.yahoo.vespa.applicationmodel.ConfigId;
@@ -12,19 +12,38 @@ import com.yahoo.vespa.applicationmodel.ServiceType;
import com.yahoo.vespa.service.monitor.application.ZoneApplication;
import com.yahoo.vespa.service.monitor.internal.MonitorManager;
+import java.util.HashMap;
+import java.util.Map;
+
/**
* @author hakon
*/
public class HealthMonitorManager implements MonitorManager {
+ private final Map<ApplicationId, ApplicationHealthMonitor> healthMonitors = new HashMap<>();
+ private final ConfigserverConfig configserverConfig;
+
@Inject
- public HealthMonitorManager() {}
+ public HealthMonitorManager(ConfigserverConfig configserverConfig) {
+ this.configserverConfig = configserverConfig;
+ }
@Override
- public void applicationActivated(SuperModel superModel, ApplicationInfo application) {
+ public void applicationActivated(ApplicationInfo application) {
+ if (applicationMonitored(application.getApplicationId())) {
+ ApplicationHealthMonitor monitor =
+ ApplicationHealthMonitor.startMonitoring(application);
+ healthMonitors.put(application.getApplicationId(), monitor);
+ }
}
@Override
- public void applicationRemoved(SuperModel superModel, ApplicationId id) {
+ public void applicationRemoved(ApplicationId id) {
+ if (applicationMonitored(id)) {
+ ApplicationHealthMonitor monitor = healthMonitors.remove(id);
+ if (monitor != null) {
+ monitor.close();
+ }
+ }
}
@Override
@@ -32,13 +51,18 @@ public class HealthMonitorManager implements MonitorManager {
ClusterId clusterId,
ServiceType serviceType,
ConfigId configId) {
- // TODO: Do proper health check
- if (ZoneApplication.isNodeAdminService(applicationId, clusterId, serviceType)) {
+ if (!configserverConfig.nodeAdminInContainer() &&
+ ZoneApplication.isNodeAdminService(applicationId, clusterId, serviceType)) {
+ // If node admin doesn't run in a JDisc container, it must be monitored with health.
+ // TODO: Do proper health check
return ServiceStatus.UP;
}
- throw new IllegalArgumentException("Health monitoring not implemented for application " +
- applicationId.toShortString() + ", cluster " + clusterId.s() + ", serviceType " +
- serviceType);
+ return ServiceStatus.NOT_CHECKED;
+ }
+
+ private boolean applicationMonitored(ApplicationId id) {
+ // todo: health-check config server
+ return false;
}
}
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/health/HealthResponse.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/health/HealthResponse.java
new file mode 100644
index 00000000000..574523ad564
--- /dev/null
+++ b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/health/HealthResponse.java
@@ -0,0 +1,35 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.service.monitor.internal.health;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.yahoo.text.JSON;
+
+/**
+ * Response entity from /state/v1/health
+ *
+ * @author hakon
+ */
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class HealthResponse {
+ @JsonProperty("status")
+ public Status status = new Status();
+
+ @JsonIgnoreProperties(ignoreUnknown = true)
+ public static class Status {
+ public static final String DEFAULT_STATUS = "down";
+
+ @JsonProperty("code")
+ public String code = DEFAULT_STATUS;
+
+ @Override
+ public String toString() {
+ return "{ \"code\": \"" + JSON.escape(code) + "\" }";
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "{ \"status\": " + status.toString() + " }";
+ }
+}
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/slobrok/SlobrokMonitorManagerImpl.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/slobrok/SlobrokMonitorManagerImpl.java
index aaaab22e742..68958c94dfd 100644
--- a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/slobrok/SlobrokMonitorManagerImpl.java
+++ b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/slobrok/SlobrokMonitorManagerImpl.java
@@ -3,8 +3,6 @@ package com.yahoo.vespa.service.monitor.internal.slobrok;
import com.google.inject.Inject;
import com.yahoo.config.model.api.ApplicationInfo;
-import com.yahoo.config.model.api.SuperModel;
-import com.yahoo.config.model.api.SuperModelListener;
import com.yahoo.config.provision.ApplicationId;
import com.yahoo.jrt.slobrok.api.Mirror;
import com.yahoo.log.LogLevel;
@@ -13,6 +11,7 @@ import com.yahoo.vespa.applicationmodel.ConfigId;
import com.yahoo.vespa.applicationmodel.ServiceStatus;
import com.yahoo.vespa.applicationmodel.ServiceType;
import com.yahoo.vespa.service.monitor.SlobrokApi;
+import com.yahoo.vespa.service.monitor.application.ConfigServerApplication;
import com.yahoo.vespa.service.monitor.internal.MonitorManager;
import java.util.HashMap;
@@ -21,7 +20,7 @@ import java.util.Optional;
import java.util.function.Supplier;
import java.util.logging.Logger;
-public class SlobrokMonitorManagerImpl implements SuperModelListener, SlobrokApi, MonitorManager {
+public class SlobrokMonitorManagerImpl implements SlobrokApi, MonitorManager {
private static final Logger logger =
Logger.getLogger(SlobrokMonitorManagerImpl.class.getName());
@@ -40,7 +39,11 @@ public class SlobrokMonitorManagerImpl implements SuperModelListener, SlobrokApi
}
@Override
- public void applicationActivated(SuperModel superModel, ApplicationInfo application) {
+ public void applicationActivated(ApplicationInfo application) {
+ if (!applicationMonitoredWithSlobrok(application.getApplicationId())) {
+ return;
+ }
+
synchronized (monitor) {
SlobrokMonitor slobrokMonitor = slobrokMonitors.computeIfAbsent(
application.getApplicationId(),
@@ -50,7 +53,11 @@ public class SlobrokMonitorManagerImpl implements SuperModelListener, SlobrokApi
}
@Override
- public void applicationRemoved(SuperModel superModel, ApplicationId id) {
+ public void applicationRemoved(ApplicationId id) {
+ if (!applicationMonitoredWithSlobrok(id)) {
+ return;
+ }
+
synchronized (monitor) {
SlobrokMonitor slobrokMonitor = slobrokMonitors.remove(id);
if (slobrokMonitor == null) {
@@ -79,6 +86,10 @@ public class SlobrokMonitorManagerImpl implements SuperModelListener, SlobrokApi
ClusterId clusterId,
ServiceType serviceType,
ConfigId configId) {
+ if (!applicationMonitoredWithSlobrok(applicationId)) {
+ return ServiceStatus.NOT_CHECKED;
+ }
+
Optional<String> slobrokServiceName = findSlobrokServiceName(serviceType, configId);
if (slobrokServiceName.isPresent()) {
synchronized (monitor) {
@@ -95,6 +106,14 @@ public class SlobrokMonitorManagerImpl implements SuperModelListener, SlobrokApi
}
}
+ private boolean applicationMonitoredWithSlobrok(ApplicationId applicationId) {
+ if (applicationId.equals(ConfigServerApplication.CONFIG_SERVER_APPLICATION.getApplicationId())) {
+ return false;
+ }
+
+ return true;
+ }
+
/**
* Get the Slobrok service name of the service, or empty if the service
* is not registered with Slobrok.
diff --git a/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/application/ConfigServerAppGeneratorTest.java b/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/application/ApplicationInstanceGeneratorTest.java
index 58f99786017..e1d9b728bf8 100644
--- a/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/application/ConfigServerAppGeneratorTest.java
+++ b/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/application/ApplicationInstanceGeneratorTest.java
@@ -1,22 +1,27 @@
// 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.application;
+import com.yahoo.cloud.config.ConfigserverConfig;
+import com.yahoo.config.model.api.ApplicationInfo;
+import com.yahoo.config.provision.Zone;
import com.yahoo.vespa.applicationmodel.ApplicationInstance;
import com.yahoo.vespa.applicationmodel.ServiceStatus;
import com.yahoo.vespa.service.monitor.ServiceStatusProvider;
+import com.yahoo.vespa.service.monitor.internal.ConfigserverUtil;
import org.junit.Test;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
+import static com.yahoo.vespa.service.monitor.application.ConfigServerApplication.CONFIG_SERVER_APPLICATION;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
-public class ConfigServerAppGeneratorTest {
+public class ApplicationInstanceGeneratorTest {
private static final String configServer1 = "cfg1.yahoo.com";
private static final String configServer2 = "cfg2.yahoo.com";
private static final String configServer3 = "cfg3.yahoo.com";
@@ -28,9 +33,16 @@ public class ConfigServerAppGeneratorTest {
private final ServiceStatusProvider statusProvider = mock(ServiceStatusProvider.class);
@Test
- public void toApplicationInstance() throws Exception {
+ public void toApplicationInstance() {
when(statusProvider.getStatus(any(), any(), any(), any())).thenReturn(ServiceStatus.NOT_CHECKED);
- ApplicationInstance applicationInstance = new ConfigServerAppGenerator(configServerList)
+ ConfigserverConfig config = ConfigserverUtil.create(
+ true,
+ configServer1,
+ configServer2,
+ configServer3);
+ Zone zone = mock(Zone.class);
+ ApplicationInfo configServer = CONFIG_SERVER_APPLICATION.makeApplicationInfo(config);
+ ApplicationInstance applicationInstance = new ApplicationInstanceGenerator(configServer, zone)
.makeApplicationInstance(statusProvider);
assertEquals(
diff --git a/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/ConfigserverUtil.java b/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/ConfigserverUtil.java
new file mode 100644
index 00000000000..68a55d41b19
--- /dev/null
+++ b/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/ConfigserverUtil.java
@@ -0,0 +1,44 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.service.monitor.internal;
+
+import com.yahoo.cloud.config.ConfigserverConfig;
+import com.yahoo.config.model.api.ApplicationInfo;
+import com.yahoo.vespa.service.monitor.application.ConfigServerApplication;
+
+/**
+ * @author hakon
+ */
+public class ConfigserverUtil {
+ /** Create a ConfigserverConfig with the given settings. */
+ public static ConfigserverConfig create(
+ boolean nodeAdminInContainer,
+ String configServerHostname1,
+ String configServerHostname2,
+ String configServerHostname3) {
+ return new ConfigserverConfig(
+ new ConfigserverConfig.Builder()
+ .nodeAdminInContainer(nodeAdminInContainer)
+ .zookeeperserver(new ConfigserverConfig.Zookeeperserver.Builder().hostname(configServerHostname1).port(1))
+ .zookeeperserver(new ConfigserverConfig.Zookeeperserver.Builder().hostname(configServerHostname2).port(2))
+ .zookeeperserver(new ConfigserverConfig.Zookeeperserver.Builder().hostname(configServerHostname3).port(3)));
+ }
+
+ public static ConfigserverConfig createExampleConfigserverConfig(boolean nodeAdminInContainer) {
+ return create(nodeAdminInContainer, "cfg1", "cfg2", "cfg3");
+ }
+
+ public static ApplicationInfo makeConfigServerApplicationInfo(
+ String configServerHostname1,
+ String configServerHostname2,
+ String configServerHostname3) {
+ return ConfigServerApplication.CONFIG_SERVER_APPLICATION.makeApplicationInfo(create(
+ true,
+ configServerHostname1,
+ configServerHostname2,
+ configServerHostname3));
+ }
+
+ public static ApplicationInfo makeExampleConfigServer() {
+ return makeConfigServerApplicationInfo("cfg1", "cfg2", "cfg3");
+ }
+}
diff --git a/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/DuperModelTest.java b/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/DuperModelTest.java
new file mode 100644
index 00000000000..0a68b4b0ff7
--- /dev/null
+++ b/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/DuperModelTest.java
@@ -0,0 +1,40 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.service.monitor.internal;
+
+import com.yahoo.cloud.config.ConfigserverConfig;
+import com.yahoo.config.model.api.ApplicationInfo;
+import com.yahoo.config.model.api.SuperModel;
+import com.yahoo.vespa.applicationmodel.ServiceStatus;
+import com.yahoo.vespa.service.monitor.ServiceStatusProvider;
+import com.yahoo.vespa.service.monitor.application.ConfigServerApplication;
+import org.junit.Test;
+
+import java.util.Collections;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+/**
+ * @author hakon
+ */
+public class DuperModelTest {
+ private final ServiceStatusProvider statusProvider = mock(ServiceStatusProvider.class);
+
+ @Test
+ public void toApplicationInstance() {
+ when(statusProvider.getStatus(any(), any(), any(), any())).thenReturn(ServiceStatus.NOT_CHECKED);
+ ConfigserverConfig config = ConfigserverUtil.createExampleConfigserverConfig(true);
+ DuperModel duperModel = new DuperModel(config);
+ SuperModel superModel = mock(SuperModel.class);
+ ApplicationInfo superModelApplicationInfo = mock(ApplicationInfo.class);
+ when(superModel.getAllApplicationInfos()).thenReturn(Collections.singletonList(superModelApplicationInfo));
+ List<ApplicationInfo> applicationInfos = duperModel.getApplicationInfos(superModel);
+ assertEquals(2, applicationInfos.size());
+ assertEquals(ConfigServerApplication.CONFIG_SERVER_APPLICATION.getApplicationId(), applicationInfos.get(0).getApplicationId());
+ assertSame(superModelApplicationInfo, applicationInfos.get(1));
+ }
+}
diff --git a/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/ModelGeneratorTest.java b/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/ModelGeneratorTest.java
index a21691ee4d0..07cfa124434 100644
--- a/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/ModelGeneratorTest.java
+++ b/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/ModelGeneratorTest.java
@@ -1,6 +1,7 @@
// 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.internal;
+import com.yahoo.cloud.config.ConfigserverConfig;
import com.yahoo.config.model.api.SuperModel;
import com.yahoo.config.provision.Environment;
import com.yahoo.config.provision.RegionName;
@@ -15,13 +16,9 @@ import com.yahoo.vespa.service.monitor.application.ConfigServerApplication;
import com.yahoo.vespa.service.monitor.internal.slobrok.SlobrokMonitorManagerImpl;
import org.junit.Test;
-import java.util.Collections;
import java.util.Iterator;
-import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.any;
@@ -35,13 +32,13 @@ public class ModelGeneratorTest {
private final int PORT = 2;
@Test
- public void toApplicationModelWithConfigServerApplication() throws Exception {
- SuperModel superModel =
- ExampleModel.createExampleSuperModelWithOneRpcPort(HOSTNAME, PORT);
+ public void toApplicationModel() throws Exception {
+ SuperModel superModel = ExampleModel.createExampleSuperModelWithOneRpcPort(HOSTNAME, PORT);
- List<String> configServerHosts = Stream.of("cfg1", "cfg2", "cfg3")
- .collect(Collectors.toList());
- ModelGenerator modelGenerator = new ModelGenerator(configServerHosts);
+ ConfigserverConfig config = ConfigserverUtil.create(
+ true, "cfg1", "cfg2", "cfg3");
+ DuperModel duperModel = new DuperModel(config);
+ ModelGenerator modelGenerator = new ModelGenerator();
Zone zone = new Zone(Environment.from(ENVIRONMENT), RegionName.from(REGION));
@@ -51,7 +48,7 @@ public class ModelGeneratorTest {
ServiceModel serviceModel =
modelGenerator.toServiceModel(
- superModel,
+ duperModel.getApplicationInfos(superModel),
zone,
slobrokMonitorManager);
@@ -78,32 +75,6 @@ public class ModelGeneratorTest {
}
}
- @Test
- public void toApplicationModel() throws Exception {
- SuperModel superModel =
- ExampleModel.createExampleSuperModelWithOneRpcPort(HOSTNAME, PORT);
- ModelGenerator modelGenerator = new ModelGenerator(Collections.emptyList());
-
- Zone zone = new Zone(Environment.from(ENVIRONMENT), RegionName.from(REGION));
-
- SlobrokMonitorManagerImpl slobrokMonitorManager = mock(SlobrokMonitorManagerImpl.class);
- when(slobrokMonitorManager.getStatus(any(), any(), any(), any()))
- .thenReturn(ServiceStatus.UP);
-
- ServiceModel serviceModel =
- modelGenerator.toServiceModel(
- superModel,
- zone,
- slobrokMonitorManager);
-
- Map<ApplicationInstanceReference,
- ApplicationInstance> applicationInstances =
- serviceModel.getAllApplicationInstances();
-
- assertEquals(1, applicationInstances.size());
- verifyOtherApplication(applicationInstances.values().iterator().next());
- }
-
private void verifyOtherApplication(ApplicationInstance applicationInstance) {
assertEquals(String.format("%s:%s:%s:%s:%s",
ExampleModel.TENANT,
diff --git a/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/SuperModelListenerImplTest.java b/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/SuperModelListenerImplTest.java
index 83bad0ddb2a..eb6d6d583f7 100644
--- a/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/SuperModelListenerImplTest.java
+++ b/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/SuperModelListenerImplTest.java
@@ -14,6 +14,7 @@ import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -22,11 +23,13 @@ public class SuperModelListenerImplTest {
public void sanityCheck() {
SlobrokMonitorManagerImpl slobrokMonitorManager = mock(SlobrokMonitorManagerImpl.class);
ServiceMonitorMetrics metrics = mock(ServiceMonitorMetrics.class);
+ DuperModel duperModel = mock(DuperModel.class);
ModelGenerator modelGenerator = mock(ModelGenerator.class);
Zone zone = mock(Zone.class);
SuperModelListenerImpl listener = new SuperModelListenerImpl(
slobrokMonitorManager,
metrics,
+ duperModel,
modelGenerator,
zone);
@@ -38,13 +41,15 @@ public class SuperModelListenerImplTest {
ApplicationInfo application2 = mock(ApplicationInfo.class);
List<ApplicationInfo> applications = Stream.of(application1, application2)
.collect(Collectors.toList());
- when(superModel.getAllApplicationInfos()).thenReturn(applications);
+ when(duperModel.getApplicationInfos(superModel)).thenReturn(applications);
listener.start(superModelProvider);
- verify(slobrokMonitorManager).applicationActivated(superModel, application1);
- verify(slobrokMonitorManager).applicationActivated(superModel, application2);
+ verify(duperModel, times(1)).getApplicationInfos(superModel);
+ verify(slobrokMonitorManager).applicationActivated(application1);
+ verify(slobrokMonitorManager).applicationActivated(application2);
ServiceModel serviceModel = listener.get();
- verify(modelGenerator).toServiceModel(superModel, zone, slobrokMonitorManager);
+ verify(duperModel, times(2)).getApplicationInfos(superModel);
+ verify(modelGenerator).toServiceModel(applications, zone, slobrokMonitorManager);
}
} \ No newline at end of file
diff --git a/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/UnionMonitorManagerTest.java b/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/UnionMonitorManagerTest.java
index b7c3ed8e1e1..79916e43712 100644
--- a/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/UnionMonitorManagerTest.java
+++ b/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/UnionMonitorManagerTest.java
@@ -1,95 +1,44 @@
// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.service.monitor.internal;
-import com.yahoo.cloud.config.ConfigserverConfig;
-import com.yahoo.config.provision.ApplicationId;
-import com.yahoo.vespa.applicationmodel.ClusterId;
import com.yahoo.vespa.applicationmodel.ConfigId;
-import com.yahoo.vespa.applicationmodel.ServiceType;
+import com.yahoo.vespa.applicationmodel.ServiceStatus;
import com.yahoo.vespa.service.monitor.internal.health.HealthMonitorManager;
import com.yahoo.vespa.service.monitor.internal.slobrok.SlobrokMonitorManagerImpl;
import org.junit.Test;
import static com.yahoo.vespa.applicationmodel.ClusterId.NODE_ADMIN;
+import static com.yahoo.vespa.applicationmodel.ServiceStatus.*;
+import static com.yahoo.vespa.applicationmodel.ServiceStatus.NOT_CHECKED;
+import static com.yahoo.vespa.applicationmodel.ServiceStatus.UP;
import static com.yahoo.vespa.applicationmodel.ServiceType.CONTAINER;
import static com.yahoo.vespa.service.monitor.application.ZoneApplication.ZONE_APPLICATION_ID;
+import static org.junit.Assert.assertSame;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
public class UnionMonitorManagerTest {
- @Test
- public void nodeAdminInContainer() {
- testWith(
- true,
- ZONE_APPLICATION_ID,
- NODE_ADMIN,
- CONTAINER,
- 1,
- 0);
- }
-
- @Test
- public void nodeAdminOutsideContainer() {
- boolean inContainer = false;
-
- // When nodeAdminInContainer is set, then only the node admin cluster should use health
- testWith(
- inContainer,
- ZONE_APPLICATION_ID,
- NODE_ADMIN,
- CONTAINER,
- 0,
- 1);
-
- testWith(
- inContainer,
- ApplicationId.fromSerializedForm("a:b:default"),
- NODE_ADMIN,
- CONTAINER,
- 1,
- 0);
+ private final SlobrokMonitorManagerImpl slobrokMonitorManager = mock(SlobrokMonitorManagerImpl.class);
+ private final HealthMonitorManager healthMonitorManager = mock(HealthMonitorManager.class);
- testWith(
- inContainer,
- ZONE_APPLICATION_ID,
- new ClusterId("foo"),
- CONTAINER,
- 1,
- 0);
+ private final UnionMonitorManager manager = new UnionMonitorManager(
+ slobrokMonitorManager,
+ healthMonitorManager);
- testWith(
- inContainer,
- ZONE_APPLICATION_ID,
- NODE_ADMIN,
- new ServiceType("foo"),
- 1,
- 0);
+ @Test
+ public void verifyHealthTakesPriority() {
+ testWith(UP, DOWN, UP);
+ testWith(NOT_CHECKED, DOWN, DOWN);
+ testWith(NOT_CHECKED, NOT_CHECKED, NOT_CHECKED);
}
- private void testWith(boolean nodeAdminInContainer,
- ApplicationId applicationId,
- ClusterId clusterId,
- ServiceType serviceType,
- int expectedSlobrokCalls,
- int expectedHealthCalls) {
- SlobrokMonitorManagerImpl slobrokMonitorManager = mock(SlobrokMonitorManagerImpl.class);
- HealthMonitorManager healthMonitorManager = mock(HealthMonitorManager.class);
-
- ConfigserverConfig.Builder builder = new ConfigserverConfig.Builder();
- builder.nodeAdminInContainer(nodeAdminInContainer);
- ConfigserverConfig config = new ConfigserverConfig(builder);
-
-
- UnionMonitorManager manager = new UnionMonitorManager(
- slobrokMonitorManager,
- healthMonitorManager,
- config);
-
- manager.getStatus(applicationId, clusterId, serviceType, new ConfigId("config-id"));
-
- verify(slobrokMonitorManager, times(expectedSlobrokCalls)).getStatus(any(), any(), any(), any());
- verify(healthMonitorManager, times(expectedHealthCalls)).getStatus(any(), any(), any(), any());
+ private void testWith(ServiceStatus healthStatus,
+ ServiceStatus slobrokStatus,
+ ServiceStatus expectedStatus) {
+ when(healthMonitorManager.getStatus(any(), any(), any(), any())).thenReturn(healthStatus);
+ when(slobrokMonitorManager.getStatus(any(), any(), any(), any())).thenReturn(slobrokStatus);
+ ServiceStatus status = manager.getStatus(ZONE_APPLICATION_ID, NODE_ADMIN, CONTAINER, new ConfigId("config-id"));
+ assertSame(expectedStatus, status);
}
} \ No newline at end of file
diff --git a/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/health/ApplicationHealthMonitorTest.java b/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/health/ApplicationHealthMonitorTest.java
new file mode 100644
index 00000000000..51b0503565f
--- /dev/null
+++ b/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/health/ApplicationHealthMonitorTest.java
@@ -0,0 +1,24 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.service.monitor.internal.health;
+
+import com.yahoo.vespa.applicationmodel.ServiceStatus;
+import com.yahoo.vespa.service.monitor.application.ConfigServerApplication;
+import com.yahoo.vespa.service.monitor.internal.ConfigserverUtil;
+import org.junit.Test;
+
+import static com.yahoo.vespa.applicationmodel.ServiceStatus.NOT_CHECKED;
+import static org.junit.Assert.assertEquals;
+
+public class ApplicationHealthMonitorTest {
+ @Test
+ public void sanityCheck() {
+ ApplicationHealthMonitor monitor = ApplicationHealthMonitor.startMonitoring(
+ ConfigserverUtil.makeExampleConfigServer());
+ ServiceStatus status = monitor.getStatus(
+ ConfigServerApplication.CONFIG_SERVER_APPLICATION.getApplicationId(),
+ ConfigServerApplication.CLUSTER_ID,
+ ConfigServerApplication.SERVICE_TYPE,
+ ConfigServerApplication.configIdFrom(0));
+ assertEquals(NOT_CHECKED, status);
+ }
+} \ No newline at end of file
diff --git a/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/health/HealthMonitorManagerTest.java b/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/health/HealthMonitorManagerTest.java
new file mode 100644
index 00000000000..97963393268
--- /dev/null
+++ b/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/health/HealthMonitorManagerTest.java
@@ -0,0 +1,49 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.service.monitor.internal.health;
+
+import com.yahoo.cloud.config.ConfigserverConfig;
+import com.yahoo.config.model.api.ApplicationInfo;
+import com.yahoo.vespa.applicationmodel.ClusterId;
+import com.yahoo.vespa.applicationmodel.ConfigId;
+import com.yahoo.vespa.applicationmodel.ServiceStatus;
+import com.yahoo.vespa.applicationmodel.ServiceType;
+import com.yahoo.vespa.service.monitor.application.ZoneApplication;
+import com.yahoo.vespa.service.monitor.internal.ConfigserverUtil;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class HealthMonitorManagerTest {
+ @Test
+ public void addRemove() {
+ ConfigserverConfig config = ConfigserverUtil.createExampleConfigserverConfig(true);
+ HealthMonitorManager manager = new HealthMonitorManager(config);
+ ApplicationInfo applicationInfo = ConfigserverUtil.makeExampleConfigServer();
+ manager.applicationActivated(applicationInfo);
+ manager.applicationRemoved(applicationInfo.getApplicationId());
+ }
+
+ @Test
+ public void withNodeAdmin() {
+ ConfigserverConfig config = ConfigserverUtil.createExampleConfigserverConfig(true);
+ HealthMonitorManager manager = new HealthMonitorManager(config);
+ ServiceStatus status = manager.getStatus(
+ ZoneApplication.ZONE_APPLICATION_ID,
+ ClusterId.NODE_ADMIN,
+ ServiceType.CONTAINER,
+ new ConfigId("config-id-1"));
+ assertEquals(ServiceStatus.NOT_CHECKED, status);
+ }
+
+ @Test
+ public void withHostAdmin() {
+ ConfigserverConfig config = ConfigserverUtil.createExampleConfigserverConfig(false);
+ HealthMonitorManager manager = new HealthMonitorManager(config);
+ ServiceStatus status = manager.getStatus(
+ ZoneApplication.ZONE_APPLICATION_ID,
+ ClusterId.NODE_ADMIN,
+ ServiceType.CONTAINER,
+ new ConfigId("config-id-1"));
+ assertEquals(ServiceStatus.UP, status);
+ }
+} \ No newline at end of file
diff --git a/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/health/HealthMonitorTest.java b/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/health/HealthMonitorTest.java
new file mode 100644
index 00000000000..cca1530ad97
--- /dev/null
+++ b/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/health/HealthMonitorTest.java
@@ -0,0 +1,21 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.service.monitor.internal.health;
+
+import com.yahoo.vespa.applicationmodel.ServiceStatus;
+import org.junit.Test;
+
+import java.net.MalformedURLException;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+
+public class HealthMonitorTest {
+ @Test
+ public void basicTests() throws MalformedURLException {
+ HealthClient healthClient = mock(HealthClient.class);
+ try (HealthMonitor monitor = new HealthMonitor(healthClient)) {
+ monitor.startMonitoring();
+ assertEquals(ServiceStatus.NOT_CHECKED, monitor.getStatus());
+ }
+ }
+} \ No newline at end of file
diff --git a/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/slobrok/SlobrokMonitorManagerImplTest.java b/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/slobrok/SlobrokMonitorManagerImplTest.java
index 8e4443df83b..a567559980b 100644
--- a/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/slobrok/SlobrokMonitorManagerImplTest.java
+++ b/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/slobrok/SlobrokMonitorManagerImplTest.java
@@ -2,7 +2,7 @@
package com.yahoo.vespa.service.monitor.internal.slobrok;
import com.yahoo.config.model.api.ApplicationInfo;
-import com.yahoo.config.model.api.SuperModel;
+import com.yahoo.config.provision.ApplicationId;
import com.yahoo.vespa.applicationmodel.ClusterId;
import com.yahoo.vespa.applicationmodel.ConfigId;
import com.yahoo.vespa.applicationmodel.ServiceStatus;
@@ -28,18 +28,19 @@ public class SlobrokMonitorManagerImplTest {
private final SlobrokMonitorManagerImpl slobrokMonitorManager =
new SlobrokMonitorManagerImpl(slobrokMonitorFactory);
private final SlobrokMonitor slobrokMonitor = mock(SlobrokMonitor.class);
- private final SuperModel superModel = mock(SuperModel.class);
+ private final ApplicationId applicationId = ApplicationId.from("tenant", "app", "instance");
private final ApplicationInfo application = mock(ApplicationInfo.class);
private final ClusterId clusterId = new ClusterId("cluster-id");
@Before
public void setup() {
when(slobrokMonitorFactory.get()).thenReturn(slobrokMonitor);
+ when(application.getApplicationId()).thenReturn(applicationId);
}
@Test
public void testActivationOfApplication() {
- slobrokMonitorManager.applicationActivated(superModel, application);
+ slobrokMonitorManager.applicationActivated(application);
verify(slobrokMonitorFactory, times(1)).get();
}
@@ -51,14 +52,14 @@ public class SlobrokMonitorManagerImplTest {
@Test
public void testGetStatus_ApplicationInSlobrok() {
- slobrokMonitorManager.applicationActivated(superModel, application);
+ slobrokMonitorManager.applicationActivated(application);
when(slobrokMonitor.registeredInSlobrok("config.id")).thenReturn(true);
assertEquals(ServiceStatus.UP, getStatus("topleveldispatch"));
}
@Test
public void testGetStatus_ServiceNotInSlobrok() {
- slobrokMonitorManager.applicationActivated(superModel, application);
+ slobrokMonitorManager.applicationActivated(application);
when(slobrokMonitor.registeredInSlobrok("config.id")).thenReturn(false);
assertEquals(ServiceStatus.DOWN, getStatus("topleveldispatch"));
}