summaryrefslogtreecommitdiffstats
path: root/service-monitor
diff options
context:
space:
mode:
authorHåkon Hallingstad <hakon@oath.com>2017-09-28 16:21:45 +0200
committerHåkon Hallingstad <hakon@oath.com>2017-09-28 16:21:45 +0200
commit2b145fd26c0b6a59d200a10c1bc107a92f6829f3 (patch)
tree146bc9182fc265508d1913c5a4ef06edc201c4af /service-monitor
parent12694e5879ae0261d1d92e81f7cb900d31a4a051 (diff)
Map SuperModel to ServiceModel
Diffstat (limited to 'service-monitor')
-rw-r--r--service-monitor/pom.xml12
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/monitor/ConfigServerApplication.java52
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/monitor/ModelGenerator.java119
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/monitor/ServiceModel.java34
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/monitor/SlobrokMonitor2.java122
-rw-r--r--service-monitor/src/test/java/com/yahoo/vespa/service/monitor/ConfigServerApplicationTest.java61
-rw-r--r--service-monitor/src/test/java/com/yahoo/vespa/service/monitor/ExampleModel.java65
-rw-r--r--service-monitor/src/test/java/com/yahoo/vespa/service/monitor/ModelGeneratorTest.java107
-rw-r--r--service-monitor/src/test/java/com/yahoo/vespa/service/monitor/SlobrokMonitor2Test.java58
9 files changed, 630 insertions, 0 deletions
diff --git a/service-monitor/pom.xml b/service-monitor/pom.xml
index 8d8518f2b20..13602c60cf8 100644
--- a/service-monitor/pom.xml
+++ b/service-monitor/pom.xml
@@ -54,6 +54,18 @@
<scope>compile</scope>
</dependency>
<dependency>
+ <groupId>com.yahoo.vespa</groupId>
+ <artifactId>config-model-api</artifactId>
+ <version>${project.version}</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.yahoo.vespa</groupId>
+ <artifactId>config-provisioning</artifactId>
+ <version>${project.version}</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
<groupId>org.json4s</groupId>
<artifactId>json4s-native_${scala.major-version}</artifactId>
<scope>test</scope>
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/ConfigServerApplication.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/ConfigServerApplication.java
new file mode 100644
index 00000000000..5cffcec82b8
--- /dev/null
+++ b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/ConfigServerApplication.java
@@ -0,0 +1,52 @@
+// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.service.monitor;
+
+import com.yahoo.vespa.applicationmodel.ApplicationInstance;
+import com.yahoo.vespa.applicationmodel.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.ServiceInstance;
+import com.yahoo.vespa.applicationmodel.ServiceType;
+import com.yahoo.vespa.applicationmodel.TenantId;
+
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * A service/application model of the config server with health status.
+ */
+public class ConfigServerApplication {
+ public static final ClusterId CLUSTER_ID = new ClusterId("zone-config-servers");
+ public static final ServiceType SERVICE_TYPE = new ServiceType("configserver");
+ public static final TenantId TENANT_ID = new TenantId("hosted-vespa");
+ public static final ApplicationInstanceId APPLICATION_INSTANCE_ID = new ApplicationInstanceId("zone-config-servers");
+ public static final String CONFIG_ID_PREFIX = "configid.";
+
+ ApplicationInstance<ServiceMonitorStatus> toApplicationInstance(List<String> hostnames) {
+ Set<ServiceInstance<ServiceMonitorStatus>> serviceInstances = hostnames.stream()
+ .map(hostname -> new ServiceInstance<>(
+ new ConfigId(CONFIG_ID_PREFIX + hostname),
+ new HostName(hostname),
+ ServiceMonitorStatus.NOT_CHECKED))
+ .collect(Collectors.toSet());
+
+ ServiceCluster<ServiceMonitorStatus> serviceCluster = new ServiceCluster<>(
+ CLUSTER_ID,
+ SERVICE_TYPE,
+ serviceInstances);
+
+ Set<ServiceCluster<ServiceMonitorStatus>> serviceClusters =
+ Stream.of(serviceCluster).collect(Collectors.toSet());
+
+ ApplicationInstance<ServiceMonitorStatus> applicationInstance = new ApplicationInstance<>(
+ TENANT_ID,
+ APPLICATION_INSTANCE_ID,
+ serviceClusters);
+
+ return applicationInstance;
+ }
+}
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/ModelGenerator.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/ModelGenerator.java
new file mode 100644
index 00000000000..ef418f99d47
--- /dev/null
+++ b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/ModelGenerator.java
@@ -0,0 +1,119 @@
+// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.service.monitor;
+
+import com.yahoo.config.model.api.ApplicationInfo;
+import com.yahoo.config.model.api.HostInfo;
+import com.yahoo.config.model.api.ServiceInfo;
+import com.yahoo.config.model.api.SuperModel;
+import com.yahoo.config.provision.Zone;
+import com.yahoo.vespa.applicationmodel.ApplicationInstance;
+import com.yahoo.vespa.applicationmodel.ApplicationInstanceId;
+import com.yahoo.vespa.applicationmodel.ApplicationInstanceReference;
+import com.yahoo.vespa.applicationmodel.ClusterId;
+import com.yahoo.vespa.applicationmodel.ConfigId;
+import com.yahoo.vespa.applicationmodel.HostName;
+import com.yahoo.vespa.applicationmodel.ServiceCluster;
+import com.yahoo.vespa.applicationmodel.ServiceClusterKey;
+import com.yahoo.vespa.applicationmodel.ServiceInstance;
+import com.yahoo.vespa.applicationmodel.ServiceType;
+import com.yahoo.vespa.applicationmodel.TenantId;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * Util to convert SuperModel to ServiceModel and application model classes
+ */
+public class ModelGenerator {
+ public static final String CLUSTER_ID_PROPERTY_NAME = "clustername";
+
+ ServiceModel toServiceModel(
+ SuperModel superModel,
+ Zone zone,
+ List<String> configServerHosts,
+ SlobrokMonitor2 slobrokMonitor) {
+ Map<ApplicationInstanceReference, ApplicationInstance<ServiceMonitorStatus>> applicationInstances = new HashMap<>();
+
+ for (ApplicationInfo applicationInfo : superModel.getAllApplicationInfos()) {
+ ApplicationInstance<ServiceMonitorStatus> applicationInstance = toApplicationInstance(
+ applicationInfo,
+ zone,
+ slobrokMonitor);
+ applicationInstances.put(applicationInstance.reference(), applicationInstance);
+ }
+
+ // The config server is part of the service model (but not super model)
+ ConfigServerApplication configServerApplication = new ConfigServerApplication();
+ ApplicationInstance<ServiceMonitorStatus> configServerApplicationInstance =
+ configServerApplication.toApplicationInstance(configServerHosts);
+ applicationInstances.put(configServerApplicationInstance.reference(), configServerApplicationInstance);
+
+ return new ServiceModel(applicationInstances);
+ }
+
+ ApplicationInstance<ServiceMonitorStatus> toApplicationInstance(
+ ApplicationInfo applicationInfo,
+ Zone zone,
+ SlobrokMonitor2 slobrokMonitor) {
+ Map<ServiceClusterKey, Set<ServiceInstance<ServiceMonitorStatus>>> 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<ServiceMonitorStatus> serviceInstance =
+ toServiceInstance(serviceInfo, hostName, slobrokMonitor);
+
+ if (!groupedServiceInstances.containsKey(serviceClusterKey)) {
+ groupedServiceInstances.put(serviceClusterKey, new HashSet<>());
+ }
+ groupedServiceInstances.get(serviceClusterKey).add(serviceInstance);
+ }
+ }
+
+ Set<ServiceCluster<ServiceMonitorStatus>> serviceClusters = groupedServiceInstances.entrySet().stream()
+ .map(entry -> new ServiceCluster<>(
+ entry.getKey().clusterId(),
+ entry.getKey().serviceType(),
+ entry.getValue()))
+ .collect(Collectors.toSet());
+
+ ApplicationInstance<ServiceMonitorStatus> applicationInstance = new ApplicationInstance<>(
+ new TenantId(applicationInfo.getApplicationId().tenant().toString()),
+ toApplicationInstanceId(applicationInfo, zone),
+ serviceClusters);
+
+ return applicationInstance;
+ }
+
+ ServiceClusterKey toServiceClusterKey(ServiceInfo serviceInfo) {
+ ClusterId clusterId = new ClusterId(serviceInfo.getProperty(CLUSTER_ID_PROPERTY_NAME).orElse(""));
+ ServiceType serviceType = toServiceType(serviceInfo);
+ return new ServiceClusterKey(clusterId, serviceType);
+ }
+
+ ServiceInstance<ServiceMonitorStatus> toServiceInstance(
+ ServiceInfo serviceInfo,
+ HostName hostName,
+ SlobrokMonitor2 slobrokMonitor) {
+ ConfigId configId = new ConfigId(serviceInfo.getConfigId());
+ ServiceMonitorStatus serviceStatus = slobrokMonitor.getStatus(toServiceType(serviceInfo), configId);
+ return new ServiceInstance<>(configId, hostName,serviceStatus);
+ }
+
+ 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()));
+ }
+
+ ServiceType toServiceType(ServiceInfo serviceInfo) {
+ return new ServiceType(serviceInfo.getServiceType());
+ }
+}
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/ServiceModel.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/ServiceModel.java
new file mode 100644
index 00000000000..b39af0238c5
--- /dev/null
+++ b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/ServiceModel.java
@@ -0,0 +1,34 @@
+// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.service.monitor;
+
+import com.yahoo.vespa.applicationmodel.ApplicationInstance;
+import com.yahoo.vespa.applicationmodel.ApplicationInstanceReference;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Optional;
+
+/**
+ * The ServiceModel is almost a mirror of the SuperModel, except that it
+ * also gives ServiceMonitorStatus on each service, and there may be
+ * artificial applications like the config server "application".
+ */
+// @Immutable
+public class ServiceModel {
+ private final Map<ApplicationInstanceReference,
+ ApplicationInstance<ServiceMonitorStatus>> applications;
+
+ ServiceModel(Map<ApplicationInstanceReference,
+ ApplicationInstance<ServiceMonitorStatus>> applications) {
+ this.applications = Collections.unmodifiableMap(applications);
+ }
+
+ Map<ApplicationInstanceReference,
+ ApplicationInstance<ServiceMonitorStatus>> getAllApplicationInstances() {
+ return applications;
+ }
+
+ Optional<ApplicationInstance<ServiceMonitorStatus>> getApplicationInstance(ApplicationInstanceReference reference) {
+ return Optional.ofNullable(applications.get(reference));
+ }
+}
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/SlobrokMonitor2.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/SlobrokMonitor2.java
new file mode 100644
index 00000000000..f0cda0eba37
--- /dev/null
+++ b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/SlobrokMonitor2.java
@@ -0,0 +1,122 @@
+// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.service.monitor;
+
+import com.yahoo.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.model.api.SuperModel;
+import com.yahoo.jrt.Spec;
+import com.yahoo.jrt.Supervisor;
+import com.yahoo.jrt.Transport;
+import com.yahoo.jrt.slobrok.api.Mirror;
+import com.yahoo.jrt.slobrok.api.SlobrokList;
+import com.yahoo.log.LogLevel;
+import com.yahoo.vespa.applicationmodel.ConfigId;
+import com.yahoo.vespa.applicationmodel.ServiceType;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import java.util.logging.Logger;
+
+public class SlobrokMonitor2 implements AutoCloseable {
+ public static final String SLOBROK_RPC_PORT_TAG = "rpc";
+
+ private static final Logger log = Logger.getLogger(SlobrokMonitor2.class.getName());
+
+ private final SlobrokList slobrokList;
+ private final Mirror mirror;
+
+ SlobrokMonitor2() {
+ this(new SlobrokList());
+ }
+
+ // Package-private for testing.
+ SlobrokMonitor2(SlobrokList slobrokList, Mirror mirror) {
+ this.slobrokList = slobrokList;
+ this.mirror = mirror;
+ }
+
+ private SlobrokMonitor2(SlobrokList slobrokList) {
+ this(slobrokList, new Mirror(new Supervisor(new Transport()), slobrokList));
+ }
+
+ void updateSlobrokList(SuperModel superModel) {
+ // If we ever need to optimize this method, then we should make this class
+ // have a Map<ApplicationId, List<String>>, mapping each application to
+ // its list of specs. Then, whenever a single application is activated or removed,
+ // only modify that List<String>.
+
+ List<String> slobrokSpecs = new ArrayList<>();
+
+ for (ApplicationInfo application : superModel.getAllApplicationInfos()) {
+ for (HostInfo host : application.getModel().getHosts()) {
+ for (ServiceInfo service : host.getServices()) {
+ for (PortInfo port : service.getPorts()) {
+ if (port.getTags().contains(SLOBROK_RPC_PORT_TAG)) {
+ Spec spec = new Spec(host.getHostname(), port.getPort());
+ slobrokSpecs.add(spec.toString());
+ }
+ }
+ }
+ }
+ }
+
+ slobrokList.setup(slobrokSpecs.toArray(new String[0]));
+ }
+
+ ServiceMonitorStatus getStatus(ServiceType serviceType, ConfigId configId) {
+ Optional<String> slobrokServiceName = lookup(serviceType, configId);
+ if (slobrokServiceName.isPresent()) {
+ if (mirror.lookup(slobrokServiceName.get()).length != 0) {
+ return ServiceMonitorStatus.UP;
+ } else {
+ return ServiceMonitorStatus.DOWN;
+ }
+ } else {
+ return ServiceMonitorStatus.NOT_CHECKED;
+ }
+ }
+
+ @Override
+ public void close() {
+ mirror.shutdown();
+ }
+
+ // Package-private for testing
+ Optional<String> lookup(ServiceType serviceType, ConfigId configId) {
+ switch (serviceType.s()) {
+ case "adminserver":
+ case "config-sentinel":
+ case "configproxy":
+ case "configserver":
+ case "filedistributorservice":
+ case "logd":
+ case "logserver":
+ case "metricsproxy":
+ case "slobrok":
+ case "transactionlogserver":
+ case "ytracecleaner":
+ return Optional.empty();
+
+ case "topleveldispatch":
+ return Optional.of(configId.s());
+
+ case "qrserver":
+ case "container":
+ case "docprocservice":
+ case "container-clustercontroller":
+ return Optional.of("vespa/service/" + configId.s());
+
+ case "searchnode": //TODO: handle only as storagenode instead of both as searchnode/storagenode
+ return Optional.of(configId.s() + "/realtimecontroller");
+ case "distributor":
+ case "storagenode":
+ return Optional.of("storage/cluster." + configId.s());
+ default:
+ log.log(LogLevel.DEBUG, "Unknown service type " + serviceType.s() + " with config id " + configId.s());
+ return Optional.empty();
+ }
+ }
+}
diff --git a/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/ConfigServerApplicationTest.java b/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/ConfigServerApplicationTest.java
new file mode 100644
index 00000000000..ec91507c846
--- /dev/null
+++ b/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/ConfigServerApplicationTest.java
@@ -0,0 +1,61 @@
+// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.service.monitor;
+
+import com.yahoo.vespa.applicationmodel.ApplicationInstance;
+import org.junit.Test;
+
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class ConfigServerApplicationTest {
+ private static final String configServer1 = "cfg1.yahoo.com";
+ private static final String configServer2 = "cfg2.yahoo.com";
+ private static final String configServer3 = "cfg3.yahoo.com";
+ private static final List<String> configServerList = Stream.of(
+ configServer1,
+ configServer2,
+ configServer3).collect(Collectors.toList());
+
+ @Test
+ public void toApplicationInstance() throws Exception {
+ ConfigServerApplication application = new ConfigServerApplication();
+ ApplicationInstance<ServiceMonitorStatus> applicationInstance =
+ application.toApplicationInstance(configServerList);
+
+ // Backward compatibility check
+ assertEquals(
+ SlobrokAndConfigIntersector.configServerApplicationInstanceId(),
+ applicationInstance.applicationInstanceId());
+ assertEquals(
+ SlobrokAndConfigIntersector.syntheticHostedVespaTenantId(),
+ applicationInstance.tenantId());
+
+ assertEquals(
+ ConfigServerApplication.TENANT_ID.toString() +
+ ":" + ConfigServerApplication.APPLICATION_INSTANCE_ID,
+ applicationInstance.reference().toString());
+
+ assertEquals(
+ ConfigServerApplication.CLUSTER_ID,
+ applicationInstance.serviceClusters().iterator().next().clusterId());
+
+ assertEquals(
+ ServiceMonitorStatus.NOT_CHECKED,
+ applicationInstance
+ .serviceClusters().iterator().next()
+ .serviceInstances().iterator().next()
+ .serviceStatus());
+
+ assertTrue(configServerList.contains(
+ applicationInstance
+ .serviceClusters().iterator().next()
+ .serviceInstances().iterator().next()
+ .hostName()
+ .toString()));
+ }
+
+} \ No newline at end of file
diff --git a/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/ExampleModel.java b/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/ExampleModel.java
new file mode 100644
index 00000000000..d9766d65d3f
--- /dev/null
+++ b/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/ExampleModel.java
@@ -0,0 +1,65 @@
+// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.service.monitor;
+
+import com.yahoo.config.model.api.ApplicationInfo;
+import com.yahoo.config.model.api.HostInfo;
+import com.yahoo.config.model.api.Model;
+import com.yahoo.config.model.api.PortInfo;
+import com.yahoo.config.model.api.ServiceInfo;
+import com.yahoo.config.model.api.SuperModel;
+import com.yahoo.config.provision.ApplicationId;
+import com.yahoo.config.provision.ApplicationName;
+import com.yahoo.config.provision.InstanceName;
+import com.yahoo.config.provision.TenantName;
+
+import java.util.HashMap;
+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.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class ExampleModel {
+
+ static final String CLUSTER_ID = "cluster-id";
+ static final String SERVICE_NAME = "service-name";
+ static final String SERVICE_TYPE = "service-type";
+ static final String CONFIG_ID = "config-id";
+ static final String TENANT = "tenant";
+ static final String APPLICATION_NAME = "application";
+ public static final String INSTANCE_NAME = "default";
+
+ static SuperModel createExampleSuperModelWithOneRpcPort(String hostname, int rpcPort) {
+ Set<String> tags = Stream.of(SlobrokMonitor2.SLOBROK_RPC_PORT_TAG, "footag")
+ .collect(Collectors.toSet());
+ Map<String, String> properties = new HashMap<>();
+ properties.put(ModelGenerator.CLUSTER_ID_PROPERTY_NAME, CLUSTER_ID);
+ Set<PortInfo> portInfos = Stream.of(new PortInfo(rpcPort, tags)).collect(Collectors.toSet());
+ ServiceInfo serviceInfo = new ServiceInfo(
+ SERVICE_NAME,
+ SERVICE_TYPE,
+ portInfos,
+ properties,
+ CONFIG_ID,
+ hostname);
+ List<ServiceInfo> serviceInfos = Stream.of(serviceInfo).collect(Collectors.toList());
+ HostInfo hostInfo = new HostInfo(hostname, serviceInfos);
+ List<HostInfo> hostInfos = Stream.of(hostInfo).collect(Collectors.toList());
+
+ TenantName tenantName = TenantName.from(TENANT);
+ ApplicationName applicationName = ApplicationName.from(APPLICATION_NAME);
+ InstanceName instanceName = InstanceName.from(INSTANCE_NAME);
+ ApplicationId applicationId = ApplicationId.from(tenantName, applicationName, instanceName);
+ Model model = mock(Model.class);
+ when(model.getHosts()).thenReturn(hostInfos);
+ ApplicationInfo applicationInfo = new ApplicationInfo(applicationId, 1l, model);
+
+ Map<TenantName, Map<ApplicationId, ApplicationInfo>> applicationInfos = new HashMap<>();
+ applicationInfos.put(tenantName, new HashMap<>());
+ applicationInfos.get(tenantName).put(applicationId, applicationInfo);
+ return new SuperModel(applicationInfos);
+ }
+}
diff --git a/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/ModelGeneratorTest.java b/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/ModelGeneratorTest.java
new file mode 100644
index 00000000000..e54fdc51a3a
--- /dev/null
+++ b/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/ModelGeneratorTest.java
@@ -0,0 +1,107 @@
+// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.service.monitor;
+
+import com.yahoo.config.model.api.SuperModel;
+import com.yahoo.config.provision.Environment;
+import com.yahoo.config.provision.RegionName;
+import com.yahoo.config.provision.Zone;
+import com.yahoo.vespa.applicationmodel.ApplicationInstance;
+import com.yahoo.vespa.applicationmodel.ApplicationInstanceReference;
+import com.yahoo.vespa.applicationmodel.ServiceCluster;
+import com.yahoo.vespa.applicationmodel.ServiceInstance;
+import org.junit.Test;
+
+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;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class ModelGeneratorTest {
+ private final String ENVIRONMENT = "prod";
+ private final String REGION = "us-west-1";
+ private final String HOSTNAME = "hostname";
+ private final int PORT = 2;
+
+ @Test
+ public void toApplicationModel() throws Exception {
+ SuperModel superModel =
+ ExampleModel.createExampleSuperModelWithOneRpcPort(HOSTNAME, PORT);
+ ModelGenerator modelGenerator = new ModelGenerator();
+
+ Zone zone = new Zone(Environment.from(ENVIRONMENT), RegionName.from(REGION));
+
+ List<String> configServerHosts = Stream.of("cfg1", "cfg2", "cfg3")
+ .collect(Collectors.toList());
+
+ SlobrokMonitor2 slobrokMonitor = mock(SlobrokMonitor2.class);
+ when(slobrokMonitor.getStatus(any(), any())).thenReturn(ServiceMonitorStatus.UP);
+
+ ServiceModel serviceModel =
+ modelGenerator.toServiceModel(
+ superModel,
+ zone,
+ configServerHosts,
+ slobrokMonitor);
+
+ Map<ApplicationInstanceReference,
+ ApplicationInstance<ServiceMonitorStatus>> applicationInstances =
+ serviceModel.getAllApplicationInstances();
+
+ assertEquals(2, applicationInstances.size());
+
+ Iterator<Map.Entry<ApplicationInstanceReference,
+ ApplicationInstance<ServiceMonitorStatus>>> iterator =
+ applicationInstances.entrySet().iterator();
+
+ ApplicationInstance<ServiceMonitorStatus> applicationInstance1 = iterator.next().getValue();
+ ApplicationInstance<ServiceMonitorStatus> applicationInstance2 = iterator.next().getValue();
+
+ if (applicationInstance1.applicationInstanceId().equals(
+ ConfigServerApplication.APPLICATION_INSTANCE_ID)) {
+ verifyConfigServerApplication(applicationInstance1);
+ verifyOtherApplication(applicationInstance2);
+ } else {
+ verifyConfigServerApplication(applicationInstance2);
+ verifyOtherApplication(applicationInstance1);
+ }
+ }
+
+ private void verifyOtherApplication(ApplicationInstance<ServiceMonitorStatus> applicationInstance) {
+ assertEquals(String.format("%s:%s:%s:%s:%s",
+ ExampleModel.TENANT,
+ ExampleModel.APPLICATION_NAME,
+ ENVIRONMENT,
+ REGION,
+ ExampleModel.INSTANCE_NAME),
+ applicationInstance.reference().toString());
+
+ assertEquals(ExampleModel.TENANT, applicationInstance.tenantId().toString());
+ Set<ServiceCluster<ServiceMonitorStatus>> serviceClusters =
+ applicationInstance.serviceClusters();
+ assertEquals(1, serviceClusters.size());
+ ServiceCluster<ServiceMonitorStatus> serviceCluster = serviceClusters.iterator().next();
+ assertEquals(ExampleModel.CLUSTER_ID, serviceCluster.clusterId().toString());
+ assertEquals(ExampleModel.SERVICE_TYPE, serviceCluster.serviceType().toString());
+ Set<ServiceInstance<ServiceMonitorStatus>> serviceInstances =
+ serviceCluster.serviceInstances();
+ assertEquals(1, serviceClusters.size());
+ ServiceInstance<ServiceMonitorStatus> serviceInstance = serviceInstances.iterator().next();
+ assertEquals(HOSTNAME, serviceInstance.hostName().toString());
+ assertEquals(ExampleModel.CONFIG_ID, serviceInstance.configId().toString());
+ assertEquals(ServiceMonitorStatus.UP, serviceInstance.serviceStatus());
+ }
+
+ private void verifyConfigServerApplication(
+ ApplicationInstance<ServiceMonitorStatus> applicationInstance) {
+ assertEquals(ConfigServerApplication.APPLICATION_INSTANCE_ID,
+ applicationInstance.applicationInstanceId());
+ }
+
+} \ No newline at end of file
diff --git a/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/SlobrokMonitor2Test.java b/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/SlobrokMonitor2Test.java
new file mode 100644
index 00000000000..242112694eb
--- /dev/null
+++ b/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/SlobrokMonitor2Test.java
@@ -0,0 +1,58 @@
+// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.service.monitor;
+
+import com.yahoo.config.model.api.SuperModel;
+import com.yahoo.jrt.slobrok.api.Mirror;
+import com.yahoo.jrt.slobrok.api.SlobrokList;
+import com.yahoo.vespa.applicationmodel.ConfigId;
+import com.yahoo.vespa.applicationmodel.ServiceType;
+import org.junit.Test;
+
+import java.util.Optional;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class SlobrokMonitor2Test {
+ private final SlobrokList slobrokList = mock(SlobrokList.class);
+ private final Mirror mirror = mock(Mirror.class);
+ private SlobrokMonitor2 slobrokMonitor = new SlobrokMonitor2(slobrokList, mirror);
+
+ @Test
+ public void testLookup() {
+ assertEquals(
+ Optional.of("config.id"),
+ lookup("topleveldispatch", "config.id"));
+
+ assertEquals(
+ Optional.empty(),
+ lookup("adminserver", "config.id"));
+ }
+
+ private Optional<String> lookup(String serviceType, String configId) {
+ return slobrokMonitor.lookup(new ServiceType(serviceType), new ConfigId(configId));
+ }
+
+ @Test
+ public void testGetStatus() {
+ ServiceType serviceType = new ServiceType("topleveldispatch");
+ ConfigId configId = new ConfigId("config.id");
+ when(mirror.lookup("config.id")).thenReturn(new Mirror.Entry[1]);
+ assertEquals(ServiceMonitorStatus.UP, slobrokMonitor.getStatus(serviceType, configId));
+ }
+
+ @Test
+ public void testUpdateSlobrokList() {
+ final String hostname = "hostname";
+ final int port = 1;
+
+ SuperModel superModel = ExampleModel.createExampleSuperModelWithOneRpcPort(hostname, port);
+ slobrokMonitor.updateSlobrokList(superModel);
+
+ String[] expectedSpecs = new String[] {"tcp/" + hostname + ":" + port};
+ verify(slobrokList).setup(expectedSpecs);
+ }
+
+} \ No newline at end of file