aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHåkon Hallingstad <hakon@oath.com>2018-11-30 15:13:32 +0100
committerHåkon Hallingstad <hakon@oath.com>2018-11-30 15:13:32 +0100
commit72cc2930e964eea0969b7f8bcea7fe6b4f0872f0 (patch)
tree403dda89422340efee18b0a796c56bd1fa3ad007
parent1b2ccec2d8f5ad05a7a718b62f256b4fd19bda74 (diff)
Add infrastructure applications to DuperModel
DuperModel is (will be) responsible for both active tenant applications (through SuperModel) and infrastructure applications. This PR is one step in that direction: - All infrastructure applications (config, confighost, controller, controllerhost, and proxyhost) are owned and managed by DuperModel. - The InfrastructureProvisioner retrieves all possible infra apps from the DuperModel (through a reduced API), and "activates" each of them if target is set and there are any nodes etc. - The InfrastructureProvisioner then notifies the DuperModel which apps have been activated, and with which hosts. - The DuperModel can then build delegate artificially create ApplicationInfo, which gets translated into the application model, and finally the service model. - The resulting service model has NOT_CHECKED for each hostadmin service instance. This is sufficient for goal 1 of this sprint. - The config server application currently has health, so that's kept as-is for now. - Feature flags have been tried and works and allows 1. to disable adding the infra apps in the DuperModel, and 2. to enable the infra configserver instead of the currently created configserver w/health.
-rw-r--r--application-model/src/main/java/com/yahoo/vespa/applicationmodel/ServiceType.java3
-rw-r--r--config-model-api/src/main/java/com/yahoo/config/model/api/SuperModel.java4
-rw-r--r--configserver/src/main/resources/configserver-app/services.xml3
-rw-r--r--flags/pom.xml6
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/InfrastructureProvisioner.java98
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRepositoryMaintenance.java10
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/ContainerConfig.java1
-rw-r--r--node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockDuperModel.java46
-rw-r--r--node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/InfrastructureProvisionerTest.java167
-rw-r--r--service-monitor/pom.xml6
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/ConfigServerApplication.java8
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/ConfigServerHostApplication.java11
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/ControllerApplication.java11
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/ControllerHostApplication.java12
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/DuperModel.java140
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/DuperModelInfraApi.java26
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/DuperModelListener.java (renamed from service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/DuperModelListener.java)2
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/HostedVespaApplication.java69
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/InfraApplication.java142
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/InfraApplicationApi.java22
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/ProxyHostApplication.java11
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/TenantHostApplication.java14
-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.java42
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/MonitorManager.java1
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/ServiceMonitorImpl.java8
-rw-r--r--service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/SuperModelListenerImpl.java1
-rw-r--r--service-monitor/src/test/java/com/yahoo/vespa/service/monitor/application/ApplicationInstanceGeneratorTest.java2
-rw-r--r--service-monitor/src/test/java/com/yahoo/vespa/service/monitor/application/DuperModelTest.java95
-rw-r--r--service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/ConfigserverUtil.java2
-rw-r--r--service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/DuperModelTest.java53
-rw-r--r--service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/ModelGeneratorTest.java5
-rw-r--r--service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/SuperModelListenerImplTest.java1
-rw-r--r--service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/health/ApplicationHealthMonitorTest.java3
34 files changed, 713 insertions, 316 deletions
diff --git a/application-model/src/main/java/com/yahoo/vespa/applicationmodel/ServiceType.java b/application-model/src/main/java/com/yahoo/vespa/applicationmodel/ServiceType.java
index 0054264d42f..07f2cd604b4 100644
--- a/application-model/src/main/java/com/yahoo/vespa/applicationmodel/ServiceType.java
+++ b/application-model/src/main/java/com/yahoo/vespa/applicationmodel/ServiceType.java
@@ -12,6 +12,9 @@ public class ServiceType {
// Common service types.
public static final ServiceType CONTAINER = new ServiceType("container");
public static final ServiceType SLOBROK = new ServiceType("slobrok");
+ public static final ServiceType HOST_ADMIN = new ServiceType("hostadmin");
+ public static final ServiceType CONFIG_SERVER = new ServiceType("configserver");
+ public static final ServiceType CONTROLLER = new ServiceType("controller");
private final String id;
diff --git a/config-model-api/src/main/java/com/yahoo/config/model/api/SuperModel.java b/config-model-api/src/main/java/com/yahoo/config/model/api/SuperModel.java
index 52adc4ad51b..31a1c929a71 100644
--- a/config-model-api/src/main/java/com/yahoo/config/model/api/SuperModel.java
+++ b/config-model-api/src/main/java/com/yahoo/config/model/api/SuperModel.java
@@ -14,6 +14,10 @@ import java.util.Map;
import java.util.Optional;
import java.util.Set;
+/**
+ * The SuperModel contains the ApplicationInfo of all active applications (applications whose configs have been
+ * activated/reloaded and not yet removed).
+ */
public class SuperModel {
private final Map<ApplicationId, ApplicationInfo> models;
diff --git a/configserver/src/main/resources/configserver-app/services.xml b/configserver/src/main/resources/configserver-app/services.xml
index 3dd6e0090c5..92ec8d53022 100644
--- a/configserver/src/main/resources/configserver-app/services.xml
+++ b/configserver/src/main/resources/configserver-app/services.xml
@@ -60,11 +60,14 @@
<!-- TODO Vespa 7: Remove scoreboard.xml, replaced by metrics-packets.xml -->
<preprocess:include file='hosted-vespa/scoreboard.xml' required='false' />
+ <component id="com.yahoo.vespa.flags.FileFlagSource" bundle="flags"/>
+
<preprocess:include file='hosted-vespa/metrics-packets.xml' required='false' />
<preprocess:include file='controller/container.xml' required='false' />
<component id="com.yahoo.vespa.service.monitor.internal.slobrok.SlobrokMonitorManagerImpl" bundle="service-monitor" />
<component id="com.yahoo.vespa.service.monitor.internal.health.HealthMonitorManager" bundle="service-monitor" />
<component id="com.yahoo.vespa.service.monitor.internal.ServiceMonitorImpl" bundle="service-monitor" />
+ <component id="com.yahoo.vespa.service.monitor.application.DuperModel" bundle="service-monitor" />
<component id="com.yahoo.vespa.orchestrator.ServiceMonitorInstanceLookupService" bundle="orchestrator" />
<component id="com.yahoo.vespa.orchestrator.status.ZookeeperStatusService" bundle="orchestrator" />
<component id="com.yahoo.vespa.orchestrator.controller.RetryingClusterControllerClientFactory" bundle="orchestrator" />
diff --git a/flags/pom.xml b/flags/pom.xml
index 57c57f907d3..5a535ad4de8 100644
--- a/flags/pom.xml
+++ b/flags/pom.xml
@@ -20,12 +20,6 @@
<dependencies>
<dependency>
<groupId>com.yahoo.vespa</groupId>
- <artifactId>defaults</artifactId>
- <version>${project.version}</version>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>com.yahoo.vespa</groupId>
<artifactId>container-dev</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/InfrastructureProvisioner.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/InfrastructureProvisioner.java
index 07e4d586a91..d37629241f8 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/InfrastructureProvisioner.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/InfrastructureProvisioner.java
@@ -1,8 +1,8 @@
// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.hosted.provision.maintenance;
-import com.google.common.collect.ImmutableList;
import com.yahoo.component.Version;
+import com.yahoo.config.provision.HostName;
import com.yahoo.config.provision.HostSpec;
import com.yahoo.config.provision.NodeType;
import com.yahoo.config.provision.Provisioner;
@@ -11,12 +11,9 @@ import com.yahoo.transaction.Mutex;
import com.yahoo.transaction.NestedTransaction;
import com.yahoo.vespa.hosted.provision.Node;
import com.yahoo.vespa.hosted.provision.NodeRepository;
-import com.yahoo.vespa.service.monitor.application.ConfigServerApplication;
-import com.yahoo.vespa.service.monitor.application.ConfigServerHostApplication;
-import com.yahoo.vespa.service.monitor.application.ControllerApplication;
-import com.yahoo.vespa.service.monitor.application.ControllerHostApplication;
-import com.yahoo.vespa.service.monitor.application.HostedVespaApplication;
-import com.yahoo.vespa.service.monitor.application.ProxyHostApplication;
+import com.yahoo.vespa.service.monitor.application.DuperModelInfraApi;
+import com.yahoo.vespa.service.monitor.application.InfraApplication;
+import com.yahoo.vespa.service.monitor.application.InfraApplicationApi;
import java.time.Duration;
import java.util.List;
@@ -34,33 +31,56 @@ import java.util.stream.Collectors;
public class InfrastructureProvisioner extends Maintainer {
private static final Logger logger = Logger.getLogger(InfrastructureProvisioner.class.getName());
- private static final List<HostedVespaApplication> HOSTED_VESPA_APPLICATIONS = ImmutableList.of(
- ConfigServerApplication.CONFIG_SERVER_APPLICATION,
- ConfigServerHostApplication.CONFIG_SERVER_HOST_APPLICATION,
- ProxyHostApplication.PROXY_HOST_APPLICATION,
- ControllerApplication.CONTROLLER_APPLICATION,
- ControllerHostApplication.CONTROLLER_HOST_APPLICATION);
private final Provisioner provisioner;
private final InfrastructureVersions infrastructureVersions;
+ private final DuperModelInfraApi duperModel;
public InfrastructureProvisioner(Provisioner provisioner, NodeRepository nodeRepository,
- InfrastructureVersions infrastructureVersions, Duration interval, JobControl jobControl) {
+ InfrastructureVersions infrastructureVersions, Duration interval, JobControl jobControl,
+ DuperModelInfraApi duperModel) {
super(nodeRepository, interval, jobControl);
this.provisioner = provisioner;
this.infrastructureVersions = infrastructureVersions;
+ this.duperModel = duperModel;
}
@Override
protected void maintain() {
- for (HostedVespaApplication application: HOSTED_VESPA_APPLICATIONS) {
+ for (InfraApplicationApi application: duperModel.getSupportedInfraApplications()) {
try (Mutex lock = nodeRepository().lock(application.getApplicationId())) {
- Optional<Version> version = getTargetVersion(application.getCapacity().type());
- if (! version.isPresent()) continue;
+ NodeType nodeType = application.getCapacity().type();
+
+ Optional<Version> targetVersion = infrastructureVersions.getTargetVersionFor(nodeType);
+ if (!targetVersion.isPresent()) {
+ logger.log(LogLevel.DEBUG, "Skipping provision of " + nodeType + ": No target version set");
+ duperModel.infraApplicationRemoved(application.getApplicationId());
+ continue;
+ }
+
+ List<Version> wantedVersions = nodeRepository()
+ .getNodes(nodeType, Node.State.ready, Node.State.reserved, Node.State.active, Node.State.inactive)
+ .stream()
+ .map(node -> node.allocation()
+ .map(allocation -> allocation.membership().cluster().vespaVersion())
+ .orElse(null))
+ .collect(Collectors.toList());
+ if (wantedVersions.isEmpty()) {
+ logger.log(LogLevel.DEBUG, "Skipping provision of " + nodeType + ": No nodes to provision");
+ duperModel.infraApplicationRemoved(application.getApplicationId());
+ continue;
+ }
+
+ if (wantedVersions.stream().allMatch(targetVersion.get()::equals) &&
+ duperModel.infraApplicationIsActive(application.getApplicationId())) {
+ logger.log(LogLevel.DEBUG, "Skipping provision of " + nodeType +
+ ": Already provisioned to target version " + targetVersion);
+ continue;
+ }
List<HostSpec> hostSpecs = provisioner.prepare(
application.getApplicationId(),
- application.getClusterSpecWithVersion(version.get()),
+ application.getClusterSpecWithVersion(targetVersion.get()),
application.getCapacity(),
1, // groups
logger::log);
@@ -68,42 +88,14 @@ public class InfrastructureProvisioner extends Maintainer {
NestedTransaction nestedTransaction = new NestedTransaction();
provisioner.activate(nestedTransaction, application.getApplicationId(), hostSpecs);
nestedTransaction.commit();
- }
- }
- }
- /**
- * Returns the version that the given node type should be provisioned to. This is
- * the version returned by {@link InfrastructureVersions#getTargetVersionFor} unless a provisioning is:
- * <ul>
- * <li>not possible: no nodes of given type in legal state in node-repo</li>
- * <li>redundant: all nodes that can be provisioned already have the right wanted Vespa version</li>
- * </ul>
- */
- Optional<Version> getTargetVersion(NodeType nodeType) {
- Optional<Version> targetVersion = infrastructureVersions.getTargetVersionFor(nodeType);
- if (!targetVersion.isPresent()) {
- logger.log(LogLevel.DEBUG, "Skipping provision of " + nodeType + ": No target version set");
- return Optional.empty();
- }
-
- List<Version> wantedVersions = nodeRepository().getNodes(nodeType,
- Node.State.ready, Node.State.reserved, Node.State.active, Node.State.inactive).stream()
- .map(node -> node.allocation()
- .map(allocation -> allocation.membership().cluster().vespaVersion())
- .orElse(null))
- .collect(Collectors.toList());
- if (wantedVersions.isEmpty()) {
- logger.log(LogLevel.DEBUG, "Skipping provision of " + nodeType + ": No nodes to provision");
- return Optional.empty();
- }
-
- if (wantedVersions.stream().allMatch(targetVersion.get()::equals)) {
- logger.log(LogLevel.DEBUG, "Skipping provision of " + nodeType +
- ": Already provisioned to target version " + targetVersion);
- return Optional.empty();
+ duperModel.infraApplicationActivated(
+ application.getApplicationId(),
+ hostSpecs.stream().map(HostSpec::hostname).map(HostName::from).collect(Collectors.toList()));
+ } catch (RuntimeException e) {
+ logger.log(LogLevel.INFO, "Failed to activate " + application.getApplicationId(), e);
+ // loop around to activate the next application
+ }
}
- return targetVersion;
}
-
}
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRepositoryMaintenance.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRepositoryMaintenance.java
index ded19a84f0d..677288009da 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRepositoryMaintenance.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/maintenance/NodeRepositoryMaintenance.java
@@ -18,6 +18,7 @@ import com.yahoo.vespa.hosted.provision.maintenance.retire.RetirementPolicyList;
import com.yahoo.vespa.hosted.provision.provisioning.FlavorSpareChecker;
import com.yahoo.vespa.hosted.provision.provisioning.FlavorSpareCount;
import com.yahoo.vespa.orchestrator.Orchestrator;
+import com.yahoo.vespa.service.monitor.application.DuperModelInfraApi;
import com.yahoo.vespa.service.monitor.ServiceMonitor;
import java.time.Clock;
@@ -57,15 +58,16 @@ public class NodeRepositoryMaintenance extends AbstractComponent {
public NodeRepositoryMaintenance(NodeRepository nodeRepository, Deployer deployer, Provisioner provisioner,
HostLivenessTracker hostLivenessTracker, ServiceMonitor serviceMonitor,
Zone zone, Orchestrator orchestrator, Metric metric,
- ConfigserverConfig configserverConfig) {
+ ConfigserverConfig configserverConfig,
+ DuperModelInfraApi duperModelInfraApi) {
this(nodeRepository, deployer, provisioner, hostLivenessTracker, serviceMonitor, zone, Clock.systemUTC(),
- orchestrator, metric, configserverConfig);
+ orchestrator, metric, configserverConfig, duperModelInfraApi);
}
public NodeRepositoryMaintenance(NodeRepository nodeRepository, Deployer deployer, Provisioner provisioner,
HostLivenessTracker hostLivenessTracker, ServiceMonitor serviceMonitor,
Zone zone, Clock clock, Orchestrator orchestrator, Metric metric,
- ConfigserverConfig configserverConfig) {
+ ConfigserverConfig configserverConfig, DuperModelInfraApi duperModelInfraApi) {
DefaultTimes defaults = new DefaultTimes(zone);
jobControl = new JobControl(nodeRepository.database());
infrastructureVersions = new InfrastructureVersions(nodeRepository.database());
@@ -81,7 +83,7 @@ public class NodeRepositoryMaintenance extends AbstractComponent {
provisionedExpirer = new ProvisionedExpirer(nodeRepository, clock, durationFromEnv("provisioned_expiry").orElse(defaults.provisionedExpiry), jobControl);
nodeRebooter = new NodeRebooter(nodeRepository, clock, durationFromEnv("reboot_interval").orElse(defaults.rebootInterval), jobControl);
metricsReporter = new MetricsReporter(nodeRepository, metric, orchestrator, serviceMonitor, periodicApplicationMaintainer::pendingDeployments, durationFromEnv("metrics_interval").orElse(defaults.metricsInterval), jobControl);
- infrastructureProvisioner = new InfrastructureProvisioner(provisioner, nodeRepository, infrastructureVersions, durationFromEnv("infrastructure_provision_interval").orElse(defaults.infrastructureProvisionInterval), jobControl);
+ infrastructureProvisioner = new InfrastructureProvisioner(provisioner, nodeRepository, infrastructureVersions, durationFromEnv("infrastructure_provision_interval").orElse(defaults.infrastructureProvisionInterval), jobControl, duperModelInfraApi);
RetirementPolicy policy = new RetirementPolicyList(new RetireIPv4OnlyNodes(zone));
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/ContainerConfig.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/ContainerConfig.java
index 27215529cf4..035cb8f0aaf 100644
--- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/ContainerConfig.java
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/ContainerConfig.java
@@ -21,6 +21,7 @@ public class ContainerConfig {
" <component id='com.yahoo.vespa.hosted.provision.testutils.MockProvisioner'/>\n" +
" <component id='com.yahoo.vespa.hosted.provision.testutils.TestHostLivenessTracker'/>\n" +
" <component id='com.yahoo.vespa.hosted.provision.testutils.ServiceMonitorStub'/>\n" +
+ " <component id='com.yahoo.vespa.hosted.provision.testutils.MockDuperModel'/>\n" +
" <component id='com.yahoo.vespa.hosted.provision.testutils.MockNodeFlavors'/>\n" +
" <component id='com.yahoo.vespa.hosted.provision.testutils.MockNodeRepository'/>\n" +
" <component id='com.yahoo.vespa.hosted.provision.lb.LoadBalancerServiceProvider'/>\n" +
diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockDuperModel.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockDuperModel.java
new file mode 100644
index 00000000000..b366538949a
--- /dev/null
+++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/testutils/MockDuperModel.java
@@ -0,0 +1,46 @@
+// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.hosted.provision.testutils;
+
+import com.google.inject.Inject;
+import com.yahoo.config.provision.ApplicationId;
+import com.yahoo.config.provision.HostName;
+import com.yahoo.vespa.service.monitor.application.DuperModelInfraApi;
+import com.yahoo.vespa.service.monitor.application.InfraApplicationApi;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * @author hakonhall
+ */
+public class MockDuperModel implements DuperModelInfraApi {
+ private final Map<ApplicationId, InfraApplicationApi> supportedInfraApps = new HashMap<>();
+ private final ConcurrentHashMap<ApplicationId, List<HostName>> activeApps = new ConcurrentHashMap<>();
+
+ @Inject
+ public MockDuperModel() {
+ }
+
+ @Override
+ public List<InfraApplicationApi> getSupportedInfraApplications() {
+ return new ArrayList<>(supportedInfraApps.values());
+ }
+
+ @Override
+ public boolean infraApplicationIsActive(ApplicationId applicationId) {
+ return activeApps.containsKey(applicationId);
+ }
+
+ @Override
+ public void infraApplicationActivated(ApplicationId applicationId, List<HostName> hostnames) {
+ activeApps.put(applicationId, hostnames);
+ }
+
+ @Override
+ public void infraApplicationRemoved(ApplicationId applicationId) {
+ activeApps.remove(applicationId);
+ }
+}
diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/InfrastructureProvisionerTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/InfrastructureProvisionerTest.java
index 642e6adfc75..4926d3f5013 100644
--- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/InfrastructureProvisionerTest.java
+++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/maintenance/InfrastructureProvisionerTest.java
@@ -4,8 +4,11 @@ package com.yahoo.vespa.hosted.provision.maintenance;
import com.yahoo.component.Version;
import com.yahoo.config.provision.ClusterMembership;
import com.yahoo.config.provision.ClusterSpec;
+import com.yahoo.config.provision.HostName;
+import com.yahoo.config.provision.HostSpec;
import com.yahoo.config.provision.NodeType;
import com.yahoo.config.provision.Provisioner;
+import com.yahoo.log.event.Collection;
import com.yahoo.vespa.hosted.provision.Node;
import com.yahoo.vespa.hosted.provision.NodeRepository;
import com.yahoo.vespa.hosted.provision.NodeRepositoryTester;
@@ -14,7 +17,10 @@ import com.yahoo.vespa.hosted.provision.node.Allocation;
import com.yahoo.vespa.hosted.provision.node.Generation;
import com.yahoo.vespa.service.monitor.application.ConfigServerApplication;
import com.yahoo.vespa.service.monitor.application.ControllerApplication;
-import com.yahoo.vespa.service.monitor.application.HostedVespaApplication;
+import com.yahoo.vespa.service.monitor.application.DuperModelInfraApi;
+import com.yahoo.vespa.service.monitor.application.InfraApplication;
+import com.yahoo.vespa.service.monitor.application.InfraApplicationApi;
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -22,11 +28,20 @@ import org.junit.runners.Parameterized.Parameters;
import java.time.Duration;
import java.util.Arrays;
+import java.util.Collections;
import java.util.Optional;
import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyList;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
/**
@@ -38,8 +53,8 @@ public class InfrastructureProvisionerTest {
@Parameters(name = "application={0}")
public static Iterable<Object[]> parameters() {
return Arrays.asList(
- new HostedVespaApplication[]{ConfigServerApplication.CONFIG_SERVER_APPLICATION},
- new HostedVespaApplication[]{ControllerApplication.CONTROLLER_APPLICATION}
+ new InfraApplicationApi[]{new ConfigServerApplication()},
+ new InfraApplicationApi[]{new ControllerApplication()}
);
}
@@ -47,81 +62,161 @@ public class InfrastructureProvisionerTest {
private final Provisioner provisioner = mock(Provisioner.class);
private final NodeRepository nodeRepository = tester.nodeRepository();
private final InfrastructureVersions infrastructureVersions = mock(InfrastructureVersions.class);
+ private final DuperModelInfraApi duperModelInfraApi = mock(DuperModelInfraApi.class);
private final InfrastructureProvisioner infrastructureProvisioner = new InfrastructureProvisioner(
- provisioner, nodeRepository, infrastructureVersions, Duration.ofDays(99), new JobControl(nodeRepository.database()));
-
- private final HostedVespaApplication application;
+ provisioner, nodeRepository, infrastructureVersions, Duration.ofDays(99), new JobControl(nodeRepository.database()),
+ duperModelInfraApi);
+ private final HostName node1 = HostName.from("node-1");
+ private final HostName node2 = HostName.from("node-2");
+ private final HostName node3 = HostName.from("node-3");
+ private final Version target = Version.fromString("6.123.456");
+ private final Version oldVersion = Version.fromString("6.122.333");
+
+ private final InfraApplicationApi application;
private final NodeType nodeType;
- public InfrastructureProvisionerTest(HostedVespaApplication application) {
+ public InfrastructureProvisionerTest(InfraApplicationApi application) {
this.application = application;
this.nodeType = application.getCapacity().type();
+ when(duperModelInfraApi.getSupportedInfraApplications()).thenReturn(Collections.singletonList(application));
+ }
+
+ @Test
+ public void remove_application_if_without_target_version() {
+ when(infrastructureVersions.getTargetVersionFor(eq(nodeType))).thenReturn(Optional.empty());
+ addNode(1, Node.State.active, Optional.of(target));
+ infrastructureProvisioner.maintain();
+ verify(duperModelInfraApi).infraApplicationRemoved(application.getApplicationId());
+ verifyNoMoreInteractions(provisioner);
+ }
+
+ @Test
+ public void remove_application_if_without_nodes() {
+ when(infrastructureVersions.getTargetVersionFor(eq(nodeType))).thenReturn(Optional.of(target));
+ addNode(1, Node.State.failed, Optional.of(target));
+ addNode(2, Node.State.parked, Optional.empty());
+ infrastructureProvisioner.maintain();
+ verify(duperModelInfraApi).infraApplicationRemoved(application.getApplicationId());
+ verifyNoMoreInteractions(provisioner);
}
@Test
- public void returns_version_if_usable_nodes_on_old_version() {
- Version target = Version.fromString("6.123.456");
- Version oldVersion = Version.fromString("6.122.333");
+ public void no_op_if_nodes_active_and_on_target_version() {
when(infrastructureVersions.getTargetVersionFor(eq(nodeType))).thenReturn(Optional.of(target));
addNode(1, Node.State.failed, Optional.of(oldVersion));
- addNode(2, Node.State.dirty, Optional.empty());
- addNode(3, Node.State.active, Optional.of(oldVersion));
+ addNode(2, Node.State.parked, Optional.of(target));
+ addNode(3, Node.State.active, Optional.of(target));
+ addNode(4, Node.State.inactive, Optional.of(target));
+ addNode(5, Node.State.dirty, Optional.empty());
+
+ when(duperModelInfraApi.infraApplicationIsActive(eq(application.getApplicationId()))).thenReturn(true);
+
+ infrastructureProvisioner.maintain();
+ verify(duperModelInfraApi, never()).infraApplicationRemoved(any());
+ verify(duperModelInfraApi, never()).infraApplicationActivated(any(), any());
+ verifyNoMoreInteractions(provisioner);
+ }
+
+ @Test
+ public void activates_after_target_has_been_set_the_first_time() {
+ when(infrastructureVersions.getTargetVersionFor(eq(nodeType))).thenReturn(Optional.of(target));
+
+ addNode(1, Node.State.inactive, Optional.empty());
+ addNode(2, Node.State.parked, Optional.empty());
+ addNode(3, Node.State.active, Optional.empty());
+ addNode(4, Node.State.failed, Optional.empty());
+ addNode(5, Node.State.dirty, Optional.empty());
+
+ when(provisioner.prepare(any(), any(), any(), anyInt(), any())).thenReturn(Arrays.asList(
+ new HostSpec(node1.value(), Collections.emptyList()),
+ new HostSpec(node2.value(), Collections.emptyList()),
+ new HostSpec(node3.value(), Collections.emptyList())));
+
+ infrastructureProvisioner.maintain();
- assertEquals(Optional.of(target), infrastructureProvisioner.getTargetVersion(nodeType));
+ verify(provisioner).prepare(eq(application.getApplicationId()), any(), any(), anyInt(), any());
+ verify(provisioner).activate(any(), eq(application.getApplicationId()), any());
+ verify(duperModelInfraApi).infraApplicationActivated(application.getApplicationId(), Arrays.asList(node1, node2, node3));
+ }
+
+
+ @Test
+ public void activates_the_first_time_after_jvm_start() {
+ when(infrastructureVersions.getTargetVersionFor(eq(nodeType))).thenReturn(Optional.of(target));
+
+ addNode(1, Node.State.active, Optional.of(target));
+
+ when(duperModelInfraApi.infraApplicationIsActive(eq(application.getApplicationId()))).thenReturn(false);
+ when(provisioner.prepare(any(), any(), any(), anyInt(), any())).thenReturn(Collections.singletonList(
+ new HostSpec(node1.value(), Collections.emptyList())));
+
+ infrastructureProvisioner.maintain();
+
+ verify(provisioner).prepare(eq(application.getApplicationId()), any(), any(), anyInt(), any());
+ verify(provisioner).activate(any(), eq(application.getApplicationId()), any());
+ verify(duperModelInfraApi).infraApplicationActivated(application.getApplicationId(), Arrays.asList(node1));
}
@Test
- public void returns_version_if_has_usable_nodes_without_version() {
- Version target = Version.fromString("6.123.456");
- Version oldVersion = Version.fromString("6.122.333");
+ public void provision_usable_nodes_on_old_version() {
when(infrastructureVersions.getTargetVersionFor(eq(nodeType))).thenReturn(Optional.of(target));
addNode(1, Node.State.failed, Optional.of(oldVersion));
- addNode(2, Node.State.ready, Optional.empty());
- addNode(3, Node.State.active, Optional.of(target));
+ addNode(2, Node.State.inactive, Optional.of(target));
+ addNode(3, Node.State.active, Optional.of(oldVersion));
- assertEquals(Optional.of(target), infrastructureProvisioner.getTargetVersion(nodeType));
+ when(duperModelInfraApi.getSupportedInfraApplications()).thenReturn(Collections.singletonList(application));
+ when(provisioner.prepare(any(), any(), any(), anyInt(), any())).thenReturn(Arrays.asList(
+ new HostSpec(node2.value(), Collections.emptyList()),
+ new HostSpec(node3.value(), Collections.emptyList())));
+
+ infrastructureProvisioner.maintain();
+
+ verify(provisioner).prepare(eq(application.getApplicationId()), any(), any(), anyInt(), any());
+ verify(provisioner).activate(any(), eq(application.getApplicationId()), any());
+ verify(duperModelInfraApi).infraApplicationActivated(application.getApplicationId(), Arrays.asList(node2, node3));
}
@Test
- public void returns_empty_if_usable_nodes_on_target_version() {
- Version target = Version.fromString("6.123.456");
- Version oldVersion = Version.fromString("6.122.333");
+ public void provision_with_usable_node_without_version() {
when(infrastructureVersions.getTargetVersionFor(eq(nodeType))).thenReturn(Optional.of(target));
addNode(1, Node.State.failed, Optional.of(oldVersion));
- addNode(2, Node.State.parked, Optional.of(target));
+ addNode(2, Node.State.ready, Optional.empty());
addNode(3, Node.State.active, Optional.of(target));
- addNode(4, Node.State.inactive, Optional.of(target));
- addNode(5, Node.State.dirty, Optional.empty());
- assertEquals(Optional.empty(), infrastructureProvisioner.getTargetVersion(nodeType));
+ when(provisioner.prepare(any(), any(), any(), anyInt(), any()))
+ .thenReturn(Arrays.asList(
+ new HostSpec(node2.value(), Collections.emptyList()),
+ new HostSpec(node3.value(), Collections.emptyList())));
+
+ infrastructureProvisioner.maintain();
+
+ verify(provisioner).prepare(eq(application.getApplicationId()), any(), any(), anyInt(), any());
+ verify(provisioner).activate(any(), eq(application.getApplicationId()), any());
+ verify(duperModelInfraApi).infraApplicationActivated(application.getApplicationId(), Arrays.asList(node2, node3));
}
@Test
public void returns_empty_if_no_usable_nodes() {
- when(infrastructureVersions.getTargetVersionFor(eq(nodeType))).thenReturn(Optional.of(Version.fromString("6.123.456")));
+ when(infrastructureVersions.getTargetVersionFor(eq(nodeType))).thenReturn(Optional.of(target));
- // No nodes in node repo
- assertEquals(Optional.empty(), infrastructureProvisioner.getTargetVersion(nodeType));
+ infrastructureProvisioner.maintain();
+ verifyNoMoreInteractions(provisioner);
// Add nodes in non-provisionable states
addNode(1, Node.State.dirty, Optional.empty());
addNode(2, Node.State.failed, Optional.empty());
- assertEquals(Optional.empty(), infrastructureProvisioner.getTargetVersion(nodeType));
- }
- @Test
- public void returns_empty_if_target_version_not_set() {
- when(infrastructureVersions.getTargetVersionFor(eq(nodeType))).thenReturn(Optional.empty());
- assertEquals(Optional.empty(), infrastructureProvisioner.getTargetVersion(nodeType));
+ infrastructureProvisioner.maintain();
+ verifyNoMoreInteractions(provisioner);
}
private Node addNode(int id, Node.State state, Optional<Version> wantedVespaVersion) {
Node node = tester.addNode("id-" + id, "node-" + id, "default", nodeType);
Optional<Node> nodeWithAllocation = wantedVespaVersion.map(version -> {
- ClusterSpec clusterSpec = ClusterSpec.from(application.getClusterType(), application.getClusterId(), ClusterSpec.Group.from(0), version, false);
+ ClusterSpec clusterSpec = ClusterSpec.from(ClusterSpec.Type.admin, new ClusterSpec.Id("clusterid"), ClusterSpec.Group.from(0), version, false);
ClusterMembership membership = ClusterMembership.from(clusterSpec, 1);
Allocation allocation = new Allocation(application.getApplicationId(), membership, new Generation(0, 0), false);
return node.with(allocation);
diff --git a/service-monitor/pom.xml b/service-monitor/pom.xml
index b8065ed3636..168af826b40 100644
--- a/service-monitor/pom.xml
+++ b/service-monitor/pom.xml
@@ -36,6 +36,12 @@
</dependency>
<dependency>
<groupId>com.yahoo.vespa</groupId>
+ <artifactId>flags</artifactId>
+ <version>${project.version}</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.yahoo.vespa</groupId>
<artifactId>component</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
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 5ad38cebcfc..f1041835a39 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
@@ -25,7 +25,7 @@ import java.util.Map;
/**
* A service/application model of the config server with health status.
*/
-public class ConfigServerApplication extends HostedVespaApplication {
+public class ConfigServerApplication extends InfraApplication {
public static final ConfigServerApplication CONFIG_SERVER_APPLICATION = new ConfigServerApplication();
public static final TenantId TENANT_ID = new TenantId(CONFIG_SERVER_APPLICATION.getApplicationId().tenant().value());
@@ -39,12 +39,12 @@ public class ConfigServerApplication extends HostedVespaApplication {
return new ConfigId(CONFIG_ID_PREFIX + index);
}
- private ConfigServerApplication() {
+ public ConfigServerApplication() {
super("zone-config-servers", NodeType.config,
- ClusterSpec.Type.admin, ClusterSpec.Id.from("zone-config-servers"));
+ ClusterSpec.Type.admin, ClusterSpec.Id.from("zone-config-servers"), ServiceType.CONFIG_SERVER);
}
- public ApplicationInfo makeApplicationInfo(ConfigserverConfig config) {
+ public ApplicationInfo makeApplicationInfoFromConfig(ConfigserverConfig config) {
List<HostInfo> hostInfos = new ArrayList<>();
List<ConfigserverConfig.Zookeeperserver> zooKeeperServers = config.zookeeperserver();
for (int index = 0; index < zooKeeperServers.size(); ++index) {
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/ConfigServerHostApplication.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/ConfigServerHostApplication.java
index 18420fe64a1..9925e2ac69b 100644
--- a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/ConfigServerHostApplication.java
+++ b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/ConfigServerHostApplication.java
@@ -3,13 +3,12 @@ package com.yahoo.vespa.service.monitor.application;
import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.config.provision.NodeType;
+import com.yahoo.vespa.applicationmodel.ServiceType;
-public class ConfigServerHostApplication extends HostedVespaApplication {
-
- public static final ConfigServerHostApplication CONFIG_SERVER_HOST_APPLICATION = new ConfigServerHostApplication();
-
- private ConfigServerHostApplication() {
+public class ConfigServerHostApplication extends InfraApplication {
+ public ConfigServerHostApplication() {
super("configserver-host", NodeType.confighost,
- ClusterSpec.Type.container, ClusterSpec.Id.from("configserver-host"));
+ ClusterSpec.Type.container, ClusterSpec.Id.from("configserver-host"),
+ ServiceType.HOST_ADMIN);
}
}
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/ControllerApplication.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/ControllerApplication.java
index c1bc303e792..ec4cb73383e 100644
--- a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/ControllerApplication.java
+++ b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/ControllerApplication.java
@@ -3,16 +3,15 @@ package com.yahoo.vespa.service.monitor.application;
import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.config.provision.NodeType;
+import com.yahoo.vespa.applicationmodel.ServiceType;
/**
* @author mpolden
*/
-public class ControllerApplication extends HostedVespaApplication {
-
- public static final ControllerApplication CONTROLLER_APPLICATION = new ControllerApplication();
-
- private ControllerApplication() {
- super("controller", NodeType.controller, ClusterSpec.Type.container, ClusterSpec.Id.from("controller"));
+public class ControllerApplication extends InfraApplication {
+ public ControllerApplication() {
+ super("controller", NodeType.controller, ClusterSpec.Type.container,
+ ClusterSpec.Id.from("controller"), ServiceType.CONTROLLER);
}
}
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/ControllerHostApplication.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/ControllerHostApplication.java
index 8311919d570..c23794b3835 100644
--- a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/ControllerHostApplication.java
+++ b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/ControllerHostApplication.java
@@ -3,16 +3,14 @@ package com.yahoo.vespa.service.monitor.application;
import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.config.provision.NodeType;
+import com.yahoo.vespa.applicationmodel.ServiceType;
/**
* @author mpolden
*/
-public class ControllerHostApplication extends HostedVespaApplication {
-
- public static final ControllerHostApplication CONTROLLER_HOST_APPLICATION = new ControllerHostApplication();
-
- protected ControllerHostApplication() {
- super("controller-host", NodeType.controllerhost, ClusterSpec.Type.container, ClusterSpec.Id.from("controller-host"));
+public class ControllerHostApplication extends InfraApplication {
+ public ControllerHostApplication() {
+ super("controller-host", NodeType.controllerhost, ClusterSpec.Type.container,
+ ClusterSpec.Id.from("controller-host"), ServiceType.HOST_ADMIN);
}
-
}
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/DuperModel.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/DuperModel.java
new file mode 100644
index 00000000000..eecd1a73cf9
--- /dev/null
+++ b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/DuperModel.java
@@ -0,0 +1,140 @@
+// 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.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.config.provision.HostName;
+import com.yahoo.vespa.flags.FeatureFlag;
+import com.yahoo.vespa.flags.FlagSource;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * The {@code DuperModel} unites the {@link com.yahoo.config.model.api.SuperModel SuperModel}
+ * with synthetic applications like the config server application.
+ *
+ * @author hakon
+ */
+public class DuperModel implements DuperModelInfraApi {
+ // Infrastructure applications
+ private static final ConfigServerApplication configServerApplication = new ConfigServerApplication();
+ private static final ConfigServerHostApplication configServerHostApplication = new ConfigServerHostApplication();
+ private static final ProxyHostApplication proxyHostApplication = new ProxyHostApplication();
+ private static final ControllerApplication controllerApplication = new ControllerApplication();
+ private static final ControllerHostApplication controllerHostApplication = new ControllerHostApplication();
+
+ private static final Map<ApplicationId, InfraApplication> supportedInfraApplications = Stream.of(
+ configServerApplication,
+ configServerHostApplication,
+ proxyHostApplication,
+ controllerApplication,
+ controllerHostApplication)
+ .collect(Collectors.toMap(InfraApplication::getApplicationId, Function.identity()));
+
+ private final boolean containsInfra;
+ private final boolean useConfigserverConfig;
+
+ // Each of the above infrastructure applications may be active, in case their ApplicationInfo is present here
+ private final ConcurrentHashMap<ApplicationId, ApplicationInfo> infraInfos =
+ new ConcurrentHashMap<>(2 * supportedInfraApplications.size());
+
+ // ApplicationInfo known at construction time
+ private final List<ApplicationInfo> staticInfos = new ArrayList<>();
+
+ @Inject
+ public DuperModel(ConfigserverConfig configServerConfig, FlagSource flagSource) {
+ this(
+ // Whether to include activate infrastructure applications in the DuperModel.
+ new FeatureFlag("dupermodel-contains-infra", true, flagSource).value(),
+
+ // Whether to base the ApplicationInfo for the config server on ConfigserverConfig or InfrastructureProvisioner:
+ // - ConfigserverConfig: The list of config servers comes from VESPA_CONFIGSERVERS environment variable.
+ // - InfrastructureProvisioner: The list of config servers comes from the node repository.
+ //
+ // The goal is to use InfrastructureProvisioner like other infrastructure applications.
+ new FeatureFlag("dupermodel-use-configserverconfig", true, flagSource).value(),
+ configServerConfig.multitenant(),
+ configServerApplication.makeApplicationInfoFromConfig(configServerConfig));
+ }
+
+ /** For testing */
+ public DuperModel(boolean containsInfra,
+ boolean useConfigserverConfig,
+ boolean multitenant,
+ ApplicationInfo configServerApplicationInfo) {
+ this.containsInfra = containsInfra;
+ this.useConfigserverConfig = useConfigserverConfig;
+
+ // Single-tenant applications have the config server as part of the application model, conflicting and would have conflicting.
+ // TODO: Add health monitoring for config server when part of application model.
+ if (useConfigserverConfig && multitenant) {
+ staticInfos.add(configServerApplicationInfo);
+ }
+ }
+
+ public ConfigServerApplication getConfigServerApplication() {
+ return configServerApplication;
+ }
+
+ public ConfigServerHostApplication getConfigServerHostApplication() {
+ return configServerHostApplication;
+ }
+
+ public ProxyHostApplication getProxyHostApplication() {
+ return proxyHostApplication;
+ }
+
+ public ControllerApplication getControllerApplication() {
+ return controllerApplication;
+ }
+
+ public ControllerHostApplication getControllerHostApplication() {
+ return controllerHostApplication;
+ }
+
+ @Override
+ public List<InfraApplicationApi> getSupportedInfraApplications() {
+ return new ArrayList<>(supportedInfraApplications.values());
+ }
+
+ @Override
+ public boolean infraApplicationIsActive(ApplicationId applicationId) {
+ return infraInfos.containsKey(applicationId);
+ }
+
+ @Override
+ public void infraApplicationActivated(ApplicationId applicationId, List<HostName> hostnames) {
+ InfraApplication application = supportedInfraApplications.get(applicationId);
+ if (application == null) {
+ throw new IllegalArgumentException("There is no infrastructure application with ID '" + applicationId + "'");
+ }
+
+ if (useConfigserverConfig && application.equals(configServerApplication)) {
+ return;
+ }
+
+ infraInfos.put(application.getApplicationId(), application.makeApplicationInfo(hostnames));
+ }
+
+ @Override
+ public void infraApplicationRemoved(ApplicationId applicationId) {
+ infraInfos.remove(applicationId);
+ }
+
+ public List<ApplicationInfo> getApplicationInfos(SuperModel superModelSnapshot) {
+ List<ApplicationInfo> allApplicationInfos = new ArrayList<>();
+ allApplicationInfos.addAll(staticInfos);
+ if (containsInfra) allApplicationInfos.addAll(infraInfos.values());
+ allApplicationInfos.addAll(superModelSnapshot.getAllApplicationInfos());
+ return allApplicationInfos;
+ }
+}
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/DuperModelInfraApi.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/DuperModelInfraApi.java
new file mode 100644
index 00000000000..2faeca55fa4
--- /dev/null
+++ b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/DuperModelInfraApi.java
@@ -0,0 +1,26 @@
+// 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.provision.ApplicationId;
+import com.yahoo.config.provision.HostName;
+
+import java.util.List;
+
+/**
+ * The DuperModel's API for infrastructure applications.
+ *
+ * @author hakonhall
+ */
+public interface DuperModelInfraApi {
+ /** Returns the list of supported infrastructure applications. */
+ List<InfraApplicationApi> getSupportedInfraApplications();
+
+ /** Returns true if the DuperModel has registered the infrastructure application as active. */
+ boolean infraApplicationIsActive(ApplicationId applicationId);
+
+ /** Update the DuperModel: A supported infrastructure application has been activated or is active. */
+ void infraApplicationActivated(ApplicationId applicationId, List<HostName> hostnames);
+
+ /** Update the DuperModel: A supported infrastructure application has been removed or is not active. */
+ void infraApplicationRemoved(ApplicationId applicationId);
+}
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/application/DuperModelListener.java
index 235c7db5c36..34b8109ce53 100644
--- 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/application/DuperModelListener.java
@@ -1,5 +1,5 @@
// 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;
+package com.yahoo.vespa.service.monitor.application;
import com.yahoo.config.model.api.ApplicationInfo;
import com.yahoo.config.model.api.SuperModel;
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/HostedVespaApplication.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/HostedVespaApplication.java
deleted file mode 100644
index 23fafa701d9..00000000000
--- a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/HostedVespaApplication.java
+++ /dev/null
@@ -1,69 +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.provision.ApplicationId;
-import com.yahoo.config.provision.Capacity;
-import com.yahoo.config.provision.ClusterSpec;
-import com.yahoo.config.provision.NodeType;
-import com.yahoo.config.provision.TenantName;
-import com.yahoo.component.Version;
-
-/**
- * @author freva
- */
-public abstract class HostedVespaApplication {
-
- public static final TenantName TENANT_NAME = TenantName.from("hosted-vespa");
-
- private final ApplicationId applicationId;
- private final Capacity capacity;
- private final ClusterSpec.Type clusterType;
- private final ClusterSpec.Id clusterId;
-
- protected HostedVespaApplication(String applicationName, NodeType nodeType,
- ClusterSpec.Type clusterType, ClusterSpec.Id clusterId) {
- this(createHostedVespaApplicationId(applicationName), Capacity.fromRequiredNodeType(nodeType),
- clusterType, clusterId);
- }
-
- protected HostedVespaApplication(ApplicationId applicationId, Capacity capacity,
- ClusterSpec.Type clusterType, ClusterSpec.Id clusterId) {
- this.applicationId = applicationId;
- this.capacity = capacity;
- this.clusterType = clusterType;
- this.clusterId = clusterId;
- }
-
- public ApplicationId getApplicationId() {
- return applicationId;
- }
-
- public Capacity getCapacity() {
- return capacity;
- }
-
- public ClusterSpec getClusterSpecWithVersion(Version version) {
- return ClusterSpec.request(clusterType, clusterId, version, true);
- }
-
- public ClusterSpec.Type getClusterType() {
- return clusterType;
- }
-
- public ClusterSpec.Id getClusterId() {
- return clusterId;
- }
-
- public static ApplicationId createHostedVespaApplicationId(String applicationName) {
- return new ApplicationId.Builder()
- .tenant(TENANT_NAME)
- .applicationName(applicationName)
- .build();
- }
-
- @Override
- public String toString() {
- return applicationId.toString();
- }
-
-}
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/InfraApplication.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/InfraApplication.java
new file mode 100644
index 00000000000..1c4f6ea3d2a
--- /dev/null
+++ b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/InfraApplication.java
@@ -0,0 +1,142 @@
+// 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.PortInfo;
+import com.yahoo.config.model.api.ServiceInfo;
+import com.yahoo.config.provision.ApplicationId;
+import com.yahoo.config.provision.Capacity;
+import com.yahoo.config.provision.ClusterSpec;
+import com.yahoo.config.provision.HostName;
+import com.yahoo.config.provision.NodeType;
+import com.yahoo.config.provision.TenantName;
+import com.yahoo.component.Version;
+import com.yahoo.vespa.applicationmodel.ConfigId;
+import com.yahoo.vespa.applicationmodel.ServiceType;
+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;
+import java.util.Objects;
+
+/**
+ * @author freva
+ */
+public abstract class InfraApplication implements InfraApplicationApi {
+ static final int HEALTH_PORT = 8080;
+
+ private static final TenantName TENANT_NAME = TenantName.from("hosted-vespa");
+ private static final String CONFIG_ID_PREFIX = "configid.";
+
+ private final ApplicationId applicationId;
+ private final Capacity capacity;
+ private final ClusterSpec.Type clusterType;
+ private final ClusterSpec.Id clusterId;
+ private final ServiceType serviceType;
+
+ public static ApplicationId createHostedVespaApplicationId(String applicationName) {
+ return new ApplicationId.Builder()
+ .tenant(TENANT_NAME)
+ .applicationName(applicationName)
+ .build();
+ }
+
+ protected InfraApplication(String applicationName,
+ NodeType nodeType,
+ ClusterSpec.Type clusterType,
+ ClusterSpec.Id clusterId,
+ ServiceType serviceType) {
+ this.applicationId = createHostedVespaApplicationId(applicationName);
+ this.capacity = Capacity.fromRequiredNodeType(nodeType);
+ this.clusterType = clusterType;
+ this.clusterId = clusterId;
+ this.serviceType = serviceType;
+ }
+
+ @Override
+ public ApplicationId getApplicationId() {
+ return applicationId;
+ }
+
+ @Override
+ public Capacity getCapacity() {
+ return capacity;
+ }
+
+ @Override
+ public ClusterSpec getClusterSpecWithVersion(Version version) {
+ return ClusterSpec.request(clusterType, clusterId, version, true);
+ }
+
+ public ClusterSpec.Type getClusterType() {
+ return clusterType;
+ }
+
+ public ClusterSpec.Id getClusterId() {
+ return clusterId;
+ }
+
+ public ApplicationInfo makeApplicationInfo(List<HostName> hostnames) {
+ List<HostInfo> hostInfos = new ArrayList<>();
+ for (int index = 0; index < hostnames.size(); ++index) {
+ hostInfos.add(makeHostInfo(hostnames.get(index), HEALTH_PORT, index, serviceType, clusterId));
+ }
+
+ return new ApplicationInfo(applicationId, 0, new HostsModel(hostInfos));
+ }
+
+ private static HostInfo makeHostInfo(HostName hostname, int port, int configIndex, ServiceType serviceType, ClusterSpec.Id clusterId) {
+ PortInfo portInfo = new PortInfo(port, ApplicationHealthMonitor.PORT_TAGS_HEALTH);
+
+ Map<String, String> properties = new HashMap<>();
+ properties.put(ModelGenerator.CLUSTER_ID_PROPERTY_NAME, clusterId.value());
+
+ ServiceInfo serviceInfo = new ServiceInfo(
+ // service name == service type for the first service of each type on each host
+ serviceType.s(),
+ serviceType.s(),
+ Collections.singletonList(portInfo),
+ properties,
+ configIdFrom(configIndex).s(),
+ hostname.value());
+
+ return new HostInfo(hostname.value(), Collections.singletonList(serviceInfo));
+ }
+
+ private static ConfigId configIdFrom(int index) {
+ return new ConfigId(CONFIG_ID_PREFIX + index);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ InfraApplication that = (InfraApplication) o;
+ return Objects.equals(applicationId, that.applicationId) &&
+ Objects.equals(capacity, that.capacity) &&
+ clusterType == that.clusterType &&
+ Objects.equals(clusterId, that.clusterId) &&
+ Objects.equals(serviceType, that.serviceType);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(applicationId, capacity, clusterType, clusterId, serviceType);
+ }
+
+ @Override
+ public String toString() {
+ return "InfraApplication{" +
+ "applicationId=" + applicationId +
+ ", capacity=" + capacity +
+ ", clusterType=" + clusterType +
+ ", clusterId=" + clusterId +
+ ", serviceType=" + serviceType +
+ '}';
+ }
+}
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/InfraApplicationApi.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/InfraApplicationApi.java
new file mode 100644
index 00000000000..3777a50b531
--- /dev/null
+++ b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/InfraApplicationApi.java
@@ -0,0 +1,22 @@
+// 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.component.Version;
+import com.yahoo.config.model.api.ApplicationInfo;
+import com.yahoo.config.provision.ApplicationId;
+import com.yahoo.config.provision.Capacity;
+import com.yahoo.config.provision.ClusterSpec;
+import com.yahoo.config.provision.HostName;
+
+import java.util.List;
+
+/**
+ * API of infrastructure application that is accessible via DuperModelInfraApi.
+ *
+ * @author hakonhall
+ */
+public interface InfraApplicationApi {
+ ApplicationId getApplicationId();
+ Capacity getCapacity();
+ ClusterSpec getClusterSpecWithVersion(Version version);
+}
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/ProxyHostApplication.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/ProxyHostApplication.java
index c1af7a0977e..2debec5d299 100644
--- a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/ProxyHostApplication.java
+++ b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/ProxyHostApplication.java
@@ -3,12 +3,11 @@ package com.yahoo.vespa.service.monitor.application;
import com.yahoo.config.provision.ClusterSpec;
import com.yahoo.config.provision.NodeType;
+import com.yahoo.vespa.applicationmodel.ServiceType;
-public class ProxyHostApplication extends HostedVespaApplication {
-
- public static final ProxyHostApplication PROXY_HOST_APPLICATION = new ProxyHostApplication();
-
- private ProxyHostApplication() {
- super("proxy-host", NodeType.proxyhost, ClusterSpec.Type.container, ClusterSpec.Id.from("proxy-host"));
+public class ProxyHostApplication extends InfraApplication {
+ public ProxyHostApplication() {
+ super("proxy-host", NodeType.proxyhost, ClusterSpec.Type.container,
+ ClusterSpec.Id.from("proxy-host"), ServiceType.HOST_ADMIN);
}
}
diff --git a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/TenantHostApplication.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/TenantHostApplication.java
deleted file mode 100644
index 27879a03c08..00000000000
--- a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/application/TenantHostApplication.java
+++ /dev/null
@@ -1,14 +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.provision.ClusterSpec;
-import com.yahoo.config.provision.NodeType;
-
-public class TenantHostApplication extends HostedVespaApplication {
-
- public static final TenantHostApplication TENANT_HOST_APPLICATION = new TenantHostApplication();
-
- private TenantHostApplication() {
- super("tenant-host", NodeType.host, ClusterSpec.Type.container, ClusterSpec.Id.from("tenant-host"));
- }
-}
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 c10015d3bfa..4a4189cddd7 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
@@ -10,14 +10,14 @@ import java.util.Objects;
/**
* @author hakon
*
- * TODO: This does not extend HostedVespaApplication because
+ * TODO: This does not extend InfraApplication because
* 1) It is not deployed same as the other HostedVespaApplications
* 2) ZoneApplication has multiple clusters
*/
public class ZoneApplication {
private ZoneApplication() {}
- public static final ApplicationId ZONE_APPLICATION_ID = HostedVespaApplication
+ public static final ApplicationId ZONE_APPLICATION_ID = InfraApplication
.createHostedVespaApplicationId("routing");
public static boolean isNodeAdminService(ApplicationId applicationId,
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
deleted file mode 100644
index 80e0bfd2710..00000000000
--- a/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/DuperModel.java
+++ /dev/null
@@ -1,42 +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.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) {
- // Single-tenant applications have the config server as part of the application model.
- // TODO: Add health monitoring for config server when part of application model.
- if (configServerConfig.multitenant()) {
- 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/MonitorManager.java b/service-monitor/src/main/java/com/yahoo/vespa/service/monitor/internal/MonitorManager.java
index 1edf3a18215..965c425b91e 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,6 +1,7 @@
// 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.vespa.service.monitor.application.DuperModelListener;
import com.yahoo.vespa.service.monitor.ServiceStatusProvider;
/**
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 eb346cf40c1..728c761c71d 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
@@ -9,6 +9,7 @@ import com.yahoo.jdisc.Metric;
import com.yahoo.jdisc.Timer;
import com.yahoo.vespa.applicationmodel.ApplicationInstance;
import com.yahoo.vespa.applicationmodel.ApplicationInstanceReference;
+import com.yahoo.vespa.service.monitor.application.DuperModel;
import com.yahoo.vespa.service.monitor.ServiceModel;
import com.yahoo.vespa.service.monitor.ServiceMonitor;
import com.yahoo.vespa.service.monitor.internal.health.HealthMonitorManager;
@@ -26,12 +27,11 @@ public class ServiceMonitorImpl implements ServiceMonitor {
HealthMonitorManager healthMonitorManager,
Metric metric,
Timer timer,
- Zone zone) {
+ Zone zone,
+ DuperModel duperModel) {
ServiceMonitorMetrics metrics = new ServiceMonitorMetrics(metric, timer);
- DuperModel duperModel = new DuperModel(configserverConfig);
- UnionMonitorManager monitorManager =
- new UnionMonitorManager(slobrokMonitorManager, healthMonitorManager);
+ UnionMonitorManager monitorManager = new UnionMonitorManager(slobrokMonitorManager, healthMonitorManager);
SuperModelListenerImpl superModelListener = new SuperModelListenerImpl(
monitorManager,
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 f509809c33d..7e2b61af090 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
@@ -7,6 +7,7 @@ import com.yahoo.config.model.api.SuperModelListener;
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.application.DuperModel;
import com.yahoo.vespa.service.monitor.ServiceModel;
import com.yahoo.vespa.service.monitor.ServiceStatusProvider;
diff --git a/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/application/ApplicationInstanceGeneratorTest.java b/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/application/ApplicationInstanceGeneratorTest.java
index 899cc59bb34..4608e8b0aa8 100644
--- a/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/application/ApplicationInstanceGeneratorTest.java
+++ b/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/application/ApplicationInstanceGeneratorTest.java
@@ -42,7 +42,7 @@ public class ApplicationInstanceGeneratorTest {
configServer2,
configServer3);
Zone zone = mock(Zone.class);
- ApplicationInfo configServer = CONFIG_SERVER_APPLICATION.makeApplicationInfo(config);
+ ApplicationInfo configServer = CONFIG_SERVER_APPLICATION.makeApplicationInfoFromConfig(config);
ApplicationInstance applicationInstance = new ApplicationInstanceGenerator(configServer, zone)
.makeApplicationInstance(statusProvider);
diff --git a/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/application/DuperModelTest.java b/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/application/DuperModelTest.java
new file mode 100644
index 00000000000..40204c0de8e
--- /dev/null
+++ b/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/application/DuperModelTest.java
@@ -0,0 +1,95 @@
+// 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.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.config.provision.HostName;
+import com.yahoo.vespa.applicationmodel.ServiceStatus;
+import com.yahoo.vespa.service.monitor.ServiceStatusProvider;
+import com.yahoo.vespa.service.monitor.internal.ConfigserverUtil;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import static org.hamcrest.CoreMatchers.hasItem;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+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);
+ private final ConfigserverConfig configserverConfig = ConfigserverUtil.createExampleConfigserverConfig();
+ private final ApplicationInfo configServerApplicationInfo = new ConfigServerApplication().makeApplicationInfoFromConfig(configserverConfig);
+ private final SuperModel superModel = mock(SuperModel.class);
+
+ @Before
+ public void setUp() {
+ when(statusProvider.getStatus(any(), any(), any(), any())).thenReturn(ServiceStatus.NOT_CHECKED);
+ }
+
+ @Test
+ public void toApplicationInstance() {
+ DuperModel duperModel = new DuperModel(false, true, true, configServerApplicationInfo);
+ 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));
+ }
+
+ @Test
+ public void toApplicationInstanceInSingleTenantMode() {
+ DuperModel duperModel = new DuperModel(false, true, false, configServerApplicationInfo);
+ ApplicationInfo superModelApplicationInfo = mock(ApplicationInfo.class);
+ when(superModel.getAllApplicationInfos()).thenReturn(Collections.singletonList(superModelApplicationInfo));
+ List<ApplicationInfo> applicationInfos = duperModel.getApplicationInfos(superModel);
+ assertEquals(1, applicationInfos.size());
+ assertSame(superModelApplicationInfo, applicationInfos.get(0));
+ }
+
+ @Test
+ public void testInfraApplications() {
+ DuperModel duperModel = new DuperModel(true, true, true, configServerApplicationInfo);
+ ApplicationInfo infraApplicationInfo = mock(ApplicationInfo.class);
+ when(superModel.getAllApplicationInfos()).thenReturn(Collections.emptyList());
+
+ List<ApplicationInfo> applicationInfos = duperModel.getApplicationInfos(superModel);
+ assertEquals(1, applicationInfos.size());
+ assertEquals(duperModel.getConfigServerApplication().getApplicationId(), applicationInfos.get(0).getApplicationId());
+
+ List<InfraApplicationApi> infraApis = duperModel.getSupportedInfraApplications();
+ assertEquals(5, infraApis.size());
+
+ InfraApplication proxyHostApp = duperModel.getProxyHostApplication();
+ assertFalse(duperModel.infraApplicationIsActive(proxyHostApp.getApplicationId()));
+
+ List<HostName> hostnames = Stream.of("host1").map(HostName::from).collect(Collectors.toList());
+ duperModel.infraApplicationActivated(proxyHostApp.getApplicationId(), hostnames);
+
+ assertTrue(duperModel.infraApplicationIsActive(proxyHostApp.getApplicationId()));
+ applicationInfos = duperModel.getApplicationInfos(superModel);
+ assertEquals(2, applicationInfos.size());
+ List<ApplicationId> applicationIds = applicationInfos.stream()
+ .map(ApplicationInfo::getApplicationId)
+ .collect(Collectors.toList());
+ assertThat(applicationIds, hasItem(proxyHostApp.getApplicationId()));
+
+ duperModel.infraApplicationRemoved(proxyHostApp.getApplicationId());
+ assertFalse(duperModel.infraApplicationIsActive(proxyHostApp.getApplicationId()));
+ }
+}
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
index 85df02949a6..16963797ac8 100644
--- 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
@@ -38,7 +38,7 @@ public class ConfigserverUtil {
String configServerHostname1,
String configServerHostname2,
String configServerHostname3) {
- return ConfigServerApplication.CONFIG_SERVER_APPLICATION.makeApplicationInfo(create(
+ return ConfigServerApplication.CONFIG_SERVER_APPLICATION.makeApplicationInfoFromConfig(create(
true,
true,
configServerHostname1,
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
deleted file mode 100644
index c9d19d0ccd9..00000000000
--- a/service-monitor/src/test/java/com/yahoo/vespa/service/monitor/internal/DuperModelTest.java
+++ /dev/null
@@ -1,53 +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.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();
- 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));
- }
-
- @Test
- public void toApplicationInstanceInSingleTenantMode() {
- when(statusProvider.getStatus(any(), any(), any(), any())).thenReturn(ServiceStatus.NOT_CHECKED);
- ConfigserverConfig config = ConfigserverUtil.createExampleConfigserverConfig(true, false);
- 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(1, applicationInfos.size());
- assertSame(superModelApplicationInfo, applicationInfos.get(0));
- }
-}
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 5a57451a298..275fa8568c2 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
@@ -2,6 +2,7 @@
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.Environment;
import com.yahoo.config.provision.RegionName;
@@ -11,6 +12,7 @@ import com.yahoo.vespa.applicationmodel.ApplicationInstanceReference;
import com.yahoo.vespa.applicationmodel.ServiceCluster;
import com.yahoo.vespa.applicationmodel.ServiceInstance;
import com.yahoo.vespa.applicationmodel.ServiceStatus;
+import com.yahoo.vespa.service.monitor.application.DuperModel;
import com.yahoo.vespa.service.monitor.ServiceModel;
import com.yahoo.vespa.service.monitor.application.ConfigServerApplication;
import com.yahoo.vespa.service.monitor.internal.slobrok.SlobrokMonitorManagerImpl;
@@ -36,7 +38,8 @@ public class ModelGeneratorTest {
SuperModel superModel = ExampleModel.createExampleSuperModelWithOneRpcPort(HOSTNAME, PORT);
ConfigserverConfig config = ConfigserverUtil.createExampleConfigserverConfig();
- DuperModel duperModel = new DuperModel(config);
+ ApplicationInfo configServerInfo = new ConfigServerApplication().makeApplicationInfoFromConfig(config);
+ DuperModel duperModel = new DuperModel(false, true, true, configServerInfo);
ModelGenerator modelGenerator = new ModelGenerator();
Zone zone = new Zone(Environment.from(ENVIRONMENT), RegionName.from(REGION));
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 eb6d6d583f7..e2da7b98f56 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
@@ -5,6 +5,7 @@ import com.yahoo.config.model.api.ApplicationInfo;
import com.yahoo.config.model.api.SuperModel;
import com.yahoo.config.model.api.SuperModelProvider;
import com.yahoo.config.provision.Zone;
+import com.yahoo.vespa.service.monitor.application.DuperModel;
import com.yahoo.vespa.service.monitor.ServiceModel;
import com.yahoo.vespa.service.monitor.internal.slobrok.SlobrokMonitorManagerImpl;
import org.junit.Test;
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
index b0fdb14726f..945d6c633af 100644
--- 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
@@ -3,6 +3,7 @@ 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.application.DuperModel;
import com.yahoo.vespa.service.monitor.internal.ConfigserverUtil;
import org.junit.Test;
@@ -36,6 +37,8 @@ public class ApplicationHealthMonitorTest {
ConfigserverUtil.makeExampleConfigServer(),
monitorFactory);
+ ConfigServerApplication configServerApplication = new ConfigServerApplication();
+
ServiceStatus status1 = applicationMonitor.getStatus(
ConfigServerApplication.CONFIG_SERVER_APPLICATION.getApplicationId(),
ConfigServerApplication.CLUSTER_ID,