aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHÃ¥kon Hallingstad <hakon@oath.com>2018-12-03 20:40:06 +0100
committerGitHub <noreply@github.com>2018-12-03 20:40:06 +0100
commit45907798a1cf2c5364c9e0f24c7815adf7110c87 (patch)
tree1e2f4d9ac716a7e6983a55d034a6c2f3aa3f07d8
parent9c5f6713a54387b035a565e62ff30bb0a7b54cf8 (diff)
Revert "Revert "Add infrastructure applications to DuperModel""
-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.java164
-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, 708 insertions, 318 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..9248ab36f2a 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,8 @@ 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.InfraApplicationApi;
import java.time.Duration;
import java.util.List;
@@ -34,33 +30,57 @@ 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()) {
+ // TODO: Unprovision active nodes from application?
+ 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..a4c2cee9404 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,6 +4,8 @@ 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.vespa.hosted.provision.Node;
@@ -14,7 +16,8 @@ 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.InfraApplicationApi;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -22,11 +25,16 @@ 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.eq;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
/**
@@ -38,8 +46,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 +55,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")));
+ public void avoid_provisioning_if_no_usable_nodes() {
+ 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..b28b37006ed
--- /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.
+ // 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,